From 0fd48affd8edf9d31063eef323d60c925af50fe4 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 17 Feb 2023 14:39:53 -0500 Subject: [PATCH] Split out rest of initClusterFrame to runnables Signed-off-by: Sebastian Malton --- packages/core/src/common/cluster/cluster.ts | 6 +- packages/core/src/renderer/bootstrap.tsx | 5 -- .../cluster-frame-cluster.injectable.ts | 20 +++++ .../add-close-frame-handling.injectable.ts | 22 +++++ ...mit-open-cluster-frame-event.injectable.ts | 33 ++++++++ .../init-cluster-frame.injectable.ts | 80 ------------------- ...ions-after-catalog-populates.injectable.ts | 48 +++++++++++ ...me-close.global-override-for-injectable.ts | 9 +++ .../on-cluster-frame-close.injectable.ts | 36 +++++++++ ...cluster-to-finish-activating.injectable.ts | 32 ++++++++ 10 files changed, 201 insertions(+), 90 deletions(-) create mode 100644 packages/core/src/renderer/cluster-frame-context/cluster-frame-cluster.injectable.ts create mode 100644 packages/core/src/renderer/frames/cluster-frame/add-close-frame-handling.injectable.ts create mode 100644 packages/core/src/renderer/frames/cluster-frame/emit-open-cluster-frame-event.injectable.ts delete mode 100644 packages/core/src/renderer/frames/cluster-frame/init-cluster-frame.injectable.ts create mode 100644 packages/core/src/renderer/frames/cluster-frame/load-extensions-after-catalog-populates.injectable.ts create mode 100644 packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.global-override-for-injectable.ts create mode 100644 packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.injectable.ts create mode 100644 packages/core/src/renderer/frames/cluster-frame/wait-for-cluster-to-finish-activating.injectable.ts diff --git a/packages/core/src/common/cluster/cluster.ts b/packages/core/src/common/cluster/cluster.ts index f00d9c3f89..2c643d36ba 100644 --- a/packages/core/src/common/cluster/cluster.ts +++ b/packages/core/src/common/cluster/cluster.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { action, comparer, computed, makeObservable, observable, reaction, runInAction, when } from "mobx"; +import { action, comparer, computed, makeObservable, observable, reaction, runInAction } from "mobx"; import type { ClusterContextHandler } from "../../main/context-handler/context-handler"; import type { KubeConfig } from "@kubernetes/client-node"; import { HttpError } from "@kubernetes/client-node"; @@ -76,10 +76,6 @@ export class Cluster implements ClusterModel { return this._proxyKubeconfigManager; } - get whenReady() { - return when(() => this.ready); - } - /** * Kubeconfig context name * diff --git a/packages/core/src/renderer/bootstrap.tsx b/packages/core/src/renderer/bootstrap.tsx index 949e10e687..2bc726331a 100644 --- a/packages/core/src/renderer/bootstrap.tsx +++ b/packages/core/src/renderer/bootstrap.tsx @@ -11,7 +11,6 @@ import { DefaultProps } from "./mui-base-theme"; import { DiContextProvider } from "@ogre-tools/injectable-react"; import type { DiContainer } from "@ogre-tools/injectable"; import initRootFrameInjectable from "./frames/root-frame/init-root-frame.injectable"; -import initClusterFrameInjectable from "./frames/cluster-frame/init-cluster-frame.injectable"; import { Router } from "react-router"; import historyInjectable from "./navigation/history.injectable"; import startFrameInjectable from "./start-frame/start-frame.injectable"; @@ -30,10 +29,6 @@ export async function bootstrap(di: DiContainer) { const initRootFrame = di.inject(initRootFrameInjectable); await initRootFrame(); - } else { - const initClusterFrame = di.inject(initClusterFrameInjectable); - - await initClusterFrame(); } } catch (error) { console.error(`[BOOTSTRAP]: view initialization error: ${error}`, { diff --git a/packages/core/src/renderer/cluster-frame-context/cluster-frame-cluster.injectable.ts b/packages/core/src/renderer/cluster-frame-context/cluster-frame-cluster.injectable.ts new file mode 100644 index 0000000000..19d68c21af --- /dev/null +++ b/packages/core/src/renderer/cluster-frame-context/cluster-frame-cluster.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 assert from "assert"; +import hostedClusterInjectable from "./hosted-cluster.injectable"; + +const clusterFrameClusterInjectable = getInjectable({ + id: "cluster-frame-cluster", + instantiate: (di) => { + const cluster = di.inject(hostedClusterInjectable); + + assert(cluster, "This can only be injected within a cluster frame"); + + return cluster; + }, +}); + +export default clusterFrameClusterInjectable; diff --git a/packages/core/src/renderer/frames/cluster-frame/add-close-frame-handling.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/add-close-frame-handling.injectable.ts new file mode 100644 index 0000000000..263503ff4f --- /dev/null +++ b/packages/core/src/renderer/frames/cluster-frame/add-close-frame-handling.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 { beforeClusterFrameStartsSecondInjectionToken } from "../../before-frame-starts/tokens"; +import handleOnClusterFrameCloseInjectable from "./on-cluster-frame-close.injectable"; + +const addCloseFrameHandlingInjectable = getInjectable({ + id: "add-close-frame-handling", + instantiate: (di) => ({ + id: "add-close-frame-handling", + run: () => { + const handleOnClusterFrameClose = di.inject(handleOnClusterFrameCloseInjectable); + + handleOnClusterFrameClose(); + }, + }), + injectionToken: beforeClusterFrameStartsSecondInjectionToken, +}); + +export default addCloseFrameHandlingInjectable; diff --git a/packages/core/src/renderer/frames/cluster-frame/emit-open-cluster-frame-event.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/emit-open-cluster-frame-event.injectable.ts new file mode 100644 index 0000000000..d44028206f --- /dev/null +++ b/packages/core/src/renderer/frames/cluster-frame/emit-open-cluster-frame-event.injectable.ts @@ -0,0 +1,33 @@ +/** + * 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 emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; +import { beforeClusterFrameStartsSecondInjectionToken } from "../../before-frame-starts/tokens"; +import clusterFrameClusterInjectable from "../../cluster-frame-context/cluster-frame-cluster.injectable"; + +const emitOpenClusterFrameEventInjectable = getInjectable({ + id: "emit-open-cluster-frame-event", + instantiate: (di) => ({ + id: "emit-open-cluster-frame-event", + run: () => { + const emitAppEvent = di.inject(emitAppEventInjectable); + const cluster = di.inject(clusterFrameClusterInjectable); + + // use setTimeout to remove this from the order of operations + setTimeout(() => { + emitAppEvent({ + name: "cluster", + action: "open", + params: { + clusterId: cluster.id, + }, + }); + }); + }, + }), + injectionToken: beforeClusterFrameStartsSecondInjectionToken, +}); + +export default emitOpenClusterFrameEventInjectable; diff --git a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame.injectable.ts deleted file mode 100644 index a08117046f..0000000000 --- a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame.injectable.ts +++ /dev/null @@ -1,80 +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 catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; -import frameRoutingIdInjectable from "../../../features/electron/renderer/frame-routing-id.injectable"; -import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable"; -import assert from "assert"; -import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; -import showErrorNotificationInjectable from "../../components/notifications/show-error-notification.injectable"; -import autoInitExtensionsInjectable from "../../../features/extensions/loader/common/auto-init-extensions.injectable"; -import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; -import { when } from "mobx"; -import requestSetClusterFrameIdInjectable from "../../../features/cluster/frame-id/renderer/request-set-frame-id.injectable"; -import unmountRootComponentInjectable from "../../window/unmount-root-component.injectable"; - -const initClusterFrameInjectable = getInjectable({ - id: "init-cluster-frame", - - instantiate: (di) => { - const hostedCluster = di.inject(hostedClusterInjectable); - - assert(hostedCluster, "This can only be injected within a cluster frame"); - - const autoInitExtensions = di.inject(autoInitExtensionsInjectable); - const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); - const frameRoutingId = di.inject(frameRoutingIdInjectable); - const emitAppEvent = di.inject(emitAppEventInjectable); - const logger = di.inject(prefixedLoggerInjectable, "CLUSTER-FRAME"); - const showErrorNotification = di.inject(showErrorNotificationInjectable); - const requestSetClusterFrameId = di.inject(requestSetClusterFrameIdInjectable); - const unmountRootComponent = di.inject(unmountRootComponentInjectable); - - return async () => { - logger.info(`Init dashboard, clusterId=${hostedCluster.id}, frameId=${frameRoutingId}`); - - await requestSetClusterFrameId(hostedCluster.id); - await hostedCluster.whenReady; // cluster.activate() is done at this point - - catalogEntityRegistry.activeEntity = hostedCluster.id; - - // Only load the extensions once the catalog has been populated. - // Note that the Catalog might still have unprocessed entities until the extensions are fully loaded. - when( - () => catalogEntityRegistry.items.get().length > 0, - () => - autoInitExtensions(), - { - timeout: 15_000, - onError: (error) => { - logger.warn( - "[CLUSTER-FRAME]: error from activeEntity when()", - error, - ); - - showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded."); - }, - }, - ); - - setTimeout(() => { - emitAppEvent({ - name: "cluster", - action: "open", - params: { - clusterId: hostedCluster.id, - }, - }); - }); - - window.addEventListener("beforeunload", () => { - logger.info(`Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`); - unmountRootComponent(); - }); - }; - }, -}); - -export default initClusterFrameInjectable; diff --git a/packages/core/src/renderer/frames/cluster-frame/load-extensions-after-catalog-populates.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/load-extensions-after-catalog-populates.injectable.ts new file mode 100644 index 0000000000..2951211bd0 --- /dev/null +++ b/packages/core/src/renderer/frames/cluster-frame/load-extensions-after-catalog-populates.injectable.ts @@ -0,0 +1,48 @@ +/** + * 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 { when } from "mobx"; +import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; +import autoInitExtensionsInjectable from "../../../features/extensions/loader/common/auto-init-extensions.injectable"; +import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; +import { beforeClusterFrameStartsSecondInjectionToken } from "../../before-frame-starts/tokens"; +import clusterFrameClusterInjectable from "../../cluster-frame-context/cluster-frame-cluster.injectable"; +import showErrorNotificationInjectable from "../../components/notifications/show-error-notification.injectable"; +import waitForClusterToFinishActivatingInjectable from "./wait-for-cluster-to-finish-activating.injectable"; + +const loadExtensionsAfterCatalogPopulatesInjectable = getInjectable({ + id: "load-extensions-after-catalog-populates", + instantiate: (di) => ({ + id: "load-extensions-after-catalog-populates", + run: async () => { + const cluster = di.inject(clusterFrameClusterInjectable); + const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); + const autoInitExtensions = di.inject(autoInitExtensionsInjectable); + const logger = di.inject(prefixedLoggerInjectable, "CLUSTER-FRAME"); + const showErrorNotification = di.inject(showErrorNotificationInjectable); + + catalogEntityRegistry.activeEntity = cluster.id; + + // Only load the extensions once the catalog has been populated. + // Note that the Catalog might still have unprocessed entities until the extensions are fully loaded. + when( + () => catalogEntityRegistry.items.get().length > 0, + () => + autoInitExtensions(), + { + timeout: 15_000, + onError: (error) => { + logger.warn("error from activeEntity when()", error); + showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded."); + }, + }, + ); + }, + runAfter: di.inject(waitForClusterToFinishActivatingInjectable), + }), + injectionToken: beforeClusterFrameStartsSecondInjectionToken, +}); + +export default loadExtensionsAfterCatalogPopulatesInjectable; diff --git a/packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.global-override-for-injectable.ts b/packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.global-override-for-injectable.ts new file mode 100644 index 0000000000..c451c63141 --- /dev/null +++ b/packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.global-override-for-injectable.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "../../../common/test-utils/get-global-override"; +import handleOnClusterFrameCloseInjectable from "./on-cluster-frame-close.injectable"; + +export default getGlobalOverride(handleOnClusterFrameCloseInjectable, () => () => {}); diff --git a/packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.injectable.ts new file mode 100644 index 0000000000..42bfe712a1 --- /dev/null +++ b/packages/core/src/renderer/frames/cluster-frame/on-cluster-frame-close.injectable.ts @@ -0,0 +1,36 @@ +/** + * 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 { once } from "lodash"; +import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; +import frameRoutingIdInjectable from "../../../features/electron/renderer/frame-routing-id.injectable"; +import clusterFrameClusterInjectable from "../../cluster-frame-context/cluster-frame-cluster.injectable"; +import closeRendererLogFileInjectable from "../../logger/close-renderer-log-file.injectable"; +import unmountRootComponentInjectable from "../../window/unmount-root-component.injectable"; + +const handleOnClusterFrameCloseInjectable = getInjectable({ + id: "handle-on-cluster-frame-close", + instantiate: (di) => { + const cluster = di.inject(clusterFrameClusterInjectable); + const frameRoutingId = di.inject(frameRoutingIdInjectable); + const logger = di.inject(prefixedLoggerInjectable, "CLUSTER-FRAME"); + const closeFileLogging = di.inject(closeRendererLogFileInjectable); + const unmountRootComponent = di.inject(unmountRootComponentInjectable); + + const onCloseFrame = once(() => { + logger.info(`Unload dashboard, clusterId=${(cluster.id)}, frameId=${frameRoutingId}`); + closeFileLogging(); + unmountRootComponent(); + }); + + return () => { + window.addEventListener("beforeunload", onCloseFrame); + window.addEventListener("pagehide", onCloseFrame); + }; + }, + causesSideEffects: true, +}); + +export default handleOnClusterFrameCloseInjectable; diff --git a/packages/core/src/renderer/frames/cluster-frame/wait-for-cluster-to-finish-activating.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/wait-for-cluster-to-finish-activating.injectable.ts new file mode 100644 index 0000000000..c0279be5c6 --- /dev/null +++ b/packages/core/src/renderer/frames/cluster-frame/wait-for-cluster-to-finish-activating.injectable.ts @@ -0,0 +1,32 @@ +/** + * 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 { when } from "mobx"; +import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; +import requestSetClusterFrameIdInjectable from "../../../features/cluster/frame-id/renderer/request-set-frame-id.injectable"; +import frameRoutingIdInjectable from "../../../features/electron/renderer/frame-routing-id.injectable"; +import { beforeClusterFrameStartsSecondInjectionToken } from "../../before-frame-starts/tokens"; +import clusterFrameClusterInjectable from "../../cluster-frame-context/cluster-frame-cluster.injectable"; + +const waitForClusterToFinishActivatingInjectable = getInjectable({ + id: "wait-for-cluster-to-finish-activating", + instantiate: (di) => ({ + id: "wait-for-cluster-to-finish-activating", + run: async () => { + const cluster = di.inject(clusterFrameClusterInjectable); + const requestSetClusterFrameId = di.inject(requestSetClusterFrameIdInjectable); + const logger = di.inject(prefixedLoggerInjectable, "CLUSTER-FRAME"); + const frameRoutingId = di.inject(frameRoutingIdInjectable); + + logger.info(`Init dashboard, clusterId=${cluster.id}, frameId=${frameRoutingId}`); + + await requestSetClusterFrameId(cluster.id); + await when(() => cluster.ready); // cluster.activate() is done at this point + }, + }), + injectionToken: beforeClusterFrameStartsSecondInjectionToken, +}); + +export default waitForClusterToFinishActivatingInjectable;