1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

refactoring

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-07-08 22:59:33 +03:00
parent 4a06f65cb8
commit 507e2dcfee
7 changed files with 142 additions and 82 deletions

View File

@ -40,6 +40,7 @@ export interface ClusterPreferences {
export class ClusterStore extends BaseStore<ClusterStoreModel> { export class ClusterStore extends BaseStore<ClusterStoreModel> {
@observable activeCluster: ClusterId; @observable activeCluster: ClusterId;
@observable clusters = observable.map<ClusterId, Cluster>(); @observable clusters = observable.map<ClusterId, Cluster>();
@observable removedClusters = observable.map<ClusterId, Cluster>();
private constructor() { private constructor() {
super({ super({
@ -86,12 +87,32 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
@action @action
protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) { protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) {
const clustersMap = new Map<ClusterId, Cluster>(); const currentClusters = this.clusters.toJS();
const newClusters = new Map<ClusterId, Cluster>();
const removedClusters = new Map<ClusterId, Cluster>();
// update new clusters
clusters.forEach(clusterModel => { clusters.forEach(clusterModel => {
clustersMap.set(clusterModel.id, new Cluster(clusterModel)); let cluster = currentClusters.get(clusterModel.id);
if (cluster) {
Object.assign(cluster, clusterModel);
cluster.mergeModel(clusterModel);
} else {
cluster = new Cluster(clusterModel);
}
newClusters.set(clusterModel.id, cluster);
}); });
this.activeCluster = clustersMap.has(activeCluster) ? activeCluster : null;
this.clusters.replace(clustersMap); // update removed clusters
currentClusters.forEach(cluster => {
if (!newClusters.has(cluster.id)) {
removedClusters.set(cluster.id, cluster);
}
});
this.activeCluster = newClusters.has(activeCluster) ? activeCluster : null;
this.clusters.replace(newClusters);
this.removedClusters.replace(removedClusters);
} }
toJSON(): ClusterStoreModel { toJSON(): ClusterStoreModel {

View File

@ -1,18 +1,18 @@
import { autorun } from "mobx";
import { apiPrefix, appProto } from "../common/vars";
import { app } from "electron" import { app } from "electron"
import { reaction } from "mobx";
import path from "path" import path from "path"
import http from "http" import http from "http"
import { copyFile, ensureDir } from "fs-extra" import { copyFile, ensureDir } from "fs-extra"
import filenamify from "filenamify" import filenamify from "filenamify"
import { validateConfig } from "./k8s"; import { apiPrefix, appProto } from "../common/vars";
import { Cluster } from "./cluster"
import { ClusterId, ClusterModel, clusterStore } from "../common/cluster-store" import { ClusterId, ClusterModel, clusterStore } from "../common/cluster-store"
import logger from "./logger"
import { onMessages } from "../common/ipc-helpers"; import { onMessages } from "../common/ipc-helpers";
import { ClusterIpcMessage } from "../common/ipc-messages"; import { ClusterIpcMessage } from "../common/ipc-messages";
import { FeatureInstallRequest } from "./feature";
import { tracker } from "../common/tracker"; import { tracker } from "../common/tracker";
import { validateConfig } from "./k8s";
import { Cluster } from "./cluster"
import { FeatureInstallRequest } from "./feature";
import logger from "./logger"
export interface ClusterIconUpload { export interface ClusterIconUpload {
clusterId: string; clusterId: string;
@ -26,16 +26,19 @@ export class ClusterManager {
} }
constructor(protected port: number) { constructor(protected port: number) {
autorun(() => { reaction(() => clusterStore.clusters.toJS(), clusters => {
// fixme: detect and stop removed clusters from config file ? clusters.forEach(cluster => {
clusterStore.clusters.forEach((cluster: Cluster) => {
if (!cluster.initialized) { if (!cluster.initialized) {
cluster.init(this.port); cluster.init(this.port).then(() => cluster.refreshCluster());
cluster.refreshCluster();
} }
}) })
}); });
reaction(() => clusterStore.removedClusters.toJS(), removedClusters => {
if (removedClusters.size > 0) {
removedClusters.forEach(cluster => cluster.stopServer());
clusterStore.removedClusters.clear();
}
});
ClusterManager.ipcListen(this); ClusterManager.ipcListen(this);
} }

View File

@ -56,6 +56,10 @@ export class Cluster implements ClusterModel {
@observable features: FeatureStatusMap = {}; @observable features: FeatureStatusMap = {};
constructor(model: ClusterModel) { constructor(model: ClusterModel) {
this.mergeModel(model);
}
mergeModel(model: ClusterModel) {
Object.assign(this, model) Object.assign(this, model)
} }

View File

@ -25,12 +25,6 @@ let windowManager: WindowManager = null;
let clusterManager: ClusterManager = null; let clusterManager: ClusterManager = null;
let proxyServer: proxy.LensProxy = null; let proxyServer: proxy.LensProxy = null;
const vmURL = formatUrl({
pathname: path.join(__dirname, `${appName}.html`),
protocol: "file",
slashes: true,
})
mangleProxyEnv() mangleProxyEnv()
if (app.commandLine.getSwitchValue("proxy-server") !== "") { if (app.commandLine.getSwitchValue("proxy-server") !== "") {
process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server")
@ -82,8 +76,13 @@ async function main() {
} }
// manage lens windows // manage lens windows
windowManager = new WindowManager({showSplash: true}); const vmURL = formatUrl({
windowManager.showMain(vmURL) pathname: path.join(__dirname, `${appName}.html`),
protocol: "file",
slashes: true,
})
windowManager = new WindowManager();
windowManager.loadURL(vmURL)
} }
app.on("ready", main) app.on("ready", main)
@ -96,15 +95,8 @@ app.on('window-all-closed', function () {
windowManager = null windowManager = null
if (clusterManager) clusterManager.stop() if (clusterManager) clusterManager.stop()
} }
}) });
// app.on("activate", () => { app.on("will-quit", async event => {
// if (!windowManager) {
// logger.debug("activate main window")
// windowManager = new WindowManager({ showSplash: false })
// windowManager.showMain(vmURL)
// }
// })
app.on("will-quit", async (event) => {
event.preventDefault(); // To allow mixpanel sending to be executed event.preventDefault(); // To allow mixpanel sending to be executed
if (clusterManager) clusterManager.stop() if (clusterManager) clusterManager.stop()
if (proxyServer) proxyServer.close() if (proxyServer) proxyServer.close()

View File

@ -1,36 +1,30 @@
import { BrowserWindow, shell } from "electron" import { BrowserView, BrowserWindow, shell } from "electron"
import { reaction } from "mobx";
import windowStateKeeper from "electron-window-state" import windowStateKeeper from "electron-window-state"
import type { ClusterId } from "../common/cluster-store";
import { clusterStore } from "../common/cluster-store";
import { tracker } from "../common/tracker"; import { tracker } from "../common/tracker";
export class WindowManager { export interface WindowManagerParams {
public mainWindow: BrowserWindow = null; showSplash?: boolean;
public splashWindow: BrowserWindow = null; }
protected windowState: windowStateKeeper.State;
constructor({ showSplash = true } = {}) { export class WindowManager {
// Manage main window size&position with persistence protected mainWindow: BrowserWindow;
protected splashWindow?: BrowserWindow;
protected windowState: windowStateKeeper.State;
protected views = new Map<ClusterId, BrowserView>();
protected disposers: Function[] = [];
constructor(protected params: WindowManagerParams = {}) {
this.params = { showSplash: true, ...params };
// Manage main window size and position with state persistence
this.windowState = windowStateKeeper({ this.windowState = windowStateKeeper({
defaultHeight: 900, defaultHeight: 900,
defaultWidth: 1440, defaultWidth: 1440,
}); });
this.splashWindow = new BrowserWindow({
width: 500,
height: 300,
backgroundColor: "#1e2124",
center: true,
frame: false,
resizable: false,
show: false,
webPreferences: {
nodeIntegration: true
}
})
if (showSplash) {
this.splashWindow.loadURL("static://splash.html")
this.splashWindow.show()
}
this.mainWindow = new BrowserWindow({ this.mainWindow = new BrowserWindow({
show: false, show: false,
x: this.windowState.x, x: this.windowState.x,
@ -41,45 +35,92 @@ export class WindowManager {
titleBarStyle: "hidden", titleBarStyle: "hidden",
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
webviewTag: true
}, },
}); });
// Splash-screen window with loading indicator
this.splashWindow = new BrowserWindow({
width: 500,
height: 300,
backgroundColor: "#1e2124",
center: true,
frame: false,
resizable: false,
show: false,
});
this.splashWindow.loadURL("static://splash.html")
// Hook window state manager into window lifecycle // Hook window state manager into window lifecycle
this.windowState.manage(this.mainWindow); this.windowState.manage(this.mainWindow);
// handle close event // Disallow closing main window
this.mainWindow.on("close", () => { this.mainWindow.on("close", (evt) => {
this.mainWindow = null; evt.preventDefault();
}); });
// open external links in default browser (target=_blank, window.open) // Open external links in default browser (target=_blank, window.open)
this.mainWindow.webContents.on("new-window", (event, url) => { this.mainWindow.webContents.on("new-window", (event, url) => {
event.preventDefault(); event.preventDefault();
shell.openExternal(url); shell.openExternal(url);
}); });
// handle external links // Track main window focus
this.mainWindow.webContents.on("will-navigate", (event, link) => {
if (link.startsWith("http://localhost")) {
return;
}
event.preventDefault();
shell.openExternal(link);
})
this.mainWindow.on("focus", () => { this.mainWindow.on("focus", () => {
tracker.event("app", "focus") tracker.event("app", "focus")
}) });
// Clean up views for removed clusters
this.disposers.push(
reaction(() => clusterStore.removedClusters.toJS(), removedClusters => {
removedClusters.forEach(cluster => {
const lensView = this.getView(cluster.id);
if (lensView) {
lensView.destroy();
this.views.delete(cluster.id);
}
});
})
);
} }
public showMain(url: string) { setView(clusterId: ClusterId) {
this.mainWindow.loadURL(url).then(() => { const view = this.getView(clusterId)
this.splashWindow.hide() this.mainWindow.setBrowserView(view);
this.splashWindow.loadURL("data:text/html;charset=utf-8,").then(() => { }
this.splashWindow.close()
this.mainWindow.show() getView(clusterId: ClusterId): BrowserView {
let view = this.views.get(clusterId);
if (!view) {
view = new BrowserView({
webPreferences: {
nodeIntegration: true
}
}) })
}) // view.setBackgroundColor("#878686");
// view.setAutoResize({ horizontal: true, vertical: true });
// view.webContents.loadURL("data:text/html;charset=utf-8,<b>TEST</b>")
this.views.set(clusterId, view);
}
return view;
}
async loadURL(url: string) {
if (this.params.showSplash) {
this.splashWindow.show();
}
await this.mainWindow.loadURL(url);
this.mainWindow.show();
this.splashWindow.hide();
}
destroy() {
this.disposers.forEach(dispose => dispose());
this.disposers.length = 0;
this.views.forEach(view => view.destroy());
this.views.clear();
this.mainWindow.destroy();
this.splashWindow.destroy();
this.mainWindow = null;
this.splashWindow = null;
} }
} }

View File

@ -1,10 +1,9 @@
.Workspaces { .Workspaces {
height: 100%;
display: grid; display: grid;
grid-template-areas: "draggable draggable" "menu lens-view" "bottom-bar bottom-bar"; grid-template-areas: "draggable draggable" "menu lens-view" "bottom-bar bottom-bar";
grid-template-rows: 20px 1fr min-content; grid-template-rows: 20px 1fr min-content;
grid-template-columns: min-content 1fr; grid-template-columns: min-content 1fr;
height: 100%;
> .draggable-top { > .draggable-top {
@include set-draggable; @include set-draggable;

View File

@ -1,5 +1,6 @@
import "./workspaces.scss" import "./workspaces.scss"
import React from "react"; import React from "react";
import { observable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Trans } from "@lingui/macro"; import { Trans } from "@lingui/macro";
@ -8,7 +9,6 @@ import { Icon } from "../icon";
import { ClustersMenu } from "./clusters-menu"; import { ClustersMenu } from "./clusters-menu";
import { Menu, MenuItem } from "../menu"; import { Menu, MenuItem } from "../menu";
import { prevDefault } from "../../utils"; import { prevDefault } from "../../utils";
import { observable } from "mobx";
// todo: support `workspaceId` in URL // todo: support `workspaceId` in URL