@backstage/plugin-kubernetes 0.9.2-next.2 → 0.9.2

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,37 @@
1
1
  # @backstage/plugin-kubernetes
2
2
 
3
+ ## 0.9.2
4
+
5
+ ### Patch Changes
6
+
7
+ - dc3cddf51ab5: Fix cyclical dependency in built output
8
+ - 4e697e88f0e2: Add resource utilization to Pod Drawer
9
+ - 4b230b97660d: Add errors to PodDrawer
10
+ - 73cc0deee48a: Add proposed fix dialog for pod errors
11
+ - Updated dependencies
12
+ - @backstage/core-plugin-api@1.5.2
13
+ - @backstage/core-components@0.13.2
14
+ - @backstage/theme@0.4.0
15
+ - @backstage/plugin-catalog-react@1.7.0
16
+ - @backstage/catalog-model@1.4.0
17
+ - @backstage/errors@1.2.0
18
+ - @backstage/config@1.0.8
19
+ - @backstage/plugin-kubernetes-common@0.6.4
20
+
21
+ ## 0.9.2-next.3
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies
26
+ - @backstage/core-components@0.13.2-next.3
27
+ - @backstage/catalog-model@1.4.0-next.1
28
+ - @backstage/config@1.0.7
29
+ - @backstage/core-plugin-api@1.5.2-next.0
30
+ - @backstage/errors@1.2.0-next.0
31
+ - @backstage/theme@0.4.0-next.1
32
+ - @backstage/plugin-catalog-react@1.7.0-next.3
33
+ - @backstage/plugin-kubernetes-common@0.6.4-next.1
34
+
3
35
  ## 0.9.2-next.2
4
36
 
