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

Fix settings saving and catalog view

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2021-04-28 12:32:34 -04:00
parent 39fbcdc695
commit ba568e33ca
4 changed files with 44 additions and 59 deletions

View File

@ -1,7 +1,8 @@
import { autorun, toJS } from "mobx";
import { reaction, toJS } 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";
export class CatalogPusher {
static init(catalog: CatalogEntityRegistry) {
@ -11,22 +12,20 @@ export class CatalogPusher {
private constructor(private catalog: CatalogEntityRegistry) {}
init() {
const disposers: { (): void; }[] = [];
const disposers: Disposer[] = [];
disposers.push(autorun(() => {
this.broadcast();
disposers.push(reaction(() => this.catalog.items, (items) => {
broadcastMessage("catalog:items", toJS(items, { recurseEverything: true }));
}, {
fireImmediately: true,
}));
const listener = subscribeToBroadcast("catalog:broadcast", () => {
this.broadcast();
broadcastMessage("catalog:items", toJS(this.catalog.items, { recurseEverything: true }));
});
disposers.push(() => unsubscribeFromBroadcast("catalog:broadcast", listener));
return disposers;
}
broadcast() {
broadcastMessage("catalog:items", toJS(this.catalog.items, { recurseEverything: true }));
}
}

View File

@ -4,7 +4,7 @@ import { watch } from "chokidar";
import fs from "fs";
import * as uuid from "uuid";
import stream from "stream";
import { ExtendedObservableMap, iter, Singleton } from "../../common/utils";
import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils";
import logger from "../logger";
import { KubeConfig } from "@kubernetes/client-node";
import { loadConfigFromString, splitConfig, validateKubeConfig } from "../../common/kube-helpers";
@ -15,16 +15,12 @@ import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store";
const logPrefix = "[KUBECONFIG-SYNC]:";
type Disposer = () => void;
export class KubeconfigSyncManager extends Singleton {
protected sources = observable.map<string, [IComputedValue<Iterable<CatalogEntity>>, Disposer]>();
protected sources = observable.map<string, [IComputedValue<CatalogEntity[]>, Disposer]>();
protected syncing = false;
protected syncListDisposer?: Disposer;
protected getSyncName(file: string): string {
return `lens:kube-sync:${file}`;
}
protected static readonly syncName = "lens:kube-sync";
@action
startSync(port: number): void {
@ -36,10 +32,17 @@ export class KubeconfigSyncManager extends Singleton {
logger.info(`${logPrefix} starting requested syncs`);
catalogEntityRegistry.addComputedSource(KubeconfigSyncManager.syncName, computed(() => (
Array.from(iter.flatMap(
this.sources.values(),
([entities]) => entities.get()
))
)));
// This must be done so that c&p-ed clusters are visible
this.startNewSync(ClusterStore.storedKubeConfigFolder, port);
for (const [filePath] of UserStore.getInstance().syncKubeconfigEntries) {
for (const filePath of UserStore.getInstance().syncKubeconfigEntries.keys()) {
this.startNewSync(filePath, port);
}
@ -63,6 +66,7 @@ export class KubeconfigSyncManager extends Singleton {
this.stopOldSync(filePath);
}
catalogEntityRegistry.removeSource(KubeconfigSyncManager.syncName);
this.syncing = false;
}
@ -70,26 +74,24 @@ export class KubeconfigSyncManager extends Singleton {
protected startNewSync(filePath: string, port: number): void {
if (this.sources.has(filePath)) {
// don't start a new sync if we already have one
return;
return void logger.debug(`${logPrefix} already syncing file/folder`, { filePath });
}
logger.info(`${logPrefix} starting sync of file`, { filePath });
const changeSet = watchFileChanges(filePath, port);
this.sources.set(filePath, watchFileChanges(filePath, port));
this.sources.set(filePath, changeSet);
catalogEntityRegistry.addComputedSource(this.getSyncName(filePath), changeSet[0]);
logger.info(`${logPrefix} starting sync of file/folder`, { filePath });
logger.debug(`${logPrefix} ${this.sources.size} files/folders watched`, { files: Array.from(this.sources.keys()) });
}
@action
protected stopOldSync(filePath: string): void {
if (!this.sources.has(filePath)) {
if (!this.sources.delete(filePath)) {
// already stopped
return;
return void logger.debug(`${logPrefix} no syncing file/folder to stop`, { filePath });
}
logger.info(`${logPrefix} stopping sync of file`, { filePath });
this.sources.delete(filePath);
catalogEntityRegistry.removeSource(this.getSyncName(filePath));
logger.info(`${logPrefix} stopping sync of file/folder`, { filePath });
logger.debug(`${logPrefix} ${this.sources.size} files/folders watched`, { files: Array.from(this.sources.keys()) });
}
}

View File

@ -16,27 +16,7 @@ export class CatalogEntityRegistry {
}
@action updateItems(items: (CatalogEntityData & CatalogEntityKindData)[]) {
this._items.forEach((item, index) => {
const foundIndex = items.findIndex((i) => i.apiVersion === item.apiVersion && i.kind === item.kind && i.metadata.uid === item.metadata.uid);
if (foundIndex === -1) {
this._items.splice(index, 1);
}
});
items.forEach((data) => {
const item = this.categoryRegistry.getEntityForData(data);
if (!item) return; // invalid data
const index = this._items.findIndex((i) => i.apiVersion === item.apiVersion && i.kind === item.kind && i.metadata.uid === item.metadata.uid);
if (index === -1) {
this._items.push(item);
} else {
this._items.splice(index, 1, item);
}
});
this._items = items.map(data => this.categoryRegistry.getEntityForData(data));
}
get items() {

View File

@ -7,7 +7,7 @@ import { Description, Folder, Delete, HelpOutline } from "@material-ui/icons";
import { action, computed, observable, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import fse from "fs-extra";
import { KubeconfigSyncEntry, UserStore } from "../../../common/user-store";
import { KubeconfigSyncEntry, KubeconfigSyncValue, UserStore } from "../../../common/user-store";
import { Button } from "../button";
import { SubTitle } from "../layout/sub-title";
import { Spinner } from "../spinner";
@ -18,37 +18,41 @@ interface SyncInfo {
type: "file" | "folder" | "unknown";
}
interface Entry {
interface Entry extends Value {
filePath: string;
}
interface Value {
data: KubeconfigSyncValue;
info: SyncInfo;
}
async function getMapEntry(entry: KubeconfigSyncEntry): Promise<[string, SyncInfo]> {
async function getMapEntry({ filePath, ...data}: KubeconfigSyncEntry): Promise<[string, Value]> {
try {
// stat follows the stat(2) linux syscall spec, namely it follows symlinks
const stats = await fse.stat(entry.filePath);
const stats = await fse.stat(filePath);
if (stats.isFile()) {
return [entry.filePath, { type: "file" }];
return [filePath, { info: { type: "file" }, data }];
}
if (stats.isDirectory()) {
return [entry.filePath, { type: "folder" }];
return [filePath, { info: { type: "folder" }, data }];
}
logger.warn("[KubeconfigSyncs]: unknown stat entry", { stats });
return [entry.filePath, { type: "unknown" }];
return [filePath, { info: { type: "unknown" }, data }];
} catch (error) {
logger.warn(`[KubeconfigSyncs]: failed to stat entry: ${error}`, { error });
return [entry.filePath, { type: "unknown" }];
return [filePath, { info: { type: "unknown" }, data }];
}
}
@observer
export class KubeconfigSyncs extends React.Component {
syncs = observable.map<string, SyncInfo>();
syncs = observable.map<string, Value>();
@observable loaded = false;
async componentDidMount() {
@ -63,7 +67,7 @@ export class KubeconfigSyncs extends React.Component {
this.loaded = true;
disposeOnUnmount(this, [
reaction(() => Array.from(this.syncs.keys()), syncs => {
reaction(() => Array.from(this.syncs.entries(), ([filePath, { data }]) => [filePath, data]), syncs => {
UserStore.getInstance().syncKubeconfigEntries.replace(syncs);
})
]);
@ -74,7 +78,7 @@ export class KubeconfigSyncs extends React.Component {
return undefined;
}
return Array.from(this.syncs.entries(), ([filePath, info]) => ({ filePath, info }));
return Array.from(this.syncs.entries(), ([filePath, value]) => ({ filePath, ...value }));
}
@action