mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
store-sync-fixes, part 1
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
67377af52e
commit
c06c322ca9
@ -1,14 +1,13 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import Config from "conf"
|
import Config from "conf"
|
||||||
import { Options as ConfOptions } from "conf/dist/source/types"
|
import { Options as ConfOptions } from "conf/dist/source/types"
|
||||||
import produce from "immer";
|
|
||||||
import { app, ipcMain, ipcRenderer, remote } from "electron"
|
import { app, ipcMain, ipcRenderer, remote } from "electron"
|
||||||
import { action, observable, reaction, toJS, when } from "mobx";
|
import { action, observable, reaction, toJS, when } from "mobx";
|
||||||
import Singleton from "./utils/singleton";
|
import Singleton from "./utils/singleton";
|
||||||
import isEqual from "lodash/isEqual"
|
|
||||||
import { getAppVersion } from "./utils/app-version";
|
import { getAppVersion } from "./utils/app-version";
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import { broadcastMessage } from "./ipc-helpers";
|
import { broadcastMessage } from "./ipc-helpers";
|
||||||
|
import isEqual from "lodash/isEqual";
|
||||||
|
|
||||||
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
||||||
autoLoad?: boolean;
|
autoLoad?: boolean;
|
||||||
@ -63,25 +62,33 @@ export class BaseStore<T = any> extends Singleton {
|
|||||||
});
|
});
|
||||||
const storeModel = Object.assign({}, this.storeConfig.store);
|
const storeModel = Object.assign({}, this.storeConfig.store);
|
||||||
Reflect.deleteProperty(storeModel, "__internal__"); // fixme: avoid "external-internals"
|
Reflect.deleteProperty(storeModel, "__internal__"); // fixme: avoid "external-internals"
|
||||||
logger.info(`[STORE]: loaded ${this.storeConfig.path}`);
|
logger.info(`[STORE]: LOADED from ${this.storeConfig.path}`);
|
||||||
this.fromStore(storeModel);
|
this.fromStore(storeModel);
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async save(model: T) {
|
||||||
|
logger.info(`[STORE]: SAVING ${this.name}`);
|
||||||
|
// fixme: https://github.com/sindresorhus/conf/issues/114
|
||||||
|
Object.entries(model).forEach(([key, value]) => {
|
||||||
|
this.storeConfig.set(key, value); // save update to config file
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
enableSync() {
|
enableSync() {
|
||||||
this.syncDisposers.push(
|
this.syncDisposers.push(
|
||||||
reaction(() => this.toJSON(), this.onModelChange.bind(this)),
|
reaction(() => this.toJSON(), model => this.onModelChange(model)),
|
||||||
);
|
);
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
ipcMain.on(this.syncEvent, (event, model: T) => {
|
ipcMain.on(this.syncEvent, (event, model: T) => {
|
||||||
logger.debug(`[STORE]: ${this.name} sync update from renderer`, model);
|
logger.info(`[STORE]: SYNC ${this.name} from renderer`);
|
||||||
this.onSync(model);
|
this.onSync(model);
|
||||||
});
|
});
|
||||||
this.syncDisposers.push(() => ipcMain.removeAllListeners(this.syncEvent));
|
this.syncDisposers.push(() => ipcMain.removeAllListeners(this.syncEvent));
|
||||||
}
|
}
|
||||||
if (ipcRenderer) {
|
if (ipcRenderer) {
|
||||||
ipcRenderer.on(this.syncEvent, (event, model: T) => {
|
ipcRenderer.on(this.syncEvent, (event, model: T) => {
|
||||||
logger.debug(`[STORE]: ${this.name} sync update from main`, model);
|
logger.info(`[STORE]: SYNC ${this.name} from main`);
|
||||||
this.onSync(model);
|
this.onSync(model);
|
||||||
});
|
});
|
||||||
this.syncDisposers.push(() => ipcRenderer.removeAllListeners(this.syncEvent));
|
this.syncDisposers.push(() => ipcRenderer.removeAllListeners(this.syncEvent));
|
||||||
@ -101,14 +108,10 @@ export class BaseStore<T = any> extends Singleton {
|
|||||||
|
|
||||||
protected async onModelChange(model: T) {
|
protected async onModelChange(model: T) {
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
broadcastMessage(this.syncEvent, model); // send updates to renderer views
|
this.save(model); // save to config file
|
||||||
|
broadcastMessage({ channel: this.syncEvent }, model); // broadcast to renderer views
|
||||||
// fixme: https://github.com/sindresorhus/conf/issues/114
|
|
||||||
Object.entries(model).forEach(([key, value]) => {
|
|
||||||
this.storeConfig.set(key, value); // save update to config file
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// sends "update-request" event to main-process
|
// send "update-request" to main-process
|
||||||
if (ipcRenderer) {
|
if (ipcRenderer) {
|
||||||
ipcRenderer.send(this.syncEvent, model);
|
ipcRenderer.send(this.syncEvent, model);
|
||||||
}
|
}
|
||||||
@ -119,11 +122,6 @@ export class BaseStore<T = any> extends Singleton {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
merge(updater: (modelDraft: T) => void) {
|
|
||||||
this.data = produce(this.data, updater);
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: use "serializr" ?
|
// todo: use "serializr" ?
|
||||||
toJSON(): T {
|
toJSON(): T {
|
||||||
return toJS(this.data, {
|
return toJS(this.data, {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// https://www.electronjs.org/docs/api/ipc-main
|
// https://www.electronjs.org/docs/api/ipc-main
|
||||||
// https://www.electronjs.org/docs/api/ipc-renderer
|
// https://www.electronjs.org/docs/api/ipc-renderer
|
||||||
|
|
||||||
import { ipcMain, ipcRenderer, webContents } from "electron"
|
import { ipcMain, ipcRenderer, WebContents, webContents } from "electron"
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
|
|
||||||
export type IpcChannel = string;
|
export type IpcChannel = string;
|
||||||
@ -15,8 +15,17 @@ export interface IpcMessageHandler<T extends any[] = any> {
|
|||||||
(...args: T): any;
|
(...args: T): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function broadcastMessage(channel: IpcChannel, ...args: any[]) {
|
export interface IpcBroadcastOpts {
|
||||||
webContents.getAllWebContents().forEach(webContent => {
|
channel: IpcChannel
|
||||||
|
filter?: (webContent: WebContents) => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function broadcastMessage({ channel, filter }: IpcBroadcastOpts, ...args: any[]) {
|
||||||
|
let webContentsList = webContents.getAllWebContents();
|
||||||
|
if (filter) {
|
||||||
|
webContentsList = webContentsList.filter(filter);
|
||||||
|
}
|
||||||
|
webContentsList.forEach(webContent => {
|
||||||
webContent.send(channel, ...args);
|
webContent.send(channel, ...args);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export class KubeAuthProxy {
|
|||||||
const channel = `kube-auth:${this.cluster.id}`
|
const channel = `kube-auth:${this.cluster.id}`
|
||||||
const message = { data, stream };
|
const message = { data, stream };
|
||||||
logger.debug(channel, message);
|
logger.debug(channel, message);
|
||||||
broadcastMessage(channel, message);
|
broadcastMessage({ channel }, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public exit() {
|
public exit() {
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import type { ClusterId } from "../common/cluster-store";
|
|||||||
import { clusterStore } from "../common/cluster-store";
|
import { clusterStore } from "../common/cluster-store";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
|
||||||
|
// fixme: activate landing-page when no-clusters exists
|
||||||
|
|
||||||
export class WindowManager {
|
export class WindowManager {
|
||||||
protected activeView: BrowserWindow;
|
protected activeView: BrowserWindow;
|
||||||
protected views = new Map<ClusterId, BrowserWindow>();
|
protected views = new Map<ClusterId, BrowserWindow>();
|
||||||
@ -68,11 +70,12 @@ export class WindowManager {
|
|||||||
const activeView = this.activeView;
|
const activeView = this.activeView;
|
||||||
const isLoadedBefore = !!this.getView(clusterId);
|
const isLoadedBefore = !!this.getView(clusterId);
|
||||||
const view = this.initView(clusterId);
|
const view = this.initView(clusterId);
|
||||||
logger.info(`Activating cluster(${cluster.id}) view`, {
|
logger.info(`[WINDOW-MANAGER]: activating cluster view`, {
|
||||||
|
id: cluster.id,
|
||||||
contextName: cluster.contextName,
|
contextName: cluster.contextName,
|
||||||
isLoadedBefore: isLoadedBefore,
|
isLoadedBefore: isLoadedBefore,
|
||||||
});
|
});
|
||||||
if (view !== activeView) {
|
if (activeView !== view) {
|
||||||
if (!isLoadedBefore) {
|
if (!isLoadedBefore) {
|
||||||
await cluster.whenReady;
|
await cluster.whenReady;
|
||||||
await view.loadURL(cluster.webContentUrl);
|
await view.loadURL(cluster.webContentUrl);
|
||||||
@ -86,7 +89,10 @@ export class WindowManager {
|
|||||||
this.activeView = view;
|
this.activeView = view;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`Activating cluster(${clusterId}) view has failed: ${err.stack}`);
|
logger.error(`[WINDOW-MANAGER]: can't activate cluster view`, {
|
||||||
|
clusterId: cluster.id,
|
||||||
|
err: String(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ interface Props {
|
|||||||
export class ClustersMenu extends React.Component<Props> {
|
export class ClustersMenu extends React.Component<Props> {
|
||||||
showCluster = (cluster: Cluster) => {
|
showCluster = (cluster: Cluster) => {
|
||||||
clusterStore.activeClusterId = cluster.id;
|
clusterStore.activeClusterId = cluster.id;
|
||||||
console.log('load lens for cluster:', cluster.toJSON());
|
console.log('show lens for cluster:', cluster.contextName);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCluster = () => {
|
addCluster = () => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user