@backstage/plugin-kubernetes 0.4.22 → 0.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @backstage/plugin-kubernetes
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c010632f88: Add pod metrics lookup and display in pod table.
8
+
9
+ ## Backwards incompatible changes
10
+
11
+ If your Kubernetes distribution does not have the [metrics server](https://github.com/kubernetes-sigs/metrics-server) installed,
12
+ you will need to set the `skipMetricsLookup` config flag to `false`.
13
+
14
+ See the [configuration docs](https://backstage.io/docs/features/kubernetes/configuration) for more details.
15
+
16
+ ### Patch Changes
17
+
18
+ - cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used.
19
+ - Updated dependencies
20
+ - @backstage/core-components@0.8.0
21
+ - @backstage/core-plugin-api@0.3.0
22
+ - @backstage/plugin-kubernetes-common@0.2.0
23
+ - @backstage/plugin-catalog-react@0.6.5
24
+
3
25
  ## 0.4.22
4
26
 
5
27
  ### Patch Changes
package/dist/index.esm.js CHANGED
@@ -4,7 +4,7 @@ import React__default, { Fragment, useState, useEffect, useContext } from 'react
4
4
  import { useEntity } from '@backstage/plugin-catalog-react';
5
5
  import { Routes, Route } from 'react-router-dom';
6
6
  import { Typography, Chip, Grid, makeStyles, createStyles, Button, Drawer, IconButton, FormControlLabel, Switch, Accordion, AccordionSummary, AccordionDetails, Divider, Stepper, Step, StepLabel } from '@material-ui/core';
7
- import { WarningPanel, InfoCard, Table, SubvalueCell, StatusError, StatusOK, StatusAborted, Button as Button$1, CodeSnippet, StructuredMetadataTable, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
7
+ import { WarningPanel, InfoCard, Table, StatusOK, SubvalueCell, StatusError, StatusAborted, Button as Button$1, CodeSnippet, StructuredMetadataTable, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
8
8
  import EmptyStateImage from './assets/emptystate.svg';
9
9
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
10
10
  import Close from '@material-ui/icons/Close';
@@ -45,7 +45,7 @@ class KubernetesBackendClient {
45
45
  method: "POST",
46
46
  headers: {
47
47
  "Content-Type": "application/json",
48
- ...idToken && {Authorization: `Bearer ${idToken}`}
48
+ ...idToken && { Authorization: `Bearer ${idToken}` }
49
49
  },
50
50
  body: JSON.stringify(requestBody)
51
51
  });
@@ -60,7 +60,7 @@ class KubernetesBackendClient {
60
60
  const response = await fetch(url, {
61
61
  method: "GET",
62
62
  headers: {
63
- ...idToken && {Authorization: `Bearer ${idToken}`}
63
+ ...idToken && { Authorization: `Bearer ${idToken}` }
64
64
  }
65
65
  });
66
66
  return (await this.handleResponse(response)).items;
@@ -86,7 +86,7 @@ class GoogleKubernetesAuthProvider {
86
86
  if ("auth" in requestBody) {
87
87
  requestBody.auth.google = googleAuthToken;
88
88
  } else {
89
- requestBody.auth = {google: googleAuthToken};
89
+ requestBody.auth = { google: googleAuthToken };
90
90
  }
91
91
  return requestBody;
92
92
  }
@@ -106,7 +106,7 @@ class AwsKubernetesAuthProvider {
106
106
 
107
107
  class KubernetesAuthProviders {
108
108
  constructor(options) {
109
- this.kubernetesAuthProviderMap = new Map();
109
+ this.kubernetesAuthProviderMap = /* @__PURE__ */ new Map();
110
110
  this.kubernetesAuthProviderMap.set("google", new GoogleKubernetesAuthProvider(options.googleAuthApi));
111
111
  this.kubernetesAuthProviderMap.set("serviceAccount", new ServiceAccountKubernetesAuthProvider());
112
112
  this.kubernetesAuthProviderMap.set("aws", new AwsKubernetesAuthProvider());
@@ -132,13 +132,13 @@ const kubernetesPlugin = createPlugin({
132
132
  discoveryApi: discoveryApiRef,
133
133
  identityApi: identityApiRef
134
134
  },
135
- factory: ({discoveryApi, identityApi}) => new KubernetesBackendClient({discoveryApi, identityApi})
135
+ factory: ({ discoveryApi, identityApi }) => new KubernetesBackendClient({ discoveryApi, identityApi })
136
136
  }),
137
137
  createApiFactory({
138
138
  api: kubernetesAuthProvidersApiRef,
139
- deps: {googleAuthApi: googleAuthApiRef},
140
- factory: ({googleAuthApi}) => {
141
- return new KubernetesAuthProviders({googleAuthApi});
139
+ deps: { googleAuthApi: googleAuthApiRef },
140
+ factory: ({ googleAuthApi }) => {
141
+ return new KubernetesAuthProviders({ googleAuthApi });
142
142
  }
143
143
  })
144
144
  ],
@@ -241,7 +241,7 @@ const ErrorEmptyState = () => {
241
241
  "data-testid": "emptyStateImg"
242
242
  })));
243
243
  };
244
- const ErrorReporting = ({detectedErrors}) => {
244
+ const ErrorReporting = ({ detectedErrors }) => {
245
245
  const errors = Array.from(detectedErrors.values()).flat().sort(sortBySeverity);
246
246
  return /* @__PURE__ */ React.createElement(React.Fragment, null, errors.length === 0 ? /* @__PURE__ */ React.createElement(InfoCard, {
247
247
  title: "Error Reporting"
@@ -249,7 +249,7 @@ const ErrorReporting = ({detectedErrors}) => {
249
249
  title: "Error Reporting",
250
250
  data: errors,
251
251
  columns,
252
- options: {paging: true, search: false}
252
+ options: { paging: true, search: false }
253
253
  }));
254
254
  };
255
255
 
@@ -372,10 +372,36 @@ const renderCondition = (condition) => {
372
372
  }
373
373
  return [condition.type, /* @__PURE__ */ React__default.createElement(StatusAborted, null)];
374
374
  };
375
+ const currentToDeclaredResourceToPerc = (current, resource) => {
376
+ if (typeof current === "number" && typeof resource === "number") {
377
+ return `${Math.round(current / resource * 100)}%`;
378
+ }
379
+ const numerator = BigInt(current);
380
+ const denominator = BigInt(resource);
381
+ return `${numerator * BigInt(100) / denominator}%`;
382
+ };
383
+ const podStatusToCpuUtil = (podStatus) => {
384
+ const cpuUtil = podStatus.cpu;
385
+ let currentUsage = cpuUtil.currentUsage;
386
+ if (typeof cpuUtil.currentUsage === "number") {
387
+ currentUsage = cpuUtil.currentUsage / 10;
388
+ }
389
+ return /* @__PURE__ */ React__default.createElement(SubvalueCell, {
390
+ value: `requests: ${currentToDeclaredResourceToPerc(currentUsage, cpuUtil.requestTotal)}`,
391
+ subvalue: `limits: ${currentToDeclaredResourceToPerc(currentUsage, cpuUtil.limitTotal)}`
392
+ });
393
+ };
394
+ const podStatusToMemoryUtil = (podStatus) => {
395
+ const memUtil = podStatus.memory;
396
+ return /* @__PURE__ */ React__default.createElement(SubvalueCell, {
397
+ value: `requests: ${currentToDeclaredResourceToPerc(memUtil.currentUsage, memUtil.requestTotal)}`,
398
+ subvalue: `limits: ${currentToDeclaredResourceToPerc(memUtil.currentUsage, memUtil.limitTotal)}`
399
+ });
400
+ };
375
401
 
376
402
  const detectErrorsInObjects = (objects, kind, clusterName, errorMappers) => {
377
403
  var _a, _b;
378
- const errors = new Map();
404
+ const errors = /* @__PURE__ */ new Map();
379
405
  for (const object of objects) {
380
406
  for (const errorMapper of errorMappers) {
381
407
  if (errorMapper.errorExists(object)) {
@@ -523,7 +549,7 @@ const hpaErrorMappers = [
523
549
  const detectErrorsInHpa = (hpas, clusterName) => detectErrorsInObjects(hpas, "HorizontalPodAutoscaler", clusterName, hpaErrorMappers);
524
550
 
525
551
  const detectErrors = (objects) => {
526
- const errors = new Map();
552
+ const errors = /* @__PURE__ */ new Map();
527
553
  for (const clusterResponse of objects.items) {
528
554
  let clusterErrors = [];
529
555
  const groupedResponses = groupResponses(clusterResponse.resources);
@@ -581,7 +607,7 @@ const useKubernetesObjects = (entity, intervalMs = 1e4) => {
581
607
  };
582
608
  };
583
609
 
584
- const PodNamesWithErrorsContext = React__default.createContext(new Set());
610
+ const PodNamesWithErrorsContext = React__default.createContext(/* @__PURE__ */ new Set());
585
611
 
586
612
  const GroupedResponsesContext = React__default.createContext({
587
613
  pods: [],
@@ -761,7 +787,7 @@ const PodDrawerButton = withStyles({
761
787
  textTransform: "none"
762
788
  }
763
789
  })(Button);
764
- const ErrorPanel = ({cluster, errorMessage}) => /* @__PURE__ */ React__default.createElement(WarningPanel, {
790
+ const ErrorPanel = ({ cluster, errorMessage }) => /* @__PURE__ */ React__default.createElement(WarningPanel, {
765
791
  title: "There was a problem formatting the link to the Kubernetes dashboard",
766
792
  message: `Could not format the link to the dashboard of your cluster named '${cluster.name}'. Its dashboardApp property has been set to '${cluster.dashboardApp || "standard"}.'`
767
793
  }, errorMessage && /* @__PURE__ */ React__default.createElement(Typography, {
@@ -794,7 +820,7 @@ const KubernetesDrawerContent = ({
794
820
  const [isYaml, setIsYaml] = useState(false);
795
821
  const classes = useDrawerContentStyles();
796
822
  const cluster = useContext(ClusterContext);
797
- const {clusterLink, errorMessage} = tryFormatClusterLink({
823
+ const { clusterLink, errorMessage } = tryFormatClusterLink({
798
824
  dashboardUrl: cluster.dashboardUrl,
799
825
  dashboardApp: cluster.dashboardApp,
800
826
  object,
@@ -923,6 +949,10 @@ const PodDrawer = ({
923
949
  });
924
950
  };
925
951
 
952
+ const PodNamesWithMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
953
+
954
+ const READY_COLUMNS = "READY";
955
+ const RESOURCE_COLUMNS = "RESOURCE";
926
956
  const DEFAULT_COLUMNS = [
927
957
  {
928
958
  title: "name",
@@ -943,7 +973,52 @@ const DEFAULT_COLUMNS = [
943
973
  render: containerStatuses
944
974
  }
945
975
  ];
946
- const PodsTable = ({pods, extraColumns = []}) => {
976
+ const READY = [
977
+ {
978
+ title: "containers ready",
979
+ align: "center",
980
+ render: containersReady
981
+ },
982
+ {
983
+ title: "total restarts",
984
+ align: "center",
985
+ render: totalRestarts,
986
+ type: "numeric"
987
+ }
988
+ ];
989
+ const PodsTable = ({ pods, extraColumns = [] }) => {
990
+ const podNamesWithMetrics = useContext(PodNamesWithMetricsContext);
991
+ const columns = [...DEFAULT_COLUMNS];
992
+ if (extraColumns.includes(READY_COLUMNS)) {
993
+ columns.push(...READY);
994
+ }
995
+ if (extraColumns.includes(RESOURCE_COLUMNS)) {
996
+ const resourceColumns = [
997
+ {
998
+ title: "CPU usage %",
999
+ render: (pod) => {
1000
+ var _a, _b;
1001
+ const metrics = podNamesWithMetrics.get((_b = (_a = pod.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1002
+ if (!metrics) {
1003
+ return "unknown";
1004
+ }
1005
+ return podStatusToCpuUtil(metrics);
1006
+ }
1007
+ },
1008
+ {
1009
+ title: "Memory usage %",
1010
+ render: (pod) => {
1011
+ var _a, _b;
1012
+ const metrics = podNamesWithMetrics.get((_b = (_a = pod.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1013
+ if (!metrics) {
1014
+ return "unknown";
1015
+ }
1016
+ return podStatusToMemoryUtil(metrics);
1017
+ }
1018
+ }
1019
+ ];
1020
+ columns.push(...resourceColumns);
1021
+ }
947
1022
  const tableStyle = {
948
1023
  minWidth: "0",
949
1024
  width: "100%"
@@ -951,9 +1026,9 @@ const PodsTable = ({pods, extraColumns = []}) => {
951
1026
  return /* @__PURE__ */ React__default.createElement("div", {
952
1027
  style: tableStyle
953
1028
  }, /* @__PURE__ */ React__default.createElement(Table, {
954
- options: {paging: true, search: false},
1029
+ options: { paging: true, search: false },
955
1030
  data: pods,
956
- columns: DEFAULT_COLUMNS.concat(extraColumns)
1031
+ columns
957
1032
  }));
958
1033
  };
959
1034
 
@@ -1047,19 +1122,6 @@ const getMatchingHpa = (ownerName, ownerKind, hpas) => {
1047
1122
  });
1048
1123
  };
1049
1124
 
1050
- const deploymentPodColumns = [
1051
- {
1052
- title: "containers ready",
1053
- align: "center",
1054
- render: containersReady
1055
- },
1056
- {
1057
- title: "total restarts",
1058
- align: "center",
1059
- render: totalRestarts,
1060
- type: "numeric"
1061
- }
1062
- ];
1063
1125
  const DeploymentSummary = ({
1064
1126
  deployment,
1065
1127
  numberOfCurrentPods,
@@ -1081,7 +1143,7 @@ const DeploymentSummary = ({
1081
1143
  item: true,
1082
1144
  xs: 1
1083
1145
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1084
- style: {height: "5em"},
1146
+ style: { height: "5em" },
1085
1147
  orientation: "vertical"
1086
1148
  })), hpa && /* @__PURE__ */ React__default.createElement(Grid, {
1087
1149
  item: true,
@@ -1131,7 +1193,7 @@ const DeploymentAccordion = ({
1131
1193
  return podNamesWithErrors.has((_b = (_a = p.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1132
1194
  });
1133
1195
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1134
- TransitionProps: {unmountOnExit: true}
1196
+ TransitionProps: { unmountOnExit: true }
1135
1197
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1136
1198
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1137
1199
  }, /* @__PURE__ */ React__default.createElement(DeploymentSummary, {
@@ -1141,7 +1203,7 @@ const DeploymentAccordion = ({
1141
1203
  hpa: matchingHpa
1142
1204
  })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(PodsTable, {
1143
1205
  pods: ownedPods,
1144
- extraColumns: deploymentPodColumns
1206
+ extraColumns: [READY_COLUMNS, RESOURCE_COLUMNS]
1145
1207
  })));
1146
1208
  };
1147
1209
  const DeploymentsAccordions = ({}) => {
@@ -1199,7 +1261,7 @@ const IngressDrawer = ({
1199
1261
  }, "Ingress"))));
1200
1262
  };
1201
1263
 
1202
- const IngressSummary = ({ingress}) => {
1264
+ const IngressSummary = ({ ingress }) => {
1203
1265
  return /* @__PURE__ */ React__default.createElement(Grid, {
1204
1266
  container: true,
1205
1267
  direction: "row",
@@ -1214,20 +1276,20 @@ const IngressSummary = ({ingress}) => {
1214
1276
  item: true,
1215
1277
  xs: 1
1216
1278
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1217
- style: {height: "5em"},
1279
+ style: { height: "5em" },
1218
1280
  orientation: "vertical"
1219
1281
  })));
1220
1282
  };
1221
- const IngressCard = ({ingress}) => {
1283
+ const IngressCard = ({ ingress }) => {
1222
1284
  return /* @__PURE__ */ React__default.createElement(StructuredMetadataTable, {
1223
1285
  metadata: {
1224
1286
  ...ingress.spec
1225
1287
  }
1226
1288
  });
1227
1289
  };
1228
- const IngressAccordion = ({ingress}) => {
1290
+ const IngressAccordion = ({ ingress }) => {
1229
1291
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1230
- TransitionProps: {unmountOnExit: true}
1292
+ TransitionProps: { unmountOnExit: true }
1231
1293
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1232
1294
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1233
1295
  }, /* @__PURE__ */ React__default.createElement(IngressSummary, {
@@ -1282,7 +1344,7 @@ const ServiceDrawer = ({
1282
1344
  }, "Service"))));
1283
1345
  };
1284
1346
 
1285
- const ServiceSummary = ({service}) => {
1347
+ const ServiceSummary = ({ service }) => {
1286
1348
  var _a, _b;
1287
1349
  return /* @__PURE__ */ React__default.createElement(Grid, {
1288
1350
  container: true,
@@ -1298,7 +1360,7 @@ const ServiceSummary = ({service}) => {
1298
1360
  item: true,
1299
1361
  xs: 1
1300
1362
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1301
- style: {height: "5em"},
1363
+ style: { height: "5em" },
1302
1364
  orientation: "vertical"
1303
1365
  })), /* @__PURE__ */ React__default.createElement(Grid, {
1304
1366
  item: true
@@ -1306,7 +1368,7 @@ const ServiceSummary = ({service}) => {
1306
1368
  variant: "subtitle2"
1307
1369
  }, "Type: ", (_b = (_a = service.spec) == null ? void 0 : _a.type) != null ? _b : "?")));
1308
1370
  };
1309
- const ServiceCard = ({service}) => {
1371
+ const ServiceCard = ({ service }) => {
1310
1372
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1311
1373
  const metadata = {};
1312
1374
  if ((_d = (_c = (_b = (_a = service.status) == null ? void 0 : _a.loadBalancer) == null ? void 0 : _b.ingress) == null ? void 0 : _c.length) != null ? _d : -1 > 0) {
@@ -1326,9 +1388,9 @@ const ServiceCard = ({service}) => {
1326
1388
  }
1327
1389
  });
1328
1390
  };
1329
- const ServiceAccordion = ({service}) => {
1391
+ const ServiceAccordion = ({ service }) => {
1330
1392
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1331
- TransitionProps: {unmountOnExit: true}
1393
+ TransitionProps: { unmountOnExit: true }
1332
1394
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1333
1395
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1334
1396
  }, /* @__PURE__ */ React__default.createElement(ServiceSummary, {
@@ -1389,7 +1451,7 @@ const JobDrawer = ({
1389
1451
  }, "Job"))));
1390
1452
  };
1391
1453
 
1392
- const JobSummary = ({job}) => {
1454
+ const JobSummary = ({ job }) => {
1393
1455
  var _a, _b, _c, _d, _e, _f;
1394
1456
  return /* @__PURE__ */ React__default.createElement(Grid, {
1395
1457
  container: true,
@@ -1405,7 +1467,7 @@ const JobSummary = ({job}) => {
1405
1467
  item: true,
1406
1468
  xs: 1
1407
1469
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1408
- style: {height: "5em"},
1470
+ style: { height: "5em" },
1409
1471
  orientation: "vertical"
1410
1472
  })), /* @__PURE__ */ React__default.createElement(Grid, {
1411
1473
  item: true,
@@ -1422,9 +1484,9 @@ const JobSummary = ({job}) => {
1422
1484
  item: true
1423
1485
  }, "Completion time: ", job.status.completionTime.toString())));
1424
1486
  };
1425
- const JobAccordion = ({job, ownedPods}) => {
1487
+ const JobAccordion = ({ job, ownedPods }) => {
1426
1488
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1427
- TransitionProps: {unmountOnExit: true}
1489
+ TransitionProps: { unmountOnExit: true }
1428
1490
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1429
1491
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1430
1492
  }, /* @__PURE__ */ React__default.createElement(JobSummary, {
@@ -1433,7 +1495,7 @@ const JobAccordion = ({job, ownedPods}) => {
1433
1495
  pods: ownedPods
1434
1496
  })));
1435
1497
  };
1436
- const JobsAccordions = ({jobs}) => {
1498
+ const JobsAccordions = ({ jobs }) => {
1437
1499
  const groupedResponses = useContext(GroupedResponsesContext);
1438
1500
  return /* @__PURE__ */ React__default.createElement(Grid, {
1439
1501
  container: true,
@@ -1496,7 +1558,7 @@ const CronJobDrawer = ({
1496
1558
  }))));
1497
1559
  };
1498
1560
 
1499
- const CronJobSummary = ({cronJob}) => {
1561
+ const CronJobSummary = ({ cronJob }) => {
1500
1562
  var _a, _b;
1501
1563
  return /* @__PURE__ */ React__default.createElement(Grid, {
1502
1564
  container: true,
@@ -1512,7 +1574,7 @@ const CronJobSummary = ({cronJob}) => {
1512
1574
  item: true,
1513
1575
  xs: 1
1514
1576
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1515
- style: {height: "5em"},
1577
+ style: { height: "5em" },
1516
1578
  orientation: "vertical"
1517
1579
  })), /* @__PURE__ */ React__default.createElement(Grid, {
1518
1580
  item: true,
@@ -1529,9 +1591,9 @@ const CronJobSummary = ({cronJob}) => {
1529
1591
  variant: "body1"
1530
1592
  }, "Schedule:", " ", ((_b = cronJob.spec) == null ? void 0 : _b.schedule) ? `${cronJob.spec.schedule} (${cronstrue.toString(cronJob.spec.schedule)})` : "N/A"))));
1531
1593
  };
1532
- const CronJobAccordion = ({cronJob, ownedJobs}) => {
1594
+ const CronJobAccordion = ({ cronJob, ownedJobs }) => {
1533
1595
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1534
- TransitionProps: {unmountOnExit: true}
1596
+ TransitionProps: { unmountOnExit: true }
1535
1597
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1536
1598
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1537
1599
  }, /* @__PURE__ */ React__default.createElement(CronJobSummary, {
@@ -1660,7 +1722,7 @@ const RolloutSummary = ({
1660
1722
  item: true,
1661
1723
  xs: 1
1662
1724
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1663
- style: {height: "5em"},
1725
+ style: { height: "5em" },
1664
1726
  orientation: "vertical"
1665
1727
  })), hpa && /* @__PURE__ */ React__default.createElement(Grid, {
1666
1728
  item: true,
@@ -1708,7 +1770,7 @@ const RolloutSummary = ({
1708
1770
  }
1709
1771
  }, /* @__PURE__ */ React__default.createElement(PauseIcon, null), /* @__PURE__ */ React__default.createElement(Typography, {
1710
1772
  variant: "subtitle1"
1711
- }, "Paused (", DateTime.fromISO(pauseTime).toRelative({locale: "en"}), ")"))), abortedMessage && /* @__PURE__ */ React__default.createElement(Grid, {
1773
+ }, "Paused (", DateTime.fromISO(pauseTime).toRelative({ locale: "en" }), ")"))), abortedMessage && /* @__PURE__ */ React__default.createElement(Grid, {
1712
1774
  item: true,
1713
1775
  xs: 3
1714
1776
  }, AbortedTitle));
@@ -1729,7 +1791,7 @@ const RolloutAccordion = ({
1729
1791
  const abortedMessage = findAbortedMessage(rollout);
1730
1792
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1731
1793
  defaultExpanded,
1732
- TransitionProps: {unmountOnExit: true}
1794
+ TransitionProps: { unmountOnExit: true }
1733
1795
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1734
1796
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1735
1797
  }, /* @__PURE__ */ React__default.createElement(RolloutSummary, {
@@ -1738,11 +1800,11 @@ const RolloutAccordion = ({
1738
1800
  numberOfPodsWithErrors: podsWithErrors.length,
1739
1801
  hpa: matchingHpa
1740
1802
  })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement("div", {
1741
- style: {width: "100%"}
1803
+ style: { width: "100%" }
1742
1804
  }, /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(Typography, {
1743
1805
  variant: "h6"
1744
1806
  }, "Rollout status")), /* @__PURE__ */ React__default.createElement("div", {
1745
- style: {margin: "1rem"}
1807
+ style: { margin: "1rem" }
1746
1808
  }, abortedMessage && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, AbortedTitle, /* @__PURE__ */ React__default.createElement(Typography, {
1747
1809
  variant: "subtitle2"
1748
1810
  }, abortedMessage)), /* @__PURE__ */ React__default.createElement(StepsProgress, {
@@ -1750,7 +1812,8 @@ const RolloutAccordion = ({
1750
1812
  steps: (_f = (_e = (_d = (_c = rollout.spec) == null ? void 0 : _c.strategy) == null ? void 0 : _d.canary) == null ? void 0 : _e.steps) != null ? _f : [],
1751
1813
  currentStepIndex
1752
1814
  })), /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(PodsTable, {
1753
- pods: ownedPods
1815
+ pods: ownedPods,
1816
+ extraColumns: [READY_COLUMNS, RESOURCE_COLUMNS]
1754
1817
  })))));
1755
1818
  };
1756
1819
  const RolloutAccordions = ({
@@ -1832,7 +1895,7 @@ const DefaultCustomResourceSummary = ({
1832
1895
  item: true,
1833
1896
  xs: 1
1834
1897
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1835
- style: {height: "5em"},
1898
+ style: { height: "5em" },
1836
1899
  orientation: "vertical"
1837
1900
  })));
1838
1901
  };
@@ -1843,7 +1906,7 @@ const DefaultCustomResourceAccordion = ({
1843
1906
  }) => {
1844
1907
  return /* @__PURE__ */ React__default.createElement(Accordion, {
1845
1908
  defaultExpanded,
1846
- TransitionProps: {unmountOnExit: true}
1909
+ TransitionProps: { unmountOnExit: true }
1847
1910
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1848
1911
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1849
1912
  }, /* @__PURE__ */ React__default.createElement(DefaultCustomResourceSummary, {
@@ -1933,7 +1996,7 @@ const ClusterSummary = ({
1933
1996
  item: true,
1934
1997
  xs: 1
1935
1998
  }, /* @__PURE__ */ React__default.createElement(Divider, {
1936
- style: {height: "4em"},
1999
+ style: { height: "4em" },
1937
2000
  orientation: "vertical"
1938
2001
  })), /* @__PURE__ */ React__default.createElement(Grid, {
1939
2002
  item: true,
@@ -1948,16 +2011,26 @@ const ClusterSummary = ({
1948
2011
  item: true
1949
2012
  }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pods with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))));
1950
2013
  };
1951
- const Cluster = ({clusterObjects, podsWithErrors}) => {
2014
+ const Cluster = ({ clusterObjects, podsWithErrors }) => {
1952
2015
  const groupedResponses = groupResponses(clusterObjects.resources);
2016
+ const podNameToMetrics = clusterObjects.podMetrics.flat().reduce((accum, next) => {
2017
+ var _a;
2018
+ const name = (_a = next.pod.metadata) == null ? void 0 : _a.name;
2019
+ if (name !== void 0) {
2020
+ accum.set(name, next);
2021
+ }
2022
+ return accum;
2023
+ }, /* @__PURE__ */ new Map());
1953
2024
  return /* @__PURE__ */ React__default.createElement(ClusterContext.Provider, {
1954
2025
  value: clusterObjects.cluster
1955
2026
  }, /* @__PURE__ */ React__default.createElement(GroupedResponsesContext.Provider, {
1956
2027
  value: groupedResponses
2028
+ }, /* @__PURE__ */ React__default.createElement(PodNamesWithMetricsContext.Provider, {
2029
+ value: podNameToMetrics
1957
2030
  }, /* @__PURE__ */ React__default.createElement(PodNamesWithErrorsContext.Provider, {
1958
2031
  value: podsWithErrors
1959
2032
  }, /* @__PURE__ */ React__default.createElement(Accordion, {
1960
- TransitionProps: {unmountOnExit: true}
2033
+ TransitionProps: { unmountOnExit: true }
1961
2034
  }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1962
2035
  expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null)
1963
2036
  }, /* @__PURE__ */ React__default.createElement(ClusterSummary, {
@@ -1975,16 +2048,16 @@ const Cluster = ({clusterObjects, podsWithErrors}) => {
1975
2048
  item: true
1976
2049
  }, /* @__PURE__ */ React__default.createElement(IngressesAccordions, null)), /* @__PURE__ */ React__default.createElement(Grid, {
1977
2050
  item: true
1978
- }, /* @__PURE__ */ React__default.createElement(ServicesAccordions, null)), /* @__PURE__ */ React__default.createElement(Grid, {
2051
+ }, /* @__PURE__ */ React__default.createElement(ServicesAccordions, null))), /* @__PURE__ */ React__default.createElement(Grid, {
1979
2052
  item: true
1980
2053
  }, /* @__PURE__ */ React__default.createElement(CronJobsAccordions, null))))))));
1981
2054
  };
1982
2055
 
1983
- const KubernetesContent = ({entity}) => {
2056
+ const KubernetesContent = ({ entity }) => {
1984
2057
  var _a;
1985
- const {kubernetesObjects, error} = useKubernetesObjects(entity);
2058
+ const { kubernetesObjects, error } = useKubernetesObjects(entity);
1986
2059
  const clustersWithErrors = (_a = kubernetesObjects == null ? void 0 : kubernetesObjects.items.filter((r) => r.errors.length > 0)) != null ? _a : [];
1987
- const detectedErrors = kubernetesObjects !== void 0 ? detectErrors(kubernetesObjects) : new Map();
2060
+ const detectedErrors = kubernetesObjects !== void 0 ? detectErrors(kubernetesObjects) : /* @__PURE__ */ new Map();
1988
2061
  return /* @__PURE__ */ React__default.createElement(Page, {
1989
2062
  themeId: "tool"
1990
2063
  }, /* @__PURE__ */ React__default.createElement(Content, null, kubernetesObjects === void 0 && error === void 0 && /* @__PURE__ */ React__default.createElement(Progress, null), clustersWithErrors.length > 0 && /* @__PURE__ */ React__default.createElement(Grid, {
@@ -2062,7 +2135,7 @@ const isKubernetesAvailable = (entity) => {
2062
2135
  };
2063
2136
  const Router = (_props) => {
2064
2137
  var _a, _b;
2065
- const {entity} = useEntity();
2138
+ const { entity } = useEntity();
2066
2139
  const kubernetesAnnotationValue = (_a = entity.metadata.annotations) == null ? void 0 : _a[KUBERNETES_ANNOTATION];
2067
2140
  const kubernetesLabelSelectorQueryAnnotationValue = (_b = entity.metadata.annotations) == null ? void 0 : _b[KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION];
2068
2141
  if (kubernetesAnnotationValue || kubernetesLabelSelectorQueryAnnotationValue) {