1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

chore: Fix overriding errors by improving abstraction usage

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-05-03 10:06:46 -04:00
parent a86361e09e
commit 1bc837608c
7 changed files with 97 additions and 37 deletions

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { ConfigMapStore } from "./store";
import configMapStoreInjectable from "./store.injectable";
export type RequestConfigMap = ConfigMapStore["load"];
const requestConfigMapInjectable = getInjectable({
id: "request-config-map",
instantiate: (di): RequestConfigMap => {
const configMapStore = di.inject(configMapStoreInjectable);
return (ref) => configMapStore.load(ref);
},
});
export default requestConfigMapInjectable;

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { SecretStore } from "./store";
import secretStoreInjectable from "./store.injectable";
export type RequestSecret = SecretStore["load"];
const requestSecretInjectable = getInjectable({
id: "request-secret",
instantiate: (di): RequestSecret => {
const secretStore = di.inject(secretStoreInjectable);
return (ref) => secretStore.load(ref);
},
});
export default requestSecretInjectable;

View File

@ -22,9 +22,12 @@ import type { GetDetailsUrl } from "../../kube-detail-params/get-details-url.inj
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable"; import getDetailsUrlInjectable from "../../kube-detail-params/get-details-url.injectable";
import secretStoreInjectable from "../../config-secrets/store.injectable"; import secretStoreInjectable from "../../config-secrets/store.injectable";
import type { RequestSecret } from "../../config-secrets/request-secret.injectable";
import requestSecretInjectable from "../../config-secrets/request-secret.injectable";
interface Dependencies { interface Dependencies {
secretStore: SecretStore; secretStore: SecretStore;
requestSecret: RequestSecret;
getDetailsUrl: GetDetailsUrl; getDetailsUrl: GetDetailsUrl;
} }
@ -35,7 +38,7 @@ class NonInjectedServiceAccountsDetails extends React.Component<KubeObjectDetail
private defensiveLoadSecretIn = (namespace: string) => ( private defensiveLoadSecretIn = (namespace: string) => (
({ name }: { name: string }) => ( ({ name }: { name: string }) => (
this.props.secretStore.load({ name, namespace }) this.props.requestSecret({ name, namespace })
.catch(() => name) .catch(() => name)
) )
); );
@ -164,5 +167,6 @@ export const ServiceAccountsDetails = withInjectables<Dependencies, KubeObjectDe
...props, ...props,
getDetailsUrl: di.inject(getDetailsUrlInjectable), getDetailsUrl: di.inject(getDetailsUrlInjectable),
secretStore: di.inject(secretStoreInjectable), secretStore: di.inject(secretStoreInjectable),
requestSecret: di.inject(requestSecretInjectable),
}), }),
}); });

View File

@ -5,15 +5,15 @@
import React from "react"; import React from "react";
import type { ConfigMapStore } from "../../config-maps/store"; import type { ConfigMapStore } from "../../config-maps/store";
import configMapStoreInjectable from "../../config-maps/store.injectable";
import type { SecretStore } from "../../config-secrets/store"; import type { SecretStore } from "../../config-secrets/store";
import secretStoreInjectable from "../../config-secrets/store.injectable";
import type { Container } from "@k8slens/kube-object"; import type { Container } from "@k8slens/kube-object";
import { Secret, ConfigMap, Pod, SecretType } from "@k8slens/kube-object"; import { Secret, ConfigMap, Pod, SecretType } from "@k8slens/kube-object";
import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
import type { DiRender } from "../../test-utils/renderFor"; import type { DiRender } from "../../test-utils/renderFor";
import { renderFor } from "../../test-utils/renderFor"; import { renderFor } from "../../test-utils/renderFor";
import { ContainerEnvironment } from "../pod-container-env"; import { ContainerEnvironment } from "../pod-container-env";
import requestSecretInjectable from "../../config-secrets/request-secret.injectable";
import requestConfigMapInjectable from "../../config-maps/request-config-map.injectable";
describe("<ContainerEnv />", () => { describe("<ContainerEnv />", () => {
let render: DiRender; let render: DiRender;
@ -36,8 +36,8 @@ describe("<ContainerEnv />", () => {
getByName: jest.fn(), getByName: jest.fn(),
}); });
di.override(secretStoreInjectable, () => secretStore as jest.Mocked<SecretStore>); di.override(requestSecretInjectable, () => () => Promise.resolve({} as Secret));
di.override(configMapStoreInjectable, () => configMapStore as jest.Mocked<ConfigMapStore>); di.override(requestConfigMapInjectable, () => () => Promise.resolve({} as ConfigMap));
render = renderFor(di); render = renderFor(di);
}); });

View File

