mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
149 lines
4.6 KiB
TypeScript
149 lines
4.6 KiB
TypeScript
/**
|
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
*/
|
|
|
|
import { action, makeObservable, observable, when } from "mobx";
|
|
import type { ClusterId } from "../../../common/cluster-types";
|
|
import type { Disposer } from "../../utils";
|
|
import { getClusterFrameUrl, onceDefined } from "../../utils";
|
|
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(protected readonly dependencies: Dependencies) {
|
|
makeObservable(this);
|
|
}
|
|
|
|
public hasLoadedView(clusterId: string): boolean {
|
|
return Boolean(this.views.get(clusterId)?.isLoaded);
|
|
}
|
|
|
|
@action
|
|
public initView(clusterId: ClusterId) {
|
|
const cluster = this.dependencies.getClusterById(clusterId);
|
|
|
|
if (!cluster) {
|
|
this.dependencies.logger.warn(`[LENS-VIEW]: not initializing view; unknown clusterId="${clusterId}"`);
|
|
|
|
return;
|
|
}
|
|
|
|
const parentElem = document.getElementById("lens-views");
|
|
|
|
assert(parentElem, "DOM with #lens-views must be present");
|
|
|
|
if (this.views.has(clusterId)) {
|
|
return;
|
|
}
|
|
|
|
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(() => {
|
|
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`);
|
|
view.isLoaded = true;
|
|
}), { once: true });
|
|
this.views.set(clusterId, { frame: iframe, isLoaded: false });
|
|
parentElem.appendChild(iframe);
|
|
|
|
this.dependencies.logger.info(`[LENS-VIEW]: waiting cluster to be ready, clusterId=${clusterId}`);
|
|
|
|
const dispose = when(
|
|
() => cluster.ready,
|
|
() => this.dependencies.logger.info(`[LENS-VIEW]: cluster is ready, clusterId=${clusterId}`),
|
|
);
|
|
|
|
when(
|
|
// cluster.disconnect is set to `false` when the cluster starts to connect
|
|
() => !cluster.disconnected,
|
|
() => {
|
|
when(
|
|
() => {
|
|
const cluster = this.dependencies.getClusterById(clusterId);
|
|
|
|
return Boolean(!cluster || (cluster.disconnected && this.views.get(clusterId)?.isLoaded));
|
|
},
|
|
() => {
|
|
this.dependencies.logger.info(`[LENS-VIEW]: remove dashboard, clusterId=${clusterId}`);
|
|
this.views.delete(clusterId);
|
|
|
|
// Must only remove iframe from DOM after it unloads old code. Else it crashes
|
|
iframe.addEventListener("load", () => parentElem.removeChild(iframe), {
|
|
once: true,
|
|
});
|
|
|
|
// This causes the old code to be unloaded.
|
|
iframe.setAttribute("src", "");
|
|
|
|
dispose();
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
private prevVisibleClusterChange?: Disposer;
|
|
|
|
public setVisibleCluster(clusterId: ClusterId | null): void {
|
|
// Clear the previous when ASAP
|
|
this.prevVisibleClusterChange?.();
|
|
|
|
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
|
|
? this.dependencies.getClusterById(clusterId)
|
|
: undefined;
|
|
|
|
if (cluster && clusterId) {
|
|
this.prevVisibleClusterChange = onceDefined(
|
|
() => {
|
|
const view = this.views.get(clusterId);
|
|
|
|
if (cluster.available && cluster.ready && view?.isLoaded) {
|
|
return view;
|
|
}
|
|
|
|
return undefined;
|
|
},
|
|
(view: LensView) => {
|
|
this.dependencies.logger.info(`[LENS-VIEW]: cluster id=${clusterId} should now be visible`);
|
|
view.frame.classList.remove("hidden");
|
|
view.frame.focus();
|
|
this.dependencies.emitClusterVisibility(clusterId);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
public clearVisibleCluster() {
|
|
this.setVisibleCluster(null);
|
|
}
|
|
}
|