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> {
@observable activeCluster: ClusterId;
@observable clusters = observable.map<ClusterId, Cluster>();
@observable removedClusters = observable.map<ClusterId, Cluster>();
private constructor() {
super({
@ -86,12 +87,32 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
@action
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 => {
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 {

View File

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

View File

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

View File

@ -25,12 +25,6 @@ let windowManager: WindowManager = null;
let clusterManager: ClusterManager = null;
let proxyServer: proxy.LensProxy = null;
const vmURL = formatUrl({
pathname: path.join(__dirname, `${appName}.html`),
protocol: "file",
slashes: true,
})
mangleProxyEnv()
if (app.commandLine.getSwitchValue("proxy-server") !== "") {
process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server")
@ -82,8 +76,13 @@ async function main() {
}
// manage lens windows
windowManager = new WindowManager({showSplash: true});
windowManager.showMain(vmURL)
const vmURL = formatUrl({
pathname: path.join(__dirname, `${appName}.html`),
protocol: "file",
slashes: true,
})
windowManager = new WindowManager();
windowManager.loadURL(vmURL)
}
app.on("ready", main)
@ -96,15 +95,8 @@ app.on('window-all-closed', function () {
windowManager = null
if (clusterManager) clusterManager.stop()
}
})
// app.on("activate", () => {
// if (!windowManager) {
// logger.debug("activate main window")
// windowManager = new WindowManager({ showSplash: false })
// windowManager.showMain(vmURL)
// }
// })
app.on("will-quit", async (event) => {
});
app.on("will-quit", async event => {
event.preventDefault(); // To allow mixpanel sending to be executed
if (clusterManager) clusterManager.stop()
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 type { ClusterId } from "../common/cluster-store";
import { clusterStore } from "../common/cluster-store";
import { tracker } from "../common/tracker";
export class WindowManager {
public mainWindow: BrowserWindow = null;
public splashWindow: BrowserWindow = null;
protected windowState: windowStateKeeper.State;
export interface WindowManagerParams {
showSplash?: boolean;
}
constructor({ showSplash = true } = {}) {
// Manage main window size&position with persistence
export class WindowManager {
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({
defaultHeight: 900,
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({
show: false,
x: this.windowState.x,
@ -41,45 +35,92 @@ export class WindowManager {
titleBarStyle: "hidden",
webPreferences: {
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
this.windowState.manage(this.mainWindow);
// handle close event
this.mainWindow.on("close", () => {
this.mainWindow = null;
// Disallow closing main window
this.mainWindow.on("close", (evt) => {
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) => {
event.preventDefault();
shell.openExternal(url);
});
// handle external links
this.mainWindow.webContents.on("will-navigate", (event, link) => {
if (link.startsWith("http://localhost")) {
return;
}
event.preventDefault();
shell.openExternal(link);
})
// Track main window focus
this.mainWindow.on("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) {
this.mainWindow.loadURL(url).then(() => {
this.splashWindow.hide()
this.splashWindow.loadURL("data:text/html;charset=utf-8,").then(() => {
this.splashWindow.close()
this.mainWindow.show()
setView(clusterId: ClusterId) {
const view = this.getView(clusterId)
this.mainWindow.setBrowserView(view);
}
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 {
height: 100%;
display: grid;
grid-template-areas: "draggable draggable" "menu lens-view" "bottom-bar bottom-bar";
grid-template-rows: 20px 1fr min-content;
grid-template-columns: min-content 1fr;
height: 100%;
> .draggable-top {
@include set-draggable;

View File

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