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:
parent
7a89c8f74c
commit
c0cc56dba2
@ -340,7 +340,7 @@ exports[`helm-charts - navigation to Helm charts when navigating to Helm charts
|
||||
class="items box grow flex column"
|
||||
>
|
||||
<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
|
||||
class="TableHead sticky nowrap topLine"
|
||||
@ -430,7 +430,7 @@ exports[`helm-charts - navigation to Helm charts when navigating to Helm charts
|
||||
>
|
||||
<i
|
||||
class="Icon material interactive focusable"
|
||||
id="menu_actions_15"
|
||||
id="menu_actions_17"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
||||
@ -10,8 +10,6 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
|
||||
import currentPathInjectable from "../../renderer/routes/current-path.injectable";
|
||||
import { routeInjectionToken } from "../../common/front-end-routing/route-injection-token";
|
||||
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 routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
|
||||
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 navigateToFrontPageInjectable from "../../common/front-end-routing/navigate-to-front-page.injectable";
|
||||
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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
@ -39,16 +36,6 @@ describe("preferences - closing-preferences", () => {
|
||||
rendererDi.register(testFrontPageRouteComponentInjectable);
|
||||
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) => {
|
||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||
const testFrontPage = di.inject(testFrontPageRouteInjectable);
|
||||
|
||||
@ -5,28 +5,13 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
|
||||
describe("preferences - navigation to application preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
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", () => {
|
||||
|
||||
@ -5,28 +5,12 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
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", () => {
|
||||
|
||||
@ -5,30 +5,15 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 type { FakeExtensionData } 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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
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", () => {
|
||||
|
||||
@ -5,29 +5,12 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
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", () => {
|
||||
|
||||
@ -5,27 +5,12 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
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", () => {
|
||||
|
||||
@ -8,29 +8,14 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { FakeExtensionData } 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 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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
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", () => {
|
||||
|
||||
@ -5,11 +5,7 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 ipcRendererInjectable from "../../renderer/app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
|
||||
|
||||
describe("preferences - navigation to terminal preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
@ -18,18 +14,7 @@ describe("preferences - navigation to terminal preferences", () => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
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(ipcRendererInjectable, () => ({
|
||||
on: jest.fn(),
|
||||
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
|
||||
} as never));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -6,10 +6,6 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
@ -17,19 +13,6 @@ describe("preferences - navigation using application menu", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
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();
|
||||
});
|
||||
|
||||
@ -284,7 +284,7 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => {
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const configurationToBeMigrated = {
|
||||
"some-directory-for-user-data": {
|
||||
"lens-hotbar-store.json": JSON.stringify({
|
||||
@ -351,8 +351,6 @@ describe("HotbarStore", () => {
|
||||
|
||||
di.override(appVersionInjectable, () => "5.0.0-beta.10");
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
hotbarStore = di.inject(hotbarStoreInjectable);
|
||||
|
||||
hotbarStore.load();
|
||||
|
||||
@ -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;
|
||||
@ -10,6 +10,7 @@ export type HasCategoryForEntity = (data: CatalogEntityData & CatalogEntityKindD
|
||||
|
||||
const hasCategoryForEntityInjectable = getInjectable({
|
||||
id: "has-category-for-entity",
|
||||
|
||||
instantiate: (di): HasCategoryForEntity => {
|
||||
const registry = di.inject(catalogCategoryRegistryInjectable);
|
||||
|
||||
|
||||
@ -30,8 +30,8 @@ export interface ClusterDependencies {
|
||||
readonly directoryForKubeConfigs: string;
|
||||
readonly logger: Logger;
|
||||
readonly detectorRegistry: DetectorRegistry;
|
||||
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager | undefined;
|
||||
createContextHandler: (cluster: Cluster) => ClusterContextHandler | undefined;
|
||||
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager;
|
||||
createContextHandler: (cluster: Cluster) => ClusterContextHandler;
|
||||
createKubectl: (clusterVersion: string) => Kubectl;
|
||||
createAuthorizationReview: (config: KubeConfig) => CanI;
|
||||
createListNamespaces: (config: KubeConfig) => ListNamespaces;
|
||||
|
||||
@ -23,11 +23,9 @@ const mockFetch = fetch as FetchMock;
|
||||
describe("forRemoteCluster", () => {
|
||||
let apiManager: jest.Mocked<ApiManager>;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
apiManager = new ApiManager() as jest.Mocked<ApiManager>;
|
||||
|
||||
di.override(apiManagerInjectable, () => apiManager);
|
||||
@ -87,11 +85,9 @@ describe("KubeApi", () => {
|
||||
let request: KubeJsonApi;
|
||||
let apiManager: jest.Mocked<ApiManager>;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
await di.runSetups();
|
||||
|
||||
request = new KubeJsonApi({
|
||||
serverAddress: `http://127.0.0.1:9999`,
|
||||
apiBase: "/api-kube",
|
||||
|
||||
@ -45,7 +45,7 @@ describe("runManyFor", () => {
|
||||
|
||||
const runMany = runManyFor(rootDi)(someInjectionTokenForRunnables);
|
||||
|
||||
actualPromise = runMany();
|
||||
actualPromise = runMany() as Promise<void>;
|
||||
});
|
||||
|
||||
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", () => {
|
||||
let runMock: AsyncFnMock<(arg: string) => Promise<void>>;
|
||||
let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
|
||||
let actualPromise: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -110,7 +110,7 @@ describe("runManyFor", () => {
|
||||
|
||||
const runMany = runManyFor(di)(someInjectionTokenForRunnables);
|
||||
|
||||
actualPromise = runMany();
|
||||
actualPromise = runMany() as Promise<void>;
|
||||
});
|
||||
|
||||
it("runs first level runnables", () => {
|
||||
@ -173,7 +173,7 @@ describe("runManyFor", () => {
|
||||
});
|
||||
|
||||
describe("when running many with parameter", () => {
|
||||
let runMock: AsyncFnMock<(arg: string, arg2: string) => Promise<void>>;
|
||||
let runMock: AsyncFnMock<(...args: unknown[]) => Promise<void>>;
|
||||
|
||||
beforeEach(() => {
|
||||
const rootDi = createContainer();
|
||||
|
||||
@ -10,35 +10,37 @@ import type {
|
||||
import { filter, map } from "lodash/fp";
|
||||
|
||||
export interface Runnable<TParameter = void> {
|
||||
run: (parameter: TParameter) => Promise<void> | void;
|
||||
run: Run<TParameter>;
|
||||
runAfter?: this;
|
||||
}
|
||||
|
||||
export const runManyFor =
|
||||
(di: DiContainerForInjection) =>
|
||||
<TRunnable extends Runnable<unknown>>(
|
||||
injectionToken: InjectionToken<TRunnable, void>,
|
||||
type Run<Param> = (parameter: Param) => Promise<void> | void;
|
||||
|
||||
export type RunMany = <Param>(
|
||||
injectionToken: InjectionToken<Runnable<Param>, void>
|
||||
) => Run<Param>;
|
||||
|
||||
export function runManyFor(di: DiContainerForInjection): RunMany {
|
||||
return (injectionToken) => async (parameter) => {
|
||||
const allRunnables = di.injectMany(injectionToken);
|
||||
|
||||
const recursedRun = async (
|
||||
runAfterRunnable: Runnable<any> | undefined = undefined,
|
||||
) =>
|
||||
async (parameter: Parameters<TRunnable["run"]>[0]) => {
|
||||
const allRunnables = di.injectMany(injectionToken);
|
||||
await pipeline(
|
||||
allRunnables,
|
||||
|
||||
const recursedRun = async (runAfterRunnable: Runnable<unknown> = undefined) =>
|
||||
await pipeline(
|
||||
allRunnables,
|
||||
filter((runnable) => runnable.runAfter === runAfterRunnable),
|
||||
|
||||
filter((runnable) => runnable.runAfter === runAfterRunnable),
|
||||
|
||||
map(async (runnable) => {
|
||||
await runnable.run(parameter);
|
||||
|
||||
await recursedRun(runnable);
|
||||
}),
|
||||
|
||||
promises => Promise.all(promises),
|
||||
);
|
||||
|
||||
await recursedRun();
|
||||
};
|
||||
map(async (runnable) => {
|
||||
await runnable.run(parameter);
|
||||
|
||||
await recursedRun(runnable);
|
||||
}),
|
||||
|
||||
(promises) => Promise.all(promises),
|
||||
);
|
||||
|
||||
await recursedRun();
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,32 +8,38 @@ import type {
|
||||
InjectionToken,
|
||||
} from "@ogre-tools/injectable";
|
||||
import { filter, map } from "lodash/fp";
|
||||
import type { Runnable } from "./run-many-for";
|
||||
|
||||
export interface RunnableSync<TParameter = void> {
|
||||
run: (parameter: TParameter) => void;
|
||||
run: RunSync<TParameter>;
|
||||
runAfter?: this;
|
||||
}
|
||||
|
||||
export const runManySyncFor =
|
||||
(di: DiContainerForInjection) =>
|
||||
<TRunnable extends RunnableSync<unknown>>(
|
||||
injectionToken: InjectionToken<TRunnable, void>,
|
||||
type RunSync<Param> = (parameter: Param) => void;
|
||||
|
||||
export type RunManySync = <Param>(
|
||||
injectionToken: InjectionToken<Runnable<Param>, void>
|
||||
) => RunSync<Param>;
|
||||
|
||||
export function runManySyncFor(di: DiContainerForInjection): RunManySync {
|
||||
return (injectionToken) => async (parameter) => {
|
||||
const allRunnables = di.injectMany(injectionToken);
|
||||
|
||||
const recursedRun = (
|
||||
runAfterRunnable: RunnableSync<any> | undefined = undefined,
|
||||
) =>
|
||||
(parameter: Parameters<TRunnable["run"]>[0]) => {
|
||||
const allRunnables = di.injectMany(injectionToken);
|
||||
pipeline(
|
||||
allRunnables,
|
||||
|
||||
const recursedRun = (runAfterRunnable: RunnableSync<unknown> = undefined) =>
|
||||
pipeline(
|
||||
allRunnables,
|
||||
filter((runnable) => runnable.runAfter === runAfterRunnable),
|
||||
|
||||
filter((runnable) => runnable.runAfter === runAfterRunnable),
|
||||
map((runnable) => {
|
||||
runnable.run(parameter);
|
||||
|
||||
map((runnable) => {
|
||||
runnable.run(parameter);
|
||||
recursedRun(runnable);
|
||||
}),
|
||||
);
|
||||
|
||||
recursedRun(runnable);
|
||||
}),
|
||||
);
|
||||
|
||||
recursedRun();
|
||||
};
|
||||
recursedRun();
|
||||
};
|
||||
}
|
||||
|
||||
@ -33,5 +33,11 @@ export const getLegacyGlobalDiForExtensionApi = () => {
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ describe("get-electron-app-path", () => {
|
||||
di.override(registerChannelInjectable, () => () => undefined);
|
||||
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", () => {
|
||||
|
||||
@ -7,7 +7,7 @@ import directoryForKubeConfigsInjectable from "../../../common/app-paths/directo
|
||||
import { KubeconfigSyncManager } from "./manager";
|
||||
import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token";
|
||||
import clusterManagerInjectable from "../../cluster-manager.injectable";
|
||||
import catalogEntityRegistryInjectable from "../../catalog/catalog-entity-registry.injectable";
|
||||
import catalogEntityRegistryInjectable from "../../catalog/entity-registry.injectable";
|
||||
|
||||
const kubeconfigSyncManagerInjectable = getInjectable({
|
||||
id: "kubeconfig-sync-manager",
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { syncWeblinks } from "./weblinks";
|
||||
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({
|
||||
id: "sync-weblinks",
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/catalog-entity-registry.injectable";
|
||||
import { startCatalogSyncToRenderer } from "../catalog-pusher";
|
||||
import { getStartableStoppable } from "../../common/utils/get-startable-stoppable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
|
||||
const catalogSyncToRendererInjectable = getInjectable({
|
||||
id: "catalog-sync-to-renderer",
|
||||
|
||||
@ -4,14 +4,13 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import hasCategoryForEntityInjectable from "../../common/catalog/has-category-for-entity.injectable";
|
||||
import { CatalogEntityRegistry } from "./catalog-entity-registry";
|
||||
import catalogCategoryRegistryInjectable from "../../common/catalog/catalog-category-registry.injectable";
|
||||
import { CatalogEntityRegistry } from "./entity-registry";
|
||||
|
||||
const catalogEntityRegistryInjectable = getInjectable({
|
||||
id: "catalog-entity-registry",
|
||||
|
||||
instantiate: (di) => new CatalogEntityRegistry({
|
||||
hasCategoryForEntity: di.inject(hasCategoryForEntityInjectable),
|
||||
categoryRegistryRegistry: di.inject(catalogCategoryRegistryInjectable);
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ interface Dependencies {
|
||||
k8sRequest: K8sRequest;
|
||||
}
|
||||
|
||||
export type DetectorConstructor = new (cluster: Cluster) => BaseClusterDetector;
|
||||
export type DetectorConstructor = new (cluster: Cluster, k8sRequest: K8sRequest) => BaseClusterDetector;
|
||||
|
||||
export class DetectorRegistry {
|
||||
constructor(private dependencies: Dependencies) {}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ClusterManager } from "./cluster-manager";
|
||||
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({
|
||||
id: "cluster-manager",
|
||||
|
||||
@ -10,13 +10,13 @@ import type { Cluster } from "../common/cluster/cluster";
|
||||
import logger from "./logger";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import { getClusterIdFromHost, isErrnoException } from "../common/utils";
|
||||
import type { catalogEntityRegistry } from "./catalog";
|
||||
import type { KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster";
|
||||
import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../common/catalog-entities/kubernetes-cluster";
|
||||
import { ipcMainOn } from "../common/ipc";
|
||||
import { once } from "lodash";
|
||||
import type { ClusterStore } from "../common/cluster-store/cluster-store";
|
||||
import type { ClusterId } from "../common/cluster-types";
|
||||
import type { CatalogEntityRegistry } from "./catalog";
|
||||
|
||||
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) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ const createContextHandlerInjectable = getInjectable({
|
||||
const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable);
|
||||
const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable);
|
||||
|
||||
return (cluster: Cluster): ClusterContextHandler | undefined => {
|
||||
return (cluster: Cluster): ClusterContextHandler => {
|
||||
const clusterUrl = new URLParse(cluster.apiUrl);
|
||||
|
||||
const dependencies = {
|
||||
|
||||
@ -9,10 +9,11 @@ import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import clusterManagerInjectable from "../../../cluster-manager.injectable";
|
||||
import applicationMenuItemsInjectable from "../../../menu/application-menu-items.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 { onLoadOfApplicationInjectionToken } from "../../../start-main-application/runnable-tokens/on-load-of-application-injection-token";
|
||||
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({
|
||||
id: "setup-ipc-main-handlers",
|
||||
@ -30,6 +31,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const operatingSystemTheme = di.inject(operatingSystemThemeInjectable);
|
||||
const askUserForFilePaths = di.inject(askUserForFilePathsInjectable);
|
||||
|
||||
return {
|
||||
run: () => {
|
||||
@ -43,6 +45,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
catalogEntityRegistry,
|
||||
clusterStore,
|
||||
operatingSystemTheme,
|
||||
askUserForFilePaths,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@ -21,9 +21,9 @@ import type { MenuItemOpts } from "../../../menu/application-menu-items.injectab
|
||||
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window";
|
||||
import { handleWindowAction, onLocationChange } from "../../../ipc/window";
|
||||
import { openFilePickingDialogChannel } from "../../../../common/ipc/dialog";
|
||||
import { showOpenDialog } from "../../../ipc/dialog";
|
||||
import { getNativeThemeChannel } from "../../../../common/ipc/native-theme";
|
||||
import type { Theme } from "../../../theme/operating-system-theme-state.injectable";
|
||||
import type { AskUserForFilePaths } from "../../../ipc/ask-user-for-file-paths.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
directoryForLensLocalStorage: string;
|
||||
@ -33,9 +33,10 @@ interface Dependencies {
|
||||
catalogEntityRegistry: CatalogEntityRegistry;
|
||||
clusterStore: ClusterStore;
|
||||
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) => {
|
||||
return ClusterStore.getInstance()
|
||||
.getById(clusterId)
|
||||
@ -149,7 +150,7 @@ export const setupIpcMainHandlers = ({ applicationMenuItems, directoryForLensLoc
|
||||
|
||||
ipcMainOn(windowLocationChangedChannel, () => onLocationChange());
|
||||
|
||||
ipcMainHandle(openFilePickingDialogChannel, (event, opts) => showOpenDialog(opts));
|
||||
ipcMainHandle(openFilePickingDialogChannel, (event, opts) => askUserForFilePaths(opts));
|
||||
|
||||
ipcMainHandle(broadcastMainChannel, (event, channel, ...args) => broadcastMessage(channel, ...args));
|
||||
|
||||
|
||||
@ -31,7 +31,6 @@ import joinPathsInjectable from "../common/path/join-paths.injectable";
|
||||
import { joinPathsFake } from "../common/test-utils/join-paths-fake";
|
||||
import hotbarStoreInjectable from "../common/hotbars/store.injectable";
|
||||
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 appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable";
|
||||
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 registerFileProtocolInjectable from "./electron-app/features/register-file-protocol.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 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";
|
||||
@ -125,8 +122,6 @@ export function getDiForUnitTesting(opts: GetDiForUnitTestingOptions = {}) {
|
||||
di.override(trayInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
di.override(applicationMenuInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
|
||||
di.override(catalogCategoryRegistryInjectable, () => new CatalogCategoryRegistry());
|
||||
|
||||
// TODO: Remove usages of globally exported appEventBus to get rid of this
|
||||
di.override(appEventBusInjectable, () => new EventEmitter<[AppEvent]>());
|
||||
|
||||
@ -229,7 +224,7 @@ const overrideElectronFeatures = (di: DiContainer) => {
|
||||
close: () => {},
|
||||
|
||||
send: (arg) => {
|
||||
const sendFake = di.inject(sendToChannelInElectronBrowserWindowInjectable);
|
||||
const sendFake = di.inject(sendToChannelInElectronBrowserWindowInjectable) as any;
|
||||
|
||||
sendFake(null, arg);
|
||||
},
|
||||
|
||||
@ -12,10 +12,14 @@ import logger from "../logger";
|
||||
import { execHelm } from "./exec";
|
||||
import type { HelmEnv, HelmRepo, HelmRepoConfig } from "./helm-repo-manager";
|
||||
|
||||
class HelmRepoManager {
|
||||
protected repos: HelmRepo[];
|
||||
protected helmEnv: HelmEnv;
|
||||
protected didUpdateOnce: boolean;
|
||||
interface EnsuredHelmRepoManagerData {
|
||||
helmEnv: HelmEnv;
|
||||
didUpdateOnce: boolean;
|
||||
}
|
||||
|
||||
export class HelmRepoManager {
|
||||
protected helmEnv?: HelmEnv;
|
||||
protected didUpdateOnce?: boolean;
|
||||
|
||||
public async loadAvailableRepos(): Promise<HelmRepo[]> {
|
||||
const res = await customRequestPromise({
|
||||
@ -25,13 +29,13 @@ class HelmRepoManager {
|
||||
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();
|
||||
|
||||
const repos = await this.list();
|
||||
const repos = await this.list(this.helmEnv);
|
||||
|
||||
if (repos.length === 0) {
|
||||
await this.addRepo({
|
||||
@ -44,12 +48,17 @@ class HelmRepoManager {
|
||||
await this.update();
|
||||
this.didUpdateOnce = true;
|
||||
}
|
||||
|
||||
return {
|
||||
didUpdateOnce: this.didUpdateOnce,
|
||||
helmEnv: this.helmEnv,
|
||||
};
|
||||
}
|
||||
|
||||
protected async parseHelmEnv() {
|
||||
const output = await execHelm(["env"]);
|
||||
const lines = output.split(/\r?\n/); // split by new line feed
|
||||
const env: HelmEnv = {};
|
||||
const env: Partial<Record<string, string>> = {};
|
||||
|
||||
lines.forEach((line: string) => {
|
||||
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();
|
||||
|
||||
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 {
|
||||
const rawConfig = await readFile(
|
||||
this.helmEnv.HELM_REPOSITORY_CONFIG,
|
||||
"utf8",
|
||||
);
|
||||
const rawConfig = await readFile(helmEnv.HELM_REPOSITORY_CONFIG, "utf8");
|
||||
const parsedConfig = yaml.load(rawConfig) as HelmRepoConfig;
|
||||
|
||||
if (typeof parsedConfig === "object" && parsedConfig) {
|
||||
@ -88,13 +94,13 @@ class HelmRepoManager {
|
||||
|
||||
public async repositories(): Promise<HelmRepo[]> {
|
||||
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,
|
||||
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`,
|
||||
cacheFilePath: `${helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`,
|
||||
}));
|
||||
} catch (error) {
|
||||
logger.error(`[HELM]: repositories listing error`, error);
|
||||
@ -104,21 +110,20 @@ class HelmRepoManager {
|
||||
}
|
||||
|
||||
public async update() {
|
||||
return execHelm(["repo", "update"]);
|
||||
return execHelm([
|
||||
"repo",
|
||||
"update",
|
||||
]);
|
||||
}
|
||||
|
||||
public async addRepo({
|
||||
name,
|
||||
url,
|
||||
insecureSkipTlsVerify,
|
||||
username,
|
||||
password,
|
||||
caFile,
|
||||
keyFile,
|
||||
certFile,
|
||||
}: HelmRepo) {
|
||||
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, url];
|
||||
const args = [
|
||||
"repo",
|
||||
"add",
|
||||
name,
|
||||
url,
|
||||
];
|
||||
|
||||
if (insecureSkipTlsVerify) {
|
||||
args.push("--insecure-skip-tls-verify");
|
||||
@ -150,7 +155,11 @@ class HelmRepoManager {
|
||||
public async removeRepo({ name, url }: HelmRepo): Promise<string> {
|
||||
logger.info(`[HELM]: removing repo ${name} (${url})`);
|
||||
|
||||
return execHelm(["repo", "remove", name]);
|
||||
return execHelm([
|
||||
"repo",
|
||||
"remove",
|
||||
name,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
36
src/main/ipc/ask-user-for-file-paths.injectable.ts
Normal file
36
src/main/ipc/ask-user-for-file-paths.injectable.ts
Normal 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;
|
||||
@ -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 };
|
||||
}
|
||||
@ -14,7 +14,7 @@ export interface KubeConfigManagerInstantiationParameter {
|
||||
cluster: Cluster;
|
||||
}
|
||||
|
||||
export type CreateKubeconfigManager = (cluster: Cluster) => KubeconfigManager | undefined;
|
||||
export type CreateKubeconfigManager = (cluster: Cluster) => KubeconfigManager;
|
||||
|
||||
const createKubeconfigManagerInjectable = getInjectable({
|
||||
id: "create-kubeconfig-manager",
|
||||
|
||||
@ -7,7 +7,7 @@ import net from "net";
|
||||
import type http from "http";
|
||||
import spdy from "spdy";
|
||||
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 { ClusterContextHandler } from "../context-handler/context-handler";
|
||||
import logger from "../logger";
|
||||
@ -59,12 +59,9 @@ const disallowedPorts = new Set([
|
||||
]);
|
||||
|
||||
export class LensProxy {
|
||||
protected origin: string;
|
||||
protected proxyServer: http.Server;
|
||||
protected closed = false;
|
||||
protected retryCounters = new Map<string, number>();
|
||||
protected getClusterForRequest: GetClusterForRequest;
|
||||
|
||||
|
||||
constructor(private dependencies: Dependencies) {
|
||||
this.configureProxy(dependencies.proxy);
|
||||
|
||||
@ -15,10 +15,12 @@ import parseRequestInjectable from "./parse-request.injectable";
|
||||
import { contentTypes } from "./router-content-types";
|
||||
import mockFs from "mock-fs";
|
||||
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", () => {
|
||||
let router: Router;
|
||||
let routeHandlerMock: AsyncFnMock<RouteHandler<any, string>>;
|
||||
let routeHandlerMock: AsyncFnMock<() => any>;
|
||||
|
||||
beforeEach(async () => {
|
||||
routeHandlerMock = asyncFn();
|
||||
|
||||
@ -8,8 +8,8 @@ import type http from "http";
|
||||
import { toPairs } from "lodash/fp";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { contentTypes } from "./router-content-types";
|
||||
import type { ServerIncomingMessage } from "../lens-proxy";
|
||||
import type { LensApiRequest, LensApiResult, Route } from "./route";
|
||||
import type { ServerIncomingMessage } from "../lens-proxy/lens-proxy";
|
||||
|
||||
export interface RouterRequestOpts {
|
||||
req: http.IncomingMessage;
|
||||
|
||||
@ -5,14 +5,13 @@
|
||||
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { PrometheusProviderRegistry } from "../../prometheus";
|
||||
import { route } from "../../router/route";
|
||||
import prometheusProviderRegistryInjectable from "../../prometheus/prometheus-provider-registry.injectable";
|
||||
|
||||
const getMetricProvidersRouteInjectable = getRouteInjectable({
|
||||
id: "get-metric-providers-route",
|
||||
|
||||
instantiate: () => {
|
||||
instantiate: (di) => {
|
||||
const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable);
|
||||
|
||||
return route({
|
||||
@ -26,7 +25,7 @@ const getMetricProvidersRouteInjectable = getRouteInjectable({
|
||||
({ name, id, isConfigurable }) => ({ name, id, isConfigurable }),
|
||||
),
|
||||
}));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default getMetricProvidersRouteInjectable;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable";
|
||||
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({
|
||||
id: "terminal-shell-env-modify",
|
||||
|
||||
@ -34,7 +34,7 @@ const createLensWindowInjectable = getInjectable({
|
||||
instantiate:
|
||||
(di) =>
|
||||
(configuration: LensWindowConfiguration) => {
|
||||
let browserWindow: LensWindow = null;
|
||||
let browserWindow: LensWindow | undefined;
|
||||
|
||||
const createElectronWindow = di.inject(createElectronWindowForInjectable)(
|
||||
{
|
||||
@ -52,14 +52,14 @@ const createLensWindowInjectable = getInjectable({
|
||||
beforeOpen: configuration.beforeOpen,
|
||||
|
||||
onClose: () => {
|
||||
browserWindow = null;
|
||||
browserWindow = undefined;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
get visible() {
|
||||
return !!this.browserWindow;
|
||||
return !!browserWindow;
|
||||
},
|
||||
|
||||
show: async () => {
|
||||
@ -72,7 +72,7 @@ const createLensWindowInjectable = getInjectable({
|
||||
|
||||
close: () => {
|
||||
browserWindow?.close();
|
||||
browserWindow = null;
|
||||
browserWindow = undefined;
|
||||
},
|
||||
|
||||
send: async (args: SendToViewArgs) => {
|
||||
|
||||
@ -44,7 +44,7 @@ const initializeExtensionsInjectable = getInjectable({
|
||||
});
|
||||
|
||||
extensionLoader.initExtensions(extensions);
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
showErrorPopup(
|
||||
"Lens Error",
|
||||
`Could not load extensions${
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
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 kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync-manager/kubeconfig-sync-manager.injectable";
|
||||
import ensureDirInjectable from "../../../../common/fs/ensure-dir.injectable";
|
||||
import kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync/manager.injectable";
|
||||
|
||||
const startKubeConfigSyncInjectable = getInjectable({
|
||||
id: "start-kubeconfig-sync",
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
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 kubeconfigSyncManagerInjectable from "../../../catalog-sources/kubeconfig-sync/manager.injectable";
|
||||
|
||||
const stopKubeConfigSyncInjectable = getInjectable({
|
||||
id: "stop-kube-config-sync",
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import hotbarStoreInjectable from "../../../common/hotbar-store.injectable";
|
||||
import setupSyncingOfGeneralCatalogEntitiesInjectable from "./setup-syncing-of-general-catalog-entities.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "../runnable-tokens/on-load-of-application-injection-token";
|
||||
import hotbarStoreInjectable from "../../../common/hotbars/store.injectable";
|
||||
|
||||
const setupHotbarStoreInjectable = getInjectable({
|
||||
id: "setup-hotbar-store",
|
||||
|
||||
@ -28,7 +28,7 @@ const setupLensProxyInjectable = getInjectable({
|
||||
try {
|
||||
logger.info("🔌 Starting LensProxy");
|
||||
await lensProxy.listen(); // lensProxy.port available
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
showErrorPopup("Lens Error", `Could not start proxy: ${error?.message || "unknown error"}`);
|
||||
|
||||
return exitApp();
|
||||
|
||||
@ -5,13 +5,19 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiBase } from "../../common/k8s-api";
|
||||
import { onApiError } from "./on-api-error";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
|
||||
const setupOnApiErrorListenersInjectable = getInjectable({
|
||||
id: "setup-on-api-error-listeners",
|
||||
setup: () => {
|
||||
apiBase?.onError.addListener(onApiError);
|
||||
},
|
||||
instantiate: () => undefined,
|
||||
|
||||
instantiate: () => ({
|
||||
run: () => {
|
||||
apiBase?.onError.addListener(onApiError);
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default setupOnApiErrorListenersInjectable;
|
||||
|
||||
@ -105,7 +105,7 @@ class NonInjectedReleaseDetails extends Component<ReleaseDetailsProps & Dependen
|
||||
upgradeVersion = (release: HelmRelease) => {
|
||||
const { hideDetails, createUpgradeChartTab } = this.props;
|
||||
|
||||
this.props.createUpgradeChartTab(this.release);
|
||||
createUpgradeChartTab(release);
|
||||
hideDetails();
|
||||
};
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ClusterFrameHandler } from "./lens-views";
|
||||
import { ClusterFrameHandler } from "./cluster-frame-handler";
|
||||
|
||||
const clusterFramesInjectable = getInjectable({
|
||||
id: "cluster-frames",
|
||||
const clusterFrameHandlerInjectable = getInjectable({
|
||||
id: "cluster-frame-handler",
|
||||
instantiate: () => new ClusterFrameHandler(),
|
||||
});
|
||||
|
||||
export default clusterFramesInjectable;
|
||||
export default clusterFrameHandlerInjectable;
|
||||
@ -9,7 +9,7 @@ import type { IComputedValue } from "mobx";
|
||||
import { computed, makeObservable, reaction } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
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 { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||
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 navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.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 catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||
|
||||
@ -107,7 +107,7 @@ export const ClusterView = withInjectables<Dependencies>(NonInjectedClusterView,
|
||||
getProps: (di) => ({
|
||||
clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId,
|
||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||
clusterFrames: di.inject(clusterFramesInjectable),
|
||||
clusterFrames: di.inject(clusterFrameHandlerInjectable),
|
||||
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -4,28 +4,20 @@
|
||||
*/
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
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 type { RenderResult } from "@testing-library/react";
|
||||
import mockFs from "mock-fs";
|
||||
import React from "react";
|
||||
import * as selectEvent from "react-select-event";
|
||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||
import { DeleteClusterDialog } from "../view";
|
||||
import { DeleteClusterDialog } from "../delete-cluster-dialog";
|
||||
import type { ClusterModel } from "../../../../common/cluster-types";
|
||||
import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token";
|
||||
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 openDeleteClusterDialogInjectable from "../open.injectable";
|
||||
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.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 { getApplicationBuilder } from "../../test-utils/get-application-builder";
|
||||
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 { routeSpecificComponentInjectionToken } from "../../../routes/route-specific-component-injection-token";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
@ -50,33 +43,29 @@ jest.mock("electron", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const kubeconfig = `
|
||||
const multiClusterConfig = `
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://localhost
|
||||
name: test
|
||||
name: some-current-context-cluster
|
||||
- cluster:
|
||||
server: http://localhost
|
||||
name: other-cluster
|
||||
name: some-non-current-context-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: test
|
||||
user: test
|
||||
name: test
|
||||
cluster: some-current-context-cluster
|
||||
user: some-user
|
||||
name: some-current-context
|
||||
- context:
|
||||
cluster: test
|
||||
user: test
|
||||
name: test2
|
||||
- context:
|
||||
cluster: other-cluster
|
||||
user: test
|
||||
name: other-context
|
||||
current-context: other-context
|
||||
cluster: some-non-current-context-cluster
|
||||
user: some-user
|
||||
name: some-non-current-context
|
||||
current-context: some-current-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: test
|
||||
- name: some-user
|
||||
user:
|
||||
token: kubeconfig-user-q4lm4:xxxyyyy
|
||||
`;
|
||||
@ -86,17 +75,17 @@ apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: http://localhost
|
||||
name: other-cluster
|
||||
name: some-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: other-cluster
|
||||
user: test
|
||||
name: other-context
|
||||
current-context: other-context
|
||||
cluster: some-cluster
|
||||
user: some-user
|
||||
name: some-context
|
||||
current-context: some-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: test
|
||||
- name: some-user
|
||||
user:
|
||||
token: kubeconfig-user-q4lm4:xxxyyyy
|
||||
`;
|
||||
@ -107,46 +96,22 @@ describe("<DeleteClusterDialog />", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let createCluster: (model: ClusterModel) => Cluster;
|
||||
let openDeleteClusterDialog: OpenDeleteClusterDialog;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
|
||||
mainDi.override(createContextHandlerInjectable, () => () => undefined);
|
||||
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined);
|
||||
mainDi.override(createContextHandlerInjectable, () => () => undefined as any);
|
||||
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined as any);
|
||||
|
||||
rendererDi.override(hotbarStoreInjectable, () => ({}));
|
||||
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({
|
||||
id: "some-test-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
Component: () => <DeleteClusterDialog />,
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
});
|
||||
|
||||
const { rendererDi } = applicationBuilder.dis;
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
@ -154,70 +119,100 @@ describe("<DeleteClusterDialog />", () => {
|
||||
navigateToRoute(testRoute);
|
||||
});
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponent);
|
||||
|
||||
mockFs();
|
||||
|
||||
openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable);
|
||||
createCluster = mainDi.inject(createClusterInjectionToken);
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable);
|
||||
createCluster = rendererDi.inject(createClusterInjectionToken);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("shows context switcher when deleting current cluster", async () => {
|
||||
const mockOpts = {
|
||||
"temp-kube-config": multiClusterConfig,
|
||||
};
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
config = new KubeConfig();
|
||||
config.loadFromString(multiClusterConfig);
|
||||
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
const createCluster = rendererDi.inject(createClusterInjectionToken);
|
||||
|
||||
const cluster = createCluster({
|
||||
id: "some-current-context-cluster",
|
||||
contextName: "some-current-context",
|
||||
preferences: {
|
||||
clusterName: "some-current-context-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
});
|
||||
|
||||
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;
|
||||
let createCluster: (model: ClusterModel) => Cluster;
|
||||
let deleteClusterDialogModel: DeleteClusterDialogModel;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockOpts = {
|
||||
"temp-kube-config": kubeconfig,
|
||||
"temp-kube-config": multiClusterConfig,
|
||||
};
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
config = new KubeConfig();
|
||||
config.loadFromString(kubeconfig);
|
||||
config.loadFromString(multiClusterConfig);
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
|
||||
deleteClusterDialogModel = applicationBuilder.dis.rendererDi.inject(deleteClusterDialogModelInjectable);
|
||||
createCluster = applicationBuilder.dis.mainDi.inject(createClusterInjectionToken);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("renders w/o errors", () => {
|
||||
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({
|
||||
id: "test",
|
||||
contextName: "test",
|
||||
id: "some-non-current-context-cluster",
|
||||
contextName: "some-non-current-context",
|
||||
preferences: {
|
||||
clusterName: "minikube",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
deleteClusterDialogModel.open({ cluster, config });
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
|
||||
const message = "The contents of kubeconfig file will be changed!";
|
||||
|
||||
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({
|
||||
id: "other-cluster",
|
||||
contextName: "other-context",
|
||||
id: "some-current-context-cluster",
|
||||
contextName: "some-current-context",
|
||||
preferences: {
|
||||
clusterName: "other-cluster",
|
||||
clusterName: "some-current-context-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
@ -227,42 +222,17 @@ describe("<DeleteClusterDialog />", () => {
|
||||
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({
|
||||
id: "other-cluster",
|
||||
contextName: "other-context",
|
||||
id: "some-current-context-cluster",
|
||||
contextName: "some-current-context",
|
||||
preferences: {
|
||||
clusterName: "other-cluster",
|
||||
clusterName: "some-current-context-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-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 link = getByTestId("context-switch");
|
||||
@ -270,28 +240,30 @@ describe("<DeleteClusterDialog />", () => {
|
||||
expect(link).toBeInstanceOf(HTMLElement);
|
||||
fireEvent.click(link);
|
||||
|
||||
const menu = await screen.findByText("Select new context...");
|
||||
const menu = getByText("Select new context...");
|
||||
|
||||
expect(menu).toBeInTheDocument();
|
||||
selectEvent.openMenu(menu);
|
||||
|
||||
expect(await screen.findByText("test")).toBeInTheDocument();
|
||||
expect(await screen.findByText("test2")).toBeInTheDocument();
|
||||
expect(getByText("some-current-context")).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({
|
||||
id: "some-cluster",
|
||||
contextName: "test",
|
||||
id: "some-non-current-context-cluster",
|
||||
contextName: "some-non-current-context",
|
||||
|
||||
preferences: {
|
||||
clusterName: "test",
|
||||
clusterName: "some-non-current-context-cluster",
|
||||
},
|
||||
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true);
|
||||
|
||||
deleteClusterDialogModel.open({ cluster, config });
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
|
||||
expect(rendered.getByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
|
||||
|
||||
@ -301,8 +273,6 @@ describe("<DeleteClusterDialog />", () => {
|
||||
|
||||
describe("Kubeconfig with single cluster", () => {
|
||||
let rendered: RenderResult;
|
||||
let createCluster: (model: ClusterModel) => Cluster;
|
||||
let deleteClusterDialogModel: DeleteClusterDialogModel;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockOpts = {
|
||||
@ -315,28 +285,44 @@ describe("<DeleteClusterDialog />", () => {
|
||||
config.loadFromString(singleClusterConfig);
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
|
||||
deleteClusterDialogModel = applicationBuilder.dis.rendererDi.inject(deleteClusterDialogModelInjectable);
|
||||
createCluster = applicationBuilder.dis.mainDi.inject(createClusterInjectionToken);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("shows warning if no other contexts left", async () => {
|
||||
it("shows warning if no other contexts left", () => {
|
||||
const cluster = createCluster({
|
||||
id: "other-cluster",
|
||||
contextName: "other-context",
|
||||
id: "some-cluster",
|
||||
contextName: "some-context",
|
||||
preferences: {
|
||||
clusterName: "other-cluster",
|
||||
clusterName: "some-cluster",
|
||||
},
|
||||
kubeConfigPath: "./temp-kube-config",
|
||||
});
|
||||
|
||||
deleteClusterDialogModel.open({ cluster, config });
|
||||
openDeleteClusterDialog({ cluster, config });
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
@ -50,6 +50,7 @@ class NonInjectedMenuActions extends React.Component<MenuActionsProps & Dependen
|
||||
removeConfirmationMessage: "Remove item?",
|
||||
};
|
||||
|
||||
// TODO: Make deterministic
|
||||
public id = uniqueId("menu_actions_");
|
||||
|
||||
@observable isOpen = !!this.props.toolbar;
|
||||
|
||||
@ -9,7 +9,6 @@ import { extensionRegistratorInjectionToken } from "../../../extensions/extensio
|
||||
import type { IObservableArray } from "mobx";
|
||||
import { computed, observable, runInAction } from "mobx";
|
||||
import { renderFor } from "./renderFor";
|
||||
import observableHistoryInjectable from "../../navigation/observable-history.injectable";
|
||||
import React from "react";
|
||||
import { Router } from "react-router-dom";
|
||||
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 { ClusterFrameContext } from "../../cluster-frame-context/cluster-frame-context";
|
||||
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 namespaceStoreInjectable from "../+namespaces/namespace-store/namespace-store.injectable";
|
||||
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable";
|
||||
import startMainApplicationInjectable from "../../../main/start-main-application/start-main-application.injectable";
|
||||
import startFrameInjectable from "../../start-frame/start-frame.injectable";
|
||||
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>;
|
||||
|
||||
@ -235,9 +235,11 @@ export const getApplicationBuilder = () => {
|
||||
|
||||
const clusterStub = {
|
||||
accessibleNamespaces: [],
|
||||
} as Cluster;
|
||||
} as unknown as Cluster;
|
||||
|
||||
const namespaceStoreStub = {} as NamespaceStore;
|
||||
const namespaceStoreStub = {
|
||||
contextNamespaces: [],
|
||||
} as unknown as NamespaceStore;
|
||||
|
||||
const clusterFrameContextFake = new ClusterFrameContext(
|
||||
clusterStub,
|
||||
@ -321,7 +323,7 @@ export const getApplicationBuilder = () => {
|
||||
await startFrame();
|
||||
|
||||
const render = renderFor(rendererDi);
|
||||
const history = rendererDi.inject(observableHistoryInjectable);
|
||||
const history = rendererDi.inject(historyInjectable) as any;
|
||||
const currentRouteComponent = rendererDi.inject(currentRouteComponentInjectable);
|
||||
|
||||
for (const callback of beforeRenderCallbacks) {
|
||||
|
||||
@ -18,12 +18,13 @@ const createClusterInjectable = getInjectable({
|
||||
logger: di.inject(loggerInjectable),
|
||||
|
||||
// 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.");},
|
||||
createContextHandler: () => undefined,
|
||||
createContextHandler: () => undefined as never,
|
||||
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."); },
|
||||
detectorRegistry: undefined,
|
||||
detectorRegistry: undefined as never,
|
||||
createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
};
|
||||
|
||||
|
||||
@ -34,11 +34,15 @@ import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-
|
||||
import hostedClusterIdInjectable from "../common/cluster-store/hosted-cluster-id.injectable";
|
||||
import type { GetDiForUnitTestingOptions } from "../test-utils/get-dis-for-unit-testing";
|
||||
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 lensResourcesDirInjectable from "../common/vars/lens-resources-dir.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 = {}) => {
|
||||
const {
|
||||
@ -75,6 +79,11 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
|
||||
|
||||
di.override(lensResourcesDirInjectable, () => "/irrelevant");
|
||||
|
||||
di.override(ipcRendererInjectable, () => ({
|
||||
invoke: () => {},
|
||||
on: () => {},
|
||||
}) as unknown as IpcRenderer);
|
||||
|
||||
di.override(broadcastMessageInjectable, () => () => {
|
||||
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
|
||||
di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore);
|
||||
|
||||
di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} }));
|
||||
|
||||
di.override(
|
||||
userStoreInjectable,
|
||||
() =>
|
||||
({
|
||||
isTableColumnHidden: () => false,
|
||||
extensionRegistryUrl: { customUrl: "some-custom-url" },
|
||||
syncKubeconfigEntries: observable.map(),
|
||||
terminalConfig: { fontSize: 42 },
|
||||
editorConfiguration: { minimap: {}, tabSize: 42, fontSize: 42 },
|
||||
} as unknown as UserStore),
|
||||
);
|
||||
|
||||
@ -113,12 +128,6 @@ export const getDiForUnitTesting = (opts: GetDiForUnitTestingOptions = {}) => {
|
||||
info: noop,
|
||||
silly: noop,
|
||||
}));
|
||||
|
||||
di.override(themeStoreInjectable, () => ({
|
||||
activeTheme: {
|
||||
type: "some-active-theme-type",
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
return di;
|
||||
|
||||
@ -10,6 +10,7 @@ import historyInjectable from "./history.injectable";
|
||||
|
||||
const observableHistoryInjectable = getInjectable({
|
||||
id: "observable-history",
|
||||
|
||||
instantiate: (di) => {
|
||||
const history = di.inject(historyInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* 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 type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
||||
@ -46,7 +46,7 @@ export default extensionRouteRegistratorInjectable;
|
||||
|
||||
const toRouteInjectableFor =
|
||||
(
|
||||
di: DiContainerForInstantiate,
|
||||
di: DiContainerForInjection,
|
||||
extension: LensRendererExtension,
|
||||
extensionInstallationCount: number,
|
||||
) =>
|
||||
|
||||
@ -87,8 +87,8 @@ export const overrideIpcBridge = ({
|
||||
mainDi.override(
|
||||
sendToChannelInElectronBrowserWindowInjectable,
|
||||
() =>
|
||||
(browserWindow, { channel: channelName, data }: SendToViewArgs) => {
|
||||
const handles = rendererIpcFakeHandles.get(channelName);
|
||||
(browserWindow, { channel: channelName, data = [] }: SendToViewArgs) => {
|
||||
const handles = rendererIpcFakeHandles.get(channelName) || [];
|
||||
|
||||
if (isEmpty(handles)) {
|
||||
throw new Error(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user