@jfvilas/plugin-kwirth-metrics 0.12.8 → 0.12.9

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 (30) hide show
  1. package/README.md +23 -8
  2. package/dist/api/KwirthMetricsClient.esm.js +4 -57
  3. package/dist/api/KwirthMetricsClient.esm.js.map +1 -1
  4. package/dist/api/types.esm.js.map +1 -1
  5. package/dist/components/{EntityKwirthMetricsContent/EntityKwirthMetricsContent.esm.js → EntityKwirthMetricsContent.esm.js} +83 -64
  6. package/dist/components/EntityKwirthMetricsContent.esm.js.map +1 -0
  7. package/dist/components/{Options/Options.esm.js → Options.esm.js} +1 -1
  8. package/dist/components/Options.esm.js.map +1 -0
  9. package/dist/index.d.ts +5 -4
  10. package/dist/index.esm.js +4 -0
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/plugin.esm.js +1 -1
  13. package/dist/plugin.esm.js.map +1 -1
  14. package/dist/routes.esm.js.map +1 -1
  15. package/package.json +1 -1
  16. package/dist/assets/kwirthmetrics-component-not-found.svg +0 -29
  17. package/dist/components/ClusterList/ClusterList.esm.js +0 -30
  18. package/dist/components/ClusterList/ClusterList.esm.js.map +0 -1
  19. package/dist/components/ComponentNotFound/ComponentNotFound.esm.js +0 -63
  20. package/dist/components/ComponentNotFound/ComponentNotFound.esm.js.map +0 -1
  21. package/dist/components/EntityKwirthMetricsContent/EntityKwirthMetricsContent.esm.js.map +0 -1
  22. package/dist/components/EntityKwirthMetricsContent/index.esm.js +0 -2
  23. package/dist/components/EntityKwirthMetricsContent/index.esm.js.map +0 -1
  24. package/dist/components/ObjectSelector/ObjectSelector.esm.js +0 -82
  25. package/dist/components/ObjectSelector/ObjectSelector.esm.js.map +0 -1
  26. package/dist/components/Options/Options.esm.js.map +0 -1
  27. package/dist/components/ShowError/ShowError.esm.js +0 -20
  28. package/dist/components/ShowError/ShowError.esm.js.map +0 -1
  29. package/dist/components/StatusLog/StatusLog.esm.js +0 -10
  30. package/dist/components/StatusLog/StatusLog.esm.js.map +0 -1
package/README.md CHANGED
@@ -3,13 +3,13 @@ This package is a Backstage plugin for **showing real-time streamed Kubernetes o
3
3
 
4
4
 
5
5
  ## Version compatibility
6
- This very first version of KwirthMetrics is compatible with Kwirth core server versions according to following table.
6
+ KwirthMetrics is compatible with Kwirth core server versions according to following table.
7
7
 
8
8
  | Plugin Kwirth version | Kwirth version |
9
9
  |-|-|
10
- |0.12.5|0.4.20|
10
+ |0.13.0|0.4.131|
11
11
  |0.12.8|0.4.45|
12
-
12
+ |0.12.5|0.4.20|
13
13
 
14
14
 
15
15
  ## What for?
@@ -39,7 +39,6 @@ This frontend plugin **includes just the visualization of metrics** charts. All
39
39
  The ability to restart pods is also configured in the app-config (YAML, env or whatever), and **restartig permissions are set independently than chart streaming permissions**.
40
40
  The backend plugin is the only responsible for configuration and permissionism, all the capabilities related with showing charts are implemented in the frontend plugin, which is in charge of establishing the connections to the corresponding Kwirth instances (running inside your Kubernetes clusters).
41
41
 
42
-
43
42
  ## How does it work?
44
43
  Let's explain this by following a user working sequence:
45
44
 
@@ -66,7 +65,7 @@ If everyting is correctly configured and tagged, the user should see a list of c
66
65
 
67
66
  ```bash
68
67
  # From your Backstage root directory
69
- yarn --cwd packages/app add @jfvilas/plugin-kwirth-metrics @jfvilas/plugin-kwirth-common @jfvilas/kwirth-common
68
+ yarn --cwd packages/app add @jfvilas/plugin-kwirth-metrics @jfvilas/plugin-kwirth-common @jfvilas/plugin-kwirth-frontend @jfvilas/kwirth-common
70
69
  ```
71
70
 
