diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index ea0537bda3..4b2d72ea85 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -5,6 +5,7 @@ import "../../common/catalog-entities"; export class CatalogEntityRegistry { @observable protected _items: CatalogEntity[] = observable.array([], { deep: true }); + @observable protected _activeEntity: CatalogEntity; constructor(private categoryRegistry: CatalogCategoryRegistry) {} @@ -39,6 +40,14 @@ export class CatalogEntityRegistry { }); } + set activeEntity(entity: CatalogEntity) { + this._activeEntity = entity; + } + + get activeEntity() { + return this._activeEntity; + } + get items() { return this._items; } diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index c09b4d7057..fb1bb9e497 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -2,49 +2,21 @@ import "./cluster-manager.scss"; import React from "react"; import { Redirect, Route, Switch } from "react-router"; -import { comparer, reaction } from "mobx"; -import { disposeOnUnmount, observer } from "mobx-react"; +import { observer } from "mobx-react"; import { BottomBar } from "./bottom-bar"; import { Catalog, catalogRoute } from "../+catalog"; import { Preferences, preferencesRoute } from "../+preferences"; import { AddCluster, addClusterRoute } from "../+add-cluster"; import { ClusterView } from "./cluster-view"; import { clusterViewRoute } from "./cluster-view.route"; -import { ClusterStore } from "../../../common/cluster-store"; -import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views"; import { globalPageRegistry } from "../../../extensions/registries/page-registry"; import { Extensions, extensionsRoute } from "../+extensions"; -import { getMatchedClusterId } from "../../navigation"; import { HotbarMenu } from "../hotbar/hotbar-menu"; import { EntitySettings, entitySettingsRoute } from "../+entity-settings"; import { Welcome, welcomeRoute, welcomeURL } from "../+welcome"; @observer export class ClusterManager extends React.Component { - componentDidMount() { - const getMatchedCluster = () => ClusterStore.getInstance().getById(getMatchedClusterId()); - - disposeOnUnmount(this, [ - reaction(getMatchedClusterId, initView, { - fireImmediately: true - }), - reaction(() => !getMatchedClusterId(), () => ClusterStore.getInstance().setActive(null)), - reaction(() => [ - getMatchedClusterId(), // refresh when active cluster-view changed - hasLoadedView(getMatchedClusterId()), // refresh when cluster's webview loaded - getMatchedCluster()?.available, // refresh on disconnect active-cluster - getMatchedCluster()?.ready, // refresh when cluster ready-state change - ], refreshViews, { - fireImmediately: true, - equals: comparer.shallow, - }), - ]); - } - - componentWillUnmount() { - lensViews.clear(); - } - render() { return (
diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 7fb68ceb36..797b79e709 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -39,10 +39,6 @@ export class ClusterStatus extends React.Component { error: res.error, }); }); - - if (this.cluster.disconnected) { - await this.activateCluster(); - } } componentWillUnmount() { diff --git a/src/renderer/components/cluster-manager/cluster-view.tsx b/src/renderer/components/cluster-manager/cluster-view.tsx index fbc55d8db3..448d6afdbf 100644 --- a/src/renderer/components/cluster-manager/cluster-view.tsx +++ b/src/renderer/components/cluster-manager/cluster-view.tsx @@ -5,11 +5,12 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { RouteComponentProps } from "react-router"; import { IClusterViewRouteParams } from "./cluster-view.route"; import { ClusterStatus } from "./cluster-status"; -import { hasLoadedView } from "./lens-views"; +import { hasLoadedView, initView, refreshViews } from "./lens-views"; import { Cluster } from "../../../main/cluster"; -import { navigate } from "../../navigation"; -import { catalogURL } from "../+catalog"; import { ClusterStore } from "../../../common/cluster-store"; +import { requestMain } from "../../../common/ipc"; +import { clusterActivateHandler } from "../../../common/cluster-ipc"; +import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; interface Props extends RouteComponentProps { } @@ -26,15 +27,37 @@ export class ClusterView extends React.Component { async componentDidMount() { disposeOnUnmount(this, [ - reaction(() => this.clusterId, clusterId => ClusterStore.getInstance().setActive(clusterId), { + reaction(() => this.clusterId, (clusterId) => { + this.showCluster(clusterId); + }, { fireImmediately: true, - }), - reaction(() => this.cluster.online, (online) => { - if (!online) navigate(catalogURL()); }) ]); } + componentWillUnmount() { + this.hideCluster(); + } + + showCluster(clusterId: string) { + initView(clusterId); + requestMain(clusterActivateHandler, this.clusterId, false); + + const entity = catalogEntityRegistry.getById(this.clusterId); + + if (entity) { + catalogEntityRegistry.activeEntity = entity; + } + } + + hideCluster() { + refreshViews(); + + if (catalogEntityRegistry.activeEntity?.metadata?.uid === this.clusterId) { + catalogEntityRegistry.activeEntity = null; + } + } + render() { const { cluster } = this; const showStatus = cluster && (!cluster.available || !hasLoadedView(cluster.id) || !cluster.ready); diff --git a/src/renderer/components/cluster-manager/lens-views.ts b/src/renderer/components/cluster-manager/lens-views.ts index 30fae018cc..4b08ad9efe 100644 --- a/src/renderer/components/cluster-manager/lens-views.ts +++ b/src/renderer/components/cluster-manager/lens-views.ts @@ -1,7 +1,8 @@ import { observable, when } from "mobx"; import { ClusterId, ClusterStore, getClusterFrameUrl } from "../../../common/cluster-store"; -import { getMatchedClusterId } from "../../navigation"; +import { navigate } from "../../navigation"; import logger from "../../../main/logger"; +import { catalogURL } from "../+catalog"; export interface LensView { isLoaded?: boolean @@ -16,9 +17,12 @@ export function hasLoadedView(clusterId: ClusterId): boolean { } export async function initView(clusterId: ClusterId) { + refreshViews(clusterId); + if (!clusterId || lensViews.has(clusterId)) { return; } + const cluster = ClusterStore.getInstance().getById(clusterId); if (!cluster) { @@ -51,16 +55,23 @@ export async function autoCleanOnRemove(clusterId: ClusterId, iframe: HTMLIFrame logger.info(`[LENS-VIEW]: remove dashboard, clusterId=${clusterId}`); lensViews.delete(clusterId); + const wasVisible = iframe.style.display !== "none"; + // Keep frame in DOM to avoid possible bugs when same cluster re-created after being removed. // In that case for some reasons `webFrame.routingId` returns some previous frameId (usage in app.tsx) // Issue: https://github.com/lensapp/lens/issues/811 + iframe.style.display = "none"; iframe.dataset.meta = `${iframe.name} was removed at ${new Date().toLocaleString()}`; iframe.removeAttribute("name"); iframe.contentWindow.postMessage("teardown", "*"); + + if (wasVisible) { + navigate(catalogURL()); + } } -export function refreshViews() { - const cluster = ClusterStore.getInstance().getById(getMatchedClusterId()); +export function refreshViews(visibleClusterId?: string) { + const cluster = !visibleClusterId ? null : ClusterStore.getInstance().getById(visibleClusterId); lensViews.forEach(({ clusterId, view, isLoaded }) => { const isCurrent = clusterId === cluster?.id; diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index 931ebc02e8..29c44fc81e 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -12,7 +12,6 @@ import { Icon } from "../icon"; import { Badge } from "../badge"; import { CommandOverlay } from "../command-palette"; import { HotbarSwitchCommand } from "./hotbar-switch-command"; -import { ClusterStore } from "../../../common/cluster-store"; import { Tooltip, TooltipPosition } from "../tooltip"; interface Props { @@ -26,7 +25,7 @@ export class HotbarMenu extends React.Component { } isActive(item: CatalogEntity) { - return ClusterStore.getInstance().activeClusterId == item.getId(); + return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId(); } getEntity(item: HotbarItem) {