From 005adb10ce01531b2d87789e184a4c2fbdf651d6 Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Mon, 26 May 2025 18:39:06 +0200 Subject: [PATCH] dbeaver/pro#5215 track close event on layout close (#3472) * dbeaver/pro#5215 track close event on layout close * dbeaver/pro#5215 support old close behaviour * dbeaver/pro#5215 add event data check to user form * dbeaver/pro#5215 change naming --------- Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com> --- .../AppScreen/BaseOptionsPanelService.ts | 18 +++++++++-------- .../Screens/AppScreen/OptionsPanelService.ts | 13 ++++++++---- .../Users/UsersTable/UserEdit.tsx | 6 +++--- .../src/Search/ConnectionSearchService.ts | 20 ++++++++++--------- .../PublicConnectionFormService.ts | 18 +++++++++-------- .../src/UserProfileOptionsPanelService.ts | 2 +- 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/webapp/packages/core-ui/src/Screens/AppScreen/BaseOptionsPanelService.ts b/webapp/packages/core-ui/src/Screens/AppScreen/BaseOptionsPanelService.ts index 537ef828b3..e26cd8714e 100644 --- a/webapp/packages/core-ui/src/Screens/AppScreen/BaseOptionsPanelService.ts +++ b/webapp/packages/core-ui/src/Screens/AppScreen/BaseOptionsPanelService.ts @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -9,11 +9,11 @@ import { action, makeObservable, observable } from 'mobx'; import { Executor, type IExecutor } from '@cloudbeaver/core-executor'; -import type { OptionsPanelService } from './OptionsPanelService.js'; +import type { OptionsPanelCloseEventData, OptionsPanelService } from './OptionsPanelService.js'; export abstract class BaseOptionsPanelService { itemId: T | null; - readonly onClose: IExecutor; + readonly onClose: IExecutor; constructor( protected readonly optionsPanelService: OptionsPanelService, @@ -26,6 +26,12 @@ export abstract class BaseOptionsPanelService { this.close = this.close.bind(this); this.open = this.open.bind(this); + this.onClose.addHandler(data => { + if (data === 'after') { + this.itemId = null; + } + }); + makeObservable(this, { itemId: observable.ref, open: action, @@ -52,10 +58,6 @@ export abstract class BaseOptionsPanelService { return; } - const result = await this.optionsPanelService.close(); - - if (result) { - this.itemId = null; - } + await this.optionsPanelService.close(); } } diff --git a/webapp/packages/core-ui/src/Screens/AppScreen/OptionsPanelService.ts b/webapp/packages/core-ui/src/Screens/AppScreen/OptionsPanelService.ts index 0ee324c074..9e5ff0ab24 100644 --- a/webapp/packages/core-ui/src/Screens/AppScreen/OptionsPanelService.ts +++ b/webapp/packages/core-ui/src/Screens/AppScreen/OptionsPanelService.ts @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ import { Executor, ExecutorInterrupter, type IExecutionContext, type IExecutor, import { NavigationService } from './NavigationService.js'; +export type OptionsPanelCloseEventData = 'before' | 'after'; + @injectable() export class OptionsPanelService { active: boolean; - readonly closeTask: IExecutor; + readonly closeTask: IExecutor; panelComponent: (() => React.FC) | null; private basePanelComponent: (() => React.FC) | null; @@ -55,12 +57,12 @@ export class OptionsPanelService { return true; } - async close(context?: IExecutionContext): Promise { + async close(context?: IExecutionContext): Promise { if (this.panelComponent === null) { return true; } - const contexts = await this.closeTask.execute(undefined, context); + const contexts = await this.closeTask.execute('before', context); const interrupted = contexts.getContext(ExecutorInterrupter.interruptContext); @@ -68,9 +70,12 @@ export class OptionsPanelService { return false; } + await this.closeTask.execute('after', context); + this.panelComponent = null; this.basePanelComponent = null; this.active = false; + return true; } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx index 0d6a4266f0..9334e1456c 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UserEdit.tsx @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -36,8 +36,8 @@ export const UserEdit = observer>(function UserEdit useExecutor({ executor: usersTableOptionsPanelService.onClose, handlers: [ - async function closeHandler(_, contexts) { - if (state.isChanged) { + async function closeHandler(event, contexts) { + if (state.isChanged && event === 'before') { const result = await commonDialogService.open(ConfirmationDialog, { title: 'core_blocks_confirmation_dialog_title', message: 'ui_save_reminder', diff --git a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts index c13f7dcd06..dda1378ad5 100644 --- a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts +++ b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts @@ -15,7 +15,7 @@ import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dial import { NotificationService } from '@cloudbeaver/core-events'; import { ExecutorInterrupter, type IExecutorHandler } from '@cloudbeaver/core-executor'; import type { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; -import { OptionsPanelService } from '@cloudbeaver/core-ui'; +import { OptionsPanelService, type OptionsPanelCloseEventData } from '@cloudbeaver/core-ui'; import { ConnectionFormService, ConnectionFormState, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections'; const SearchDatabase = importLazyComponent(() => import('./SearchDatabase.js').then(module => module.SearchDatabase)); @@ -92,16 +92,18 @@ export class ConnectionSearchService { } } - private readonly closeHandler: IExecutorHandler = async (data, contexts) => { - const isDialogClosed = await this.showUnsavedChangesDialog(); + private readonly closeHandler: IExecutorHandler = async (data, contexts) => { + if (data === 'before') { + const isDialogClosed = await this.showUnsavedChangesDialog(); - if (!isDialogClosed) { - ExecutorInterrupter.interrupt(contexts); - return; + if (!isDialogClosed) { + ExecutorInterrupter.interrupt(contexts); + return; + } + + this.clearFormState(); + this.close(); } - - this.clearFormState(); - this.close(); }; private get optionsPart() { diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index 8cc6a03d2d..435781e203 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -17,7 +17,7 @@ import { NotificationService } from '@cloudbeaver/core-events'; import { executorHandlerFilter, ExecutorInterrupter, type IExecutorHandler } from '@cloudbeaver/core-executor'; import type { ResourceKey, ResourceKeySimple } from '@cloudbeaver/core-resource'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; -import { FormMode, OptionsPanelService } from '@cloudbeaver/core-ui'; +import { FormMode, OptionsPanelService, type OptionsPanelCloseEventData } from '@cloudbeaver/core-ui'; import { AuthenticationService } from '@cloudbeaver/plugin-authentication'; import { ConnectionFormState } from '../ConnectionForm/ConnectionFormState.js'; @@ -148,15 +148,17 @@ export class PublicConnectionFormService { } }; - private readonly closeHandler: IExecutorHandler = async (data, contexts) => { - const confirmed = await this.showUnsavedChangesDialog(); + private readonly closeHandler: IExecutorHandler = async (data, contexts) => { + if (data === 'before') { + const confirmed = await this.showUnsavedChangesDialog(); - if (!confirmed) { - ExecutorInterrupter.interrupt(contexts); - return; + if (!confirmed) { + ExecutorInterrupter.interrupt(contexts); + return; + } + + this.clearFormState(); } - - this.clearFormState(); }; private async showUnsavedChangesDialog(): Promise { diff --git a/webapp/packages/plugin-user-profile/src/UserProfileOptionsPanelService.ts b/webapp/packages/plugin-user-profile/src/UserProfileOptionsPanelService.ts index 0f04031d9c..2dc67fb1de 100644 --- a/webapp/packages/plugin-user-profile/src/UserProfileOptionsPanelService.ts +++ b/webapp/packages/plugin-user-profile/src/UserProfileOptionsPanelService.ts @@ -33,7 +33,7 @@ export class UserProfileOptionsPanelService { this.onOpen = new SyncExecutor(); this.onClose = new Executor(); - this.optionsPanelService.closeTask.next(this.onClose, undefined, () => this.optionsPanelService.isOpen(panelGetter)); + this.optionsPanelService.closeTask.next(this.onClose, undefined, data => data === 'before' && this.optionsPanelService.isOpen(panelGetter)); this.userInfoResource.onDataUpdate.addHandler(this.userUpdateHandler.bind(this)); makeObservable(this, {