72
71
  3. Make sure the [Kwirth backend plugin](https://www.npmjs.com/package/@jfvilas/plugin-kwirth-backend#configure) is installed and configured.
@@ -78,13 +77,14 @@ If everyting is correctly configured and tagged, the user should see a list of c
78
77
  1. Add the KwirthMetrics plugin as a tab in your Entity pages:
79
78
 
80
79
  Firstly, import the plugin module.
80
+
81
81
  ```typescript
82
82
  // In packages/app/src/components/catalog/EntityPage.tsx
83
83
  import { EntityKwirthMetricsContent, isKwirthAvailable } from '@jfvilas/plugin-kwirth-metrics';
84
84
  ```
85
85
 
86
86
  Then, add a tab to your EntityPage (the 'if' is optional, you can keep the 'KwirthMetrics' tab always visible if you prefer to do it that way).
87
- ````jsx
87
+ ```jsx
88
88
  // Note: Add to any other Pages as well (e.g. defaultEntityPage or webSiteEntityPage, for example)
89
89
  const serviceEntityPage = (
90
90
  <EntityLayout>
@@ -95,6 +95,21 @@ If everyting is correctly configured and tagged, the user should see a list of c
95
95
  </EntityLayout>
96
96
  )
97
97
  ```
98
+ You can setup some default *viewing* options on the `EntityKwirthMetricsContent` component, so, when the entity loads the default options will be set. These options are:
99
+ - `depth`
100
+ - `width`
101
+ - `interval`
102
+ - `chart`
103
+ (The meaning of these properties are explained at the end of this document)
104
+
105
+ If you want to setup a long-running histogram as a default chart for your entities you should setup your entity page like this:
106
+ ```jsx
107
+ ...
108
+ <EntityLayout.Route if={isKwirthAvailable} path="/kwirthmetrics" title="KwirthMetrics">
109
+ <EntityKwirthMetricsContent allMetrics={true} enableRestart={false} depth={100} chart={'bar'}/>
110
+ </EntityLayout.Route>
111
+ ...
112
+ ```
98
113
 
99
114
  2. Label your catalog-info according to one of these two startegies:
100
115
 
@@ -102,7 +117,7 @@ If everyting is correctly configured and tagged, the user should see a list of c
102
117
 
103
118
  ```yaml
104
119
  metadata:
105
- annotaations:
120
+ annotations:
106
121
  backstage.io/kubernetes-id: entity001
107
122
  ```
108
123
 
@@ -110,7 +125,7 @@ If everyting is correctly configured and tagged, the user should see a list of c
110
125
 
111
126
  ```yaml
112
127
  metadata:
113
- annotaations:
128
+ annotations:
114
129
  backstage.io/kubernetes-id: 'app=core,artifact=backend'
115
130
  ```
116
131
 
@@ -1,4 +1,4 @@
1
- import { getVersion, getResources, requestAccess } from '@jfvilas/plugin-kwirth-common';
1
+ import { getInfo, getVersion, getResources, requestAccess } from '@jfvilas/plugin-kwirth-common';
2
2
 
3
3
  class KwirthMetricsClient {
4
4
  discoveryApi;
@@ -7,71 +7,18 @@ class KwirthMetricsClient {
7
7
  this.discoveryApi = options.discoveryApi;
8
8
  this.fetchApi = options.fetchApi;
9
9
  }
10
- // +++ test
10
+ async getInfo() {
11
+ return getInfo(this.discoveryApi, this.fetchApi);
12
+ }
11
13
  async getVersion() {
12
14
  return getVersion(this.discoveryApi, this.fetchApi);
13
15
  }
14
- // move to common
15
- // async getVersion(): Promise<string> {
16
- // try {
17
- // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')
18
- // const targetUrl = `${baseUrl}/version`
19
- // const result = await this.fetchApi.fetch(targetUrl)
20
- // const data = await result.json()
21
- // if (!result.ok) {
22
- // throw new Error(`getVersion error: not ok`)
23
- // }
24
- // return data.version
25
- // }
26
- // catch (err) {
27
- // throw new Error(`getVersion error: ${err}`)
28
- // }
29
- // }
30
- // async getResources(entity:Entity): Promise<ClusterValidPods> {
31
- // try {
32
- // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')
33
- // const targetUrl = `${baseUrl}/start`
34
- // var payload=JSON.stringify(entity)
35
- // const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})
36
- // const data = await result.json() as ClusterValidPods
37
- // if (!result.ok) {
38
- // throw new Error(`getResources error: not ok`)
39
- // }
40
- // return data
41
- // }
42
- // catch (err) {
43
- // throw new Error(`getResources error: ${err}`)
44
- // }
45
- // }
46
16
  async getResources(entity) {
47
17
  return getResources(this.discoveryApi, this.fetchApi, entity);
48
18
  }
49
19
  async requestAccess(entity, channel, scopes) {
50
20
  return requestAccess(this.discoveryApi, this.fetchApi, entity, channel, scopes);
51
21
  }
52
- //+++ move to backstage-common
53
- // async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {
54
- // try {
55
- // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')
56
- // var targetUrl:URL= new URL (`${baseUrl}/access`)
57
- // targetUrl.searchParams.append('scopes',scopes.join(','))
58
- // targetUrl.searchParams.append('channel',channel)
59
- // var payload=JSON.stringify(entity)
60
- // const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})
61
- // const data = await result.json() as ClusterValidPods[]
62
- // // we reconstruct the 'Map' from string of arrays
63
- // for (var c of data) {
64
- // c.accessKeys = new Map(JSON.parse(((c as any).accessKeys)))
65
- // }
66
- // if (!result.ok) {
67
- // throw new Error(`requestAccess error: not ok`)
68
- // }
69
- // return data
70
- // }
71
- // catch (err) {
72
- // throw new Error(`requestAccess error: ${err}`)
73
- // }
74
- // }
75
22
  }
76
23
 
77
24
  export { KwirthMetricsClient };
@@ -1 +1 @@
1
- {"version":3,"file":"KwirthMetricsClient.esm.js","sources":["../../src/api/KwirthMetricsClient.ts"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'\r\nimport { KwirthMetricsApi } from './types'\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { ClusterValidPods, getResources, getVersion, requestAccess } from '@jfvilas/plugin-kwirth-common'\r\nimport { InstanceConfigScopeEnum } from '@jfvilas/kwirth-common'\r\n\r\nexport interface KwirthMetricsClientOptions {\r\n discoveryApi: DiscoveryApi\r\n fetchApi: FetchApi\r\n}\r\n\r\nexport class KwirthMetricsClient implements KwirthMetricsApi {\r\n private readonly discoveryApi: DiscoveryApi\r\n private readonly fetchApi: FetchApi\r\n\r\n\r\n constructor(options: KwirthMetricsClientOptions) {\r\n this.discoveryApi = options.discoveryApi\r\n this.fetchApi = options.fetchApi\r\n }\r\n\r\n // +++ test\r\n async getVersion() : Promise<string> {\r\n return getVersion(this.discoveryApi, this.fetchApi)\r\n }\r\n\r\n // move to common\r\n // async getVersion(): Promise<string> {\r\n // try {\r\n // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')\r\n // const targetUrl = `${baseUrl}/version`\r\n\r\n // const result = await this.fetchApi.fetch(targetUrl)\r\n // const data = await result.json()\r\n\r\n // if (!result.ok) {\r\n // throw new Error(`getVersion error: not ok`)\r\n // }\r\n // return data.version\r\n // }\r\n // catch (err) {\r\n // throw new Error(`getVersion error: ${err}`)\r\n // }\r\n // }\r\n\r\n // async getResources(entity:Entity): Promise<ClusterValidPods> {\r\n // try {\r\n // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')\r\n // const targetUrl = `${baseUrl}/start`\r\n\r\n // var payload=JSON.stringify(entity)\r\n // const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})\r\n // const data = await result.json() as ClusterValidPods\r\n\r\n // if (!result.ok) {\r\n // throw new Error(`getResources error: not ok`)\r\n // }\r\n // return data\r\n // }\r\n // catch (err) {\r\n // throw new Error(`getResources error: ${err}`)\r\n // }\r\n // }\r\n async getResources(entity:Entity): Promise<ClusterValidPods> {\r\n return getResources(this.discoveryApi, this.fetchApi, entity)\r\n }\r\n\r\n async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {\r\n return requestAccess(this.discoveryApi, this.fetchApi, entity, channel, scopes)\r\n }\r\n\r\n //+++ move to backstage-common\r\n // async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {\r\n // try {\r\n // const baseUrl = await this.discoveryApi.getBaseUrl('kwirth')\r\n // var targetUrl:URL= new URL (`${baseUrl}/access`)\r\n // targetUrl.searchParams.append('scopes',scopes.join(','))\r\n // targetUrl.searchParams.append('channel',channel)\r\n\r\n // var payload=JSON.stringify(entity)\r\n // const result = await this.fetchApi.fetch(targetUrl, {method:'POST', body:payload, headers:{'Content-Type':'application/json'}})\r\n // const data = await result.json() as ClusterValidPods[]\r\n\r\n // // we reconstruct the 'Map' from string of arrays\r\n // for (var c of data) {\r\n // c.accessKeys = new Map(JSON.parse(((c as any).accessKeys)))\r\n // }\r\n // if (!result.ok) {\r\n // throw new Error(`requestAccess error: not ok`)\r\n // }\r\n // return data\r\n // }\r\n // catch (err) {\r\n // throw new Error(`requestAccess error: ${err}`)\r\n // }\r\n // }\r\n\r\n}\r\n"],"names":[],"mappings":";;AA0BO,MAAM,mBAAgD,CAAA;AAAA,EACxC,YAAA;AAAA,EACA,QAAA;AAAA,EAGjB,YAAY,OAAqC,EAAA;AAC7C,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA;AAC5B,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA;AAAA;AAC5B;AAAA,EAGA,MAAM,UAA+B,GAAA;AACjC,IAAA,OAAO,UAAW,CAAA,IAAA,CAAK,YAAc,EAAA,IAAA,CAAK,QAAQ,CAAA;AAAA;AACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuCA,MAAM,aAAa,MAA0C,EAAA;AACzD,IAAA,OAAO,YAAa,CAAA,IAAA,CAAK,YAAc,EAAA,IAAA,CAAK,UAAU,MAAM,CAAA;AAAA;AAChE,EAEA,MAAM,aAAA,CAAc,MAAe,EAAA,OAAA,EAAgB,MAA+D,EAAA;AAC9G,IAAA,OAAO,cAAc,IAAK,CAAA,YAAA,EAAc,KAAK,QAAU,EAAA,MAAA,EAAQ,SAAS,MAAM,CAAA;AAAA;AAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BJ;;;;"}
1
+ {"version":3,"file":"KwirthMetricsClient.esm.js","sources":["../../src/api/KwirthMetricsClient.ts"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'\r\nimport { KwirthMetricsApi } from './types'\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { ClusterValidPods, getInfo, getResources, getVersion, IBackendInfo, requestAccess } from '@jfvilas/plugin-kwirth-common'\r\nimport { InstanceConfigScopeEnum } from '@jfvilas/kwirth-common'\r\n\r\nexport interface KwirthMetricsClientOptions {\r\n discoveryApi: DiscoveryApi\r\n fetchApi: FetchApi\r\n}\r\n\r\nexport class KwirthMetricsClient implements KwirthMetricsApi {\r\n private readonly discoveryApi: DiscoveryApi\r\n private readonly fetchApi: FetchApi\r\n\r\n\r\n constructor(options: KwirthMetricsClientOptions) {\r\n this.discoveryApi = options.discoveryApi\r\n this.fetchApi = options.fetchApi\r\n }\r\n\r\n async getInfo() : Promise<IBackendInfo> {\r\n return getInfo(this.discoveryApi, this.fetchApi)\r\n }\r\n\r\n async getVersion() : Promise<string> {\r\n return getVersion(this.discoveryApi, this.fetchApi)\r\n }\r\n\r\n async getResources(entity:Entity): Promise<ClusterValidPods> {\r\n return getResources(this.discoveryApi, this.fetchApi, entity)\r\n }\r\n\r\n async requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]> {\r\n return requestAccess(this.discoveryApi, this.fetchApi, entity, channel, scopes)\r\n }\r\n\r\n}\r\n"],"names":[],"mappings":";;AA0BO,MAAM,mBAAA,CAAgD;AAAA,EACxC,YAAA;AAAA,EACA,QAAA;AAAA,EAGjB,YAAY,OAAA,EAAqC;AAC7C,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,QAAA;AAAA,EAC5B;AAAA,EAEA,MAAM,OAAA,GAAkC;AACpC,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,QAAQ,CAAA;AAAA,EACnD;AAAA,EAEA,MAAM,UAAA,GAA+B;AACjC,IAAA,OAAO,UAAA,CAAW,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,QAAQ,CAAA;AAAA,EACtD;AAAA,EAEA,MAAM,aAAa,MAAA,EAA0C;AACzD,IAAA,OAAO,YAAA,CAAa,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,UAAU,MAAM,CAAA;AAAA,EAChE;AAAA,EAEA,MAAM,aAAA,CAAc,MAAA,EAAe,OAAA,EAAgB,MAAA,EAA+D;AAC9G,IAAA,OAAO,cAAc,IAAA,CAAK,YAAA,EAAc,KAAK,QAAA,EAAU,MAAA,EAAQ,SAAS,MAAM,CAAA;AAAA,EAClF;AAEJ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.esm.js","sources":["../../src/api/types.ts"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { createApiRef } from '@backstage/core-plugin-api'\r\nimport { InstanceConfigScopeEnum } from '@jfvilas/kwirth-common'\r\nimport { ClusterValidPods } from '@jfvilas/plugin-kwirth-common'\r\n\r\nexport interface KwirthMetricsApi {\r\n requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]>\r\n getResources(entity:Entity): Promise<ClusterValidPods>\r\n getVersion(): Promise<string>\r\n}\r\n\r\nexport const kwirthMetricsApiRef = createApiRef<KwirthMetricsApi>({\r\n id: 'plugin.kwirthmetrics.api',\r\n})\r\n"],"names":[],"mappings":";;AA0BO,MAAM,sBAAsB,YAA+B,CAAA;AAAA,EAChE,EAAI,EAAA;AACN,CAAC;;;;"}
1
+ {"version":3,"file":"types.esm.js","sources":["../../src/api/types.ts"],"sourcesContent":["/*\r\nCopyright 2024 Julio Fernandez\r\n\r\nLicensed under the Apache License, Version 2.0 (the \"License\");\r\nyou may not use this file except in compliance with the License.\r\nYou may obtain a copy of the License at\r\n\r\n http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nUnless required by applicable law or agreed to in writing, software\r\ndistributed under the License is distributed on an \"AS IS\" BASIS,\r\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\nSee the License for the specific language governing permissions and\r\nlimitations under the License.\r\n*/\r\nimport { Entity } from '@backstage/catalog-model'\r\nimport { createApiRef } from '@backstage/core-plugin-api'\r\nimport { InstanceConfigScopeEnum } from '@jfvilas/kwirth-common'\r\nimport { ClusterValidPods, IBackendInfo } from '@jfvilas/plugin-kwirth-common'\r\n\r\nexport interface KwirthMetricsApi {\r\n requestAccess(entity:Entity, channel:string, scopes:InstanceConfigScopeEnum[]): Promise<ClusterValidPods[]>\r\n getResources(entity:Entity): Promise<ClusterValidPods>\r\n getVersion(): Promise<string>\r\n getInfo(): Promise<IBackendInfo>\r\n}\r\n\r\nexport const kwirthMetricsApiRef = createApiRef<KwirthMetricsApi>({\r\n id: 'plugin.kwirthmetrics.api',\r\n})\r\n"],"names":[],"mappings":";;AA2BO,MAAM,sBAAsB,YAAA,CAA+B;AAAA,EAChE,EAAA,EAAI;AACN,CAAC;;;;"}
@@ -2,20 +2,12 @@ import React, { useState, useRef } from 'react';
2
2
  import useAsync from 'react-use/esm/useAsync';
3
3
  import { Progress, WarningPanel } from '@backstage/core-components';
4
4
  import { useApi, alertApiRef } from '@backstage/core-plugin-api';
5
- import { isKwirthAvailable, ANNOTATION_BACKSTAGE_KUBERNETES_LABELID, ANNOTATION_BACKSTAGE_KUBERNETES_LABELSELECTOR } from '@jfvilas/plugin-kwirth-common';
5
+ import { isKwirthAvailable, ANNOTATION_BACKSTAGE_KUBERNETES_LABELID, ANNOTATION_BACKSTAGE_KUBERNETES_LABELSELECTOR, getPodList, getContainerList } from '@jfvilas/plugin-kwirth-common';
6
6
  import { useEntity, MissingAnnotationEmptyState } from '@backstage/plugin-catalog-react';
7
- import { kwirthMetricsApiRef } from '../../api/types.esm.js';
7
+ import { kwirthMetricsApiRef } from '../api/types.esm.js';
8
8
  import { SignalMessageLevelEnum, InstanceConfigScopeEnum, InstanceMessageTypeEnum, OpsCommandEnum, accessKeySerialize, InstanceMessageChannelEnum, InstanceMessageFlowEnum, InstanceMessageActionEnum, MetricsConfigModeEnum, InstanceConfigViewEnum, InstanceConfigObjectEnum } from '@jfvilas/kwirth-common';
9
- import { ComponentNotFound, ErrorType } from '../ComponentNotFound/ComponentNotFound.esm.js';
10
- import { Options } from '../Options/Options.esm.js';
11
- import { ClusterList } from '../ClusterList/ClusterList.esm.js';
12
- import { ObjectSelector } from '../ObjectSelector/ObjectSelector.esm.js';
13
- import { ShowError } from '../ShowError/ShowError.esm.js';
14
- import { StatusLog } from '../StatusLog/StatusLog.esm.js';
15
- import { Box, Grid, Card, CardHeader, CardContent, FormControl, Select, MenuItem, Checkbox } from '@material-ui/core';
16
- import Divider from '@material-ui/core/Divider';
17
- import IconButton from '@material-ui/core/IconButton';
18
- import Typography from '@material-ui/core/Typography';
9
+ import { ShowError, ComponentNotFound, ErrorType, ClusterList, KwirthNews, ObjectSelector, StatusLog } from '@jfvilas/plugin-kwirth-frontend';
10
+ import { Box, Grid, Card, CardHeader, Typography, FormControl, Select, MenuItem, Checkbox, Divider, CardContent, IconButton, Tooltip as Tooltip$1 } from '@material-ui/core';
19
11
  import PlayIcon from '@material-ui/icons/PlayArrow';
20
12
  import PauseIcon from '@material-ui/icons/Pause';
21
13
  import StopIcon from '@material-ui/icons/Stop';
@@ -23,14 +15,15 @@ import InfoIcon from '@material-ui/icons/Info';
23
15
  import WarningIcon from '@material-ui/icons/Warning';
24
16
  import ErrorIcon from '@material-ui/icons/Error';
25
17
  import RefreshIcon from '@material-ui/icons/Refresh';
26
- import KwirthMetricsLogo from '../../assets/kwirthmetrics-logo.svg';
18
+ import KwirthMetricsLogo from '../assets/kwirthmetrics-logo.svg';
27
19
  import { BarChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, LabelList, AreaChart, Area, LineChart, Line, ResponsiveContainer } from 'recharts';
20
+ import { Options } from './Options.esm.js';
28
21
 
29
22
  const EntityKwirthMetricsContent = (props) => {
30
23
  const kwirthMetricsApi = useApi(kwirthMetricsApiRef);
31
24
  const alertApi = useApi(alertApiRef);
32
25
  const { entity } = useEntity();
33
- const [clusterValidPods, setClusterValidPods] = useState([]);
26
+ const [validClusters, setValidClusters] = useState([]);
34
27
  const [selectedClusterName, setSelectedClusterName] = useState("");
35
28
  const [selectedNamespaces, setSelectedNamespaces] = useState([]);
36
29
  const [selectedPodNames, setSelectedPodNames] = useState([]);
@@ -44,10 +37,19 @@ const EntityKwirthMetricsContent = (props) => {
44
37
  const [statusMessages, setStatusMessages] = useState([]);
45
38
  const [websocket, setWebsocket] = useState();
46
39
  const [instance, setInstance] = useState();
47
- const kwirthMetricsOptionsRef = useRef({ depth: 10, width: 3, interval: 10, chart: "area", aggregate: false, merge: false, stack: false });
40
+ const kwirthMetricsOptionsRef = useRef({
41
+ depth: props.depth !== void 0 ? props.depth : 10,
42
+ width: props.width !== void 0 ? props.width : 3,
43
+ interval: props.interval !== void 0 ? props.interval : 15,
44
+ chart: props.chart !== void 0 ? props.chart : "area",
45
+ aggregate: false,
46
+ merge: false,
47
+ stack: false
48
+ });
48
49
  const [showStatusDialog, setShowStatusDialog] = useState(false);
49
50
  const [statusLevel, setStatusLevel] = useState(SignalMessageLevelEnum.INFO);
50
51
  const [backendVersion, setBackendVersion] = useState("");
52
+ const [backendInfo, setBackendInfo] = useState();
51
53
  const [_refresh, setRefresh] = useState(0);
52
54
  const [allMetrics, setAllMetrics] = useState(
53
55
  [
@@ -61,10 +63,11 @@ const EntityKwirthMetricsContent = (props) => {
61
63
  );
62
64
  const { loading, error } = useAsync(async () => {
63
65
  if (backendVersion === "") setBackendVersion(await kwirthMetricsApi.getVersion());
66
+ if (!backendInfo) setBackendInfo(await kwirthMetricsApi.getInfo());
64
67
  let reqScopes = [InstanceConfigScopeEnum.STREAM];
65
68
  if (props.enableRestart) reqScopes.push(InstanceConfigScopeEnum.RESTART);
66
69
  let data = await kwirthMetricsApi.requestAccess(entity, "metrics", reqScopes);
67
- setClusterValidPods(data);
70
+ setValidClusters(data);
68
71
  });
69
72
  const colours = [
70
73
  "#6e5bb8",
@@ -148,25 +151,32 @@ const EntityKwirthMetricsContent = (props) => {
148
151
  setStarted(false);
149
152
  paused.current = true;
150
153
  };
151
- const clickStop = () => {
154
+ const onClickStop = () => {
152
155
  setStarted(false);
153
156
  setStopped(true);
154
157
  paused.current = false;
155
158
  stopMetricsViewer();
156
159
  };
157
160
  const onSelectCluster = async (clusterName) => {
161
+ if (started) onClickStop();
158
162
  if (clusterName) {
159
163
  setSelectedClusterName(clusterName);
160
- setSelectedNamespaces([]);
161
164
  setSelectedPodNames([]);
162
165
  setSelectedContainerNames([]);
163
- setMetricsMessages([]);
164
166
  setStatusMessages([]);
165
- clickStop();
166
- let cluster = clusterValidPods.find((cluster2) => cluster2.name === clusterName);
167
- if (cluster && cluster.metrics) {
168
- cluster.metrics.sort((a, b) => a.metric.startsWith("kwirth") ? -1 : 1);
167
+ let cluster = validClusters.find((cluster2) => cluster2.name === clusterName);
168
+ if (cluster && cluster.pods && cluster.metrics) {
169
+ cluster.metrics.sort((a, _b) => a.metric.startsWith("kwirth") ? -1 : 1);
169
170
  setAllMetrics(cluster.metrics);
171
+ let validNamespaces = Array.from(new Set(cluster.pods.map((pod) => pod.namespace)));
172
+ if (validNamespaces.length === 1) {
173
+ setSelectedNamespaces(validNamespaces);
174
+ let podList = getPodList(cluster.pods, validNamespaces);
175
+ setSelectedPodNames(podList.map((pod) => pod.name));
176
+ setSelectedContainerNames(getContainerList(cluster.pods, validNamespaces, podList.map((pod) => pod.name)));
177
+ } else {
178
+ setSelectedNamespaces([]);
179
+ }
170
180
  }
171
181
  }
172
182
  };
@@ -196,24 +206,28 @@ const EntityKwirthMetricsContent = (props) => {
196
206
  setInstance(instanceMessage.instance);
197
207
  else {
198
208
  let signalMessage = instanceMessage;
199
- alertApi.post({ message: signalMessage.text, severity: "error", display: "transient" });
209
+ if (signalMessage.text) {
210
+ alertApi.post({ message: signalMessage.text, severity: "error", display: "transient" });
211
+ }
200
212
  }
201
213
  } else {
202
214
  let signalMessage = instanceMessage;
203
- addMessage(signalMessage.level, signalMessage.text);
204
- switch (signalMessage.level) {
205
- case SignalMessageLevelEnum.INFO:
206
- alertApi.post({ message: signalMessage.text, severity: "info", display: "transient" });
207
- break;
208
- case SignalMessageLevelEnum.WARNING:
209
- alertApi.post({ message: signalMessage.text, severity: "warning", display: "transient" });
210
- break;
211
- case SignalMessageLevelEnum.ERROR:
212
- alertApi.post({ message: signalMessage.text, severity: "error", display: "transient" });
213
- break;
214
- default:
215
- alertApi.post({ message: signalMessage.text, severity: "success", display: "transient" });
216
- break;
215
+ if (signalMessage.text) {
216
+ addMessage(signalMessage.level, signalMessage.text);
217
+ switch (signalMessage.level) {
218
+ case SignalMessageLevelEnum.INFO:
219
+ alertApi.post({ message: signalMessage.text, severity: "info", display: "transient" });
220
+ break;
221
+ case SignalMessageLevelEnum.WARNING:
222
+ alertApi.post({ message: signalMessage.text, severity: "warning", display: "transient" });
223
+ break;
224
+ case SignalMessageLevelEnum.ERROR:
225
+ alertApi.post({ message: signalMessage.text, severity: "error", display: "transient" });
226
+ break;
227
+ default:
228
+ alertApi.post({ message: signalMessage.text, severity: "success", display: "transient" });
229
+ break;
230
+ }
217
231
  }
218
232
  }
219
233
  break;
@@ -249,12 +263,12 @@ const EntityKwirthMetricsContent = (props) => {
249
263
  }
250
264
  };
251
265
  const websocketOnOpen = (ws) => {
252
- let cluster = clusterValidPods.find((cluster2) => cluster2.name === selectedClusterName);
266
+ let cluster = validClusters.find((cluster2) => cluster2.name === selectedClusterName);
253
267
  if (!cluster) {
254
268
  addMessage(SignalMessageLevelEnum.ERROR, "Cluster not found");
255
269
  return;
256
270
  }
257
- let pods = cluster.data.filter((p2) => selectedNamespaces.includes(p2.namespace));
271
+ let pods = cluster.pods.filter((p2) => selectedNamespaces.includes(p2.namespace));
258
272
  if (!pods || pods.length === 0) {
259
273
  addMessage(SignalMessageLevelEnum.ERROR, "Pod not found");
260
274
  return;
@@ -298,7 +312,7 @@ const EntityKwirthMetricsContent = (props) => {
298
312
  }
299
313
  };
300
314
  const startMetricsViewer = () => {
301
- let cluster = clusterValidPods.find((cluster2) => cluster2.name === selectedClusterName);
315
+ let cluster = validClusters.find((cluster2) => cluster2.name === selectedClusterName);
302
316
  if (!cluster) {
303
317
  addMessage(SignalMessageLevelEnum.ERROR, "Cluster not found");
304
318
  return;
@@ -328,28 +342,25 @@ const EntityKwirthMetricsContent = (props) => {
328
342
  };
329
343
  const actionButtons = () => {
330
344
  let hasStreamKey = false, hasRestartKey = false;
331
- let cluster = clusterValidPods.find((cluster2) => cluster2.name === selectedClusterName);
345
+ let cluster = validClusters.find((cluster2) => cluster2.name === selectedClusterName);
332
346
  if (cluster) {
333
347
  hasStreamKey = Boolean(cluster.accessKeys.has(InstanceConfigScopeEnum.STREAM));
334
348
  hasRestartKey = Boolean(cluster.accessKeys.get(InstanceConfigScopeEnum.RESTART));
335
349
  }
336
- return /* @__PURE__ */ React.createElement(React.Fragment, null, props.enableRestart && /* @__PURE__ */ React.createElement(IconButton, { title: "Restart", onClick: onClickRestart, disabled: selectedPodNames.length === 0 || !hasRestartKey || !websocket || !started }, /* @__PURE__ */ React.createElement(RefreshIcon, null)), /* @__PURE__ */ React.createElement(IconButton, { onClick: clickStart, title: "Play", disabled: started || !paused || selectedPodNames.length === 0 || selectedMetrics.length == 0 || !hasStreamKey }, /* @__PURE__ */ React.createElement(PlayIcon, null)), /* @__PURE__ */ React.createElement(IconButton, { onClick: clickPause, title: "Pause", disabled: !(started && !paused.current && selectedPodNames.length === 0) }, /* @__PURE__ */ React.createElement(PauseIcon, null)), /* @__PURE__ */ React.createElement(IconButton, { onClick: clickStop, title: "Stop", disabled: stopped || selectedPodNames.length === 0 }, /* @__PURE__ */ React.createElement(StopIcon, null)));
350
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, props.enableRestart && /* @__PURE__ */ React.createElement(IconButton, { title: "Restart", onClick: onClickRestart, disabled: selectedPodNames.length === 0 || !hasRestartKey || !websocket || !started }, /* @__PURE__ */ React.createElement(RefreshIcon, null)), /* @__PURE__ */ React.createElement(IconButton, { onClick: clickStart, title: "Play", disabled: started || !paused || selectedPodNames.length === 0 || selectedMetrics.length == 0 || !hasStreamKey }, /* @__PURE__ */ React.createElement(PlayIcon, null)), /* @__PURE__ */ React.createElement(IconButton, { onClick: clickPause, title: "Pause", disabled: !(started && !paused.current && selectedPodNames.length === 0) }, /* @__PURE__ */ React.createElement(PauseIcon, null)), /* @__PURE__ */ React.createElement(IconButton, { onClick: onClickStop, title: "Stop", disabled: stopped || selectedPodNames.length === 0 }, /* @__PURE__ */ React.createElement(StopIcon, null)));
337
351
  };
338
352
  const onMetricsChange = (event) => {
339
353
  setSelectedMetrics(event.target.value);
340
354
  };
341
- const metricsSelector = () => {
342
- let disabled = selectedClusterName === "" || selectedNamespaces.length === 0;
343
- return /* @__PURE__ */ React.createElement(FormControl, { style: { marginLeft: 16, width: "300px" }, size: "small" }, /* @__PURE__ */ React.createElement(Select, { value: selectedMetrics, MenuProps: { variant: "menu" }, multiple: true, onChange: onMetricsChange, renderValue: (selected) => selected.join(", "), disabled: disabled || started }, allMetrics.map(
344
- (m) => /* @__PURE__ */ React.createElement(MenuItem, { key: m.metric, value: m.metric, style: { marginTop: "-6px", marginBottom: "-6px" } }, /* @__PURE__ */ React.createElement(Checkbox, { checked: selectedMetrics.includes(m.metric), style: { marginTop: "-6px", marginBottom: "-6px" } }), /* @__PURE__ */ React.createElement(Typography, { style: { marginTop: "-6px", marginBottom: "-6px" } }, m.metric))
345
- )));
346
- };
347
355
  const statusButtons = (title) => {
348
356
  const show = (level) => {
349
357
  setShowStatusDialog(true);
350
358
  setStatusLevel(level);
351
359
  };
352
- return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, title)), /* @__PURE__ */ React.createElement(Grid, { item: true, style: { marginTop: "-8px" } }, /* @__PURE__ */ React.createElement(IconButton, { title: "info", disabled: !statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.INFO), onClick: () => show(SignalMessageLevelEnum.INFO) }, /* @__PURE__ */ React.createElement(InfoIcon, { style: { color: statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.INFO) ? "blue" : "#BDBDBD" } })), /* @__PURE__ */ React.createElement(IconButton, { title: "warning", disabled: !statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.WARNING), onClick: () => show(SignalMessageLevelEnum.WARNING), style: { marginLeft: "-16px" } }, /* @__PURE__ */ React.createElement(WarningIcon, { style: { color: statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.WARNING) ? "gold" : "#BDBDBD" } })), /* @__PURE__ */ React.createElement(IconButton, { title: "error", disabled: !statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.ERROR), onClick: () => show(SignalMessageLevelEnum.ERROR), style: { marginLeft: "-16px" } }, /* @__PURE__ */ React.createElement(ErrorIcon, { style: { color: statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.ERROR) ? "red" : "#BDBDBD" } }))), /* @__PURE__ */ React.createElement(Grid, { item: true }, metricsSelector()));
360
+ const prepareText = (txt) => {
361
+ return txt ? txt.length > 25 ? txt.substring(0, 25) + "..." : txt : "N/A";
362
+ };
363
+ return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, prepareText(title))), /* @__PURE__ */ React.createElement(Grid, { item: true, style: { marginTop: "-8px" } }, /* @__PURE__ */ React.createElement(IconButton, { title: "info", disabled: !statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.INFO), onClick: () => show(SignalMessageLevelEnum.INFO) }, /* @__PURE__ */ React.createElement(InfoIcon, { style: { color: statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.INFO) ? "blue" : "#BDBDBD" } })), /* @__PURE__ */ React.createElement(IconButton, { title: "warning", disabled: !statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.WARNING), onClick: () => show(SignalMessageLevelEnum.WARNING), style: { marginLeft: "-16px" } }, /* @__PURE__ */ React.createElement(WarningIcon, { style: { color: statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.WARNING) ? "gold" : "#BDBDBD" } })), /* @__PURE__ */ React.createElement(IconButton, { title: "error", disabled: !statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.ERROR), onClick: () => show(SignalMessageLevelEnum.ERROR), style: { marginLeft: "-16px" } }, /* @__PURE__ */ React.createElement(ErrorIcon, { style: { color: statusMessages.some((m) => m.type === InstanceMessageTypeEnum.SIGNAL && m.level === SignalMessageLevelEnum.ERROR) ? "red" : "#BDBDBD" } }))));
353
364
  };
