@backstage/plugin-kubernetes 0.10.3-next.1 → 0.10.3-next.3

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/dist/index.esm.js CHANGED
@@ -2,22 +2,27 @@ import { stringifyEntityRef } from '@backstage/catalog-model';
2
2
  import { NotFoundError } from '@backstage/errors';
3
3
  import { createApiRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, gitlabAuthApiRef, googleAuthApiRef, microsoftAuthApiRef, oktaAuthApiRef, oneloginAuthApiRef, createRoutableExtension, useApi } from '@backstage/core-plugin-api';
4
4
  import * as React from 'react';
5
- import React__default, { useState, useCallback, useContext, Fragment } from 'react';
5
+ import React__default, { useCallback, useContext, useState, useEffect, useMemo, 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, 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';
8
+ import { Typography, makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Grid, Paper, 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, LinearGauge, DismissableBanner, EmptyState, LogViewer, 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';
13
- import { Skeleton } from '@material-ui/lab';
13
+ import CloseIcon from '@material-ui/icons/Close';
14
+ import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser';
14
15
  import useAsync from 'react-use/lib/useAsync';
16
+ import useInterval from 'react-use/lib/useInterval';
17
+ import useAsyncRetry from 'react-use/lib/useAsyncRetry';
18
+ import 'xterm/css/xterm.css';
19
+ import { Terminal } from 'xterm';
20
+ import { FitAddon } from 'xterm-addon-fit';
21
+ import { AttachAddon } from 'xterm-addon-attach';
22
+ import { Skeleton } from '@material-ui/lab';
15
23
  import SubjectIcon from '@material-ui/icons/Subject';
16
- import CloseIcon from '@material-ui/icons/Close';
17
24
  import OpenInNewIcon from '@material-ui/icons/OpenInNew';
18
25
  import { withStyles, makeStyles as makeStyles$1, createStyles as createStyles$1 } from '@material-ui/core/styles';
19
- import useInterval from 'react-use/lib/useInterval';
20
- import useAsyncRetry from 'react-use/lib/useAsyncRetry';
21
26
  import jsyaml from 'js-yaml';
22
27
  import Dialog$1 from '@material-ui/core/Dialog';
23
28
  import DialogActions from '@material-ui/core/DialogActions';
@@ -892,6 +897,364 @@ const detectErrors = (objects) => {
892
897
  return errors;
893
898
  };
894
899
 
900
+ const currentToDeclaredResourceToPerc$1 = (current, resource) => {
901
+ if (Number(resource) === 0)
902
+ return 0;
903
+ if (typeof current === "number" && typeof resource === "number") {
904
+ return Math.round(current / resource * 100);
905
+ }
906
+ const numerator = BigInt(current);
907
+ const denominator = BigInt(resource);
908
+ return Number(numerator * BigInt(100) / denominator);
909
+ };
910
+ const bytesToMiB = (value) => {
911
+ return `${(parseFloat(value.toString()) / 1024 / 1024).toFixed(0)}MiB`;
912
+ };
913
+ const formatMillicores = (value) => {
914
+ return `${(parseFloat(value.toString()) * 1e3).toFixed(0)}m`;
915
+ };
916
+
917
+ const useIsPodExecTerminalSupported = () => {
918
+ const kubernetesApi = useApi(kubernetesApiRef);
919
+ return useAsync(async () => {
920
+ const clusters = await kubernetesApi.getClusters();
921
+ if (clusters.length !== 1) {
922
+ return false;
923
+ }
924
+ const { authProvider } = clusters[0];
925
+ const isClientAuthProvider = ["aks", "google", "oidc"].some(
926
+ (authProviderName) => authProvider.includes(authProviderName)
927
+ );
928
+ return !isClientAuthProvider;
929
+ });
930
+ };
931
+
932
+ const generateAuth = async (entity, kubernetesApi, kubernetesAuthProvidersApi) => {
933
+ var _a;
934
+ const clusters = await kubernetesApi.getClusters();
935
+ const authProviders = [
936
+ ...new Set(
937
+ clusters.map(
938
+ (c) => `${c.authProvider}${c.oidcTokenProvider ? `.${c.oidcTokenProvider}` : ""}`
939
+ )
940
+ )
941
+ ];
942
+ let requestBody = {
943
+ entity
944
+ };
945
+ for (const authProviderStr of authProviders) {
946
+ requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(
947
+ authProviderStr,
948
+ requestBody
949
+ );
950
+ }
951
+ return (_a = requestBody.auth) != null ? _a : {};
952
+ };
953
+
954
+ const useKubernetesObjects = (entity, intervalMs = 1e4) => {
955
+ const kubernetesApi = useApi(kubernetesApiRef);
956
+ const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
957
+ const getObjects = useCallback(async () => {
958
+ const auth = await generateAuth(
959
+ entity,
960
+ kubernetesApi,
961
+ kubernetesAuthProvidersApi
962
+ );
963
+ return await kubernetesApi.getObjectsByEntity({
964
+ auth,
965
+ entity
966
+ });
967
+ }, [kubernetesApi, entity, kubernetesAuthProvidersApi]);
968
+ const { value, loading, error, retry } = useAsyncRetry(
969
+ () => getObjects(),
970
+ [getObjects]
971
+ );
972
+ useInterval(() => retry(), intervalMs);
973
+ return {
974
+ kubernetesObjects: value,
975
+ loading,
976
+ error: error == null ? void 0 : error.message
977
+ };
978
+ };
979
+
980
+ const useCustomResources = (entity, customResourceMatchers, intervalMs = 1e4) => {
981
+ const kubernetesApi = useApi(kubernetesApiRef);
982
+ const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
983
+ const matchersString = JSON.stringify(customResourceMatchers);
984
+ const getCustomObjects = useCallback(
985
+ async () => {
986
+ const auth = await generateAuth(
987
+ entity,
988
+ kubernetesApi,
989
+ kubernetesAuthProvidersApi
990
+ );
991
+ return await kubernetesApi.getCustomObjectsByEntity({
992
+ auth,
993
+ customResources: customResourceMatchers,
994
+ entity
995
+ });
996
+ },
997
+ // eslint-disable-next-line react-hooks/exhaustive-deps
998
+ [kubernetesApi, entity, kubernetesAuthProvidersApi, matchersString]
999
+ );
1000
+ const { value, loading, error, retry } = useAsyncRetry(
1001
+ () => getCustomObjects(),
1002
+ [getCustomObjects]
1003
+ );
1004
+ useInterval(() => retry(), intervalMs);
1005
+ return {
1006
+ kubernetesObjects: value,
1007
+ loading,
1008
+ error: error == null ? void 0 : error.message
1009
+ };
1010
+ };
1011
+
1012
+ const PodNamesWithErrorsContext = React__default.createContext(
1013
+ /* @__PURE__ */ new Set()
1014
+ );
1015
+
1016
+ const PodNamesWithMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
1017
+
1018
+ const GroupedResponsesContext = React__default.createContext({
1019
+ pods: [],
1020
+ replicaSets: [],
1021
+ deployments: [],
1022
+ services: [],
1023
+ configMaps: [],
1024
+ horizontalPodAutoscalers: [],
1025
+ ingresses: [],
1026
+ jobs: [],
1027
+ cronJobs: [],
1028
+ customResources: [],
1029
+ statefulsets: []
1030
+ });
1031
+
1032
+ const ClusterContext = React__default.createContext({
1033
+ name: ""
1034
+ });
1035
+
1036
+ const PodMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
1037
+ const usePodMetrics = (clusterName, matcher) => {
1038
+ var _a, _b, _c, _d;
1039
+ const targetRef = {
1040
+ name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
1041
+ namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1042
+ };
1043
+ const metricsMap = useContext(PodMetricsContext);
1044
+ const metrics = metricsMap.get(clusterName);
1045
+ return metrics == null ? void 0 : metrics.find((m) => {
1046
+ var _a2, _b2, _c2, _d2;
1047
+ const pod = m.pod;
1048
+ 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 : "");
1049
+ });
1050
+ };
1051
+
1052
+ const DetectedErrorsContext = React__default.createContext([]);
1053
+ const useMatchingErrors = (matcher) => {
1054
+ var _a, _b, _c, _d;
1055
+ const targetRef = {
1056
+ name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
1057
+ namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
1058
+ kind: matcher.kind,
1059
+ apiGroup: matcher.apiVersion
1060
+ };
1061
+ const errors = useContext(DetectedErrorsContext);
1062
+ return errors.filter((e) => {
1063
+ const r = e.sourceRef;
1064
+ return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
1065
+ });
1066
+ };
1067
+
1068
+ const textEncoder = new TextEncoder();
1069
+ class PodExecTerminalAttachAddon extends AttachAddon {
1070
+ constructor(socket, options) {
1071
+ super(socket, options);
1072
+ const thisAddon = this;
1073
+ thisAddon._sendBinary = (data) => {
1074
+ if (!thisAddon._checkOpenSocket()) {
1075
+ return;
1076
+ }
1077
+ const buffer = Uint8Array.from([0, ...textEncoder.encode(data)]);
1078
+ thisAddon._socket.send(buffer);
1079
+ };
1080
+ thisAddon._sendData = (data) => {
1081
+ if (!thisAddon._checkOpenSocket()) {
1082
+ return;
1083
+ }
1084
+ thisAddon._sendBinary(data);
1085
+ };
1086
+ }
1087
+ }
1088
+
1089
+ const hasSocketProtocol = (url) => /wss?:\/\//.test(url.toString());
1090
+ const PodExecTerminal = (props) => {
1091
+ const { containerName, podNamespace, podName } = props;
1092
+ const [baseUrl, setBaseUrl] = useState(window.location.host);
1093
+ const terminalRef = React__default.useRef(null);
1094
+ const discoveryApi = useApi(discoveryApiRef);
1095
+ const namespace = podNamespace != null ? podNamespace : "default";
1096
+ useEffect(() => {
1097
+ discoveryApi.getBaseUrl("kubernetes").then((url) => url != null ? url : window.location.host).then((url) => url.replace(/^http(s?):\/\//, "ws$1://")).then((url) => setBaseUrl(url));
1098
+ }, [discoveryApi]);
1099
+ const urlParams = useMemo(() => {
1100
+ const params = new URLSearchParams({
1101
+ container: containerName,
1102
+ stdin: "true",
1103
+ stdout: "true",
1104
+ stderr: "true",
1105
+ tty: "true",
1106
+ command: "/bin/sh"
1107
+ });
1108
+ return params;
1109
+ }, [containerName]);
1110
+ const socketUrl = useMemo(() => {
1111
+ if (!hasSocketProtocol(baseUrl)) {
1112
+ return "";
1113
+ }
1114
+ return new URL(
1115
+ `${baseUrl}/proxy/api/v1/namespaces/${namespace}/pods/${podName}/exec?${urlParams}`
1116
+ );
1117
+ }, [baseUrl, namespace, podName, urlParams]);
1118
+ useEffect(() => {
1119
+ if (!hasSocketProtocol(socketUrl)) {
1120
+ return () => {
1121
+ };
1122
+ }
1123
+ const terminal = new Terminal();
1124
+ const fitAddon = new FitAddon();
1125
+ terminal.loadAddon(fitAddon);
1126
+ if (terminalRef.current) {
1127
+ terminal.open(terminalRef.current);
1128
+ fitAddon.fit();
1129
+ }
1130
+ terminal.writeln("Starting terminal, please wait...");
1131
+ const socket = new WebSocket(socketUrl, ["channel.k8s.io"]);
1132
+ socket.onopen = () => {
1133
+ terminal.clear();
1134
+ const attachAddon = new PodExecTerminalAttachAddon(socket, {
1135
+ bidirectional: true
1136
+ });
1137
+ terminal.loadAddon(attachAddon);
1138
+ };
1139
+ socket.onclose = () => {
1140
+ terminal.writeln("Socket connection closed");
1141
+ };
1142
+ return () => {
1143
+ terminal == null ? void 0 : terminal.clear();
1144
+ socket == null ? void 0 : socket.close();
1145
+ };
1146
+ }, [baseUrl, socketUrl]);
1147
+ return /* @__PURE__ */ React__default.createElement(
1148
+ "div",
1149
+ {
1150
+ "data-testid": "terminal",
1151
+ ref: terminalRef,
1152
+ style: {
1153
+ width: "100%",
1154
+ height: "100%"
1155
+ }
1156
+ }
1157
+ );
1158
+ };
1159
+
1160
+ const useStyles$3 = makeStyles(
1161
+ (theme) => createStyles({
1162
+ dialogPaper: { minHeight: "calc(100% - 64px)" },
1163
+ dialogContent: { flexBasis: 0 },
1164
+ closeButton: {
1165
+ position: "absolute",
1166
+ right: theme.spacing(1),
1167
+ top: theme.spacing(1),
1168
+ color: theme.palette.grey[500]
1169
+ }
1170
+ })
1171
+ );
1172
+ const PodExecTerminalDialog = (props) => {
1173
+ const classes = useStyles$3();
1174
+ const { clusterName, containerName, podName } = props;
1175
+ const [open, setOpen] = useState(false);
1176
+ const isPodExecTerminalSupported = useIsPodExecTerminalSupported();
1177
+ const openDialog = () => {
1178
+ setOpen(true);
1179
+ };
1180
+ const closeDialog = () => {
1181
+ setOpen(false);
1182
+ };
1183
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, !isPodExecTerminalSupported.loading && isPodExecTerminalSupported.value && /* @__PURE__ */ React__default.createElement(
1184
+ Dialog,
1185
+ {
1186
+ maxWidth: false,
1187
+ fullWidth: true,
1188
+ open,
1189
+ onClose: closeDialog,
1190
+ PaperProps: { className: classes.dialogPaper }
1191
+ },
1192
+ /* @__PURE__ */ React__default.createElement(DialogTitle, { id: "dialog-title" }, podName, " - ", containerName, " terminal shell on cluster", " ", clusterName, /* @__PURE__ */ React__default.createElement(
1193
+ IconButton,
1194
+ {
1195
+ "aria-label": "close",
1196
+ className: classes.closeButton,
1197
+ onClick: closeDialog
1198
+ },
1199
+ /* @__PURE__ */ React__default.createElement(CloseIcon, null)
1200
+ )),
1201
+ /* @__PURE__ */ React__default.createElement(DialogContent, { className: classes.dialogContent }, /* @__PURE__ */ React__default.createElement(PodExecTerminal, { ...props }))
1202
+ ), /* @__PURE__ */ React__default.createElement(
1203
+ Button,
1204
+ {
1205
+ variant: "outlined",
1206
+ "aria-label": "open terminal",
1207
+ component: "label",
1208
+ disabled: isPodExecTerminalSupported.loading || !isPodExecTerminalSupported.value,
1209
+ onClick: openDialog,
1210
+ startIcon: /* @__PURE__ */ React__default.createElement(OpenInBrowserIcon, null)
1211
+ },
1212
+ "Terminal"
1213
+ ));
1214
+ };
1215
+
1216
+ const getProgressColor = ({
1217
+ palette,
1218
+ value,
1219
+ inverse,
1220
+ max
1221
+ }) => {
1222
+ if (isNaN(value)) {
1223
+ return palette.status.pending;
1224
+ }
1225
+ const actualMax = max ? max : 100;
1226
+ const actualValue = inverse ? actualMax - value : value;
1227
+ if (actualValue >= actualMax) {
1228
+ return palette.status.error;
1229
+ } else if (actualValue > 90 || actualValue < 40) {
1230
+ return palette.status.warning;
1231
+ }
1232
+ return palette.status.ok;
1233
+ };
1234
+ const ResourceUtilization = ({
1235
+ compressed = false,
1236
+ title,
1237
+ usage,
1238
+ total,
1239
+ totalFormatted
1240
+ }) => {
1241
+ const utilization = currentToDeclaredResourceToPerc$1(usage, total);
1242
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
1243
+ Typography,
1244
+ {
1245
+ variant: compressed ? "caption" : "subtitle2"
1246
+ },
1247
+ `${title}: ${totalFormatted}`
1248
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
1249
+ LinearGauge,
1250
+ {
1251
+ getColor: getProgressColor,
1252
+ width: compressed ? "thin" : "thick",
1253
+ value: utilization / 100
1254
+ }
1255
+ ), !compressed && /* @__PURE__ */ React__default.createElement(Typography, { variant: "caption" }, "usage: ", `${utilization}%`)));
1256
+ };
1257
+
895
1258
  const usePodLogs = ({ containerScope, previous }) => {
896
1259
  const kubernetesProxyApi = useApi(kubernetesProxyApiRef);
897
1260
  return useAsync(async () => {
@@ -981,65 +1344,6 @@ const PodLogsDialog = ({ containerScope }) => {
981
1344
  ));
982
1345
  };
983
1346
 
984
- const currentToDeclaredResourceToPerc$1 = (current, resource) => {
985
- if (Number(resource) === 0)
986
- return 0;
987
- if (typeof current === "number" && typeof resource === "number") {
988
- return Math.round(current / resource * 100);
989
- }
990
- const numerator = BigInt(current);
991
- const denominator = BigInt(resource);
992
- return Number(numerator * BigInt(100) / denominator);
993
- };
994
- const bytesToMiB = (value) => {
995
- return `${(parseFloat(value.toString()) / 1024 / 1024).toFixed(0)}MiB`;
996
- };
997
- const formatMillicores = (value) => {
998
- return `${(parseFloat(value.toString()) * 1e3).toFixed(0)}m`;
999
- };
1000
-
1001
- const getProgressColor = ({
1002
- palette,
1003
- value,
1004
- inverse,
1005
- max
1006
- }) => {
1007
- if (isNaN(value)) {
1008
- return palette.status.pending;
1009
- }
1010
- const actualMax = max ? max : 100;
1011
- const actualValue = inverse ? actualMax - value : value;
1012
- if (actualValue >= actualMax) {
1013
- return palette.status.error;
1014
- } else if (actualValue > 90 || actualValue < 40) {
1015
- return palette.status.warning;
1016
- }
1017
- return palette.status.ok;
1018
- };
1019
- const ResourceUtilization = ({
1020
- compressed = false,
1021
- title,
1022
- usage,
1023
- total,
1024
- totalFormatted
1025
- }) => {
1026
- const utilization = currentToDeclaredResourceToPerc$1(usage, total);
1027
- return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
1028
- Typography,
1029
- {
1030
- variant: compressed ? "caption" : "subtitle2"
1031
- },
1032
- `${title}: ${totalFormatted}`
1033
- )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
1034
- LinearGauge,
1035
- {
1036
- getColor: getProgressColor,
1037
- width: compressed ? "thin" : "thick",
1038
- value: utilization / 100
1039
- }
1040
- ), !compressed && /* @__PURE__ */ React__default.createElement(Typography, { variant: "caption" }, "usage: ", `${utilization}%`)));
1041
- };
1042
-
1043
1347
  const getContainerHealthChecks = (containerSpec, containerStatus) => {
1044
1348
  var _a, _b, _c, _d;
1045
1349
  if (((_b = (_a = containerStatus.state) == null ? void 0 : _a.terminated) == null ? void 0 : _b.reason) === "Completed") {
@@ -1155,7 +1459,7 @@ const ContainerCard = ({
1155
1459
  containerMetrics.memoryUsage.limitTotal
1156
1460
  )
1157
1461
  }
1158
- ))))), /* @__PURE__ */ React__default.createElement(CardActions, { disableSpacing: true }, /* @__PURE__ */ React__default.createElement(
1462
+ ))))), /* @__PURE__ */ React__default.createElement(CardActions, null, /* @__PURE__ */ React__default.createElement(
1159
1463
  PodLogsDialog,
1160
1464
  {
1161
1465
  containerScope: {
@@ -1163,145 +1467,17 @@ const ContainerCard = ({
1163
1467
  ...podScope
1164
1468
  }
1165
1469
  }
1470
+ ), /* @__PURE__ */ React__default.createElement(
1471
+ PodExecTerminalDialog,
1472
+ {
1473
+ clusterName: podScope.clusterName,
1474
+ containerName: containerStatus.name,
1475
+ podName: podScope.podName,
1476
+ podNamespace: podScope.podNamespace
1477
+ }
1166
1478
  )));
1167
1479
  };
