diff --git a/src/main/catalog-pusher.ts b/src/main/catalog-pusher.ts index e97dc07038..5c9a41b702 100644 --- a/src/main/catalog-pusher.ts +++ b/src/main/catalog-pusher.ts @@ -24,10 +24,17 @@ import { broadcastMessage } from "../common/ipc"; import type { CatalogEntityRegistry } from "./catalog"; import "../common/catalog-entities/kubernetes-cluster"; 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) { return reaction(() => toJS(catalog.items), (items) => { - broadcastMessage("catalog:items", items); + broadcaster(items); }, { fireImmediately: true, }); diff --git a/src/renderer/api/__tests__/catalog-entity-registry.test.ts b/src/renderer/api/__tests__/catalog-entity-registry.test.ts index 8a26aabc00..08e5d83a50 100644 --- a/src/renderer/api/__tests__/catalog-entity-registry.test.ts +++ b/src/renderer/api/__tests__/catalog-entity-registry.test.ts @@ -26,7 +26,7 @@ import type { CatalogEntityData, CatalogEntityKindData } from "../catalog-entity class TestCatalogEntityRegistry extends CatalogEntityRegistry { replaceItems(items: Array) { - this.rawItems.replace(items); + this.updateItems(items); } } @@ -99,6 +99,32 @@ describe("CatalogEntityRegistry", () => { 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", () => { const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry); const items = [ diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index e2f83058b8..ba148ec142 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -19,17 +19,16 @@ * 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 { CatalogCategory, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../../common/catalog"; import "../../common/catalog-entities"; -import { iter } from "../utils"; import type { Cluster } from "../../main/cluster"; import { ClusterStore } from "../../common/cluster-store"; export class CatalogEntityRegistry { - protected rawItems = observable.array(); - @observable.ref activeEntity?: CatalogEntity; + protected _entities = observable.map([], { deep: true }); + @observable.ref activeEntity: CatalogEntity; constructor(private categoryRegistry: CatalogCategoryRegistry) { makeObservable(this); @@ -37,20 +36,42 @@ export class CatalogEntityRegistry { init() { subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => { - this.rawItems.replace(items); + this.updateItems(items); + }); + } + + @action updateItems(items: (CatalogEntityData & CatalogEntityKindData)[]) { + const newIds = items.map((item) => item.metadata.uid); + + Array.from(this._entities.keys()).forEach((uid) => { + if (!newIds.includes(uid)) this._entities.delete(uid); + }); + + items.forEach((item) => { + 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 { + existing.metadata = item.metadata; + existing.spec = item.spec; + existing.status = item.status; + } }); } @computed get items() { - return Array.from(iter.filterMap(this.rawItems, rawItem => this.categoryRegistry.getEntityForData(rawItem))); + return Array.from(this._entities.values()); } @computed get entities(): Map { - return new Map(this.items.map(item => [item.metadata.uid, item])); + return this._entities; } - getById(id: string) { - return this.entities.get(id); + getById(id: string) { + return this.entities.get(id) as T; } getItemsForApiKind(apiVersion: string, kind: string): T[] {