mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor ContainerEnviroment into seperate components
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
1e739ba7db
commit
4a37a74420
@ -100,6 +100,30 @@ export interface VolumeMount {
|
||||
subPathExpr?: string;
|
||||
}
|
||||
|
||||
export interface EnvVar {
|
||||
name: string;
|
||||
value?: string;
|
||||
valueFrom?: {
|
||||
fieldRef?: {
|
||||
apiVersion: string;
|
||||
fieldPath: string;
|
||||
};
|
||||
secretKeyRef?: {
|
||||
key: string;
|
||||
name: string;
|
||||
};
|
||||
configMapKeyRef?: {
|
||||
key: string;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface EnvFromSource {
|
||||
configMapRef?: LocalObjectReference;
|
||||
secretRef?: LocalObjectReference;
|
||||
}
|
||||
|
||||
export interface PodContainer extends Partial<Record<PodContainerProbe, IContainerProbe>> {
|
||||
name: string;
|
||||
image: string;
|
||||
@ -118,28 +142,8 @@ export interface PodContainer extends Partial<Record<PodContainerProbe, IContain
|
||||
};
|
||||
terminationMessagePath?: string;
|
||||
terminationMessagePolicy?: string;
|
||||
env?: {
|
||||
name: string;
|
||||
value?: string;
|
||||
valueFrom?: {
|
||||
fieldRef?: {
|
||||
apiVersion: string;
|
||||
fieldPath: string;
|
||||
};
|
||||
secretKeyRef?: {
|
||||
key: string;
|
||||
name: string;
|
||||
};
|
||||
configMapKeyRef?: {
|
||||
key: string;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
envFrom?: {
|
||||
configMapRef?: LocalObjectReference;
|
||||
secretRef?: LocalObjectReference;
|
||||
}[];
|
||||
env?: EnvVar[];
|
||||
envFrom?: EnvFromSource[];
|
||||
volumeMounts?: VolumeMount[];
|
||||
imagePullPolicy?: string;
|
||||
}
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./pod-container-env.scss";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { PodContainer } from "../../../common/k8s-api/endpoints";
|
||||
import { DrawerItem } from "../drawer";
|
||||
import { autorun } from "mobx";
|
||||
import { iter } from "../../utils";
|
||||
import _ from "lodash";
|
||||
import type { SecretStore } from "../+config-secrets/store";
|
||||
import type { ConfigMapStore } from "../+config-maps/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import configMapStoreInjectable from "../+config-maps/store.injectable";
|
||||
import secretStoreInjectable from "../+config-secrets/store.injectable";
|
||||
import { SecretKey } from "../+config-secrets/secret-key";
|
||||
|
||||
export interface ContainerEnvironmentProps {
|
||||
container: PodContainer;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
secretStore: SecretStore;
|
||||
configMapStore: ConfigMapStore;
|
||||
}
|
||||
|
||||
const NonInjectedContainerEnvironment = observer((props: ContainerEnvironmentProps & Dependencies) => {
|
||||
const {
|
||||
container: { env, envFrom },
|
||||
namespace,
|
||||
configMapStore,
|
||||
secretStore,
|
||||
} = props;
|
||||
|
||||
useEffect(() => autorun(() => {
|
||||
for (const { valueFrom } of env ?? []) {
|
||||
if (valueFrom?.configMapKeyRef) {
|
||||
configMapStore.load({ name: valueFrom.configMapKeyRef.name, namespace });
|
||||
}
|
||||
}
|
||||
|
||||
for (const { configMapRef, secretRef } of envFrom ?? []) {
|
||||
if (secretRef?.name) {
|
||||
secretStore.load({ name: secretRef.name, namespace });
|
||||
}
|
||||
|
||||
if (configMapRef?.name) {
|
||||
configMapStore.load({ name: configMapRef.name, namespace });
|
||||
}
|
||||
}
|
||||
}), []);
|
||||
|
||||
const renderEnv = () => {
|
||||
const orderedEnv = _.sortBy(env, "name");
|
||||
|
||||
return orderedEnv.map(variable => {
|
||||
const { name, value, valueFrom } = variable;
|
||||
let secretValue = null;
|
||||
|
||||
if (value) {
|
||||
secretValue = value;
|
||||
}
|
||||
|
||||
if (valueFrom) {
|
||||
const { fieldRef, secretKeyRef, configMapKeyRef } = valueFrom;
|
||||
|
||||
if (fieldRef) {
|
||||
const { apiVersion, fieldPath } = fieldRef;
|
||||
|
||||
secretValue = `fieldRef(${apiVersion}:${fieldPath})`;
|
||||
}
|
||||
|
||||
if (secretKeyRef) {
|
||||
const secret = secretStore.getByName(secretKeyRef.name, namespace);
|
||||
|
||||
if (secret) {
|
||||
secretValue = (
|
||||
<SecretKey
|
||||
secret={secret}
|
||||
field={secretKeyRef.key}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (configMapKeyRef) {
|
||||
const { name, key } = configMapKeyRef;
|
||||
const configMap = configMapStore.getByName(name, namespace);
|
||||
|
||||
secretValue = configMap
|
||||
? configMap.data[key]
|
||||
: `configMapKeyRef(${name}${key})`;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="variable"
|
||||
key={name}
|
||||
data-testid={`env-${name}`}
|
||||
>
|
||||
<span className="var-name">{name}</span>
|
||||
{`= `}
|
||||
{secretValue}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const renderEnvFrom = () => {
|
||||
return Array.from(iter.filterFlatMap(envFrom ?? [], vars => {
|
||||
if (vars.configMapRef?.name) {
|
||||
return renderEnvFromConfigMap(vars.configMapRef.name);
|
||||
}
|
||||
|
||||
if (vars.secretRef?.name) {
|
||||
return renderEnvFromSecret(vars.secretRef.name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}));
|
||||
};
|
||||
|
||||
const renderEnvFromConfigMap = (configMapName: string) => {
|
||||
const configMap = configMapStore.getByName(configMapName, namespace);
|
||||
|
||||
if (!configMap) return null;
|
||||
|
||||
return Object.entries(configMap.data).map(([name, value]) => (
|
||||
<div
|
||||
className="variable"
|
||||
key={name}
|
||||
data-testid={`envFrom-configmap-${configMap.getName()}`}
|
||||
>
|
||||
<span className="var-name">{name}</span>
|
||||
{`= `}
|
||||
{value}
|
||||
</div>
|
||||
));
|
||||
};
|
||||
|
||||
const renderEnvFromSecret = (secretName: string) => {
|
||||
const secret = secretStore.getByName(secretName, namespace);
|
||||
|
||||
if (!secret) return null;
|
||||
|
||||
return Object.keys(secret.data)
|
||||
.map(name => (
|
||||
<div
|
||||
className="variable"
|
||||
key={name}
|
||||
data-testid={`envFrom-secret-${secretName}-${name}`}
|
||||
>
|
||||
<span className="var-name">{name}</span>
|
||||
{`= `}
|
||||
<SecretKey
|
||||
secret={secret}
|
||||
field={name}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<DrawerItem name="Environment" className="ContainerEnvironment">
|
||||
{renderEnv()}
|
||||
{renderEnvFrom()}
|
||||
</DrawerItem>
|
||||
);
|
||||
});
|
||||
|
||||
export const ContainerEnvironment = withInjectables<Dependencies, ContainerEnvironmentProps>(NonInjectedContainerEnvironment, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
configMapStore: di.inject(configMapStoreInjectable),
|
||||
secretStore: di.inject(secretStoreInjectable),
|
||||
}),
|
||||
});
|
||||
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { autorun } from "mobx";
|
||||
import React, { useEffect } from "react";
|
||||
import type { ConfigMapStore } from "../../+config-maps/store";
|
||||
import configMapStoreInjectable from "../../+config-maps/store.injectable";
|
||||
import { SecretKey } from "../../+config-secrets/secret-key";
|
||||
import type { SecretStore } from "../../+config-secrets/store";
|
||||
import secretStoreInjectable from "../../+config-secrets/store.injectable";
|
||||
import type { EnvFromSource } from "../../../../common/k8s-api/endpoints";
|
||||
import type { Logger } from "../../../../common/logger";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import { iter, object } from "../../../utils";
|
||||
|
||||
export interface ContainerEnvFromSourceProps {
|
||||
envFrom: EnvFromSource[];
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
secretStore: SecretStore;
|
||||
configMapStore: ConfigMapStore;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
const NonInjectedContainerEnvFromSource = ({
|
||||
envFrom,
|
||||
namespace,
|
||||
configMapStore,
|
||||
secretStore,
|
||||
logger,
|
||||
}: ContainerEnvFromSourceProps & Dependencies) => {
|
||||
useEffect(() => autorun(() => {
|
||||
for (const { configMapRef, secretRef } of envFrom) {
|
||||
if (secretRef?.name) {
|
||||
secretStore
|
||||
.load({ name: secretRef.name, namespace })
|
||||
.catch(error => logger.warn(`[CONTAINER-ENV]: failed to load Secret ${secretRef.name} in ns=${namespace}`, error));
|
||||
}
|
||||
|
||||
if (configMapRef?.name) {
|
||||
configMapStore
|
||||
.load({ name: configMapRef.name, namespace })
|
||||
.catch(error => logger.warn(`[CONTAINER-ENV]: failed to load ConfigMap ${configMapRef.name} in ns=${namespace}`, error));
|
||||
}
|
||||
}
|
||||
}), []);
|
||||
|
||||
const renderValue = (testIdName: string, fieldName: string, kind: "configmap" | "secret", value: JSX.Element | string) => (
|
||||
<div
|
||||
className="variable"
|
||||
key={fieldName}
|
||||
data-testid={`envFrom-${kind}-${testIdName}`}
|
||||
>
|
||||
<span className="var-name">{fieldName}</span>
|
||||
{`= `}
|
||||
{value}
|
||||
</div>
|
||||
);
|
||||
|
||||
const renderEnvFromConfigMap = (configMapName: string) => {
|
||||
const configMap = configMapStore.getByName(configMapName, namespace);
|
||||
|
||||
return object.entries(configMap?.data ?? {})
|
||||
.map(([fieldName, value]) => renderValue(
|
||||
`${configMapName}:${fieldName}`,
|
||||
fieldName,
|
||||
"configmap",
|
||||
value,
|
||||
));
|
||||
};
|
||||
|
||||
const renderEnvFromSecret = (secretName: string) => {
|
||||
const secret = secretStore.getByName(secretName, namespace);
|
||||
|
||||
if (!secret) return null;
|
||||
|
||||
return Object.keys(secret.data)
|
||||
.map(fieldName => renderValue(
|
||||
`${secretName}:${fieldName}`,
|
||||
fieldName,
|
||||
"secret",
|
||||
<SecretKey
|
||||
secret={secret}
|
||||
field={fieldName}
|
||||
/>,
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
Array.from(iter.filterFlatMap(envFrom, vars => {
|
||||
if (vars.configMapRef?.name) {
|
||||
return renderEnvFromConfigMap(vars.configMapRef.name);
|
||||
}
|
||||
|
||||
if (vars.secretRef?.name) {
|
||||
return renderEnvFromSecret(vars.secretRef.name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}))
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ContainerEnvFromSource = withInjectables<Dependencies, ContainerEnvFromSourceProps>(NonInjectedContainerEnvFromSource, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
configMapStore: di.inject(configMapStoreInjectable),
|
||||
secretStore: di.inject(secretStoreInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
}),
|
||||
});
|
||||
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { sortBy } from "lodash";
|
||||
import { autorun } from "mobx";
|
||||
import React, { useEffect } from "react";
|
||||
import type { ConfigMapStore } from "../../+config-maps/store";
|
||||
import configMapStoreInjectable from "../../+config-maps/store.injectable";
|
||||
import { SecretKey } from "../../+config-secrets/secret-key";
|
||||
import type { SecretStore } from "../../+config-secrets/store";
|
||||
import secretStoreInjectable from "../../+config-secrets/store.injectable";
|
||||
import type { EnvVar } from "../../../../common/k8s-api/endpoints";
|
||||
import type { Logger } from "../../../../common/logger";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
|
||||
export interface ContainerEnvProps {
|
||||
env: EnvVar[];
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
secretStore: SecretStore;
|
||||
configMapStore: ConfigMapStore;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
const NonInjectedContainerEnv = ({
|
||||
env,
|
||||
namespace,
|
||||
configMapStore,
|
||||
secretStore,
|
||||
logger,
|
||||
}: ContainerEnvProps & Dependencies) => {
|
||||
useEffect(() => autorun(() => {
|
||||
for (const { valueFrom } of env) {
|
||||
if (valueFrom?.configMapKeyRef) {
|
||||
const { configMapKeyRef } = valueFrom;
|
||||
|
||||
configMapStore
|
||||
.load({ name: configMapKeyRef.name, namespace })
|
||||
.catch(error => logger.warn(`[CONTAINER-ENV]: failed to load ConfigMap ${configMapKeyRef.name} in ns=${namespace}`, error));
|
||||
}
|
||||
|
||||
if (valueFrom?.secretKeyRef) {
|
||||
const { secretKeyRef } = valueFrom;
|
||||
|
||||
secretStore
|
||||
.load({ name: secretKeyRef.name, namespace })
|
||||
.catch(error => logger.warn(`[CONTAINER-ENV]: failed to load Secret ${secretKeyRef.name} in ns=${namespace}`, error));
|
||||
}
|
||||
}
|
||||
}), []);
|
||||
|
||||
const getEnvVarValue = ({ value, valueFrom }: EnvVar) => {
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!valueFrom) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { fieldRef, secretKeyRef, configMapKeyRef } = valueFrom;
|
||||
|
||||
if (fieldRef) {
|
||||
const { apiVersion, fieldPath } = fieldRef;
|
||||
|
||||
return `fieldRef(${apiVersion}:${fieldPath})`;
|
||||
}
|
||||
|
||||
if (secretKeyRef) {
|
||||
const secret = secretStore.getByName(secretKeyRef.name, namespace);
|
||||
|
||||
if (secret) {
|
||||
return (
|
||||
<SecretKey
|
||||
secret={secret}
|
||||
field={secretKeyRef.key}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (configMapKeyRef) {
|
||||
const { name, key } = configMapKeyRef;
|
||||
const configMap = configMapStore.getByName(name, namespace);
|
||||
|
||||
return configMap?.data[key] ?? `configMapKeyRef(${name}${key})`;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
sortBy(env, "name")
|
||||
.map(envVar => ({
|
||||
name: envVar.name,
|
||||
value: getEnvVarValue(envVar),
|
||||
}))
|
||||
.filter(({ value }) => value !== null)
|
||||
.map(({ name, value }) => (
|
||||
<div
|
||||
className="variable"
|
||||
key={name}
|
||||
data-testid={`env-${name}`}
|
||||
>
|
||||
<span className="var-name">{name}</span>
|
||||
{`= `}
|
||||
{value}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ContainerEnv = withInjectables<Dependencies, ContainerEnvProps>(NonInjectedContainerEnv, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
configMapStore: di.inject(configMapStoreInjectable),
|
||||
secretStore: di.inject(secretStoreInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
}),
|
||||
});
|
||||
@ -13,7 +13,7 @@ import { Secret, ConfigMap, Pod, SecretType } from "../../../../common/k8s-api/e
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import { ContainerEnvironment } from "../pod-container-env";
|
||||
import { ContainerEnvironment } from "./view";
|
||||
|
||||
describe("<ContainerEnv />", () => {
|
||||
let render: DiRender;
|
||||
@ -24,11 +24,15 @@ describe("<ContainerEnv />", () => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
secretStore = ({
|
||||
load: jest.fn(),
|
||||
load: jest.fn().mockImplementation(async () => {
|
||||
return {} as Secret;
|
||||
}),
|
||||
getByName: jest.fn(),
|
||||
});
|
||||
configMapStore = ({
|
||||
load: jest.fn(),
|
||||
load: jest.fn().mockImplementation(async () => {
|
||||
return {} as ConfigMap;
|
||||
}),
|
||||
getByName: jest.fn(),
|
||||
});
|
||||
|
||||
@ -87,7 +91,7 @@ describe("<ContainerEnv />", () => {
|
||||
});
|
||||
const result = render(<ContainerEnvironment container={container} namespace={pod.getNs()} />);
|
||||
|
||||
expect(result.getByTestId("env-foobar").innerHTML).toBe(`<span class="var-name">foobar</span>= https://localhost:12345`);
|
||||
expect(result.getByTestId("env-foobar")).toHaveTextContent(`foobar= https://localhost:12345`);
|
||||
});
|
||||
|
||||
it("renders envFrom when given a configMapRef", () => {
|
||||
@ -136,7 +140,7 @@ describe("<ContainerEnv />", () => {
|
||||
});
|
||||
const result = render(<ContainerEnvironment container={container} namespace={pod.getNs()} />);
|
||||
|
||||
expect(result.getByTestId("envFrom-configmap-my-config-map").innerHTML).toBe(`<span class="var-name">configFoo</span>= configBar`);
|
||||
expect(result.getByTestId("envFrom-configmap-my-config-map:configFoo")).toHaveTextContent(`configFoo= configBar`);
|
||||
});
|
||||
|
||||
it("renders envFrom when given a secretRef", () => {
|
||||
@ -186,7 +190,7 @@ describe("<ContainerEnv />", () => {
|
||||
});
|
||||
const result = render(<ContainerEnvironment container={container} namespace={pod.getNs()} />);
|
||||
|
||||
expect(result.getByTestId("envFrom-secret-my-secret-bar").innerHTML).toMatch(`<span class="var-name">bar</span>= secretKeyRef(my-secret.bar)`);
|
||||
expect(result.getByTestId("envFrom-secret-my-secret:bar")).toHaveTextContent(/^bar= secretKeyRef\(my-secret\.bar\)/);
|
||||
});
|
||||
|
||||
it("renders env", () => {
|
||||
@ -214,7 +218,7 @@ describe("<ContainerEnv />", () => {
|
||||
});
|
||||
const result = render(<ContainerEnvironment container={container} namespace={pod.getNs()} />);
|
||||
|
||||
expect(result.getByTestId("env-foobar").innerHTML).toBe(`<span class="var-name">foobar</span>= https://localhost:12345`);
|
||||
expect(result.getByTestId("env-foobar")).toHaveTextContent(`foobar= https://localhost:12345`);
|
||||
});
|
||||
|
||||
it("renders both env and configMapRef envFrom", () => {
|
||||
@ -267,7 +271,7 @@ describe("<ContainerEnv />", () => {
|
||||
});
|
||||
const result = render(<ContainerEnvironment container={container} namespace={pod.getNs()} />);
|
||||
|
||||
expect(result.getByTestId("env-foobar").innerHTML).toBe(`<span class="var-name">foobar</span>= https://localhost:12345`);
|
||||
expect(result.getByTestId("envFrom-configmap-my-config-map").innerHTML).toBe(`<span class="var-name">configFoo</span>= configBar`);
|
||||
expect(result.getByTestId("env-foobar")).toHaveTextContent(`foobar= https://localhost:12345`);
|
||||
expect(result.getByTestId("envFrom-configmap-my-config-map:configFoo")).toHaveTextContent(`configFoo= configBar`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./view.scss";
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { PodContainer } from "../../../../common/k8s-api/endpoints";
|
||||
import { DrawerItem } from "../../drawer";
|
||||
import { ContainerEnv } from "./env";
|
||||
import { ContainerEnvFromSource } from "./env-from";
|
||||
|
||||
export interface ContainerEnvironmentProps {
|
||||
container: PodContainer;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export const ContainerEnvironment = observer(({
|
||||
container: { env, envFrom },
|
||||
namespace,
|
||||
}: ContainerEnvironmentProps) => (
|
||||
<DrawerItem name="Environment" className="ContainerEnvironment">
|
||||
{env && (
|
||||
<ContainerEnv
|
||||
env={env}
|
||||
namespace={namespace}
|
||||
/>
|
||||
)}
|
||||
{envFrom && (
|
||||
<ContainerEnvFromSource
|
||||
envFrom={envFrom}
|
||||
namespace={namespace}
|
||||
/>
|
||||
)}
|
||||
</DrawerItem>
|
||||
));
|
||||
@ -11,7 +11,7 @@ import { DrawerItem } from "../drawer";
|
||||
import { cssNames, isDefined } from "../../utils";
|
||||
import { StatusBrick } from "../status-brick";
|
||||
import { Badge } from "../badge";
|
||||
import { ContainerEnvironment } from "./pod-container-env";
|
||||
import { ContainerEnvironment } from "./pod-container-env/view";
|
||||
import { PodContainerPort } from "./pod-container-port";
|
||||
import { ResourceMetrics } from "../resource-metrics";
|
||||
import type { MetricData } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user