diff --git a/src/common/catalog/catalog-category-registry.ts b/src/common/catalog/catalog-category-registry.ts index 43da644a1c..4d87437ff4 100644 --- a/src/common/catalog/catalog-category-registry.ts +++ b/src/common/catalog/catalog-category-registry.ts @@ -45,6 +45,10 @@ export class CatalogCategoryRegistry { return Array.from(this.categories); } + getById(id: string): CatalogCategory{ + return this.categories.find(category => category.getId() === id); + } + getForGroupKind(group: string, kind: string) { return this.categories.find((c) => c.spec.group === group && c.spec.names.kind === kind) as T; } diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index 4c5aec9286..755c874d08 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -25,7 +25,7 @@ import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegis import "../../common/catalog-entities"; export class CatalogEntityRegistry { - @observable protected _items: CatalogEntity[] = observable.array([], { deep: true }); + @observable protected _items: CatalogEntity[] = observable.array(); @observable protected _activeEntity: CatalogEntity; constructor(private categoryRegistry: CatalogCategoryRegistry) { diff --git a/src/renderer/components/+catalog/catalog-entity.store.ts b/src/renderer/components/+catalog/catalog-entity.store.ts index 9936c83063..8ae17d9fdd 100644 --- a/src/renderer/components/+catalog/catalog-entity.store.ts +++ b/src/renderer/components/+catalog/catalog-entity.store.ts @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { action, computed, IReactionDisposer, observable, reaction, makeObservable } from "mobx"; +import { action, autorun, computed, makeObservable, observable } from "mobx"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity"; import { ItemObject, ItemStore } from "../../item.store"; -import { autoBind } from "../../utils"; +import { autoBind, disposer } from "../../utils"; import { CatalogCategory } from "../../../common/catalog"; export class CatalogEntityItem implements ItemObject { @@ -87,13 +87,15 @@ export class CatalogEntityItem implements ItemObject { } export class CatalogEntityStore extends ItemStore { - @observable activeCategory?: CatalogCategory; + dispose = disposer(); + @observable.ref activeCategory?: CatalogCategory; constructor() { super(); makeObservable(this); autoBind(this); + this.bindAutoLoading(); } @computed get entities() { @@ -104,16 +106,24 @@ export class CatalogEntityStore extends ItemStore { return catalogEntityRegistry.getItemsForCategory(this.activeCategory).map(entity => new CatalogEntityItem(entity)); } - watch() { - const disposers: IReactionDisposer[] = [ - reaction(() => this.entities, () => this.loadAll()), - reaction(() => this.activeCategory, () => this.loadAll(), { delay: 100}) - ]; + protected bindAutoLoading() { + const disposer = autorun(() => { + this.loadItem(this.activeCategory); // preload active category + this.loadItems(this.entities); // preload all available entities + }); - return () => disposers.forEach((dispose) => dispose()); + this.dispose.push(disposer); } - loadAll() { - return this.loadItems(() => this.entities); + async loadItem(category: CatalogCategory): Promise { + return super.loadItem(() => category); + } + + async loadItems(entities: CatalogEntityItem[] = []) { + return super.loadItems(() => entities); + } + + async loadAll() { + return this.loadItems(); } } diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 44fe5f27f5..ec3521719c 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -23,14 +23,14 @@ import "./catalog.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { ItemListLayout } from "../item-object-list"; -import { action, observable, reaction, makeObservable } from "mobx"; +import { autorun, computed, makeObservable, observable } from "mobx"; import { CatalogEntityItem, CatalogEntityStore } from "./catalog-entity.store"; import { navigate } from "../../navigation"; import { kebabCase } from "lodash"; import { PageLayout } from "../layout/page-layout"; -import { MenuItem, MenuActions } from "../menu"; +import { MenuActions, MenuItem } from "../menu"; import { Icon } from "../icon"; -import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity"; +import { CatalogCategory, CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity"; import { Badge } from "../badge"; import { HotbarStore } from "../../../common/hotbar-store"; import { boundMethod } from "../../utils"; @@ -44,31 +44,37 @@ enum sortBy { source = "source", status = "status" } + @observer export class Catalog extends React.Component { - @observable private catalogEntityStore?: CatalogEntityStore; - @observable.deep private contextMenu: CatalogEntityContextMenuContext; - @observable activeTab?: string; + private catalogEntityStore = new CatalogEntityStore(); + + private contextMenu: CatalogEntityContextMenuContext = { + menuItems: [], + navigate: (url: string) => navigate(url), + }; + + @observable activeCategoryId = this.categories[0]?.getId(); + + @computed get activeCategory(): CatalogCategory { + return catalogCategoryRegistry.getById(this.activeCategoryId); + } + + @computed get categories(): CatalogCategory[] { + return catalogCategoryRegistry.items; + } constructor(props: {}) { super(props); makeObservable(this); } - async componentDidMount() { - this.contextMenu = { - menuItems: [], - navigate: (url: string) => navigate(url) - }; - this.catalogEntityStore = new CatalogEntityStore(); + componentDidMount() { disposeOnUnmount(this, [ - this.catalogEntityStore.watch(), - reaction(() => catalogCategoryRegistry.items, (items) => { - if (!this.activeTab && items.length > 0) { - this.activeTab = items[0].getId(); - this.catalogEntityStore.activeCategory = items[0]; - } - }, { fireImmediately: true }) + () => this.catalogEntityStore.dispose(), // stop all events, loaders, etc. + autorun(() => { + this.catalogEntityStore.activeCategory = this.activeCategory; // sync + }), ]); } @@ -97,21 +103,14 @@ export class Catalog extends React.Component { } } - get categories() { - return catalogCategoryRegistry.items; - } - - @action - onTabChange = (tabId: string | null) => { - const activeCategory = this.categories.find(category => category.getId() === tabId); - - this.catalogEntityStore.activeCategory = activeCategory; - this.activeTab = activeCategory?.getId(); - }; - renderNavigation() { return ( - + this.activeCategoryId = categoryId} + >
Catalog
item.onContextMenuOpen(this.contextMenu)}> - this.addToHotbar(item) }> + this.addToHotbar(item)}> Add to Hotbar { menuItems.map((menuItem, index) => ( this.onMenuItemClick(menuItem)}> - {menuItem.title} + {menuItem.title} )) } @@ -156,8 +155,8 @@ export class Catalog extends React.Component { } render() { - if (!this.catalogEntityStore) { - return null; + if (!this.activeCategory) { + return ""; } return ( @@ -167,7 +166,7 @@ export class Catalog extends React.Component { provideBackButtonNavigation={false} contentGaps={false}> [ item.name, item.source, - item.labels.map((label) => ), + item.labels.map((label) => ), { title: item.phase, className: kebabCase(item.phase) } ]} - onDetails={(item: CatalogEntityItem) => this.onDetails(item) } + onDetails={(item: CatalogEntityItem) => this.onDetails(item)} renderItemMenu={this.renderItemMenu} /> - + ); } diff --git a/src/renderer/item.store.ts b/src/renderer/item.store.ts index b249a4539f..83733dea41 100644 --- a/src/renderer/item.store.ts +++ b/src/renderer/item.store.ts @@ -120,7 +120,7 @@ export abstract class ItemStore { protected async loadItem(...args: any[]): Promise @action protected async loadItem(request: () => Promise, sortItems = true) { - const item = await request().catch(() => null); + const item = await Promise.resolve(request()).catch(() => null); if (item) { const existingItem = this.items.find(el => el.getId() === item.getId());