mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Upgrade to electron 12 and Node 14 (#3572)
Upgrade to electron 12 and Node 14 - Compute cluster ID for tests - Switch to temporary appData path while testing Signed-off-by: Sebastian Malton <sebastian@malton.name> Co-authored-by: Sebastian Malton <smalton@mirantis.com> Co-authored-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
50 files changed
+1000
-1099
No files matched your search
@@ -37,7 +37,6 @@ import { Console } from "console";
|
||||
import { SemVer } from "semver";
|
||||
import electron from "electron";
|
||||
import { stdout, stderr } from "process";
|
||||
import { beforeEachWrapped } from "../../../integration/helpers/utils";
|
||||
import { ThemeStore } from "../../renderer/theme.store";
|
||||
import type { ClusterStoreModel } from "../cluster-store";
|
||||
|
||||
@@ -45,7 +44,7 @@ console = new Console(stdout, stderr);
|
||||
|
||||
describe("user store tests", () => {
|
||||
describe("for an empty config", () => {
|
||||
beforeEachWrapped(() => {
|
||||
beforeEach(() => {
|
||||
mockFs({ tmp: { "config.json": "{}", "kube_config": "{}" } });
|
||||
|
||||
(UserStore.createInstance() as any).refreshNewContexts = jest.fn(() => Promise.resolve());
|
||||
@@ -94,7 +93,7 @@ describe("user store tests", () => {
|
||||
});
|
||||
|
||||
describe("migrations", () => {
|
||||
beforeEachWrapped(() => {
|
||||
beforeEach(() => {
|
||||
mockFs({
|
||||
"tmp": {
|
||||
"config.json": JSON.stringify({
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import path from "path";
|
||||
import Config from "conf";
|
||||
import type { Options as ConfOptions } from "conf/dist/source/types";
|
||||
import { app, ipcMain, ipcRenderer, remote } from "electron";
|
||||
import { ipcMain, ipcRenderer } from "electron";
|
||||
import { IReactionOptions, makeObservable, reaction, runInAction } from "mobx";
|
||||
import { getAppVersion, Singleton, toJS, Disposer } from "./utils";
|
||||
import logger from "../main/logger";
|
||||
@@ -30,6 +30,7 @@ import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import { isTestEnv } from "./vars";
|
||||
import { kebabCase } from "lodash";
|
||||
import { getPath } from "./utils/getPath";
|
||||
|
||||
export interface BaseStoreParams<T> extends ConfOptions<T> {
|
||||
syncOptions?: IReactionOptions;
|
||||
@@ -88,7 +89,7 @@ export abstract class BaseStore<T> extends Singleton {
|
||||
}
|
||||
|
||||
protected cwd() {
|
||||
return (app || remote.app).getPath("userData");
|
||||
return getPath("userData");
|
||||
}
|
||||
|
||||
protected async saveToFile(model: T) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export const dialogShowOpenDialogHandler = "dialog:show-open-dialog";
|
||||
|
||||
export * from "./ipc";
|
||||
export * from "./invalid-kubeconfig";
|
||||
export * from "./update-available.ipc";
|
||||
|
||||
@@ -23,12 +23,14 @@
|
||||
// https://www.electronjs.org/docs/api/ipc-main
|
||||
// https://www.electronjs.org/docs/api/ipc-renderer
|
||||
|
||||
import { ipcMain, ipcRenderer, remote, webContents } from "electron";
|
||||
import { ipcMain, ipcRenderer, webContents } from "electron";
|
||||
import { toJS } from "../utils/toJS";
|
||||
import logger from "../../main/logger";
|
||||
import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames";
|
||||
import type { Disposer } from "../utils";
|
||||
|
||||
const remote = ipcMain ? null : require("@electron/remote");
|
||||
|
||||
const subFramesChannel = "ipc:get-sub-frames";
|
||||
|
||||
export async function requestMain(channel: string, ...args: any[]) {
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, ipcMain, remote } from "electron";
|
||||
import { ipcMain } from "electron";
|
||||
import winston, { format } from "winston";
|
||||
import type Transport from "winston-transport";
|
||||
import { consoleFormat } from "winston-console-format";
|
||||
import { isDebugging, isTestEnv } from "./vars";
|
||||
import BrowserConsole from "winston-transport-browserconsole";
|
||||
import { SentryTransport } from "./logger-transports";
|
||||
import { getPath } from "./utils/getPath";
|
||||
|
||||
const logLevel = process.env.LOG_LEVEL
|
||||
? process.env.LOG_LEVEL
|
||||
@@ -71,7 +72,7 @@ if (!isTestEnv) {
|
||||
handleExceptions: false,
|
||||
level: logLevel,
|
||||
filename: "lens.log",
|
||||
dirname: (app ?? remote?.app)?.getPath("logs"),
|
||||
dirname: getPath("logs"),
|
||||
maxsize: 16 * 1024,
|
||||
maxFiles: 16,
|
||||
tailable: true,
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, remote } from "electron";
|
||||
import { app } from "electron";
|
||||
import semver from "semver";
|
||||
import { action, computed, observable, reaction, makeObservable } from "mobx";
|
||||
import { BaseStore } from "../base-store";
|
||||
@@ -32,7 +32,8 @@ import { fileNameMigration } from "../../migrations/user-store";
|
||||
import { ObservableToggleSet, toJS } from "../../renderer/utils";
|
||||
import { DESCRIPTORS, KubeconfigSyncValue, UserPreferencesModel, EditorConfiguration } from "./preferences-helpers";
|
||||
import logger from "../../main/logger";
|
||||
import type {monaco} from "react-monaco-editor";
|
||||
import type { monaco } from "react-monaco-editor";
|
||||
import { getPath } from "../utils/getPath";
|
||||
|
||||
export interface UserStoreModel {
|
||||
lastSeenAppVersion: string;
|
||||
@@ -69,7 +70,7 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
||||
@observable shell?: string;
|
||||
@observable downloadBinariesPath?: string;
|
||||
@observable kubectlBinariesPath?: string;
|
||||
|
||||
|
||||
/**
|
||||
* Download kubectl binaries matching cluster version
|
||||
*/
|
||||
@@ -86,7 +87,7 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
||||
* Monaco editor configs
|
||||
*/
|
||||
@observable editorConfiguration:EditorConfiguration = {tabSize: null, miniMap: null, lineNumbers: null};
|
||||
|
||||
|
||||
/**
|
||||
* The set of file/folder paths to be synced
|
||||
*/
|
||||
@@ -115,7 +116,7 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
||||
});
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Returns monaco editor options for selected editor type (the place, where a particular instance of the editor is mounted)
|
||||
@@ -244,5 +245,5 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
||||
* @returns string
|
||||
*/
|
||||
export function getDefaultKubectlDownloadPath(): string {
|
||||
return path.join((app || remote.app).getPath("userData"), "binaries");
|
||||
return path.join(getPath("userData"), "binaries");
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, ipcMain } from "electron";
|
||||
|
||||
const remote = ipcMain ? null : require("@electron/remote");
|
||||
|
||||
/**
|
||||
* calls getPath either on app or on the remote's app
|
||||
*
|
||||
* @deprecated Use a different method for accessing the getPath function
|
||||
*/
|
||||
export function getPath(name: Parameters<typeof app["getPath"]>[0]): string {
|
||||
if (app) {
|
||||
return app.getPath(name);
|
||||
}
|
||||
|
||||
return remote.app.getPath(name);
|
||||
}
|
||||
@@ -40,6 +40,7 @@ export * from "./downloadFile";
|
||||
export * from "./formatDuration";
|
||||
export * from "./escapeRegExp";
|
||||
export * from "./extended-map";
|
||||
export * from "./getPath";
|
||||
export * from "./getRandId";
|
||||
export * from "./hash-set";
|
||||
export * from "./local-kubeconfig";
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, remote } from "electron";
|
||||
import path from "path";
|
||||
import * as uuid from "uuid";
|
||||
import type { ClusterId } from "../cluster-types";
|
||||
import { getPath } from "./getPath";
|
||||
|
||||
export function storedKubeConfigFolder(): string {
|
||||
return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs");
|
||||
return path.resolve(getPath("userData"), "kubeconfigs");
|
||||
}
|
||||
|
||||
export function getCustomKubeConfigPath(clusterId: ClusterId = uuid.v4()): string {
|
||||
|
||||
@@ -35,6 +35,9 @@ export const isTestEnv = !!process.env.JEST_WORKER_ID;
|
||||
export const isDevelopment = !isTestEnv && !isProduction;
|
||||
export const isPublishConfigured = Object.keys(packageInfo.build).includes("publish");
|
||||
|
||||
export const integrationTestingArg = "--integration-testing";
|
||||
export const isIntegrationTesting = process.argv.includes(integrationTestingArg);
|
||||
|
||||
export const productName = packageInfo.productName;
|
||||
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
|
||||
export const publicPath = "/build/" as string;
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, ipcRenderer, remote } from "electron";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { EventEmitter } from "events";
|
||||
import { isEqual } from "lodash";
|
||||
import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx";
|
||||
import path from "path";
|
||||
import { ClusterStore } from "../common/cluster-store";
|
||||
import { broadcastMessage, ipcMainOn, ipcRendererOn, requestMain, ipcMainHandle } from "../common/ipc";
|
||||
import { Disposer, getHostedClusterId, Singleton, toJS } from "../common/utils";
|
||||
import { Disposer, getHostedClusterId, Singleton, toJS, getPath } from "../common/utils";
|
||||
import logger from "../main/logger";
|
||||
import type { InstalledExtension } from "./extension-discovery";
|
||||
import { ExtensionsStore } from "./extensions-store";
|
||||
@@ -36,7 +36,7 @@ import type { LensRendererExtension } from "./lens-renderer-extension";
|
||||
import * as registries from "./registries";
|
||||
|
||||
export function extensionPackagesRoot() {
|
||||
return path.join((app || remote.app).getPath("userData"));
|
||||
return path.join(getPath("userData"));
|
||||
}
|
||||
|
||||
const logModule = "[EXTENSIONS-LOADER]";
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ import { VersionDetector } from "./cluster-detectors/version-detector";
|
||||
import { DetectorRegistry } from "./cluster-detectors/detector-registry";
|
||||
import plimit from "p-limit";
|
||||
import { toJS } from "../common/utils";
|
||||
import { initialNodeShellImage, ClusterState, ClusterMetadataKey, ClusterRefreshOptions, ClusterStatus, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-types";
|
||||
import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-types";
|
||||
import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus } from "../common/cluster-types";
|
||||
|
||||
/**
|
||||
* Cluster
|
||||
|
||||
@@ -26,14 +26,9 @@ import { ClusterManager } from "./cluster-manager";
|
||||
import logger from "./logger";
|
||||
|
||||
export function exitApp() {
|
||||
console.log("before windowManager");
|
||||
const windowManager = WindowManager.getInstance(false);
|
||||
|
||||
console.log("before clusterManager");
|
||||
const clusterManager = ClusterManager.getInstance(false);
|
||||
|
||||
console.log("after clusterManager");
|
||||
|
||||
appEventBus.emit({ name: "service", action: "close" });
|
||||
windowManager?.hide();
|
||||
clusterManager?.stop();
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
|
||||
import { randomBytes } from "crypto";
|
||||
import { SHA256 } from "crypto-js";
|
||||
import { app, remote } from "electron";
|
||||
import fse from "fs-extra";
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import path from "path";
|
||||
import { BaseStore } from "../common/base-store";
|
||||
import type { LensExtensionId } from "../extensions/lens-extension";
|
||||
import { toJS } from "../common/utils";
|
||||
import { getPath } from "../common/utils/getPath";
|
||||
|
||||
interface FSProvisionModel {
|
||||
extensions: Record<string, string>; // extension names to paths
|
||||
@@ -55,7 +55,7 @@ export class FilesystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
||||
if (!this.registeredExtensions.has(extensionName)) {
|
||||
const salt = randomBytes(32).toString("hex");
|
||||
const hashedName = SHA256(`${extensionName}/${salt}`).toString();
|
||||
const dirPath = path.resolve((app || remote.app).getPath("userData"), "extension_data", hashedName);
|
||||
const dirPath = path.resolve(getPath("userData"), "extension_data", hashedName);
|
||||
|
||||
this.registeredExtensions.set(extensionName, dirPath);
|
||||
}
|
||||
|
||||
+17
-14
@@ -22,12 +22,12 @@
|
||||
// Main process
|
||||
|
||||
import "../common/system-ca";
|
||||
import { initialize as initializeRemote } from "@electron/remote/main";
|
||||
import * as Mobx from "mobx";
|
||||
import * as LensExtensionsCommonApi from "../extensions/common-api";
|
||||
import * as LensExtensionsMainApi from "../extensions/main-api";
|
||||
import { app, autoUpdater, dialog, powerMonitor } from "electron";
|
||||
import { appName, isMac, productName } from "../common/vars";
|
||||
import path from "path";
|
||||
import { appName, isIntegrationTesting, isMac, productName } from "../common/vars";
|
||||
import { LensProxy } from "./lens-proxy";
|
||||
import { WindowManager } from "./window-manager";
|
||||
import { ClusterManager } from "./cluster-manager";
|
||||
@@ -63,13 +63,13 @@ import { ensureDir } from "fs-extra";
|
||||
import { Router } from "./router";
|
||||
import { initMenu } from "./menu";
|
||||
import { initTray } from "./tray";
|
||||
import * as path from "path";
|
||||
import { kubeApiRequest, shellApiRequest } from "./proxy-functions";
|
||||
|
||||
const onCloseCleanup = disposer();
|
||||
const onQuitCleanup = disposer();
|
||||
|
||||
SentryInit();
|
||||
|
||||
const workingDir = path.join(app.getPath("appData"), appName);
|
||||
const cleanup = disposer();
|
||||
|
||||
app.setName(appName);
|
||||
|
||||
logger.info(`📟 Setting ${productName} as protocol client for lens://`);
|
||||
@@ -80,14 +80,16 @@ if (app.setAsDefaultProtocolClient("lens")) {
|
||||
logger.info("📟 Protocol client register failed ❗");
|
||||
}
|
||||
|
||||
if (!process.env.CICD) {
|
||||
app.setPath("userData", workingDir);
|
||||
if (process.env.CICD) {
|
||||
app.setPath("appData", process.env.CICD);
|
||||
app.setPath("userData", path.join(process.env.CICD, appName));
|
||||
}
|
||||
|
||||
if (process.env.LENS_DISABLE_GPU) {
|
||||
app.disableHardwareAcceleration();
|
||||
}
|
||||
|
||||
initializeRemote();
|
||||
configurePackages();
|
||||
mangleProxyEnv();
|
||||
initializers.initIpcMainHandlers();
|
||||
@@ -121,7 +123,7 @@ app.on("second-instance", (event, argv) => {
|
||||
});
|
||||
|
||||
app.on("ready", async () => {
|
||||
logger.info(`🚀 Starting ${productName} from "${workingDir}"`);
|
||||
logger.info(`🚀 Starting ${productName} from "${app.getPath("exe")}"`);
|
||||
logger.info("🐚 Syncing shell environment");
|
||||
await shellSync();
|
||||
|
||||
@@ -209,7 +211,7 @@ app.on("ready", async () => {
|
||||
logger.info("🖥️ Starting WindowManager");
|
||||
const windowManager = WindowManager.createInstance();
|
||||
|
||||
cleanup.push(
|
||||
onQuitCleanup.push(
|
||||
initMenu(windowManager),
|
||||
initTray(windowManager),
|
||||
);
|
||||
@@ -221,7 +223,7 @@ app.on("ready", async () => {
|
||||
}
|
||||
|
||||
ipcMainOn(IpcRendererNavigationEvents.LOADED, async () => {
|
||||
cleanup.push(pushCatalogToRenderer(catalogEntityRegistry));
|
||||
onCloseCleanup.push(pushCatalogToRenderer(catalogEntityRegistry));
|
||||
await ensureDir(storedKubeConfigFolder());
|
||||
KubeconfigSyncManager.getInstance().startSync();
|
||||
startUpdateChecking();
|
||||
@@ -269,7 +271,7 @@ app.on("activate", (event, hasVisibleWindows) => {
|
||||
/**
|
||||
* This variable should is used so that `autoUpdater.installAndQuit()` works
|
||||
*/
|
||||
let blockQuit = true;
|
||||
let blockQuit = !isIntegrationTesting;
|
||||
|
||||
autoUpdater.on("before-quit-for-update", () => blockQuit = false);
|
||||
|
||||
@@ -282,7 +284,7 @@ app.on("will-quit", (event) => {
|
||||
appEventBus.emit({ name: "app", action: "close" });
|
||||
ClusterManager.getInstance(false)?.stop(); // close cluster connections
|
||||
KubeconfigSyncManager.getInstance(false)?.stopSync();
|
||||
cleanup();
|
||||
onCloseCleanup();
|
||||
|
||||
if (lprm) {
|
||||
// This is set to false here so that LPRM can wait to send future lens://
|
||||
@@ -298,7 +300,8 @@ app.on("will-quit", (event) => {
|
||||
return; // skip exit to make tray work, to quit go to app's global menu or tray's menu
|
||||
}
|
||||
|
||||
LensProtocolRouterMain.getInstance(false)?.cleanup();
|
||||
lprm?.cleanup();
|
||||
onQuitCleanup();
|
||||
});
|
||||
|
||||
app.on("open-url", (event, rawUrl) => {
|
||||
|
||||
@@ -19,20 +19,21 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import type { IpcMainInvokeEvent } from "electron";
|
||||
import { BrowserWindow, dialog, IpcMainInvokeEvent } from "electron";
|
||||
import { KubernetesCluster } from "../../common/catalog-entities";
|
||||
import { clusterFrameMap } from "../../common/cluster-frames";
|
||||
import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler, clusterDeleteHandler } from "../../common/cluster-ipc";
|
||||
import { ClusterStore } from "../../common/cluster-store";
|
||||
import type { ClusterId } from "../../common/cluster-types";
|
||||
import { appEventBus } from "../../common/event-bus";
|
||||
import { ipcMainHandle } from "../../common/ipc";
|
||||
import { dialogShowOpenDialogHandler, ipcMainHandle } from "../../common/ipc";
|
||||
import { catalogEntityRegistry } from "../catalog";
|
||||
import { ClusterManager } from "../cluster-manager";
|
||||
import { bundledKubectlPath } from "../kubectl";
|
||||
import logger from "../logger";
|
||||
import { promiseExecFile } from "../promise-exec";
|
||||
import { ResourceApplier } from "../resource-applier";
|
||||
import { WindowManager } from "../window-manager";
|
||||
|
||||
export function initIpcMainHandlers() {
|
||||
ipcMainHandle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
|
||||
@@ -138,4 +139,10 @@ export function initIpcMainHandlers() {
|
||||
throw `${clusterId} is not a valid cluster id`;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMainHandle(dialogShowOpenDialogHandler, async (event, dialogOpts: Electron.OpenDialogOptions) => {
|
||||
await WindowManager.getInstance().ensureMainWindow();
|
||||
|
||||
return dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), dialogOpts);
|
||||
});
|
||||
}
|
||||
+2
-2
@@ -19,7 +19,6 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, remote } from "electron";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { promiseExec } from "./promise-exec";
|
||||
@@ -32,6 +31,7 @@ import { customRequest } from "../common/request";
|
||||
import { getBundledKubectlVersion } from "../common/utils/app-version";
|
||||
import { isDevelopment, isWindows, isTestEnv } from "../common/vars";
|
||||
import { SemVer } from "semver";
|
||||
import { getPath } from "../common/utils/getPath";
|
||||
|
||||
const bundledVersion = getBundledKubectlVersion();
|
||||
const kubectlMap: Map<string, string> = new Map([
|
||||
@@ -84,7 +84,7 @@ export class Kubectl {
|
||||
protected dirname: string;
|
||||
|
||||
static get kubectlDir() {
|
||||
return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl");
|
||||
return path.join(getPath("userData"), "binaries", "kubectl");
|
||||
}
|
||||
|
||||
public static readonly bundledKubectlVersion: string = bundledVersion;
|
||||
|
||||
+3
-3
@@ -83,7 +83,7 @@ export function buildMenu(windowManager: WindowManager) {
|
||||
accelerator: "CmdOrCtrl+,",
|
||||
click() {
|
||||
navigate(preferencesURL());
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Extensions",
|
||||
@@ -106,7 +106,7 @@ export function buildMenu(windowManager: WindowManager) {
|
||||
exitApp();
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
};
|
||||
const fileMenu: MenuItemConstructorOptions = {
|
||||
label: "File",
|
||||
@@ -150,7 +150,7 @@ export function buildMenu(windowManager: WindowManager) {
|
||||
}
|
||||
}
|
||||
])
|
||||
]
|
||||
],
|
||||
};
|
||||
const editMenu: MenuItemConstructorOptions = {
|
||||
label: "Edit",
|
||||
|
||||
@@ -89,7 +89,8 @@ export class WindowManager extends Singleton {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
enableRemoteModule: true,
|
||||
webviewTag: true
|
||||
webviewTag: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
});
|
||||
this.windowState.manage(this.mainWindow);
|
||||
@@ -257,7 +258,10 @@ export class WindowManager extends Singleton {
|
||||
resizable: false,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
}
|
||||
});
|
||||
await this.splashWindow.loadURL("static://splash.html");
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
*/
|
||||
|
||||
import fse from "fs-extra";
|
||||
import { app, remote } from "electron";
|
||||
import path from "path";
|
||||
import { getPath } from "../../common/utils/getPath";
|
||||
|
||||
export function fileNameMigration() {
|
||||
const userDataPath = (app || remote.app).getPath("userData");
|
||||
const userDataPath = getPath("userData");
|
||||
const configJsonPath = path.join(userDataPath, "config.json");
|
||||
const lensUserStoreJsonPath = path.join(userDataPath, "lens-user-store.json");
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export class HelmCharts extends Component<Props> {
|
||||
searchProps: {
|
||||
...searchProps,
|
||||
placeholder: "Search Helm Charts...",
|
||||
},
|
||||
}
|
||||
})}
|
||||
renderTableHeader={[
|
||||
{ className: "icon", showWithColumn: columnId.name },
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
import "./extensions.scss";
|
||||
|
||||
import { remote, shell } from "electron";
|
||||
import { shell } from "electron";
|
||||
import fse from "fs-extra";
|
||||
import _ from "lodash";
|
||||
import { makeObservable, observable, reaction, when } from "mobx";
|
||||
@@ -46,6 +46,8 @@ import { InstalledExtensions } from "./installed-extensions";
|
||||
import { Notice } from "./notice";
|
||||
import { SettingLayout } from "../layout/setting-layout";
|
||||
import { docsUrl } from "../../../common/vars";
|
||||
import { dialog } from "../../remote-helpers";
|
||||
import { getPath } from "../../../common/utils/getPath";
|
||||
|
||||
function getMessageFromError(error: any): string {
|
||||
if (!error || typeof error !== "object") {
|
||||
@@ -466,9 +468,8 @@ async function installFromInput(input: string) {
|
||||
const supportedFormats = ["tar", "tgz"];
|
||||
|
||||
async function installFromSelectFileDialog() {
|
||||
const { dialog, BrowserWindow, app } = remote;
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), {
|
||||
defaultPath: app.getPath("downloads"),
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog({
|
||||
defaultPath: getPath("downloads"),
|
||||
properties: ["openFile", "multiSelections"],
|
||||
message: `Select extensions to install (formats: ${supportedFormats.join(", ")}), `,
|
||||
buttonLabel: "Use configuration",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import "./add-helm-repo-dialog.scss";
|
||||
|
||||
import React from "react";
|
||||
import { remote, FileFilter } from "electron";
|
||||
import type { FileFilter } from "electron";
|
||||
import { observable, makeObservable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { Dialog, DialogProps } from "../dialog";
|
||||
@@ -35,6 +35,7 @@ import { SubTitle } from "../layout/sub-title";
|
||||
import { Icon } from "../icon";
|
||||
import { Notifications } from "../notifications";
|
||||
import { HelmRepo, HelmRepoManager } from "../../../main/helm/helm-repo-manager";
|
||||
import { dialog } from "../../remote-helpers";
|
||||
|
||||
interface Props extends Partial<DialogProps> {
|
||||
onAddRepo: Function
|
||||
@@ -88,8 +89,7 @@ export class AddHelmRepoDialog extends React.Component<Props> {
|
||||
}
|
||||
|
||||
async selectFileDialog(type: FileType, fileFilter: FileFilter) {
|
||||
const { dialog, BrowserWindow } = remote;
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), {
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog({
|
||||
defaultPath: this.getFilePath(type),
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
message: `Select file`,
|
||||
|
||||
@@ -50,6 +50,7 @@ export async function initView(clusterId: ClusterId) {
|
||||
const parentElem = document.getElementById("lens-views");
|
||||
const iframe = document.createElement("iframe");
|
||||
|
||||
iframe.id = `cluster-frame-${cluster.id}`;
|
||||
iframe.name = cluster.contextName;
|
||||
iframe.setAttribute("src", getClusterFrameUrl(clusterId));
|
||||
iframe.addEventListener("load", () => {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export * from "./path-picker";
|
||||
@@ -27,7 +27,7 @@ import { UserStore } from "../../common/user-store";
|
||||
import { getAllEntries } from "../components/+preferences/kubeconfig-syncs";
|
||||
import { runInAction } from "mobx";
|
||||
import { isWindows } from "../../common/vars";
|
||||
import { PathPicker } from "../components/path-picker/path-picker";
|
||||
import { PathPicker } from "../components/path-picker";
|
||||
import { Notifications } from "../components/notifications";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ function HotbarTooManyItemsHandler(): void {
|
||||
Notifications.error(`Cannot have more than ${defaultHotbarCells} items pinned to a hotbar`);
|
||||
}
|
||||
|
||||
export function registerIpcHandlers() {
|
||||
export function registerIpcListeners() {
|
||||
onCorrect({
|
||||
source: ipcRenderer,
|
||||
channel: UpdateAvailableChannel,
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import { navigate } from "../navigation";
|
||||
|
||||
/**
|
||||
* The definition of a keyboard shortcut
|
||||
*/
|
||||
interface Shortcut {
|
||||
code?: string;
|
||||
key?: string;
|
||||
metaKey?: boolean;
|
||||
altKey?: boolean;
|
||||
shiftKey?: boolean;
|
||||
ctrlKey?: boolean;
|
||||
action: () => void;
|
||||
}
|
||||
|
||||
const shortcuts: Shortcut[] = [
|
||||
{
|
||||
key: "p",
|
||||
metaKey: true,
|
||||
shiftKey: true,
|
||||
action: () => ipcRenderer.emit("command-palette:open"),
|
||||
},
|
||||
{
|
||||
code: "Comma",
|
||||
metaKey: true,
|
||||
action: () => navigate("/preferences"),
|
||||
},
|
||||
];
|
||||
|
||||
function shortcutMatches(shortcut: Shortcut, event: KeyboardEvent): boolean {
|
||||
if (typeof shortcut.metaKey === "boolean" && shortcut.metaKey !== event.metaKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof shortcut.altKey === "boolean" && shortcut.altKey !== event.altKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof shortcut.shiftKey === "boolean" && shortcut.shiftKey !== event.shiftKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof shortcut.ctrlKey === "boolean" && shortcut.ctrlKey !== event.ctrlKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof shortcut.code === "string" && shortcut.code !== event.code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof shortcut.key === "string" && shortcut.key !== event.key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function registerKeyboardShortcuts() {
|
||||
window.addEventListener("keydown", event => {
|
||||
for (const shortcut of shortcuts) {
|
||||
if (shortcutMatches(shortcut, event)) {
|
||||
shortcut.action();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -32,10 +32,11 @@ import { ExtensionLoader } from "../extensions/extension-loader";
|
||||
import { broadcastMessage } from "../common/ipc";
|
||||
import { CommandContainer } from "./components/command-palette/command-container";
|
||||
import { bindProtocolAddRouteHandlers, LensProtocolRouterRenderer } from "./protocol-handler";
|
||||
import { registerIpcHandlers } from "./ipc";
|
||||
import { registerIpcListeners } from "./ipc";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { IpcRendererNavigationEvents } from "./navigation/events";
|
||||
import { catalogEntityRegistry } from "./api/catalog-entity-registry";
|
||||
import { registerKeyboardShortcuts } from "./keyboard-shortcuts";
|
||||
|
||||
@observer
|
||||
export class LensApp extends React.Component {
|
||||
@@ -48,7 +49,8 @@ export class LensApp extends React.Component {
|
||||
window.addEventListener("offline", () => broadcastMessage("network:offline"));
|
||||
window.addEventListener("online", () => broadcastMessage("network:online"));
|
||||
|
||||
registerIpcHandlers();
|
||||
registerKeyboardShortcuts();
|
||||
registerIpcListeners();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { dialogShowOpenDialogHandler, requestMain } from "../../common/ipc";
|
||||
|
||||
export async function showOpenDialog(options: Electron.OpenDialogOptions): Promise<Electron.OpenDialogReturnValue> {
|
||||
return requestMain(dialogShowOpenDialogHandler, options);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import * as dialog from "./dialog";
|
||||
|
||||
export { dialog };
|
||||
@@ -22,13 +22,12 @@
|
||||
// Keeps window.localStorage state in external JSON-files.
|
||||
// Because app creates random port between restarts => storage session wiped out each time.
|
||||
import path from "path";
|
||||
import { app, remote } from "electron";
|
||||
import { comparer, observable, reaction, toJS, when } from "mobx";
|
||||
import fse from "fs-extra";
|
||||
import { StorageHelper } from "./storageHelper";
|
||||
import { ClusterStore } from "../../common/cluster-store";
|
||||
import logger from "../../main/logger";
|
||||
import { getHostedClusterId } from "../../common/utils";
|
||||
import { getHostedClusterId, getPath } from "../../common/utils";
|
||||
|
||||
const storage = observable({
|
||||
initialized: false,
|
||||
@@ -47,7 +46,7 @@ export function createStorage<T>(key: string, defaultValue: T) {
|
||||
|
||||
export function createAppStorage<T>(key: string, defaultValue: T, clusterId?: string | undefined) {
|
||||
const { logPrefix } = StorageHelper;
|
||||
const folder = path.resolve((app || remote.app).getPath("userData"), "lens-local-storage");
|
||||
const folder = path.resolve(getPath("userData"), "lens-local-storage");
|
||||
const fileName = `${clusterId ?? "app"}.json`;
|
||||
const filePath = path.resolve(folder, fileName);
|
||||
|
||||
|
||||
Reference in new issue
Block a user