diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index a7cd5cc3c5..049d8122b5 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -209,13 +209,17 @@ export class ClusterStore extends BaseStore { export const clusterStore = ClusterStore.getInstance(); +export function isClusterView(): boolean { + return !!getHostedClusterId(); // note: process.isMainFrame cannot be used here since it's "true" for webview-tags +} + export function getClusterIdFromHost(hostname: string): ClusterId { - const subDomains = hostname.split(":")[0].split("."); - return subDomains.slice(-2)[0]; // e.g host == "%clusterId.localhost:45345" + return hostname.match(/^(.*?)\.localhost/)?.[1] } export function getClusterFrameUrl(clusterId: ClusterId) { - return `//${clusterId}.${location.host}`; + const { protocol, host } = location + return `${protocol}//${clusterId}.${host}` } export function getHostedClusterId() { diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 348d5bbd3f..8c28167275 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -31,6 +31,7 @@ export class WindowManager { nodeIntegration: true, nodeIntegrationInSubFrames: true, enableRemoteModule: true, + webviewTag: true, }, }); this.windowState.manage(this.mainView); diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 80c27cb418..1e39d1d47a 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -4,7 +4,7 @@ import { render } from "react-dom"; import { isMac } from "../common/vars"; import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; -import { clusterStore } from "../common/cluster-store"; +import { clusterStore, isClusterView } from "../common/cluster-store"; import { i18nStore } from "./i18n"; import { themeStore } from "./theme.store"; import { App } from "./components/app"; @@ -35,4 +35,4 @@ export async function bootstrap(App: AppComponent) { } // run -bootstrap(process.isMainFrame ? LensApp : App); +bootstrap(isClusterView() ? App : LensApp); diff --git a/src/renderer/components/cluster-manager/cluster-view.route.ts b/src/renderer/components/cluster-manager/cluster-view.route.ts index 82e99497d5..c649577c36 100644 --- a/src/renderer/components/cluster-manager/cluster-view.route.ts +++ b/src/renderer/components/cluster-manager/cluster-view.route.ts @@ -2,7 +2,7 @@ import { reaction } from "mobx"; import { ipcRenderer } from "electron"; import { matchPath, RouteProps } from "react-router"; import { buildURL, navigation } from "../../navigation"; -import { clusterStore } from "../../../common/cluster-store"; +import { clusterStore, isClusterView } from "../../../common/cluster-store"; export interface IClusterViewRouteParams { clusterId: string; @@ -30,7 +30,7 @@ export function getMatchedCluster() { } if (ipcRenderer) { - if (process.isMainFrame) { + if (isClusterView()) { // Keep track of active cluster-id for handling IPC/menus/etc. reaction(() => getMatchedClusterId(), clusterId => { ipcRenderer.send("cluster-view:current-id", clusterId); diff --git a/src/renderer/components/cluster-manager/lens-views.ts b/src/renderer/components/cluster-manager/lens-views.ts index 370ed665c3..67cbcc6940 100644 --- a/src/renderer/components/cluster-manager/lens-views.ts +++ b/src/renderer/components/cluster-manager/lens-views.ts @@ -1,12 +1,16 @@ +import { WebviewTag } from "electron"; import { observable, when } from "mobx"; import { ClusterId, clusterStore, getClusterFrameUrl } from "../../../common/cluster-store"; -import { getMatchedCluster } from "./cluster-view.route" import logger from "../../../main/logger"; +import { isDebugging, isDevelopment, isProduction } from "../../../common/vars"; +import { getMatchedCluster } from "./cluster-view.route"; + +export type LensViewElem = HTMLIFrameElement | WebviewTag; export interface LensView { isLoaded?: boolean clusterId: ClusterId; - view: HTMLIFrameElement + view: LensViewElem; } export const lensViews = observable.map(); @@ -20,31 +24,35 @@ export async function initView(clusterId: ClusterId) { return; } logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`) + let view: LensViewElem; const cluster = clusterStore.getById(clusterId); const parentElem = document.getElementById("lens-views"); - const iframe = document.createElement("iframe"); - iframe.name = cluster.contextName; - iframe.setAttribute("src", getClusterFrameUrl(clusterId)) - iframe.addEventListener("load", () => { - logger.info(`[LENS-VIEW]: loaded from ${iframe.src}`) + const frameUrl = getClusterFrameUrl(clusterId); + const onLoad = () => { + logger.info(`[LENS-VIEW]: loaded from ${view.src}`) lensViews.get(clusterId).isLoaded = true; - }, { once: true }); - lensViews.set(clusterId, { clusterId, view: iframe }); - parentElem.appendChild(iframe); - await autoCleanOnRemove(clusterId, iframe); + }; + if (isDevelopment || isDebugging) { + view = document.createElement("iframe"); + view.addEventListener("load", onLoad); + view.name = cluster.contextName; + } else if (isProduction) { + view = document.createElement("webview"); + view.addEventListener("did-frame-finish-load", onLoad); + view.setAttribute("nodeintegration", "true"); + view.setAttribute("enableremotemodule", "true"); + } + view.setAttribute("src", frameUrl); + parentElem.appendChild(view); + lensViews.set(clusterId, { clusterId, view }); + await autoCleanOnRemove(clusterId, view); } -export async function autoCleanOnRemove(clusterId: ClusterId, iframe: HTMLIFrameElement) { +export async function autoCleanOnRemove(clusterId: ClusterId, view: LensViewElem) { await when(() => !clusterStore.getById(clusterId)); logger.info(`[LENS-VIEW]: remove dashboard, clusterId=${clusterId}`) - lensViews.delete(clusterId) - - // 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.dataset.meta = `${iframe.name} was removed at ${new Date().toLocaleString()}`; - iframe.removeAttribute("src") - iframe.removeAttribute("name") + lensViews.delete(clusterId); + view.parentElement.removeChild(view); } export function refreshViews() {