diff --git a/webapp/packages/core-app/src/NavigationTree/NavigationTreeNode/useNavigationNode.ts b/webapp/packages/core-app/src/NavigationTree/NavigationTreeNode/useNavigationNode.ts index 928f4c7075..1f201ad87a 100644 --- a/webapp/packages/core-app/src/NavigationTree/NavigationTreeNode/useNavigationNode.ts +++ b/webapp/packages/core-app/src/NavigationTree/NavigationTreeNode/useNavigationNode.ts @@ -9,13 +9,11 @@ import { useContext, useEffect, useState } from 'react'; import { useObjectRef } from '@cloudbeaver/core-blocks'; -import { useService } from '@cloudbeaver/core-di'; import type { NavNode } from '../../shared/NodesManager/EntityTypes'; import { EObjectFeature } from '../../shared/NodesManager/EObjectFeature'; import { useNode } from '../../shared/NodesManager/useNode'; import { useChildren } from '../../shared/useChildren'; -import { NavigationTreeService } from '../NavigationTreeService'; import { TreeContext } from '../TreeContext'; interface INavigationNode { @@ -37,7 +35,6 @@ export function useNavigationNode(node: NavNode): INavigationNode { const contextRef = useObjectRef({ context: useContext(TreeContext), }); - const navigationTreeService = useService(NavigationTreeService); const [processing, setProcessing] = useState(false); const { isLoading } = useNode(node.id); const children = useChildren(node.id); @@ -56,20 +53,6 @@ export function useNavigationNode(node: NavNode): INavigationNode { expanded = false; } - const handleExpand = async () => { - if (!expanded) { - const timeout = setTimeout(() => setProcessing(true), 1); - const state = await navigationTreeService.loadNestedNodes(node.id); - clearTimeout(timeout); - setProcessing(false); - if (!state) { - contextRef.context?.tree.expand(node, false); - return; - } - } - contextRef.context?.tree.expand(node, !expanded); - }; - const handleOpen = async () => { setProcessing(true); try { @@ -79,6 +62,10 @@ export function useNavigationNode(node: NavNode): INavigationNode { } }; + const handleExpand = async () => { + contextRef.context?.tree.expand(node, !expanded); + }; + const handleSelect = (multiple = false, nested = false) => { contextRef.context?.tree.select(node, multiple, nested); }; diff --git a/webapp/packages/core-app/src/NavigationTree/useElementsTree.ts b/webapp/packages/core-app/src/NavigationTree/useElementsTree.ts index 34aa0dac77..9ba3e45a16 100644 --- a/webapp/packages/core-app/src/NavigationTree/useElementsTree.ts +++ b/webapp/packages/core-app/src/NavigationTree/useElementsTree.ts @@ -76,6 +76,36 @@ export function useElementsTree(options: IOptions): IElementsTree { const state = options.localState || localTreeNodesState; + async function loadTree(nodeId: string) { + let children = [nodeId]; + + while (children.length > 0) { + const nextChildren: string[] = []; + + for (const child of children) { + const nodeState = state.get(child); + if (!nodeState.expanded && child !== options.root) { + continue; + } + + const loaded = await navTreeService.loadNestedNodes(child); + + if (!loaded) { + const node = navNodeInfoResource.get(child); + + if (node) { + elementsTree.expand(node, false); + } + continue; + } + + nextChildren.push(...(navTreeResource.get(child) || [])); + } + + children = nextChildren; + } + } + function getNodeChildren(nodeId: string): string[] { const node = navNodeInfoResource.get(nodeId); @@ -166,10 +196,14 @@ export function useElementsTree(options: IOptions): IElementsTree { options.onFilter?.(node, value); }, - expand(node: NavNode, state: boolean) { + async expand(node: NavNode, state: boolean) { const treeNodeState = this.state.get(node.id); treeNodeState.expanded = state; + if (state) { + await loadTree(node.id); + } + options.onExpand?.(node, state); }, select(node: NavNode, multiple: boolean, nested: boolean) { @@ -192,39 +226,9 @@ export function useElementsTree(options: IOptions): IElementsTree { }, }, undefined, { root: observable.ref, renderers: observable.ref }); - async function refreshNode(nodeId: string) { - let children = [nodeId]; - - while (children.length > 0) { - const nextChildren: string[] = []; - - for (const child of children) { - const nodeState = state.get(child); - if (!nodeState.expanded && child !== options.root) { - continue; - } - - const loaded = await navTreeService.loadNestedNodes(child); - - if (!loaded) { - const node = navNodeInfoResource.get(child); - - if (node) { - elementsTree.expand(node, false); - } - continue; - } - - nextChildren.push(...(navTreeResource.get(child) || [])); - } - - children = nextChildren; - } - } - useExecutor({ executor: navTreeResource.onNodeRefresh, - handlers: [refreshNode], + handlers: [loadTree], }); useExecutor({ diff --git a/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts b/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts index 606d5fbb0c..d5d6ec5d13 100644 --- a/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts +++ b/webapp/packages/core-app/src/shared/NodesManager/NavNodeManagerService.ts @@ -6,6 +6,8 @@ * you may not use this file except in compliance with the License. */ +import { runInAction } from 'mobx'; + import { ConnectionAuthService, Connection, ConnectionInfoResource } from '@cloudbeaver/core-connections'; @@ -140,14 +142,14 @@ export class NavNodeManagerService extends Bootstrap { getTree(navNodeKey: NavNodeKey[]): Array getTree(navNodeId: string | NavNodeKey | NavNodeKey[]): string[] | undefined | Array { if (typeof navNodeId === 'string') { - return this.navTree.data.get(navNodeId); + return this.navTree.get(navNodeId); } if (Array.isArray(navNodeId)) { return navNodeId.map(node => this.navTree.data.get(node.nodeId)); } - return this.navTree.data.get(navNodeId.nodeId); + return this.navTree.get(navNodeId.nodeId); } loadTree(navNodeId: string): Promise { @@ -339,35 +341,40 @@ export class NavNodeManagerService extends Bootstrap { // const count = ResourceKeyUtils.count(key); await this.navTree.load(ROOT_NODE_PATH); - await ResourceKeyUtils.forEachAsync(key, async key => { - const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); - this.navTree.markTreeOutdated(nodeId); - // addOpenedConnection - const connectionInfo = this.connectionInfo.get(key); + runInAction(() => { + ResourceKeyUtils.forEach(key, async key => { + const nodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); + this.navTree.markTreeOutdated(nodeId); - if (!connectionInfo?.connected) { - this.removeTree(nodeId); - } + if (this.navTree.has(nodeId)) { + const connectionInfo = this.connectionInfo.get(key); - // if (count > 1) { - this.navNodeInfoResource.markOutdated(nodeId); + if (!connectionInfo?.connected) { + this.removeTree(nodeId); + } + } + + // if (count > 1) { + this.navNodeInfoResource.markOutdated(nodeId); // } else { // await this.navNodeInfoResource.refresh(nodeId); // } + }); }); } - private async connectionRemoveHandler(key: ResourceKey) { - ResourceKeyUtils.forEach(key, key => { - // deleteConnection - const navNodeId = NodeManagerUtils.connectionIdToConnectionNodeId(key); + 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]); + const node = this.getNode(navNodeId); + if (!node) { + return; + } + this.navTree.deleteInNode(node.parentId, [navNodeId]); + }); }); } diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index 117cd1278b..4dd332ec13 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import { action, makeObservable } from 'mobx'; +import { action, makeObservable, runInAction } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor'; @@ -102,14 +102,16 @@ export class ConnectionInfoResource extends CachedMapResource { + const unrestoredConnectionIdList = Array.from(this.data.values()) + .map(connection => connection.id) + .filter(connectionId => !connections.some(connection => connection.id === connectionId)); + + this.delete(resourceKeyList(unrestoredConnectionIdList)); + }); + await this.addList(connections); - const unrestoredConnectionIdList = Array.from(this.data.values()) - .map(connection => connection.id) - .filter(connectionId => !connections.some(connection => connection.id === connectionId)); - - this.delete(resourceKeyList(unrestoredConnectionIdList)); - await this.onSessionUpdate.execute(connections); }); } finally { diff --git a/webapp/packages/core-sdk/src/Resource/CachedMapResource.ts b/webapp/packages/core-sdk/src/Resource/CachedMapResource.ts index ae307c3ffc..20b3a2a250 100644 --- a/webapp/packages/core-sdk/src/Resource/CachedMapResource.ts +++ b/webapp/packages/core-sdk/src/Resource/CachedMapResource.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import { computed, makeObservable } from 'mobx'; +import { action, computed, makeObservable } from 'mobx'; import { Executor, IExecutor } from '@cloudbeaver/core-executor'; import { MetadataMap } from '@cloudbeaver/core-utils'; @@ -77,6 +77,8 @@ export abstract class CachedMapResource< })); makeObservable(this, { + set: action, + delete: action, values: computed, keys: computed, }); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx index b2aac49aa3..594f977f83 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx @@ -29,7 +29,6 @@ function getClasses(rawValue: any) { export const CellFormatter: React.FC = observer(function CellFormatter({ rowIdx, row, column, isCellSelected }) { const editorRef = useRef(null); - const cellRef = useRef(null); const cellContext = useContext(CellContext); const context = useContext(DataGridContext); const editingContext = useContext(EditingContext); @@ -66,7 +65,7 @@ export const CellFormatter: React.FC = observer(function CellFor return styled()( <> - + {value} {(isCellSelected || cellContext?.mouse.state.mouseEnter) && context && (