From 7cfb7419fd5678472042d383e4b8a6230f830c06 Mon Sep 17 00:00:00 2001 From: Wroud Date: Mon, 21 Jun 2021 14:04:27 +0300 Subject: [PATCH] refactor(core-app): CB-821 lazy tree update --- .../NodesManager/NavNodeManagerService.ts | 73 +------------------ .../shared/NodesManager/NavTreeResource.ts | 67 +++++++++++++++-- .../core-sdk/src/Resource/ResourceKeyList.ts | 9 +++ 3 files changed, 70 insertions(+), 79 deletions(-) diff --git a/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts b/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts index fded3c2dcb..e0a826b59a 100644 --- a/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts +++ b/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts @@ -6,8 +6,6 @@ * you may not use this file except in compliance with the License. */ -import { runInAction } from 'mobx'; - import { ConnectionAuthService, Connection, ConnectionInfoResource } from '@cloudbeaver/core-connections'; @@ -17,9 +15,7 @@ import { IExecutor, Executor, IExecutionContextProvider } from '@cloudbeaver/cor import { PermissionsService, EPermission, ServerService } from '@cloudbeaver/core-root'; -import { - resourceKeyList, ResourceKey, ResourceKeyUtils -} from '@cloudbeaver/core-sdk'; +import { resourceKeyList } from '@cloudbeaver/core-sdk'; import { NavigationService } from '@cloudbeaver/core-ui'; import { ENodeFeature } from './ENodeFeature'; @@ -116,11 +112,7 @@ export class NavNodeManagerService extends Bootstrap { .addHandler(this.navigateHandler.bind(this)); } - register(): void { - this.connectionInfo.onItemAdd.addHandler(this.connectionUpdateHandler.bind(this)); - this.connectionInfo.onItemDelete.addHandler(this.connectionRemoveHandler.bind(this)); - this.connectionInfo.onConnectionCreate.addHandler(this.connectionCreateHandler.bind(this)); - } + register(): void { } load(): void {} @@ -320,67 +312,6 @@ export class NavNodeManagerService extends Bootstrap { }; }; - private async connectionCreateHandler(connection: Connection) { - const enabled = await this.isNavTreeEnabled(); - if (!enabled) { - return; - } - - const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(connection.id); - this.navTree.markTreeOutdated(nodeId); - - const tree = await this.navTree.load(ROOT_NODE_PATH); - - if (!tree.includes(nodeId)) { - await this.navTree.refresh(ROOT_NODE_PATH); - } - } - - private async connectionUpdateHandler(key: ResourceKey) { - const enabled = await this.isNavTreeEnabled(); - if (!enabled) { - return; - } - - await this.navTree.load(ROOT_NODE_PATH); - - runInAction(() => { - ResourceKeyUtils.forEach(key, async key => { - const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); - - if (this.navTree.has(nodeId)) { - const connectionInfo = this.connectionInfo.get(key); - - if (!connectionInfo?.connected) { - this.removeTree(nodeId); - } else { - this.navTree.markTreeOutdated(nodeId); - } - } - - const nodeInfo = this.navNodeInfoResource.get(nodeId); - - if (nodeInfo) { - this.navTree.markOutdated(nodeInfo.parentId); - } - }); - }); - } - - private connectionRemoveHandler(key: ResourceKey) { - runInAction(() => { - ResourceKeyUtils.forEach(key, key => { - const navNodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); - - const node = this.getNode(navNodeId); - if (!node) { - return; - } - this.navTree.deleteInNode(node.parentId, [navNodeId]); - }); - }); - } - private async navigateHandler( data: INodeNavigationData, contexts: IExecutionContextProvider diff --git a/webapp/packages/core-app/src/shared/NodesManager/NavTreeResource.ts b/webapp/packages/core-app/src/shared/NodesManager/NavTreeResource.ts index a6ec51ffbd..7b89fbfdc6 100644 --- a/webapp/packages/core-app/src/shared/NodesManager/NavTreeResource.ts +++ b/webapp/packages/core-app/src/shared/NodesManager/NavTreeResource.ts @@ -6,8 +6,9 @@ * you may not use this file except in compliance with the License. */ -import { action, computed, makeObservable } from 'mobx'; +import { action, computed, makeObservable, runInAction } from 'mobx'; +import { Connection, ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { Executor, IExecutor } from '@cloudbeaver/core-executor'; import { SessionDataResource } from '@cloudbeaver/core-root'; @@ -25,7 +26,8 @@ import { import { MetadataMap } from '@cloudbeaver/core-utils'; import { CoreSettingsService } from '../../CoreSettingsService'; -import { NavNodeInfoResource } from './NavNodeInfoResource'; +import { NavNodeInfoResource, ROOT_NODE_PATH } from './NavNodeInfoResource'; +import { NodeManagerUtils } from './NodeManagerUtils'; // TODO: so much dirty export interface NodePath { @@ -51,14 +53,16 @@ export class NavTreeResource extends CachedMapResource { private graphQLService: GraphQLService, private navNodeInfoResource: NavNodeInfoResource, private coreSettingsService: CoreSettingsService, - private sessionDataResource: SessionDataResource + private sessionDataResource: SessionDataResource, + private connectionInfo: ConnectionInfoResource ) { super(); - makeObservable(this, { + makeObservable(this, { childrenLimit: computed, setDetails: action, setNavObject: action, + connectionRemoveHandler: action.bound, }); this.metadata = new MetadataMap(() => ({ @@ -72,19 +76,22 @@ export class NavTreeResource extends CachedMapResource { this.onNodeRefresh = new Executor(null, (a, b) => a === b); this.onDataOutdated.addHandler(navNodeInfoResource.markOutdated.bind(navNodeInfoResource)); this.sessionDataResource.onDataUpdate.addPostHandler(() => this.markOutdated()); + this.connectionInfo.onItemAdd.addHandler(this.connectionUpdateHandler.bind(this)); + this.connectionInfo.onItemDelete.addHandler(this.connectionRemoveHandler); + this.connectionInfo.onConnectionCreate.addHandler(this.connectionCreateHandler.bind(this)); } async refreshTree(navNodeId: string): Promise { await this.graphQLService.sdk.navRefreshNode({ nodePath: navNodeId, }); - this.markTreeOutdated(navNodeId); + await this.markTreeOutdated(navNodeId); await this.refresh(navNodeId); await this.onNodeRefresh.execute(navNodeId); } - markTreeOutdated(navNodeId: ResourceKey): void { - this.markOutdated(resourceKeyList(this.getNestedChildren(navNodeId))); + async markTreeOutdated(navNodeId: ResourceKey): Promise { + await this.markOutdated(resourceKeyList(this.getNestedChildren(navNodeId))); } setDetails(keyObject: ResourceKey, state: boolean): void { @@ -179,7 +186,7 @@ export class NavTreeResource extends CachedMapResource { const allKeys = resourceKeyList(items); this.markUpdated(allKeys); this.onItemDelete.execute(allKeys); - this.navNodeInfoResource.delete(resourceKeyList(items.filter(navNodeId => navNodeId !== key))); + this.navNodeInfoResource.delete(ResourceKeyUtils.exclude(allKeys, key)); } protected async loader(key: ResourceKey): Promise> { @@ -216,6 +223,50 @@ export class NavTreeResource extends CachedMapResource { return nestedChildren; } + private async connectionUpdateHandler(key: ResourceKey) { + await this.markOutdated(ROOT_NODE_PATH); + + ResourceKeyUtils.forEach(key, async key => { + const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); + + if (this.has(nodeId)) { + const connectionInfo = this.connectionInfo.get(key); + + if (!connectionInfo?.connected) { + this.delete(nodeId); + } else { + this.markTreeOutdated(nodeId); + } + } + + const node = this.navNodeInfoResource.get(nodeId); + + if (node) { + this.markOutdated(node.parentId); + } + }); + } + + private connectionRemoveHandler(key: ResourceKey) { + runInAction(() => { + ResourceKeyUtils.forEach(key, key => { + const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); + + const node = this.navNodeInfoResource.get(nodeId); + + if (node) { + this.deleteInNode(node.parentId, [nodeId]); + } + }); + }); + } + + private async connectionCreateHandler(connection: Connection) { + const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(connection.id); + await this.markOutdated(ROOT_NODE_PATH); + await this.markTreeOutdated(nodeId); + } + private setNavObject(data: NavNodeChildrenQuery | NavNodeChildrenQuery[]) { if (Array.isArray(data)) { for (const node of data) { diff --git a/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts b/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts index c692f15f42..cd45d38608 100644 --- a/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts +++ b/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts @@ -46,6 +46,7 @@ export interface ResourceKeyUtils { every: (key: ResourceKey, predicate: (key: TKey, index: number) => boolean) => boolean; map: MapFnc; includes: (first: ResourceKey, second: ResourceKey) => boolean; + exclude: (first: ResourceKeyList, second: ResourceKey) => ResourceKey; } // eslint-disable-next-line @typescript-eslint/no-redeclare @@ -142,6 +143,14 @@ export const ResourceKeyUtils: ResourceKeyUtils = { return param === key; }, + + exclude(param: ResourceKeyList, key: ResourceKey): ResourceKey { + if (isResourceKeyList(key)) { + return resourceKeyList(param.list.filter(param => !key.list.includes(param)), param.mark); + } + + return resourceKeyList(param.list.filter(param => param !== key), param.mark); + }, }; export function isResourceKeyList(data: any): data is ResourceKeyList {