@ -5,19 +5,20 @@
import "./pod-container-env.scss"; import "./pod-container-env.scss";
import React, { useEffect } from "react"; import React, { useEffect, useRef } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import type { Container } from "@k8slens/kube-object"; import type { ConfigMap, Container, Secret } from "@k8slens/kube-object";
import { DrawerItem } from "../drawer"; import { DrawerItem } from "../drawer";
import { autorun } from "mobx"; import { autorun, observable } from "mobx";
import { object } from "@k8slens/utilities"; import { getOrInsertWith, object } from "@k8slens/utilities";
import _ from "lodash"; import _ from "lodash";
import { withInjectables } from "@ogre-tools/injectable-react"; import type { IAsyncComputed } from "@ogre-tools/injectable-react";
import type { ConfigMapStore } from "../config-maps/store"; import { asyncComputed, withInjectables } from "@ogre-tools/injectable-react";
import type { SecretStore } from "../config-secrets/store";
import configMapStoreInjectable from "../config-maps/store.injectable";
import secretStoreInjectable from "../config-secrets/store.injectable";
import { SecretKey } from "./secret-key"; import { SecretKey } from "./secret-key";
import type { RequestSecret } from "../config-secrets/request-secret.injectable";
import requestSecretInjectable from "../config-secrets/request-secret.injectable";
import type { RequestConfigMap } from "../config-maps/request-config-map.injectable";
import requestConfigMapInjectable from "../config-maps/request-config-map.injectable";
export interface ContainerEnvironmentProps { export interface ContainerEnvironmentProps {
container: Container; container: Container;
@ -25,32 +26,49 @@ export interface ContainerEnvironmentProps {
} }
interface Dependencies { interface Dependencies {
configMapStore: ConfigMapStore; requestConfigMap: RequestConfigMap;
secretStore: SecretStore; requestSecret: RequestSecret;
} }
const NonInjectedContainerEnvironment = observer((props: Dependencies & ContainerEnvironmentProps) => { const NonInjectedContainerEnvironment = observer((props: Dependencies & ContainerEnvironmentProps) => {
const { const {
container: { env, envFrom = [] }, container: { env, envFrom = [] },
namespace, namespace,
configMapStore, requestConfigMap,
secretStore, requestSecret,
} = props; } = props;
const secrets = useRef(observable.map<string, IAsyncComputed<Secret>>());
const configMaps = useRef(observable.map<string, IAsyncComputed<ConfigMap>>());
useEffect( () => autorun(() => { useEffect( () => autorun(() => {
for (const { valueFrom } of env ?? []) { for (const { valueFrom } of env ?? []) {
if (valueFrom?.configMapKeyRef?.name) { const { configMapKeyRef: { name } = { name: undefined }} = valueFrom ?? {};
void configMapStore.load({ name: valueFrom.configMapKeyRef.name, namespace });
if (name) {
getOrInsertWith(configMaps.current, name, () => asyncComputed({
betweenUpdates: "show-latest-value",
valueWhenPending: undefined,
getValueFromObservedPromise: () => requestConfigMap({ name, namespace }),
}));
} }
} }
for (const { configMapRef, secretRef } of envFrom ?? []) { for (const { configMapRef, secretRef } of envFrom ?? []) {
if (secretRef?.name) { if (secretRef?.name) {
void secretStore.load({ name: secretRef.name, namespace }); getOrInsertWith(secrets.current, secretRef.name, () => asyncComputed({
betweenUpdates: "show-latest-value",
valueWhenPending: undefined,
getValueFromObservedPromise: () => requestSecret({ name: secretRef.name, namespace }),
}));
} }
if (configMapRef?.name) { if (configMapRef?.name) {
void configMapStore.load({ name: configMapRef.name, namespace }); getOrInsertWith(configMaps.current, configMapRef.name, () => asyncComputed({
betweenUpdates: "show-latest-value",
valueWhenPending: undefined,
getValueFromObservedPromise: () => requestConfigMap({ name: configMapRef.name, namespace }),
}));
} }
} }
}), []); }), []);
@ -83,7 +101,7 @@ const NonInjectedContainerEnvironment = observer((props: Dependencies & Containe
); );
} else if (configMapKeyRef?.name) { } else if (configMapKeyRef?.name) {
const { name, key } = configMapKeyRef; const { name, key } = configMapKeyRef;
const configMap = configMapStore.getByName(name, namespace); const configMap = configMaps.current.get(name)?.value.get();
secretValue = configMap secretValue = configMap
? configMap.data[key] ? configMap.data[key]
@ -117,7 +135,7 @@ const NonInjectedContainerEnvironment = observer((props: Dependencies & Containe
); );
const renderEnvFromConfigMap = (configMapName: string, prefix: string | undefined) => { const renderEnvFromConfigMap = (configMapName: string, prefix: string | undefined) => {
const configMap = configMapStore.getByName(configMapName, namespace); const configMap = configMaps.current.get(configMapName)?.value.get();
if (!configMap) return null; if (!configMap) return null;
@ -135,7 +153,7 @@ const NonInjectedContainerEnvironment = observer((props: Dependencies & Containe
}; };
const renderEnvFromSecret = (secretName: string, prefix: string | undefined) => { const renderEnvFromSecret = (secretName: string, prefix: string | undefined) => {
const secret = secretStore.getByName(secretName, namespace); const secret = secrets.current.get(secretName)?.value.get();
if (!secret) return null; if (!secret) return null;
@ -169,7 +187,7 @@ const NonInjectedContainerEnvironment = observer((props: Dependencies & Containe
export const ContainerEnvironment = withInjectables<Dependencies, ContainerEnvironmentProps>(NonInjectedContainerEnvironment, { export const ContainerEnvironment = withInjectables<Dependencies, ContainerEnvironmentProps>(NonInjectedContainerEnvironment, {
getProps: (di, props) => ({ getProps: (di, props) => ({
...props, ...props,
configMapStore: di.inject(configMapStoreInjectable), requestConfigMap: di.inject(requestConfigMapInjectable),
secretStore: di.inject(secretStoreInjectable), requestSecret: di.inject(requestSecretInjectable),
}), }),
}); });

View File

@ -10,11 +10,11 @@ import type { RenderResult } from "@testing-library/react";
import { act } from "@testing-library/react"; import { act } from "@testing-library/react";
import React from "react"; import React from "react";
import type { SecretStore } from "../config-secrets/store"; import type { SecretStore } from "../config-secrets/store";
import secretStoreInjectable from "../config-secrets/store.injectable";
import { Secret, SecretType } from "@k8slens/kube-object"; import { Secret, SecretType } from "@k8slens/kube-object";
import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import { renderFor } from "../test-utils/renderFor"; import { renderFor } from "../test-utils/renderFor";
import { SecretKey } from "./secret-key"; import { SecretKey } from "./secret-key";
import requestSecretInjectable from "../config-secrets/request-secret.injectable";
describe("SecretKey technical tests", () => { describe("SecretKey technical tests", () => {
let loadSecretMock: AsyncFnMock<SecretStore["load"]>; let loadSecretMock: AsyncFnMock<SecretStore["load"]>;
@ -25,9 +25,7 @@ describe("SecretKey technical tests", () => {
const render = renderFor(di); const render = renderFor(di);
loadSecretMock = asyncFn(); loadSecretMock = asyncFn();
di.override(secretStoreInjectable, () => ({ di.override(requestSecretInjectable, () => loadSecretMock);
load: loadSecretMock,
} as Partial<SecretStore> as SecretStore));
result = render(( result = render((
<SecretKey <SecretKey

View File

@ -6,10 +6,10 @@ import React, { useState } from "react";
import type { EnvVarKeySelector } from "@k8slens/kube-object"; import type { EnvVarKeySelector } from "@k8slens/kube-object";
import { Icon } from "@k8slens/icon"; import { Icon } from "@k8slens/icon";
import { base64, cssNames, isObject } from "@k8slens/utilities"; import { base64, cssNames, isObject } from "@k8slens/utilities";
import type { SecretStore } from "../config-secrets/store";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import secretStoreInjectable from "../config-secrets/store.injectable";
import type { SetRequired } from "type-fest"; import type { SetRequired } from "type-fest";
import type { RequestSecret } from "../config-secrets/request-secret.injectable";
import requestSecretInjectable from "../config-secrets/request-secret.injectable";
export interface SecretKeyProps { export interface SecretKeyProps {
reference: SetRequired<EnvVarKeySelector, "name">; reference: SetRequired<EnvVarKeySelector, "name">;
@ -17,12 +17,12 @@ export interface SecretKeyProps {
} }
interface Dependencies { interface Dependencies {
secretStore: SecretStore; requestSecret: RequestSecret;
} }
const NonInjectedSecretKey = (props: SecretKeyProps & Dependencies) => { const NonInjectedSecretKey = (props: SecretKeyProps & Dependencies) => {
const { const {
reference: { name, key }, namespace, secretStore, reference: { name, key }, namespace, requestSecret,
} = props; } = props;
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -38,7 +38,7 @@ const NonInjectedSecretKey = (props: SecretKeyProps & Dependencies) => {
void (async () => { void (async () => {
try { try {
const secret = await secretStore.load({ name, namespace }); const secret = await requestSecret({ name, namespace });
try { try {
setSecretData(base64.decode(secret.data[key] ?? "")); setSecretData(base64.decode(secret.data[key] ?? ""));
@ -82,6 +82,6 @@ const NonInjectedSecretKey = (props: SecretKeyProps & Dependencies) => {
export const SecretKey = withInjectables<Dependencies, SecretKeyProps>(NonInjectedSecretKey, { export const SecretKey = withInjectables<Dependencies, SecretKeyProps>(NonInjectedSecretKey, {
getProps: (di, props) => ({ getProps: (di, props) => ({
...props, ...props,
secretStore: di.inject(secretStoreInjectable), requestSecret: di.inject(requestSecretInjectable),
}), }),
}); });