mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
mobx-6: use toJS()-wrapper since monkey-patching require(mobx).toJS doesn't work
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
4a9178e8ea
commit
5d09d7a126
@ -50,9 +50,9 @@ export class ExamplePreferencesStore extends Store.ExtensionStore<ExamplePrefere
|
||||
}
|
||||
|
||||
toJSON(): ExamplePreferencesModel {
|
||||
return toJS({
|
||||
enabled: this.enabled
|
||||
});
|
||||
return {
|
||||
enabled: toJS(this.enabled)
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { action, computed, observable, toJS, makeObservable } from "mobx";
|
||||
import { action, computed, observable, makeObservable } from "mobx";
|
||||
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity";
|
||||
import { toJS } from "../utils";
|
||||
|
||||
export class CatalogCategoryRegistry {
|
||||
@observable protected categories: CatalogCategory[] = [];
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import path from "path";
|
||||
import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron";
|
||||
import { unlink } from "fs-extra";
|
||||
import { action, comparer, computed, observable, reaction, toJS, makeObservable } from "mobx";
|
||||
import { action, comparer, computed, observable, reaction, makeObservable } from "mobx";
|
||||
import { BaseStore } from "./base-store";
|
||||
import { Cluster, ClusterState } from "../main/cluster";
|
||||
import migrations from "../migrations/cluster-store";
|
||||
@ -12,7 +12,7 @@ import { saveToAppFiles } from "./utils/saveToAppFiles";
|
||||
import { KubeConfig } from "@kubernetes/client-node";
|
||||
import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc";
|
||||
import { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting";
|
||||
import { disposer, noop } from "./utils";
|
||||
import { disposer, noop, toJS } from "./utils";
|
||||
|
||||
export interface ClusterIconUpload {
|
||||
clusterId: string;
|
||||
|
||||
@ -2,24 +2,6 @@
|
||||
import * as Mobx from "mobx";
|
||||
import * as Immer from "immer";
|
||||
|
||||
const { isObservable, toJS, observable } = Mobx;
|
||||
|
||||
/**
|
||||
* Patch-fixing mobx@6.toJS() to support partially observable objects as data-input.
|
||||
* Otherwise it won't be recursively converted to corresponding non-observable plain JS-structure.
|
||||
* @example
|
||||
* data = {one: 1, two: observable.array([2])}; // "data" itself is non-observable
|
||||
*/
|
||||
Object.defineProperty(Mobx, "toJS", {
|
||||
value(data: any) {
|
||||
if (typeof data === "object" && !isObservable(data)) {
|
||||
return toJS(observable.box(data).get());
|
||||
}
|
||||
|
||||
return toJS(data);
|
||||
}
|
||||
});
|
||||
|
||||
export default function configurePackages() {
|
||||
// Docs: https://mobx.js.org/configuration.html
|
||||
Mobx.configure({
|
||||
@ -33,7 +15,7 @@ export default function configurePackages() {
|
||||
});
|
||||
|
||||
// Docs: https://immerjs.github.io/immer/
|
||||
// Required for `storage-helper.ts`
|
||||
// Required in `utils/storage-helper.ts`
|
||||
Immer.setAutoFreeze(false); // allow to merge mobx observables
|
||||
Immer.enableMapSet(); // allow to merge maps and sets
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { action, comparer, observable, toJS, makeObservable } from "mobx";
|
||||
import { action, comparer, observable, makeObservable } from "mobx";
|
||||
import { BaseStore } from "./base-store";
|
||||
import migrations from "../migrations/hotbar-store";
|
||||
import * as uuid from "uuid";
|
||||
import { CatalogEntityItem } from "../renderer/components/+catalog/catalog-entity.store";
|
||||
import isNull from "lodash/isNull";
|
||||
import { toJS } from "./utils";
|
||||
|
||||
export interface HotbarItem {
|
||||
entity: {
|
||||
|
||||
@ -3,32 +3,33 @@
|
||||
// https://www.electronjs.org/docs/api/ipc-renderer
|
||||
|
||||
import { ipcMain, ipcRenderer, remote, webContents } from "electron";
|
||||
import { toJS } from "mobx";
|
||||
import { toJS } from "../utils/toJS";
|
||||
import logger from "../../main/logger";
|
||||
import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames";
|
||||
|
||||
const subFramesChannel = "ipc:get-sub-frames";
|
||||
|
||||
export function handleRequest(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) {
|
||||
ipcMain.handle(channel, (event: Electron.IpcMainInvokeEvent, ...args: any[]) => {
|
||||
args = toJS(args); // unwrap possibly leaking observable values
|
||||
ipcMain.handle(channel, async (event, ...args) => {
|
||||
const payload = await listener(event, ...args);
|
||||
|
||||
return listener(event, ...args);
|
||||
return sanitizePayload(payload);
|
||||
});
|
||||
}
|
||||
|
||||
export async function requestMain(channel: string, ...args: any[]) {
|
||||
return ipcRenderer.invoke(channel, ...toJS(args));
|
||||
return ipcRenderer.invoke(channel, ...args.map(sanitizePayload));
|
||||
}
|
||||
|
||||
function getSubFrames(): ClusterFrameInfo[] {
|
||||
return toJS(Array.from(clusterFrameMap.values()));
|
||||
return Array.from(clusterFrameMap.values());
|
||||
}
|
||||
|
||||
export async function broadcastMessage(channel: string, ...args: any[]) {
|
||||
const views = (webContents || remote?.webContents)?.getAllWebContents();
|
||||
|
||||
if (!views) return;
|
||||
args = args.map(sanitizePayload);
|
||||
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.send(channel, ...args);
|
||||
@ -83,7 +84,13 @@ export function unsubscribeAllFromBroadcast(channel: string) {
|
||||
}
|
||||
|
||||
export function bindBroadcastHandlers() {
|
||||
handleRequest(subFramesChannel, () => {
|
||||
return getSubFrames();
|
||||
});
|
||||
handleRequest(subFramesChannel, () => getSubFrames());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizing data for IPC-messaging before send.
|
||||
* Removes possible observable values to avoid exceptions like "can't clone object".
|
||||
*/
|
||||
function sanitizePayload<T>(data: any): T {
|
||||
return toJS(data);
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import type { ThemeId } from "../renderer/theme.store";
|
||||
import { app, remote } from "electron";
|
||||
import semver from "semver";
|
||||
import { readFile } from "fs-extra";
|
||||
import { action, computed, observable, reaction, toJS, makeObservable } from "mobx";
|
||||
import { action, computed, observable, reaction, makeObservable } from "mobx";
|
||||
import moment from "moment-timezone";
|
||||
import { BaseStore } from "./base-store";
|
||||
import migrations from "../migrations/user-store";
|
||||
@ -13,7 +13,7 @@ import logger from "../main/logger";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import { fileNameMigration } from "../migrations/user-store";
|
||||
import { ObservableToggleSet } from "../renderer/utils";
|
||||
import { ObservableToggleSet, toJS } from "../renderer/utils";
|
||||
|
||||
export interface UserStoreModel {
|
||||
kubeConfigPath: string;
|
||||
|
||||
25
src/common/utils/__tests__/toJS.test.ts
Normal file
25
src/common/utils/__tests__/toJS.test.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { isObservable, observable } from "mobx";
|
||||
import { toJS } from "../toJS";
|
||||
|
||||
describe("utils/toJS(data: any)", () => {
|
||||
const y = { y: 2 };
|
||||
|
||||
const data = observable({ x: 1, y }, {}, {
|
||||
deep: false, // this will keep ref to "y"
|
||||
});
|
||||
const data2 = {
|
||||
x: 1, // partially observable
|
||||
y: observable(y),
|
||||
};
|
||||
|
||||
test("converts mobx-observable to corresponding js struct with links preserving", () => {
|
||||
expect(toJS(data).y).toBe(y);
|
||||
expect(isObservable(toJS(data).y)).toBeFalsy();
|
||||
});
|
||||
|
||||
test("converts partially observable js struct", () => {
|
||||
expect(toJS(data2).y).not.toBe(y);
|
||||
expect(toJS(data2).y).toEqual(y);
|
||||
expect(isObservable(toJS(data2).y)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@ -6,6 +6,7 @@ export * from "./app-version";
|
||||
export * from "./autobind";
|
||||
export * from "./base64";
|
||||
export * from "./camelCase";
|
||||
export * from "./toJS";
|
||||
export * from "./cloneJson";
|
||||
export * from "./debouncePromise";
|
||||
export * from "./defineGlobal";
|
||||
|
||||
18
src/common/utils/toJS.ts
Normal file
18
src/common/utils/toJS.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Wrapper for mobx.toJS() to support partially observable objects as data-input (>= mobx6).
|
||||
* Otherwise, output result won't be recursively converted to corresponding plain JS-structure.
|
||||
*
|
||||
* @example
|
||||
* mobx.toJS({one: 1, two: observable.array([2])}); // "data.two" == ObservableArray<number>
|
||||
*/
|
||||
import * as mobx from "mobx";
|
||||
import { isObservable, observable } from "mobx";
|
||||
|
||||
export function toJS<T>(data: T): T {
|
||||
// make data observable for recursive toJS()-output
|
||||
if (typeof data === "object" && !isObservable(data)) {
|
||||
return mobx.toJS(observable.box(data).get());
|
||||
}
|
||||
|
||||
return mobx.toJS(data);
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { action, IEnhancer, IObservableSetInitialValues, makeObservable, ObservableSet } from "mobx";
|
||||
import { ObservableSet } from "mobx";
|
||||
|
||||
export class ToggleSet<T> extends Set<T> {
|
||||
public toggle(value: T): void {
|
||||
@ -10,13 +10,6 @@ export class ToggleSet<T> extends Set<T> {
|
||||
}
|
||||
|
||||
export class ObservableToggleSet<T> extends ObservableSet<T> {
|
||||
constructor(data?: IObservableSetInitialValues<T>, enhancer?: IEnhancer<T>) {
|
||||
super(data, enhancer);
|
||||
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@action
|
||||
public toggle(value: T): void {
|
||||
if (!this.delete(value)) {
|
||||
// Set.prototype.delete returns false if `value` was not in the set
|
||||
|
||||
@ -2,11 +2,11 @@ import { watch } from "chokidar";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { EventEmitter } from "events";
|
||||
import fse from "fs-extra";
|
||||
import { observable, reaction, toJS, when, makeObservable } from "mobx";
|
||||
import { observable, reaction, when, makeObservable } from "mobx";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc";
|
||||
import { Singleton } from "../common/utils";
|
||||
import { Singleton, toJS } from "../common/utils";
|
||||
import logger from "../main/logger";
|
||||
import { ExtensionInstallationStateStore } from "../renderer/components/+extensions/extension-install.store";
|
||||
import { extensionInstaller, PackageJson } from "./extension-installer";
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { LensExtensionId } from "./lens-extension";
|
||||
import { BaseStore } from "../common/base-store";
|
||||
import { action, computed, observable, toJS, makeObservable } from "mobx";
|
||||
import { action, computed, observable, makeObservable } from "mobx";
|
||||
import { toJS } from "../common/utils";
|
||||
|
||||
export interface LensExtensionsStoreModel {
|
||||
extensions: Record<LensExtensionId, LensExtensionState>;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { reaction, toJS } from "mobx";
|
||||
import { reaction } from "mobx";
|
||||
import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "../common/ipc";
|
||||
import { CatalogEntityRegistry} from "../common/catalog";
|
||||
import "../common/catalog-entities/kubernetes-cluster";
|
||||
import { Disposer } from "../common/utils";
|
||||
import { Disposer, toJS } from "../common/utils";
|
||||
|
||||
export class CatalogPusher {
|
||||
static init(catalog: CatalogEntityRegistry) {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import "../common/cluster-ipc";
|
||||
import type http from "http";
|
||||
import { ipcMain } from "electron";
|
||||
import { action, autorun, reaction, toJS, makeObservable } from "mobx";
|
||||
import { action, autorun, makeObservable, reaction } from "mobx";
|
||||
import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store";
|
||||
import { Cluster } from "./cluster";
|
||||
import logger from "./logger";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import { Singleton } from "../common/utils";
|
||||
import { Singleton, toJS } from "../common/utils";
|
||||
import { catalogEntityRegistry } from "../common/catalog";
|
||||
import { KubernetesCluster } from "../common/catalog-entities/kubernetes-cluster";
|
||||
|
||||
@ -24,7 +24,6 @@ export class ClusterManager extends Singleton {
|
||||
this.syncClustersFromCatalog(entities);
|
||||
});
|
||||
|
||||
|
||||
// auto-stop removed clusters
|
||||
autorun(() => {
|
||||
const removedClusters = Array.from(ClusterStore.getInstance().removedClusters.values());
|
||||
@ -143,9 +142,7 @@ export class ClusterManager extends Singleton {
|
||||
}
|
||||
|
||||
export function catalogEntityFromCluster(cluster: Cluster) {
|
||||
return new KubernetesCluster(toJS({
|
||||
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||
kind: "KubernetesCluster",
|
||||
return new KubernetesCluster({
|
||||
metadata: {
|
||||
uid: cluster.id,
|
||||
name: cluster.name,
|
||||
@ -164,5 +161,5 @@ export function catalogEntityFromCluster(cluster: Cluster) {
|
||||
message: "",
|
||||
active: !cluster.disconnected
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,15 +1,6 @@
|
||||
import { ipcMain } from "electron";
|
||||
import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-store";
|
||||
import {
|
||||
action,
|
||||
comparer,
|
||||
computed,
|
||||
observable,
|
||||
reaction,
|
||||
toJS,
|
||||
when,
|
||||
makeObservable,
|
||||
} from "mobx";
|
||||
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||
import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc";
|
||||
import { ContextHandler } from "./context-handler";
|
||||
import { AuthorizationV1Api, CoreV1Api, HttpError, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node";
|
||||
@ -21,6 +12,7 @@ import logger from "./logger";
|
||||
import { VersionDetector } from "./cluster-detectors/version-detector";
|
||||
import { detectorRegistry } from "./cluster-detectors/detector-registry";
|
||||
import plimit from "p-limit";
|
||||
import { toJS } from "../common/utils";
|
||||
|
||||
export enum ClusterStatus {
|
||||
AccessGranted = 2,
|
||||
|
||||
@ -2,10 +2,11 @@ import { randomBytes } from "crypto";
|
||||
import { SHA256 } from "crypto-js";
|
||||
import { app, remote } from "electron";
|
||||
import fse from "fs-extra";
|
||||
import { action, observable, toJS, makeObservable } from "mobx";
|
||||
import { action, observable, makeObservable } from "mobx";
|
||||
import path from "path";
|
||||
import { BaseStore } from "../common/base-store";
|
||||
import { LensExtensionId } from "../extensions/lens-extension";
|
||||
import { toJS } from "../common/utils";
|
||||
|
||||
interface FSProvisionModel {
|
||||
extensions: Record<string, string>; // extension names to paths
|
||||
|
||||
@ -4,11 +4,11 @@ import React from "react";
|
||||
import kebabCase from "lodash/kebabCase";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { autorun, observable, reaction, toJS, makeObservable } from "mobx";
|
||||
import { autorun, observable, reaction, makeObservable } from "mobx";
|
||||
import { IPodMetrics, nodesApi, Pod, pvcApi, configMapApi } from "../../api/endpoints";
|
||||
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||
import { Badge } from "../badge";
|
||||
import { boundMethod, cssNames, interval } from "../../utils";
|
||||
import { boundMethod, cssNames, interval, toJS } from "../../utils";
|
||||
import { PodDetailsContainer } from "./pod-details-container";
|
||||
import { PodDetailsAffinities } from "./pod-details-affinities";
|
||||
import { PodDetailsTolerations } from "./pod-details-tolerations";
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
|
||||
import { Select } from "../select";
|
||||
import { computed, observable, toJS, makeObservable } from "mobx";
|
||||
import { computed, makeObservable, observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||
@ -52,13 +51,11 @@ export class CommandDialog extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = toJS(command.action);
|
||||
|
||||
try {
|
||||
CommandOverlay.close();
|
||||
|
||||
if (command.scope === "global") {
|
||||
action({
|
||||
command.action({
|
||||
entity: commandRegistry.activeEntity
|
||||
});
|
||||
} else if(commandRegistry.activeEntity) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { autorun, observable, reaction, toJS } from "mobx";
|
||||
import { autoBind, createStorage, StorageHelper } from "../../utils";
|
||||
import { autorun, observable, reaction } from "mobx";
|
||||
import { autoBind, createStorage, StorageHelper, toJS } from "../../utils";
|
||||
import { dockStore, TabId } from "./dock.store";
|
||||
|
||||
export interface DockTabStoreOptions {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import debounce from "lodash/debounce";
|
||||
import { reaction, toJS } from "mobx";
|
||||
import { reaction } from "mobx";
|
||||
import { Terminal as XTerm } from "xterm";
|
||||
import { FitAddon } from "xterm-addon-fit";
|
||||
import { dockStore, TabId } from "./dock.store";
|
||||
import { TerminalApi } from "../../api/terminal-api";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import { boundMethod } from "../../utils";
|
||||
import { boundMethod, toJS } from "../../utils";
|
||||
import { isMac } from "../../../common/vars";
|
||||
import { camelCase } from "lodash";
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user