diff --git a/.babelrc b/.babelrc index 693bff5b29..c2afdea6db 100644 --- a/.babelrc +++ b/.babelrc @@ -1,10 +1,27 @@ { "presets": [ - "@babel/preset-env", + [ + "@babel/preset-env", + { + "modules": "commonjs", + "targets": { + "esmodules": false + } + } + ], "@babel/preset-react", "@lingui/babel-preset-react" ], "plugins": [ - "macros" + "macros", + "@babel/plugin-syntax-dynamic-import", + [ + "@babel/plugin-transform-runtime", + { + "absoluteRuntime": false, + "regenerator": true, + "useESModules": true + } + ] ] } diff --git a/package.json b/package.json index e9eaf928ff..e4432901e5 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,11 @@ "version": "3.5.0-beta.1", "main": "dist/main.js", "scripts": { - "dev": "yarn compile:dll && concurrently yarn:dev:*", + "dev": "concurrently yarn:dev:*", "dev-run": "electron --inspect .", "dev:main": "DEBUG=true webpack --watch --progress --config webpack.main.ts", "dev:renderer": "DEBUG=true webpack --watch --progress --config webpack.renderer.ts", - "compile": "NODE_ENV=production concurrently 'yarn download-bins' 'yarn i18n:compile' 'yarn compile:dll' && concurrently yarn:compile:*", + "compile": "NODE_ENV=production concurrently 'yarn download-bins' 'yarn i18n:compile' && concurrently yarn:compile:*", "compile:main": "NODE_ENV=production webpack --progress --config webpack.main.ts $@", "compile:renderer": "NODE_ENV=production webpack --progress --config webpack.renderer.ts $@", "compile:dll": "webpack --config webpack.dll.ts $@", @@ -196,6 +196,8 @@ }, "devDependencies": { "@babel/core": "^7.10.2", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-runtime": "^7.6.2", "@babel/preset-env": "^7.10.2", "@babel/preset-react": "^7.10.1", "@babel/preset-typescript": "^7.10.1", diff --git a/src/common/system-ca.ts b/src/common/system-ca.ts index 05b464ec35..df21d5be87 100644 --- a/src/common/system-ca.ts +++ b/src/common/system-ca.ts @@ -1,7 +1,7 @@ import { isMac, isWindows } from "./vars"; if (isMac) { - console.warn("//FIXME: MAC-CA IMPORT ERROR!"); + // fixme: mac-ca import error // require("mac-ca"); } if (isWindows) { diff --git a/src/common/vars.ts b/src/common/vars.ts index 97094b3aa4..5d10085d0d 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -17,7 +17,6 @@ export const mainDir = path.join(contextDir, "src/main"); export const rendererDir = path.join(contextDir, "src/renderer"); export const htmlTemplate = path.resolve(rendererDir, "template.html"); export const sassCommonVars = path.resolve(rendererDir, "components/vars.scss"); -export const tsConfigFile = path.resolve(contextDir, "tsconfig.json"); // Apis export const staticProto = "static://" diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 7ab828a6fd..53a68af8cf 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -12,6 +12,7 @@ import { promises } from "fs" import { ensureDir } from "fs-extra" import filenamify from "filenamify" import { v4 as uuid } from "uuid" +import { apiPrefix } from "../common/vars"; export type FeatureInstallRequest = { name: string; @@ -261,7 +262,7 @@ export class ClusterManager { cluster = this.clusters.get(clusterId) if (cluster) { // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, "/api-kube") + req.url = req.url.replace(`/${clusterId}`, apiPrefix.KUBE_BASE) } } } else { diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 56268c92e3..5adb9a9401 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -9,6 +9,7 @@ import { Kubectl } from "./kubectl"; import { PromiseIpc } from "electron-promise-ipc" import request from "request-promise-native" import { KubeconfigManager } from "./kubeconfig-manager" +import { apiPrefix } from "../common/vars"; enum ClusterStatus { AccessGranted = 2, @@ -180,7 +181,8 @@ export class Cluster implements ClusterInfo { } protected async k8sRequest(path: string, opts: request.RequestPromiseOptions = {}) { - const url = `http://127.0.0.1:${this.port}/api-kube${path}`; // fixme: remove hardcoded api prefix + const prefix = apiPrefix.KUBE_BASE; + const url = `http://127.0.0.1:${this.port}${prefix}${path}`; opts.json = true; opts.timeout = 10000; opts.headers = Object.assign({}, opts.headers, { diff --git a/src/main/index.ts b/src/main/index.ts index 922a2e4253..d9a48ca0ef 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,23 +1,139 @@ // Main process import "../common/system-ca" -import { app, BrowserWindow } from "electron" +import "../common/prometheus-providers" +import { app, dialog, protocol } from "electron" +import { PromiseIpc } from "electron-promise-ipc" +import path from "path" +import { format as formatUrl } from "url" +import logger from "./logger" +import initMenu from "./menu" +import * as proxy from "./proxy" +import { WindowManager } from "./window-manager"; +import { clusterStore } from "../common/cluster-store" +import { tracker } from "./tracker" +import { ClusterManager } from "./cluster-manager"; +import AppUpdater from "./app-updater" +import { shellSync } from "./shell-sync" +import { getFreePort } from "./port" +import { mangleProxyEnv } from "./proxy-env" +import { findMainWebContents } from "./webcontents" +import { registerStaticProtocol } from "../common/register-static"; +import { isMac } from "../common/vars"; -console.log('MAIN', process.resourcesPath) -console.log('userData', app.getPath("userData")) +mangleProxyEnv() +if (app.commandLine.getSwitchValue("proxy-server") !== "") { + process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") +} -app.whenReady().then(async function start() { - var mainWindow = new BrowserWindow({ - width: 1024, - height: 768, - show: false, - webPreferences: { - devTools: true, - nodeIntegration: true, - } - }); +const promiseIpc = new PromiseIpc({ timeout: 2000 }) +let windowManager: WindowManager = null; +let clusterManager: ClusterManager = null; - await mainWindow.loadFile("dist/index.html"); - mainWindow.show(); - mainWindow.focus(); -}); +const vmURL = formatUrl({ + pathname: path.join(__dirname, "dist/index.html"), + protocol: "file", + slashes: true, +}) + +async function main() { + await shellSync() + + const updater = new AppUpdater() + updater.start(); + + tracker.event("app", "start"); + + registerStaticProtocol(); + protocol.registerFileProtocol('store', (request, callback) => { + const url = request.url.substr(8) + callback(path.normalize(`${app.getPath("userData")}/${url}`)) + }, (error) => { + if (error) console.error('Failed to register protocol') + }) + + let port: number = null + // find free port + try { + port = await getFreePort() + } catch (error) { + logger.error(error) + await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") + app.quit(); + } + + // create cluster manager + clusterManager = new ClusterManager(clusterStore.getAllClusterObjects(), port) + + // run proxy + try { + proxy.listen(port, clusterManager) + } catch (error) { + logger.error(`Could not start proxy (127.0.0:${port}): ${error.message}`) + await dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${port}): ${error.message || "unknown error"}`) + app.quit(); + } + + // boot windowmanager + windowManager = new WindowManager(); + windowManager.showMain(vmURL) + + initMenu({ + logoutHook: async () => { + // IPC send needs webContents as we're sending it to renderer + promiseIpc.send('logout', findMainWebContents(), {}).then((data: any) => { + logger.debug("logout IPC sent"); + }) + }, + showPreferencesHook: async () => { + // IPC send needs webContents as we're sending it to renderer + promiseIpc.send('navigate', findMainWebContents(), { name: 'preferences-page' }).then((data: any) => { + logger.debug("navigate: preferences IPC sent"); + }) + }, + addClusterHook: async () => { + promiseIpc.send('navigate', findMainWebContents(), { name: "add-cluster-page" }).then((data: any) => { + logger.debug("navigate: add-cluster-page IPC sent"); + }) + }, + showWhatsNewHook: async () => { + promiseIpc.send('navigate', findMainWebContents(), { name: "whats-new-page" }).then((data: any) => { + logger.debug("navigate: whats-new-page IPC sent"); + }) + }, + clusterSettingsHook: async () => { + promiseIpc.send('navigate', findMainWebContents(), { name: "cluster-settings-page" }).then((data: any) => { + logger.debug("navigate: cluster-settings-page IPC sent"); + }) + }, + }, promiseIpc) +} + +app.on("ready", main) +app.on('window-all-closed', function () { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (!isMac) { + app.quit(); + } else { + windowManager = null + if (clusterManager) clusterManager.stop() + } +}) +app.on("activate", () => { + if (!windowManager) { + logger.debug("activate main window") + windowManager = new WindowManager(false) + windowManager.showMain(vmURL) + } +}) +app.on("will-quit", async (event) => { + event.preventDefault(); // To allow mixpanel sending to be executed + if (clusterManager) clusterManager.stop() + app.exit(0); +}) + +// todo: auto-restart app in dev-mode +// if (isDevelopment) { +// require('electron-reloader')(module); +// } diff --git a/src/main/index_backup.ts b/src/main/index_backup.ts deleted file mode 100644 index 195f5c5ad1..0000000000 --- a/src/main/index_backup.ts +++ /dev/null @@ -1,139 +0,0 @@ -// Main process - -import "../common/system-ca" -import "../common/prometheus-providers" -import { app, dialog, protocol } from "electron" -import { PromiseIpc } from "electron-promise-ipc" -import path from "path" -import { format as formatUrl } from "url" -import logger from "./logger" -import initMenu from "./menu" -import * as proxy from "./proxy" -import { WindowManager } from "./window-manager"; -import { clusterStore } from "../common/cluster-store" -import { tracker } from "./tracker" -import { ClusterManager } from "./cluster-manager"; -import AppUpdater from "./app-updater" -import { shellSync } from "./shell-sync" -import { getFreePort } from "./port" -import { mangleProxyEnv } from "./proxy-env" -import { findMainWebContents } from "./webcontents" -import { registerStaticProtocol } from "../common/register-static"; -import { isDevelopment, isMac } from "../common/vars"; - -mangleProxyEnv() -if (app.commandLine.getSwitchValue("proxy-server") !== "") { - process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") -} -const promiseIpc = new PromiseIpc({ timeout: 2000 }) - -let windowManager: WindowManager = null; -let clusterManager: ClusterManager = null; -const vmURL = isDevelopment ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}` : formatUrl({ - pathname: path.join(__dirname, "index.html"), - protocol: "file", - slashes: true, -}) - -async function main() { - await shellSync() - - const updater = new AppUpdater() - updater.start(); - - tracker.event("app", "start"); - - registerStaticProtocol(); - protocol.registerFileProtocol('store', (request, callback) => { - const url = request.url.substr(8) - callback(path.normalize(`${app.getPath("userData")}/${url}`)) - }, (error) => { - if (error) console.error('Failed to register protocol') - }) - - let port: number = null - // find free port - try { - port = await getFreePort() - } catch (error) { - logger.error(error) - await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") - app.quit(); - } - - // create cluster manager - clusterManager = new ClusterManager(clusterStore.getAllClusterObjects(), port) - - // run proxy - try { - proxy.listen(port, clusterManager) - } catch (error) { - logger.error(`Could not start proxy (127.0.0:${port}): ${error.message}`) - await dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${port}): ${error.message || "unknown error"}`) - app.quit(); - } - - // boot windowmanager - windowManager = new WindowManager(); - windowManager.showMain(vmURL) - - initMenu({ - logoutHook: async () => { - // IPC send needs webContents as we're sending it to renderer - promiseIpc.send('logout', findMainWebContents(), {}).then((data: any) => { - logger.debug("logout IPC sent"); - }) - }, - showPreferencesHook: async () => { - // IPC send needs webContents as we're sending it to renderer - promiseIpc.send('navigate', findMainWebContents(), { name: 'preferences-page' }).then((data: any) => { - logger.debug("navigate: preferences IPC sent"); - }) - }, - addClusterHook: async () => { - promiseIpc.send('navigate', findMainWebContents(), { name: "add-cluster-page" }).then((data: any) => { - logger.debug("navigate: add-cluster-page IPC sent"); - }) - }, - showWhatsNewHook: async () => { - promiseIpc.send('navigate', findMainWebContents(), { name: "whats-new-page" }).then((data: any) => { - logger.debug("navigate: whats-new-page IPC sent"); - }) - }, - clusterSettingsHook: async () => { - promiseIpc.send('navigate', findMainWebContents(), { name: "cluster-settings-page" }).then((data: any) => { - logger.debug("navigate: cluster-settings-page IPC sent"); - }) - }, - }, promiseIpc) -} - -app.on("ready", main) -app.on('window-all-closed', function () { - // On OS X it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (!isMac) { - app.quit(); - } - else { - windowManager = null - if (clusterManager) clusterManager.stop() - } -}) -app.on("activate", () => { - if (!windowManager) { - logger.debug("activate main window") - windowManager = new WindowManager(false) - windowManager.showMain(vmURL) - } -}) -app.on("will-quit", async (event) => { - event.preventDefault(); // To allow mixpanel sending to be executed - if (clusterManager) clusterManager.stop() - app.exit(0); -}) - -// todo: check auto-restart app in dev-mode -// if (isDevelopment) { -// require('electron-reloader')(module); -// } diff --git a/src/main/proxy.ts b/src/main/proxy.ts index 160a96276a..dfdeac05ac 100644 --- a/src/main/proxy.ts +++ b/src/main/proxy.ts @@ -8,6 +8,7 @@ import logger from "./logger" import * as shell from "./node-shell-session" import { ClusterManager } from "./cluster-manager" import { Router } from "./router" +import { apiPrefix } from "../common/vars"; export class LensProxy { public static readonly localShellSessions = true @@ -110,9 +111,10 @@ export class LensProxy { } protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { - if (req.url.startsWith("/api-kube/")) { + const prefix = apiPrefix.KUBE_BASE; + if (req.url.startsWith(prefix)) { delete req.headers.authorization - req.url = req.url.replace("/api-kube", "") + req.url = req.url.replace(prefix, "") const isWatchRequest = req.url.includes("watch=") return await contextHandler.getApiTarget(isWatchRequest) } diff --git a/src/main/routes/metrics.ts b/src/main/routes/metrics.ts index 3e1688d6fd..ea5fb54c7c 100644 --- a/src/main/routes/metrics.ts +++ b/src/main/routes/metrics.ts @@ -2,6 +2,7 @@ import { LensApiRequest } from "../router" import { LensApi } from "../lens-api" import requestPromise from "request-promise-native" import { PrometheusProviderRegistry, PrometheusProvider, PrometheusNodeQuery, PrometheusClusterQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery, PrometheusQueryOpts} from "../prometheus/provider-registry" +import { apiPrefix } from "../../common/vars"; export type IMetricsQuery = string | string[] | { [metricName: string]: string; @@ -12,7 +13,7 @@ class MetricsRoute extends LensApi { public async routeMetrics(request: LensApiRequest) { const { response, cluster} = request const query: IMetricsQuery = request.payload; - const serverUrl = `http://127.0.0.1:${cluster.port}/api-kube` + const serverUrl = `http://127.0.0.1:${cluster.port}${apiPrefix.KUBE_BASE}` const headers = { "Host": `${cluster.id}.localhost:${cluster.port}`, "Content-type": "application/json", diff --git a/src/renderer/_vue/App.vue b/src/renderer/_vue/App.vue index 0ca9d236cd..5143d7c063 100644 --- a/src/renderer/_vue/App.vue +++ b/src/renderer/_vue/App.vue @@ -1,29 +1,33 @@