1168
1480
 
1169
- const generateAuth = async (entity, kubernetesApi, kubernetesAuthProvidersApi) => {
1170
- var _a;
1171
- const clusters = await kubernetesApi.getClusters();
1172
- const authProviders = [
1173
- ...new Set(
1174
- clusters.map(
1175
- (c) => `${c.authProvider}${c.oidcTokenProvider ? `.${c.oidcTokenProvider}` : ""}`
1176
- )
1177
- )
1178
- ];
1179
- let requestBody = {
1180
- entity
1181
- };
1182
- for (const authProviderStr of authProviders) {
1183
- requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(
1184
- authProviderStr,
1185
- requestBody
1186
- );
1187
- }
1188
- return (_a = requestBody.auth) != null ? _a : {};
1189
- };
1190
-
1191
- const useKubernetesObjects = (entity, intervalMs = 1e4) => {
1192
- const kubernetesApi = useApi(kubernetesApiRef);
1193
- const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
1194
- const getObjects = useCallback(async () => {
1195
- const auth = await generateAuth(
1196
- entity,
1197
- kubernetesApi,
1198
- kubernetesAuthProvidersApi
1199
- );
1200
- return await kubernetesApi.getObjectsByEntity({
1201
- auth,
1202
- entity
1203
- });
1204
- }, [kubernetesApi, entity, kubernetesAuthProvidersApi]);
1205
- const { value, loading, error, retry } = useAsyncRetry(
1206
- () => getObjects(),
1207
- [getObjects]
1208
- );
1209
- useInterval(() => retry(), intervalMs);
1210
- return {
1211
- kubernetesObjects: value,
1212
- loading,
1213
- error: error == null ? void 0 : error.message
1214
- };
1215
- };
1216
-
1217
- const useCustomResources = (entity, customResourceMatchers, intervalMs = 1e4) => {
1218
- const kubernetesApi = useApi(kubernetesApiRef);
1219
- const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
1220
- const matchersString = JSON.stringify(customResourceMatchers);
1221
- const getCustomObjects = useCallback(
1222
- async () => {
1223
- const auth = await generateAuth(
1224
- entity,
1225
- kubernetesApi,
1226
- kubernetesAuthProvidersApi
1227
- );
1228
- return await kubernetesApi.getCustomObjectsByEntity({
1229
- auth,
1230
- customResources: customResourceMatchers,
1231
- entity
1232
- });
1233
- },
1234
- // eslint-disable-next-line react-hooks/exhaustive-deps
1235
- [kubernetesApi, entity, kubernetesAuthProvidersApi, matchersString]
1236
- );
1237
- const { value, loading, error, retry } = useAsyncRetry(
1238
- () => getCustomObjects(),
1239
- [getCustomObjects]
1240
- );
1241
- useInterval(() => retry(), intervalMs);
1242
- return {
1243
- kubernetesObjects: value,
1244
- loading,
1245
- error: error == null ? void 0 : error.message
1246
- };
1247
- };
1248
-
1249
- const PodNamesWithErrorsContext = React__default.createContext(
1250
- /* @__PURE__ */ new Set()
1251
- );
1252
-
1253
- const PodNamesWithMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
1254
-
1255
- const GroupedResponsesContext = React__default.createContext({
1256
- pods: [],
1257
- replicaSets: [],
1258
- deployments: [],
1259
- services: [],
1260
- configMaps: [],
1261
- horizontalPodAutoscalers: [],
1262
- ingresses: [],
1263
- jobs: [],
1264
- cronJobs: [],
1265
- customResources: [],
1266
- statefulsets: []
1267
- });
1268
-
1269
- const ClusterContext = React__default.createContext({
1270
- name: ""
1271
- });
1272
-
1273
- const PodMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
1274
- const usePodMetrics = (clusterName, matcher) => {
1275
- var _a, _b, _c, _d;
1276
- const targetRef = {
1277
- name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
1278
- namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1279
- };
1280
- const metricsMap = useContext(PodMetricsContext);
1281
- const metrics = metricsMap.get(clusterName);
1282
- return metrics == null ? void 0 : metrics.find((m) => {
1283
- var _a2, _b2, _c2, _d2;
1284
- const pod = m.pod;
1285
- 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 : "");
1286
- });
1287
- };
1288
-
1289
- const DetectedErrorsContext = React__default.createContext([]);
1290
- const useMatchingErrors = (matcher) => {
1291
- var _a, _b, _c, _d;
1292
- const targetRef = {
1293
- name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
1294
- namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
1295
- kind: matcher.kind,
1296
- apiGroup: matcher.apiVersion
1297
- };
1298
- const errors = useContext(DetectedErrorsContext);
1299
- return errors.filter((e) => {
1300
- const r = e.sourceRef;
1301
- return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
1302
- });
1303
- };
1304
-
1305
1481
  const kindMappings$3 = {
1306
1482
  deployment: "deployment",
1307
1483
  pod: "pod",
@@ -3558,5 +3734,5 @@ var Router$1 = /*#__PURE__*/Object.freeze({
3558
3734
  Router: Router
3559
3735
  });
3560
3736
 
3561
- 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 };
3737
+ 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, PodExecTerminal, PodExecTerminalDialog, PodLogs, PodLogsDialog, PodMetricsContext, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, ResourceUtilization, Router, ServerSideKubernetesAuthProvider, ServicesAccordions, clusterLinksFormatters, detectErrors, formatClusterLink, isKubernetesAvailable, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesPlugin, kubernetesProxyApiRef, kubernetesPlugin as plugin, useCustomResources, useEvents, useIsPodExecTerminalSupported, useKubernetesObjects, useMatchingErrors, usePodLogs, usePodMetrics };
3562
3738
  //# sourceMappingURL=index.esm.js.map