diff --git a/webapp/packages/core-navigation-tree/src/NodesManager/DBObjectResource.ts b/webapp/packages/core-navigation-tree/src/NodesManager/DBObjectResource.ts index b7fdee9e3d..34c8c468ac 100644 --- a/webapp/packages/core-navigation-tree/src/NodesManager/DBObjectResource.ts +++ b/webapp/packages/core-navigation-tree/src/NodesManager/DBObjectResource.ts @@ -8,13 +8,19 @@ import { injectable } from '@cloudbeaver/core-di'; import { - GraphQLService, CachedMapResource, ResourceKey, isResourceKeyList, resourceKeyList, ResourceKeyUtils + GraphQLService, CachedMapResource, ResourceKey, isResourceKeyList, resourceKeyList, ResourceKeyUtils, ResourceKeyList } from '@cloudbeaver/core-sdk'; import type { DBObject } from './EntityTypes'; import { NavNodeInfoResource } from './NavNodeInfoResource'; import { NavTreeResource } from './NavTreeResource'; +const dbObjectParentKeySymbol = Symbol('@connection-folder/project') as unknown as string; +export const DBObjectParentKey = (parentId: string) => resourceKeyList( + [dbObjectParentKeySymbol], + parentId +); + @injectable() export class DBObjectResource extends CachedMapResource { constructor( @@ -24,24 +30,25 @@ export class DBObjectResource extends CachedMapResource { ) { super(); + this.addAlias( + isDBObjectParentKey, + param => resourceKeyList(navTreeResource.get(param.mark) || []), + true + ); // this.preloadResource(this.navNodeInfoResource); this.navNodeInfoResource.outdateResource(this); this.navNodeInfoResource.deleteInResource(this); this.navNodeInfoResource.onDataOutdated.addHandler(this.outdateChildren.bind(this)); } - async loadChildren(parentId: string, key: ResourceKey): Promise> { - await this.performUpdate( - key, - [], - () => this.loadFromChildren(parentId, 0, this.navTreeResource.childrenLimit + 1), - () => this.isLoaded(key) && !this.isOutdated(key) - ); + protected async loader(originalKey: ResourceKey): Promise> { + const key = this.transformParam(originalKey); - return this.data; - } + if (isDBObjectParentKey(originalKey)) { + await this.loadFromChildren(originalKey.mark, 0, this.navTreeResource.childrenLimit + 1); + return this.data; + } - protected async loader(key: ResourceKey): Promise> { if (isResourceKeyList(key)) { const values: DBObject[] = []; for (const navNodeId of key.list) { @@ -87,3 +94,9 @@ export class DBObjectResource extends CachedMapResource { // } } } + +function isDBObjectParentKey( + param: ResourceKey +): param is ResourceKeyList { + return isResourceKeyList(param) && param.list.includes(dbObjectParentKeySymbol); +} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/NavNodeView/VirtualFolder/VirtualFolderPanel.tsx b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/NavNodeView/VirtualFolder/VirtualFolderPanel.tsx index ed90e4e978..e1c671f229 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/NavNodeView/VirtualFolder/VirtualFolderPanel.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/NavNodeView/VirtualFolder/VirtualFolderPanel.tsx @@ -6,14 +6,15 @@ * you may not use this file except in compliance with the License. */ +import { untracked } from 'mobx'; import { observer } from 'mobx-react-lite'; +import { useEffect } from 'react'; import styled, { css } from 'reshadow'; import { Loader, TextPlaceholder, useMapResource } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { useTranslate } from '@cloudbeaver/core-localization'; -import { NavNodeInfoResource, NavTreeResource, DBObjectResource, type DBObject } from '@cloudbeaver/core-navigation-tree'; -import { resourceKeyList } from '@cloudbeaver/core-sdk'; +import { NavNodeInfoResource, NavTreeResource, DBObjectResource, type DBObject, DBObjectParentKey } from '@cloudbeaver/core-navigation-tree'; import { type NavNodeTransformViewComponent, NavNodeViewService } from '@cloudbeaver/plugin-navigation-tree'; import { TableLoader } from '../../ObjectPropertyTable/Table/TableLoader'; @@ -42,24 +43,26 @@ export const VirtualFolderPanel: NavNodeTransformViewComponent = observer(functi onLoad: async resource => !(await resource.preloadNodeParents(parents, nodeId)), }); - const { nodes, truncated } = navNodeViewService.limit(tree.data || []); - const key = resourceKeyList(nodes); - const dbObject = useMapResource(VirtualFolderPanel, DBObjectResource, key, { - async onLoad(resource: DBObjectResource) { - const preloaded = await tree.resource.preloadNodeParents(parents, nodeId); + const limited = navNodeViewService.limit(tree.data || []); - if (!preloaded) { - return true; - } + const { nodes, duplicates } = navNodeViewService.filterDuplicates(limited.nodes); - await resource.loadChildren(nodeId, key); - return true; - }, + const dbObject = useMapResource(VirtualFolderPanel, DBObjectResource, DBObjectParentKey(nodeId), { preload: [tree], }); + useEffect(() => { + untracked(() => { + navNodeViewService.logDuplicates(nodeId, duplicates); + }); + }); + const objects = dbObject.data - .filter(object => object && navNodeInfoResource.get(object.id)?.nodeType === nodeType) as DBObject[]; + .filter(object => ( + object + && nodes.includes(object.id) + && navNodeInfoResource.get(object.id)?.nodeType === nodeType + )) as DBObject[]; return styled(style)( {() => styled(style)( @@ -68,7 +71,7 @@ export const VirtualFolderPanel: NavNodeTransformViewComponent = observer(functi {translate('plugin_object_viewer_table_no_items')} ) : ( - 0} /> + 0} /> )} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/ObjectPropertyTable.tsx b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/ObjectPropertyTable.tsx index 687c7eeb6f..d22f551e18 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/ObjectPropertyTable.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/ObjectPropertyTable.tsx @@ -14,8 +14,7 @@ import styled, { css } from 'reshadow'; import { Loader, TextPlaceholder, useMapResource } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { useTranslate } from '@cloudbeaver/core-localization'; -import { NavTreeResource, DBObjectResource, type DBObject } from '@cloudbeaver/core-navigation-tree'; -import { resourceKeyList } from '@cloudbeaver/core-sdk'; +import { NavTreeResource, DBObjectResource, type DBObject, DBObjectParentKey } from '@cloudbeaver/core-navigation-tree'; import { NavNodeViewService } from '@cloudbeaver/plugin-navigation-tree'; import { TableLoader } from './Table/TableLoader'; @@ -54,18 +53,7 @@ export const ObjectPropertyTable = observer(function O const { nodes, duplicates } = navNodeViewService.filterDuplicates(limited.nodes); - const key = resourceKeyList(nodes); - const dbObject = useMapResource(ObjectPropertyTable, DBObjectResource, key, { - async onLoad(resource: DBObjectResource) { - const preloaded = await tree.resource.preloadNodeParents(parents, objectId); - - if (!preloaded) { - return true; - } - - await resource.loadChildren(objectId, key); - return true; - }, + const dbObject = useMapResource(ObjectPropertyTable, DBObjectResource, DBObjectParentKey(objectId), { preload: [tree], }); @@ -75,20 +63,21 @@ export const ObjectPropertyTable = observer(function O }); }); - const objects = dbObject.data as DBObject[]; + const objects = dbObject.data.filter(object => nodes.includes(object?.id ?? '')) as DBObject[]; return styled(styles)( - {() => styled(styles)( - <> - {nodes.length === 0 ? ( - {translate('plugin_object_viewer_table_no_items')} - ) : ( -
- 0} /> -
- )} - - )} + + {() => styled(styles)( + <> + {nodes.length === 0 ? ( + {translate('plugin_object_viewer_table_no_items')} + ) : ( +
+ 0} /> +
+ )} + + )}
); });