From 9def11573e1488428bc65f724b7fac3b27f72df8 Mon Sep 17 00:00:00 2001 From: Naumov Alexey Date: Mon, 20 Jun 2022 03:58:33 +0200 Subject: [PATCH 1/6] feat(plugin-sql-editor): CB-1498 ask result-set save confirmation on certain actions --- .../src/ConnectionsManagerService.ts | 43 +++++++++- .../src/AuthenticationService.ts | 17 +++- .../src/SqlEditorBootstrap.ts | 86 +++++++++++++++++++ ...nuBootstrap.ts => SqlEditorMenuService.ts} | 10 +-- .../plugin-sql-editor/src/manifest.ts | 6 +- 5 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts rename webapp/packages/plugin-sql-editor/src/{MenuBootstrap.ts => SqlEditorMenuService.ts} (96%) diff --git a/webapp/packages/core-connections/src/ConnectionsManagerService.ts b/webapp/packages/core-connections/src/ConnectionsManagerService.ts index 578f42dbf1..f456e7ea49 100644 --- a/webapp/packages/core-connections/src/ConnectionsManagerService.ts +++ b/webapp/packages/core-connections/src/ConnectionsManagerService.ts @@ -10,16 +10,25 @@ import { ProcessSnackbar } from '@cloudbeaver/core-blocks'; import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; -import { Executor, IExecutor } from '@cloudbeaver/core-executor'; +import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; import { ConnectionInfoResource, Connection } from './ConnectionInfoResource'; import { ContainerResource, IStructContainers, ObjectContainer } from './ContainerResource'; import { EConnectionFeature } from './EConnectionFeature'; +type ConnectionHandlerState = 'before' | 'after'; + +export interface IConnectionHandlerData { + connectionId: string; + state: ConnectionHandlerState; +} + @injectable() export class ConnectionsManagerService { readonly connectionExecutor: IExecutor; + readonly onDisconnect: IExecutor; + readonly onDelete: IExecutor; private disconnecting: boolean; @@ -30,7 +39,11 @@ export class ConnectionsManagerService { private readonly commonDialogService: CommonDialogService ) { this.disconnecting = false; + this.connectionExecutor = new Executor(null, (active, current) => active === current); + this.onDisconnect = new Executor(); + this.onDelete = new Executor(); + this.connectionExecutor.addHandler(() => connectionInfo.load(CachedMapAllKey)); } @@ -84,6 +97,15 @@ export class ConnectionsManagerService { return; } + const contexts = await this.onDelete.execute({ + connectionId: id, + state: 'before', + }); + + if (ExecutorInterrupter.isInterrupted(contexts)) { + return; + } + const result = await this.commonDialogService.open(ConfirmationDialogDelete, { title: 'ui_data_delete_confirmation', message: `You're going to delete "${connection.name}" connection. Are you sure?`, @@ -94,6 +116,11 @@ export class ConnectionsManagerService { } await this.connectionInfo.deleteConnection(id); + + this.onDelete.execute({ + connectionId: id, + state: 'after', + }); } hasAnyConnection(connected?: boolean): boolean { @@ -140,11 +167,25 @@ export class ConnectionsManagerService { if (!connection || !connection.connected) { return; } + const contexts = await this.onDisconnect.execute({ + connectionId: connection.id, + state: 'before', + }); + + if (ExecutorInterrupter.isInterrupted(contexts)) { + return; + } + const { controller, notification } = this.notificationService.processNotification(() => ProcessSnackbar, {}, { title: 'Disconnecting...' }); try { await this._closeConnectionAsync(connection); + notification.close(); + this.onDisconnect.execute({ + connectionId: connection.id, + state: 'after', + }); } catch (exception: any) { controller.reject(exception); } diff --git a/webapp/packages/plugin-authentication/src/AuthenticationService.ts b/webapp/packages/plugin-authentication/src/AuthenticationService.ts index 81ba60c2b5..6b20863bc3 100644 --- a/webapp/packages/plugin-authentication/src/AuthenticationService.ts +++ b/webapp/packages/plugin-authentication/src/AuthenticationService.ts @@ -11,7 +11,7 @@ import { AppAuthService, AuthInfoService, AuthProviderContext, AuthProviderServi import { injectable, Bootstrap } from '@cloudbeaver/core-di'; import type { DialogueStateResult } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; -import type { IExecutorHandler } from '@cloudbeaver/core-executor'; +import { Executor, ExecutorInterrupter, IExecutorHandler } from '@cloudbeaver/core-executor'; import { ServerConfigResource, SessionDataResource } from '@cloudbeaver/core-root'; import { ScreenService } from '@cloudbeaver/core-routing'; import type { ObjectOrigin } from '@cloudbeaver/core-sdk'; @@ -19,8 +19,12 @@ import { openCenteredPopup } from '@cloudbeaver/core-utils'; import { AuthDialogService } from './Dialog/AuthDialogService'; +export type LogoutState = 'before' | 'after'; + @injectable() export class AuthenticationService extends Bootstrap { + readonly onLogout: Executor; + configureAuthProvider: (() => void) | null; configureIdentityProvider: (() => void) | null; @@ -40,6 +44,9 @@ export class AuthenticationService extends Bootstrap { private readonly serverConfigResource: ServerConfigResource, ) { super(); + + this.onLogout = new Executor(); + this.authPromise = null; this.configureAuthProvider = null; this.configureIdentityProvider = null; @@ -58,6 +65,12 @@ export class AuthenticationService extends Bootstrap { } async logout(): Promise { + const contexts = await this.onLogout.execute('before'); + + if (ExecutorInterrupter.isInterrupted(contexts)) { + return; + } + if (this.authInfoService.userAuthConfigurations.length > 0) { const userAuthConfiguration = this.authInfoService.userAuthConfigurations[0]; @@ -72,6 +85,8 @@ export class AuthenticationService extends Bootstrap { if (!this.administrationScreenService.isConfigurationMode) { this.screenService.navigateToRoot(); } + + await this.onLogout.execute('after'); } catch (exception: any) { this.notificationService.logException(exception, 'Can\'t logout'); } diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts new file mode 100644 index 0000000000..c5a59e8e42 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts @@ -0,0 +1,86 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2022 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import { ConnectionsManagerService, IConnectionHandlerData } from '@cloudbeaver/core-connections'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import { ExecutorInterrupter, IExecutionContextProvider } from '@cloudbeaver/core-executor'; +import { IServerConfigSaveData, ServerConfigurationService } from '@cloudbeaver/plugin-administration'; +import { AuthenticationService, LogoutState } from '@cloudbeaver/plugin-authentication'; +import { SqlEditorTabService } from '@cloudbeaver/plugin-sql-editor-navigation-tab'; + +import { SqlEditorMenuService } from './SqlEditorMenuService'; +import { SqlResultTabsService } from './SqlResultTabs/SqlResultTabsService'; + +@injectable() +export class SqlEditorBootstrap extends Bootstrap { + constructor( + private readonly authenticationService: AuthenticationService, + private readonly sqlEditorTabService: SqlEditorTabService, + private readonly sqlResultTabsService: SqlResultTabsService, + private readonly sqlEditorMenuService: SqlEditorMenuService, + private readonly connectionsManagerService: ConnectionsManagerService, + private readonly serverConfigurationService: ServerConfigurationService + ) { + super(); + } + + register(): void { + this.sqlEditorMenuService.register(); + + this.authenticationService.onLogout.addHandler(this.logoutHandler.bind(this)); + this.connectionsManagerService.onDisconnect.addHandler(this.connectionHandler.bind(this)); + this.connectionsManagerService.onDelete.addHandler(this.connectionHandler.bind(this)); + this.serverConfigurationService.saveTask.addHandler(this.saveHandler.bind(this)); + } + + load(): void | Promise { } + + private async saveHandler(data: IServerConfigSaveData, contexts: IExecutionContextProvider) { + for (const tab of this.sqlEditorTabService.sqlEditorTabs) { + const canSave = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); + + if (!canSave) { + ExecutorInterrupter.interrupt(contexts); + return; + } + } + } + + private async logoutHandler(data: LogoutState, contexts: IExecutionContextProvider) { + if (data === 'before') { + for (const tab of this.sqlEditorTabService.sqlEditorTabs) { + const canLogout = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); + + if (!canLogout) { + ExecutorInterrupter.interrupt(contexts); + return; + } + } + } + } + + private async connectionHandler( + data: IConnectionHandlerData, + contexts: IExecutionContextProvider + ) { + if (data.state === 'before') { + for (const tab of this.sqlEditorTabService.sqlEditorTabs) { + if (tab.handlerState.executionContext?.connectionId !== data.connectionId) { + continue; + } + + const canPerformAction = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); + + if (!canPerformAction) { + ExecutorInterrupter.interrupt(contexts); + return; + } + } + } + } +} \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorMenuService.ts similarity index 96% rename from webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts rename to webapp/packages/plugin-sql-editor/src/SqlEditorMenuService.ts index 8f20f18eb0..719b10e517 100644 --- a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorMenuService.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import { injectable } from '@cloudbeaver/core-di'; import { ActionService, KeyBindingService, MenuService, IAction, IDataContextProvider } from '@cloudbeaver/core-view'; import { ACTION_SQL_EDITOR_EXECUTE } from './actions/ACTION_SQL_EDITOR_EXECUTE'; @@ -22,14 +22,12 @@ import { KEY_BINDING_SQL_EDITOR_SHOW_EXECUTION_PLAN } from './actions/bindings/K import { DATA_CONTEXT_SQL_EDITOR_DATA } from './SqlEditor/DATA_CONTEXT_SQL_EDITOR_DATA'; @injectable() -export class MenuBootstrap extends Bootstrap { +export class SqlEditorMenuService { constructor( private readonly actionService: ActionService, private readonly keyBindingService: KeyBindingService, private readonly menuService: MenuService - ) { - super(); - } + ) { } register(): void { this.actionService.addHandler({ @@ -124,6 +122,4 @@ export class MenuBootstrap extends Bootstrap { break; } } - - load(): void { } } \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/src/manifest.ts b/webapp/packages/plugin-sql-editor/src/manifest.ts index 8b8f9b8de3..8e48120cee 100644 --- a/webapp/packages/plugin-sql-editor/src/manifest.ts +++ b/webapp/packages/plugin-sql-editor/src/manifest.ts @@ -9,9 +9,10 @@ import type { PluginManifest } from '@cloudbeaver/core-di'; import { LocaleService } from './LocaleService'; -import { MenuBootstrap } from './MenuBootstrap'; import { SqlDialectInfoService } from './SqlDialectInfoService'; import { SQLCodeEditorPanelBootstrap } from './SqlEditor/SQLCodeEditorPanel/SQLCodeEditorPanelBootstrap'; +import { SqlEditorBootstrap } from './SqlEditorBootstrap'; +import { SqlEditorMenuService } from './SqlEditorMenuService'; import { SqlEditorModeService } from './SqlEditorModeService'; import { SqlEditorService } from './SqlEditorService'; import { SqlEditorSettingsService } from './SqlEditorSettingsService'; @@ -28,7 +29,9 @@ export const sqlEditorPluginManifest: PluginManifest = { providers: [ LocaleService, + SqlEditorBootstrap, SqlEditorService, + SqlEditorMenuService, SqlDialectInfoService, SqlQueryResultService, SqlQueryService, @@ -38,6 +41,5 @@ export const sqlEditorPluginManifest: PluginManifest = { SqlEditorModeService, SQLCodeEditorPanelBootstrap, SqlEditorView, - MenuBootstrap, ], }; From cc5d1f55ec1511cec229d155a20f02528c00bcc4 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Mon, 20 Jun 2022 12:00:56 +0300 Subject: [PATCH 2/6] CB-2175 fix NPE get struct containers (#909) --- .../cloudbeaver/service/navigator/impl/WebServiceNavigator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java index 9b4988b371..335f28b5ab 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java @@ -221,7 +221,7 @@ public class WebServiceNavigator implements DBWServiceNavigator { contextDefaults != null && contextDefaults.supportsSchemaChange() && ( contextDefaults.getDefaultCatalog().getName().equals(node.getName()) - || catalog.equals(node.getName()) + || node.getName().equals(catalog) ) ) { try { From 2d2b85df88f6758c64bb6c7fb3baee23ab12d6cb Mon Sep 17 00:00:00 2001 From: Naumov Alexey Date: Mon, 20 Jun 2022 12:21:03 +0200 Subject: [PATCH 3/6] feat(plugin-sql-editor): CB-1498 move handler logic to the plugin-sql-editor-navigation-tab --- .../src/SqlEditorBootstrap.ts | 49 ++++++++++- ...lEditorMenuService.ts => MenuBootstrap.ts} | 10 ++- .../src/SqlEditorBootstrap.ts | 86 ------------------- .../plugin-sql-editor/src/manifest.ts | 6 +- 4 files changed, 54 insertions(+), 97 deletions(-) rename webapp/packages/plugin-sql-editor/src/{SqlEditorMenuService.ts => MenuBootstrap.ts} (96%) delete mode 100644 webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts diff --git a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts index f670ffc007..6890f7293f 100644 --- a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts +++ b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts @@ -12,15 +12,16 @@ import { ConnectionSchemaManagerService, isObjectCatalogProvider, isObjectSchemaProvider, DATA_CONTEXT_NAV_NODE, NavigationTabsService } from '@cloudbeaver/core-app'; -import { isConnectionProvider } from '@cloudbeaver/core-connections'; +import { ConnectionsManagerService, IConnectionHandlerData, isConnectionProvider } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult, RenameDialog } from '@cloudbeaver/core-dialogs'; -import type { IExecutorHandler } from '@cloudbeaver/core-executor'; +import { ExecutorInterrupter, IExecutionContextProvider, IExecutorHandler } from '@cloudbeaver/core-executor'; import { ExtensionUtils } from '@cloudbeaver/core-extensions'; import { ISessionAction, sessionActionContext, SessionActionService } from '@cloudbeaver/core-root'; import { ActionService, ACTION_RENAME, DATA_CONTEXT_MENU_NESTED, menuExtractActions, MenuService, ViewService } from '@cloudbeaver/core-view'; +import { AuthenticationService, LogoutState } from '@cloudbeaver/plugin-authentication'; import { DATA_CONTEXT_CONNECTION } from '@cloudbeaver/plugin-connections'; -import { DATA_CONTEXT_SQL_EDITOR_STATE } from '@cloudbeaver/plugin-sql-editor'; +import { DATA_CONTEXT_SQL_EDITOR_STATE, SqlResultTabsService } from '@cloudbeaver/plugin-sql-editor'; import { ACTION_SQL_EDITOR_OPEN } from './ACTION_SQL_EDITOR_OPEN'; import { DATA_CONTEXT_SQL_EDITOR_TAB } from './DATA_CONTEXT_SQL_EDITOR_TAB'; @@ -41,12 +42,19 @@ export class SqlEditorBootstrap extends Bootstrap { private readonly menuService: MenuService, private readonly sessionActionService: SessionActionService, private readonly commonDialogService: CommonDialogService, - private readonly sqlEditorTabService: SqlEditorTabService + private readonly sqlEditorTabService: SqlEditorTabService, + private readonly authenticationService: AuthenticationService, + private readonly sqlResultTabsService: SqlResultTabsService, + private readonly connectionsManagerService: ConnectionsManagerService, ) { super(); } register(): void { + this.authenticationService.onLogout.addHandler(this.logoutHandler.bind(this)); + this.connectionsManagerService.onDisconnect.addHandler(this.connectionHandler.bind(this)); + this.connectionsManagerService.onDelete.addHandler(this.connectionHandler.bind(this)); + this.mainMenuService.registerRootItem( { id: 'sql-editor', @@ -186,4 +194,37 @@ export class SqlEditorBootstrap extends Bootstrap { } } }; + + private async logoutHandler(data: LogoutState, contexts: IExecutionContextProvider) { + if (data === 'before') { + for (const tab of this.sqlEditorTabService.sqlEditorTabs) { + const canLogout = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); + + if (!canLogout) { + ExecutorInterrupter.interrupt(contexts); + return; + } + } + } + } + + private async connectionHandler( + data: IConnectionHandlerData, + contexts: IExecutionContextProvider + ) { + if (data.state === 'before') { + for (const tab of this.sqlEditorTabService.sqlEditorTabs) { + if (tab.handlerState.executionContext?.connectionId !== data.connectionId) { + continue; + } + + const canPerformAction = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); + + if (!canPerformAction) { + ExecutorInterrupter.interrupt(contexts); + return; + } + } + } + } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorMenuService.ts b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts similarity index 96% rename from webapp/packages/plugin-sql-editor/src/SqlEditorMenuService.ts rename to webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts index 719b10e517..2612bd9999 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorMenuService.ts +++ b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import { injectable } from '@cloudbeaver/core-di'; +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { ActionService, KeyBindingService, MenuService, IAction, IDataContextProvider } from '@cloudbeaver/core-view'; import { ACTION_SQL_EDITOR_EXECUTE } from './actions/ACTION_SQL_EDITOR_EXECUTE'; @@ -22,12 +22,14 @@ import { KEY_BINDING_SQL_EDITOR_SHOW_EXECUTION_PLAN } from './actions/bindings/K import { DATA_CONTEXT_SQL_EDITOR_DATA } from './SqlEditor/DATA_CONTEXT_SQL_EDITOR_DATA'; @injectable() -export class SqlEditorMenuService { +export class MenuBootstrap extends Bootstrap { constructor( private readonly actionService: ActionService, private readonly keyBindingService: KeyBindingService, private readonly menuService: MenuService - ) { } + ) { + super(); + } register(): void { this.actionService.addHandler({ @@ -122,4 +124,6 @@ export class SqlEditorMenuService { break; } } + + load(): void | Promise { } } \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts deleted file mode 100644 index c5a59e8e42..0000000000 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorBootstrap.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2022 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ - -import { ConnectionsManagerService, IConnectionHandlerData } from '@cloudbeaver/core-connections'; -import { Bootstrap, injectable } from '@cloudbeaver/core-di'; -import { ExecutorInterrupter, IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import { IServerConfigSaveData, ServerConfigurationService } from '@cloudbeaver/plugin-administration'; -import { AuthenticationService, LogoutState } from '@cloudbeaver/plugin-authentication'; -import { SqlEditorTabService } from '@cloudbeaver/plugin-sql-editor-navigation-tab'; - -import { SqlEditorMenuService } from './SqlEditorMenuService'; -import { SqlResultTabsService } from './SqlResultTabs/SqlResultTabsService'; - -@injectable() -export class SqlEditorBootstrap extends Bootstrap { - constructor( - private readonly authenticationService: AuthenticationService, - private readonly sqlEditorTabService: SqlEditorTabService, - private readonly sqlResultTabsService: SqlResultTabsService, - private readonly sqlEditorMenuService: SqlEditorMenuService, - private readonly connectionsManagerService: ConnectionsManagerService, - private readonly serverConfigurationService: ServerConfigurationService - ) { - super(); - } - - register(): void { - this.sqlEditorMenuService.register(); - - this.authenticationService.onLogout.addHandler(this.logoutHandler.bind(this)); - this.connectionsManagerService.onDisconnect.addHandler(this.connectionHandler.bind(this)); - this.connectionsManagerService.onDelete.addHandler(this.connectionHandler.bind(this)); - this.serverConfigurationService.saveTask.addHandler(this.saveHandler.bind(this)); - } - - load(): void | Promise { } - - private async saveHandler(data: IServerConfigSaveData, contexts: IExecutionContextProvider) { - for (const tab of this.sqlEditorTabService.sqlEditorTabs) { - const canSave = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); - - if (!canSave) { - ExecutorInterrupter.interrupt(contexts); - return; - } - } - } - - private async logoutHandler(data: LogoutState, contexts: IExecutionContextProvider) { - if (data === 'before') { - for (const tab of this.sqlEditorTabService.sqlEditorTabs) { - const canLogout = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); - - if (!canLogout) { - ExecutorInterrupter.interrupt(contexts); - return; - } - } - } - } - - private async connectionHandler( - data: IConnectionHandlerData, - contexts: IExecutionContextProvider - ) { - if (data.state === 'before') { - for (const tab of this.sqlEditorTabService.sqlEditorTabs) { - if (tab.handlerState.executionContext?.connectionId !== data.connectionId) { - continue; - } - - const canPerformAction = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); - - if (!canPerformAction) { - ExecutorInterrupter.interrupt(contexts); - return; - } - } - } - } -} \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/src/manifest.ts b/webapp/packages/plugin-sql-editor/src/manifest.ts index 8e48120cee..8b8f9b8de3 100644 --- a/webapp/packages/plugin-sql-editor/src/manifest.ts +++ b/webapp/packages/plugin-sql-editor/src/manifest.ts @@ -9,10 +9,9 @@ import type { PluginManifest } from '@cloudbeaver/core-di'; import { LocaleService } from './LocaleService'; +import { MenuBootstrap } from './MenuBootstrap'; import { SqlDialectInfoService } from './SqlDialectInfoService'; import { SQLCodeEditorPanelBootstrap } from './SqlEditor/SQLCodeEditorPanel/SQLCodeEditorPanelBootstrap'; -import { SqlEditorBootstrap } from './SqlEditorBootstrap'; -import { SqlEditorMenuService } from './SqlEditorMenuService'; import { SqlEditorModeService } from './SqlEditorModeService'; import { SqlEditorService } from './SqlEditorService'; import { SqlEditorSettingsService } from './SqlEditorSettingsService'; @@ -29,9 +28,7 @@ export const sqlEditorPluginManifest: PluginManifest = { providers: [ LocaleService, - SqlEditorBootstrap, SqlEditorService, - SqlEditorMenuService, SqlDialectInfoService, SqlQueryResultService, SqlQueryService, @@ -41,5 +38,6 @@ export const sqlEditorPluginManifest: PluginManifest = { SqlEditorModeService, SQLCodeEditorPanelBootstrap, SqlEditorView, + MenuBootstrap, ], }; From c3bdc6caa404b7ea10d01a83251072cc6d3ca73a Mon Sep 17 00:00:00 2001 From: Naumov Alexey Date: Mon, 20 Jun 2022 12:34:58 +0200 Subject: [PATCH 4/6] fix(plugin-sql-editor): CB-1498 chain executors --- .../src/ConnectionsManagerService.ts | 29 +++++++++---------- .../src/SqlEditorBootstrap.ts | 15 +++++----- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionsManagerService.ts b/webapp/packages/core-connections/src/ConnectionsManagerService.ts index f456e7ea49..9d6d3492f1 100644 --- a/webapp/packages/core-connections/src/ConnectionsManagerService.ts +++ b/webapp/packages/core-connections/src/ConnectionsManagerService.ts @@ -17,18 +17,16 @@ import { ConnectionInfoResource, Connection } from './ConnectionInfoResource'; import { ContainerResource, IStructContainers, ObjectContainer } from './ContainerResource'; import { EConnectionFeature } from './EConnectionFeature'; -type ConnectionHandlerState = 'before' | 'after'; - -export interface IConnectionHandlerData { +export interface IConnectionExecutorData { connectionId: string; - state: ConnectionHandlerState; + state: 'before' | 'after'; } @injectable() export class ConnectionsManagerService { readonly connectionExecutor: IExecutor; - readonly onDisconnect: IExecutor; - readonly onDelete: IExecutor; + readonly onDisconnect: IExecutor; + readonly onDelete: IExecutor; private disconnecting: boolean; @@ -45,6 +43,7 @@ export class ConnectionsManagerService { this.onDelete = new Executor(); this.connectionExecutor.addHandler(() => connectionInfo.load(CachedMapAllKey)); + this.onDelete.before(this.onDisconnect); } async requireConnection(connectionId: string | null = null): Promise { @@ -97,15 +96,6 @@ export class ConnectionsManagerService { return; } - const contexts = await this.onDelete.execute({ - connectionId: id, - state: 'before', - }); - - if (ExecutorInterrupter.isInterrupted(contexts)) { - return; - } - const result = await this.commonDialogService.open(ConfirmationDialogDelete, { title: 'ui_data_delete_confirmation', message: `You're going to delete "${connection.name}" connection. Are you sure?`, @@ -115,6 +105,15 @@ export class ConnectionsManagerService { return; } + const contexts = await this.onDelete.execute({ + connectionId: id, + state: 'before', + }); + + if (ExecutorInterrupter.isInterrupted(contexts)) { + return; + } + await this.connectionInfo.deleteConnection(id); this.onDelete.execute({ diff --git a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts index 6890f7293f..79f0a7f248 100644 --- a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts +++ b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts @@ -12,7 +12,7 @@ import { ConnectionSchemaManagerService, isObjectCatalogProvider, isObjectSchemaProvider, DATA_CONTEXT_NAV_NODE, NavigationTabsService } from '@cloudbeaver/core-app'; -import { ConnectionsManagerService, IConnectionHandlerData, isConnectionProvider } from '@cloudbeaver/core-connections'; +import { ConnectionsManagerService, IConnectionExecutorData, isConnectionProvider } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult, RenameDialog } from '@cloudbeaver/core-dialogs'; import { ExecutorInterrupter, IExecutionContextProvider, IExecutorHandler } from '@cloudbeaver/core-executor'; @@ -52,8 +52,7 @@ export class SqlEditorBootstrap extends Bootstrap { register(): void { this.authenticationService.onLogout.addHandler(this.logoutHandler.bind(this)); - this.connectionsManagerService.onDisconnect.addHandler(this.connectionHandler.bind(this)); - this.connectionsManagerService.onDelete.addHandler(this.connectionHandler.bind(this)); + this.connectionsManagerService.onDisconnect.addHandler(this.disconnectHandler.bind(this)); this.mainMenuService.registerRootItem( { @@ -208,9 +207,9 @@ export class SqlEditorBootstrap extends Bootstrap { } } - private async connectionHandler( - data: IConnectionHandlerData, - contexts: IExecutionContextProvider + private async disconnectHandler( + data: IConnectionExecutorData, + contexts: IExecutionContextProvider ) { if (data.state === 'before') { for (const tab of this.sqlEditorTabService.sqlEditorTabs) { @@ -218,9 +217,9 @@ export class SqlEditorBootstrap extends Bootstrap { continue; } - const canPerformAction = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); + const canDisconnect = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); - if (!canPerformAction) { + if (!canDisconnect) { ExecutorInterrupter.interrupt(contexts); return; } From 0cc4c4eb76e61b0df70e7ea80b7b4767dab87699 Mon Sep 17 00:00:00 2001 From: Naumov Alexey Date: Mon, 20 Jun 2022 13:19:20 +0200 Subject: [PATCH 5/6] fix(plugin-sql-editor): CB-1498 chain logout executor --- .../src/ConnectionsManagerService.ts | 20 +++++++++++++------ .../src/SqlEditorBootstrap.ts | 6 ++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionsManagerService.ts b/webapp/packages/core-connections/src/ConnectionsManagerService.ts index 9d6d3492f1..583e2a7a66 100644 --- a/webapp/packages/core-connections/src/ConnectionsManagerService.ts +++ b/webapp/packages/core-connections/src/ConnectionsManagerService.ts @@ -12,13 +12,14 @@ import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } fr import { NotificationService } from '@cloudbeaver/core-events'; import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor'; import { CachedMapAllKey } from '@cloudbeaver/core-sdk'; +import { AuthenticationService } from '@cloudbeaver/plugin-authentication'; import { ConnectionInfoResource, Connection } from './ConnectionInfoResource'; import { ContainerResource, IStructContainers, ObjectContainer } from './ContainerResource'; import { EConnectionFeature } from './EConnectionFeature'; export interface IConnectionExecutorData { - connectionId: string; + connections: string[]; state: 'before' | 'after'; } @@ -34,7 +35,8 @@ export class ConnectionsManagerService { readonly connectionInfo: ConnectionInfoResource, readonly containerContainers: ContainerResource, private readonly notificationService: NotificationService, - private readonly commonDialogService: CommonDialogService + private readonly commonDialogService: CommonDialogService, + private readonly authenticationService: AuthenticationService, ) { this.disconnecting = false; @@ -44,6 +46,12 @@ export class ConnectionsManagerService { this.connectionExecutor.addHandler(() => connectionInfo.load(CachedMapAllKey)); this.onDelete.before(this.onDisconnect); + this.authenticationService.onLogout.before(this.onDisconnect, state => ({ + connections: this.connectionInfo.values + .filter(connection => connection.connected) + .map(connection => connection.id), + state, + })); } async requireConnection(connectionId: string | null = null): Promise { @@ -106,7 +114,7 @@ export class ConnectionsManagerService { } const contexts = await this.onDelete.execute({ - connectionId: id, + connections: [id], state: 'before', }); @@ -117,7 +125,7 @@ export class ConnectionsManagerService { await this.connectionInfo.deleteConnection(id); this.onDelete.execute({ - connectionId: id, + connections: [id], state: 'after', }); } @@ -167,7 +175,7 @@ export class ConnectionsManagerService { return; } const contexts = await this.onDisconnect.execute({ - connectionId: connection.id, + connections: [connection.id], state: 'before', }); @@ -182,7 +190,7 @@ export class ConnectionsManagerService { notification.close(); this.onDisconnect.execute({ - connectionId: connection.id, + connections: [connection.id], state: 'after', }); } catch (exception: any) { diff --git a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts index 79f0a7f248..821a96d2ab 100644 --- a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts +++ b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts @@ -19,7 +19,7 @@ import { ExecutorInterrupter, IExecutionContextProvider, IExecutorHandler } from import { ExtensionUtils } from '@cloudbeaver/core-extensions'; import { ISessionAction, sessionActionContext, SessionActionService } from '@cloudbeaver/core-root'; import { ActionService, ACTION_RENAME, DATA_CONTEXT_MENU_NESTED, menuExtractActions, MenuService, ViewService } from '@cloudbeaver/core-view'; -import { AuthenticationService, LogoutState } from '@cloudbeaver/plugin-authentication'; +import type { LogoutState } from '@cloudbeaver/plugin-authentication'; import { DATA_CONTEXT_CONNECTION } from '@cloudbeaver/plugin-connections'; import { DATA_CONTEXT_SQL_EDITOR_STATE, SqlResultTabsService } from '@cloudbeaver/plugin-sql-editor'; @@ -43,7 +43,6 @@ export class SqlEditorBootstrap extends Bootstrap { private readonly sessionActionService: SessionActionService, private readonly commonDialogService: CommonDialogService, private readonly sqlEditorTabService: SqlEditorTabService, - private readonly authenticationService: AuthenticationService, private readonly sqlResultTabsService: SqlResultTabsService, private readonly connectionsManagerService: ConnectionsManagerService, ) { @@ -51,7 +50,6 @@ export class SqlEditorBootstrap extends Bootstrap { } register(): void { - this.authenticationService.onLogout.addHandler(this.logoutHandler.bind(this)); this.connectionsManagerService.onDisconnect.addHandler(this.disconnectHandler.bind(this)); this.mainMenuService.registerRootItem( @@ -213,7 +211,7 @@ export class SqlEditorBootstrap extends Bootstrap { ) { if (data.state === 'before') { for (const tab of this.sqlEditorTabService.sqlEditorTabs) { - if (tab.handlerState.executionContext?.connectionId !== data.connectionId) { + if (!data.connections.includes(tab.handlerState.executionContext?.connectionId ?? '')) { continue; } From c2427b6eb6e8aa57bb99f936aab3595ee89051de Mon Sep 17 00:00:00 2001 From: Naumov Alexey Date: Mon, 20 Jun 2022 13:25:14 +0200 Subject: [PATCH 6/6] fix(plugin-sql-editor): CB-1498 remove extra code --- .../src/AuthenticationService.ts | 4 ++-- .../src/SqlEditorBootstrap.ts | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/webapp/packages/plugin-authentication/src/AuthenticationService.ts b/webapp/packages/plugin-authentication/src/AuthenticationService.ts index 6b20863bc3..e4311e09d7 100644 --- a/webapp/packages/plugin-authentication/src/AuthenticationService.ts +++ b/webapp/packages/plugin-authentication/src/AuthenticationService.ts @@ -19,11 +19,11 @@ import { openCenteredPopup } from '@cloudbeaver/core-utils'; import { AuthDialogService } from './Dialog/AuthDialogService'; -export type LogoutState = 'before' | 'after'; +export type LogoutEventType = 'before' | 'after'; @injectable() export class AuthenticationService extends Bootstrap { - readonly onLogout: Executor; + readonly onLogout: Executor; configureAuthProvider: (() => void) | null; configureIdentityProvider: (() => void) | null; diff --git a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts index 821a96d2ab..9e5da89dec 100644 --- a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts +++ b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts @@ -19,7 +19,6 @@ import { ExecutorInterrupter, IExecutionContextProvider, IExecutorHandler } from import { ExtensionUtils } from '@cloudbeaver/core-extensions'; import { ISessionAction, sessionActionContext, SessionActionService } from '@cloudbeaver/core-root'; import { ActionService, ACTION_RENAME, DATA_CONTEXT_MENU_NESTED, menuExtractActions, MenuService, ViewService } from '@cloudbeaver/core-view'; -import type { LogoutState } from '@cloudbeaver/plugin-authentication'; import { DATA_CONTEXT_CONNECTION } from '@cloudbeaver/plugin-connections'; import { DATA_CONTEXT_SQL_EDITOR_STATE, SqlResultTabsService } from '@cloudbeaver/plugin-sql-editor'; @@ -192,19 +191,6 @@ export class SqlEditorBootstrap extends Bootstrap { } }; - private async logoutHandler(data: LogoutState, contexts: IExecutionContextProvider) { - if (data === 'before') { - for (const tab of this.sqlEditorTabService.sqlEditorTabs) { - const canLogout = await this.sqlResultTabsService.canCloseResultTabs(tab.handlerState); - - if (!canLogout) { - ExecutorInterrupter.interrupt(contexts); - return; - } - } - } - } - private async disconnectHandler( data: IConnectionExecutorData, contexts: IExecutionContextProvider