@backstage/plugin-kubernetes-react 0.0.0-nightly-20230927021302

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.
@@ -0,0 +1,3229 @@
1
+ import { createApiRef, useApi, discoveryApiRef } from '@backstage/core-plugin-api';
2
+ import useAsync from 'react-use/lib/useAsync';
3
+ import * as React from 'react';
4
+ import React__default, { useCallback, useContext, useState, useEffect, useMemo, Fragment } from 'react';
5
+ import useInterval from 'react-use/lib/useInterval';
6
+ import useAsyncRetry from 'react-use/lib/useAsyncRetry';
7
+ import { stringifyEntityRef } from '@backstage/catalog-model';
8
+ import { NotFoundError } from '@backstage/errors';
9
+ import { makeStyles, createStyles, Dialog, DialogTitle, IconButton, DialogContent, Button, Grid, Typography, 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';
10
+ import { groupResponses } from '@backstage/plugin-kubernetes-common';
11
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
12
+ import { LinearGauge, DismissableBanner, EmptyState, LogViewer, StructuredMetadataTable, CodeSnippet, WarningPanel, LinkButton, StatusError, StatusOK, StatusWarning, ItemCardGrid, SubvalueCell, StatusAborted, Table, StatusPending } from '@backstage/core-components';
13
+ import { DateTime } from 'luxon';
14
+ import CloseIcon from '@material-ui/icons/Close';
15
+ import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser';
16
+ import { Terminal } from 'xterm';
17
+ import { FitAddon } from 'xterm-addon-fit';
18
+ import { AttachAddon } from 'xterm-addon-attach';
19
+ import { Skeleton } from '@material-ui/lab';
20
+ import SubjectIcon from '@material-ui/icons/Subject';
21
+ import OpenInNewIcon from '@material-ui/icons/OpenInNew';
22
+ import { withStyles, makeStyles as makeStyles$1, createStyles as createStyles$1 } from '@material-ui/core/styles';
23
+ import jsyaml from 'js-yaml';
24
+ import Dialog$1 from '@material-ui/core/Dialog';
25
+ import DialogActions from '@material-ui/core/DialogActions';
26
+ import DialogContent$1 from '@material-ui/core/DialogContent';
27
+ import DialogTitle$1 from '@material-ui/core/DialogTitle';
28
+ import IconButton$1 from '@material-ui/core/IconButton';
29
+ import Typography$1 from '@material-ui/core/Typography';
30
+ import HelpIcon from '@material-ui/icons/Help';
31
+ import InfoIcon from '@material-ui/icons/Info';
32
+ import WarningIcon from '@material-ui/icons/Warning';
33
+ import cronstrue from 'cronstrue';
34
+ import lodash from 'lodash';
35
+ import PauseIcon from '@material-ui/icons/Pause';
36
+ import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
37
+
38
+ const kubernetesApiRef = createApiRef({
39
+ id: "plugin.kubernetes.service"
40
+ });
41
+ const kubernetesProxyApiRef = createApiRef({
42
+ id: "plugin.kubernetes.proxy-service"
43
+ });
44
+
45
+ const useIsPodExecTerminalSupported = () => {
46
+ const kubernetesApi = useApi(kubernetesApiRef);
47
+ return useAsync(async () => {
48
+ const clusters = await kubernetesApi.getClusters();
49
+ if (clusters.length !== 1) {
50
+ return false;
51
+ }
52
+ const { authProvider } = clusters[0];
53
+ const isClientAuthProvider = ["aks", "google", "oidc"].some(
54
+ (authProviderName) => authProvider.includes(authProviderName)
55
+ );
56
+ return !isClientAuthProvider;
57
+ });
58
+ };
59
+
60
+ const generateAuth = async (entity, kubernetesApi, kubernetesAuthProvidersApi) => {
61
+ var _a;
62
+ const clusters = await kubernetesApi.getClusters();
63
+ const authProviders = [
64
+ ...new Set(
65
+ clusters.map(
66
+ (c) => `${c.authProvider}${c.oidcTokenProvider ? `.${c.oidcTokenProvider}` : ""}`
67
+ )
68
+ )
69
+ ];
70
+ let requestBody = {
71
+ entity
72
+ };
73
+ for (const authProviderStr of authProviders) {
74
+ requestBody = await kubernetesAuthProvidersApi.decorateRequestBodyForAuth(
75
+ authProviderStr,
76
+ requestBody
77
+ );
78
+ }
79
+ return (_a = requestBody.auth) != null ? _a : {};
80
+ };
81
+
82
+ const kubernetesAuthProvidersApiRef = createApiRef({
83
+ id: "plugin.kubernetes-auth-providers.service"
84
+ });
85
+
86
+ var __defProp$4 = Object.defineProperty;
87
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
88
+ var __publicField$4 = (obj, key, value) => {
89
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
90
+ return value;
91
+ };
92
+ class GoogleKubernetesAuthProvider {
93
+ constructor(authProvider) {
94
+ __publicField$4(this, "authProvider");
95
+ this.authProvider = authProvider;
96
+ }
97
+ async decorateRequestBodyForAuth(requestBody) {
98
+ const googleAuthToken = (await this.getCredentials()).token;
99
+ if ("auth" in requestBody) {
100
+ requestBody.auth.google = googleAuthToken;
101
+ } else {
102
+ requestBody.auth = { google: googleAuthToken };
103
+ }
104
+ return requestBody;
105
+ }
106
+ async getCredentials() {
107
+ return {
108
+ token: await this.authProvider.getAccessToken(
109
+ "https://www.googleapis.com/auth/cloud-platform.read-only"
110
+ )
111
+ };
112
+ }
113
+ }
114
+
115
+ class ServerSideKubernetesAuthProvider {
116
+ async decorateRequestBodyForAuth(requestBody) {
117
+ return requestBody;
118
+ }
119
+ async getCredentials() {
120
+ return {};
121
+ }
122
+ }
123
+
124
+ var __defProp$3 = Object.defineProperty;
125
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
126
+ var __publicField$3 = (obj, key, value) => {
127
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
128
+ return value;
129
+ };
130
+ class OidcKubernetesAuthProvider {
131
+ constructor(providerName, authProvider) {
132
+ __publicField$3(this, "providerName");
133
+ __publicField$3(this, "authProvider");
134
+ this.providerName = providerName;
135
+ this.authProvider = authProvider;
136
+ }
137
+ async decorateRequestBodyForAuth(requestBody) {
138
+ const authToken = (await this.getCredentials()).token;
139
+ const auth = { ...requestBody.auth };
140
+ if (auth.oidc) {
141
+ auth.oidc[this.providerName] = authToken;
142
+ } else {
143
+ auth.oidc = { [this.providerName]: authToken };
144
+ }
145
+ requestBody.auth = auth;
146
+ return requestBody;
147
+ }
148
+ async getCredentials() {
149
+ return {
150
+ token: await this.authProvider.getIdToken()
151
+ };
152
+ }
153
+ }
154
+
155
+ class AksKubernetesAuthProvider {
156
+ constructor(microsoftAuthApi) {
157
+ this.microsoftAuthApi = microsoftAuthApi;
158
+ }
159
+ async decorateRequestBodyForAuth(requestBody) {
160
+ return {
161
+ ...requestBody,
162
+ auth: { ...requestBody.auth, aks: (await this.getCredentials()).token }
163
+ };
164
+ }
165
+ async getCredentials() {
166
+ return {
167
+ token: await this.microsoftAuthApi.getAccessToken(
168
+ "6dae42f8-4368-4678-94ff-3960e28e3630/user.read"
169
+ )
170
+ };
171
+ }
172
+ }
173
+
174
+ var __defProp$2 = Object.defineProperty;
175
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
176
+ var __publicField$2 = (obj, key, value) => {
177
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
178
+ return value;
179
+ };
180
+ class KubernetesAuthProviders {
181
+ constructor(options) {
182
+ __publicField$2(this, "kubernetesAuthProviderMap");
183
+ this.kubernetesAuthProviderMap = /* @__PURE__ */ new Map();
184
+ this.kubernetesAuthProviderMap.set(
185
+ "google",
186
+ new GoogleKubernetesAuthProvider(options.googleAuthApi)
187
+ );
188
+ this.kubernetesAuthProviderMap.set(
189
+ "serviceAccount",
190
+ new ServerSideKubernetesAuthProvider()
191
+ );
192
+ this.kubernetesAuthProviderMap.set(
193
+ "googleServiceAccount",
194
+ new ServerSideKubernetesAuthProvider()
195
+ );
196
+ this.kubernetesAuthProviderMap.set(
197
+ "aws",
198
+ new ServerSideKubernetesAuthProvider()
199
+ );
200
+ this.kubernetesAuthProviderMap.set(
201
+ "azure",
202
+ new ServerSideKubernetesAuthProvider()
203
+ );
204
+ this.kubernetesAuthProviderMap.set(
205
+ "localKubectlProxy",
206
+ new ServerSideKubernetesAuthProvider()
207
+ );
208
+ this.kubernetesAuthProviderMap.set(
209
+ "aks",
210
+ new AksKubernetesAuthProvider(options.microsoftAuthApi)
211
+ );
212
+ if (options.oidcProviders) {
213
+ Object.keys(options.oidcProviders).forEach((provider) => {
214
+ this.kubernetesAuthProviderMap.set(
215
+ `oidc.${provider}`,
216
+ new OidcKubernetesAuthProvider(
217
+ provider,
218
+ options.oidcProviders[provider]
219
+ )
220
+ );
221
+ });
222
+ }
223
+ }
224
+ async decorateRequestBodyForAuth(authProvider, requestBody) {
225
+ const kubernetesAuthProvider = this.kubernetesAuthProviderMap.get(authProvider);
226
+ if (kubernetesAuthProvider) {
227
+ return await kubernetesAuthProvider.decorateRequestBodyForAuth(
228
+ requestBody
229
+ );
230
+ }
231
+ if (authProvider.startsWith("oidc.")) {
232
+ throw new Error(
233
+ `KubernetesAuthProviders has no oidcProvider configured for ${authProvider}`
234
+ );
235
+ }
236
+ throw new Error(
237
+ `authProvider "${authProvider}" has no KubernetesAuthProvider defined for it`
238
+ );
239
+ }
240
+ async getCredentials(authProvider) {
241
+ const kubernetesAuthProvider = this.kubernetesAuthProviderMap.get(authProvider);
242
+ if (kubernetesAuthProvider) {
243
+ return await kubernetesAuthProvider.getCredentials();
244
+ }
245
+ if (authProvider.startsWith("oidc.")) {
246
+ throw new Error(
247
+ `KubernetesAuthProviders has no oidcProvider configured for ${authProvider}`
248
+ );
249
+ }
250
+ throw new Error(
251
+ `authProvider "${authProvider}" has no KubernetesAuthProvider defined for it`
252
+ );
253
+ }
254
+ }
255
+
256
+ const useKubernetesObjects = (entity, intervalMs = 1e4) => {
257
+ const kubernetesApi = useApi(kubernetesApiRef);
258
+ const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
259
+ const getObjects = useCallback(async () => {
260
+ const auth = await generateAuth(
261
+ entity,
262
+ kubernetesApi,
263
+ kubernetesAuthProvidersApi
264
+ );
265
+ return await kubernetesApi.getObjectsByEntity({
266
+ auth,
267
+ entity
268
+ });
269
+ }, [kubernetesApi, entity, kubernetesAuthProvidersApi]);
270
+ const { value, loading, error, retry } = useAsyncRetry(
271
+ () => getObjects(),
272
+ [getObjects]
273
+ );
274
+ useInterval(() => retry(), intervalMs);
275
+ return {
276
+ kubernetesObjects: value,
277
+ loading,
278
+ error: error == null ? void 0 : error.message
279
+ };
280
+ };
281
+
282
+ const useCustomResources = (entity, customResourceMatchers, intervalMs = 1e4) => {
283
+ const kubernetesApi = useApi(kubernetesApiRef);
284
+ const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
285
+ const matchersString = JSON.stringify(customResourceMatchers);
286
+ const getCustomObjects = useCallback(
287
+ async () => {
288
+ const auth = await generateAuth(
289
+ entity,
290
+ kubernetesApi,
291
+ kubernetesAuthProvidersApi
292
+ );
293
+ return await kubernetesApi.getCustomObjectsByEntity({
294
+ auth,
295
+ customResources: customResourceMatchers,
296
+ entity
297
+ });
298
+ },
299
+ // eslint-disable-next-line react-hooks/exhaustive-deps
300
+ [kubernetesApi, entity, kubernetesAuthProvidersApi, matchersString]
301
+ );
302
+ const { value, loading, error, retry } = useAsyncRetry(
303
+ () => getCustomObjects(),
304
+ [getCustomObjects]
305
+ );
306
+ useInterval(() => retry(), intervalMs);
307
+ return {
308
+ kubernetesObjects: value,
309
+ loading,
310
+ error: error == null ? void 0 : error.message
311
+ };
312
+ };
313
+
314
+ const PodNamesWithErrorsContext = React__default.createContext(
315
+ /* @__PURE__ */ new Set()
316
+ );
317
+
318
+ const PodNamesWithMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
319
+
320
+ const GroupedResponsesContext = React__default.createContext({
321
+ pods: [],
322
+ replicaSets: [],
323
+ deployments: [],
324
+ services: [],
325
+ configMaps: [],
326
+ horizontalPodAutoscalers: [],
327
+ ingresses: [],
328
+ jobs: [],
329
+ cronJobs: [],
330
+ customResources: [],
331
+ statefulsets: []
332
+ });
333
+
334
+ const ClusterContext = React__default.createContext({
335
+ name: ""
336
+ });
337
+
338
+ const PodMetricsContext = React__default.createContext(/* @__PURE__ */ new Map());
339
+ const usePodMetrics = (clusterName, matcher) => {
340
+ var _a, _b, _c, _d;
341
+ const targetRef = {
342
+ name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
343
+ namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
344
+ };
345
+ const metricsMap = useContext(PodMetricsContext);
346
+ const metrics = metricsMap.get(clusterName);
347
+ return metrics == null ? void 0 : metrics.find((m) => {
348
+ var _a2, _b2, _c2, _d2;
349
+ const pod = m.pod;
350
+ 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 : "");
351
+ });
352
+ };
353
+
354
+ const DetectedErrorsContext = React__default.createContext([]);
355
+ const useMatchingErrors = (matcher) => {
356
+ var _a, _b, _c, _d;
357
+ const targetRef = {
358
+ name: (_b = (_a = matcher.metadata) == null ? void 0 : _a.name) != null ? _b : "",
359
+ namespace: (_d = (_c = matcher.metadata) == null ? void 0 : _c.namespace) != null ? _d : "",
360
+ kind: matcher.kind,
361
+ apiGroup: matcher.apiVersion
362
+ };
363
+ const errors = useContext(DetectedErrorsContext);
364
+ return errors.filter((e) => {
365
+ const r = e.sourceRef;
366
+ return targetRef.apiGroup === r.apiGroup && targetRef.kind === r.kind && targetRef.name === r.name && targetRef.namespace === r.namespace;
367
+ });
368
+ };
369
+
370
+ var __defProp$1 = Object.defineProperty;
371
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
372
+ var __publicField$1 = (obj, key, value) => {
373
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
374
+ return value;
375
+ };
376
+ class KubernetesBackendClient {
377
+ constructor(options) {
378
+ __publicField$1(this, "discoveryApi");
379
+ __publicField$1(this, "identityApi");
380
+ __publicField$1(this, "kubernetesAuthProvidersApi");
381
+ this.discoveryApi = options.discoveryApi;
382
+ this.identityApi = options.identityApi;
383
+ this.kubernetesAuthProvidersApi = options.kubernetesAuthProvidersApi;
384
+ }
385
+ async handleResponse(response) {
386
+ if (!response.ok) {
387
+ const payload = await response.text();
388
+ let message;
389
+ switch (response.status) {
390
+ case 404:
391
+ message = "Could not find the Kubernetes Backend (HTTP 404). Make sure the plugin has been fully installed.";
392
+ break;
393
+ default:
394
+ message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
395
+ }
396
+ throw new Error(message);
397
+ }
398
+ return await response.json();
399
+ }
400
+ async postRequired(path, requestBody) {
401
+ const url = `${await this.discoveryApi.getBaseUrl("kubernetes")}${path}`;
402
+ const { token: idToken } = await this.identityApi.getCredentials();
403
+ const response = await fetch(url, {
404
+ method: "POST",
405
+ headers: {
406
+ "Content-Type": "application/json",
407
+ ...idToken && { Authorization: `Bearer ${idToken}` }
408
+ },
409
+ body: JSON.stringify(requestBody)
410
+ });
411
+ return this.handleResponse(response);
412
+ }
413
+ async getCluster(clusterName) {
414
+ const cluster = await this.getClusters().then(
415
+ (clusters) => clusters.find((c) => c.name === clusterName)
416
+ );
417
+ if (!cluster) {
418
+ throw new NotFoundError(`Cluster ${clusterName} not found`);
419
+ }
420
+ return cluster;
421
+ }
422
+ async getCredentials(authProvider) {
423
+ return await this.kubernetesAuthProvidersApi.getCredentials(authProvider);
424
+ }
425
+ async getObjectsByEntity(requestBody) {
426
+ return await this.postRequired(
427
+ `/services/${requestBody.entity.metadata.name}`,
428
+ requestBody
429
+ );
430
+ }
431
+ async getWorkloadsByEntity(request) {
432
+ return await this.postRequired("/resources/workloads/query", {
433
+ auth: request.auth,
434
+ entityRef: stringifyEntityRef(request.entity)
435
+ });
436
+ }
437
+ async getCustomObjectsByEntity(request) {
438
+ return await this.postRequired(`/resources/custom/query`, {
439
+ entityRef: stringifyEntityRef(request.entity),
440
+ auth: request.auth,
441
+ customResources: request.customResources
442
+ });
443
+ }
444
+ async getClusters() {
445
+ const { token: idToken } = await this.identityApi.getCredentials();
446
+ const url = `${await this.discoveryApi.getBaseUrl("kubernetes")}/clusters`;
447
+ const response = await fetch(url, {
448
+ method: "GET",
449
+ headers: {
450
+ ...idToken && { Authorization: `Bearer ${idToken}` }
451
+ }
452
+ });
453
+ return (await this.handleResponse(response)).items;
454
+ }
455
+ async proxy(options) {
456
+ var _a;
457
+ const { authProvider } = await this.getCluster(options.clusterName);
458
+ const { token: k8sToken } = await this.getCredentials(authProvider);
459
+ const url = `${await this.discoveryApi.getBaseUrl("kubernetes")}/proxy${options.path}`;
460
+ const identityResponse = await this.identityApi.getCredentials();
461
+ const headers = {
462
+ ...(_a = options.init) == null ? void 0 : _a.headers,
463
+ [`Backstage-Kubernetes-Cluster`]: options.clusterName,
464
+ ...k8sToken && {
465
+ [`Backstage-Kubernetes-Authorization`]: `Bearer ${k8sToken}`
466
+ },
467
+ ...identityResponse.token && {
468
+ Authorization: `Bearer ${identityResponse.token}`
469
+ }
470
+ };
471
+ return await fetch(url, { ...options.init, headers });
472
+ }
473
+ }
474
+
475
+ var __defProp = Object.defineProperty;
476
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
477
+ var __publicField = (obj, key, value) => {
478
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
479
+ return value;
480
+ };
481
+ class KubernetesProxyClient {
482
+ constructor(options) {
483
+ __publicField(this, "kubernetesApi");
484
+ this.kubernetesApi = options.kubernetesApi;
485
+ }
486
+ async handleText(response) {
487
+ if (!response.ok) {
488
+ const payload = await response.text();
489
+ let message;
490
+ switch (response.status) {
491
+ default:
492
+ message = `Proxy request failed with ${response.status} ${response.statusText}, ${payload}`;
493
+ }
494
+ throw new Error(message);
495
+ }
496
+ return await response.text();
497
+ }
498
+ async handleJson(response) {
499
+ if (!response.ok) {
500
+ const payload = await response.text();
501
+ let message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
502
+ switch (response.status) {
503
+ case 404:
504
+ message = `Proxy request failed with ${response.status} ${response.statusText}, ${payload}`;
505
+ break;
506
+ default:
507
+ message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
508
+ }
509
+ throw new Error(message);
510
+ }
511
+ return await response.json();
512
+ }
513
+ async getEventsByInvolvedObjectName({
514
+ clusterName,
515
+ involvedObjectName,
516
+ namespace
517
+ }) {
518
+ return await this.kubernetesApi.proxy({
519
+ clusterName,
520
+ path: `/api/v1/namespaces/${namespace}/events?fieldSelector=involvedObject.name=${involvedObjectName}`,
521
+ init: {
522
+ method: "GET"
523
+ }
524
+ }).then((response) => this.handleJson(response)).then((eventList) => eventList.items);
525
+ }
526
+ async getPodLogs({
527
+ podName,
528
+ namespace,
529
+ clusterName,
530
+ containerName,
531
+ previous
532
+ }) {
533
+ const params = new URLSearchParams({
534
+ container: containerName
535
+ });
536
+ if (previous) {
537
+ params.append("previous", "");
538
+ }
539
+ return await this.kubernetesApi.proxy({
540
+ clusterName,
541
+ path: `/api/v1/namespaces/${namespace}/pods/${podName}/log?${params.toString()}`,
542
+ init: {
543
+ method: "GET"
544
+ }
545
+ }).then((response) => this.handleText(response)).then((text) => ({ text }));
546
+ }
547
+ }
548
+
549
+ const currentToDeclaredResourceToPerc$1 = (current, resource) => {
550
+ if (Number(resource) === 0)
551
+ return 0;
552
+ if (typeof current === "number" && typeof resource === "number") {
553
+ return Math.round(current / resource * 100);
554
+ }
555
+ const numerator = BigInt(current);
556
+ const denominator = BigInt(resource);
557
+ return Number(numerator * BigInt(100) / denominator);
558
+ };
559
+ const bytesToMiB = (value) => {
560
+ return `${(parseFloat(value.toString()) / 1024 / 1024).toFixed(0)}MiB`;
561
+ };
562
+ const formatMillicores = (value) => {
563
+ return `${(parseFloat(value.toString()) * 1e3).toFixed(0)}m`;
564
+ };
565
+
566
+ var __accessCheck = (obj, member, msg) => {
567
+ if (!member.has(obj))
568
+ throw TypeError("Cannot " + msg);
569
+ };
570
+ var __privateGet = (obj, member, getter) => {
571
+ __accessCheck(obj, member, "read from private field");
572
+ return getter ? getter.call(obj) : member.get(obj);
573
+ };
574
+ var __privateAdd = (obj, member, value) => {
575
+ if (member.has(obj))
576
+ throw TypeError("Cannot add the same private member more than once");
577
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
578
+ };
579
+ var _textEncoder;
580
+ class PodExecTerminalAttachAddon extends AttachAddon {
581
+ constructor(socket, options) {
582
+ super(socket, options);
583
+ __privateAdd(this, _textEncoder, new TextEncoder());
584
+ const thisAddon = this;
585
+ thisAddon._sendBinary = (data) => {
586
+ if (!thisAddon._checkOpenSocket()) {
587
+ return;
588
+ }
589
+ const buffer = Uint8Array.from([0, ...__privateGet(this, _textEncoder).encode(data)]);
590
+ thisAddon._socket.send(buffer);
591
+ };
592
+ thisAddon._sendData = (data) => {
593
+ if (!thisAddon._checkOpenSocket()) {
594
+ return;
595
+ }
596
+ thisAddon._sendBinary(data);
597
+ };
598
+ }
599
+ }
600
+ _textEncoder = new WeakMap();
601
+
602
+ const hasSocketProtocol = (url) => /wss?:\/\//.test(url.toString());
603
+ const PodExecTerminal = (props) => {
604
+ const { containerName, podNamespace, podName } = props;
605
+ const [baseUrl, setBaseUrl] = useState(window.location.host);
606
+ const terminalRef = React__default.useRef(null);
607
+ const discoveryApi = useApi(discoveryApiRef);
608
+ const namespace = podNamespace != null ? podNamespace : "default";
609
+ useEffect(() => {
610
+ discoveryApi.getBaseUrl("kubernetes").then((url) => url != null ? url : window.location.host).then((url) => url.replace(/^http(s?):\/\//, "ws$1://")).then((url) => setBaseUrl(url));
611
+ }, [discoveryApi]);
612
+ const urlParams = useMemo(() => {
613
+ const params = new URLSearchParams({
614
+ container: containerName,
615
+ stdin: "true",
616
+ stdout: "true",
617
+ stderr: "true",
618
+ tty: "true",
619
+ command: "/bin/sh"
620
+ });
621
+ return params;
622
+ }, [containerName]);
623
+ const socketUrl = useMemo(() => {
624
+ if (!hasSocketProtocol(baseUrl)) {
625
+ return "";
626
+ }
627
+ return new URL(
628
+ `${baseUrl}/proxy/api/v1/namespaces/${namespace}/pods/${podName}/exec?${urlParams}`
629
+ );
630
+ }, [baseUrl, namespace, podName, urlParams]);
631
+ useEffect(() => {
632
+ if (!hasSocketProtocol(socketUrl)) {
633
+ return () => {
634
+ };
635
+ }
636
+ const terminal = new Terminal();
637
+ const fitAddon = new FitAddon();
638
+ terminal.loadAddon(fitAddon);
639
+ if (terminalRef.current) {
640
+ terminal.open(terminalRef.current);
641
+ fitAddon.fit();
642
+ }
643
+ terminal.writeln("Starting terminal, please wait...");
644
+ const socket = new WebSocket(socketUrl, ["channel.k8s.io"]);
645
+ socket.onopen = () => {
646
+ terminal.clear();
647
+ const attachAddon = new PodExecTerminalAttachAddon(socket, {
648
+ bidirectional: true
649
+ });
650
+ terminal.loadAddon(attachAddon);
651
+ };
652
+ socket.onclose = () => {
653
+ terminal.writeln("Socket connection closed");
654
+ };
655
+ return () => {
656
+ terminal == null ? void 0 : terminal.clear();
657
+ socket == null ? void 0 : socket.close();
658
+ };
659
+ }, [baseUrl, socketUrl]);
660
+ return /* @__PURE__ */ React__default.createElement(
661
+ "div",
662
+ {
663
+ "data-testid": "terminal",
664
+ ref: terminalRef,
665
+ style: {
666
+ width: "100%",
667
+ height: "100%"
668
+ }
669
+ }
670
+ );
671
+ };
672
+
673
+ const useStyles$3 = makeStyles(
674
+ (theme) => createStyles({
675
+ dialogPaper: { minHeight: "calc(100% - 64px)" },
676
+ dialogContent: { flexBasis: 0 },
677
+ closeButton: {
678
+ position: "absolute",
679
+ right: theme.spacing(1),
680
+ top: theme.spacing(1),
681
+ color: theme.palette.grey[500]
682
+ }
683
+ })
684
+ );
685
+ const PodExecTerminalDialog = (props) => {
686
+ const classes = useStyles$3();
687
+ const { clusterName, containerName, podName } = props;
688
+ const [open, setOpen] = useState(false);
689
+ const isPodExecTerminalSupported = useIsPodExecTerminalSupported();
690
+ const openDialog = () => {
691
+ setOpen(true);
692
+ };
693
+ const closeDialog = () => {
694
+ setOpen(false);
695
+ };
696
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, !isPodExecTerminalSupported.loading && isPodExecTerminalSupported.value && /* @__PURE__ */ React__default.createElement(
697
+ Dialog,
698
+ {
699
+ maxWidth: false,
700
+ fullWidth: true,
701
+ open,
702
+ onClose: closeDialog,
703
+ PaperProps: { className: classes.dialogPaper }
704
+ },
705
+ /* @__PURE__ */ React__default.createElement(DialogTitle, { id: "dialog-title" }, podName, " - ", containerName, " terminal shell on cluster", " ", clusterName, /* @__PURE__ */ React__default.createElement(
706
+ IconButton,
707
+ {
708
+ "aria-label": "close",
709
+ className: classes.closeButton,
710
+ onClick: closeDialog
711
+ },
712
+ /* @__PURE__ */ React__default.createElement(CloseIcon, null)
713
+ )),
714
+ /* @__PURE__ */ React__default.createElement(DialogContent, { className: classes.dialogContent }, /* @__PURE__ */ React__default.createElement(PodExecTerminal, { ...props }))
715
+ ), /* @__PURE__ */ React__default.createElement(
716
+ Button,
717
+ {
718
+ variant: "outlined",
719
+ "aria-label": "open terminal",
720
+ component: "label",
721
+ disabled: isPodExecTerminalSupported.loading || !isPodExecTerminalSupported.value,
722
+ onClick: openDialog,
723
+ startIcon: /* @__PURE__ */ React__default.createElement(OpenInBrowserIcon, null)
724
+ },
725
+ "Terminal"
726
+ ));
727
+ };
728
+
729
+ const getProgressColor = ({
730
+ palette,
731
+ value,
732
+ inverse,
733
+ max
734
+ }) => {
735
+ if (isNaN(value)) {
736
+ return palette.status.pending;
737
+ }
738
+ const actualMax = max ? max : 100;
739
+ const actualValue = inverse ? actualMax - value : value;
740
+ if (actualValue >= actualMax) {
741
+ return palette.status.error;
742
+ } else if (actualValue > 90 || actualValue < 40) {
743
+ return palette.status.warning;
744
+ }
745
+ return palette.status.ok;
746
+ };
747
+ const ResourceUtilization = ({
748
+ compressed = false,
749
+ title,
750
+ usage,
751
+ total,
752
+ totalFormatted
753
+ }) => {
754
+ const utilization = currentToDeclaredResourceToPerc$1(usage, total);
755
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 0 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
756
+ Typography,
757
+ {
758
+ variant: compressed ? "caption" : "subtitle2"
759
+ },
760
+ `${title}: ${totalFormatted}`
761
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
762
+ LinearGauge,
763
+ {
764
+ getColor: getProgressColor,
765
+ width: compressed ? "thin" : "thick",
766
+ value: utilization / 100
767
+ }
768
+ ), !compressed && /* @__PURE__ */ React__default.createElement(Typography, { variant: "caption" }, "usage: ", `${utilization}%`)));
769
+ };
770
+
771
+ const usePodLogs = ({ containerScope, previous }) => {
772
+ const kubernetesProxyApi = useApi(kubernetesProxyApiRef);
773
+ return useAsync(async () => {
774
+ return await kubernetesProxyApi.getPodLogs({
775
+ podName: containerScope.podName,
776
+ namespace: containerScope.podNamespace,
777
+ containerName: containerScope.containerName,
778
+ clusterName: containerScope.clusterName,
779
+ previous
780
+ });
781
+ }, [JSON.stringify(containerScope)]);
782
+ };
783
+
784
+ const PodLogs = ({
785
+ containerScope,
786
+ previous
787
+ }) => {
788
+ const { value, error, loading } = usePodLogs({
789
+ containerScope,
790
+ previous
791
+ });
792
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, error && /* @__PURE__ */ React__default.createElement(
793
+ DismissableBanner,
794
+ {
795
+ ...{
796
+ message: error.message,
797
+ variant: "error",
798
+ fixed: false
799
+ },
800
+ id: "pod-logs"
801
+ }
802
+ ), /* @__PURE__ */ React__default.createElement(
803
+ Paper,
804
+ {
805
+ elevation: 1,
806
+ style: { height: "100%", width: "100%", minHeight: "55rem" }
807
+ },
808
+ loading && /* @__PURE__ */ React__default.createElement(Skeleton, { variant: "rect", width: "100%", height: "100%" }),
809
+ !loading && value !== void 0 && (value.text === "" ? /* @__PURE__ */ React__default.createElement(
810
+ EmptyState,
811
+ {
812
+ missing: "data",
813
+ title: "No logs emitted",
814
+ description: "No logs were emitted by the container"
815
+ }
816
+ ) : /* @__PURE__ */ React__default.createElement(LogViewer, { text: value.text }))
817
+ ));
818
+ };
819
+
820
+ const useStyles$2 = makeStyles(
821
+ (theme) => createStyles({
822
+ closeButton: {
823
+ position: "absolute",
824
+ right: theme.spacing(1),
825
+ top: theme.spacing(1),
826
+ color: theme.palette.grey[500]
827
+ }
828
+ })
829
+ );
830
+ const PodLogsDialog = ({ containerScope }) => {
831
+ const classes = useStyles$2();
832
+ const [open, setOpen] = useState(false);
833
+ const openDialog = () => {
834
+ setOpen(true);
835
+ };
836
+ const closeDialog = () => {
837
+ setOpen(false);
838
+ };
839
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Dialog, { maxWidth: "xl", fullWidth: true, open, onClose: closeDialog }, /* @__PURE__ */ React__default.createElement(DialogTitle, { id: "dialog-title" }, containerScope.podName, " - ", containerScope.containerName, " logs on cluster ", containerScope.clusterName, /* @__PURE__ */ React__default.createElement(
840
+ IconButton,
841
+ {
842
+ "aria-label": "close",
843
+ className: classes.closeButton,
844
+ onClick: closeDialog
845
+ },
846
+ /* @__PURE__ */ React__default.createElement(CloseIcon, null)
847
+ )), /* @__PURE__ */ React__default.createElement(DialogContent, null, /* @__PURE__ */ React__default.createElement(PodLogs, { containerScope }))), /* @__PURE__ */ React__default.createElement(
848
+ Button,
849
+ {
850
+ variant: "outlined",
851
+ "aria-label": "get logs",
852
+ component: "label",
853
+ onClick: openDialog,
854
+ startIcon: /* @__PURE__ */ React__default.createElement(SubjectIcon, null)
855
+ },
856
+ "Logs"
857
+ ));
858
+ };
859
+
860
+ const getContainerHealthChecks = (containerSpec, containerStatus) => {
861
+ var _a, _b, _c, _d;
862
+ if (((_b = (_a = containerStatus.state) == null ? void 0 : _a.terminated) == null ? void 0 : _b.reason) === "Completed") {
863
+ return {
864
+ "not waiting to start": ((_c = containerStatus.state) == null ? void 0 : _c.waiting) === void 0,
865
+ "no restarts": containerStatus.restartCount === 0
866
+ };
867
+ }
868
+ return {
869
+ "not waiting to start": ((_d = containerStatus.state) == null ? void 0 : _d.waiting) === void 0,
870
+ started: !!containerStatus.started,
871
+ ready: containerStatus.ready,
872
+ "no restarts": containerStatus.restartCount === 0,
873
+ "readiness probe set": containerSpec && (containerSpec == null ? void 0 : containerSpec.readinessProbe) !== void 0
874
+ };
875
+ };
876
+ const getCurrentState = (containerStatus) => {
877
+ var _a, _b, _c, _d, _e;
878
+ return ((_b = (_a = containerStatus.state) == null ? void 0 : _a.waiting) == null ? void 0 : _b.reason) || ((_d = (_c = containerStatus.state) == null ? void 0 : _c.terminated) == null ? void 0 : _d.reason) || (((_e = containerStatus.state) == null ? void 0 : _e.running) !== void 0 ? "Running" : "Unknown");
879
+ };
880
+ const getStartedAtTime = (containerStatus) => {
881
+ var _a, _b, _c, _d;
882
+ return ((_b = (_a = containerStatus.state) == null ? void 0 : _a.running) == null ? void 0 : _b.startedAt) || ((_d = (_c = containerStatus.state) == null ? void 0 : _c.terminated) == null ? void 0 : _d.startedAt);
883
+ };
884
+ const ContainerDatetime = ({ prefix, dateTime }) => {
885
+ return /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, prefix, ":", " ", DateTime.fromISO(dateTime).toRelative({
886
+ locale: "en"
887
+ }));
888
+ };
889
+ const ContainerCard = ({
890
+ podScope,
891
+ containerSpec,
892
+ containerStatus,
893
+ containerMetrics
894
+ }) => {
895
+ var _a, _b;
896
+ if (containerSpec === void 0) {
897
+ return /* @__PURE__ */ React__default.createElement(Typography, null, "error reading pod from cluster");
898
+ }
899
+ const containerStartedTime = getStartedAtTime(containerStatus);
900
+ const containerFinishedTime = (_b = (_a = containerStatus.state) == null ? void 0 : _a.terminated) == null ? void 0 : _b.finishedAt;
901
+ return /* @__PURE__ */ React__default.createElement(Card, null, /* @__PURE__ */ React__default.createElement(
902
+ CardHeader,
903
+ {
904
+ title: containerStatus.name,
905
+ subheader: containerStatus.image
906
+ }
907
+ ), /* @__PURE__ */ React__default.createElement(CardContent, null, /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, containerStartedTime && /* @__PURE__ */ React__default.createElement(
908
+ ContainerDatetime,
909
+ {
910
+ prefix: "Started",
911
+ dateTime: containerStartedTime
912
+ }
913
+ ), containerFinishedTime && /* @__PURE__ */ React__default.createElement(
914
+ ContainerDatetime,
915
+ {
916
+ prefix: "Completed",
917
+ dateTime: containerFinishedTime
918
+ }
919
+ ), containerStartedTime && containerFinishedTime && /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "Execution time:", " ", DateTime.fromISO(containerFinishedTime).diff(DateTime.fromISO(containerStartedTime), [
920
+ "hours",
921
+ "minutes",
922
+ "seconds"
923
+ ]).toHuman())), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "Status: ", getCurrentState(containerStatus))), containerStatus.restartCount > 0 && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "Restarts: ", containerStatus.restartCount)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "Container health")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
924
+ StructuredMetadataTable,
925
+ {
926
+ metadata: getContainerHealthChecks(
927
+ containerSpec,
928
+ containerStatus
929
+ )
930
+ }
931
+ )), 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(
932
+ ResourceUtilization,
933
+ {
934
+ compressed: true,
935
+ title: "CPU requests",
936
+ usage: containerMetrics.cpuUsage.currentUsage,
937
+ total: containerMetrics.cpuUsage.requestTotal,
938
+ totalFormatted: formatMillicores(
939
+ containerMetrics.cpuUsage.requestTotal
940
+ )
941
+ }
942
+ ), /* @__PURE__ */ React__default.createElement(
943
+ ResourceUtilization,
944
+ {
945
+ compressed: true,
946
+ title: "CPU limits",
947
+ usage: containerMetrics.cpuUsage.currentUsage,
948
+ total: containerMetrics.cpuUsage.limitTotal,
949
+ totalFormatted: formatMillicores(
950
+ containerMetrics.cpuUsage.limitTotal
951
+ )
952
+ }
953
+ ), /* @__PURE__ */ React__default.createElement(
954
+ ResourceUtilization,
955
+ {
956
+ compressed: true,
957
+ title: "Memory requests",
958
+ usage: containerMetrics.memoryUsage.currentUsage,
959
+ total: containerMetrics.memoryUsage.requestTotal,
960
+ totalFormatted: bytesToMiB(
961
+ containerMetrics.memoryUsage.requestTotal
962
+ )
963
+ }
964
+ ), /* @__PURE__ */ React__default.createElement(
965
+ ResourceUtilization,
966
+ {
967
+ compressed: true,
968
+ title: "Memory limits",
969
+ usage: containerMetrics.memoryUsage.currentUsage,
970
+ total: containerMetrics.memoryUsage.limitTotal,
971
+ totalFormatted: bytesToMiB(
972
+ containerMetrics.memoryUsage.limitTotal
973
+ )
974
+ }
975
+ ))))), /* @__PURE__ */ React__default.createElement(CardActions, null, /* @__PURE__ */ React__default.createElement(
976
+ PodLogsDialog,
977
+ {
978
+ containerScope: {
979
+ containerName: containerStatus.name,
980
+ ...podScope
981
+ }
982
+ }
983
+ ), /* @__PURE__ */ React__default.createElement(
984
+ PodExecTerminalDialog,
985
+ {
986
+ clusterName: podScope.clusterName,
987
+ containerName: containerStatus.name,
988
+ podName: podScope.podName,
989
+ podNamespace: podScope.podNamespace
990
+ }
991
+ )));
992
+ };
993
+
994
+ const kindMappings$3 = {
995
+ deployment: "deployment",
996
+ pod: "pod",
997
+ ingress: "ingress",
998
+ service: "service",
999
+ horizontalpodautoscaler: "deployment",
1000
+ statefulset: "statefulset"
1001
+ };
1002
+ function standardFormatter(options) {
1003
+ var _a, _b, _c, _d;
1004
+ if (!options.dashboardUrl) {
1005
+ throw new Error("standard dashboard requires a dashboardUrl option");
1006
+ }
1007
+ const result = new URL(options.dashboardUrl.href);
1008
+ const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1009
+ const namespace = encodeURIComponent(
1010
+ (_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1011
+ );
1012
+ const validKind = kindMappings$3[options.kind.toLocaleLowerCase("en-US")];
1013
+ if (!result.pathname.endsWith("/")) {
1014
+ result.pathname += "/";
1015
+ }
1016
+ if (validKind && name && namespace) {
1017
+ result.hash = `/${validKind}/${namespace}/${name}`;
1018
+ } else if (namespace) {
1019
+ result.hash = "/workloads";
1020
+ }
1021
+ if (namespace) {
1022
+ result.hash += `?namespace=${namespace}`;
1023
+ }
1024
+ return result;
1025
+ }
1026
+
1027
+ const kindMappings$2 = {
1028
+ deployment: "apps.deployment",
1029
+ ingress: "networking.k8s.io.ingress",
1030
+ service: "service",
1031
+ horizontalpodautoscaler: "autoscaling.horizontalpodautoscaler"
1032
+ };
1033
+ function rancherFormatter(options) {
1034
+ var _a, _b, _c, _d;
1035
+ if (!options.dashboardUrl) {
1036
+ throw new Error("Rancher dashboard requires a dashboardUrl option");
1037
+ }
1038
+ const basePath = new URL(options.dashboardUrl.href);
1039
+ const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1040
+ const namespace = encodeURIComponent(
1041
+ (_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1042
+ );
1043
+ const validKind = kindMappings$2[options.kind.toLocaleLowerCase("en-US")];
1044
+ if (!basePath.pathname.endsWith("/")) {
1045
+ basePath.pathname += "/";
1046
+ }
1047
+ let path = "";
1048
+ if (validKind && name && namespace) {
1049
+ path = `explorer/${validKind}/${namespace}/${name}`;
1050
+ } else if (namespace) {
1051
+ path = "explorer/workload";
1052
+ }
1053
+ return new URL(path, basePath);
1054
+ }
1055
+
1056
+ const kindMappings$1 = {
1057
+ deployment: "deployments",
1058
+ ingress: "ingresses",
1059
+ service: "services",
1060
+ horizontalpodautoscaler: "horizontalpodautoscalers",
1061
+ persistentvolume: "persistentvolumes"
1062
+ };
1063
+ function openshiftFormatter(options) {
1064
+ var _a, _b, _c, _d;
1065
+ if (!options.dashboardUrl) {
1066
+ throw new Error("OpenShift dashboard requires a dashboardUrl option");
1067
+ }
1068
+ const basePath = new URL(options.dashboardUrl.href);
1069
+ const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1070
+ const namespace = encodeURIComponent(
1071
+ (_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1072
+ );
1073
+ const validKind = kindMappings$1[options.kind.toLocaleLowerCase("en-US")];
1074
+ if (!basePath.pathname.endsWith("/")) {
1075
+ basePath.pathname += "/";
1076
+ }
1077
+ let path = "";
1078
+ if (namespace) {
1079
+ if (name && validKind) {
1080
+ path = `k8s/ns/${namespace}/${validKind}/${name}`;
1081
+ } else {
1082
+ path = `k8s/cluster/projects/${namespace}`;
1083
+ }
1084
+ } else if (validKind) {
1085
+ path = `k8s/cluster/${validKind}`;
1086
+ if (name) {
1087
+ path += `/${name}`;
1088
+ }
1089
+ }
1090
+ return new URL(path, basePath);
1091
+ }
1092
+
1093
+ const basePath = "https://portal.azure.com/#blade/Microsoft_Azure_ContainerService/AksK8ResourceMenuBlade/overview-Deployment/aksClusterId";
1094
+ const requiredParams = ["subscriptionId", "resourceGroup", "clusterName"];
1095
+ function aksFormatter(options) {
1096
+ if (!options.dashboardParameters) {
1097
+ throw new Error("AKS dashboard requires a dashboardParameters option");
1098
+ }
1099
+ const args = options.dashboardParameters;
1100
+ for (const param of requiredParams) {
1101
+ if (typeof args[param] !== "string") {
1102
+ throw new Error(
1103
+ `AKS dashboard requires a "${param}" of type string in the dashboardParameters option`
1104
+ );
1105
+ }
1106
+ }
1107
+ const path = `/subscriptions/${args.subscriptionId}/resourceGroups/${args.resourceGroup}/providers/Microsoft.ContainerService/managedClusters/${args.clusterName}`;
1108
+ const { name, namespace, uid } = options.object.metadata;
1109
+ const { selector } = options.object.spec;
1110
+ const params = {
1111
+ kind: options.kind,
1112
+ metadata: { name, namespace, uid },
1113
+ spec: {
1114
+ selector
1115
+ }
1116
+ };
1117
+ return new URL(
1118
+ `${basePath}/${encodeURIComponent(path)}/resource/${encodeURIComponent(
1119
+ JSON.stringify(params)
1120
+ )}`
1121
+ );
1122
+ }
1123
+
1124
+ function eksFormatter(_options) {
1125
+ throw new Error("EKS formatter is not yet implemented. Please, contribute!");
1126
+ }
1127
+
1128
+ const kindMappings = {
1129
+ deployment: "deployment",
1130
+ pod: "pod",
1131
+ ingress: "ingress",
1132
+ service: "service",
1133
+ horizontalpodautoscaler: "deployment"
1134
+ };
1135
+ function gkeFormatter(options) {
1136
+ var _a, _b, _c, _d;
1137
+ if (!options.dashboardParameters) {
1138
+ throw new Error("GKE dashboard requires a dashboardParameters option");
1139
+ }
1140
+ const args = options.dashboardParameters;
1141
+ if (typeof args.projectId !== "string") {
1142
+ throw new Error(
1143
+ 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option'
1144
+ );
1145
+ }
1146
+ if (typeof args.region !== "string") {
1147
+ throw new Error(
1148
+ 'GKE dashboard requires a "region" of type string in the dashboardParameters option'
1149
+ );
1150
+ }
1151
+ if (typeof args.clusterName !== "string") {
1152
+ throw new Error(
1153
+ 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option'
1154
+ );
1155
+ }
1156
+ const basePath = new URL("https://console.cloud.google.com/");
1157
+ const region = encodeURIComponent(args.region);
1158
+ const clusterName = encodeURIComponent(args.clusterName);
1159
+ const name = encodeURIComponent((_b = (_a = options.object.metadata) == null ? void 0 : _a.name) != null ? _b : "");
1160
+ const namespace = encodeURIComponent(
1161
+ (_d = (_c = options.object.metadata) == null ? void 0 : _c.namespace) != null ? _d : ""
1162
+ );
1163
+ const validKind = kindMappings[options.kind.toLocaleLowerCase("en-US")];
1164
+ let path = "";
1165
+ if (namespace && name && validKind) {
1166
+ const kindsWithDetails = ["ingress", "pod"];
1167
+ const landingPage = kindsWithDetails.includes(validKind) ? "details" : "overview";
1168
+ path = `kubernetes/${validKind}/${region}/${clusterName}/${namespace}/${name}/${landingPage}`;
1169
+ } else {
1170
+ path = `kubernetes/clusters/details/${region}/${clusterName}/details`;
1171
+ }
1172
+ const result = new URL(path, basePath);
1173
+ result.searchParams.set("project", args.projectId);
1174
+ return result;
1175
+ }
1176
+
1177
+ const clusterLinksFormatters = {
1178
+ standard: standardFormatter,
1179
+ rancher: rancherFormatter,
1180
+ openshift: openshiftFormatter,
1181
+ aks: aksFormatter,
1182
+ eks: eksFormatter,
1183
+ gke: gkeFormatter
1184
+ };
1185
+ const defaultFormatterName = "standard";
1186
+
1187
+ function formatClusterLink(options) {
1188
+ if (!options.dashboardUrl && !options.dashboardParameters) {
1189
+ return void 0;
1190
+ }
1191
+ if (options.dashboardUrl && !options.object) {
1192
+ return options.dashboardUrl;
1193
+ }
1194
+ const app = options.dashboardApp || defaultFormatterName;
1195
+ const formatter = clusterLinksFormatters[app];
1196
+ if (!formatter) {
1197
+ throw new Error(`Could not find Kubernetes dashboard app named '${app}'`);
1198
+ }
1199
+ const url = formatter({
1200
+ dashboardUrl: options.dashboardUrl ? new URL(options.dashboardUrl) : void 0,
1201
+ dashboardParameters: options.dashboardParameters,
1202
+ object: options.object,
1203
+ kind: options.kind
1204
+ });
1205
+ return url.toString();
1206
+ }
1207
+
1208
+ const ManifestYaml = ({ object }) => {
1209
+ const [managedFields, setManagedFields] = useState(false);
1210
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
1211
+ FormControlLabel,
1212
+ {
1213
+ control: /* @__PURE__ */ React__default.createElement(
1214
+ Switch,
1215
+ {
1216
+ checked: managedFields,
1217
+ onChange: (event) => {
1218
+ setManagedFields(event.target.checked);
1219
+ },
1220
+ name: "Managed Fields"
1221
+ }
1222
+ ),
1223
+ label: "Managed Fields"
1224
+ }
1225
+ ), /* @__PURE__ */ React__default.createElement(
1226
+ CodeSnippet,
1227
+ {
1228
+ language: "yaml",
1229
+ text: jsyaml.dump(object, {
1230
+ // NOTE: this will remove any field called `managedFields`
1231
+ // not just the metadata one
1232
+ // TODO: @mclarke make this only remove the `metadata.managedFields`
1233
+ replacer: (key, value) => {
1234
+ if (!managedFields) {
1235
+ return key === "managedFields" ? void 0 : value;
1236
+ }
1237
+ return value;
1238
+ }
1239
+ })
1240
+ }
1241
+ ));
1242
+ };
1243
+
1244
+ const useDrawerStyles$1 = makeStyles(
1245
+ (theme) => createStyles({
1246
+ paper: {
1247
+ width: "50%",
1248
+ justifyContent: "space-between",
1249
+ padding: theme.spacing(2.5)
1250
+ }
1251
+ })
1252
+ );
1253
+ const useDrawerContentStyles$2 = makeStyles(
1254
+ (_) => createStyles({
1255
+ header: {
1256
+ display: "flex",
1257
+ flexDirection: "row",
1258
+ justifyContent: "space-between"
1259
+ },
1260
+ errorMessage: {
1261
+ marginTop: "1em",
1262
+ marginBottom: "1em"
1263
+ },
1264
+ options: {
1265
+ display: "flex",
1266
+ flexDirection: "row",
1267
+ justifyContent: "space-between"
1268
+ },
1269
+ icon: {
1270
+ fontSize: 20
1271
+ },
1272
+ content: {
1273
+ height: "80%"
1274
+ }
1275
+ })
1276
+ );
1277
+ const PodDrawerButton = withStyles({
1278
+ root: {
1279
+ padding: "6px 5px"
1280
+ },
1281
+ label: {
1282
+ textTransform: "none"
1283
+ }
1284
+ })(Button);
1285
+ const LinkErrorPanel = ({
1286
+ cluster,
1287
+ errorMessage
1288
+ }) => /* @__PURE__ */ React__default.createElement(
1289
+ WarningPanel,
1290
+ {
1291
+ title: "There was a problem formatting the link to the Kubernetes dashboard",
1292
+ 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"}.'`
1293
+ },
1294
+ errorMessage && /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2" }, "Errors: ", errorMessage)
1295
+ );
1296
+ function replaceNullsWithUndefined(someObj) {
1297
+ const replacer = (_, value) => String(value) === "null" || String(value) === "undefined" ? void 0 : value;
1298
+ return JSON.parse(JSON.stringify(someObj, replacer));
1299
+ }
1300
+ function tryFormatClusterLink(options) {
1301
+ try {
1302
+ return {
1303
+ clusterLink: formatClusterLink(options),
1304
+ errorMessage: ""
1305
+ };
1306
+ } catch (err) {
1307
+ return {
1308
+ clusterLink: "",
1309
+ errorMessage: err.message || err.toString()
1310
+ };
1311
+ }
1312
+ }
1313
+ const KubernetesStructuredMetadataTableDrawerContent = ({
1314
+ toggleDrawer,
1315
+ object,
1316
+ renderObject,
1317
+ kind
1318
+ }) => {
1319
+ var _a, _b;
1320
+ const [isYaml, setIsYaml] = useState(false);
1321
+ const classes = useDrawerContentStyles$2();
1322
+ const cluster = useContext(ClusterContext);
1323
+ const { clusterLink, errorMessage } = tryFormatClusterLink({
1324
+ dashboardUrl: cluster.dashboardUrl,
1325
+ dashboardApp: cluster.dashboardApp,
1326
+ dashboardParameters: cluster.dashboardParameters,
1327
+ object,
1328
+ kind
1329
+ });
1330
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: classes.header }, /* @__PURE__ */ React__default.createElement(Grid, { container: true, justifyContent: "flex-start", alignItems: "flex-start" }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 11 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, (_b = (_a = object.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown name")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 1 }, /* @__PURE__ */ React__default.createElement(
1331
+ IconButton,
1332
+ {
1333
+ key: "dismiss",
1334
+ title: "Close the drawer",
1335
+ onClick: (e) => toggleDrawer(e, false),
1336
+ color: "inherit"
1337
+ },
1338
+ /* @__PURE__ */ React__default.createElement(CloseIcon, { className: classes.icon })
1339
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 11 }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "body1" }, kind)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 11 }, /* @__PURE__ */ React__default.createElement(
1340
+ FormControlLabel,
1341
+ {
1342
+ control: /* @__PURE__ */ React__default.createElement(
1343
+ Switch,
1344
+ {
1345
+ checked: isYaml,
1346
+ onChange: (event) => {
1347
+ setIsYaml(event.target.checked);
1348
+ },
1349
+ name: "YAML"
1350
+ }
1351
+ ),
1352
+ label: "YAML"
1353
+ }
1354
+ )))), errorMessage && /* @__PURE__ */ React__default.createElement("div", { className: classes.errorMessage }, /* @__PURE__ */ React__default.createElement(LinkErrorPanel, { cluster, errorMessage })), /* @__PURE__ */ React__default.createElement("div", { className: classes.options }, /* @__PURE__ */ React__default.createElement("div", null, clusterLink && /* @__PURE__ */ React__default.createElement(
1355
+ LinkButton,
1356
+ {
1357
+ variant: "outlined",
1358
+ color: "primary",
1359
+ size: "small",
1360
+ to: clusterLink,
1361
+ endIcon: /* @__PURE__ */ React__default.createElement(OpenInNewIcon, null)
1362
+ },
1363
+ "Open Kubernetes Dashboard"
1364
+ ))), /* @__PURE__ */ React__default.createElement("div", { className: classes.content }, isYaml && /* @__PURE__ */ React__default.createElement(ManifestYaml, { object }), !isYaml && /* @__PURE__ */ React__default.createElement(
1365
+ StructuredMetadataTable,
1366
+ {
1367
+ metadata: renderObject(replaceNullsWithUndefined(object))
1368
+ }
1369
+ )));
1370
+ };
1371
+ const KubernetesStructuredMetadataTableDrawer = ({
1372
+ object,
1373
+ renderObject,
1374
+ kind,
1375
+ buttonVariant = "subtitle2",
1376
+ expanded = false,
1377
+ children
1378
+ }) => {
1379
+ var _a, _b;
1380
+ const [isOpen, setIsOpen] = useState(expanded);
1381
+ const classes = useDrawerStyles$1();
1382
+ const toggleDrawer = (e, newValue) => {
1383
+ e.stopPropagation();
1384
+ setIsOpen(newValue);
1385
+ };
1386
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
1387
+ PodDrawerButton,
1388
+ {
1389
+ onClick: (e) => toggleDrawer(e, true),
1390
+ onFocus: (event) => event.stopPropagation()
1391
+ },
1392
+ children === void 0 ? /* @__PURE__ */ React__default.createElement(Typography, { variant: buttonVariant }, (_b = (_a = object.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown object") : children
1393
+ ), /* @__PURE__ */ React__default.createElement(
1394
+ Drawer,
1395
+ {
1396
+ classes: {
1397
+ paper: classes.paper
1398
+ },
1399
+ anchor: "right",
1400
+ open: isOpen,
1401
+ onClose: (e) => toggleDrawer(e, false),
1402
+ onClick: (event) => event.stopPropagation()
1403
+ },
1404
+ /* @__PURE__ */ React__default.createElement(
1405
+ KubernetesStructuredMetadataTableDrawerContent,
1406
+ {
1407
+ kind,
1408
+ toggleDrawer,
1409
+ object,
1410
+ renderObject
1411
+ }
1412
+ )
1413
+ ));
1414
+ };
1415
+
1416
+ const useDrawerContentStyles$1 = makeStyles(
1417
+ (_theme) => createStyles({
1418
+ header: {
1419
+ display: "flex",
1420
+ flexDirection: "row",
1421
+ justifyContent: "space-between"
1422
+ },
1423
+ content: {
1424
+ height: "80%"
1425
+ },
1426
+ icon: {
1427
+ fontSize: 20
1428
+ }
1429
+ })
1430
+ );
1431
+ const KubernetesDrawerContent = ({
1432
+ children,
1433
+ header,
1434
+ kubernetesObject,
1435
+ close
1436
+ }) => {
1437
+ var _a;
1438
+ const classes = useDrawerContentStyles$1();
1439
+ const [isYaml, setIsYaml] = useState(false);
1440
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: classes.header }, /* @__PURE__ */ React__default.createElement(Grid, { container: true, justifyContent: "flex-start", alignItems: "flex-start" }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 11 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, (_a = kubernetesObject.metadata) == null ? void 0 : _a.name)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 1 }, /* @__PURE__ */ React__default.createElement(
1441
+ IconButton,
1442
+ {
1443
+ key: "dismiss",
1444
+ title: "Close the drawer",
1445
+ onClick: () => close(),
1446
+ color: "inherit"
1447
+ },
1448
+ /* @__PURE__ */ React__default.createElement(CloseIcon, { className: classes.icon })
1449
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, header), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
1450
+ FormControlLabel,
1451
+ {
1452
+ control: /* @__PURE__ */ React__default.createElement(
1453
+ Switch,
1454
+ {
1455
+ checked: isYaml,
1456
+ onChange: (event) => {
1457
+ setIsYaml(event.target.checked);
1458
+ },
1459
+ name: "YAML"
1460
+ }
1461
+ ),
1462
+ label: "YAML"
1463
+ }
1464
+ )))), /* @__PURE__ */ React__default.createElement("div", { className: classes.content }, isYaml && /* @__PURE__ */ React__default.createElement(ManifestYaml, { object: kubernetesObject }), !isYaml && children));
1465
+ };
1466
+ const useDrawerStyles = makeStyles(
1467
+ (theme) => createStyles({
1468
+ paper: {
1469
+ width: "50%",
1470
+ justifyContent: "space-between",
1471
+ padding: theme.spacing(2.5)
1472
+ }
1473
+ })
1474
+ );
1475
+ const DrawerButton = withStyles$1({
1476
+ root: {
1477
+ padding: "6px 5px"
1478
+ },
1479
+ label: {
1480
+ textTransform: "none"
1481
+ }
1482
+ })(Button);
1483
+ const KubernetesDrawer = ({
1484
+ open,
1485
+ label,
1486
+ drawerContentsHeader,
1487
+ kubernetesObject,
1488
+ children
1489
+ }) => {
1490
+ const classes = useDrawerStyles();
1491
+ const [isOpen, setIsOpen] = useState(open != null ? open : false);
1492
+ const toggleDrawer = (e, newValue) => {
1493
+ e.stopPropagation();
1494
+ setIsOpen(newValue);
1495
+ };
1496
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(DrawerButton, { onClick: () => setIsOpen(true) }, label), /* @__PURE__ */ React__default.createElement(
1497
+ Drawer,
1498
+ {
1499
+ classes: {
1500
+ paper: classes.paper
1501
+ },
1502
+ anchor: "right",
1503
+ open: isOpen,
1504
+ onClose: (e) => toggleDrawer(e, false),
1505
+ onClick: (event) => event.stopPropagation()
1506
+ },
1507
+ isOpen && /* @__PURE__ */ React__default.createElement(
1508
+ KubernetesDrawerContent,
1509
+ {
1510
+ header: drawerContentsHeader,
1511
+ kubernetesObject,
1512
+ children,
1513
+ close: () => setIsOpen(false)
1514
+ }
1515
+ )
1516
+ ));
1517
+ };
1518
+
1519
+ const PodCondition = ({ condition }) => {
1520
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, condition.status === "False" && /* @__PURE__ */ React__default.createElement(StatusError, null, condition.type, " - (", condition.reason, " ", condition.lastTransitionTime && DateTime.fromISO(condition.lastTransitionTime).toRelative({
1521
+ locale: "en"
1522
+ }), ") - ", condition.message, " "), condition.status === "True" && /* @__PURE__ */ React__default.createElement(StatusOK, null, condition.type, " - (", condition.lastTransitionTime && DateTime.fromISO(condition.lastTransitionTime).toRelative({
1523
+ locale: "en"
1524
+ }), ")"), condition.status === "Unknown" && /* @__PURE__ */ React__default.createElement(StatusWarning, null, condition.type, " - (", condition.lastTransitionTime && DateTime.fromISO(condition.lastTransitionTime).toRelative({
1525
+ locale: "en"
1526
+ }), ") ", condition.message));
1527
+ };
1528
+ const PendingPodContent = ({ pod }) => {
1529
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1530
+ const startupConditions = [
1531
+ (_b = (_a = pod.status) == null ? void 0 : _a.conditions) == null ? void 0 : _b.find((c) => c.type === "PodScheduled"),
1532
+ (_d = (_c = pod.status) == null ? void 0 : _c.conditions) == null ? void 0 : _d.find((c) => c.type === "Initialized"),
1533
+ (_f = (_e = pod.status) == null ? void 0 : _e.conditions) == null ? void 0 : _f.find((c) => c.type === "ContainersReady"),
1534
+ (_h = (_g = pod.status) == null ? void 0 : _g.conditions) == null ? void 0 : _h.find((c) => c.type === "Ready")
1535
+ ].filter((c) => !!c);
1536
+ return /* @__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" }, "Pod is Pending. Conditions:"), /* @__PURE__ */ React__default.createElement(List, null, startupConditions.map((c) => /* @__PURE__ */ React__default.createElement(ListItem, { key: c.type }, /* @__PURE__ */ React__default.createElement(PodCondition, { condition: c }))))));
1537
+ };
1538
+
1539
+ const useEvents = ({
1540
+ involvedObjectName,
1541
+ namespace,
1542
+ clusterName
1543
+ }) => {
1544
+ const kubernetesProxyApi = useApi(kubernetesProxyApiRef);
1545
+ return useAsync(async () => {
1546
+ return await kubernetesProxyApi.getEventsByInvolvedObjectName({
1547
+ involvedObjectName,
1548
+ namespace,
1549
+ clusterName
1550
+ });
1551
+ }, [involvedObjectName, namespace, clusterName]);
1552
+ };
1553
+
1554
+ const getAvatarByType = (type) => {
1555
+ return /* @__PURE__ */ React__default.createElement(ListItemAvatar, null, /* @__PURE__ */ React__default.createElement(Avatar, null, type === "Warning" ? /* @__PURE__ */ React__default.createElement(WarningIcon, null) : /* @__PURE__ */ React__default.createElement(InfoIcon, null)));
1556
+ };
1557
+ const EventsContent = ({
1558
+ events,
1559
+ warningEventsOnly
1560
+ }) => {
1561
+ if (events.length === 0) {
1562
+ return /* @__PURE__ */ React__default.createElement(Typography, null, "No events found");
1563
+ }
1564
+ return /* @__PURE__ */ React__default.createElement(Container, null, /* @__PURE__ */ React__default.createElement(Grid, null, /* @__PURE__ */ React__default.createElement(List, null, events.filter((event) => {
1565
+ if (warningEventsOnly) {
1566
+ return event.type === "Warning";
1567
+ }
1568
+ return true;
1569
+ }).map((event) => {
1570
+ var _a;
1571
+ const timeAgo = event.metadata.creationTimestamp ? DateTime.fromISO(event.metadata.creationTimestamp).toRelative(
1572
+ {
1573
+ locale: "en"
1574
+ }
1575
+ ) : "unknown";
1576
+ return /* @__PURE__ */ React__default.createElement(ListItem, { key: event.metadata.name }, /* @__PURE__ */ React__default.createElement(Tooltip, { title: `${(_a = event.type) != null ? _a : ""} event` }, getAvatarByType(event.type)), /* @__PURE__ */ React__default.createElement(
1577
+ ListItemText,
1578
+ {
1579
+ primary: `First event ${timeAgo} (count: ${event.count})`,
1580
+ secondary: `${event.reason}: ${event.message}`
1581
+ }
1582
+ ));
1583
+ }))));
1584
+ };
1585
+ const Events = ({
1586
+ involvedObjectName,
1587
+ namespace,
1588
+ clusterName,
1589
+ warningEventsOnly
1590
+ }) => {
1591
+ const { value, error, loading } = useEvents({
1592
+ involvedObjectName,
1593
+ namespace,
1594
+ clusterName
1595
+ });
1596
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, error && /* @__PURE__ */ React__default.createElement(
1597
+ DismissableBanner,
1598
+ {
1599
+ ...{
1600
+ message: error.message,
1601
+ variant: "error",
1602
+ fixed: false
1603
+ },
1604
+ id: "events"
1605
+ }
1606
+ ), loading && /* @__PURE__ */ React__default.createElement(Skeleton, { variant: "rect", width: "100%", height: "100%" }), !loading && value !== void 0 && /* @__PURE__ */ React__default.createElement(EventsContent, { warningEventsOnly, events: value }));
1607
+ };
1608
+
1609
+ const useStyles$1 = makeStyles$1(
1610
+ (theme) => createStyles$1({
1611
+ closeButton: {
1612
+ position: "absolute",
1613
+ right: theme.spacing(1),
1614
+ top: theme.spacing(1),
1615
+ color: theme.palette.grey[500]
1616
+ }
1617
+ })
1618
+ );
1619
+ const FixDialog = ({
1620
+ open,
1621
+ pod,
1622
+ error,
1623
+ clusterName
1624
+ }) => {
1625
+ var _a;
1626
+ const [isOpen, setOpen] = useState(!!open);
1627
+ const classes = useStyles$1();
1628
+ const openDialog = () => {
1629
+ setOpen(true);
1630
+ };
1631
+ const closeDialog = () => {
1632
+ setOpen(false);
1633
+ };
1634
+ const pf = error.proposedFix;
1635
+ const dialogContent = () => {
1636
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1637
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Detected error:"), /* @__PURE__ */ React__default.createElement(Typography$1, null, error.message)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Cause explanation:"), /* @__PURE__ */ React__default.createElement(Typography$1, null, (_b = (_a2 = error.proposedFix) == null ? void 0 : _a2.rootCauseExplanation) != null ? _b : "unknown")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Fix:"), /* @__PURE__ */ React__default.createElement(Typography$1, null, /* @__PURE__ */ React__default.createElement("ul", null, ((_d = (_c = error.proposedFix) == null ? void 0 : _c.actions) != null ? _d : []).map((fix, i) => {
1638
+ var _a3, _b2;
1639
+ return /* @__PURE__ */ React__default.createElement("li", { key: `${(_b2 = (_a3 = pod.metadata) == null ? void 0 : _a3.name) != null ? _b2 : "unknown"}-pf-${i}` }, fix);
1640
+ })))), pf && pf.type === "logs" && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Crash logs:")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 9 }, /* @__PURE__ */ React__default.createElement(
1641
+ PodLogs,
1642
+ {
1643
+ previous: true,
1644
+ containerScope: {
1645
+ podName: (_f = (_e = pod.metadata) == null ? void 0 : _e.name) != null ? _f : "unknown",
1646
+ podNamespace: (_h = (_g = pod.metadata) == null ? void 0 : _g.namespace) != null ? _h : "unknown",
1647
+ clusterName,
1648
+ containerName: pf.container
1649
+ }
1650
+ }
1651
+ ))), pf && pf.type === "events" && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography$1, { variant: "h6" }, "Events:")), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 9 }, /* @__PURE__ */ React__default.createElement(
1652
+ Events,
1653
+ {
1654
+ warningEventsOnly: true,
1655
+ involvedObjectName: (_j = (_i = pod.metadata) == null ? void 0 : _i.name) != null ? _j : "",
1656
+ namespace: (_l = (_k = pod.metadata) == null ? void 0 : _k.namespace) != null ? _l : "",
1657
+ clusterName
1658
+ }
1659
+ ))));
1660
+ };
1661
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
1662
+ Button,
1663
+ {
1664
+ variant: "outlined",
1665
+ "aria-label": "fix issue",
1666
+ component: "label",
1667
+ onClick: openDialog,
1668
+ startIcon: /* @__PURE__ */ React__default.createElement(HelpIcon, null)
1669
+ },
1670
+ "Help"
1671
+ ), /* @__PURE__ */ React__default.createElement(Dialog$1, { maxWidth: "xl", fullWidth: true, open: isOpen, onClose: closeDialog }, /* @__PURE__ */ React__default.createElement(DialogTitle$1, { id: "dialog-title" }, (_a = pod.metadata) == null ? void 0 : _a.name, " - ", error.type, /* @__PURE__ */ React__default.createElement(
1672
+ IconButton$1,
1673
+ {
1674
+ "aria-label": "close",
1675
+ className: classes.closeButton,
1676
+ onClick: closeDialog
1677
+ },
1678
+ /* @__PURE__ */ React__default.createElement(CloseIcon, null)
1679
+ )), /* @__PURE__ */ React__default.createElement(DialogContent$1, null, dialogContent()), /* @__PURE__ */ React__default.createElement(DialogActions, null, pf && pf.type === "docs" && /* @__PURE__ */ React__default.createElement(
1680
+ LinkButton,
1681
+ {
1682
+ to: pf.docsLink,
1683
+ variant: "outlined",
1684
+ startIcon: /* @__PURE__ */ React__default.createElement(OpenInNewIcon, null),
1685
+ target: "_blank",
1686
+ rel: "noopener"
1687
+ },
1688
+ "Open docs"
1689
+ ))));
1690
+ };
1691
+
1692
+ const useStyles = makeStyles(
1693
+ (_theme) => createStyles({
1694
+ root: {
1695
+ overflow: "auto"
1696
+ },
1697
+ list: {
1698
+ width: "100%"
1699
+ }
1700
+ })
1701
+ );
1702
+ const ErrorList = ({ podAndErrors }) => {
1703
+ const classes = useStyles();
1704
+ return /* @__PURE__ */ React__default.createElement(Paper, { className: classes.root }, /* @__PURE__ */ React__default.createElement(List, { className: classes.list }, podAndErrors.filter((pae) => pae.errors.length > 0).flatMap((onlyPodWithErrors) => {
1705
+ return onlyPodWithErrors.errors.map((error, i) => {
1706
+ var _a, _b, _c;
1707
+ return /* @__PURE__ */ React__default.createElement(
1708
+ React__default.Fragment,
1709
+ {
1710
+ key: `${(_b = (_a = onlyPodWithErrors.pod.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown"}-eli-${i}`
1711
+ },
1712
+ i > 0 && /* @__PURE__ */ React__default.createElement(Divider, { key: `error-divider${i}` }),
1713
+ /* @__PURE__ */ React__default.createElement(ListItem, null, /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 9 }, /* @__PURE__ */ React__default.createElement(
1714
+ ListItemText,
1715
+ {
1716
+ primary: error.message,
1717
+ secondary: (_c = onlyPodWithErrors.pod.metadata) == null ? void 0 : _c.name
1718
+ }
1719
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 3 }, /* @__PURE__ */ React__default.createElement(
1720
+ FixDialog,
1721
+ {
1722
+ pod: onlyPodWithErrors.pod,
1723
+ error,
1724
+ clusterName: onlyPodWithErrors.clusterName
1725
+ }
1726
+ ))))
1727
+ );
1728
+ });
1729
+ })));
1730
+ };
1731
+
1732
+ const useDrawerContentStyles = makeStyles(
1733
+ (_theme) => createStyles({
1734
+ header: {
1735
+ display: "flex",
1736
+ flexDirection: "row",
1737
+ justifyContent: "space-between"
1738
+ },
1739
+ content: {
1740
+ height: "80%"
1741
+ },
1742
+ icon: {
1743
+ fontSize: 20
1744
+ },
1745
+ podoklist: {
1746
+ width: "100%",
1747
+ maxWidth: 360,
1748
+ maxHeight: 360
1749
+ }
1750
+ })
1751
+ );
1752
+ function getContainerSpecByName(pod, containerName) {
1753
+ var _a;
1754
+ return (_a = pod.spec) == null ? void 0 : _a.containers.find((c) => c.name === containerName);
1755
+ }
1756
+ const PodDrawer = ({ podAndErrors, open }) => {
1757
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1758
+ const classes = useDrawerContentStyles();
1759
+ const podMetrics = usePodMetrics(podAndErrors.clusterName, podAndErrors.pod);
1760
+ return /* @__PURE__ */ React__default.createElement(
1761
+ KubernetesDrawer,
1762
+ {
1763
+ open,
1764
+ drawerContentsHeader: /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle1" }, "Pod", " ", ((_a = podAndErrors.pod.status) == null ? void 0 : _a.podIP) && `(${(_b = podAndErrors.pod.status) == null ? void 0 : _b.podIP})`),
1765
+ kubernetesObject: podAndErrors.pod,
1766
+ label: /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle1" }, (_d = (_c = podAndErrors.pod.metadata) == null ? void 0 : _c.name) != null ? _d : "unknown")
1767
+ },
1768
+ /* @__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(
1769
+ ResourceUtilization,
1770
+ {
1771
+ title: "CPU requests",
1772
+ usage: podMetrics.cpu.currentUsage,
1773
+ total: podMetrics.cpu.requestTotal,
1774
+ totalFormatted: formatMillicores(podMetrics.cpu.requestTotal)
1775
+ }
1776
+ ), /* @__PURE__ */ React__default.createElement(
1777
+ ResourceUtilization,
1778
+ {
1779
+ title: "CPU limits",
1780
+ usage: podMetrics.cpu.currentUsage,
1781
+ total: podMetrics.cpu.limitTotal,
1782
+ totalFormatted: formatMillicores(podMetrics.cpu.limitTotal)
1783
+ }
1784
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 6 }, /* @__PURE__ */ React__default.createElement(
1785
+ ResourceUtilization,
1786
+ {
1787
+ title: "Memory requests",
1788
+ usage: podMetrics.memory.currentUsage,
1789
+ total: podMetrics.memory.requestTotal,
1790
+ totalFormatted: bytesToMiB(podMetrics.memory.requestTotal)
1791
+ }
1792
+ ), /* @__PURE__ */ React__default.createElement(
1793
+ ResourceUtilization,
1794
+ {
1795
+ title: "Memory limits",
1796
+ usage: podMetrics.memory.currentUsage,
1797
+ total: podMetrics.memory.limitTotal,
1798
+ totalFormatted: bytesToMiB(podMetrics.memory.requestTotal)
1799
+ }
1800
+ ))), ((_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(
1801
+ (containerStatus, i) => {
1802
+ var _a2, _b2, _c2, _d2, _e2, _f2;
1803
+ const containerSpec = getContainerSpecByName(
1804
+ podAndErrors.pod,
1805
+ containerStatus.name
1806
+ );
1807
+ const containerMetrics = ((_a2 = podMetrics == null ? void 0 : podMetrics.containers) != null ? _a2 : []).find((c) => c.container === containerStatus.name);
1808
+ return /* @__PURE__ */ React__default.createElement(
1809
+ ContainerCard,
1810
+ {
1811
+ key: `container-card-${(_b2 = podAndErrors.pod.metadata) == null ? void 0 : _b2.name}-${i}`,
1812
+ containerMetrics,
1813
+ podScope: {
1814
+ podName: (_d2 = (_c2 = podAndErrors.pod.metadata) == null ? void 0 : _c2.name) != null ? _d2 : "unknown",
1815
+ podNamespace: (_f2 = (_e2 = podAndErrors.pod.metadata) == null ? void 0 : _e2.namespace) != null ? _f2 : "unknown",
1816
+ clusterName: podAndErrors.clusterName
1817
+ },
1818
+ containerSpec,
1819
+ containerStatus
1820
+ }
1821
+ );
1822
+ }
1823
+ ))), podAndErrors.errors.length > 0 && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5" }, "Errors")), podAndErrors.errors.length > 0 && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(ErrorList, { podAndErrors: [podAndErrors] }))))
1824
+ );
1825
+ };
1826
+
1827
+ const containersReady = (pod) => {
1828
+ var _a, _b;
1829
+ const containerStatuses2 = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : [];
1830
+ const containersReadyItem = containerStatuses2.filter((cs) => cs.ready).length;
1831
+ return `${containersReadyItem}/${containerStatuses2.length}`;
1832
+ };
1833
+ const totalRestarts = (pod) => {
1834
+ var _a, _b;
1835
+ const containerStatuses2 = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : [];
1836
+ return containerStatuses2 == null ? void 0 : containerStatuses2.reduce((a, b) => a + b.restartCount, 0);
1837
+ };
1838
+ const containerStatuses = (pod) => {
1839
+ var _a, _b;
1840
+ const containerStatusesItem = (_b = (_a = pod.status) == null ? void 0 : _a.containerStatuses) != null ? _b : [];
1841
+ const errors = containerStatusesItem.reduce((accum, next) => {
1842
+ if (next.state === void 0) {
1843
+ return accum;
1844
+ }
1845
+ const waiting = next.state.waiting;
1846
+ const terminated = next.state.terminated;
1847
+ const renderCell = (reason) => {
1848
+ var _a2;
1849
+ return /* @__PURE__ */ React__default.createElement(Fragment, { key: `${(_a2 = pod.metadata) == null ? void 0 : _a2.name}-${next.name}` }, /* @__PURE__ */ React__default.createElement(
1850
+ SubvalueCell,
1851
+ {
1852
+ value: reason === "Completed" ? /* @__PURE__ */ React__default.createElement(StatusOK, null, "Container: ", next.name) : /* @__PURE__ */ React__default.createElement(StatusError, null, "Container: ", next.name),
1853
+ subvalue: reason
1854
+ }
1855
+ ), /* @__PURE__ */ React__default.createElement("br", null));
1856
+ };
1857
+ if (waiting) {
1858
+ accum.push(renderCell(waiting.reason));
1859
+ }
1860
+ if (terminated) {
1861
+ accum.push(renderCell(terminated.reason));
1862
+ }
1863
+ return accum;
1864
+ }, []);
1865
+ if (errors.length === 0) {
1866
+ return /* @__PURE__ */ React__default.createElement(StatusOK, null, "OK");
1867
+ }
1868
+ return errors;
1869
+ };
1870
+ const renderCondition = (condition) => {
1871
+ var _a;
1872
+ const status = condition.status;
1873
+ if (status === "True") {
1874
+ return [condition.type, /* @__PURE__ */ React__default.createElement(StatusOK, null, "True")];
1875
+ } else if (status === "False") {
1876
+ return [
1877
+ condition.type,
1878
+ /* @__PURE__ */ React__default.createElement(
1879
+ SubvalueCell,
1880
+ {
1881
+ value: /* @__PURE__ */ React__default.createElement(StatusError, null, "False"),
1882
+ subvalue: (_a = condition.message) != null ? _a : ""
1883
+ }
1884
+ )
1885
+ ];
1886
+ }
1887
+ return [condition.type, /* @__PURE__ */ React__default.createElement(StatusAborted, null)];
1888
+ };
1889
+ const currentToDeclaredResourceToPerc = (current, resource) => {
1890
+ if (Number(resource) === 0)
1891
+ return `0%`;
1892
+ if (typeof current === "number" && typeof resource === "number") {
1893
+ return `${Math.round(current / resource * 100)}%`;
1894
+ }
1895
+ const numerator = BigInt(current);
1896
+ const denominator = BigInt(resource);
1897
+ return `${numerator * BigInt(100) / denominator}%`;
1898
+ };
1899
+ const podStatusToCpuUtil = (podStatus) => {
1900
+ const cpuUtil = podStatus.cpu;
1901
+ let currentUsage = cpuUtil.currentUsage;
1902
+ if (typeof cpuUtil.currentUsage === "number") {
1903
+ currentUsage = cpuUtil.currentUsage / 10;
1904
+ }
1905
+ return /* @__PURE__ */ React__default.createElement(
1906
+ SubvalueCell,
1907
+ {
1908
+ value: `requests: ${currentToDeclaredResourceToPerc(
1909
+ currentUsage,
1910
+ cpuUtil.requestTotal
1911
+ )} of ${formatMillicores(cpuUtil.requestTotal)}`,
1912
+ subvalue: `limits: ${currentToDeclaredResourceToPerc(
1913
+ currentUsage,
1914
+ cpuUtil.limitTotal
1915
+ )} of ${formatMillicores(cpuUtil.limitTotal)}`
1916
+ }
1917
+ );
1918
+ };
1919
+ const podStatusToMemoryUtil = (podStatus) => {
1920
+ const memUtil = podStatus.memory;
1921
+ return /* @__PURE__ */ React__default.createElement(
1922
+ SubvalueCell,
1923
+ {
1924
+ value: `requests: ${currentToDeclaredResourceToPerc(
1925
+ memUtil.currentUsage,
1926
+ memUtil.requestTotal
1927
+ )} of ${bytesToMiB(memUtil.requestTotal)}`,
1928
+ subvalue: `limits: ${currentToDeclaredResourceToPerc(
1929
+ memUtil.currentUsage,
1930
+ memUtil.limitTotal
1931
+ )} of ${bytesToMiB(memUtil.limitTotal)}`
1932
+ }
1933
+ );
1934
+ };
1935
+
1936
+ const READY_COLUMNS = "READY";
1937
+ const RESOURCE_COLUMNS = "RESOURCE";
1938
+ const READY = [
1939
+ {
1940
+ title: "containers ready",
1941
+ align: "center",
1942
+ render: containersReady,
1943
+ width: "auto"
1944
+ },
1945
+ {
1946
+ title: "total restarts",
1947
+ align: "center",
1948
+ render: totalRestarts,
1949
+ type: "numeric",
1950
+ width: "auto"
1951
+ }
1952
+ ];
1953
+ const PodDrawerTrigger = ({ pod }) => {
1954
+ const cluster = useContext(ClusterContext);
1955
+ const errors = useMatchingErrors({
1956
+ kind: "Pod",
1957
+ apiVersion: "v1",
1958
+ metadata: pod.metadata
1959
+ });
1960
+ return /* @__PURE__ */ React__default.createElement(
1961
+ PodDrawer,
1962
+ {
1963
+ podAndErrors: {
1964
+ pod,
1965
+ clusterName: cluster.name,
1966
+ errors
1967
+ }
1968
+ }
1969
+ );
1970
+ };
1971
+ const Cpu = ({ clusterName, pod }) => {
1972
+ const metrics = usePodMetrics(clusterName, pod);
1973
+ if (!metrics) {
1974
+ return /* @__PURE__ */ React__default.createElement(Typography, null, "unknown");
1975
+ }
1976
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, podStatusToCpuUtil(metrics));
1977
+ };
1978
+ const Memory = ({ clusterName, pod }) => {
1979
+ const metrics = usePodMetrics(clusterName, pod);
1980
+ if (!metrics) {
1981
+ return /* @__PURE__ */ React__default.createElement(Typography, null, "unknown");
1982
+ }
1983
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, podStatusToMemoryUtil(metrics));
1984
+ };
1985
+ const PodsTable = ({ pods, extraColumns = [] }) => {
1986
+ const cluster = useContext(ClusterContext);
1987
+ const defaultColumns = [
1988
+ {
1989
+ title: "name",
1990
+ highlight: true,
1991
+ render: (pod) => {
1992
+ return /* @__PURE__ */ React__default.createElement(PodDrawerTrigger, { pod });
1993
+ }
1994
+ },
1995
+ {
1996
+ title: "phase",
1997
+ render: (pod) => {
1998
+ var _a, _b;
1999
+ return (_b = (_a = pod.status) == null ? void 0 : _a.phase) != null ? _b : "unknown";
2000
+ },
2001
+ width: "auto"
2002
+ },
2003
+ {
2004
+ title: "status",
2005
+ render: containerStatuses
2006
+ }
2007
+ ];
2008
+ const columns = [...defaultColumns];
2009
+ if (extraColumns.includes(READY_COLUMNS)) {
2010
+ columns.push(...READY);
2011
+ }
2012
+ if (extraColumns.includes(RESOURCE_COLUMNS)) {
2013
+ const resourceColumns = [
2014
+ {
2015
+ title: "CPU usage %",
2016
+ render: (pod) => {
2017
+ return /* @__PURE__ */ React__default.createElement(Cpu, { clusterName: cluster.name, pod });
2018
+ },
2019
+ width: "auto"
2020
+ },
2021
+ {
2022
+ title: "Memory usage %",
2023
+ render: (pod) => {
2024
+ return /* @__PURE__ */ React__default.createElement(Memory, { clusterName: cluster.name, pod });
2025
+ },
2026
+ width: "auto"
2027
+ }
2028
+ ];
2029
+ columns.push(...resourceColumns);
2030
+ }
2031
+ const tableStyle = {
2032
+ minWidth: "0",
2033
+ width: "100%"
2034
+ };
2035
+ return /* @__PURE__ */ React__default.createElement("div", { style: tableStyle }, /* @__PURE__ */ React__default.createElement(
2036
+ Table,
2037
+ {
2038
+ options: { paging: true, search: false, emptyRowsWhenPaging: false },
2039
+ data: pods,
2040
+ columns
2041
+ }
2042
+ ));
2043
+ };
2044
+
2045
+ const DeploymentDrawer = ({
2046
+ deployment,
2047
+ expanded
2048
+ }) => {
2049
+ var _a, _b, _c;
2050
+ const namespace = (_a = deployment.metadata) == null ? void 0 : _a.namespace;
2051
+ return /* @__PURE__ */ React__default.createElement(
2052
+ KubernetesStructuredMetadataTableDrawer,
2053
+ {
2054
+ object: deployment,
2055
+ expanded,
2056
+ kind: "Deployment",
2057
+ renderObject: (deploymentObj) => {
2058
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h;
2059
+ const conditions = ((_b2 = (_a2 = deploymentObj.status) == null ? void 0 : _a2.conditions) != null ? _b2 : []).map(renderCondition).reduce((accum, next) => {
2060
+ accum[next[0]] = next[1];
2061
+ return accum;
2062
+ }, {});
2063
+ return {
2064
+ strategy: (_d = (_c2 = deploymentObj.spec) == null ? void 0 : _c2.strategy) != null ? _d : "???",
2065
+ minReadySeconds: (_f = (_e = deploymentObj.spec) == null ? void 0 : _e.minReadySeconds) != null ? _f : "???",
2066
+ progressDeadlineSeconds: (_h = (_g = deploymentObj.spec) == null ? void 0 : _g.progressDeadlineSeconds) != null ? _h : "???",
2067
+ ...conditions
2068
+ };
2069
+ }
2070
+ },
2071
+ /* @__PURE__ */ React__default.createElement(
2072
+ Grid,
2073
+ {
2074
+ container: true,
2075
+ direction: "column",
2076
+ justifyContent: "flex-start",
2077
+ alignItems: "flex-start",
2078
+ spacing: 0
2079
+ },
2080
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_c = (_b = deployment.metadata) == null ? void 0 : _b.name) != null ? _c : "unknown object")),
2081
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Deployment")),
2082
+ namespace && /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Chip, { size: "small", label: `namespace: ${namespace}` }))
2083
+ )
2084
+ );
2085
+ };
2086
+
2087
+ const HorizontalPodAutoscalerDrawer = (props) => {
2088
+ const { hpa, expanded, children } = props;
2089
+ return /* @__PURE__ */ React__default.createElement(
2090
+ KubernetesStructuredMetadataTableDrawer,
2091
+ {
2092
+ kind: "HorizontalPodAutoscaler",
2093
+ object: hpa,
2094
+ expanded,
2095
+ renderObject: (hpaObject) => {
2096
+ var _a, _b, _c, _d, _e, _f;
2097
+ return {
2098
+ targetCPUUtilizationPercentage: (_a = hpaObject.spec) == null ? void 0 : _a.targetCPUUtilizationPercentage,
2099
+ currentCPUUtilizationPercentage: (_b = hpaObject.status) == null ? void 0 : _b.currentCPUUtilizationPercentage,
2100
+ minReplicas: (_c = hpaObject.spec) == null ? void 0 : _c.minReplicas,
2101
+ maxReplicas: (_d = hpaObject.spec) == null ? void 0 : _d.maxReplicas,
2102
+ currentReplicas: (_e = hpaObject.status) == null ? void 0 : _e.currentReplicas,
2103
+ desiredReplicas: (_f = hpaObject.status) == null ? void 0 : _f.desiredReplicas
2104
+ };
2105
+ }
2106
+ },
2107
+ children
2108
+ );
2109
+ };
2110
+
2111
+ function getOwnedResources(potentialOwner, possiblyOwned) {
2112
+ return possiblyOwned.filter(
2113
+ (p) => {
2114
+ var _a, _b, _c;
2115
+ return (_c = (_b = (_a = p.metadata) == null ? void 0 : _a.ownerReferences) == null ? void 0 : _b.some(
2116
+ (o) => {
2117
+ var _a2;
2118
+ return o.uid === ((_a2 = potentialOwner.metadata) == null ? void 0 : _a2.uid);
2119
+ }
2120
+ )) != null ? _c : false;
2121
+ }
2122
+ );
2123
+ }
2124
+ const getOwnedPodsThroughReplicaSets = (potentialOwner, replicaSets, pods) => {
2125
+ return getOwnedResources(
2126
+ potentialOwner,
2127
+ replicaSets.filter((rs) => rs.status && rs.status.replicas > 0)
2128
+ ).reduce((accum, rs) => {
2129
+ return accum.concat(getOwnedResources(rs, pods));
2130
+ }, []);
2131
+ };
2132
+ const getMatchingHpa = (owner, hpas) => {
2133
+ return hpas.find((hpa) => {
2134
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2135
+ return ((_c = (_b = (_a = hpa.spec) == null ? void 0 : _a.scaleTargetRef) == null ? void 0 : _b.kind) != null ? _c : "").toLocaleLowerCase("en-US") === owner.kind.toLocaleLowerCase("en-US") && ((_e = (_d = hpa.metadata) == null ? void 0 : _d.namespace) != null ? _e : "") === ((_f = owner.namespace) != null ? _f : "unknown-namespace") && ((_i = (_h = (_g = hpa.spec) == null ? void 0 : _g.scaleTargetRef) == null ? void 0 : _h.name) != null ? _i : "") === ((_j = owner.name) != null ? _j : "unknown-deployment");
2136
+ });
2137
+ };
2138
+
2139
+ const DeploymentSummary = ({
2140
+ deployment,
2141
+ numberOfCurrentPods,
2142
+ numberOfPodsWithErrors,
2143
+ hpa
2144
+ }) => {
2145
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2146
+ return /* @__PURE__ */ React__default.createElement(
2147
+ Grid,
2148
+ {
2149
+ container: true,
2150
+ direction: "row",
2151
+ justifyContent: "space-between",
2152
+ alignItems: "center",
2153
+ spacing: 0
2154
+ },
2155
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 4, item: true }, /* @__PURE__ */ React__default.createElement(DeploymentDrawer, { deployment })),
2156
+ hpa && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 4 }, /* @__PURE__ */ React__default.createElement(HorizontalPodAutoscalerDrawer, { hpa }, /* @__PURE__ */ React__default.createElement(
2157
+ Grid,
2158
+ {
2159
+ item: true,
2160
+ container: true,
2161
+ direction: "column",
2162
+ justifyContent: "flex-start",
2163
+ alignItems: "flex-start",
2164
+ spacing: 0
2165
+ },
2166
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "min replicas ", (_b = (_a = hpa.spec) == null ? void 0 : _a.minReplicas) != null ? _b : "?", " / max replicas", " ", (_d = (_c = hpa.spec) == null ? void 0 : _c.maxReplicas) != null ? _d : "?")),
2167
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "current CPU usage:", " ", (_f = (_e = hpa.status) == null ? void 0 : _e.currentCPUUtilizationPercentage) != null ? _f : "?", "%")),
2168
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "target CPU usage:", " ", (_h = (_g = hpa.spec) == null ? void 0 : _g.targetCPUUtilizationPercentage) != null ? _h : "?", "%"))
2169
+ ))),
2170
+ /* @__PURE__ */ React__default.createElement(
2171
+ Grid,
2172
+ {
2173
+ item: true,
2174
+ container: true,
2175
+ xs: 4,
2176
+ direction: "column",
2177
+ justifyContent: "flex-start",
2178
+ alignItems: "flex-end",
2179
+ spacing: 0
2180
+ },
2181
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(StatusOK, null, numberOfCurrentPods, " pods")),
2182
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pod", numberOfPodsWithErrors > 1 ? "s" : "", " with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))
2183
+ )
2184
+ );
2185
+ };
2186
+ const DeploymentAccordion = ({
2187
+ deployment,
2188
+ ownedPods,
2189
+ matchingHpa
2190
+ }) => {
2191
+ const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
2192
+ const podsWithErrors = ownedPods.filter(
2193
+ (p) => {
2194
+ var _a, _b;
2195
+ return podNamesWithErrors.has((_b = (_a = p.metadata) == null ? void 0 : _a.name) != null ? _b : "");
2196
+ }
2197
+ );
2198
+ return /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true }, variant: "outlined" }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(
2199
+ DeploymentSummary,
2200
+ {
2201
+ deployment,
2202
+ numberOfCurrentPods: ownedPods.length,
2203
+ numberOfPodsWithErrors: podsWithErrors.length,
2204
+ hpa: matchingHpa
2205
+ }
2206
+ )), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(
2207
+ PodsTable,
2208
+ {
2209
+ pods: ownedPods,
2210
+ extraColumns: [READY_COLUMNS, RESOURCE_COLUMNS]
2211
+ }
2212
+ )));
2213
+ };
2214
+ const DeploymentsAccordions = ({}) => {
2215
+ const groupedResponses = useContext(GroupedResponsesContext);
2216
+ return /* @__PURE__ */ React__default.createElement(
2217
+ Grid,
2218
+ {
2219
+ container: true,
2220
+ direction: "column",
2221
+ justifyContent: "flex-start",
2222
+ alignItems: "flex-start"
2223
+ },
2224
+ groupedResponses.deployments.map((deployment, i) => {
2225
+ var _a, _b;
2226
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(
2227
+ DeploymentAccordion,
2228
+ {
2229
+ matchingHpa: getMatchingHpa(
2230
+ {
2231
+ name: (_a = deployment.metadata) == null ? void 0 : _a.name,
2232
+ namespace: (_b = deployment.metadata) == null ? void 0 : _b.namespace,
2233
+ kind: "deployment"
2234
+ },
2235
+ groupedResponses.horizontalPodAutoscalers
2236
+ ),
2237
+ ownedPods: getOwnedPodsThroughReplicaSets(
2238
+ deployment,
2239
+ groupedResponses.replicaSets,
2240
+ groupedResponses.pods
2241
+ ),
2242
+ deployment
2243
+ }
2244
+ )));
2245
+ })
2246
+ );
2247
+ };
2248
+
2249
+ const StatefulSetDrawer = ({
2250
+ statefulset,
2251
+ expanded
2252
+ }) => {
2253
+ var _a, _b, _c;
2254
+ const namespace = (_a = statefulset.metadata) == null ? void 0 : _a.namespace;
2255
+ return /* @__PURE__ */ React__default.createElement(
2256
+ KubernetesStructuredMetadataTableDrawer,
2257
+ {
2258
+ object: statefulset,
2259
+ expanded,
2260
+ kind: "StatefulSet",
2261
+ renderObject: (statefulsetObj) => {
2262
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j, _k, _l;
2263
+ const conditions = ((_b2 = (_a2 = statefulsetObj.status) == null ? void 0 : _a2.conditions) != null ? _b2 : []).map(renderCondition).reduce((accum, next) => {
2264
+ accum[next[0]] = next[1];
2265
+ return accum;
2266
+ }, {});
2267
+ return {
2268
+ updateStrategy: (_d = (_c2 = statefulset.spec) == null ? void 0 : _c2.updateStrategy) != null ? _d : "???",
2269
+ podManagementPolicy: (_f = (_e = statefulset.spec) == null ? void 0 : _e.podManagementPolicy) != null ? _f : "???",
2270
+ serviceName: (_h = (_g = statefulset.spec) == null ? void 0 : _g.serviceName) != null ? _h : "???",
2271
+ selector: (_j = (_i = statefulset.spec) == null ? void 0 : _i.selector) != null ? _j : "???",
2272
+ revisionHistoryLimit: (_l = (_k = statefulset.spec) == null ? void 0 : _k.revisionHistoryLimit) != null ? _l : "???",
2273
+ ...conditions
2274
+ };
2275
+ }
2276
+ },
2277
+ /* @__PURE__ */ React__default.createElement(
2278
+ Grid,
2279
+ {
2280
+ container: true,
2281
+ direction: "column",
2282
+ justifyContent: "flex-start",
2283
+ alignItems: "flex-start",
2284
+ spacing: 0
2285
+ },
2286
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_c = (_b = statefulset.metadata) == null ? void 0 : _b.name) != null ? _c : "unknown object")),
2287
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Stateful Set")),
2288
+ namespace && /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Chip, { size: "small", label: `namespace: ${namespace}` }))
2289
+ )
2290
+ );
2291
+ };
2292
+
2293
+ const StatefulSetSummary = ({
2294
+ statefulset,
2295
+ numberOfCurrentPods,
2296
+ numberOfPodsWithErrors,
2297
+ hpa
2298
+ }) => {
2299
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2300
+ return /* @__PURE__ */ React__default.createElement(
2301
+ Grid,
2302
+ {
2303
+ container: true,
2304
+ direction: "row",
2305
+ justifyContent: "space-between",
2306
+ alignItems: "center",
2307
+ spacing: 0
2308
+ },
2309
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 6, item: true }, /* @__PURE__ */ React__default.createElement(StatefulSetDrawer, { statefulset })),
2310
+ hpa && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 3 }, /* @__PURE__ */ React__default.createElement(HorizontalPodAutoscalerDrawer, { hpa }, /* @__PURE__ */ React__default.createElement(
2311
+ Grid,
2312
+ {
2313
+ item: true,
2314
+ container: true,
2315
+ direction: "column",
2316
+ justifyContent: "flex-start",
2317
+ alignItems: "flex-start",
2318
+ spacing: 0
2319
+ },
2320
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "min replicas ", (_b = (_a = hpa.spec) == null ? void 0 : _a.minReplicas) != null ? _b : "?", " / max replicas", " ", (_d = (_c = hpa.spec) == null ? void 0 : _c.maxReplicas) != null ? _d : "?")),
2321
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "current CPU usage:", " ", (_f = (_e = hpa.status) == null ? void 0 : _e.currentCPUUtilizationPercentage) != null ? _f : "?", "%")),
2322
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "target CPU usage:", " ", (_h = (_g = hpa.spec) == null ? void 0 : _g.targetCPUUtilizationPercentage) != null ? _h : "?", "%"))
2323
+ ))),
2324
+ /* @__PURE__ */ React__default.createElement(
2325
+ Grid,
2326
+ {
2327
+ item: true,
2328
+ container: true,
2329
+ xs: 3,
2330
+ direction: "column",
2331
+ justifyContent: "flex-start",
2332
+ alignItems: "flex-start",
2333
+ spacing: 0
2334
+ },
2335
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(StatusOK, null, numberOfCurrentPods, " pods")),
2336
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pod", numberOfPodsWithErrors > 1 ? "s" : "", " with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))
2337
+ )
2338
+ );
2339
+ };
2340
+ const StatefulSetAccordion = ({
2341
+ statefulset,
2342
+ ownedPods,
2343
+ matchingHpa
2344
+ }) => {
2345
+ const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
2346
+ const podsWithErrors = ownedPods.filter(
2347
+ (p) => {
2348
+ var _a, _b;
2349
+ return podNamesWithErrors.has((_b = (_a = p.metadata) == null ? void 0 : _a.name) != null ? _b : "");
2350
+ }
2351
+ );
2352
+ return /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true }, variant: "outlined" }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(
2353
+ StatefulSetSummary,
2354
+ {
2355
+ statefulset,
2356
+ numberOfCurrentPods: ownedPods.length,
2357
+ numberOfPodsWithErrors: podsWithErrors.length,
2358
+ hpa: matchingHpa
2359
+ }
2360
+ )), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(
2361
+ PodsTable,
2362
+ {
2363
+ pods: ownedPods,
2364
+ extraColumns: [READY_COLUMNS, RESOURCE_COLUMNS]
2365
+ }
2366
+ )));
2367
+ };
2368
+ const StatefulSetsAccordions = ({}) => {
2369
+ const groupedResponses = useContext(GroupedResponsesContext);
2370
+ return /* @__PURE__ */ React__default.createElement(
2371
+ Grid,
2372
+ {
2373
+ container: true,
2374
+ direction: "column",
2375
+ justifyContent: "flex-start",
2376
+ alignItems: "flex-start"
2377
+ },
2378
+ groupedResponses.statefulsets.map((statefulset, i) => {
2379
+ var _a, _b;
2380
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(
2381
+ StatefulSetAccordion,
2382
+ {
2383
+ matchingHpa: getMatchingHpa(
2384
+ {
2385
+ name: (_a = statefulset.metadata) == null ? void 0 : _a.name,
2386
+ namespace: (_b = statefulset.metadata) == null ? void 0 : _b.namespace,
2387
+ kind: "statefulset"
2388
+ },
2389
+ groupedResponses.horizontalPodAutoscalers
2390
+ ),
2391
+ ownedPods: getOwnedResources(statefulset, groupedResponses.pods),
2392
+ statefulset
2393
+ }
2394
+ )));
2395
+ })
2396
+ );
2397
+ };
2398
+
2399
+ const IngressDrawer = ({
2400
+ ingress,
2401
+ expanded
2402
+ }) => {
2403
+ var _a, _b;
2404
+ return /* @__PURE__ */ React__default.createElement(
2405
+ KubernetesStructuredMetadataTableDrawer,
2406
+ {
2407
+ object: ingress,
2408
+ expanded,
2409
+ kind: "Ingress",
2410
+ renderObject: (ingressObject) => {
2411
+ return ingressObject.spec || {};
2412
+ }
2413
+ },
2414
+ /* @__PURE__ */ React__default.createElement(
2415
+ Grid,
2416
+ {
2417
+ container: true,
2418
+ direction: "column",
2419
+ justifyContent: "flex-start",
2420
+ alignItems: "flex-start",
2421
+ spacing: 0
2422
+ },
2423
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_b = (_a = ingress.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown object")),
2424
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Ingress"))
2425
+ )
2426
+ );
2427
+ };
2428
+
2429
+ const IngressSummary = ({ ingress }) => {
2430
+ return /* @__PURE__ */ React__default.createElement(
2431
+ Grid,
2432
+ {
2433
+ container: true,
2434
+ direction: "row",
2435
+ justifyContent: "flex-start",
2436
+ alignItems: "center"
2437
+ },
2438
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 12, item: true }, /* @__PURE__ */ React__default.createElement(IngressDrawer, { ingress }))
2439
+ );
2440
+ };
2441
+ const IngressCard = ({ ingress }) => {
2442
+ return /* @__PURE__ */ React__default.createElement(
2443
+ StructuredMetadataTable,
2444
+ {
2445
+ metadata: {
2446
+ ...ingress.spec
2447
+ }
2448
+ }
2449
+ );
2450
+ };
2451
+ const IngressAccordion = ({ ingress }) => {
2452
+ return /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true } }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(IngressSummary, { ingress })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(IngressCard, { ingress })));
2453
+ };
2454
+ const IngressesAccordions = ({}) => {
2455
+ const groupedResponses = useContext(GroupedResponsesContext);
2456
+ return /* @__PURE__ */ React__default.createElement(
2457
+ Grid,
2458
+ {
2459
+ container: true,
2460
+ direction: "row",
2461
+ justifyContent: "flex-start",
2462
+ alignItems: "flex-start"
2463
+ },
2464
+ groupedResponses.ingresses.map((ingress, i) => /* @__PURE__ */ React__default.createElement(Grid, { item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(IngressAccordion, { ingress })))
2465
+ );
2466
+ };
2467
+
2468
+ const ServiceDrawer = ({
2469
+ service,
2470
+ expanded
2471
+ }) => {
2472
+ var _a, _b;
2473
+ return /* @__PURE__ */ React__default.createElement(
2474
+ KubernetesStructuredMetadataTableDrawer,
2475
+ {
2476
+ object: service,
2477
+ expanded,
2478
+ kind: "Service",
2479
+ renderObject: (serviceObject) => {
2480
+ return serviceObject.spec || {};
2481
+ }
2482
+ },
2483
+ /* @__PURE__ */ React__default.createElement(
2484
+ Grid,
2485
+ {
2486
+ container: true,
2487
+ direction: "column",
2488
+ justifyContent: "flex-start",
2489
+ alignItems: "flex-start",
2490
+ spacing: 0
2491
+ },
2492
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_b = (_a = service.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown object")),
2493
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Service"))
2494
+ )
2495
+ );
2496
+ };
2497
+
2498
+ const ServiceSummary = ({ service }) => {
2499
+ var _a, _b;
2500
+ return /* @__PURE__ */ React__default.createElement(
2501
+ Grid,
2502
+ {
2503
+ container: true,
2504
+ direction: "row",
2505
+ justifyContent: "space-between",
2506
+ alignItems: "center",
2507
+ spacing: 0
2508
+ },
2509
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 8, item: true }, /* @__PURE__ */ React__default.createElement(ServiceDrawer, { service })),
2510
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "Type: ", (_b = (_a = service.spec) == null ? void 0 : _a.type) != null ? _b : "?"))
2511
+ );
2512
+ };
2513
+ const ServiceCard = ({ service }) => {
2514
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2515
+ const metadata = {};
2516
+ 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) {
2517
+ metadata.loadbalancer = (_e = service.status) == null ? void 0 : _e.loadBalancer;
2518
+ }
2519
+ if (((_f = service.spec) == null ? void 0 : _f.type) === "ClusterIP") {
2520
+ metadata.clusterIP = service.spec.clusterIP;
2521
+ }
2522
+ if (((_g = service.spec) == null ? void 0 : _g.type) === "ExternalName") {
2523
+ metadata.externalName = service.spec.externalName;
2524
+ }
2525
+ return /* @__PURE__ */ React__default.createElement(
2526
+ StructuredMetadataTable,
2527
+ {
2528
+ metadata: {
2529
+ type: (_h = service.spec) == null ? void 0 : _h.type,
2530
+ ports: (_i = service.spec) == null ? void 0 : _i.ports,
2531
+ ...metadata
2532
+ }
2533
+ }
2534
+ );
2535
+ };
2536
+ const ServiceAccordion = ({ service }) => {
2537
+ return /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true }, variant: "outlined" }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(ServiceSummary, { service })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(ServiceCard, { service })));
2538
+ };
2539
+ const ServicesAccordions = ({}) => {
2540
+ const groupedResponses = useContext(GroupedResponsesContext);
2541
+ return /* @__PURE__ */ React__default.createElement(
2542
+ Grid,
2543
+ {
2544
+ container: true,
2545
+ direction: "row",
2546
+ justifyContent: "flex-start",
2547
+ alignItems: "flex-start"
2548
+ },
2549
+ groupedResponses.services.map((service, i) => /* @__PURE__ */ React__default.createElement(Grid, { item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(ServiceAccordion, { service })))
2550
+ );
2551
+ };
2552
+
2553
+ const JobDrawer = ({
2554
+ job,
2555
+ expanded
2556
+ }) => {
2557
+ var _a, _b;
2558
+ return /* @__PURE__ */ React__default.createElement(
2559
+ KubernetesStructuredMetadataTableDrawer,
2560
+ {
2561
+ object: job,
2562
+ expanded,
2563
+ kind: "Job",
2564
+ renderObject: (jobObj) => {
2565
+ var _a2, _b2, _c, _d, _e, _f, _g, _h;
2566
+ return {
2567
+ parallelism: (_b2 = (_a2 = jobObj.spec) == null ? void 0 : _a2.parallelism) != null ? _b2 : "???",
2568
+ completions: (_d = (_c = jobObj.spec) == null ? void 0 : _c.completions) != null ? _d : "???",
2569
+ backoffLimit: (_f = (_e = jobObj.spec) == null ? void 0 : _e.backoffLimit) != null ? _f : "???",
2570
+ startTime: (_h = (_g = jobObj.status) == null ? void 0 : _g.startTime) != null ? _h : "???"
2571
+ };
2572
+ }
2573
+ },
2574
+ /* @__PURE__ */ React__default.createElement(
2575
+ Grid,
2576
+ {
2577
+ container: true,
2578
+ direction: "column",
2579
+ justifyContent: "flex-start",
2580
+ alignItems: "flex-start",
2581
+ spacing: 0
2582
+ },
2583
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_b = (_a = job.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown object")),
2584
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Job"))
2585
+ )
2586
+ );
2587
+ };
2588
+
2589
+ const JobSummary = ({ job }) => {
2590
+ var _a, _b, _c, _d, _e, _f;
2591
+ return /* @__PURE__ */ React__default.createElement(
2592
+ Grid,
2593
+ {
2594
+ container: true,
2595
+ direction: "row",
2596
+ justifyContent: "space-between",
2597
+ alignItems: "center",
2598
+ spacing: 0
2599
+ },
2600
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 6, item: true }, /* @__PURE__ */ React__default.createElement(JobDrawer, { job })),
2601
+ /* @__PURE__ */ React__default.createElement(
2602
+ Grid,
2603
+ {
2604
+ item: true,
2605
+ container: true,
2606
+ xs: 6,
2607
+ direction: "column",
2608
+ justifyContent: "flex-start",
2609
+ alignItems: "flex-end",
2610
+ spacing: 0
2611
+ },
2612
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, ((_a = job.status) == null ? void 0 : _a.succeeded) && /* @__PURE__ */ React__default.createElement(StatusOK, null, "Succeeded"), ((_b = job.status) == null ? void 0 : _b.active) && /* @__PURE__ */ React__default.createElement(StatusPending, null, "Running"), ((_c = job.status) == null ? void 0 : _c.failed) && /* @__PURE__ */ React__default.createElement(StatusError, null, "Failed")),
2613
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, "Start time: ", (_e = (_d = job.status) == null ? void 0 : _d.startTime) == null ? void 0 : _e.toString()),
2614
+ ((_f = job.status) == null ? void 0 : _f.completionTime) && /* @__PURE__ */ React__default.createElement(Grid, { item: true }, "Completion time: ", job.status.completionTime.toString())
2615
+ )
2616
+ );
2617
+ };
2618
+ const JobAccordion = ({ job, ownedPods }) => {
2619
+ return /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true }, variant: "outlined" }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(JobSummary, { job })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(PodsTable, { pods: ownedPods })));
2620
+ };
2621
+ const JobsAccordions = ({ jobs }) => {
2622
+ const groupedResponses = useContext(GroupedResponsesContext);
2623
+ return /* @__PURE__ */ React__default.createElement(
2624
+ Grid,
2625
+ {
2626
+ container: true,
2627
+ direction: "column",
2628
+ justifyContent: "flex-start",
2629
+ alignItems: "flex-start"
2630
+ },
2631
+ jobs.map((job, i) => /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(
2632
+ JobAccordion,
2633
+ {
2634
+ ownedPods: getOwnedResources(job, groupedResponses.pods),
2635
+ job
2636
+ }
2637
+ ))))
2638
+ );
2639
+ };
2640
+
2641
+ const CronJobDrawer = ({
2642
+ cronJob,
2643
+ expanded
2644
+ }) => {
2645
+ var _a, _b, _c;
2646
+ const namespace = (_a = cronJob.metadata) == null ? void 0 : _a.namespace;
2647
+ return /* @__PURE__ */ React__default.createElement(
2648
+ KubernetesStructuredMetadataTableDrawer,
2649
+ {
2650
+ object: cronJob,
2651
+ expanded,
2652
+ kind: "CronJob",
2653
+ renderObject: (cronJobObj) => {
2654
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h;
2655
+ return {
2656
+ schedule: (_b2 = (_a2 = cronJobObj.spec) == null ? void 0 : _a2.schedule) != null ? _b2 : "???",
2657
+ startingDeadlineSeconds: (_d = (_c2 = cronJobObj.spec) == null ? void 0 : _c2.startingDeadlineSeconds) != null ? _d : "???",
2658
+ concurrencyPolicy: (_f = (_e = cronJobObj.spec) == null ? void 0 : _e.concurrencyPolicy) != null ? _f : "???",
2659
+ lastScheduleTime: (_h = (_g = cronJobObj.status) == null ? void 0 : _g.lastScheduleTime) != null ? _h : "???"
2660
+ };
2661
+ }
2662
+ },
2663
+ /* @__PURE__ */ React__default.createElement(
2664
+ Grid,
2665
+ {
2666
+ container: true,
2667
+ direction: "column",
2668
+ justifyContent: "flex-start",
2669
+ alignItems: "flex-start",
2670
+ spacing: 0
2671
+ },
2672
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_c = (_b = cronJob.metadata) == null ? void 0 : _b.name) != null ? _c : "unknown object")),
2673
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "CronJob")),
2674
+ namespace && /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Chip, { size: "small", label: `namespace: ${namespace}` }))
2675
+ )
2676
+ );
2677
+ };
2678
+
2679
+ const k8sCronAliases = /* @__PURE__ */ new Map([
2680
+ ["@yearly", "0 0 1 1 *"],
2681
+ ["@annually", "0 0 1 1 *"],
2682
+ ["@monthly", "0 0 1 * *"],
2683
+ ["@weekly", "0 0 * * 0"],
2684
+ ["@daily", "0 0 * * *"],
2685
+ ["@midnight", "0 0 * * *"],
2686
+ ["@hourly", "0 * * * *"]
2687
+ ]);
2688
+ const humanizeCron = (schedule) => {
2689
+ const deAliasedSchedule = k8sCronAliases.get(schedule) || schedule;
2690
+ try {
2691
+ return cronstrue.toString(deAliasedSchedule);
2692
+ } catch (e) {
2693
+ return deAliasedSchedule;
2694
+ }
2695
+ };
2696
+
2697
+ const CronJobSummary = ({ cronJob }) => {
2698
+ var _a, _b;
2699
+ return /* @__PURE__ */ React__default.createElement(
2700
+ Grid,
2701
+ {
2702
+ container: true,
2703
+ direction: "row",
2704
+ justifyContent: "space-between",
2705
+ alignItems: "center",
2706
+ spacing: 0
2707
+ },
2708
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 6, item: true }, /* @__PURE__ */ React__default.createElement(CronJobDrawer, { cronJob })),
2709
+ /* @__PURE__ */ React__default.createElement(
2710
+ Grid,
2711
+ {
2712
+ item: true,
2713
+ container: true,
2714
+ xs: 6,
2715
+ direction: "column",
2716
+ justifyContent: "flex-start",
2717
+ alignItems: "flex-end",
2718
+ spacing: 0
2719
+ },
2720
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, ((_a = cronJob.spec) == null ? void 0 : _a.suspend) ? /* @__PURE__ */ React__default.createElement(StatusError, null, "Suspended") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "Active")),
2721
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, "Schedule:", " ", ((_b = cronJob.spec) == null ? void 0 : _b.schedule) ? `${cronJob.spec.schedule} (${humanizeCron(
2722
+ cronJob.spec.schedule
2723
+ )})` : "N/A"))
2724
+ )
2725
+ );
2726
+ };
2727
+ const CronJobAccordion = ({ cronJob, ownedJobs }) => {
2728
+ return /* @__PURE__ */ React__default.createElement(Accordion, { TransitionProps: { unmountOnExit: true }, variant: "outlined" }, /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(CronJobSummary, { cronJob })), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(JobsAccordions, { jobs: ownedJobs.reverse() })));
2729
+ };
2730
+ const CronJobsAccordions = ({}) => {
2731
+ const groupedResponses = useContext(GroupedResponsesContext);
2732
+ return /* @__PURE__ */ React__default.createElement(
2733
+ Grid,
2734
+ {
2735
+ container: true,
2736
+ direction: "column",
2737
+ justifyContent: "flex-start",
2738
+ alignItems: "flex-start"
2739
+ },
2740
+ groupedResponses.cronJobs.map((cronJob, i) => /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(
2741
+ CronJobAccordion,
2742
+ {
2743
+ ownedJobs: getOwnedResources(cronJob, groupedResponses.jobs),
2744
+ cronJob
2745
+ }
2746
+ ))))
2747
+ );
2748
+ };
2749
+
2750
+ const RolloutDrawer = ({
2751
+ rollout,
2752
+ expanded
2753
+ }) => {
2754
+ var _a, _b;
2755
+ return /* @__PURE__ */ React__default.createElement(
2756
+ KubernetesStructuredMetadataTableDrawer,
2757
+ {
2758
+ object: rollout,
2759
+ expanded,
2760
+ kind: "Rollout",
2761
+ renderObject: () => ({})
2762
+ },
2763
+ /* @__PURE__ */ React__default.createElement(
2764
+ Grid,
2765
+ {
2766
+ container: true,
2767
+ direction: "column",
2768
+ justifyContent: "flex-start",
2769
+ alignItems: "flex-start",
2770
+ spacing: 0
2771
+ },
2772
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_b = (_a = rollout.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown object")),
2773
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Rollout"))
2774
+ )
2775
+ );
2776
+ };
2777
+
2778
+ const isSetWeightStep = (step) => step.hasOwnProperty("setWeight");
2779
+ const isPauseStep = (step) => step.hasOwnProperty("pause");
2780
+ const isAnalysisStep = (step) => step.hasOwnProperty("analysis");
2781
+ const createLabelForStep = (step) => {
2782
+ if (isSetWeightStep(step)) {
2783
+ return `setWeight ${step.setWeight}%`;
2784
+ } else if (isPauseStep(step)) {
2785
+ return step.pause.duration === void 0 ? "infinite pause" : `pause for ${step.pause.duration}`;
2786
+ } else if (isAnalysisStep(step)) {
2787
+ return /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(Typography$1, { paragraph: true }, "analysis templates:"), step.analysis.templates.map((t, i) => /* @__PURE__ */ React__default.createElement(Typography$1, { paragraph: true, key: i }, `${t.templateName}${t.clusterScope ? " (cluster scoped)" : ""}`)));
2788
+ }
2789
+ return "unknown step";
2790
+ };
2791
+ const StepsProgress = ({
2792
+ currentStepIndex,
2793
+ aborted,
2794
+ steps
2795
+ }) => {
2796
+ const activeStepIndex = currentStepIndex >= steps.length ? currentStepIndex + 1 : currentStepIndex;
2797
+ return /* @__PURE__ */ React__default.createElement(Stepper, { activeStep: aborted ? -1 : activeStepIndex, alternativeLabel: true }, steps.map((step, i) => /* @__PURE__ */ React__default.createElement(Step, { key: i }, /* @__PURE__ */ React__default.createElement(StepLabel, { "data-testid": `step-${i}` }, createLabelForStep(step)))).concat(
2798
+ /* @__PURE__ */ React__default.createElement(Step, { key: "-1" }, /* @__PURE__ */ React__default.createElement(StepLabel, { "data-testid": "step--1" }, "Canary promoted"))
2799
+ ));
2800
+ };
2801
+
2802
+ const AbortedTitle = /* @__PURE__ */ React__default.createElement(
2803
+ "div",
2804
+ {
2805
+ style: {
2806
+ display: "flex",
2807
+ alignItems: "center",
2808
+ flexWrap: "wrap"
2809
+ }
2810
+ },
2811
+ /* @__PURE__ */ React__default.createElement(ErrorOutlineIcon, null),
2812
+ /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle1" }, "Aborted")
2813
+ );
2814
+ const findAbortedMessage = (rollout) => {
2815
+ var _a, _b, _c;
2816
+ return (_c = (_b = (_a = rollout.status) == null ? void 0 : _a.conditions) == null ? void 0 : _b.find(
2817
+ (c) => c.type === "Progressing" && c.status === "False" && c.reason === "RolloutAborted"
2818
+ )) == null ? void 0 : _c.message;
2819
+ };
2820
+ const RolloutSummary = ({
2821
+ rollout,
2822
+ numberOfCurrentPods,
2823
+ numberOfPodsWithErrors,
2824
+ hpa
2825
+ }) => {
2826
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2827
+ const pauseTime = (_c = (_b = (_a = rollout.status) == null ? void 0 : _a.pauseConditions) == null ? void 0 : _b.find(
2828
+ (p) => p.reason === "CanaryPauseStep"
2829
+ )) == null ? void 0 : _c.startTime;
2830
+ const abortedMessage = findAbortedMessage(rollout);
2831
+ return /* @__PURE__ */ React__default.createElement(
2832
+ Grid,
2833
+ {
2834
+ container: true,
2835
+ direction: "row",
2836
+ justifyContent: "space-between",
2837
+ alignItems: "center",
2838
+ spacing: 0
2839
+ },
2840
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 6, item: true }, /* @__PURE__ */ React__default.createElement(RolloutDrawer, { rollout })),
2841
+ hpa && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 3 }, /* @__PURE__ */ React__default.createElement(HorizontalPodAutoscalerDrawer, { hpa }, /* @__PURE__ */ React__default.createElement(
2842
+ Grid,
2843
+ {
2844
+ item: true,
2845
+ container: true,
2846
+ direction: "column",
2847
+ justifyContent: "flex-start",
2848
+ alignItems: "flex-start",
2849
+ spacing: 0
2850
+ },
2851
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "min replicas ", (_e = (_d = hpa.spec) == null ? void 0 : _d.minReplicas) != null ? _e : "?", " / max replicas", " ", (_g = (_f = hpa.spec) == null ? void 0 : _f.maxReplicas) != null ? _g : "?")),
2852
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "current CPU usage:", " ", (_i = (_h = hpa.status) == null ? void 0 : _h.currentCPUUtilizationPercentage) != null ? _i : "?", "%")),
2853
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, "target CPU usage:", " ", (_k = (_j = hpa.spec) == null ? void 0 : _j.targetCPUUtilizationPercentage) != null ? _k : "?", "%"))
2854
+ ))),
2855
+ /* @__PURE__ */ React__default.createElement(
2856
+ Grid,
2857
+ {
2858
+ item: true,
2859
+ container: true,
2860
+ xs: 3,
2861
+ direction: "column",
2862
+ justifyContent: "flex-start",
2863
+ alignItems: "flex-end",
2864
+ spacing: 0
2865
+ },
2866
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(StatusOK, null, numberOfCurrentPods, " pods")),
2867
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pod", numberOfPodsWithErrors > 1 ? "s" : "", " with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))
2868
+ ),
2869
+ pauseTime && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 3 }, /* @__PURE__ */ React__default.createElement(
2870
+ "div",
2871
+ {
2872
+ style: {
2873
+ display: "flex",
2874
+ alignItems: "center",
2875
+ flexWrap: "wrap"
2876
+ }
2877
+ },
2878
+ /* @__PURE__ */ React__default.createElement(PauseIcon, null),
2879
+ /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle1" }, "Paused (", DateTime.fromISO(pauseTime).toRelative({ locale: "en" }), ")")
2880
+ )),
2881
+ abortedMessage && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 3 }, AbortedTitle)
2882
+ );
2883
+ };
2884
+ const RolloutAccordion = ({
2885
+ rollout,
2886
+ ownedPods,
2887
+ matchingHpa,
2888
+ defaultExpanded
2889
+ }) => {
2890
+ var _a, _b, _c, _d, _e, _f;
2891
+ const podNamesWithErrors = useContext(PodNamesWithErrorsContext);
2892
+ const podsWithErrors = ownedPods.filter(
2893
+ (p) => {
2894
+ var _a2, _b2;
2895
+ return podNamesWithErrors.has((_b2 = (_a2 = p.metadata) == null ? void 0 : _a2.name) != null ? _b2 : "");
2896
+ }
2897
+ );
2898
+ const currentStepIndex = (_b = (_a = rollout.status) == null ? void 0 : _a.currentStepIndex) != null ? _b : 0;
2899
+ const abortedMessage = findAbortedMessage(rollout);
2900
+ return /* @__PURE__ */ React__default.createElement(
2901
+ Accordion,
2902
+ {
2903
+ defaultExpanded,
2904
+ TransitionProps: { unmountOnExit: true },
2905
+ variant: "outlined"
2906
+ },
2907
+ /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(
2908
+ RolloutSummary,
2909
+ {
2910
+ rollout,
2911
+ numberOfCurrentPods: ownedPods.length,
2912
+ numberOfPodsWithErrors: podsWithErrors.length,
2913
+ hpa: matchingHpa
2914
+ }
2915
+ )),
2916
+ /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement("div", { style: { width: "100%" } }, /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h6" }, "Rollout status")), /* @__PURE__ */ React__default.createElement("div", { style: { margin: "1rem" } }, abortedMessage && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, AbortedTitle, /* @__PURE__ */ React__default.createElement(Typography, { variant: "subtitle2" }, abortedMessage)), /* @__PURE__ */ React__default.createElement(
2917
+ StepsProgress,
2918
+ {
2919
+ aborted: abortedMessage !== void 0,
2920
+ steps: (_f = (_e = (_d = (_c = rollout.spec) == null ? void 0 : _c.strategy) == null ? void 0 : _d.canary) == null ? void 0 : _e.steps) != null ? _f : [],
2921
+ currentStepIndex
2922
+ }
2923
+ )), /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(
2924
+ PodsTable,
2925
+ {
2926
+ pods: ownedPods,
2927
+ extraColumns: [READY_COLUMNS, RESOURCE_COLUMNS]
2928
+ }
2929
+ ))))
2930
+ );
2931
+ };
2932
+ const RolloutAccordions = ({
2933
+ rollouts,
2934
+ defaultExpanded = false
2935
+ }) => {
2936
+ const groupedResponses = useContext(GroupedResponsesContext);
2937
+ return /* @__PURE__ */ React__default.createElement(
2938
+ Grid,
2939
+ {
2940
+ container: true,
2941
+ direction: "column",
2942
+ justifyContent: "flex-start",
2943
+ alignItems: "flex-start"
2944
+ },
2945
+ rollouts.map((rollout, i) => {
2946
+ var _a, _b;
2947
+ return /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(
2948
+ RolloutAccordion,
2949
+ {
2950
+ defaultExpanded,
2951
+ matchingHpa: getMatchingHpa(
2952
+ {
2953
+ name: (_a = rollout.metadata) == null ? void 0 : _a.name,
2954
+ namespace: (_b = rollout.metadata) == null ? void 0 : _b.namespace,
2955
+ kind: "rollout"
2956
+ },
2957
+ groupedResponses.horizontalPodAutoscalers
2958
+ ),
2959
+ ownedPods: getOwnedPodsThroughReplicaSets(
2960
+ rollout,
2961
+ groupedResponses.replicaSets,
2962
+ groupedResponses.pods
2963
+ ),
2964
+ rollout
2965
+ }
2966
+ )));
2967
+ })
2968
+ );
2969
+ };
2970
+
2971
+ const capitalize = (str) => str.charAt(0).toLocaleUpperCase("en-US") + str.slice(1);
2972
+ const DefaultCustomResourceDrawer = ({
2973
+ customResource,
2974
+ customResourceName,
2975
+ expanded
2976
+ }) => {
2977
+ var _a, _b;
2978
+ const capitalizedName = capitalize(customResourceName);
2979
+ return /* @__PURE__ */ React__default.createElement(
2980
+ KubernetesStructuredMetadataTableDrawer,
2981
+ {
2982
+ object: customResource,
2983
+ expanded,
2984
+ kind: capitalizedName,
2985
+ renderObject: (cr) => cr
2986
+ },
2987
+ /* @__PURE__ */ React__default.createElement(
2988
+ Grid,
2989
+ {
2990
+ container: true,
2991
+ direction: "column",
2992
+ justifyContent: "flex-start",
2993
+ alignItems: "flex-start",
2994
+ spacing: 0
2995
+ },
2996
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, (_b = (_a = customResource.metadata) == null ? void 0 : _a.name) != null ? _b : "unknown object")),
2997
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, capitalizedName))
2998
+ )
2999
+ );
3000
+ };
3001
+
3002
+ const DefaultCustomResourceSummary = ({
3003
+ customResource,
3004
+ customResourceName
3005
+ }) => {
3006
+ return /* @__PURE__ */ React__default.createElement(
3007
+ Grid,
3008
+ {
3009
+ container: true,
3010
+ direction: "row",
3011
+ justifyContent: "space-between",
3012
+ alignItems: "center",
3013
+ spacing: 0
3014
+ },
3015
+ /* @__PURE__ */ React__default.createElement(Grid, { xs: 12, item: true }, /* @__PURE__ */ React__default.createElement(
3016
+ DefaultCustomResourceDrawer,
3017
+ {
3018
+ customResource,
3019
+ customResourceName
3020
+ }
3021
+ ))
3022
+ );
3023
+ };
3024
+ const DefaultCustomResourceAccordion = ({
3025
+ customResource,
3026
+ customResourceName,
3027
+ defaultExpanded
3028
+ }) => {
3029
+ return /* @__PURE__ */ React__default.createElement(
3030
+ Accordion,
3031
+ {
3032
+ defaultExpanded,
3033
+ TransitionProps: { unmountOnExit: true },
3034
+ variant: "outlined"
3035
+ },
3036
+ /* @__PURE__ */ React__default.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React__default.createElement(
3037
+ DefaultCustomResourceSummary,
3038
+ {
3039
+ customResource,
3040
+ customResourceName
3041
+ }
3042
+ )),
3043
+ /* @__PURE__ */ React__default.createElement(AccordionDetails, null, customResource.hasOwnProperty("status") && /* @__PURE__ */ React__default.createElement(StructuredMetadataTable, { metadata: customResource.status }))
3044
+ );
3045
+ };
3046
+ const DefaultCustomResourceAccordions = ({
3047
+ customResources,
3048
+ customResourceName,
3049
+ defaultExpanded = false
3050
+ }) => {
3051
+ return /* @__PURE__ */ React__default.createElement(
3052
+ Grid,
3053
+ {
3054
+ container: true,
3055
+ direction: "column",
3056
+ justifyContent: "flex-start",
3057
+ alignItems: "flex-start"
3058
+ },
3059
+ customResources.map((cr, i) => /* @__PURE__ */ React__default.createElement(Grid, { container: true, item: true, key: i, xs: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(
3060
+ DefaultCustomResourceAccordion,
3061
+ {
3062
+ defaultExpanded,
3063
+ customResource: cr,
3064
+ customResourceName
3065
+ }
3066
+ ))))
3067
+ );
3068
+ };
3069
+
3070
+ const kindToResource = (customResources) => {
3071
+ return lodash.groupBy(customResources, (value) => {
3072
+ return value.kind;
3073
+ });
3074
+ };
3075
+ const CustomResources = ({}) => {
3076
+ const groupedResponses = useContext(GroupedResponsesContext);
3077
+ const kindToResourceMap = kindToResource(groupedResponses.customResources);
3078
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, Object.entries(kindToResourceMap).map(([kind, resources], i) => {
3079
+ switch (kind) {
3080
+ case "Rollout":
3081
+ return /* @__PURE__ */ React__default.createElement(RolloutAccordions, { key: i, rollouts: resources });
3082
+ default:
3083
+ return /* @__PURE__ */ React__default.createElement(
3084
+ DefaultCustomResourceAccordions,
3085
+ {
3086
+ key: i,
3087
+ customResources: resources,
3088
+ customResourceName: kind
3089
+ }
3090
+ );
3091
+ }
3092
+ }));
3093
+ };
3094
+
3095
+ const ClusterSummary = ({
3096
+ clusterName,
3097
+ totalNumberOfPods,
3098
+ numberOfPodsWithErrors
3099
+ }) => {
3100
+ return /* @__PURE__ */ React__default.createElement(
3101
+ Grid,
3102
+ {
3103
+ container: true,
3104
+ direction: "row",
3105
+ justifyContent: "space-between",
3106
+ alignItems: "flex-start",
3107
+ spacing: 0
3108
+ },
3109
+ /* @__PURE__ */ React__default.createElement(
3110
+ Grid,
3111
+ {
3112
+ xs: 6,
3113
+ item: true,
3114
+ container: true,
3115
+ direction: "column",
3116
+ justifyContent: "flex-start",
3117
+ alignItems: "flex-start",
3118
+ spacing: 0
3119
+ },
3120
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: true }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body1" }, clusterName), /* @__PURE__ */ React__default.createElement(Typography, { color: "textSecondary", variant: "subtitle1" }, "Cluster"))
3121
+ ),
3122
+ /* @__PURE__ */ React__default.createElement(
3123
+ Grid,
3124
+ {
3125
+ item: true,
3126
+ container: true,
3127
+ xs: 3,
3128
+ direction: "column",
3129
+ justifyContent: "flex-start",
3130
+ alignItems: "flex-end",
3131
+ spacing: 0
3132
+ },
3133
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(StatusOK, null, totalNumberOfPods, " pods")),
3134
+ /* @__PURE__ */ React__default.createElement(Grid, { item: true }, numberOfPodsWithErrors > 0 ? /* @__PURE__ */ React__default.createElement(StatusError, null, numberOfPodsWithErrors, " pods with errors") : /* @__PURE__ */ React__default.createElement(StatusOK, null, "No pods with errors"))
3135
+ )
3136
+ );
3137
+ };
3138
+ const Cluster = ({ clusterObjects, podsWithErrors }) => {
3139
+ const groupedResponses = groupResponses(clusterObjects.resources);
3140
+ const podMetricsMap = /* @__PURE__ */ new Map();
3141
+ podMetricsMap.set(clusterObjects.cluster.name, clusterObjects.podMetrics);
3142
+ 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(
3143
+ ClusterSummary,
3144
+ {
3145
+ clusterName: clusterObjects.cluster.name,
3146
+ totalNumberOfPods: groupedResponses.pods.length,
3147
+ numberOfPodsWithErrors: podsWithErrors.size
3148
+ }
3149
+ )), /* @__PURE__ */ React__default.createElement(AccordionDetails, null, /* @__PURE__ */ React__default.createElement(Grid, { container: true, direction: "column" }, groupedResponses.customResources.length > 0 ? /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(CustomResources, null)) : void 0, groupedResponses.deployments.length > 0 ? /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(DeploymentsAccordions, null)) : void 0, groupedResponses.statefulsets.length > 0 ? /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(StatefulSetsAccordions, null)) : void 0, groupedResponses.ingresses.length > 0 ? /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(IngressesAccordions, null)) : void 0, groupedResponses.services.length > 0 ? /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(ServicesAccordions, null)) : void 0, groupedResponses.cronJobs.length > 0 ? /* @__PURE__ */ React__default.createElement(Grid, { item: true }, /* @__PURE__ */ React__default.createElement(CronJobsAccordions, null)) : void 0)))))));
3150
+ };
3151
+
3152
+ const clustersWithErrorsToErrorMessage = (clustersWithErrors) => {
3153
+ return clustersWithErrors.map((c, i) => {
3154
+ return /* @__PURE__ */ React__default.createElement("div", { key: i }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2" }, `Cluster: ${c.cluster.name}`), c.errors.map((e, j) => {
3155
+ return /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2", key: j }, e.errorType === "FETCH_ERROR" ? `Error communicating with Kubernetes: ${e.errorType}, message: ${e.message}` : `Error fetching Kubernetes resource: '${e.resourcePath}', error: ${e.errorType}, status code: ${e.statusCode}`);
3156
+ }), /* @__PURE__ */ React__default.createElement("br", null));
3157
+ });
3158
+ };
3159
+ const ErrorPanel = ({
3160
+ entityName,
3161
+ errorMessage,
3162
+ clustersWithErrors
3163
+ }) => /* @__PURE__ */ React__default.createElement(
3164
+ WarningPanel,
3165
+ {
3166
+ title: "There was a problem retrieving Kubernetes objects",
3167
+ message: `There was a problem retrieving some Kubernetes resources for the entity: ${entityName}. This could mean that the Error Reporting card is not completely accurate.`
3168
+ },
3169
+ clustersWithErrors && /* @__PURE__ */ React__default.createElement("div", null, "Errors: ", clustersWithErrorsToErrorMessage(clustersWithErrors)),
3170
+ errorMessage && /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2" }, "Errors: ", errorMessage)
3171
+ );
3172
+
3173
+ const columns = [
3174
+ {
3175
+ title: "cluster",
3176
+ width: "10%",
3177
+ render: (row) => row.clusterName
3178
+ },
3179
+ {
3180
+ title: "namespace",
3181
+ width: "10%",
3182
+ render: (row) => row.error.sourceRef.namespace
3183
+ },
3184
+ {
3185
+ title: "kind",
3186
+ width: "10%",
3187
+ render: (row) => row.error.sourceRef.kind
3188
+ },
3189
+ {
3190
+ title: "name",
3191
+ width: "30%",
3192
+ render: (row) => {
3193
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, row.error.sourceRef.name, " ");
3194
+ }
3195
+ },
3196
+ {
3197
+ title: "messages",
3198
+ width: "40%",
3199
+ render: (row) => row.error.message
3200
+ }
3201
+ ];
3202
+ const sortBySeverity = (a, b) => {
3203
+ if (a.error.severity < b.error.severity) {
3204
+ return 1;
3205
+ } else if (b.error.severity < a.error.severity) {
3206
+ return -1;
3207
+ }
3208
+ return 0;
3209
+ };
3210
+ const ErrorReporting = ({ detectedErrors }) => {
3211
+ const errors = Array.from(detectedErrors.entries()).flatMap(([clusterName, resourceErrors]) => {
3212
+ return resourceErrors.map((e) => ({
3213
+ clusterName,
3214
+ error: e
3215
+ }));
3216
+ }).sort(sortBySeverity);
3217
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, errors.length !== 0 && /* @__PURE__ */ React.createElement(
3218
+ Table,
3219
+ {
3220
+ title: "Error Reporting",
3221
+ data: errors,
3222
+ columns,
3223
+ options: { paging: true, search: false, emptyRowsWhenPaging: false }
3224
+ }
3225
+ ));
3226
+ };
3227
+
3228
+ export { AksKubernetesAuthProvider, Cluster, ClusterContext, ContainerCard, CronJobsAccordions, CustomResources, DetectedErrorsContext, ErrorList, ErrorPanel, ErrorReporting, Events, EventsContent, FixDialog, GoogleKubernetesAuthProvider, GroupedResponsesContext, HorizontalPodAutoscalerDrawer, IngressesAccordions, JobsAccordions, KubernetesAuthProviders, KubernetesBackendClient, KubernetesDrawer, KubernetesProxyClient, KubernetesStructuredMetadataTableDrawer, LinkErrorPanel, ManifestYaml, OidcKubernetesAuthProvider, PendingPodContent, PodDrawer, PodExecTerminal, PodExecTerminalDialog, PodLogs, PodLogsDialog, PodMetricsContext, PodNamesWithErrorsContext, PodNamesWithMetricsContext, PodsTable, READY_COLUMNS, RESOURCE_COLUMNS, ResourceUtilization, ServerSideKubernetesAuthProvider, ServicesAccordions, kubernetesApiRef, kubernetesAuthProvidersApiRef, kubernetesProxyApiRef, useCustomResources, useEvents, useIsPodExecTerminalSupported, useKubernetesObjects, useMatchingErrors, usePodLogs, usePodMetrics };
3229
+ //# sourceMappingURL=index.esm.js.map