5
37
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2,15 +2,16 @@
2
2
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
3
  import { OAuthApi, OpenIdConnectApi, DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
4
4
  import { Entity } from '@backstage/catalog-model';
5
- import { KubernetesRequestBody, ObjectsByEntityResponse, WorkloadsByEntityRequest, CustomObjectsByEntityRequest, ClusterObjects, ClusterAttributes, CustomResourceMatcher, ClientPodStatus } from '@backstage/plugin-kubernetes-common';
5
+ import { KubernetesRequestBody, ObjectsByEntityResponse, WorkloadsByEntityRequest, CustomObjectsByEntityRequest, ClusterObjects, ClusterAttributes, ClientContainerStatus, CustomResourceMatcher, ClientPodStatus } from '@backstage/plugin-kubernetes-common';
6
6
  import * as kubernetes_models_v1 from 'kubernetes-models/v1';
7
7
  import { Event, Pod, IContainer, IContainerStatus } from 'kubernetes-models/v1';
8
8
  import { JsonObject } from '@backstage/types';
9
9
  import { V1Pod, V1ReplicaSet, V1Deployment, V1HorizontalPodAutoscaler, V1Service, V1ConfigMap, V1Ingress, V1Job, V1CronJob, V1StatefulSet, V1ObjectMeta } from '@kubernetes/client-node';
10
10
  import React from 'react';
11
- import { IObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta';
11
+ import { IObjectMeta, IIoK8sApimachineryPkgApisMetaV1ObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta';
12
12
  import * as react_use_lib_useAsyncFn from 'react-use/lib/useAsyncFn';
13
13
  import { Pod as Pod$1 } from 'kubernetes-models/v1/Pod';
14
+ import { TypeMeta } from '@kubernetes-models/base';
14
15
 
15
16
  declare const kubernetesPlugin: _backstage_core_plugin_api.BackstagePlugin<{
16
17
  entityContent: _backstage_core_plugin_api.RouteRef<undefined>;
@@ -241,6 +242,11 @@ type ErrorSeverity = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
241
242
  * @public
242
243
  */
243
244
  type DetectedErrorsByCluster = Map<string, DetectedError[]>;
245
+ /**
246
+ * A reference to a Kubernetes object
247
+ *
248
+ * @public
249
+ */
244
250
  interface ResourceRef {
245
251
  name: string;
246
252
  namespace: string;
@@ -451,6 +457,7 @@ interface ContainerCardProps {
451
457
  podScope: PodScope;
452
458
  containerSpec?: IContainer;
453
459
  containerStatus: IContainerStatus;
460
+ containerMetrics?: ClientContainerStatus;
454
461
  }
455
462
  /**
456
463
  * Shows details about a container within a pod
@@ -575,6 +582,25 @@ type KubernetesContentProps = {
575
582
  };
576
583
  declare const KubernetesContent: ({ entity, refreshIntervalMs, }: KubernetesContentProps) => JSX.Element;
577
584
 
585
+ /**
586
+ * Context for Pod Metrics
587
+ *
588
+ * @public
589
+ */
590
+ interface ResourceUtilizationProps {
591
+ compressed?: boolean;
592
+ title: string;
593
+ usage: number | string;
594
+ total: number | string;
595
+ totalFormated: string;
596
+ }
597
+ /**
598
+ * Context for Pod Metrics
599
+ *
600
+ * @public
601
+ */
602
+ declare const ResourceUtilization: ({ compressed, title, usage, total, totalFormated, }: ResourceUtilizationProps) => JSX.Element;
603
+
578
604
  interface KubernetesObjects {
579
605
  kubernetesObjects?: ObjectsByEntityResponse;
580
606
  loading: boolean;
@@ -597,4 +623,40 @@ declare const GroupedResponsesContext: React.Context<GroupedResponses>;
597
623
 
598
624
  declare const ClusterContext: React.Context<ClusterAttributes>;
599
625
 
600
- export { Cluster, ClusterContext, ClusterLinksFormatter, ClusterLinksFormatterOptions, ContainerCard, ContainerCardProps, ContainerScope, CronJobsAccordions, CustomResources, DeploymentResources, DetectedError, DetectedErrorsByCluster, EntityKubernetesContent, EntityKubernetesContentProps, ErrorList, ErrorListProps, ErrorPanel, ErrorReporting, ErrorSeverity, Events, EventsContent, EventsContentProps, EventsOptions, EventsProps, FixDialog, FixDialogProps, GoogleKubernetesAuthProvider, GroupedResponses, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesApi, KubernetesAuthProviders, KubernetesAuthProvidersApi, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesObjects, KubernetesProxyApi, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PendingPodContentProps, PodAndErrors, PodDrawer, PodLogs, PodLogsDialog, PodLogsDialogProps, PodLogsOptions, PodLogsProps, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodScope, PodsTable, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useKubernetesObjects, usePodLogs };
626
+ /**
627
+ * Context for Pod Metrics
628
+ *
629
+ * @public
630
+ */
631
+ declare const PodMetricsContext: React.Context<Map<string, ClientPodStatus[]>>;
632
+ type PodMetricsMatcher = {
633
+ metadata?: IObjectMeta;
634
+ };
635
+ /**
636
+ * Find metrics matching the provided pod
637
+ *
638
+ * @public
639
+ */
640
+ declare const usePodMetrics: (clusterName: string, matcher: PodMetricsMatcher) => ClientPodStatus | undefined;
641
+
642
+ /**
643
+ * Context for detected errors
644
+ *
645
+ * @public
646
+ */
647
+ declare const DetectedErrorsContext: React.Context<DetectedError[]>;
648
+ /**
649
+ *
650
+ * @public
651
+ */
652
+ type ErrorMatcher = {
653
+ metadata?: IIoK8sApimachineryPkgApisMetaV1ObjectMeta;
654
+ } & TypeMeta;
655
+ /**
656
+ * Find errors which match the resource
657
+ *
658
+ * @public
659
+ */
660
+ declare const useMatchingErrors: (matcher: ErrorMatcher) => DetectedError[];
661
+
662
+ export { Cluster, ClusterContext, ClusterLinksFormatter, ClusterLinksFormatterOptions, ContainerCard, ContainerCardProps, ContainerScope, CronJobsAccordions, CustomResources, DeploymentResources, DetectedError, DetectedErrorsByCluster, DetectedErrorsContext, EntityKubernetesContent, EntityKubernetesContentProps, ErrorList, ErrorListProps, ErrorMatcher, ErrorPanel, ErrorReporting, ErrorSeverity, Events, EventsContent, EventsContentProps, EventsOptions, EventsProps, FixDialog, FixDialogProps, GoogleKubernetesAuthProvider, GroupedResponses, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesApi, KubernetesAuthProviders, KubernetesAuthProvidersApi, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesObjects, KubernetesProxyApi, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PendingPodContentProps, PodAndErrors, PodDrawer, PodLogs, PodLogsDialog, PodLogsDialogProps, PodLogsOptions, PodLogsProps, PodMetricsContext, PodMetricsMatcher, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodScope, PodsTable, ResourceRef, ResourceUtilization, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useKubernetesObjects, useMatchingErrors, usePodLogs, usePodMetrics };
package/dist/index.esm.js CHANGED
@@ -5,8 +5,8 @@ import * as React from 'react';
5
5
  import React__default, { useState, useCallback, useContext, Fragment } from 'react';
6
6
  import { useEntity } from '@backstage/plugin-catalog-react';
7
7
  import { Routes, Route } from 'react-router-dom';
8
- import { Typography, Paper, makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Card, CardHeader, CardContent, Grid, CardActions, FormControlLabel, Switch, Drawer, withStyles as withStyles$1, List, ListItem, Container, Tooltip, ListItemText, ListItemAvatar, Avatar, Divider, Chip, Accordion, AccordionSummary, AccordionDetails, Stepper, Step, StepLabel } from '@material-ui/core';
9
- import { WarningPanel, Table, DismissableBanner, EmptyState, LogViewer, StructuredMetadataTable, CodeSnippet, LinkButton, StatusError, StatusOK, StatusWarning, ItemCardGrid, SubvalueCell, StatusAborted, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
8
+ import { Typography, Paper, makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Grid, Card, CardHeader, CardContent, CardActions, FormControlLabel, Switch, Drawer, withStyles as withStyles$1, List, ListItem, Container, Tooltip, ListItemText, ListItemAvatar, Avatar, Divider, Chip, Accordion, AccordionSummary, AccordionDetails, Stepper, Step, StepLabel } from '@material-ui/core';
9
+ import { WarningPanel, Table, DismissableBanner, EmptyState, LogViewer, LinearGauge, StructuredMetadataTable, CodeSnippet, LinkButton, StatusError, StatusOK, StatusWarning, ItemCardGrid, SubvalueCell, StatusAborted, StatusPending, Page, Content, Progress, MissingAnnotationEmptyState } from '@backstage/core-components';
10
10
  import lodash from 'lodash';
11
11
  import { DateTime } from 'luxon';
12
12
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
@@ -943,6 +943,65 @@ const PodLogsDialog = ({ containerScope }) => {
943
943
  ));
944
944
  };
945
945
 
946
+ const currentToDeclaredResourceToPerc$1 = (current, resource) => {
947
+ if (Number(resource) === 0)
948
+ return 0;
949
+ if (typeof current === "number" && typeof resource === "number") {
950
+ return Math.round(current / resource * 100);
951
+ }
952
+ const numerator = BigInt(current);
953
+ const denominator = BigInt(resource);
954
+ return Number(numerator * BigInt(100) / denominator);
955
+ };
956
+ const bytesToMiB = (value) => {
957
+ return `${(parseFloat(value.toString()) / 1024 / 1024).toFixed(0)}MiB`;
958
+ };
959
+ const formatMilicores = (value) => {
960
+ return `${(parseFloat(value.toString()) * 1e3).toFixed(0)}m`;
961
+ };
962
+
963
+ const getProgressColor = ({
964
+ palette,
965
+ value,
966
+ inverse,
967
+ max
968
+ }) => {
969
+ if (isNaN(value)) {
970
+ return palette.status.pending;
971
+ }
972
+ const actualMax = max ? max : 100;
973
+ const actualValue = inverse ? actualMax - value : value;
974
+ if (actualValue >= actualMax) {
975
+ return palette.status.error;
976
+ } else if (actualValue > 90 || actualValue < 40) {
977
+ return palette.status.warning;
978
+ }
979
+ return palette.status.ok;
980
+ };
981
+ const ResourceUtilization = ({
982
+ compressed = false,
983
+ title,
984
+ usage,
985
+ total,
986
+ totalFormated
987
+ }) => {
988
+ const utilization = currentToDeclaredResourceToPerc$1(usage, total);
989
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
990
+ Typography,
991
+ {
992
+ variant: compressed ? "caption" : "subtitle2"
993
+ },
994
+ `${title}: ${totalFormated}`
995
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
996
+ LinearGauge,
997
+ {
998
+ getColor: getProgressColor,
999
+ width: compressed ? "thin" : "thick",
1000
+ value: utilization / 100
1001
+ }
1002
+ ), !compressed && /* @__PURE__ */ React__default.createElement(Typography, { variant: "caption" }, "usage: ", `${utilization}%`)));
1003
+ };
1004
+
946
1005
  const getContainerHealthChecks = (containerSpec, containerStatus) => {
947
1006
  var _a, _b, _c, _d;
948
1007
  if (((_b = (_a = containerStatus.state) == null ? void 0 : _a.terminated) == null ? void 0 : _b.reason) === "Completed") {
@@ -975,7 +1034,8 @@ const ContainerDatetime = ({ prefix, dateTime }) => {
975
1034
  const ContainerCard = ({
976
1035
  podScope,
977
1036
  containerSpec,
978
- containerStatus
1037
+ containerStatus,
1038
+ containerMetrics
979
1039
  }) => {
980
1040
  var _a, _b;
981
1041
  if (containerSpec === void 0) {
@@ -1013,7 +1073,51 @@ const ContainerCard = ({
1013
1073
  containerStatus
1014
1074
  )
1015
1075
  }
1016
- )))), /* @__PURE__ */ React__default.createElement(CardActions, { disableSpacing: true }, /* @__PURE__ */ React__default.createElement(
1076
+ )), containerMetrics && /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, xs: 12, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle1" }, "Resource utilization")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12, style: { minHeight: "5rem" } }, /* @__PURE__ */ React__default.createElement(
1077
+ ResourceUtilization,
1078
+ {
1079
+ compressed: true,
1080
+ title: "CPU requests",
1081
+ usage: containerMetrics.cpuUsage.currentUsage,
1082
+ total: containerMetrics.cpuUsage.requestTotal,
1083
+ totalFormated: formatMilicores(
1084
+ containerMetrics.cpuUsage.requestTotal
1085
+ )
1086
+ }
1087
+ ), /* @__PURE__ */ React__default.createElement(
1088
+ ResourceUtilization,
1089
+ {
1090
+ compressed: true,
1091
+ title: "CPU limits",
1092
+ usage: containerMetrics.cpuUsage.currentUsage,
1093
+ total: containerMetrics.cpuUsage.limitTotal,
1094
+ totalFormated: formatMilicores(
1095
+ containerMetrics.cpuUsage.limitTotal
1096
+ )
1097
+ }
1098
+ ), /* @__PURE__ */ React__default.createElement(
1099
+ ResourceUtilization,
1100
+ {
1101
+ compressed: true,
1102
+ title: "Memory requests",
1103
+ usage: containerMetrics.memoryUsage.currentUsage,
1104
+ total: containerMetrics.memoryUsage.requestTotal,
1105
+ totalFormated: bytesToMiB(
1106
+ containerMetrics.memoryUsage.requestTotal
1107
+ )
1108
+ }
1109
+ ), /* @__PURE__ */ React__default.createElement(
1110
+ ResourceUtilization,
1111
+ {
1112
+ compressed: true,
1113
+ title: "Memory limits",
1114
+ usage: containerMetrics.memoryUsage.currentUsage,
1115
+ total: containerMetrics.memoryUsage.limitTotal,
1116
+ totalFormated: bytesToMiB(
1117
+ containerMetrics.memoryUsage.requestTotal
1118
+ )
1119
+ }
1120
+ ))))), /* @__PURE__ */ React__default.createElement(CardActions, { disableSpacing: true }, /* @__PURE__ */ React__default.createElement(
1017
1121
  PodLogsDialog,
1018
1122
  {
1019
1123
  containerScope: {
@@ -1128,6 +1232,38 @@ const ClusterContext = React__default.createContext({
1128
1232
  name: ""
1129
1233
  });
1130
1234
 
1235
+ const PodMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
1236
+ const usePodMetrics = (clusterName, matcher) => {
1237
+ var _a, _b, _c, _d;
1238
+ const targetRef = {
1239
+ name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
1240
+ namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1241
+ };
1242
+ const metricsMap = useContext(PodMetricsContext);
1243
+ const metrics = metricsMap.get(clusterName);
1244
+ return metrics == null ? void 0 : metrics.find((m) => {
1245
+ var _a2, _b2, _c2, _d2;
1246
+ const pod = m.pod;
1247
+ return targetRef.name === ((_b2 = (_a2 = pod.metadata) == null ? void 0 : _a2.name) != null ? _b2 : "") && targetRef.namespace === ((_d2 = (_c2 = pod.metadata) == null ? void 0 : _c2.namespace) != null ? _d2 : "");
1248
+ });
1249
+ };
1250
+
1251
+ const DetectedErrorsContext = React__default.createContext([]);
1252
+ const useMatchingErrors = (matcher) => {
1253
+ var _a, _b, _c, _d;
1254
+ const targetRef = {
1255
+ name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
1256
+ namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
1257
+ kind: matcher.kind,
1258
+ apiGroup: matcher.apiVersion
1259
+ };
1260
+ const errors = useContext(DetectedErrorsContext);
1261
+ return errors.filter((e) => {
1262
+ const r = e.sourceRef;
1263
+ return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
1264
+ });
1265
+ };
1266
+
1131
1267
  const kindMappings$3 = {
1132
1268
  deployment: "deployment",
1133
1269
  pod: "pod",
@@ -1890,6 +2026,7 @@ function getContainerSpecByName(pod, containerName) {
1890
2026
  const PodDrawer = ({ podAndErrors, open }) => {
1891
2027
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1892
2028
  const classes = useDrawerContentStyles();
2029
+ const podMetrics = usePodMetrics(podAndErrors.clusterName, podAndErrors.pod);
1893
2030
  return /* @__PURE__ */ React__default.createElement(
1894
2031
  KubernetesDrawer,
1895
2032
  {
@@ -1898,20 +2035,54 @@ const PodDrawer = ({ podAndErrors, open }) => {
1898
2035
  kubernetesObject: podAndErrors.pod,
1899
2036
  label: /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle1" }, (_d = (_c = podAndErrors.pod.metadata) == null ? void 0 : _c.name) != null ? _d : "unknown")
1900
2037
  },
1901
- /* @__PURE__ */ React__default.createElement("div", { className: classes.content }, ((_e = podAndErrors.pod.status) == null ? void 0 : _e.phase) === "Pending" && /* @__PURE__ */ React__default.createElement(PendingPodContent, { pod: podAndErrors.pod }), ((_g = (_f = podAndErrors.pod.status) == null ? void 0 : _f.containerStatuses) == null ? void 0 : _g.length) && /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, "Containers")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(ItemCardGrid, null, (_i = (_h = podAndErrors.pod.status) == null ? void 0 : _h.containerStatuses) == null ? void 0 : _i.map(
2038
+ /* @__PURE__ */ React__default.createElement("div", { className: classes.content }, podMetrics && /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, "Resource utilization")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 6 }, /* @__PURE__ */ React__default.createElement(
2039
+ ResourceUtilization,
2040
+ {
2041
+ title: "CPU requests",
2042
+ usage: podMetrics.cpu.currentUsage,
2043
+ total: podMetrics.cpu.requestTotal,
2044
+ totalFormated: formatMilicores(podMetrics.cpu.requestTotal)
2045
+ }
2046
+ ), /* @__PURE__ */ React__default.createElement(
2047
+ ResourceUtilization,
2048
+ {
2049
+ title: "CPU limits",
2050
+ usage: podMetrics.cpu.currentUsage,
2051
+ total: podMetrics.cpu.limitTotal,
2052
+ totalFormated: formatMilicores(podMetrics.cpu.limitTotal)
2053
+ }
2054
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 6 }, /* @__PURE__ */ React__default.createElement(
2055
+ ResourceUtilization,
2056
+ {
2057
+ title: "Memory requests",
2058
+ usage: podMetrics.memory.currentUsage,
2059
+ total: podMetrics.memory.requestTotal,
2060
+ totalFormated: bytesToMiB(podMetrics.memory.requestTotal)
2061
+ }
2062
+ ), /* @__PURE__ */ React__default.createElement(
2063
+ ResourceUtilization,
2064
+ {
2065
+ title: "Memory limits",
2066
+ usage: podMetrics.memory.currentUsage,
2067
+ total: podMetrics.memory.limitTotal,
2068
+ totalFormated: bytesToMiB(podMetrics.memory.requestTotal)
2069
+ }
2070
+ ))), ((_e = podAndErrors.pod.status) == null ? void 0 : _e.phase) === "Pending" && /* @__PURE__ */ React__default.createElement(PendingPodContent, { pod: podAndErrors.pod }), ((_g = (_f = podAndErrors.pod.status) == null ? void 0 : _f.containerStatuses) == null ? void 0 : _g.length) && /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, "Containers")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(ItemCardGrid, null, (_i = (_h = podAndErrors.pod.status) == null ? void 0 : _h.containerStatuses) == null ? void 0 : _i.map(
1902
2071
  (containerStatus, i) => {
1903
- var _a2, _b2, _c2, _d2, _e2;
2072
+ var _a2, _b2, _c2, _d2, _e2, _f2;
1904
2073
  const containerSpec = getContainerSpecByName(
1905
2074
  podAndErrors.pod,
1906
2075
  containerStatus.name
1907
2076
  );
2077
+ const containerMetrics = ((_a2 = podMetrics == null ? void 0 : podMetrics.containers) != null ? _a2 : []).find((c) => c.container === containerStatus.name);
1908
2078
  return /* @__PURE__ */ React__default.createElement(
1909
2079
  ContainerCard,
1910
2080
  {
1911
- key: `container-card-${(_a2 = podAndErrors.pod.metadata) == null ? void 0 : _a2.name}-${i}`,
2081
+ key: `container-card-${(_b2 = podAndErrors.pod.metadata) == null ? void 0 : _b2.name}-${i}`,
2082
+ containerMetrics,
1912
2083
  podScope: {
1913
- podName: (_c2 = (_b2 = podAndErrors.pod.metadata) == null ? void 0 : _b2.name) != null ? _c2 : "unknown",
1914
- podNamespace: (_e2 = (_d2 = podAndErrors.pod.metadata) == null ? void 0 : _d2.namespace) != null ? _e2 : "unknown",
2084
+ podName: (_d2 = (_c2 = podAndErrors.pod.metadata) == null ? void 0 : _c2.name) != null ? _d2 : "unknown",
2085
+ podNamespace: (_f2 = (_e2 = podAndErrors.pod.metadata) == null ? void 0 : _e2.namespace) != null ? _f2 : "unknown",
1915
2086
  clusterName: podAndErrors.clusterName
1916
2087
  },
1917
2088
  containerSpec,
@@ -1995,9 +2166,6 @@ const currentToDeclaredResourceToPerc = (current, resource) => {
1995
2166
  const denominator = BigInt(resource);
1996
2167
  return `${numerator * BigInt(100) / denominator}%`;
1997
2168
  };
1998
- const formatMilicores = (value) => {
1999
- return `${parseFloat(value.toString()) * 1e3}m`;
2000
- };
2001
2169
  const podStatusToCpuUtil = (podStatus) => {
2002
2170
  const cpuUtil = podStatus.cpu;
2003
2171
  let currentUsage = cpuUtil.currentUsage;
@@ -2018,9 +2186,6 @@ const podStatusToCpuUtil = (podStatus) => {
2018
2186
  }
2019
2187
  );
2020
2188
  };
2021
- const bytesToMiB = (value) => {
2022
- return `${parseFloat(value.toString()) / 1024 / 1024}MiB`;
2023
- };
2024
2189
  const podStatusToMemoryUtil = (podStatus) => {
2025
2190
  const memUtil = podStatus.memory;
2026
2191
  return /* @__PURE__ */ React__default.createElement(
@@ -2038,22 +2203,6 @@ const podStatusToMemoryUtil = (podStatus) => {
2038
2203
  );
2039
2204
  };
2040
2205
 
2041
- const DetectedErrorsContext = React__default.createContext([]);
2042
- const useMatchingErrors = (matcher) => {
2043
- var _a, _b, _c, _d;
2044
- const targetRef = {
2045
- name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
2046
- namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
2047
- kind: matcher.kind,
2048
- apiGroup: matcher.apiVersion
2049
- };
2050
- const errors = useContext(DetectedErrorsContext);
2051
- return errors.filter((e) => {
2052
- const r = e.sourceRef;
2053
- return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
2054
- });
2055
- };
2056
-
2057
2206
  const READY_COLUMNS = "READY";
2058
2207
  const RESOURCE_COLUMNS = "RESOURCE";
2059
2208
  const READY = [
@@ -2089,8 +2238,22 @@ const PodDrawerTrigger = ({ pod }) => {
2089
2238
  }
2090
2239
  );
2091
2240
  };
2241
+ const Cpu = ({ clusterName, pod }) => {
2242
+ const metrics = usePodMetrics(clusterName, pod);
2243
+ if (!metrics) {
2244
+ return /* @__PURE__ */ React__default.createElement(Typography, null, "unknown");
2245
+ }
2246
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, podStatusToCpuUtil(metrics));
2247
+ };
2248
+ const Memory = ({ clusterName, pod }) => {
2249
+ const metrics = usePodMetrics(clusterName, pod);
2250
+ if (!metrics) {
2251
+ return /* @__PURE__ */ React__default.createElement(Typography, null, "unknown");
2252
+ }
2253
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, podStatusToMemoryUtil(metrics));
2254
+ };
2092
2255
  const PodsTable = ({ pods, extraColumns = [] }) => {
2093
- const podNamesWithMetrics = useContext(PodNamesWithMetricsContext);
2256
+ const cluster = useContext(ClusterContext);
2094
2257
  const defaultColumns = [
2095
2258
  {
2096
2259
  title: "name",
@@ -2121,24 +2284,14 @@ const PodsTable = ({ pods, extraColumns = [] }) => {
2121
2284
  {
2122
2285
  title: "CPU usage %",
2123
2286
  render: (pod) => {
2124
- var _a, _b;
2125
- const metrics = podNamesWithMetrics.get((_b = (_a = pod.metadata) == null ? void 0 : _a.name) != null ? _b : "");
2126
- if (!metrics) {
2127
- return "unknown";
2128
- }
2129
- return podStatusToCpuUtil(metrics);
2287
+ return /* @__PURE__ */ React__default.createElement(Cpu, { clusterName: cluster.name, pod });
2130
2288
  },
2131
2289
  width: "auto"
2132
2290
  },
2133
2291
  {
2134
2292
  title: "Memory usage %",
2135
2293
  render: (pod) => {
2136
- var _a, _b;
2137
- const metrics = podNamesWithMetrics.get((_b = (_a = pod.metadata) == null ? void 0 : _a.name) != null ? _b : "");
2138
- if (!metrics) {
2139
- return "unknown";
2140
- }
2141
- return podStatusToMemoryUtil(metrics);
2294
+ return /* @__PURE__ */ React__default.createElement(Memory, { clusterName: cluster.name, pod });
2142
2295
  },
2143
2296
  width: "auto"
2144
2297
  }
@@ -3254,15 +3407,9 @@ const ClusterSummary = ({
3254
3407
  };
3255
3408
  const Cluster = ({ clusterObjects, podsWithErrors }) => {
3256
3409
  const groupedResponses = groupResponses(clusterObjects.resources);
3257
- const podNameToMetrics = clusterObjects.podMetrics.flat().reduce((accum, next) => {
3258
- var _a;
3259
- const name = (_a = next.pod.metadata) == null ? void 0 : _a.name;
3260
- if (name !== void 0) {
3261
- accum.set(name, next);
3262
- }
3263
- return accum;
3264
- }, /* @__PURE__ */ new Map());
3265
- return /* @__PURE__ */ React__default.createElement(ClusterContext.Provider, { value: clusterObjects.cluster }, /* @__PURE__ */ React__default.createElement(GroupedResponsesContext.Provider, { value: groupedResponses }, /* @__PURE__ */ React__default.createElement(PodNamesWithMetricsContext.Provider, { value: podNameToMetrics }, /* @__PURE__ */ React__default.createElement(PodNamesWithErrorsContext.Provider, { value: podsWithErrors }, /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true } }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(
3410
+ const podMetricsMap = /* @__PURE__ */ new Map();
3411
+ podMetricsMap.set(clusterObjects.cluster.name, clusterObjects.podMetrics);
3412
+ return /* @__PURE__ */ React__default.createElement(ClusterContext.Provider, { value: clusterObjects.cluster }, /* @__PURE__ */ React__default.createElement(GroupedResponsesContext.Provider, { value: groupedResponses }, /* @__PURE__ */ React__default.createElement(PodMetricsContext.Provider, { value: podMetricsMap }, /* @__PURE__ */ React__default.createElement(PodNamesWithErrorsContext.Provider, { value: podsWithErrors }, /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true } }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(
3266
3413
  ClusterSummary,
3267
3414
  {
3268
3415
  clusterName: clusterObjects.cluster.name,
@@ -3373,5 +3520,5 @@ var Router$1 = /*#__PURE__*/Object.freeze({
3373
3520
  Router: Router
3374
3521
  });
3375
3522
 
3376
- export { Cluster, ClusterContext, ContainerCard, CronJobsAccordions, CustomResources, EntityKubernetesContent, ErrorList, ErrorPanel, ErrorReporting, Events, EventsContent, FixDialog, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PodDrawer, PodLogs, PodLogsDialog, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useKubernetesObjects, usePodLogs };
3523
+ export { Cluster, ClusterContext, ContainerCard, CronJobsAccordions, CustomResources, DetectedErrorsContext, EntityKubernetesContent, ErrorList, ErrorPanel, ErrorReporting, Events, EventsContent, FixDialog, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesContent, KubernetesDrawer, KubernetesDrawerContent, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, PendingPodContent, PodDrawer, PodLogs, PodLogsDialog, PodMetricsContext, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, ResourceUtilization, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useKubernetesObjects, useMatchingErrors, usePodLogs, usePodMetrics };
3377
3524
  //# sourceMappingURL=index.esm.js.map