mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix main->renderer catalog entity sync issue (#2902)
* fix main->renderer catalog entity sync issue Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
2e0ff6c928
commit
c8e2f7ca2d
@ -24,10 +24,17 @@ import { broadcastMessage } from "../common/ipc";
|
|||||||
import type { CatalogEntityRegistry } from "./catalog";
|
import type { CatalogEntityRegistry } from "./catalog";
|
||||||
import "../common/catalog-entities/kubernetes-cluster";
|
import "../common/catalog-entities/kubernetes-cluster";
|
||||||
import { toJS } from "../common/utils";
|
import { toJS } from "../common/utils";
|
||||||
|
import { debounce } from "lodash";
|
||||||
|
import type { CatalogEntity } from "../common/catalog";
|
||||||
|
|
||||||
|
|
||||||
|
const broadcaster = debounce((items: CatalogEntity[]) => {
|
||||||
|
broadcastMessage("catalog:items", items);
|
||||||
|
}, 1_000, { trailing: true });
|
||||||
|
|
||||||
export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) {
|
export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) {
|
||||||
return reaction(() => toJS(catalog.items), (items) => {
|
return reaction(() => toJS(catalog.items), (items) => {
|
||||||
broadcastMessage("catalog:items", items);
|
broadcaster(items);
|
||||||
}, {
|
}, {
|
||||||
fireImmediately: true,
|
fireImmediately: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -22,14 +22,36 @@
|
|||||||
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
import { CatalogEntityRegistry } from "../catalog-entity-registry";
|
||||||
import "../../../common/catalog-entities";
|
import "../../../common/catalog-entities";
|
||||||
import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry";
|
import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry";
|
||||||
import type { CatalogEntityData, CatalogEntityKindData } from "../catalog-entity";
|
import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "../catalog-entity";
|
||||||
|
import { WebLink } from "../../../common/catalog-entities";
|
||||||
|
|
||||||
class TestCatalogEntityRegistry extends CatalogEntityRegistry {
|
class TestCatalogEntityRegistry extends CatalogEntityRegistry {
|
||||||
replaceItems(items: Array<CatalogEntityData & CatalogEntityKindData>) {
|
replaceItems(items: Array<CatalogEntityData & CatalogEntityKindData>) {
|
||||||
this.rawItems.replace(items);
|
this.updateItems(items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FooBarCategory extends CatalogCategory {
|
||||||
|
public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
|
||||||
|
public readonly kind = "CatalogCategory";
|
||||||
|
public metadata = {
|
||||||
|
name: "FooBars",
|
||||||
|
icon: "broken"
|
||||||
|
};
|
||||||
|
public spec = {
|
||||||
|
group: "entity.k8slens.dev",
|
||||||
|
versions: [
|
||||||
|
{
|
||||||
|
name: "v1alpha1",
|
||||||
|
entityClass: WebLink
|
||||||
|
}
|
||||||
|
],
|
||||||
|
names: {
|
||||||
|
kind: "FooBar"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
describe("CatalogEntityRegistry", () => {
|
describe("CatalogEntityRegistry", () => {
|
||||||
describe("updateItems", () => {
|
describe("updateItems", () => {
|
||||||
it("adds new catalog item", () => {
|
it("adds new catalog item", () => {
|
||||||
@ -99,6 +121,32 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
expect(catalog.items[0].status.phase).toEqual("connected");
|
expect(catalog.items[0].status.phase).toEqual("connected");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("updates activeEntity", () => {
|
||||||
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
|
const items = [{
|
||||||
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
|
kind: "KubernetesCluster",
|
||||||
|
metadata: {
|
||||||
|
uid: "123",
|
||||||
|
name: "foobar",
|
||||||
|
source: "test",
|
||||||
|
labels: {}
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "disconnected"
|
||||||
|
},
|
||||||
|
spec: {}
|
||||||
|
}];
|
||||||
|
|
||||||
|
catalog.replaceItems(items);
|
||||||
|
catalog.activeEntity = catalog.items[0];
|
||||||
|
expect(catalog.activeEntity.status.phase).toEqual("disconnected");
|
||||||
|
|
||||||
|
items[0].status.phase = "connected";
|
||||||
|
catalog.replaceItems(items);
|
||||||
|
expect(catalog.activeEntity.status.phase).toEqual("connected");
|
||||||
|
});
|
||||||
|
|
||||||
it("removes deleted items", () => {
|
it("removes deleted items", () => {
|
||||||
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
const items = [
|
const items = [
|
||||||
@ -175,8 +223,31 @@ describe("CatalogEntityRegistry", () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
catalog.replaceItems(items);
|
catalog.replaceItems(items);
|
||||||
|
|
||||||
expect(catalog.items.length).toBe(1);
|
expect(catalog.items.length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does return items after matching category is added", () => {
|
||||||
|
const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry);
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
apiVersion: "entity.k8slens.dev/v1alpha1",
|
||||||
|
kind: "FooBar",
|
||||||
|
metadata: {
|
||||||
|
uid: "456",
|
||||||
|
name: "barbaz",
|
||||||
|
source: "test",
|
||||||
|
labels: {}
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
phase: "disconnected"
|
||||||
|
},
|
||||||
|
spec: {}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
catalog.replaceItems(items);
|
||||||
|
catalogCategoryRegistry.add(new FooBarCategory());
|
||||||
|
expect(catalog.items.length).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,17 +19,21 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { computed, makeObservable, observable } from "mobx";
|
import { computed, observable, makeObservable, action } from "mobx";
|
||||||
import { subscribeToBroadcast } from "../../common/ipc";
|
import { subscribeToBroadcast } from "../../common/ipc";
|
||||||
import { CatalogCategory, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../../common/catalog";
|
import { CatalogCategory, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../../common/catalog";
|
||||||
import "../../common/catalog-entities";
|
import "../../common/catalog-entities";
|
||||||
import { iter } from "../utils";
|
|
||||||
import type { Cluster } from "../../main/cluster";
|
import type { Cluster } from "../../main/cluster";
|
||||||
import { ClusterStore } from "../../common/cluster-store";
|
import { ClusterStore } from "../../common/cluster-store";
|
||||||
|
|
||||||
export class CatalogEntityRegistry {
|
export class CatalogEntityRegistry {
|
||||||
protected rawItems = observable.array<CatalogEntityData & CatalogEntityKindData>();
|
@observable.ref activeEntity: CatalogEntity;
|
||||||
@observable.ref activeEntity?: CatalogEntity;
|
protected _entities = observable.map<string, CatalogEntity>([], { deep: true });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer for keeping entities that don't yet have CatalogCategory synced
|
||||||
|
*/
|
||||||
|
protected rawEntities: (CatalogEntityData & CatalogEntityKindData)[] = [];
|
||||||
|
|
||||||
constructor(private categoryRegistry: CatalogCategoryRegistry) {
|
constructor(private categoryRegistry: CatalogCategoryRegistry) {
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
@ -37,20 +41,68 @@ export class CatalogEntityRegistry {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => {
|
subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => {
|
||||||
this.rawItems.replace(items);
|
this.updateItems(items);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action updateItems(items: (CatalogEntityData & CatalogEntityKindData)[]) {
|
||||||
|
this.rawEntities.length = 0;
|
||||||
|
|
||||||
|
const newIds = new Set(items.map((item) => item.metadata.uid));
|
||||||
|
|
||||||
|
for (const uid of this._entities.keys()) {
|
||||||
|
if (!newIds.has(uid)) {
|
||||||
|
this._entities.delete(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
this.updateItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action protected updateItem(item: (CatalogEntityData & CatalogEntityKindData)) {
|
||||||
|
const existing = this._entities.get(item.metadata.uid);
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
const entity = this.categoryRegistry.getEntityForData(item);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this._entities.set(entity.metadata.uid, entity);
|
||||||
|
} else {
|
||||||
|
this.rawEntities.push(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
existing.metadata = item.metadata;
|
||||||
|
existing.spec = item.spec;
|
||||||
|
existing.status = item.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processRawEntities() {
|
||||||
|
const items = [...this.rawEntities];
|
||||||
|
|
||||||
|
this.rawEntities.length = 0;
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
this.updateItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@computed get items() {
|
@computed get items() {
|
||||||
return Array.from(iter.filterMap(this.rawItems, rawItem => this.categoryRegistry.getEntityForData(rawItem)));
|
this.processRawEntities();
|
||||||
|
|
||||||
|
return Array.from(this._entities.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get entities(): Map<string, CatalogEntity> {
|
@computed get entities(): Map<string, CatalogEntity> {
|
||||||
return new Map(this.items.map(item => [item.metadata.uid, item]));
|
this.processRawEntities();
|
||||||
|
|
||||||
|
return this._entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(id: string) {
|
getById<T extends CatalogEntity>(id: string) {
|
||||||
return this.entities.get(id);
|
return this.entities.get(id) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
getItemsForApiKind<T extends CatalogEntity>(apiVersion: string, kind: string): T[] {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user