diff --git a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts index 9fe85c961a..6308195926 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -51,10 +51,7 @@ export class ConnectionsAdministrationService extends Bootstrap { onActivate: this.loadConnections.bind(this), onDeActivate: async (configuration: boolean, outside: boolean) => { if (outside) { - const updated = await this.connectionsResource.updateSessionConnections(); - if (updated) { - await this.connectionInfoResource.refreshSession(); - } + await this.connectionInfoResource.refreshSession(); } }, }); diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index 841c1ff354..a0f0e9874b 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -17,9 +17,12 @@ import { GraphQLService, CachedMapResource, ConnectionConfig, - UserConnectionAuthPropertiesFragment + UserConnectionAuthPropertiesFragment, + resourceKeyList } from '@cloudbeaver/core-sdk'; +import { ConnectionsResource } from './Administration/ConnectionsResource'; + export type Connection = UserConnectionFragment & { authProperties?: UserConnectionAuthPropertiesFragment[] }; @injectable() @@ -29,6 +32,7 @@ export class ConnectionInfoResource extends CachedMapResource !this.sessionUpdate); this.onItemDelete.addHandler(() => !this.sessionUpdate); + this.onConnectionCreate.addHandler(() => !this.sessionUpdate); sessionResource.onDataOutdated.addHandler(() => this.markOutdated()); appAuthService.auth.addHandler(() => this.refreshSession(true)); } @action async refreshSession(sessionUpdate?: boolean): Promise { - this.sessionUpdate = true; + this.sessionUpdate = sessionUpdate === true; try { - const { state: { connections } } = await this.graphQLService.sdk.getSessionConnections(); + const connectionsList = resourceKeyList(Array.from(this.data.keys())); + await this.performUpdate(connectionsList, async () => { + if (!sessionUpdate) { + const updated = await this.connectionsResource.updateSessionConnections(); - const restoredConnections = new Set(); - for (const connection of connections) { - await this.add(connection, sessionUpdate); - restoredConnections.add(connection.id); - } + if (!updated) { + return; + } + } - const unrestoredConnectionIdList = Array.from(this.data.values()) - .map(connection => connection.id) - .filter(connectionId => !restoredConnections.has(connectionId)); + const { state: { connections } } = await this.graphQLService.sdk.getSessionConnections(); - for (const connectionId of unrestoredConnectionIdList) { - this.delete(connectionId); - } + const restoredConnections = new Set(); + + for (const connection of connections) { + await this.add(connection); + restoredConnections.add(connection.id); + } + + const unrestoredConnectionIdList = Array.from(this.data.values()) + .map(connection => connection.id) + .filter(connectionId => !restoredConnections.has(connectionId)); + + this.delete(resourceKeyList(unrestoredConnectionIdList)); + }); } finally { this.sessionUpdate = false; } @@ -87,13 +102,13 @@ export class ConnectionInfoResource extends CachedMapResource { + @action async add(connection: Connection): Promise { const exists = this.data.has(connection.id); this.set(connection.id, connection); const observedConnection = this.get(connection.id)!; - if (!update && !exists) { + if (!exists) { await this.onConnectionCreate.execute(observedConnection); } @@ -104,7 +119,6 @@ export class ConnectionInfoResource extends CachedMapResource { const connection = await this.initConnection(id, credentials, saveCredentials); this.set(id, connection); - return connection; }); return this.get(id)!; diff --git a/webapp/packages/core-connections/src/useConnectionInfo.ts b/webapp/packages/core-connections/src/useConnectionInfo.ts index bae2261d0b..fa1689534f 100644 --- a/webapp/packages/core-connections/src/useConnectionInfo.ts +++ b/webapp/packages/core-connections/src/useConnectionInfo.ts @@ -22,12 +22,14 @@ export function useConnectionInfo(connectionId: string) { const refresh = useCallback(() => service.refresh(connectionId), [service, connectionId]); const isLoading = useCallback(() => service.isDataLoading(connectionId), [service, connectionId]); const isLoaded = useCallback(() => service.isLoaded(connectionId), [service, connectionId]); + const isOutdated = useCallback(() => service.isOutdated(connectionId), [service, connectionId]); const connect = useCallback(() => manager.requireConnection(connectionId), [manager, connectionId]); return { connectionInfo, isLoading, isLoaded, + isOutdated, load, refresh, connect, diff --git a/webapp/packages/core-executor/src/TaskScheduler/TaskScheduler.ts b/webapp/packages/core-executor/src/TaskScheduler/TaskScheduler.ts index 3b2027c6bb..0b69ba3834 100644 --- a/webapp/packages/core-executor/src/TaskScheduler/TaskScheduler.ts +++ b/webapp/packages/core-executor/src/TaskScheduler/TaskScheduler.ts @@ -47,6 +47,16 @@ export class TaskScheduler { } } + async wait(): Promise { + const queueList = this.queue.slice(); + + for (const task of queueList) { + try { + await task.task; + } catch {} + } + } + private async scheduler(id: TIdentifier, promise: () => Promise) { if (!this.isBlocked) { return promise(); diff --git a/webapp/packages/core-sdk/src/Resource/CachedResource.ts b/webapp/packages/core-sdk/src/Resource/CachedResource.ts index 83a0cb340f..6237ac5e48 100644 --- a/webapp/packages/core-sdk/src/Resource/CachedResource.ts +++ b/webapp/packages/core-sdk/src/Resource/CachedResource.ts @@ -49,6 +49,10 @@ export abstract class CachedResource< abstract isLoaded(param: TParam): boolean; + waitLoad(): Promise { + return this.scheduler.wait(); + } + isLoading(): boolean { return this.loading; } diff --git a/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts b/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts index cb8b915a00..eae7214c58 100644 --- a/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts +++ b/webapp/packages/core-sdk/src/Resource/ResourceKeyList.ts @@ -26,11 +26,6 @@ export class ResourceKeyList { } } -interface ForeachFnc { - (key: ResourceKey, action: (key: TKey, index: number) => any): any; - (key: ResourceKey, action: (key: TKey, index: number) => Promise): Promise; -} - interface MapFnc { (key: ResourceKeyList, selector: (key: TKey, index: number) => TValue): TValue[]; ( diff --git a/webapp/packages/plugin-object-viewer/src/ObjectViewerPanel.tsx b/webapp/packages/plugin-object-viewer/src/ObjectViewerPanel.tsx index e6210835d0..baf6034a60 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectViewerPanel.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectViewerPanel.tsx @@ -59,12 +59,18 @@ export const ObjectViewerPanel = observer(function ObjectViewerPanel({ navigation.selectTab(tab.id); }, [navigation, connection, tab]); - if (connection.connectionInfo && !connection.connectionInfo.connected && !connection.isLoading()) { - return ( - - - - ); + if (connection.connectionInfo) { + if (connection.isLoading()) { + return ; + } + + if (!connection.connectionInfo.connected) { + return ( + + + + ); + } } if (!isLoaded() || (!isOutdated() && isLoading())) { diff --git a/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts b/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts index 1bd243eacd..cb7610c5fe 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts +++ b/webapp/packages/plugin-object-viewer/src/ObjectViewerTabService.ts @@ -190,7 +190,7 @@ export class ObjectViewerTabService { ); if (tab) { - if (tab.handlerState.connectionId) { + if (tab.handlerState.connectionId && this.connectionInfo.has(tab.handlerState.connectionId)) { const connection = await this.connectionInfo.load(tab.handlerState.connectionId); if (!connection.connected) { @@ -229,6 +229,13 @@ export class ObjectViewerTabService { private async selectObjectTab(tab: ITab) { try { if (tab.handlerState.connectionId) { + // here we wait when connections info will be updated and then check is connections is steel available + await this.connectionInfo.waitLoad(); + + if (!this.connectionInfo.has(tab.handlerState.connectionId)) { + return; + } + const connection = await this.connectionInfo.load(tab.handlerState.connectionId); if (!connection.connected) {