354
365
  const statusClear = (level) => {
355
366
  setStatusMessages(statusMessages.filter((m) => m.level !== level));
@@ -382,7 +393,7 @@ const EntityKwirthMetricsContent = (props) => {
382
393
  switch (options.chart) {
383
394
  case "value":
384
395
  height = 40 + series.length * 80;
385
- result = /* @__PURE__ */ React.createElement(Grid, { direction: "row" }, /* @__PURE__ */ React.createElement(Typography, null, series.map((serie, index) => {
396
+ result = /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Typography, null, series.map((serie, index) => {
386
397
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, null, serie[serie.length - 1].value), /* @__PURE__ */ React.createElement(Typography, null, names[index]));
387
398
  })));
388
399
  break;
@@ -400,7 +411,16 @@ const EntityKwirthMetricsContent = (props) => {
400
411
  ));
401
412
  break;
402
413
  }
403
- return /* @__PURE__ */ React.createElement(Grid, { direction: "column", style: { width: "100%", marginBottom: 8 } }, /* @__PURE__ */ React.createElement(Typography, { align: "center" }, metric), /* @__PURE__ */ React.createElement(ResponsiveContainer, { height, key: metric + JSON.stringify(names) }, result));
414
+ let title = metric.metric.replaceAll("_", " ");
415
+ title = title[0].toLocaleUpperCase() + title.substring(1);
416
+ title = title.replaceAll("cpu", "CPU");
417
+ title = title.replaceAll(" fs ", " FS ");
418
+ title = title.replaceAll(" io ", " IO ");
419
+ title = title.replaceAll("oom", "OOM");
420
+ title = title.replaceAll("nvm", "NVM");
421
+ title = title.replaceAll("rss", "RSS");
422
+ title = title.replaceAll("failcnt", "fail count");
423
+ return /* @__PURE__ */ React.createElement(Grid, { style: { width: "100%", marginBottom: 32 } }, /* @__PURE__ */ React.createElement(Tooltip$1, { title: /* @__PURE__ */ React.createElement(Typography, { style: { fontSize: 12 } }, /* @__PURE__ */ React.createElement("b", null, metric.metric), /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("br", null), metric.help) }, /* @__PURE__ */ React.createElement(Typography, { align: "center" }, title)), /* @__PURE__ */ React.createElement(ResponsiveContainer, { height, key: metric + JSON.stringify(names) }, result));
404
424
  };
