Skip to content

Commit

Permalink
Make ClusterFrameManager fully injectable (#6590)
Browse files Browse the repository at this point in the history
* Make ClusterFrameManager fully injectable

Signed-off-by: Sebastian Malton <[email protected]>

* Fix type errors

Signed-off-by: Sebastian Malton <[email protected]>

Signed-off-by: Sebastian Malton <[email protected]>
  • Loading branch information
Nokel81 authored Nov 22, 2022
1 parent 05f17b3 commit 98e42cf
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 36 deletions.
11 changes: 11 additions & 0 deletions src/common/cluster/visibility-channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/

import type { ClusterId } from "../cluster-types";
import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token";

export const clusterVisibilityChannel: MessageChannel<ClusterId | null> = {
id: "cluster-visibility",
};
1 change: 0 additions & 1 deletion src/common/ipc/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

export const clusterActivateHandler = "cluster:activate";
export const clusterSetFrameIdHandler = "cluster:set-frame-id";
export const clusterVisibilityHandler = "cluster:visibility";
export const clusterRefreshHandler = "cluster:refresh";
export const clusterDisconnectHandler = "cluster:disconnect";
export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all";
Expand Down
2 changes: 2 additions & 0 deletions src/main/cluster/manager.injectable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import clusterStoreInjectable from "../../common/cluster-store/cluster-store.inj
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
import clustersThatAreBeingDeletedInjectable from "./are-being-deleted.injectable";
import { ClusterManager } from "./manager";
import visibleClusterInjectable from "./visible-cluster.injectable";

const clusterManagerInjectable = getInjectable({
id: "cluster-manager",
Expand All @@ -15,6 +16,7 @@ const clusterManagerInjectable = getInjectable({
store: di.inject(clusterStoreInjectable),
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
clustersThatAreBeingDeleted: di.inject(clustersThatAreBeingDeletedInjectable),
visibleCluster: di.inject(visibleClusterInjectable),
}),
});

Expand Down
9 changes: 4 additions & 5 deletions src/main/cluster/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

import "../../common/ipc/cluster";
import type http from "http";
import type { ObservableSet } from "mobx";
import { action, makeObservable, observable, observe, reaction, toJS } from "mobx";
import type { IObservableValue, ObservableSet } from "mobx";
import { action, makeObservable, observe, reaction, toJS } from "mobx";
import type { Cluster } from "../../common/cluster/cluster";
import logger from "../logger";
import { apiKubePrefix } from "../../common/vars";
Expand All @@ -27,11 +27,10 @@ interface Dependencies {
readonly store: ClusterStore;
readonly catalogEntityRegistry: CatalogEntityRegistry;
readonly clustersThatAreBeingDeleted: ObservableSet<ClusterId>;
readonly visibleCluster: IObservableValue<ClusterId | null>;
}

export class ClusterManager {
@observable visibleCluster: ClusterId | undefined = undefined;

constructor(private readonly dependencies: Dependencies) {
makeObservable(this);
}
Expand All @@ -58,7 +57,7 @@ export class ClusterManager {

reaction(() => [
this.dependencies.catalogEntityRegistry.filterItemsByPredicate(isKubernetesCluster),
this.visibleCluster,
this.dependencies.visibleCluster.get(),
] as const, ([entities, visibleCluster]) => {
for (const entity of entities) {
if (entity.getId() === visibleCluster) {
Expand Down
19 changes: 19 additions & 0 deletions src/main/cluster/visibility-handler.injectable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { clusterVisibilityChannel } from "../../common/cluster/visibility-channel";
import { getMessageChannelListenerInjectable } from "../../common/utils/channel/message-channel-listener-injection-token";
import visibleClusterInjectable from "./visible-cluster.injectable";

const clusterVisibilityHandlerInjectable = getMessageChannelListenerInjectable({
channel: clusterVisibilityChannel,
id: "base",
handler: (di) => {
const visibleCluster = di.inject(visibleClusterInjectable);

return (clusterId) => visibleCluster.set(clusterId);
},
});

export default clusterVisibilityHandlerInjectable;
14 changes: 14 additions & 0 deletions src/main/cluster/visible-cluster.injectable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* 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 { observable } from "mobx";
import type { ClusterId } from "../../common/cluster-types";

const visibleClusterInjectable = getInjectable({
id: "visible-cluster",
instantiate: () => observable.box<ClusterId | null>(null),
});

export default visibleClusterInjectable;
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import { getInjectable } from "@ogre-tools/injectable";
import { setupIpcMainHandlers } from "./setup-ipc-main-handlers";
import loggerInjectable from "../../../../common/logger.injectable";
import clusterManagerInjectable from "../../../cluster/manager.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";
Expand All @@ -20,7 +19,6 @@ const setupIpcMainHandlersInjectable = getInjectable({

instantiate: (di) => {
const logger = di.inject(loggerInjectable);
const clusterManager = di.inject(clusterManagerInjectable);
const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable);
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
const clusterStore = di.inject(clusterStoreInjectable);
Expand All @@ -36,7 +34,6 @@ const setupIpcMainHandlersInjectable = getInjectable({

setupIpcMainHandlers({
applicationMenuItemComposite,
clusterManager,
catalogEntityRegistry,
clusterStore,
operatingSystemTheme,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
import type { IpcMainInvokeEvent } from "electron";
import { BrowserWindow, Menu } from "electron";
import { clusterFrameMap } from "../../../../common/cluster-frames";
import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster";
import { clusterActivateHandler, clusterSetFrameIdHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster";
import type { ClusterId } from "../../../../common/cluster-types";
import { ClusterStore } from "../../../../common/cluster-store/cluster-store";
import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc";
import type { CatalogEntityRegistry } from "../../../catalog";
import { pushCatalogToRenderer } from "../../../catalog-pusher";
import type { ClusterManager } from "../../../cluster/manager";
import type { IComputedValue } from "mobx";
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window";
import { handleWindowAction, onLocationChange } from "../../../ipc/window";
Expand All @@ -28,7 +27,6 @@ import type { CreateResourceApplier } from "../../../resource-applier/create-res

interface Dependencies {
applicationMenuItemComposite: IComputedValue<Composite<ApplicationMenuItemTypes | MenuItemRoot>>;
clusterManager: ClusterManager;
catalogEntityRegistry: CatalogEntityRegistry;
clusterStore: ClusterStore;
operatingSystemTheme: IComputedValue<Theme>;
Expand All @@ -39,7 +37,6 @@ interface Dependencies {

export const setupIpcMainHandlers = ({
applicationMenuItemComposite,
clusterManager,
catalogEntityRegistry,
clusterStore,
operatingSystemTheme,
Expand All @@ -64,10 +61,6 @@ export const setupIpcMainHandlers = ({
}
});

ipcMainOn(clusterVisibilityHandler, (event, clusterId?: ClusterId) => {
clusterManager.visibleCluster = clusterId;
});

ipcMainHandle(clusterRefreshHandler, (event, clusterId: ClusterId) => {
return ClusterStore.getInstance()
.getById(clusterId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import { ClusterFrameHandler } from "./cluster-frame-handler";
import emitClusterVisibilityInjectable from "./emit-cluster-visibility.injectable";

const clusterFrameHandlerInjectable = getInjectable({
id: "cluster-frame-handler",
instantiate: () => new ClusterFrameHandler(),
instantiate: (di) => new ClusterFrameHandler({
emitClusterVisibility: di.inject(emitClusterVisibilityInjectable),
getClusterById: di.inject(getClusterByIdInjectable),
logger: di.inject(loggerInjectable),
}),
});

export default clusterFrameHandlerInjectable;
41 changes: 23 additions & 18 deletions src/renderer/components/cluster-manager/cluster-frame-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,29 @@
*/

import { action, makeObservable, observable, when } from "mobx";
import logger from "../../../main/logger";
import { clusterVisibilityHandler } from "../../../common/ipc/cluster";
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
import type { ClusterId } from "../../../common/cluster-types";
import type { Disposer } from "../../utils";
import { getClusterFrameUrl, onceDefined } from "../../utils";
import { ipcRenderer } from "electron";
import assert from "assert";
import type { Logger } from "../../../common/logger";
import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable";
import type { EmitClusterVisibility } from "./emit-cluster-visibility.injectable";

export interface LensView {
isLoaded: boolean;
frame: HTMLIFrameElement;
}

interface Dependencies {
readonly logger: Logger;
getClusterById: GetClusterById;
emitClusterVisibility: EmitClusterVisibility;
}

export class ClusterFrameHandler {
private readonly views = observable.map<string, LensView>();

constructor() {
constructor(protected readonly dependencies: Dependencies) {
makeObservable(this);
}

Expand All @@ -31,7 +36,7 @@ export class ClusterFrameHandler {

@action
public initView(clusterId: ClusterId) {
const cluster = ClusterStore.getInstance().getById(clusterId);
const cluster = this.dependencies.getClusterById(clusterId);
const parentElem = document.getElementById("lens-views");

assert(parentElem, "DOM with #lens-views must be present");
Expand All @@ -40,14 +45,14 @@ export class ClusterFrameHandler {
return;
}

logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`);
this.dependencies.logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`);
const iframe = document.createElement("iframe");

iframe.id = `cluster-frame-${cluster.id}`;
iframe.name = cluster.contextName;
iframe.setAttribute("src", getClusterFrameUrl(clusterId));
iframe.addEventListener("load", action(() => {
logger.info(`[LENS-VIEW]: frame for clusterId=${clusterId} has loaded`);
this.dependencies.logger.info(`[LENS-VIEW]: frame for clusterId=${clusterId} has loaded`);
const view = this.views.get(clusterId);

assert(view, `view for ${clusterId} MUST still exist here`);
Expand All @@ -56,11 +61,11 @@ export class ClusterFrameHandler {
this.views.set(clusterId, { frame: iframe, isLoaded: false });
parentElem.appendChild(iframe);

logger.info(`[LENS-VIEW]: waiting cluster to be ready, clusterId=${clusterId}`);
this.dependencies.logger.info(`[LENS-VIEW]: waiting cluster to be ready, clusterId=${clusterId}`);

const dispose = when(
() => cluster.ready,
() => logger.info(`[LENS-VIEW]: cluster is ready, clusterId=${clusterId}`),
() => this.dependencies.logger.info(`[LENS-VIEW]: cluster is ready, clusterId=${clusterId}`),
);

when(
Expand All @@ -69,12 +74,12 @@ export class ClusterFrameHandler {
() => {
when(
() => {
const cluster = ClusterStore.getInstance().getById(clusterId);
const cluster = this.dependencies.getClusterById(clusterId);

return Boolean(!cluster || (cluster.disconnected && this.views.get(clusterId)?.isLoaded));
},
() => {
logger.info(`[LENS-VIEW]: remove dashboard, clusterId=${clusterId}`);
this.dependencies.logger.info(`[LENS-VIEW]: remove dashboard, clusterId=${clusterId}`);
this.views.delete(clusterId);
parentElem.removeChild(iframe);
dispose();
Expand All @@ -86,19 +91,19 @@ export class ClusterFrameHandler {

private prevVisibleClusterChange?: Disposer;

public setVisibleCluster(clusterId: ClusterId | null) {
public setVisibleCluster(clusterId: ClusterId | null): void {
// Clear the previous when ASAP
this.prevVisibleClusterChange?.();

logger.info(`[LENS-VIEW]: refreshing iframe views, visible cluster id=${clusterId}`);
ipcRenderer.send(clusterVisibilityHandler);
this.dependencies.logger.info(`[LENS-VIEW]: refreshing iframe views, visible cluster id=${clusterId}`);
this.dependencies.emitClusterVisibility(null);

for (const { frame: view } of this.views.values()) {
view.classList.add("hidden");
}

const cluster = clusterId
? ClusterStore.getInstance().getById(clusterId)
? this.dependencies.getClusterById(clusterId)
: undefined;

if (cluster && clusterId) {
Expand All @@ -113,10 +118,10 @@ export class ClusterFrameHandler {
return undefined;
},
(view: LensView) => {
logger.info(`[LENS-VIEW]: cluster id=${clusterId} should now be visible`);
this.dependencies.logger.info(`[LENS-VIEW]: cluster id=${clusterId} should now be visible`);
view.frame.classList.remove("hidden");
view.frame.focus();
ipcRenderer.send(clusterVisibilityHandler, clusterId);
this.dependencies.emitClusterVisibility(clusterId);
},
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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 { MessageChannelHandler } from "../../../common/utils/channel/message-channel-listener-injection-token";
import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
import { clusterVisibilityChannel } from "../../../common/cluster/visibility-channel";

export type EmitClusterVisibility = MessageChannelHandler<typeof clusterVisibilityChannel>;

const emitClusterVisibilityInjectable = getInjectable({
id: "emit-cluster-visibility",
instantiate: (di): EmitClusterVisibility => {
const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken);

return (id) => sendMessageToChannel(clusterVisibilityChannel, id);
},
});

export default emitClusterVisibilityInjectable;

0 comments on commit 98e42cf

Please sign in to comment.