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

Fix merge conflicts

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-05-17 13:33:39 +03:00
parent 7a89c8f74c
commit c0cc56dba2
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
59 changed files with 358 additions and 469 deletions

View File

@ -340,7 +340,7 @@ exports[`helm-charts - navigation to Helm charts when navigating to Helm charts
class="items box grow flex column" class="items box grow flex column"
> >
<div <div
class="Table flex column HelmCharts box grow some-active-theme-type selectable scrollable sortable autoSize virtual" class="Table flex column HelmCharts box grow dark selectable scrollable sortable autoSize virtual"
> >
<div <div
class="TableHead sticky nowrap topLine" class="TableHead sticky nowrap topLine"
@ -430,7 +430,7 @@ exports[`helm-charts - navigation to Helm charts when navigating to Helm charts
> >
<i <i
class="Icon material interactive focusable" class="Icon material interactive focusable"
id="menu_actions_15" id="menu_actions_17"
tabindex="0" tabindex="0"
> >
<span <span

View File

@ -10,8 +10,6 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import currentPathInjectable from "../../renderer/routes/current-path.injectable"; import currentPathInjectable from "../../renderer/routes/current-path.injectable";
import { routeInjectionToken } from "../../common/front-end-routing/route-injection-token"; import { routeInjectionToken } from "../../common/front-end-routing/route-injection-token";
import { computed } from "mobx"; import { computed } from "mobx";
import type { UserStore } from "../../common/user-store";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import { preferenceNavigationItemInjectionToken } from "../../renderer/components/+preferences/preferences-navigation/preference-navigation-items.injectable"; import { preferenceNavigationItemInjectionToken } from "../../renderer/components/+preferences/preferences-navigation/preference-navigation-items.injectable";
import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable"; import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
import { Preferences } from "../../renderer/components/+preferences"; import { Preferences } from "../../renderer/components/+preferences";
@ -24,7 +22,6 @@ import { createObservableHistory } from "mobx-observable-history";
import navigateToPreferenceTabInjectable from "../../renderer/components/+preferences/preferences-navigation/navigate-to-preference-tab.injectable"; import navigateToPreferenceTabInjectable from "../../renderer/components/+preferences/preferences-navigation/navigate-to-preference-tab.injectable";
import navigateToFrontPageInjectable from "../../common/front-end-routing/navigate-to-front-page.injectable"; import navigateToFrontPageInjectable from "../../common/front-end-routing/navigate-to-front-page.injectable";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - closing-preferences", () => { describe("preferences - closing-preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
@ -39,16 +36,6 @@ describe("preferences - closing-preferences", () => {
rendererDi.register(testFrontPageRouteComponentInjectable); rendererDi.register(testFrontPageRouteComponentInjectable);
rendererDi.register(testNavigationItemInjectable); rendererDi.register(testNavigationItemInjectable);
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
rendererDi.override(navigateToFrontPageInjectable, (di) => { rendererDi.override(navigateToFrontPageInjectable, (di) => {
const navigateToRoute = di.inject(navigateToRouteInjectionToken); const navigateToRoute = di.inject(navigateToRouteInjectionToken);
const testFrontPage = di.inject(testFrontPageRouteInjectable); const testFrontPage = di.inject(testFrontPageRouteInjectable);

View File

@ -5,28 +5,13 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import type { UserStore } from "../../common/user-store";
import navigateToProxyPreferencesInjectable from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable"; import navigateToProxyPreferencesInjectable from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to application preferences", () => { describe("preferences - navigation to application preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
}); });
describe("given in some child page of preferences, when rendered", () => { describe("given in some child page of preferences, when rendered", () => {

View File

@ -5,28 +5,12 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import type { UserStore } from "../../common/user-store";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to editor preferences", () => { describe("preferences - navigation to editor preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
editorConfiguration: { minimap: {}, tabSize: 42, fontSize: 42 },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {

View File

@ -5,30 +5,15 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import type { UserStore } from "../../common/user-store";
import React from "react"; import React from "react";
import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake"; import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake"; import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to extension specific preferences", () => { describe("preferences - navigation to extension specific preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {

View File

@ -5,29 +5,12 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import type { UserStore } from "../../common/user-store";
import { observable } from "mobx";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to kubernetes preferences", () => { describe("preferences - navigation to kubernetes preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
syncKubeconfigEntries: observable.map(),
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {

View File

@ -5,27 +5,12 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import type { UserStore } from "../../common/user-store";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to proxy preferences", () => { describe("preferences - navigation to proxy preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {

View File

@ -8,29 +8,14 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake"; import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake"; import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import type { UserStore } from "../../common/user-store";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable"; import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable";
import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable"; import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to telemetry preferences", () => { describe("preferences - navigation to telemetry preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {

View File

@ -5,11 +5,7 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import type { UserStore } from "../../common/user-store";
import { observable } from "mobx";
import defaultShellInjectable from "../../renderer/components/+preferences/default-shell.injectable"; import defaultShellInjectable from "../../renderer/components/+preferences/default-shell.injectable";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation to terminal preferences", () => { describe("preferences - navigation to terminal preferences", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
@ -18,18 +14,7 @@ describe("preferences - navigation to terminal preferences", () => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
syncKubeconfigEntries: observable.map(),
terminalConfig: { fontSize: 42 },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(defaultShellInjectable, () => "some-default-shell"); rendererDi.override(defaultShellInjectable, () => "some-default-shell");
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
}); });
}); });

View File

@ -6,10 +6,6 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
import type { UserStore } from "../../common/user-store";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("preferences - navigation using application menu", () => { describe("preferences - navigation using application menu", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
@ -17,19 +13,6 @@ describe("preferences - navigation using application menu", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi, mainDi }) => {
mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
const userStoreStub = {
extensionRegistryUrl: { customUrl: "some-custom-url" },
} as unknown as UserStore;
rendererDi.override(userStoreInjectable, () => userStoreStub);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
});
rendered = await applicationBuilder.render(); rendered = await applicationBuilder.render();
}); });

View File

@ -284,7 +284,7 @@ describe("HotbarStore", () => {
}); });
describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => { describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => {
beforeEach(async () => { beforeEach(() => {
const configurationToBeMigrated = { const configurationToBeMigrated = {
"some-directory-for-user-data": { "some-directory-for-user-data": {
"lens-hotbar-store.json": JSON.stringify({ "lens-hotbar-store.json": JSON.stringify({
@ -351,8 +351,6 @@ describe("HotbarStore", () => {
di.override(appVersionInjectable, () => "5.0.0-beta.10"); di.override(appVersionInjectable, () => "5.0.0-beta.10");
await di.runSetups();
hotbarStore = di.inject(hotbarStoreInjectable); hotbarStore = di.inject(hotbarStoreInjectable);
hotbarStore.load(); hotbarStore.load();

View File

@ -1,14 +0,0 @@
/**
* 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 { catalogCategoryRegistry } from "./catalog-category-registry";
const catalogCategoryRegistryInjectable = getInjectable({
id: "catalog-category-registry",
instantiate: () => catalogCategoryRegistry,
causesSideEffects: true,
});
export default catalogCategoryRegistryInjectable;

View File

@ -10,6 +10,7 @@ export type HasCategoryForEntity = (data: CatalogEntityData & CatalogEntityKindD
const hasCategoryForEntityInjectable = getInjectable({ const hasCategoryForEntityInjectable = getInjectable({
id: "has-category-for-entity", id: "has-category-for-entity",
instantiate: (di): HasCategoryForEntity => { instantiate: (di): HasCategoryForEntity => {
const registry = di.inject(catalogCategoryRegistryInjectable); const registry = di.inject(catalogCategoryRegistryInjectable);

View File

@ -30,8 +30,8 @@ export interface ClusterDependencies {
readonly directoryForKubeConfigs: string; readonly directoryForKubeConfigs: string;
readonly logger: Logger; readonly logger: Logger;
readonly detectorRegistry: DetectorRegistry; readonly detectorRegistry: DetectorRegistry;
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager | undefined; createKubeconfigManager: (cluster: Cluster) => KubeconfigManager;
createContextHandler: (cluster: Cluster) => ClusterContextHandler | undefined; createContextHandler: (cluster: Cluster) => ClusterContextHandler;
createKubectl: (clusterVersion: string) => Kubectl; createKubectl: (clusterVersion: string) => Kubectl;
createAuthorizationReview: (config: KubeConfig) => CanI; createAuthorizationReview: (config: KubeConfig) => CanI;
createListNamespaces: (config: KubeConfig) => ListNamespaces; createListNamespaces: (config: KubeConfig) => ListNamespaces;

View File

@ -23,11 +23,9 @@ const mockFetch = fetch as FetchMock;
describe("forRemoteCluster", () => { describe("forRemoteCluster", () => {
let apiManager: jest.Mocked<ApiManager>; let apiManager: jest.Mocked<ApiManager>;
beforeEach(async () => { beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true }); const di = getDiForUnitTesting({ doGeneralOverrides: true });
await di.runSetups();
apiManager = new ApiManager() as jest.Mocked<ApiManager>; apiManager = new ApiManager() as jest.Mocked<ApiManager>;
di.override(apiManagerInjectable, () => apiManager); di.override(apiManagerInjectable, () => apiManager);
@ -87,11 +85,9 @@ describe("KubeApi", () => {
let request: KubeJsonApi; let request: KubeJsonApi;
let apiManager: jest.Mocked<ApiManager>; let apiManager: jest.Mocked<ApiManager>;
beforeEach(async () => { beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true }); const di = getDiForUnitTesting({ doGeneralOverrides: true });
await di.runSetups();
request = new KubeJsonApi({ request = new KubeJsonApi({
serverAddress: `http://127.0.0.1:9999`, serverAddress: `http://127.0.0.1:9999`,
apiBase: "/api-kube", apiBase: "/api-kube",

View File

@ -45,7 +45,7 @@ describe("runManyFor", () => {
const runMany = runManyFor(rootDi)(someInjectionTokenForRunnables); const runMany = runManyFor(rootDi)(someInjectionTokenForRunnables);
actualPromise = runMany(); actualPromise = runMany() as Promise<void>;
}); });
it("runs all runnables at the same time", () => { it("runs all runnables at the same time", () => {
@ -66,7 +66,7 @@ describe("runManyFor", () => {
}); });
describe("given hierarchy that is three levels deep, when running many", () => { describe("given hierarchy that is three levels deep, when running many", () => {
let runMock: AsyncFnMock<(arg: string) => Promise<void>>; let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
let actualPromise: Promise<void>; let actualPromise: Promise<void>;
beforeEach(() => { beforeEach(() => {
@ -110,7 +110,7 @@ describe("runManyFor", () => {
const runMany = runManyFor(di)(someInjectionTokenForRunnables); const runMany = runManyFor(di)(someInjectionTokenForRunnables);
actualPromise = runMany(); actualPromise = runMany() as Promise<void>;
}); });
it("runs first level runnables", () => { it("runs first level runnables", () => {
@ -173,7 +173,7 @@ describe("runManyFor", () => {
}); });
describe("when running many with parameter", () => { describe("when running many with parameter", () => {
let runMock: AsyncFnMock<(arg: string, arg2: string) => Promise<void>>; let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
beforeEach(() => { beforeEach(() => {
const rootDi = createContainer(); const rootDi = createContainer();

View File

@ -10,19 +10,23 @@ import type {
import { filter, map } from "lodash/fp"; import { filter, map } from "lodash/fp";
export interface Runnable<TParameter = void> { export interface Runnable<TParameter = void> {
run: (parameter: TParameter) => Promise<void> | void; run: Run<TParameter>;
runAfter?: this; runAfter?: this;
} }
export const runManyFor = type Run<Param> = (parameter: Param) => Promise<void> | void;
(di: DiContainerForInjection) =>
<TRunnable extends Runnable<unknown>>( export type RunMany = <Param>(
injectionToken: InjectionToken<TRunnable, void>, injectionToken: InjectionToken<Runnable<Param>, void>
) => ) => Run<Param>;
async (parameter: Parameters<TRunnable["run"]>[0]) => {
export function runManyFor(di: DiContainerForInjection): RunMany {
return (injectionToken) => async (parameter) => {
const allRunnables = di.injectMany(injectionToken); const allRunnables = di.injectMany(injectionToken);
const recursedRun = async (runAfterRunnable: Runnable<unknown> = undefined) => const recursedRun = async (
runAfterRunnable: Runnable<any> | undefined = undefined,
) =>
await pipeline( await pipeline(
allRunnables, allRunnables,
@ -34,11 +38,9 @@ export const runManyFor =
await recursedRun(runnable); await recursedRun(runnable);
}), }),
promises => Promise.all(promises), (promises) => Promise.all(promises),
); );
await recursedRun(); await recursedRun();
}; };
}

View File

@ -8,21 +8,26 @@ import type {
InjectionToken, InjectionToken,
} from "@ogre-tools/injectable"; } from "@ogre-tools/injectable";
import { filter, map } from "lodash/fp"; import { filter, map } from "lodash/fp";
import type { Runnable } from "./run-many-for";
export interface RunnableSync<TParameter = void> { export interface RunnableSync<TParameter = void> {
run: (parameter: TParameter) => void; run: RunSync<TParameter>;
runAfter?: this; runAfter?: this;
} }
export const runManySyncFor = type RunSync<Param> = (parameter: Param) => void;
(di: DiContainerForInjection) =>
<TRunnable extends RunnableSync<unknown>>( export type RunManySync = <Param>(
injectionToken: InjectionToken<TRunnable, void>, injectionToken: InjectionToken<Runnable<Param>, void>
) => ) => RunSync<Param>;
(parameter: Parameters<TRunnable["run"]>[0]) => {
export function runManySyncFor(di: DiContainerForInjection): RunManySync {
return (injectionToken) => async (parameter) => {
const allRunnables = di.injectMany(injectionToken); const allRunnables = di.injectMany(injectionToken);
const recursedRun = (runAfterRunnable: RunnableSync<unknown> = undefined) => const recursedRun = (
runAfterRunnable: RunnableSync<any> | undefined = undefined,
) =>
pipeline( pipeline(
allRunnables, allRunnables,
@ -37,3 +42,4 @@ export const runManySyncFor =
recursedRun(); recursedRun();
}; };
}

View File

@ -33,5 +33,11 @@ export const getLegacyGlobalDiForExtensionApi = () => {
}; };
export function getEnvironmentSpecificLegacyGlobalDiForExtensionApi(environment: Environments) { export function getEnvironmentSpecificLegacyGlobalDiForExtensionApi(environment: Environments) {
return legacyGlobalDis.get(environment); const di = legacyGlobalDis.get(environment);
if (!di) {
throw new Error("Tried to get DI container using legacy globals in environment which doesn't exist");
}
return di;
} }

View File

@ -35,7 +35,7 @@ describe("get-electron-app-path", () => {
di.override(registerChannelInjectable, () => () => undefined); di.override(registerChannelInjectable, () => () => undefined);
di.override(joinPathsInjectable, () => joinPathsFake); di.override(joinPathsInjectable, () => joinPathsFake);
getElectronAppPath = di.inject(getElectronAppPathInjectable); getElectronAppPath = di.inject(getElectronAppPathInjectable) as (name: string) => string;
}); });
it("given app path exists, when called, returns app path", () => { it("given app path exists, when called, returns app path", () => {

View File

@ -7,7 +7,7 @@ import directoryForKubeConfigsInjectable from "../../../common/app-paths/directo
import { KubeconfigSyncManager } from "./manager"; import { KubeconfigSyncManager } from "./manager";
import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token";
import clusterManagerInjectable from "../../cluster-manager.injectable"; import clusterManagerInjectable from "../../cluster-manager.injectable";
import catalogEntityRegistryInjectable from "../../catalog/catalog-entity-registry.injectable"; import catalogEntityRegistryInjectable from "../../catalog/entity-registry.injectable";
const kubeconfigSyncManagerInjectable = getInjectable({ const kubeconfigSyncManagerInjectable = getInjectable({
id: "kubeconfig-sync-manager", id: "kubeconfig-sync-manager",

View File

@ -5,7 +5,7 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { syncWeblinks } from "./weblinks"; import { syncWeblinks } from "./weblinks";
import weblinkStoreInjectable from "../../common/weblink-store.injectable"; import weblinkStoreInjectable from "../../common/weblink-store.injectable";
import catalogEntityRegistryInjectable from "../catalog/catalog-entity-registry.injectable"; import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
const syncWeblinksInjectable = getInjectable({ const syncWeblinksInjectable = getInjectable({
id: "sync-weblinks", id: "sync-weblinks",

View File

@ -3,9 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import catalogEntityRegistryInjectable from "../catalog/catalog-entity-registry.injectable";
import { startCatalogSyncToRenderer } from "../catalog-pusher"; import { startCatalogSyncToRenderer } from "../catalog-pusher";
import { getStartableStoppable } from "../../common/utils/get-startable-stoppable"; import { getStartableStoppable } from "../../common/utils/get-startable-stoppable";
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
const catalogSyncToRendererInjectable = getInjectable({ const catalogSyncToRendererInjectable = getInjectable({
id: "catalog-sync-to-renderer", id: "catalog-sync-to-renderer",

View File

@ -4,14 +4,13 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import hasCategoryForEntityInjectable from "../../common/catalog/has-category-for-entity.injectable"; import hasCategoryForEntityInjectable from "../../common/catalog/has-category-for-entity.injectable";
import { CatalogEntityRegistry } from "./catalog-entity-registry"; import { CatalogEntityRegistry } from "./entity-registry";
import catalogCategoryRegistryInjectable from "../../common/catalog/catalog-category-registry.injectable";
const catalogEntityRegistryInjectable = getInjectable({ const catalogEntityRegistryInjectable = getInjectable({
id: "catalog-entity-registry", id: "catalog-entity-registry",
instantiate: (di) => new CatalogEntityRegistry({ instantiate: (di) => new CatalogEntityRegistry({
hasCategoryForEntity: di.inject(hasCategoryForEntityInjectable), hasCategoryForEntity: di.inject(hasCategoryForEntityInjectable),
categoryRegistryRegistry: di.inject(catalogCategoryRegistryInjectable);
}), }),
}); });

View File

@ -13,7 +13,7 @@ interface Dependencies {
k8sRequest: K8sRequest; k8sRequest: K8sRequest;
} }
export type DetectorConstructor = new (cluster: Cluster) => BaseClusterDetector; export type DetectorConstructor = new (cluster: Cluster, k8sRequest: K8sRequest) => BaseClusterDetector;
export class DetectorRegistry { export class DetectorRegistry {
constructor(private dependencies: Dependencies) {} constructor(private dependencies: Dependencies) {}

View File

@ -5,7 +5,7 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { ClusterManager } from "./cluster-manager"; import { ClusterManager } from "./cluster-manager";
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable"; import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
import catalogEntityRegistryInjectable from "./catalog/catalog-entity-registry.injectable"; import catalogEntityRegistryInjectable from "./catalog/entity-registry.injectable";
const clusterManagerInjectable = getInjectable({ const clusterManagerInjectable = getInjectable({
id: "cluster-manager", id: "cluster-manager",

View File

@ -10,13 +10,13 @@ import type { Cluster } from "../common/cluster/cluster";
import logger from "./logger"; import logger from "./logger";
import { apiKubePrefix } from "../common/vars"; import { apiKubePrefix } from "../common/vars";
import { getClusterIdFromHost, isErrnoException } from "../common/utils"; import { getClusterIdFromHost, isErrnoException } from "../common/utils";
import type { catalogEntityRegistry } from "./catalog";
import type { KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster"; import type { KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster";
import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../common/catalog-entities/kubernetes-cluster"; import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../common/catalog-entities/kubernetes-cluster";
import { ipcMainOn } from "../common/ipc"; import { ipcMainOn } from "../common/ipc";
import { once } from "lodash"; import { once } from "lodash";
import type { ClusterStore } from "../common/cluster-store/cluster-store"; import type { ClusterStore } from "../common/cluster-store/cluster-store";
import type { ClusterId } from "../common/cluster-types"; import type { ClusterId } from "../common/cluster-types";
import type { CatalogEntityRegistry } from "./catalog";
const logPrefix = "[CLUSTER-MANAGER]:"; const logPrefix = "[CLUSTER-MANAGER]:";
@ -261,7 +261,7 @@ export class ClusterManager {
}); });
} }
getClusterForRequest(req: http.IncomingMessage): Cluster | undefined { getClusterForRequest = (req: http.IncomingMessage): Cluster | undefined => {
if (!req.headers.host) { if (!req.headers.host) {
return undefined; return undefined;
} }

View File

@ -19,7 +19,7 @@ const createContextHandlerInjectable = getInjectable({
const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable); const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable);
const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable); const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable);
return (cluster: Cluster): ClusterContextHandler | undefined => { return (cluster: Cluster): ClusterContextHandler => {
const clusterUrl = new URLParse(cluster.apiUrl); const clusterUrl = new URLParse(cluster.apiUrl);
const dependencies = { const dependencies = {

View File

@ -9,10 +9,11 @@ import loggerInjectable from "../../../../common/logger.injectable";
import clusterManagerInjectable from "../../../cluster-manager.injectable"; import clusterManagerInjectable from "../../../cluster-manager.injectable";
import applicationMenuItemsInjectable from "../../../menu/application-menu-items.injectable"; import applicationMenuItemsInjectable from "../../../menu/application-menu-items.injectable";
import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable"; import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable";
import catalogEntityRegistryInjectable from "../../../catalog/catalog-entity-registry.injectable";
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
import { onLoadOfApplicationInjectionToken } from "../../../start-main-application/runnable-tokens/on-load-of-application-injection-token"; import { onLoadOfApplicationInjectionToken } from "../../../start-main-application/runnable-tokens/on-load-of-application-injection-token";
import operatingSystemThemeInjectable from "../../../theme/operating-system-theme.injectable"; import operatingSystemThemeInjectable from "../../../theme/operating-system-theme.injectable";
import catalogEntityRegistryInjectable from "../../../catalog/entity-registry.injectable";
import askUserForFilePathsInjectable from "../../../ipc/ask-user-for-file-paths.injectable";
const setupIpcMainHandlersInjectable = getInjectable({ const setupIpcMainHandlersInjectable = getInjectable({
id: "setup-ipc-main-handlers", id: "setup-ipc-main-handlers",
@ -30,6 +31,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
const clusterStore = di.inject(clusterStoreInjectable); const clusterStore = di.inject(clusterStoreInjectable);
const operatingSystemTheme = di.inject(operatingSystemThemeInjectable); const operatingSystemTheme = di.inject(operatingSystemThemeInjectable);
const askUserForFilePaths = di.inject(askUserForFilePathsInjectable);
return { return {
run: () => { run: () => {
@ -43,6 +45,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
catalogEntityRegistry, catalogEntityRegistry,
clusterStore, clusterStore,
operatingSystemTheme, operatingSystemTheme,
askUserForFilePaths,
}); });
}, },
}; };

View File

@ -21,9 +21,9 @@ import type { MenuItemOpts } from "../../../menu/application-menu-items.injectab
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window"; import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window";
import { handleWindowAction, onLocationChange } from "../../../ipc/window"; import { handleWindowAction, onLocationChange } from "../../../ipc/window";
import { openFilePickingDialogChannel } from "../../../../common/ipc/dialog"; import { openFilePickingDialogChannel } from "../../../../common/ipc/dialog";
import { showOpenDialog } from "../../../ipc/dialog";
import { getNativeThemeChannel } from "../../../../common/ipc/native-theme"; import { getNativeThemeChannel } from "../../../../common/ipc/native-theme";
import type { Theme } from "../../../theme/operating-system-theme-state.injectable"; import type { Theme } from "../../../theme/operating-system-theme-state.injectable";
import type { AskUserForFilePaths } from "../../../ipc/ask-user-for-file-paths.injectable";
interface Dependencies { interface Dependencies {
directoryForLensLocalStorage: string; directoryForLensLocalStorage: string;
@ -33,9 +33,10 @@ interface Dependencies {
catalogEntityRegistry: CatalogEntityRegistry; catalogEntityRegistry: CatalogEntityRegistry;
clusterStore: ClusterStore; clusterStore: ClusterStore;
operatingSystemTheme: IComputedValue<Theme>; operatingSystemTheme: IComputedValue<Theme>;
askUserForFilePaths: AskUserForFilePaths;
} }
export const setupIpcMainHandlers = ({ applicationMenuItems, directoryForLensLocalStorage, getAbsolutePath, clusterManager, catalogEntityRegistry, clusterStore, operatingSystemTheme }: Dependencies) => { export const setupIpcMainHandlers = ({ applicationMenuItems, directoryForLensLocalStorage, getAbsolutePath, clusterManager, catalogEntityRegistry, clusterStore, operatingSystemTheme, askUserForFilePaths }: Dependencies) => {
ipcMainHandle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { ipcMainHandle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
return ClusterStore.getInstance() return ClusterStore.getInstance()
.getById(clusterId) .getById(clusterId)
@ -149,7 +150,7 @@ export const setupIpcMainHandlers = ({ applicationMenuItems, directoryForLensLoc
ipcMainOn(windowLocationChangedChannel, () => onLocationChange()); ipcMainOn(windowLocationChangedChannel, () => onLocationChange());
ipcMainHandle(openFilePickingDialogChannel, (event, opts) => showOpenDialog(opts)); ipcMainHandle(openFilePickingDialogChannel, (event, opts) => askUserForFilePaths(opts));
ipcMainHandle(broadcastMainChannel, (event, channel, ...args) => broadcastMessage(channel, ...args)); ipcMainHandle(broadcastMainChannel, (event, channel, ...args) => broadcastMessage(channel, ...args));

View File

@ -31,7 +31,6 @@ import joinPathsInjectable from "../common/path/join-paths.injectable";
import { joinPathsFake } from "../common/test-utils/join-paths-fake"; import { joinPathsFake } from "../common/test-utils/join-paths-fake";
import hotbarStoreInjectable from "../common/hotbars/store.injectable"; import hotbarStoreInjectable from "../common/hotbars/store.injectable";
import type { GetDiForUnitTestingOptions } from "../test-utils/get-dis-for-unit-testing"; import type { GetDiForUnitTestingOptions } from "../test-utils/get-dis-for-unit-testing";
import hotbarStoreInjectable from "../common/hotbar-store.injectable";
import isAutoUpdateEnabledInjectable from "./is-auto-update-enabled.injectable"; import isAutoUpdateEnabledInjectable from "./is-auto-update-enabled.injectable";
import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable"; import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable";
import { EventEmitter } from "../common/event-emitter"; import { EventEmitter } from "../common/event-emitter";
@ -41,8 +40,6 @@ import initializeExtensionsInjectable from "./start-main-application/runnables/i
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable"; import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
import registerFileProtocolInjectable from "./electron-app/features/register-file-protocol.injectable"; import registerFileProtocolInjectable from "./electron-app/features/register-file-protocol.injectable";
import environmentVariablesInjectable from "../common/utils/environment-variables.injectable"; import environmentVariablesInjectable from "../common/utils/environment-variables.injectable";
import { CatalogCategoryRegistry } from "../common/catalog";
import catalogCategoryRegistryInjectable from "../common/catalog/catalog-category-registry.injectable";
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable"; import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable"; import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable";
import setupRunnablesForAfterRootFrameIsReadyInjectable from "./start-main-application/runnables/setup-runnables-for-after-root-frame-is-ready.injectable"; import setupRunnablesForAfterRootFrameIsReadyInjectable from "./start-main-application/runnables/setup-runnables-for-after-root-frame-is-ready.injectable";
@ -125,8 +122,6 @@ export function getDiForUnitTesting(opts: GetDiForUnitTestingOptions = {}) {
di.override(trayInjectable, () => ({ start: () => {}, stop: () => {} })); di.override(trayInjectable, () => ({ start: () => {}, stop: () => {} }));
di.override(applicationMenuInjectable, () => ({ start: () => {}, stop: () => {} })); di.override(applicationMenuInjectable, () => ({ start: () => {}, stop: () => {} }));
di.override(catalogCategoryRegistryInjectable, () => new CatalogCategoryRegistry());
// TODO: Remove usages of globally exported appEventBus to get rid of this // TODO: Remove usages of globally exported appEventBus to get rid of this
di.override(appEventBusInjectable, () => new EventEmitter<[AppEvent]>()); di.override(appEventBusInjectable, () => new EventEmitter<[AppEvent]>());
@ -229,7 +224,7 @@ const overrideElectronFeatures = (di: DiContainer) => {
close: () => {}, close: () => {},
send: (arg) => { send: (arg) => {
const sendFake = di.inject(sendToChannelInElectronBrowserWindowInjectable); const sendFake = di.inject(sendToChannelInElectronBrowserWindowInjectable) as any;
sendFake(null, arg); sendFake(null, arg);
}, },

View File

@ -12,10 +12,14 @@ import logger from "../logger";
import { execHelm } from "./exec"; import { execHelm } from "./exec";
import type { HelmEnv, HelmRepo, HelmRepoConfig } from "./helm-repo-manager"; import type { HelmEnv, HelmRepo, HelmRepoConfig } from "./helm-repo-manager";
class HelmRepoManager { interface EnsuredHelmRepoManagerData {
protected repos: HelmRepo[]; helmEnv: HelmEnv;
protected helmEnv: HelmEnv; didUpdateOnce: boolean;
protected didUpdateOnce: boolean; }
export class HelmRepoManager {
protected helmEnv?: HelmEnv;
protected didUpdateOnce?: boolean;
public async loadAvailableRepos(): Promise<HelmRepo[]> { public async loadAvailableRepos(): Promise<HelmRepo[]> {
const res = await customRequestPromise({ const res = await customRequestPromise({
@ -25,13 +29,13 @@ class HelmRepoManager {
timeout: 10000, timeout: 10000,
}); });
return orderBy(res.body as HelmRepo[], (repo) => repo.name); return orderBy(res.body as HelmRepo[], repo => repo.name);
} }
private async ensureInitialized() { private async ensureInitialized(): Promise<EnsuredHelmRepoManagerData> {
this.helmEnv ??= await this.parseHelmEnv(); this.helmEnv ??= await this.parseHelmEnv();
const repos = await this.list(); const repos = await this.list(this.helmEnv);
if (repos.length === 0) { if (repos.length === 0) {
await this.addRepo({ await this.addRepo({
@ -44,12 +48,17 @@ class HelmRepoManager {
await this.update(); await this.update();
this.didUpdateOnce = true; this.didUpdateOnce = true;
} }
return {
didUpdateOnce: this.didUpdateOnce,
helmEnv: this.helmEnv,
};
} }
protected async parseHelmEnv() { protected async parseHelmEnv() {
const output = await execHelm(["env"]); const output = await execHelm(["env"]);
const lines = output.split(/\r?\n/); // split by new line feed const lines = output.split(/\r?\n/); // split by new line feed
const env: HelmEnv = {}; const env: Partial<Record<string, string>> = {};
lines.forEach((line: string) => { lines.forEach((line: string) => {
const [key, value] = line.split("="); const [key, value] = line.split("=");
@ -59,21 +68,18 @@ class HelmRepoManager {
} }
}); });
return env; return env as HelmEnv;
} }
public async repo(name: string): Promise<HelmRepo> { public async repo(name: string): Promise<HelmRepo | undefined> {
const repos = await this.repositories(); const repos = await this.repositories();
return repos.find((repo) => repo.name === name); return repos.find(repo => repo.name === name);
} }
private async list(): Promise<HelmRepo[]> { private async list(helmEnv: HelmEnv): Promise<HelmRepo[]> {
try { try {
const rawConfig = await readFile( const rawConfig = await readFile(helmEnv.HELM_REPOSITORY_CONFIG, "utf8");
this.helmEnv.HELM_REPOSITORY_CONFIG,
"utf8",
);
const parsedConfig = yaml.load(rawConfig) as HelmRepoConfig; const parsedConfig = yaml.load(rawConfig) as HelmRepoConfig;
if (typeof parsedConfig === "object" && parsedConfig) { if (typeof parsedConfig === "object" && parsedConfig) {
@ -88,13 +94,13 @@ class HelmRepoManager {
public async repositories(): Promise<HelmRepo[]> { public async repositories(): Promise<HelmRepo[]> {
try { try {
await this.ensureInitialized(); const { helmEnv } = await this.ensureInitialized();
const repos = await this.list(); const repos = await this.list(helmEnv);
return repos.map((repo) => ({ return repos.map(repo => ({
...repo, ...repo,
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`, cacheFilePath: `${helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`,
})); }));
} catch (error) { } catch (error) {
logger.error(`[HELM]: repositories listing error`, error); logger.error(`[HELM]: repositories listing error`, error);
@ -104,21 +110,20 @@ class HelmRepoManager {
} }
public async update() { public async update() {
return execHelm(["repo", "update"]); return execHelm([
"repo",
"update",
]);
} }
public async addRepo({ public async addRepo({ name, url, insecureSkipTlsVerify, username, password, caFile, keyFile, certFile }: HelmRepo) {
logger.info(`[HELM]: adding repo ${name} from ${url}`);
const args = [
"repo",
"add",
name, name,
url, url,
insecureSkipTlsVerify, ];
username,
password,
caFile,
keyFile,
certFile,
}: HelmRepo) {
logger.info(`[HELM]: adding repo ${name} from ${url}`);
const args = ["repo", "add", name, url];
if (insecureSkipTlsVerify) { if (insecureSkipTlsVerify) {
args.push("--insecure-skip-tls-verify"); args.push("--insecure-skip-tls-verify");
@ -150,7 +155,11 @@ class HelmRepoManager {
public async removeRepo({ name, url }: HelmRepo): Promise<string> { public async removeRepo({ name, url }: HelmRepo): Promise<string> {
logger.info(`[HELM]: removing repo ${name} (${url})`); logger.info(`[HELM]: removing repo ${name} (${url})`);
return execHelm(["repo", "remove", name]); return execHelm([
"repo",
"remove",
name,
]);
} }
} }

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { OpenDialogOptions } from "electron";
import { dialog } from "electron";
import { getInjectable } from "@ogre-tools/injectable";
import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable";
// TODO: Replace leaking electron with abstraction
export type AskUserForFilePaths = (
dialogOptions: OpenDialogOptions
) => Promise<{ canceled: boolean; filePaths: string[] }>;
const askUserForFilePathsInjectable = getInjectable({
id: "ask-user-for-file-paths",
instantiate: (di): AskUserForFilePaths => {
const showApplicationWindow = di.inject(showApplicationWindowInjectable);
return async (dialogOptions) => {
await showApplicationWindow();
const { canceled, filePaths } = await dialog.showOpenDialog(
dialogOptions,
);
return { canceled, filePaths };
};
},
causesSideEffects: true,
});
export default askUserForFilePathsInjectable;

View File

@ -1,15 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { OpenDialogOptions } from "electron";
import { dialog } from "electron";
import { WindowManager } from "../window-manager";
export async function showOpenDialog(dialogOptions: OpenDialogOptions): Promise<{ canceled: boolean; filePaths: string[] }> {
const window = await WindowManager.getInstance().ensureMainWindow();
const { canceled, filePaths } = await dialog.showOpenDialog(window, dialogOptions);
return { canceled, filePaths };
}

View File

@ -14,7 +14,7 @@ export interface KubeConfigManagerInstantiationParameter {
cluster: Cluster; cluster: Cluster;
} }
export type CreateKubeconfigManager = (cluster: Cluster) => KubeconfigManager | undefined; export type CreateKubeconfigManager = (cluster: Cluster) => KubeconfigManager;
const createKubeconfigManagerInjectable = getInjectable({ const createKubeconfigManagerInjectable = getInjectable({
id: "create-kubeconfig-manager", id: "create-kubeconfig-manager",

View File

@ -7,7 +7,7 @@ import net from "net";
import type http from "http"; import type http from "http";
import spdy from "spdy"; import spdy from "spdy";
import type httpProxy from "http-proxy"; import type httpProxy from "http-proxy";
import { apiPrefix, apiKubePrefix } from "../common/vars"; import { apiPrefix, apiKubePrefix } from "../../common/vars";
import type { Router } from "../router/router"; import type { Router } from "../router/router";
import type { ClusterContextHandler } from "../context-handler/context-handler"; import type { ClusterContextHandler } from "../context-handler/context-handler";
import logger from "../logger"; import logger from "../logger";
@ -59,12 +59,9 @@ const disallowedPorts = new Set([
]); ]);
export class LensProxy { export class LensProxy {
protected origin: string;
protected proxyServer: http.Server; protected proxyServer: http.Server;
protected closed = false; protected closed = false;
protected retryCounters = new Map<string, number>(); protected retryCounters = new Map<string, number>();
protected getClusterForRequest: GetClusterForRequest;
constructor(private dependencies: Dependencies) { constructor(private dependencies: Dependencies) {
this.configureProxy(dependencies.proxy); this.configureProxy(dependencies.proxy);

View File

@ -15,10 +15,12 @@ import parseRequestInjectable from "./parse-request.injectable";
import { contentTypes } from "./router-content-types"; import { contentTypes } from "./router-content-types";
import mockFs from "mock-fs"; import mockFs from "mock-fs";
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import type { Route } from "./route";
import type { SetRequired } from "type-fest";
describe("router", () => { describe("router", () => {
let router: Router; let router: Router;
let routeHandlerMock: AsyncFnMock<RouteHandler<any, string>>; let routeHandlerMock: AsyncFnMock<() => any>;
beforeEach(async () => { beforeEach(async () => {
routeHandlerMock = asyncFn(); routeHandlerMock = asyncFn();

View File

@ -8,8 +8,8 @@ import type http from "http";
import { toPairs } from "lodash/fp"; import { toPairs } from "lodash/fp";
import type { Cluster } from "../../common/cluster/cluster"; import type { Cluster } from "../../common/cluster/cluster";
import { contentTypes } from "./router-content-types"; import { contentTypes } from "./router-content-types";
import type { ServerIncomingMessage } from "../lens-proxy";
import type { LensApiRequest, LensApiResult, Route } from "./route"; import type { LensApiRequest, LensApiResult, Route } from "./route";
import type { ServerIncomingMessage } from "../lens-proxy/lens-proxy";
export interface RouterRequestOpts { export interface RouterRequestOpts {
req: http.IncomingMessage; req: http.IncomingMessage;

View File

@ -5,14 +5,13 @@
import { apiPrefix } from "../../../common/vars"; import { apiPrefix } from "../../../common/vars";
import { getRouteInjectable } from "../../router/router.injectable"; import { getRouteInjectable } from "../../router/router.injectable";
import { PrometheusProviderRegistry } from "../../prometheus";
import { route } from "../../router/route"; import { route } from "../../router/route";
import prometheusProviderRegistryInjectable from "../../prometheus/prometheus-provider-registry.injectable"; import prometheusProviderRegistryInjectable from "../../prometheus/prometheus-provider-registry.injectable";
const getMetricProvidersRouteInjectable = getRouteInjectable({ const getMetricProvidersRouteInjectable = getRouteInjectable({
id: "get-metric-providers-route", id: "get-metric-providers-route",
instantiate: () => { instantiate: (di) => {
const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable); const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable);
return route({ return route({
@ -26,7 +25,7 @@ const getMetricProvidersRouteInjectable = getRouteInjectable({
({ name, id, isConfigurable }) => ({ name, id, isConfigurable }), ({ name, id, isConfigurable }) => ({ name, id, isConfigurable }),
), ),
})); }));
} },
}); });
export default getMetricProvidersRouteInjectable; export default getMetricProvidersRouteInjectable;

View File

@ -6,7 +6,7 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable"; import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable";
import { terminalShellEnvModify } from "./terminal-shell-env-modifiers"; import { terminalShellEnvModify } from "./terminal-shell-env-modifiers";
import catalogEntityRegistryInjectable from "../../catalog/catalog-entity-registry.injectable"; import catalogEntityRegistryInjectable from "../../catalog/entity-registry.injectable";
const terminalShellEnvModifyInjectable = getInjectable({ const terminalShellEnvModifyInjectable = getInjectable({
id: "terminal-shell-env-modify", id: "terminal-shell-env-modify",

View File

@ -34,7 +34,7 @@ const createLensWindowInjectable = getInjectable({
instantiate: instantiate:
(di) => (di) =>
(configuration: LensWindowConfiguration) => { (configuration: LensWindowConfiguration) => {
let browserWindow: LensWindow = null; let browserWindow: LensWindow | undefined;
const createElectronWindow = di.inject(createElectronWindowForInjectable)( const createElectronWindow = di.inject(createElectronWindowForInjectable)(
{ {
@ -52,14 +52,14 @@ const createLensWindowInjectable = getInjectable({
beforeOpen: configuration.beforeOpen, beforeOpen: configuration.beforeOpen,
onClose: () => { onClose: () => {
browserWindow = null; browserWindow = undefined;
}, },
}, },
); );
return { return {
get visible() { get visible() {
return !!this.browserWindow; return !!browserWindow;
}, },
show: async () => { show: async () => {
@ -72,7 +72,7 @@ const createLensWindowInjectable = getInjectable({
close: () => { close: () => {
browserWindow?.close(); browserWindow?.close();
browserWindow = null; browserWindow = undefined;
}, },
send: async (args: SendToViewArgs) => { send: async (args: SendToViewArgs) => {

View File

@ -44,7 +44,7 @@ const initializeExtensionsInjectable = getInjectable({
}); });
extensionLoader.initExtensions(extensions); extensionLoader.initExtensions(extensions);
} catch (error) { } catch (error: any) {
showErrorPopup( showErrorPopup(
"Lens Error", "Lens Error",
`Could not load extensions${ `Could not load extensions${

View File

@ -5,8 +5,8 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { afterRootFrameIsReadyInjectionToken } from "../../runnable-tokens/after-root-frame-is-ready-injection-token"; import { afterRootFrameIsReadyInjectionToken } from "../../runnable-tokens/after-root-frame-is-ready-injection-token";
import directoryForKubeConfigsInjectable from "../../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; import directoryForKubeConfigsInjectable from "../../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync-manager/kubeconfig-sync-manager.injectable";
import ensureDirInjectable from "../../../../common/fs/ensure-dir.injectable"; import ensureDirInjectable from "../../../../common/fs/ensure-dir.injectable";
import kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync/manager.injectable";
const startKubeConfigSyncInjectable = getInjectable({ const startKubeConfigSyncInjectable = getInjectable({
id: "start-kubeconfig-sync", id: "start-kubeconfig-sync",

View File

@ -3,8 +3,8 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync-manager/kubeconfig-sync-manager.injectable";
import { beforeQuitOfFrontEndInjectionToken } from "../../runnable-tokens/before-quit-of-front-end-injection-token"; import { beforeQuitOfFrontEndInjectionToken } from "../../runnable-tokens/before-quit-of-front-end-injection-token";
import kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync/manager.injectable";
const stopKubeConfigSyncInjectable = getInjectable({ const stopKubeConfigSyncInjectable = getInjectable({
id: "stop-kube-config-sync", id: "stop-kube-config-sync",

View File

@ -3,9 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import hotbarStoreInjectable from "../../../common/hotbar-store.injectable";
import setupSyncingOfGeneralCatalogEntitiesInjectable from "./setup-syncing-of-general-catalog-entities.injectable"; import setupSyncingOfGeneralCatalogEntitiesInjectable from "./setup-syncing-of-general-catalog-entities.injectable";
import { onLoadOfApplicationInjectionToken } from "../runnable-tokens/on-load-of-application-injection-token"; import { onLoadOfApplicationInjectionToken } from "../runnable-tokens/on-load-of-application-injection-token";
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
const setupHotbarStoreInjectable = getInjectable({ const setupHotbarStoreInjectable = getInjectable({
id: "setup-hotbar-store", id: "setup-hotbar-store",

View File

@ -28,7 +28,7 @@ const setupLensProxyInjectable = getInjectable({
try { try {
logger.info("🔌 Starting LensProxy"); logger.info("🔌 Starting LensProxy");
await lensProxy.listen(); // lensProxy.port available await lensProxy.listen(); // lensProxy.port available
} catch (error) { } catch (error: any) {
showErrorPopup("Lens Error", `Could not start proxy: ${error?.message || "unknown error"}`); showErrorPopup("Lens Error", `Could not start proxy: ${error?.message || "unknown error"}`);
return exitApp(); return exitApp();

View File

@ -5,13 +5,19 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { apiBase } from "../../common/k8s-api"; import { apiBase } from "../../common/k8s-api";
import { onApiError } from "./on-api-error"; import { onApiError } from "./on-api-error";
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
const setupOnApiErrorListenersInjectable = getInjectable({ const setupOnApiErrorListenersInjectable = getInjectable({
id: "setup-on-api-error-listeners", id: "setup-on-api-error-listeners",
setup: () => {
instantiate: () => ({
run: () => {
apiBase?.onError.addListener(onApiError); apiBase?.onError.addListener(onApiError);
}, },
instantiate: () => undefined, }),
injectionToken: beforeFrameStartsInjectionToken,
causesSideEffects: true,
}); });
export default setupOnApiErrorListenersInjectable; export default setupOnApiErrorListenersInjectable;

View File

@ -105,7 +105,7 @@ class NonInjectedReleaseDetails extends Component<ReleaseDetailsProps & Dependen
upgradeVersion = (release: HelmRelease) => { upgradeVersion = (release: HelmRelease) => {
const { hideDetails, createUpgradeChartTab } = this.props; const { hideDetails, createUpgradeChartTab } = this.props;
this.props.createUpgradeChartTab(this.release); createUpgradeChartTab(release);
hideDetails(); hideDetails();
}; };

View File

@ -3,11 +3,11 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { ClusterFrameHandler } from "./lens-views"; import { ClusterFrameHandler } from "./cluster-frame-handler";
const clusterFramesInjectable = getInjectable({ const clusterFrameHandlerInjectable = getInjectable({
id: "cluster-frames", id: "cluster-frame-handler",
instantiate: () => new ClusterFrameHandler(), instantiate: () => new ClusterFrameHandler(),
}); });
export default clusterFramesInjectable; export default clusterFrameHandlerInjectable;

View File

@ -9,7 +9,7 @@ import type { IComputedValue } from "mobx";
import { computed, makeObservable, reaction } from "mobx"; import { computed, makeObservable, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react"; import { disposeOnUnmount, observer } from "mobx-react";
import { ClusterStatus } from "./cluster-status"; import { ClusterStatus } from "./cluster-status";
import type { ClusterFrameHandler } from "./lens-views"; import type { ClusterFrameHandler } from "./cluster-frame-handler";
import type { Cluster } from "../../../common/cluster/cluster"; import type { Cluster } from "../../../common/cluster/cluster";
import { ClusterStore } from "../../../common/cluster-store/cluster-store"; import { ClusterStore } from "../../../common/cluster-store/cluster-store";
import { requestClusterActivation } from "../../ipc"; import { requestClusterActivation } from "../../ipc";
@ -17,7 +17,7 @@ import { withInjectables } from "@ogre-tools/injectable-react";
import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
import clusterViewRouteParametersInjectable from "./cluster-view-route-parameters.injectable"; import clusterViewRouteParametersInjectable from "./cluster-view-route-parameters.injectable";
import clusterFramesInjectable from "./lens-views.injectable"; import clusterFrameHandlerInjectable from "./cluster-frame-handler.injectable";
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry"; import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
@ -107,7 +107,7 @@ export const ClusterView = withInjectables<Dependencies>(NonInjectedClusterView,
getProps: (di) => ({ getProps: (di) => ({
clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId, clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId,
navigateToCatalog: di.inject(navigateToCatalogInjectable), navigateToCatalog: di.inject(navigateToCatalogInjectable),
clusterFrames: di.inject(clusterFramesInjectable), clusterFrames: di.inject(clusterFrameHandlerInjectable),
entityRegistry: di.inject(catalogEntityRegistryInjectable), entityRegistry: di.inject(catalogEntityRegistryInjectable),
}), }),
}); });

View File

@ -4,28 +4,20 @@
*/ */
import "@testing-library/jest-dom/extend-expect"; import "@testing-library/jest-dom/extend-expect";
import { KubeConfig } from "@kubernetes/client-node"; import { KubeConfig } from "@kubernetes/client-node";
import { fireEvent, screen } from "@testing-library/react";
import type { RenderResult } from "@testing-library/react";
import { fireEvent } from "@testing-library/react"; import { fireEvent } from "@testing-library/react";
import type { RenderResult } from "@testing-library/react";
import mockFs from "mock-fs"; import mockFs from "mock-fs";
import React from "react"; import React from "react";
import * as selectEvent from "react-select-event"; import * as selectEvent from "react-select-event";
import type { Cluster } from "../../../../common/cluster/cluster"; import type { Cluster } from "../../../../common/cluster/cluster";
import { DeleteClusterDialog } from "../view"; import { DeleteClusterDialog } from "../view";
import { DeleteClusterDialog } from "../delete-cluster-dialog";
import type { ClusterModel } from "../../../../common/cluster-types"; import type { ClusterModel } from "../../../../common/cluster-types";
import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token";
import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable"; import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable";
import type { DiRender } from "../../test-utils/renderFor";
import { renderFor } from "../../test-utils/renderFor";
import type { OpenDeleteClusterDialog } from "../open.injectable"; import type { OpenDeleteClusterDialog } from "../open.injectable";
import openDeleteClusterDialogInjectable from "../open.injectable"; import openDeleteClusterDialogInjectable from "../open.injectable";
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable"; import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable";
import ipcRendererInjectable from "../../../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
import deleteClusterDialogModelInjectable from "../delete-cluster-dialog-model/delete-cluster-dialog-model.injectable";
import type { DeleteClusterDialogModel } from "../delete-cluster-dialog-model/delete-cluster-dialog-model";
import hotbarStoreInjectable from "../../../../common/hotbar-store.injectable";
import type { ApplicationBuilder } from "../../test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../test-utils/get-application-builder";
import { getApplicationBuilder } from "../../test-utils/get-application-builder"; import { getApplicationBuilder } from "../../test-utils/get-application-builder";
import { routeInjectionToken } from "../../../../common/front-end-routing/route-injection-token"; import { routeInjectionToken } from "../../../../common/front-end-routing/route-injection-token";
@ -33,6 +25,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx"; import { computed } from "mobx";
import { routeSpecificComponentInjectionToken } from "../../../routes/route-specific-component-injection-token"; import { routeSpecificComponentInjectionToken } from "../../../routes/route-specific-component-injection-token";
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
jest.mock("electron", () => ({ jest.mock("electron", () => ({
app: { app: {
@ -50,33 +43,29 @@ jest.mock("electron", () => ({
}, },
})); }));
const kubeconfig = ` const multiClusterConfig = `
apiVersion: v1 apiVersion: v1
clusters: clusters:
- cluster: - cluster:
server: https://localhost server: https://localhost
name: test name: some-current-context-cluster
- cluster: - cluster:
server: http://localhost server: http://localhost
name: other-cluster name: some-non-current-context-cluster
contexts: contexts:
- context: - context:
cluster: test cluster: some-current-context-cluster
user: test user: some-user
name: test name: some-current-context
- context: - context:
cluster: test cluster: some-non-current-context-cluster
user: test user: some-user
name: test2 name: some-non-current-context
- context: current-context: some-current-context
cluster: other-cluster
user: test
name: other-context
current-context: other-context
kind: Config kind: Config
preferences: {} preferences: {}
users: users:
- name: test - name: some-user
user: user:
token: kubeconfig-user-q4lm4:xxxyyyy token: kubeconfig-user-q4lm4:xxxyyyy
`; `;
@ -86,17 +75,17 @@ apiVersion: v1
clusters: clusters:
- cluster: - cluster:
server: http://localhost server: http://localhost
name: other-cluster name: some-cluster
contexts: contexts:
- context: - context:
cluster: other-cluster cluster: some-cluster
user: test user: some-user
name: other-context name: some-context
current-context: other-context current-context: some-context
kind: Config kind: Config
preferences: {} preferences: {}
users: users:
- name: test - name: some-user
user: user:
token: kubeconfig-user-q4lm4:xxxyyyy token: kubeconfig-user-q4lm4:xxxyyyy
`; `;
@ -107,45 +96,21 @@ describe("<DeleteClusterDialog />", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
let createCluster: (model: ClusterModel) => Cluster; let createCluster: (model: ClusterModel) => Cluster;
let openDeleteClusterDialog: OpenDeleteClusterDialog; let openDeleteClusterDialog: OpenDeleteClusterDialog;
let render: DiRender;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
mainDi.override(createContextHandlerInjectable, () => () => undefined); mainDi.override(createContextHandlerInjectable, () => () => undefined as any);
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined); mainDi.override(createKubeconfigManagerInjectable, () => () => undefined as any);
rendererDi.override(hotbarStoreInjectable, () => ({})); rendererDi.override(hotbarStoreInjectable, () => ({}));
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true); rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
rendererDi.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
const testRouteInjectable = getInjectable({
id: "some-test-route",
instantiate: () => ({
path: "/some-test-path",
clusterFrame: false,
isEnabled: computed(() => true),
}),
injectionToken: routeInjectionToken,
}); });
const testRouteComponent = getInjectable({ const { rendererDi } = applicationBuilder.dis;
id: "some-test-component",
instantiate: (di) => ({ rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
route: di.inject(testRouteInjectable),
Component: () => <DeleteClusterDialog />,
}),
injectionToken: routeSpecificComponentInjectionToken,
});
});
applicationBuilder.beforeRender(({ rendererDi }) => { applicationBuilder.beforeRender(({ rendererDi }) => {
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
@ -154,70 +119,100 @@ describe("<DeleteClusterDialog />", () => {
navigateToRoute(testRoute); navigateToRoute(testRoute);
}); });
rendererDi.register(testRouteInjectable, testRouteComponent);
mockFs(); mockFs();
applicationBuilder.beforeRender(({ rendererDi }) => {
openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable); openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable);
createCluster = mainDi.inject(createClusterInjectionToken); createCluster = rendererDi.inject(createClusterInjectionToken);
});
}); });
afterEach(() => { afterEach(() => {
mockFs.restore(); mockFs.restore();
}); });
describe("Kubeconfig with different clusters", () => { it("shows context switcher when deleting current cluster", async () => {
let rendered: RenderResult;
let createCluster: (model: ClusterModel) => Cluster;
let deleteClusterDialogModel: DeleteClusterDialogModel;
beforeEach(async () => {
const mockOpts = { const mockOpts = {
"temp-kube-config": kubeconfig, "temp-kube-config": multiClusterConfig,
}; };
mockFs(mockOpts); mockFs(mockOpts);
config = new KubeConfig(); config = new KubeConfig();
config.loadFromString(kubeconfig); config.loadFromString(multiClusterConfig);
rendered = await applicationBuilder.render(); applicationBuilder.beforeRender(({ rendererDi }) => {
const createCluster = rendererDi.inject(createClusterInjectionToken);
deleteClusterDialogModel = applicationBuilder.dis.rendererDi.inject(deleteClusterDialogModelInjectable); const cluster = createCluster({
createCluster = applicationBuilder.dis.mainDi.inject(createClusterInjectionToken); id: "some-current-context-cluster",
contextName: "some-current-context",
preferences: {
clusterName: "some-current-context-cluster",
},
kubeConfigPath: "./temp-kube-config",
}); });
afterEach(() => { openDeleteClusterDialog({ cluster, config });
mockFs.restore(); });
const rendered = await applicationBuilder.render();
const { getByText } = rendered;
const menu = getByText("Select new context...");
expect(menu).toBeInTheDocument();
selectEvent.openMenu(menu);
expect(getByText("some-current-context")).toBeInTheDocument();
expect(getByText("some-non-current-context")).toBeInTheDocument();
});
describe("Kubeconfig with different clusters", () => {
let rendered: RenderResult;
beforeEach(async () => {
const mockOpts = {
"temp-kube-config": multiClusterConfig,
};
mockFs(mockOpts);
config = new KubeConfig();
config.loadFromString(multiClusterConfig);
rendered = await applicationBuilder.render();
}); });
it("renders w/o errors", () => { it("renders w/o errors", () => {
expect(rendered.container).toBeInstanceOf(HTMLElement); expect(rendered.container).toBeInstanceOf(HTMLElement);
}); });
it("shows warning when deleting non-current-context cluster", async () => { it("shows warning when deleting non-current-context cluster", () => {
const cluster = createCluster({ const cluster = createCluster({
id: "test", id: "some-non-current-context-cluster",
contextName: "test", contextName: "some-non-current-context",
preferences: { preferences: {
clusterName: "minikube", clusterName: "minikube",
}, },
kubeConfigPath: "./temp-kube-config", kubeConfigPath: "./temp-kube-config",
}); });
deleteClusterDialogModel.open({ cluster, config }); openDeleteClusterDialog({ cluster, config });
const message = "The contents of kubeconfig file will be changed!"; const message = "The contents of kubeconfig file will be changed!";
expect(rendered.getByText(message)).toBeInstanceOf(HTMLElement); expect(rendered.getByText(message)).toBeInstanceOf(HTMLElement);
}); });
it("shows warning when deleting current-context cluster", async () => { it("shows warning when deleting current-context cluster", () => {
const cluster = createCluster({ const cluster = createCluster({
id: "other-cluster", id: "some-current-context-cluster",
contextName: "other-context", contextName: "some-current-context",
preferences: { preferences: {
clusterName: "other-cluster", clusterName: "some-current-context-cluster",
}, },
kubeConfigPath: "./temp-kube-config", kubeConfigPath: "./temp-kube-config",
}); });
@ -227,42 +222,17 @@ describe("<DeleteClusterDialog />", () => {
expect(rendered.getByTestId("current-context-warning")).toBeInstanceOf(HTMLElement); expect(rendered.getByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
}); });
it("shows context switcher when deleting current cluster", async () => { it("shows context switcher after checkbox click", () => {
const cluster = createCluster({ const cluster = createCluster({
id: "other-cluster", id: "some-current-context-cluster",
contextName: "other-context", contextName: "some-current-context",
preferences: { preferences: {
clusterName: "other-cluster", clusterName: "some-current-context-cluster",
}, },
kubeConfigPath: "./temp-kube-config", kubeConfigPath: "./temp-kube-config",
}); });
openDeleteClusterDialog({ cluster, config }); openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByText } = rendered;
const menu = getByText("Select new context...");
expect(menu).toBeInTheDocument();
selectEvent.openMenu(menu);
expect(getByText("test")).toBeInTheDocument();
expect(getByText("test2")).toBeInTheDocument();
});
it("shows context switcher after checkbox click", async () => {
const cluster = createCluster({
id: "some-cluster",
contextName: "test",
preferences: {
clusterName: "test",
},
kubeConfigPath: "./temp-kube-config",
});
openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByText, getByTestId } = rendered; const { getByText, getByTestId } = rendered;
const link = getByTestId("context-switch"); const link = getByTestId("context-switch");
@ -270,28 +240,30 @@ describe("<DeleteClusterDialog />", () => {
expect(link).toBeInstanceOf(HTMLElement); expect(link).toBeInstanceOf(HTMLElement);
fireEvent.click(link); fireEvent.click(link);
const menu = await screen.findByText("Select new context..."); const menu = getByText("Select new context...");
expect(menu).toBeInTheDocument(); expect(menu).toBeInTheDocument();
selectEvent.openMenu(menu); selectEvent.openMenu(menu);
expect(await screen.findByText("test")).toBeInTheDocument(); expect(getByText("some-current-context")).toBeInTheDocument();
expect(await screen.findByText("test2")).toBeInTheDocument(); expect(getByText("some-non-current-context")).toBeInTheDocument();
}); });
it("shows warning for internal kubeconfig cluster", async () => { it("given cluster in internal kubeconfig, when deleting cluster outside of current context, shows warning for internal kubeconfig cluster", () => {
const cluster = createCluster({ const cluster = createCluster({
id: "some-cluster", id: "some-non-current-context-cluster",
contextName: "test", contextName: "some-non-current-context",
preferences: { preferences: {
clusterName: "test", clusterName: "some-non-current-context-cluster",
}, },
kubeConfigPath: "./temp-kube-config", kubeConfigPath: "./temp-kube-config",
}); });
const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true); const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true);
deleteClusterDialogModel.open({ cluster, config }); openDeleteClusterDialog({ cluster, config });
expect(rendered.getByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement); expect(rendered.getByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
@ -301,8 +273,6 @@ describe("<DeleteClusterDialog />", () => {
describe("Kubeconfig with single cluster", () => { describe("Kubeconfig with single cluster", () => {
let rendered: RenderResult; let rendered: RenderResult;
let createCluster: (model: ClusterModel) => Cluster;
let deleteClusterDialogModel: DeleteClusterDialogModel;
beforeEach(async () => { beforeEach(async () => {
const mockOpts = { const mockOpts = {
@ -315,28 +285,44 @@ describe("<DeleteClusterDialog />", () => {
config.loadFromString(singleClusterConfig); config.loadFromString(singleClusterConfig);
rendered = await applicationBuilder.render(); rendered = await applicationBuilder.render();
deleteClusterDialogModel = applicationBuilder.dis.rendererDi.inject(deleteClusterDialogModelInjectable);
createCluster = applicationBuilder.dis.mainDi.inject(createClusterInjectionToken);
}); });
afterEach(() => { it("shows warning if no other contexts left", () => {
mockFs.restore();
});
it("shows warning if no other contexts left", async () => {
const cluster = createCluster({ const cluster = createCluster({
id: "other-cluster", id: "some-cluster",
contextName: "other-context", contextName: "some-context",
preferences: { preferences: {
clusterName: "other-cluster", clusterName: "some-cluster",
}, },
kubeConfigPath: "./temp-kube-config", kubeConfigPath: "./temp-kube-config",
}); });
deleteClusterDialogModel.open({ cluster, config }); openDeleteClusterDialog({ cluster, config });
expect(rendered.getByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement); expect(rendered.getByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
}); });
}); });
}); });
const testRouteInjectable = getInjectable({
id: "some-test-route",
instantiate: () => ({
path: "/some-test-path",
clusterFrame: false,
isEnabled: computed(() => true),
}),
injectionToken: routeInjectionToken,
});
const testRouteComponentInjectable = getInjectable({
id: "some-test-component",
instantiate: (di) => ({
route: di.inject(testRouteInjectable),
Component: () => <DeleteClusterDialog />,
}),
injectionToken: routeSpecificComponentInjectionToken,
});

View File

@ -50,6 +50,7 @@ class NonInjectedMenuActions extends React.Component<MenuActionsProps & Dependen
removeConfirmationMessage: "Remove item?", removeConfirmationMessage: "Remove item?",
}; };
// TODO: Make deterministic
public id = uniqueId("menu_actions_"); public id = uniqueId("menu_actions_");
@observable isOpen = !!this.props.toolbar; @observable isOpen = !!this.props.toolbar;

View File

@ -9,7 +9,6 @@ import { extensionRegistratorInjectionToken } from "../../../extensions/extensio
import type { IObservableArray } from "mobx"; import type { IObservableArray } from "mobx";
import { computed, observable, runInAction } from "mobx"; import { computed, observable, runInAction } from "mobx";
import { renderFor } from "./renderFor"; import { renderFor } from "./renderFor";
import observableHistoryInjectable from "../../navigation/observable-history.injectable";
import React from "react"; import React from "react";
import { Router } from "react-router-dom"; import { Router } from "react-router-dom";
import { Observer } from "mobx-react"; import { Observer } from "mobx-react";
@ -37,13 +36,14 @@ import navigateToHelmChartsInjectable from "../../../common/front-end-routing/ro
import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable"; import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable";
import { ClusterFrameContext } from "../../cluster-frame-context/cluster-frame-context"; import { ClusterFrameContext } from "../../cluster-frame-context/cluster-frame-context";
import type { Cluster } from "../../../common/cluster/cluster"; import type { Cluster } from "../../../common/cluster/cluster";
import type { NamespaceStore } from "../+namespaces/namespace-store/namespace.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import namespaceStoreInjectable from "../+namespaces/namespace-store/namespace-store.injectable";
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable"; import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable";
import startMainApplicationInjectable from "../../../main/start-main-application/start-main-application.injectable"; import startMainApplicationInjectable from "../../../main/start-main-application/start-main-application.injectable";
import startFrameInjectable from "../../start-frame/start-frame.injectable"; import startFrameInjectable from "../../start-frame/start-frame.injectable";
import { flushPromises } from "../../../common/test-utils/flush-promises"; import { flushPromises } from "../../../common/test-utils/flush-promises";
import type { NamespaceStore } from "../+namespaces/store";
import namespaceStoreInjectable from "../+namespaces/store.injectable";
import historyInjectable from "../../navigation/history.injectable";
type Callback = (dis: DiContainers) => void | Promise<void>; type Callback = (dis: DiContainers) => void | Promise<void>;
@ -235,9 +235,11 @@ export const getApplicationBuilder = () => {
const clusterStub = { const clusterStub = {
accessibleNamespaces: [], accessibleNamespaces: [],
} as Cluster; } as unknown as Cluster;
const namespaceStoreStub = {} as NamespaceStore; const namespaceStoreStub = {
contextNamespaces: [],
} as unknown as NamespaceStore;
const clusterFrameContextFake = new ClusterFrameContext( const clusterFrameContextFake = new ClusterFrameContext(
clusterStub, clusterStub,
@ -321,7 +323,7 @@ export const getApplicationBuilder = () => {
await startFrame(); await startFrame();
const render = renderFor(rendererDi); const render = renderFor(rendererDi);
const history = rendererDi.inject(observableHistoryInjectable); const history = rendererDi.inject(historyInjectable) as any;
const currentRouteComponent = rendererDi.inject(currentRouteComponentInjectable); const currentRouteComponent = rendererDi.inject(currentRouteComponentInjectable);
for (const callback of beforeRenderCallbacks) { for (const callback of beforeRenderCallbacks) {

View File

@ -18,12 +18,13 @@ const createClusterInjectable = getInjectable({
logger: di.inject(loggerInjectable), logger: di.inject(loggerInjectable),
// TODO: Dismantle wrong abstraction // TODO: Dismantle wrong abstraction
createKubeconfigManager: () => undefined, // Note: "as never" to get around strictness in unnatural scenario
createKubeconfigManager: () => undefined as never,
createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");}, createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");},
createContextHandler: () => undefined, createContextHandler: () => undefined as never,
createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); }, createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); },
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); }, createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
detectorRegistry: undefined, detectorRegistry: undefined as never,
createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); }, createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); },
}; };

View File

@ -34,11 +34,15 @@ import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-
import hostedClusterIdInjectable from "../common/cluster-store/hosted-cluster-id.injectable"; import hostedClusterIdInjectable from "../common/cluster-store/hosted-cluster-id.injectable";
import type { GetDiForUnitTestingOptions } from "../test-utils/get-dis-for-unit-testing"; import type { GetDiForUnitTestingOptions } from "../test-utils/get-dis-for-unit-testing";
import historyInjectable from "./navigation/history.injectable"; import historyInjectable from "./navigation/history.injectable";
import themeStoreInjectable from "./theme-store.injectable";
import apiManagerInjectable from "./components/kube-object-menu/dependencies/api-manager.injectable";
import { ApiManager } from "../common/k8s-api/api-manager"; import { ApiManager } from "../common/k8s-api/api-manager";
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable"; import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable"; import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable";
import apiManagerInjectable from "../common/k8s-api/api-manager/manager.injectable";
import ipcRendererInjectable
from "./app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
import type { IpcRenderer } from "electron";
import setupOnApiErrorListenersInjectable from "./api/setup-on-api-errors.injectable";
import { observable } from "mobx";
export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => { export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
const { const {
@ -75,6 +79,11 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
di.override(lensResourcesDirInjectable, () => "/irrelevant"); di.override(lensResourcesDirInjectable, () => "/irrelevant");
di.override(ipcRendererInjectable, () => ({
invoke: () => {},
on: () => {},
}) as unknown as IpcRenderer);
di.override(broadcastMessageInjectable, () => () => { di.override(broadcastMessageInjectable, () => () => {
throw new Error("Tried to broadcast message over IPC without explicit override."); throw new Error("Tried to broadcast message over IPC without explicit override.");
}); });
@ -89,11 +98,17 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
// eslint-disable-next-line unused-imports/no-unused-vars-ts // eslint-disable-next-line unused-imports/no-unused-vars-ts
di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore); di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore);
di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} }));
di.override( di.override(
userStoreInjectable, userStoreInjectable,
() => () =>
({ ({
isTableColumnHidden: () => false, isTableColumnHidden: () => false,
extensionRegistryUrl: { customUrl: "some-custom-url" },
syncKubeconfigEntries: observable.map(),
terminalConfig: { fontSize: 42 },
editorConfiguration: { minimap: {}, tabSize: 42, fontSize: 42 },
} as unknown as UserStore), } as unknown as UserStore),
); );
@ -113,12 +128,6 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
info: noop, info: noop,
silly: noop, silly: noop,
})); }));
di.override(themeStoreInjectable, () => ({
activeTheme: {
type: "some-active-theme-type",
},
}));
} }
return di; return di;

View File

@ -10,6 +10,7 @@ import historyInjectable from "./history.injectable";
const observableHistoryInjectable = getInjectable({ const observableHistoryInjectable = getInjectable({
id: "observable-history", id: "observable-history",
instantiate: (di) => { instantiate: (di) => {
const history = di.inject(historyInjectable); const history = di.inject(historyInjectable);
const logger = di.inject(loggerInjectable); const logger = di.inject(loggerInjectable);

View File

@ -2,7 +2,7 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { DiContainerForInstantiate } from "@ogre-tools/injectable"; import type { DiContainerForInjection } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension"; import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
@ -46,7 +46,7 @@ export default extensionRouteRegistratorInjectable;
const toRouteInjectableFor = const toRouteInjectableFor =
( (
di: DiContainerForInstantiate, di: DiContainerForInjection,
extension: LensRendererExtension, extension: LensRendererExtension,
extensionInstallationCount: number, extensionInstallationCount: number,
) => ) =>

View File

@ -87,8 +87,8 @@ export const overrideIpcBridge = ({
mainDi.override( mainDi.override(
sendToChannelInElectronBrowserWindowInjectable, sendToChannelInElectronBrowserWindowInjectable,
() => () =>
(browserWindow, { channel: channelName, data }: SendToViewArgs) => { (browserWindow, { channel: channelName, data = [] }: SendToViewArgs) => {
const handles = rendererIpcFakeHandles.get(channelName); const handles = rendererIpcFakeHandles.get(channelName) || [];
if (isEmpty(handles)) { if (isEmpty(handles)) {
throw new Error( throw new Error(