405
425
  const showMetrics = (options) => {
406
426
  if (!metricsMessages || metricsMessages.length === 0) {
@@ -409,6 +429,8 @@ const EntityKwirthMetricsContent = (props) => {
409
429
  else
410
430
  return /* @__PURE__ */ React.createElement(React.Fragment, null, started ? /* @__PURE__ */ React.createElement(Typography, null, "Waiting for first data, be patient...") : /* @__PURE__ */ React.createElement(Typography, null, "Configure ", /* @__PURE__ */ React.createElement("b", null, "chart options"), ", select some ", /* @__PURE__ */ React.createElement("b", null, "metrics on top"), ", and ", /* @__PURE__ */ React.createElement("b", null, "press PLAY"), " on top-right button to start viewing."));
411
431
  }
432
+ let cluster = validClusters.find((cluster2) => cluster2.name === selectedClusterName);
433
+ if (!cluster) return;
412
434
  let data = /* @__PURE__ */ new Map();
413
435
  for (let metricsMessage of metricsMessages) {
414
436
  let ts = new Date(metricsMessage.timestamp);
@@ -428,10 +450,11 @@ const EntityKwirthMetricsContent = (props) => {
428
450
  var firstAsset = assetNames[0];
429
451
  var allMetrics2 = Array.from(new Set(data.get(firstAsset).keys()));
430
452
  for (let metric of allMetrics2) {
453
+ let metricDefinition = cluster.metrics?.find((m) => m.metric === metric);
431
454
  var series = assetNames.map((an) => {
432
455
  return data.get(an).get(metric);
433
456
  });
434
- allCharts.push(/* @__PURE__ */ React.createElement(React.Fragment, null, addChart(options, metric, assetNames, series, "")));
457
+ allCharts.push(/* @__PURE__ */ React.createElement(React.Fragment, null, addChart(options, metricDefinition, assetNames, series, "")));
435
458
  }
436
459
  let rows = [];
437
460
  for (let i2 = 0; i2 < allCharts.length; i2 += options.width) {
@@ -442,7 +465,8 @@ const EntityKwirthMetricsContent = (props) => {
442
465
  let allCharts2 = Array.from(data.keys()).map((asset, index) => {
443
466
  return Array.from(data.get(asset)?.keys()).map((metric) => {
444
467
  var serie = data.get(asset)?.get(metric);
445
- return /* @__PURE__ */ React.createElement(React.Fragment, null, addChart(options, metric, [asset], [serie], colours[index]));
468
+ let metricDefinition = cluster.metrics?.find((m) => m.metric === metric);
469
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, addChart(options, metricDefinition, [asset], [serie], colours[index]));
446
470
  });
447
471
  });
448
472
  let rows = [];
@@ -467,7 +491,7 @@ const EntityKwirthMetricsContent = (props) => {
467
491
  }]);
468
492
  };
469
493
  const onClickRestart = () => {
470
- let cluster = clusterValidPods.find((cluster2) => cluster2.name === selectedClusterName);
494
+ let cluster = validClusters.find((cluster2) => cluster2.name === selectedClusterName);
471
495
  if (!cluster) {
472
496
  addMessage(SignalMessageLevelEnum.ERROR, "No cluster selected");
473
497
  return;
@@ -481,7 +505,7 @@ const EntityKwirthMetricsContent = (props) => {
481
505
  addMessage(SignalMessageLevelEnum.ERROR, "No instance has been established");
482
506
  return;
483
507
  }
484
- let pods = cluster.data.filter((pod) => selectedNamespaces.includes(pod.namespace));
508
+ let pods = cluster.pods.filter((pod) => selectedNamespaces.includes(pod.namespace));
485
509
  for (let pod of pods) {
486
510
  let om = {
487
511
  msgtype: "opsmessage",
@@ -512,14 +536,9 @@ const EntityKwirthMetricsContent = (props) => {
512
536
  websocket?.send(JSON.stringify(rm));
513
537
  }
514
538
  };
515
- return /* @__PURE__ */ React.createElement(React.Fragment, null, showError !== "" && /* @__PURE__ */ React.createElement(ShowError, { message: showError, onClose: () => setShowError("") }), loading && /* @__PURE__ */ React.createElement(Progress, null), !isKwirthAvailable(entity) && !loading && error && /* @__PURE__ */ React.createElement(WarningPanel, { title: "An error has ocurred while obtaining data from kuebernetes clusters.", message: error?.message }), !isKwirthAvailable(entity) && !loading && /* @__PURE__ */ React.createElement(MissingAnnotationEmptyState, { readMoreUrl: "https://github.com/jfvilas/kwirth", annotation: [ANNOTATION_BACKSTAGE_KUBERNETES_LABELID, ANNOTATION_BACKSTAGE_KUBERNETES_LABELSELECTOR] }), isKwirthAvailable(entity) && !loading && clusterValidPods && clusterValidPods.length === 0 && /* @__PURE__ */ React.createElement(ComponentNotFound, { error: ErrorType.NO_CLUSTERS, entity }), isKwirthAvailable(entity) && !loading && clusterValidPods && clusterValidPods.length > 0 && clusterValidPods.reduce((sum, cluster) => sum + cluster.data.length, 0) === 0 && /* @__PURE__ */ React.createElement(ComponentNotFound, { error: ErrorType.NO_PODS, entity }), isKwirthAvailable(entity) && !loading && clusterValidPods && clusterValidPods.length > 0 && clusterValidPods.reduce((sum, cluster) => sum + cluster.data.length, 0) > 0 && /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex" } }, /* @__PURE__ */ React.createElement(Box, { sx: { width: "200px" } }, /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "column" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(ClusterList, { resources: clusterValidPods, selectedClusterName, onSelect: onSelectCluster }))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(Options, { options: kwirthMetricsOptionsRef.current, selectedNamespaces, selectedPodNames, selectedContainerNames, onChange: onChangeOptions, disabled: selectedNamespaces.length === 0 || paused.current }))))), /* @__PURE__ */ React.createElement(Box, { sx: { flexGrow: 1, p: 1 } }, !selectedClusterName && /* @__PURE__ */ React.createElement("img", { src: KwirthMetricsLogo, alt: "No cluster selected", style: { left: "40%", marginTop: "10%", width: "20%", position: "relative" } }), selectedClusterName && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Card, { style: { marginTop: -8 } }, /* @__PURE__ */ React.createElement(
516
- CardHeader,
517
- {
518
- title: statusButtons(selectedClusterName),
519
- style: { marginTop: -4, marginBottom: 4, flexShrink: 0 },
520
- action: actionButtons()
521
- }
522
- ), /* @__PURE__ */ React.createElement(Typography, { style: { marginLeft: 16, marginBottom: 4 } }, /* @__PURE__ */ React.createElement(ObjectSelector, { cluster: clusterValidPods.find((cluster) => cluster.name === selectedClusterName), onSelect: onSelectObject, disabled: selectedClusterName === "" || started || paused.current, selectedNamespaces, selectedPodNames, selectedContainerNames, scope: InstanceConfigScopeEnum.STREAM })), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(CardContent, { style: { overflow: "auto" } }, showMetrics(kwirthMetricsOptionsRef.current)))))), showStatusDialog && /* @__PURE__ */ React.createElement(StatusLog, { level: statusLevel, onClose: () => setShowStatusDialog(false), statusMessages, onClear: statusClear }));
539
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, showError !== "" && /* @__PURE__ */ React.createElement(ShowError, { message: showError, onClose: () => setShowError("") }), loading && /* @__PURE__ */ React.createElement(Progress, null), !isKwirthAvailable(entity) && !loading && error && /* @__PURE__ */ React.createElement(WarningPanel, { title: "An error has ocurred while obtaining data from kuebernetes clusters.", message: error?.message }), !isKwirthAvailable(entity) && !loading && /* @__PURE__ */ React.createElement(MissingAnnotationEmptyState, { readMoreUrl: "https://github.com/jfvilas/kwirth", annotation: [ANNOTATION_BACKSTAGE_KUBERNETES_LABELID, ANNOTATION_BACKSTAGE_KUBERNETES_LABELSELECTOR] }), isKwirthAvailable(entity) && !loading && validClusters && validClusters.length === 0 && /* @__PURE__ */ React.createElement(ComponentNotFound, { error: ErrorType.NO_CLUSTERS, entity }), isKwirthAvailable(entity) && !loading && validClusters && validClusters.length > 0 && validClusters.reduce((sum, cluster) => sum + cluster.pods.length, 0) === 0 && /* @__PURE__ */ React.createElement(ComponentNotFound, { error: ErrorType.NO_PODS, entity }), isKwirthAvailable(entity) && !loading && validClusters && validClusters.length > 0 && validClusters.reduce((sum, cluster) => sum + cluster.pods.length, 0) > 0 && /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex" } }, /* @__PURE__ */ React.createElement(Box, { sx: { width: "200px", maxWidth: "200px" } }, /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "column" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(ClusterList, { resources: validClusters, selectedClusterName, onSelect: onSelectCluster }))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(Options, { metricsOptions: kwirthMetricsOptionsRef.current, selectedNamespaces, selectedPodNames, selectedContainerNames, onChange: onChangeOptions, disabled: selectedNamespaces.length === 0 || paused.current }))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(KwirthNews, { latestVersions: backendInfo, backendVersion }))))), /* @__PURE__ */ React.createElement(Box, { sx: { flexGrow: 1, p: 1, marginLeft: "8px" } }, !selectedClusterName && /* @__PURE__ */ React.createElement("img", { src: KwirthMetricsLogo, alt: "No cluster selected", style: { left: "40%", marginTop: "10%", width: "20%", position: "relative" } }), selectedClusterName && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Card, { style: { marginTop: -8 } }, /* @__PURE__ */ React.createElement(CardHeader, { title: statusButtons(selectedClusterName), style: { marginTop: -4, marginBottom: 4, flexShrink: 0 }, action: actionButtons() }), /* @__PURE__ */ React.createElement(Grid, { container: true, style: { alignItems: "end" } }, /* @__PURE__ */ React.createElement(Grid, { item: true, style: { width: "66%" } }, /* @__PURE__ */ React.createElement(Typography, { style: { marginLeft: 14 } }, /* @__PURE__ */ React.createElement(ObjectSelector, { cluster: validClusters.find((cluster) => cluster.name === selectedClusterName), onSelect: onSelectObject, disabled: selectedClusterName === "" || started || paused.current, selectedNamespaces, selectedPodNames, selectedContainerNames, scope: InstanceConfigScopeEnum.STREAM }))), /* @__PURE__ */ React.createElement(Grid, { item: true, style: { width: "33%", marginLeft: 0, marginBottom: 6, maxWidth: "33%" } }, /* @__PURE__ */ React.createElement(FormControl, { style: { width: "100%" } }, /* @__PURE__ */ React.createElement(Select, { value: selectedMetrics, MenuProps: { variant: "menu" }, multiple: true, onChange: onMetricsChange, renderValue: (selected) => selected.join(", ").substring(0, 40) + "...", disabled: selectedClusterName === "" || selectedNamespaces.length === 0 || started }, allMetrics.map(
540
+ (m) => /* @__PURE__ */ React.createElement(MenuItem, { key: m.metric, value: m.metric, style: { marginTop: "-8px", marginBottom: "-8px" } }, /* @__PURE__ */ React.createElement(Checkbox, { checked: selectedMetrics.includes(m.metric), style: { marginTop: "-8px", marginBottom: "-8px" } }), /* @__PURE__ */ React.createElement(Typography, { style: { marginTop: "-8px", marginBottom: "-8px" } }, m.metric))
541
+ ))))), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(CardContent, { style: { overflow: "auto" } }, showMetrics(kwirthMetricsOptionsRef.current)))))), showStatusDialog && /* @__PURE__ */ React.createElement(StatusLog, { level: statusLevel, onClose: () => setShowStatusDialog(false), statusMessages, onClear: statusClear }));
523
542
  };
524
543
 
525
544
  export { EntityKwirthMetricsContent };