import { FiltersMap, ReportBI, TaskState } from '@wix/bex-core'; import { NestedCollectionState } from './NestedCollectionState'; import { TableVirtualState } from '../TableVirtualState'; import { NestedTableNodeState } from './NestedTableNodeState'; import { action, computed, makeObservable } from 'mobx'; import { NestedTableState } from './NestedTableState'; import { NestedTableDragAndDropState } from '../../components/NestedTableDragAndDrop/NestedTableDragAndDropState'; import { getNodeOrLeaf } from './getNodeOrLeaf'; import { NestedTableNodeStatePublicAPI } from './NestedTableNodeStatePublicAPI'; import { NestedTableNestedModeStateBIReporter } from './NestedTableNestedModeStateBIReporter'; import { addEventListener } from '@wix/bex-core/util'; import { createNestedOptimisticActions } from './createNestedOptimisticActions'; export interface NestedTableNestedModeStateBaseParams {} export interface NestedTableNestedModeStateParams extends NestedTableNestedModeStateBaseParams { wrapper: NestedTableState; reportBi: ReportBI; } export class NestedTableNestedModeState { readonly wrapper; readonly container; readonly bi: NestedTableNestedModeStateBIReporter; readonly nestedCollection: NestedCollectionState; readonly virtual; readonly initTask = new TaskState(); readonly root: NestedTableNodeState; nestedTableDragAndDrop: NestedTableDragAndDropState | null = null; constructor(params: NestedTableNestedModeStateParams) { const { wrapper } = params; this.wrapper = wrapper; this.container = wrapper.container; this.bi = new NestedTableNestedModeStateBIReporter(this); const rootLevelDescriptor = this.wrapper.levels[0]; if (rootLevelDescriptor == null) { throw new Error('NestedTableState must have at least one level'); } const nestedOptimisticActionsState = { parentId: 'null', sequences: wrapper.sequences, query: wrapper.query, levelDescriptor: rootLevelDescriptor, }; const rootNodeCollection = rootLevelDescriptor.createCollection( nestedOptimisticActionsState, ); createNestedOptimisticActions( this.container, rootNodeCollection.collection, { ...nestedOptimisticActionsState, parentFilter: rootNodeCollection.parentFilter, }, ); this.nestedCollection = new NestedCollectionState({ container: this.container, levels: wrapper.levels, query: wrapper.query, nodeCollection: rootNodeCollection, sequences: wrapper.sequences, }); this.root = new NestedTableNodeState({ nestedTable: this, node: this.nestedCollection.root, levelDescriptor: rootLevelDescriptor, parentNode: null, parent: null, preRegister: true, }); this.virtual = new TableVirtualState({ table: this, getVirtualItemKey: (item) => [item.id, item.item.state.parent?.id].filter(Boolean).join('_'), }); makeObservable(this, { hasExpandableItems: computed, }); } getCollectionSnapshot() { const { toolbar } = this; const { collection: { result: { originQuery, total }, }, } = toolbar; return { viewShown: toolbar.viewsState?.views.currentView?.id, tabShown: toolbar.getCurrentTabName(), sortOrderApplied: originQuery.sort?.length ? JSON.stringify(originQuery.sort) : undefined, filtersApplied: JSON.stringify(originQuery.filtersKey), filteredListSizeShown: total, }; } get multi() { return this.toolbar.multi; } get tableState() { return this.wrapper.tableState; } get toolbar() { return this.wrapper.toolbar; } get total() { return this.nestedCollection.total; } get originQuery() { return this.toolbar.collection.originQuery; } get keyedItems() { return this.root.keyedItems; } get _keyedItemsMap() { return this.root._keyedItemsMap; } _indentationWidth = 28; _parentCellPaddingStart = 24; getKeyedItem(key: string) { return this.root.getKeyedItem(key); } getKeyedItemByIndex(ind: number) { return this.root.getKeyedItemByIndex(ind); } getNode( key: string, ): NestedTableNodeStatePublicAPI | undefined { const keyedItem = this.root._allKeyedItemsMap.get(key); if (keyedItem == null || keyedItem.item.originalKeyedItem == null) { return undefined; } const { item } = keyedItem; return getNodeOrLeaf(item.state, item.originalKeyedItem) as | NestedTableNodeState | undefined; } getAllNodes(): NestedTableNodeStatePublicAPI< C, TD, FD >[] { return this.root.getDescendants(); } get expandAll() { return this.nestedCollection.expandAll; } get isFetchAllAborted() { return this.nestedCollection.isFetchAllAborted; } get isAllCollapsed() { return this.root.getDescendants().every((node) => !node.expanded); } get hasExpandableItems() { return this.root.hasExpandableItems; } get showEmptyState() { return this.root.showEmptyState; } get hasAvailableItems() { return this.toolbar.multi.hasAvailableItems; } get resultOriginQuerySearch() { return this.toolbar.multi.resultOriginQuerySearch; } get hasNonPersistentActiveFilters() { return this.toolbar.multi.hasNonPersistentActiveFilters; } get showErrorState() { const { initTask } = this; return initTask.status.isError; } get showLoadingState() { return this.initTask.status.isLoading; } retryErrorState = action(() => { const { initTask } = this; if (initTask.status.isError) { initTask.runOnce(); } }); expandCollapseAll = action(() => { this.bi.reportExpandCollapseAll(); const isAllCollapsed = this.isAllCollapsed; const nodes = this.root.getDescendants(); for (const node of nodes) { if (node.expanded !== isAllCollapsed) { const nodeState = (node as NestedTableNodeState).node; if (!nodeState) { continue; } nodeState._expanded = !nodeState._expanded; } } }); get errorStatus() { const { initTask } = this; return initTask.errorStatus; } get query() { return this.wrapper.query; } get levels() { return this.wrapper.levels; } init() { const { initTask, wrapper, root, nestedCollection } = this; const attemptFetchAllState = wrapper._attemptFetchAllAndPopulateCache(); const disposers = [ addEventListener( root.collection.hooks, 'beforeInitialFetch', () => attemptFetchAllState.initTask.status.promise, ), addEventListener( wrapper.rootNodeCollection.collection.hooks, 'beforeInitialFetch', () => attemptFetchAllState.initTask.status.promise, ), attemptFetchAllState.init(), wrapper.init(), root.init(), nestedCollection.init(), ]; initTask.runOnce(async () => { wrapper.initTask.runOnce(); attemptFetchAllState.initTask.runOnce(); root.initTask.runOnce(); await attemptFetchAllState.initTask.status.promise; await root.initTask.status.promise; await wrapper.initTask.status.promise; }); return () => { disposers.forEach((d) => d()); }; } }