From aec299feb43c13d28714a624a282582c5034f42c Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 23 Aug 2022 16:19:40 -0400 Subject: [PATCH] Fix flakiness and improve tests for DeleteClusterDialog Signed-off-by: Sebastian Malton --- .../catalog/filtered-categories.injectable.ts | 18 + src/common/fs/delete-file.injectable.ts | 15 + src/common/ipc/cluster.ts | 3 - .../request-from-channel-injection-token.ts | 2 +- .../delete-cluster-dialog.test.tsx.snap | 2187 +++++++++++++++++ .../clear-as-deleting-channel.injectable.ts | 20 + .../common/delete-channel.injectable.ts | 20 + .../set-as-deleting-channel.injectable.ts | 20 + .../delete-cluster-dialog.test.tsx | 283 +++ ...as-deleteing-channel-handler.injectable.ts | 23 + .../main/delete-channel-handler.injectable.ts | 56 + ...as-deleteing-channel-handler.injectable.ts | 23 + .../request-clear-as-deleting.injectable.ts | 22 + .../renderer/request-delete.injectable.ts | 22 + .../request-set-as-deleting.injectable.ts | 22 + ...elm-repository-in-preferences.test.ts.snap | 4 +- ...tom-helm-repository-in-preferences.test.ts | 3 + ...sters-that-are-being-deleted.injectable.ts | 14 + .../setup-ipc-main-handlers.injectable.ts | 10 - .../setup-ipc-main-handlers.ts | 46 +- .../get-helm-chart-versions.injectable.ts | 6 +- .../components/+catalog/catalog-menu.tsx | 86 +- src/renderer/components/animate/animate.tsx | 45 +- .../__tests__/delete-cluster-dialog.test.tsx | 275 --- ...luster-frame-child-component.injectable.ts | 2 - .../delete-cluster-dialog/save-config.ts | 21 - ...beconfig.global-override-for-injectable.ts | 11 + .../save-kubeconfig.injectable.ts | 35 + .../components/delete-cluster-dialog/view.tsx | 52 +- src/renderer/components/dialog/dialog.tsx | 6 +- .../test-utils/get-application-builder.tsx | 24 + src/renderer/getDiForUnitTesting.tsx | 2 - src/renderer/ipc/index.ts | 14 +- src/test-utils/override-fs-with-fakes.ts | 8 +- 34 files changed, 2936 insertions(+), 464 deletions(-) create mode 100644 src/common/catalog/filtered-categories.injectable.ts create mode 100644 src/common/fs/delete-file.injectable.ts create mode 100644 src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap create mode 100644 src/features/cluster/delete-dialog/common/clear-as-deleting-channel.injectable.ts create mode 100644 src/features/cluster/delete-dialog/common/delete-channel.injectable.ts create mode 100644 src/features/cluster/delete-dialog/common/set-as-deleting-channel.injectable.ts create mode 100644 src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx create mode 100644 src/features/cluster/delete-dialog/main/clear-as-deleteing-channel-handler.injectable.ts create mode 100644 src/features/cluster/delete-dialog/main/delete-channel-handler.injectable.ts create mode 100644 src/features/cluster/delete-dialog/main/set-as-deleteing-channel-handler.injectable.ts create mode 100644 src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts create mode 100644 src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts create mode 100644 src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts create mode 100644 src/main/clusters-that-are-being-deleted.injectable.ts delete mode 100644 src/renderer/components/delete-cluster-dialog/__tests__/delete-cluster-dialog.test.tsx delete mode 100644 src/renderer/components/delete-cluster-dialog/save-config.ts create mode 100644 src/renderer/components/delete-cluster-dialog/save-kubeconfig.global-override-for-injectable.ts create mode 100644 src/renderer/components/delete-cluster-dialog/save-kubeconfig.injectable.ts diff --git a/src/common/catalog/filtered-categories.injectable.ts b/src/common/catalog/filtered-categories.injectable.ts new file mode 100644 index 0000000000..c84d527ff2 --- /dev/null +++ b/src/common/catalog/filtered-categories.injectable.ts @@ -0,0 +1,18 @@ +/** + * 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 { computed } from "mobx"; +import catalogCategoryRegistryInjectable from "./category-registry.injectable"; + +const filteredCategoriesInjectable = getInjectable({ + id: "filtered-categories", + instantiate: (di) => { + const registry = di.inject(catalogCategoryRegistryInjectable); + + return computed(() => [...registry.filteredItems]); + }, +}); + +export default filteredCategoriesInjectable; diff --git a/src/common/fs/delete-file.injectable.ts b/src/common/fs/delete-file.injectable.ts new file mode 100644 index 0000000000..57aba5b379 --- /dev/null +++ b/src/common/fs/delete-file.injectable.ts @@ -0,0 +1,15 @@ +/** + * 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 fsInjectable from "./fs.injectable"; + +export type DeleteFile = (filePath: string) => Promise; + +const deleteFileInjectable = getInjectable({ + id: "delete-file", + instantiate: (di): DeleteFile => di.inject(fsInjectable).unlink, +}); + +export default deleteFileInjectable; diff --git a/src/common/ipc/cluster.ts b/src/common/ipc/cluster.ts index 9f69ff42d5..c5bec1f59f 100644 --- a/src/common/ipc/cluster.ts +++ b/src/common/ipc/cluster.ts @@ -8,9 +8,6 @@ export const clusterSetFrameIdHandler = "cluster:set-frame-id"; export const clusterVisibilityHandler = "cluster:visibility"; export const clusterRefreshHandler = "cluster:refresh"; export const clusterDisconnectHandler = "cluster:disconnect"; -export const clusterDeleteHandler = "cluster:delete"; -export const clusterSetDeletingHandler = "cluster:deleting:set"; -export const clusterClearDeletingHandler = "cluster:deleting:clear"; export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all"; export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; export const clusterStates = "cluster:states"; diff --git a/src/common/utils/channel/request-from-channel-injection-token.ts b/src/common/utils/channel/request-from-channel-injection-token.ts index 5f4492543f..f4d4fdbe0c 100644 --- a/src/common/utils/channel/request-from-channel-injection-token.ts +++ b/src/common/utils/channel/request-from-channel-injection-token.ts @@ -12,7 +12,7 @@ export type RequestFromChannel = < channel: TChannel, ...request: TChannel["_requestSignature"] extends void ? [] - : [TChannel["_requestSignature"]] + : [SetRequired["_requestSignature"]] ) => Promise["_responseSignature"]>; export const requestFromChannelInjectionToken = diff --git a/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap b/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap new file mode 100644 index 0000000000..93b067c645 --- /dev/null +++ b/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap @@ -0,0 +1,2187 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Deleting a cluster when an internal kubeconfig cluster is used when the dialog is opened renders 1`] = ` + +
+
+
+
+ + + home + + + + + arrow_back + + + + + arrow_forward + + +
+
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ + +`; + +exports[`Deleting a cluster when the kubeconfig has multiple clusters when the dialog is opened for not the current cluster renders 1`] = ` + +
+
+
+
+ + + home + + + + + arrow_back + + + + + arrow_forward + + +
+
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ + +`; + +exports[`Deleting a cluster when the kubeconfig has multiple clusters when the dialog is opened for not the current cluster when context switching checkbox is clicked renders 1`] = ` + +
+
+
+
+ + + home + + + + + arrow_back + + + + + arrow_forward + + +
+
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ + +`; + +exports[`Deleting a cluster when the kubeconfig has multiple clusters when the dialog is opened for the current cluster renders 1`] = ` + +
+
+
+
+ + + home + + + + + arrow_back + + + + + arrow_forward + + +
+
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ + +`; + +exports[`Deleting a cluster when the kubeconfig has only one cluster when the dialog is opened renders 1`] = ` + +
+
+
+
+ + + home + + + + + arrow_back + + + + + arrow_forward + + +
+
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ + +`; diff --git a/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.injectable.ts b/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.injectable.ts new file mode 100644 index 0000000000..d45fecb3c2 --- /dev/null +++ b/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.injectable.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import type { RequestChannel } from "../../../../common/utils/channel/request-channel-injection-token"; +import { requestChannelInjectionToken } from "../../../../common/utils/channel/request-channel-injection-token"; + +export type ClearClusterAsDeletingChannel = RequestChannel; + +const clearClusterAsDeletingChannelInjectable = getInjectable({ + id: "clear-cluster-as-deleting-channel", + instantiate: (): ClearClusterAsDeletingChannel => ({ + id: "clear-cluster-as-deleting", + }), + injectionToken: requestChannelInjectionToken, +}); + +export default clearClusterAsDeletingChannelInjectable; diff --git a/src/features/cluster/delete-dialog/common/delete-channel.injectable.ts b/src/features/cluster/delete-dialog/common/delete-channel.injectable.ts new file mode 100644 index 0000000000..9242b062c5 --- /dev/null +++ b/src/features/cluster/delete-dialog/common/delete-channel.injectable.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import type { RequestChannel } from "../../../../common/utils/channel/request-channel-injection-token"; +import { requestChannelInjectionToken } from "../../../../common/utils/channel/request-channel-injection-token"; + +export type DeleteClusterChannel = RequestChannel; + +const deleteClusterChannelInjectable = getInjectable({ + id: "delete-cluster-channel", + instantiate: (): DeleteClusterChannel => ({ + id: "delete-cluster", + }), + injectionToken: requestChannelInjectionToken, +}); + +export default deleteClusterChannelInjectable; diff --git a/src/features/cluster/delete-dialog/common/set-as-deleting-channel.injectable.ts b/src/features/cluster/delete-dialog/common/set-as-deleting-channel.injectable.ts new file mode 100644 index 0000000000..b625dfa14e --- /dev/null +++ b/src/features/cluster/delete-dialog/common/set-as-deleting-channel.injectable.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import type { RequestChannel } from "../../../../common/utils/channel/request-channel-injection-token"; +import { requestChannelInjectionToken } from "../../../../common/utils/channel/request-channel-injection-token"; + +export type SetClusterAsDeletingChannel = RequestChannel; + +const setClusterAsDeletingChannelInjectable = getInjectable({ + id: "set-cluster-as-deleting-channel", + instantiate: (): SetClusterAsDeletingChannel => ({ + id: "set-cluster-as-deleting", + }), + injectionToken: requestChannelInjectionToken, +}); + +export default setClusterAsDeletingChannelInjectable; diff --git a/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx b/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx new file mode 100644 index 0000000000..1742dadb6f --- /dev/null +++ b/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx @@ -0,0 +1,283 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import "@testing-library/jest-dom/extend-expect"; +import { KubeConfig } from "@kubernetes/client-node"; +import type { RenderResult } from "@testing-library/react"; +import type { CreateCluster } 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 createKubeconfigManagerInjectable from "../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable"; +import normalizedPlatformInjectable from "../../../common/vars/normalized-platform.injectable"; +import kubectlBinaryNameInjectable from "../../../main/kubectl/binary-name.injectable"; +import kubectlDownloadingNormalizedArchInjectable from "../../../main/kubectl/normalized-arch.injectable"; +import openDeleteClusterDialogInjectable, { type OpenDeleteClusterDialog } from "../../../renderer/components/delete-cluster-dialog/open.injectable"; +import { type ApplicationBuilder, getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; +import storesAndApisCanBeCreatedInjectable from "../../../renderer/stores-apis-can-be-created.injectable"; +import type { Cluster } from "../../../common/cluster/cluster"; +import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; +import appEventBusInjectable from "../../../common/app-event-bus/app-event-bus.injectable"; +import path from "path"; +import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; + +const currentClusterServerUrl = "https://localhost"; +const nonCurrentClusterServerUrl = "http://localhost"; +const multiClusterConfig = ` +apiVersion: v1 +clusters: +- cluster: + server: ${currentClusterServerUrl} + name: some-current-context-cluster +- cluster: + server: ${nonCurrentClusterServerUrl} + name: some-non-current-context-cluster +contexts: +- context: + cluster: some-current-context-cluster + user: some-user + name: some-current-context +- 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: some-user + user: + token: kubeconfig-user-q4lm4:xxxyyyy +`; + +const singleClusterServerUrl = "http://localhost"; +const singleClusterConfig = ` +apiVersion: v1 +clusters: +- cluster: + server: ${singleClusterServerUrl} + name: some-cluster +contexts: +- context: + cluster: some-cluster + user: some-user + name: some-context +current-context: some-context +kind: Config +preferences: {} +users: +- name: some-user + user: + token: kubeconfig-user-q4lm4:xxxyyyy +`; + +describe("Deleting a cluster", () => { + let builder: ApplicationBuilder; + let openDeleteClusterDialog: OpenDeleteClusterDialog; + let createCluster: CreateCluster; + let rendered: RenderResult; + let config: KubeConfig; + + beforeEach(async () => { + config = new KubeConfig(); + builder = getApplicationBuilder(); + + builder.beforeApplicationStart((mainDi) => { + mainDi.override(createContextHandlerInjectable, () => () => undefined as never); + mainDi.override(createKubeconfigManagerInjectable, () => () => undefined as never); + mainDi.override(kubectlBinaryNameInjectable, () => "kubectl"); + mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64"); + mainDi.override(normalizedPlatformInjectable, () => "darwin"); + }); + + builder.beforeWindowStart((windowDi) => { + windowDi.override(storesAndApisCanBeCreatedInjectable, () => true); + openDeleteClusterDialog = windowDi.inject(openDeleteClusterDialogInjectable); + + // TODO: remove this line when all global uses of appEventBus are removed + windowDi.permitSideEffects(appEventBusInjectable); + }); + + builder.afterWindowStart(windowDi => { + createCluster = windowDi.inject(createClusterInjectionToken); + + const navigateToCatalog = windowDi.inject(navigateToCatalogInjectable); + + navigateToCatalog(); + }); + + rendered = await builder.render(); + }); + + describe("when the kubeconfig has multiple clusters", () => { + let currentCluster: Cluster; + let nonCurrentCluster: Cluster; + + beforeEach(() => { + config.loadFromString(multiClusterConfig); + + currentCluster = createCluster({ + id: "some-current-context-cluster", + contextName: "some-current-context", + preferences: { + clusterName: "some-current-context-cluster", + }, + kubeConfigPath: "./temp-kube-config", + }, { + clusterServerUrl: currentClusterServerUrl, + }); + nonCurrentCluster = createCluster({ + id: "some-non-current-context-cluster", + contextName: "some-non-current-context", + preferences: { + clusterName: "some-non-current-context-cluster", + }, + kubeConfigPath: "./temp-kube-config", + }, { + clusterServerUrl: currentClusterServerUrl, + }); + }); + + describe("when the dialog is opened for the current cluster", () => { + // TODO: replace with actual behaviour instead of technical use + beforeEach(async () => { + openDeleteClusterDialog({ + cluster: currentCluster, + config, + }); + + await rendered.findByTestId("delete-cluster-dialog"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows context switcher", () => { + expect(rendered.queryByText("Select new context...")).toBeInTheDocument(); + }); + + it("shows warning", () => { + expect(rendered.queryByTestId("current-context-warning")).toBeInTheDocument(); + }); + }); + + describe("when the dialog is opened for not the current cluster", () => { + // TODO: replace with actual behaviour instead of technical use + beforeEach(async () => { + openDeleteClusterDialog({ + cluster: nonCurrentCluster, + config, + }); + + await rendered.findByTestId("delete-cluster-dialog"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows warning", () => { + expect(rendered.queryByTestId("kubeconfig-change-warning")).toBeInTheDocument(); + }); + + it("does not show context switcher", () => { + expect(rendered.queryByText("Select new context...")).not.toBeInTheDocument(); + }); + + describe("when context switching checkbox is clicked", () => { + beforeEach(() => { + rendered.getByTestId("delete-cluster-dialog-context-switch").click(); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows context switcher", () => { + expect(rendered.queryByText("Select new context...")).toBeInTheDocument(); + }); + }); + }); + }); + + describe("when an internal kubeconfig cluster is used", () => { + let currentCluster: Cluster; + + beforeEach(() => { + config.loadFromString(singleClusterConfig); + + const directoryForKubeConfigs = builder.applicationWindow.only.di.inject(directoryForKubeConfigsInjectable); + + currentCluster = createCluster({ + id: "some-cluster", + contextName: "some-context", + preferences: { + clusterName: "some-cluster", + }, + kubeConfigPath: path.join(directoryForKubeConfigs, "some-cluster.json"), + }, { + clusterServerUrl: singleClusterServerUrl, + }); + }); + + describe("when the dialog is opened", () => { + // TODO: replace with actual behaviour instead of technical use + beforeEach(async () => { + openDeleteClusterDialog({ + cluster: currentCluster, + config, + }); + + await rendered.findByTestId("delete-cluster-dialog"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows warning", () => { + expect(rendered.queryByTestId("internal-kubeconfig-warning")).toBeInTheDocument(); + }); + }); + }); + + describe("when the kubeconfig has only one cluster", () => { + let currentCluster: Cluster; + + beforeEach(() => { + config.loadFromString(singleClusterConfig); + + currentCluster = createCluster({ + id: "some-cluster", + contextName: "some-context", + preferences: { + clusterName: "some-cluster", + }, + kubeConfigPath: "./temp-kube-config", + }, { + clusterServerUrl: singleClusterServerUrl, + }); + }); + + describe("when the dialog is opened", () => { + // TODO: replace with actual behaviour instead of technical use + beforeEach(async () => { + openDeleteClusterDialog({ + cluster: currentCluster, + config, + }); + + await rendered.findByTestId("delete-cluster-dialog"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows warning", () => { + expect(rendered.queryByTestId("no-more-contexts-warning")).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/src/features/cluster/delete-dialog/main/clear-as-deleteing-channel-handler.injectable.ts b/src/features/cluster/delete-dialog/main/clear-as-deleteing-channel-handler.injectable.ts new file mode 100644 index 0000000000..2762c44a77 --- /dev/null +++ b/src/features/cluster/delete-dialog/main/clear-as-deleteing-channel-handler.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 { requestChannelListenerInjectionToken } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import clustersThatAreBeingDeletedInjectable from "../../../../main/clusters-that-are-being-deleted.injectable"; +import clearClusterAsDeletingChannelInjectable from "../common/clear-as-deleting-channel.injectable"; + +const clearClusterAsDeletingChannelHandlerInjectable = getInjectable({ + id: "clear-cluster-as-deleting-channel-handler", + instantiate: (di) => { + const clustersThatAreBeingDeleted = di.inject(clustersThatAreBeingDeletedInjectable); + + return { + channel: di.inject(clearClusterAsDeletingChannelInjectable), + handler: (clusterId) => clustersThatAreBeingDeleted.delete(clusterId), + }; + }, + injectionToken: requestChannelListenerInjectionToken, +}); + +export default clearClusterAsDeletingChannelHandlerInjectable; diff --git a/src/features/cluster/delete-dialog/main/delete-channel-handler.injectable.ts b/src/features/cluster/delete-dialog/main/delete-channel-handler.injectable.ts new file mode 100644 index 0000000000..8945ffe625 --- /dev/null +++ b/src/features/cluster/delete-dialog/main/delete-channel-handler.injectable.ts @@ -0,0 +1,56 @@ +/** + * 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 appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable"; +import clusterFramesInjectable from "../../../../common/cluster-frames.injectable"; +import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; +import directoryForLensLocalStorageInjectable from "../../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable"; +import deleteFileInjectable from "../../../../common/fs/delete-file.injectable"; +import joinPathsInjectable from "../../../../common/path/join-paths.injectable"; +import { requestChannelListenerInjectionToken } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import deleteClusterChannelInjectable from "../common/delete-channel.injectable"; + +const deleteClusterChannelHandlerInjectable = getInjectable({ + id: "delete-cluster-channel-handler", + instantiate: (di) => { + const appEventBus = di.inject(appEventBusInjectable); + const clusterStore = di.inject(clusterStoreInjectable); + const clusterFrames = di.inject(clusterFramesInjectable); + const joinPaths = di.inject(joinPathsInjectable); + const directoryForLensLocalStorage = di.inject(directoryForLensLocalStorageInjectable); + const deleteFile = di.inject(deleteFileInjectable); + + return { + channel: di.inject(deleteClusterChannelInjectable), + handler: async (clusterId) =>{ + appEventBus.emit({ name: "cluster", action: "remove" }); + + const cluster = clusterStore.getById(clusterId); + + if (!cluster) { + return; + } + + cluster.disconnect(); + clusterFrames.delete(cluster.id); + + // Remove from the cluster store as well, this should clear any old settings + clusterStore.clusters.delete(cluster.id); + + try { + // remove the local storage file + const localStorageFilePath = joinPaths(directoryForLensLocalStorage, `${cluster.id}.json`); + + await deleteFile(localStorageFilePath); + } catch { + // ignore error + } + }, + }; + }, + injectionToken: requestChannelListenerInjectionToken, +}); + +export default deleteClusterChannelHandlerInjectable; diff --git a/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-handler.injectable.ts b/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-handler.injectable.ts new file mode 100644 index 0000000000..1a8ea2a997 --- /dev/null +++ b/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-handler.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 { requestChannelListenerInjectionToken } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import clustersThatAreBeingDeletedInjectable from "../../../../main/clusters-that-are-being-deleted.injectable"; +import setClusterAsDeletingChannelInjectable from "../common/set-as-deleting-channel.injectable"; + +const setClusterAsDeletingChannelHandlerInjectable = getInjectable({ + id: "set-cluster-as-deleting-channel-handler", + instantiate: (di) => { + const clustersThatAreBeingDeleted = di.inject(clustersThatAreBeingDeletedInjectable); + + return { + channel: di.inject(setClusterAsDeletingChannelInjectable), + handler: (clusterId) => clustersThatAreBeingDeleted.add(clusterId), + }; + }, + injectionToken: requestChannelListenerInjectionToken, +}); + +export default setClusterAsDeletingChannelHandlerInjectable; diff --git a/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts b/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts new file mode 100644 index 0000000000..b480630f6c --- /dev/null +++ b/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import clearClusterAsDeletingChannelInjectable from "../common/clear-as-deleting-channel.injectable"; + +export type RequestClearClusterAsDeleting = (clusterId: ClusterId) => Promise; + +const requestClearClusterAsDeletingInjectable = getInjectable({ + id: "request-clear-cluster-as-deleting", + instantiate: (di): RequestClearClusterAsDeleting => { + const requestChannel = di.inject(requestFromChannelInjectable); + const clearClusterAsDeletingChannel = di.inject(clearClusterAsDeletingChannelInjectable); + + return (clusterId) => requestChannel(clearClusterAsDeletingChannel, clusterId); + }, +}); + +export default requestClearClusterAsDeletingInjectable; diff --git a/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts b/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts new file mode 100644 index 0000000000..602923e60e --- /dev/null +++ b/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import deleteClusterChannelInjectable from "../common/delete-channel.injectable"; + +export type RequestDeleteCluster = (clusterId: ClusterId) => Promise; + +const requestDeleteClusterInjectable = getInjectable({ + id: "request-delete-cluster", + instantiate: (di): RequestDeleteCluster => { + const requestChannel = di.inject(requestFromChannelInjectable); + const deleteClusterChannel = di.inject(deleteClusterChannelInjectable); + + return (clusterId) => requestChannel(deleteClusterChannel, clusterId); + }, +}); + +export default requestDeleteClusterInjectable; diff --git a/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts b/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts new file mode 100644 index 0000000000..997348d44d --- /dev/null +++ b/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import setClusterAsDeletingChannelInjectable from "../common/set-as-deleting-channel.injectable"; + +export type RequestSetClusterAsDeleting = (clusterId: ClusterId) => Promise; + +const requestSetClusterAsDeletingInjectable = getInjectable({ + id: "request-set-cluster-as-deleting", + instantiate: (di): RequestSetClusterAsDeleting => { + const requestChannel = di.inject(requestFromChannelInjectable); + const setClusterAsDeletingChannel = di.inject(setClusterAsDeletingChannelInjectable); + + return (clusterId) => requestChannel(setClusterAsDeletingChannel, clusterId); + }, +}); + +export default requestSetClusterAsDeletingInjectable; diff --git a/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap b/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap index c02c727480..5c936bdb92 100644 --- a/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap +++ b/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap @@ -6916,7 +6916,7 @@ exports[`add custom helm repository in preferences when navigating to preference />