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:
parent
4a06f65cb8
commit
507e2dcfee
@ -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 {
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user