From 94b05047a952e8a0aab23a13c8c45542c8c38b55 Mon Sep 17 00:00:00 2001 From: Dmitrii Date: Wed, 1 Apr 2026 07:22:01 +0200 Subject: [PATCH 1/8] dbeaver/pro#8655 added function confirmation and result events --- .../bundles/io.cloudbeaver.model/plugin.xml | 2 + .../cloudbeaver/model/session/WebSession.java | 30 ++++++++- ...AiFunctionCallConfirmationClientEvent.java | 66 +++++++++++++++++++ .../websockets/CBClientEventProcessor.java | 9 ++- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java diff --git a/server/bundles/io.cloudbeaver.model/plugin.xml b/server/bundles/io.cloudbeaver.model/plugin.xml index 8f6f3cc06d5..bb444601012 100644 --- a/server/bundles/io.cloudbeaver.model/plugin.xml +++ b/server/bundles/io.cloudbeaver.model/plugin.xml @@ -46,6 +46,8 @@ class="io.cloudbeaver.websocket.event.client.WSSessionTaskConfirmationEvent"/> + diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 36f2f22a218..73c0fb5b7ed 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -1,6 +1,6 @@ /* * DBeaver - Universal Database Manager - * Copyright (C) 2010-2025 DBeaver Corp and others + * Copyright (C) 2010-2026 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -614,6 +614,21 @@ public WebAsyncTaskInfo createAndRunAsyncTask(@NotNull String taskName, @NotNull return runAsyncTask(asyncTask, runnable); } + @Nullable + public WebAsyncTaskInfo runAsyncTaskJob(@NotNull String taskId) { + WebAsyncTaskInfo asyncTask; + synchronized (asyncTasks) { + asyncTask = asyncTasks.get(taskId); + } + if (asyncTask == null || asyncTask.getJob() == null) { + addSessionError(new DBWebException("Task '" + taskId + "' should exist and have a job")); + return null; + } + asyncTask.setRunning(true); + asyncTask.getJob().schedule(); + return asyncTask; + } + public WebAsyncTaskInfo runAsyncTask(@NotNull WebAsyncTaskInfo asyncTask, @NotNull WebAsyncTaskProcessor runnable) { AbstractJob job = new AbstractCancelableJob(asyncTask.getName()) { @NotNull @@ -1049,6 +1064,19 @@ public void handleTaskConfirmationWithParameters(@NotNull String taskId, @NotNul } } + public void handleAiFunctionConfirmation(@NotNull String taskId, boolean confirmed) { + if (confirmed) { + runAsyncTaskJob(taskId); + } else { + try { + asyncTaskCancel(taskId); + } catch (DBWebException e) { + log.error("Error cancelling function confirmation task", e); + addSessionError(e); + } + } + } + @NotNull private String getTaskConfirmationAttributeName(@NotNull String taskId) { return WebSQLConstants.TASK_CONFIRMATION_ATTR_PREFIX + taskId; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java new file mode 100644 index 00000000000..7373c7f0bc0 --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java @@ -0,0 +1,66 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2026 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.cloudbeaver.websocket.event.client; + +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.model.websocket.WSConstants; +import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; + +public class WSAiFunctionCallConfirmationClientEvent extends WSClientEvent { + + public static final String ID = "cb_client_ai_function_call_confirmation"; + + @NotNull + private final String conversationId; + @NotNull + private final String messageId; + @NotNull + private final String taskId; + private final boolean confirmed; + + public WSAiFunctionCallConfirmationClientEvent( + @NotNull String conversationId, + @NotNull String messageId, + @NotNull String taskId, + boolean confirmed + ) { + super(ID, WSConstants.TOPIC_AI); + this.conversationId = conversationId; + this.messageId = messageId; + this.taskId = taskId; + this.confirmed = confirmed; + } + + @NotNull + public String getConversationId() { + return conversationId; + } + + @NotNull + public String getMessageId() { + return messageId; + } + + @NotNull + public String getTaskId() { + return taskId; + } + + public boolean isConfirmed() { + return confirmed; + } +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java index fef9fffdc03..ef9b2de5d5c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java @@ -1,6 +1,6 @@ /* * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others + * Copyright (C) 2010-2026 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,13 @@ public void process(@Nullable String message) { } break; } + case WSAiFunctionCallConfirmationClientEvent.ID: { + if (webSession instanceof WebSession session) { + var event = (WSAiFunctionCallConfirmationClientEvent) clientEvent; + session.handleAiFunctionConfirmation(event.getTaskId(), event.isConfirmed()); + } + break; + } default: var e = new DBWebException("Unknown client event: " + clientEvent.getId()); log.error(e.getMessage(), e); From 47d921ad55fa6c71d50f6ee14d0feb970de7af93 Mon Sep 17 00:00:00 2001 From: Dmitrii Date: Fri, 3 Apr 2026 10:01:17 +0200 Subject: [PATCH 2/8] dbeaver/pro#8655 refactor action function processing --- .../bundles/io.cloudbeaver.model/plugin.xml | 6 ++- .../cloudbeaver/model/session/WebSession.java | 16 ++++-- ...a => WSActionConfirmationClientEvent.java} | 36 ++++--------- .../client/WSActionResultClientEvent.java | 50 +++++++++++++++++++ .../schema/service.events.graphqls | 18 +++++++ .../websockets/CBClientEventProcessor.java | 13 +++-- 6 files changed, 104 insertions(+), 35 deletions(-) rename server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/{WSAiFunctionCallConfirmationClientEvent.java => WSActionConfirmationClientEvent.java} (56%) create mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java diff --git a/server/bundles/io.cloudbeaver.model/plugin.xml b/server/bundles/io.cloudbeaver.model/plugin.xml index 13d24f69e94..c49a85863b5 100644 --- a/server/bundles/io.cloudbeaver.model/plugin.xml +++ b/server/bundles/io.cloudbeaver.model/plugin.xml @@ -48,8 +48,10 @@ class="io.cloudbeaver.websocket.event.client.WSSessionTaskWithParametersConfirmationEvent"/> - + + diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index c5afcf3a151..ee71669c45d 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -1071,12 +1071,12 @@ public void handleActionCancelledEvent(@NotNull String actionId) { removeAttribute(actionId); } - public void handleAiFunctionConfirmation(@NotNull String taskId, boolean confirmed) { + public void handleActionConfirmation(@NotNull String actionId, boolean confirmed) { if (confirmed) { - runAsyncTaskJob(taskId); + runAsyncTaskJob(actionId); } else { try { - asyncTaskCancel(taskId); + asyncTaskCancel(actionId); } catch (DBWebException e) { log.error("Error cancelling function confirmation task", e); addSessionError(e); @@ -1084,6 +1084,16 @@ public void handleAiFunctionConfirmation(@NotNull String taskId, boolean confirm } } + public void handleActionResult(@NotNull String actionId, @NotNull Object result) { + CompletableFuture future = getAttribute(actionId); + if (future != null) { + future.complete(result); + removeAttribute(actionId); + } else { + log.error("Received unexpected action result event for actionId: " + actionId); + } + } + @NotNull private String getTaskConfirmationAttributeName(@NotNull String taskId) { return WebSQLConstants.TASK_CONFIRMATION_ATTR_PREFIX + taskId; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionConfirmationClientEvent.java similarity index 56% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionConfirmationClientEvent.java index 7373c7f0bc0..aaffdadbd0a 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionConfirmationClientEvent.java @@ -20,44 +20,26 @@ import org.jkiss.dbeaver.model.websocket.WSConstants; import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; -public class WSAiFunctionCallConfirmationClientEvent extends WSClientEvent { +public class WSActionConfirmationClientEvent extends WSClientEvent { - public static final String ID = "cb_client_ai_function_call_confirmation"; + public static final String ID = "cb_client_action_confirmation"; @NotNull - private final String conversationId; - @NotNull - private final String messageId; - @NotNull - private final String taskId; + private final String actionId; private final boolean confirmed; - public WSAiFunctionCallConfirmationClientEvent( - @NotNull String conversationId, - @NotNull String messageId, - @NotNull String taskId, + public WSActionConfirmationClientEvent( + @NotNull String actionId, boolean confirmed ) { - super(ID, WSConstants.TOPIC_AI); - this.conversationId = conversationId; - this.messageId = messageId; - this.taskId = taskId; + super(ID, WSConstants.TOPIC_SESSION_ACTION); + this.actionId = actionId; this.confirmed = confirmed; } @NotNull - public String getConversationId() { - return conversationId; - } - - @NotNull - public String getMessageId() { - return messageId; - } - - @NotNull - public String getTaskId() { - return taskId; + public String getActionId() { + return actionId; } public boolean isConfirmed() { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java new file mode 100644 index 00000000000..3fcba47ac4f --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java @@ -0,0 +1,50 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2026 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.cloudbeaver.websocket.event.client; + +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.model.websocket.WSConstants; +import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; + +public class WSActionResultClientEvent extends WSClientEvent { + + public static final String ID = "cb_client_action_result"; + + @NotNull + private final String actionId; + @NotNull + private final Object result; + + public WSActionResultClientEvent( + @NotNull String actionId, + @NotNull Object result + ) { + super(ID, WSConstants.TOPIC_SESSION_ACTION); + this.actionId = actionId; + this.result = result; + } + + @NotNull + public String getActionId() { + return actionId; + } + + @NotNull + public Object getResult() { + return result; + } +} diff --git a/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls index bd3b47d3213..d4bf6ba5a82 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls @@ -40,6 +40,8 @@ enum CBClientEventId { cb_client_projects_active, cb_client_session_ping, cb_client_cancel_action @since(version: "26.0.2") + cb_client_action_confirmation @since(version: "26.0.3") + cb_client_action_result @since(version: "26.0.3") } "Client subscribes on topic to receive only related events" @@ -144,6 +146,22 @@ type CBActionCancelledEvent implements CBClientEvent @since(version: "26.0.2") { actionId: String! } +"User's action result" +type CBActionResultEvent implements CBClientEvent @since(version: "26.0.3") { + id: CBClientEventId! + topicId: CBEventTopic + actionId: String! + result: Object! +} + +"User's action confirmation" +type CBActionConfirmationEvent implements CBClientEvent @since(version: "26.0.3") { + id: CBClientEventId! + topicId: CBEventTopic + actionId: String! + confirmed: Boolean +} + "Async task info status event" type WSAsyncTaskInfo @since(version: "24.3.1") { id: CBServerEventId! diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java index f20670d9eaa..55ca50be9ad 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java @@ -98,10 +98,17 @@ public void process(@Nullable String message) { } break; } - case WSAiFunctionCallConfirmationClientEvent.ID: { + case WSActionConfirmationClientEvent.ID: { if (webSession instanceof WebSession session) { - var event = (WSAiFunctionCallConfirmationClientEvent) clientEvent; - session.handleAiFunctionConfirmation(event.getTaskId(), event.isConfirmed()); + var event = (WSActionConfirmationClientEvent) clientEvent; + session.handleActionConfirmation(event.getActionId(), event.isConfirmed()); + } + break; + } + case WSActionResultClientEvent.ID: { + if (webSession instanceof WebSession session) { + var event = (WSActionResultClientEvent) clientEvent; + session.handleActionResult(event.getActionId(), event.getResult()); } break; } From 7343af5e97c6bb62bc61592a5bfcd4634e265407 Mon Sep 17 00:00:00 2001 From: naumov Date: Mon, 6 Apr 2026 11:58:57 +0200 Subject: [PATCH 3/8] dbeaver/pro#8655 support function role --- webapp/packages/core-blocks/src/Expand/Expandable.tsx | 11 ++++++----- .../src/ConnectionFolderEventHandler.ts | 2 +- .../src/ConnectionInfoEventHandler.ts | 2 +- .../src/ConnectionStateEventHandler.ts | 2 +- .../core-projects/src/ProjectInfoEventHandler.ts | 2 +- .../src/ResourceManagerEventHandler.ts | 2 +- .../src/AsyncTask/AsyncTaskInfoEventHandler.ts | 2 +- webapp/packages/core-root/src/SessionEventSource.ts | 8 ++++---- .../packages/core-root/src/SessionInfoEventHandler.ts | 2 +- .../core-root/src/SessionPermissionEventHandler.ts | 2 +- .../src/ServerNotificationsEventHandler.ts | 7 +------ .../src/SessionActionsEventHandler.ts | 4 ++-- .../TransactionLog/TransactionLogCountEventHandler.ts | 2 +- 13 files changed, 22 insertions(+), 26 deletions(-) diff --git a/webapp/packages/core-blocks/src/Expand/Expandable.tsx b/webapp/packages/core-blocks/src/Expand/Expandable.tsx index 90f86f3268a..d4ec6489b06 100644 --- a/webapp/packages/core-blocks/src/Expand/Expandable.tsx +++ b/webapp/packages/core-blocks/src/Expand/Expandable.tsx @@ -9,27 +9,28 @@ import { observer } from 'mobx-react-lite'; import { type ReactNode } from 'react'; import { IconOrImage } from '../IconOrImage.js'; -import { DisclosureProvider, Disclosure, DisclosureContent } from '@dbeaver/ui-kit'; +import { DisclosureProvider, Disclosure, DisclosureContent, clsx } from '@dbeaver/ui-kit'; import './Expandable.css'; interface Props { - label: string; + label: string | ReactNode; children: ReactNode; defaultExpanded?: boolean; disabled?: boolean; + className?: string; } -export const Expandable = observer(function Expandable({ label, defaultExpanded, disabled, children }: Props) { +export const Expandable = observer(function Expandable({ label, defaultExpanded, disabled, children, className }: Props) { return (
-

{label}

+ {typeof label === 'string' ?

{label}

: label}
-
{children}
+
{children}
diff --git a/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts b/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts index 8b01f34d545..3418dbd6f6d 100644 --- a/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts +++ b/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts @@ -12,7 +12,7 @@ import type { CbDatasourceFolderEvent as IConnectionFolderEvent } from '@cloudbe export type { IConnectionFolderEvent }; @injectable(() => [SessionEventSource]) -export class ConnectionFolderEventHandler extends TopicEventHandler { +export class ConnectionFolderEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbDatasourceFolder, sessionEventSource); } diff --git a/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts b/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts index 37ff2fe6fc0..da105d8ec98 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts @@ -12,7 +12,7 @@ import type { CbDatasourceEvent as IConnectionInfoEvent } from '@cloudbeaver/cor export type { IConnectionInfoEvent }; @injectable(() => [SessionEventSource]) -export class ConnectionInfoEventHandler extends TopicEventHandler { +export class ConnectionInfoEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbDatasource, sessionEventSource); } diff --git a/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts b/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts index 7afdf3070f6..103c5ef602b 100644 --- a/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts +++ b/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts @@ -15,7 +15,7 @@ export type IWsDataSourceConnectEvent = WsDataSourceConnectEvent; type ConnectionStateEvent = IWsDataSourceConnectEvent | IWsDataSourceDisconnectEvent; @injectable(() => [SessionEventSource]) -export class ConnectionStateEventHandler extends TopicEventHandler { +export class ConnectionStateEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbDatasourceConnection, sessionEventSource); } diff --git a/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts b/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts index 58bdd1d030d..6aa14135e79 100644 --- a/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts +++ b/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts @@ -20,7 +20,7 @@ import { isArraysEqual } from '@cloudbeaver/core-utils'; export type { IProjectInfoEvent }; @injectable(() => [SessionEventSource]) -export class ProjectInfoEventHandler extends TopicEventHandler { +export class ProjectInfoEventHandler extends TopicEventHandler { private lastActiveProjects: string[]; constructor(sessionEventSource: SessionEventSource) { diff --git a/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts b/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts index 54fb2dabf3e..11fb293a519 100644 --- a/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts +++ b/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts @@ -10,7 +10,7 @@ import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEve import type { CbrmEvent as IResourceManagerEvent } from '@cloudbeaver/core-sdk'; @injectable(() => [SessionEventSource]) -export class ResourceManagerEventHandler extends TopicEventHandler { +export class ResourceManagerEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbScripts, sessionEventSource); } diff --git a/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts b/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts index a7a9dc17208..7c1ce6b2235 100644 --- a/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts +++ b/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts @@ -12,7 +12,7 @@ import { TopicEventHandler } from '../ServerEventEmitter/TopicEventHandler.js'; import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEventTopic } from '../SessionEventSource.js'; @injectable(() => [SessionEventSource]) -export class AsyncTaskInfoEventHandler extends TopicEventHandler { +export class AsyncTaskInfoEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbSessionTask, sessionEventSource); } diff --git a/webapp/packages/core-root/src/SessionEventSource.ts b/webapp/packages/core-root/src/SessionEventSource.ts index 439e6a9a7c6..b1b50f6a9d3 100644 --- a/webapp/packages/core-root/src/SessionEventSource.ts +++ b/webapp/packages/core-root/src/SessionEventSource.ts @@ -47,22 +47,22 @@ export { ServerEventId, SessionEventTopic, ClientEventId }; export type SessionEventId = ServerEventId | ClientEventId | string; -export interface ISessionEvent extends IBaseServerEvent { +export interface ISessionEvent extends IBaseServerEvent { id: SessionEventId; - topicId?: SessionEventTopic; + topicId?: string; [key: string]: any; } export interface ITopicSubEvent extends ISessionEvent { id: ClientEventId.CbClientTopicSubscribe | ClientEventId.CbClientTopicUnsubscribe; - topicId: SessionEventTopic; + topicId: string; } const RETRY_INTERVALS = [1000, 5000, 30000, 60000]; // 1s, 5s, 30s, 1m const MAX_RETRY_ATTEMPTS = 4; @injectable(() => [SessionExpireService, EnvironmentService]) -export class SessionEventSource implements IServerEventEmitter { +export class SessionEventSource implements IServerEventEmitter { readonly eventsSubject: Observable; readonly onActivate: IExecutor; readonly onInit: ISyncExecutor; diff --git a/webapp/packages/core-root/src/SessionInfoEventHandler.ts b/webapp/packages/core-root/src/SessionInfoEventHandler.ts index f1c3e0454ab..620397d030a 100644 --- a/webapp/packages/core-root/src/SessionInfoEventHandler.ts +++ b/webapp/packages/core-root/src/SessionInfoEventHandler.ts @@ -14,7 +14,7 @@ import { ClientEventId, type ISessionEvent, type SessionEventId, SessionEventSou export { type ISessionStateEvent }; @injectable(() => [SessionEventSource]) -export class SessionInfoEventHandler extends TopicEventHandler { +export class SessionInfoEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbSession, sessionEventSource); } diff --git a/webapp/packages/core-root/src/SessionPermissionEventHandler.ts b/webapp/packages/core-root/src/SessionPermissionEventHandler.ts index 40e07ce2e77..61ff5487fed 100644 --- a/webapp/packages/core-root/src/SessionPermissionEventHandler.ts +++ b/webapp/packages/core-root/src/SessionPermissionEventHandler.ts @@ -14,7 +14,7 @@ import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEve export type { ISessionPermissionEvent }; @injectable(() => [SessionEventSource]) -export class SessionPermissionEventHandler extends TopicEventHandler { +export class SessionPermissionEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbSubjectPermissions, sessionEventSource); } diff --git a/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts b/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts index 8c8b97e705e..2a36c6b2b7f 100644 --- a/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts +++ b/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts @@ -30,12 +30,7 @@ interface ServerNotificationEventMapped extends IBaseServerEvent [SessionEventSource]) -export class ServerNotificationsEventHandler extends TopicEventHandler< - ServerNotificationEventMapped, - ISessionEvent, - SessionEventId, - SessionEventTopic -> { +export class ServerNotificationsEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(CbEventTopic.CbNotification, sessionEventSource); } diff --git a/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts b/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts index 0d897305d82..6fa90dec7a2 100644 --- a/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts +++ b/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts @@ -6,11 +6,11 @@ * you may not use this file except in compliance with the License. */ import { injectable } from '@cloudbeaver/core-di'; -import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEventTopic, TopicEventHandler } from '@cloudbeaver/core-root'; +import { type ISessionEvent, type SessionEventId, SessionEventSource, TopicEventHandler } from '@cloudbeaver/core-root'; import { CbEventTopic, type WsOpenUrlEvent } from '@cloudbeaver/core-sdk'; @injectable(() => [SessionEventSource]) -export class SessionActionsEventHandler extends TopicEventHandler { +export class SessionActionsEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(CbEventTopic.CbSessionAction, sessionEventSource); } diff --git a/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts b/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts index 790a7aef832..844830b5780 100644 --- a/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts +++ b/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts @@ -14,7 +14,7 @@ export type IWsTransactionCountEvent = WsTransactionalCountEvent; type TransactionCountEvent = IWsTransactionCountEvent; @injectable(() => [SessionEventSource]) -export class TransactionLogCountEventHandler extends TopicEventHandler { +export class TransactionLogCountEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbTransaction, sessionEventSource); } From 99d49b1ffcf82e2d054b6fac3bdd3da48fea0ef6 Mon Sep 17 00:00:00 2001 From: Dmitrii Date: Tue, 7 Apr 2026 13:35:00 +0200 Subject: [PATCH 4/8] dbeaver/pro#8655 revert ai function changes --- .../bundles/io.cloudbeaver.model/plugin.xml | 6 +-- .../cloudbeaver/model/session/WebSession.java | 16 ++---- .../client/WSActionResultClientEvent.java | 50 ------------------- ...iFunctionCallConfirmationClientEvent.java} | 36 +++++++++---- .../schema/service.events.graphqls | 18 ------- .../websockets/CBClientEventProcessor.java | 13 ++--- 6 files changed, 35 insertions(+), 104 deletions(-) delete mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java rename server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/{WSActionConfirmationClientEvent.java => WSAiFunctionCallConfirmationClientEvent.java} (56%) diff --git a/server/bundles/io.cloudbeaver.model/plugin.xml b/server/bundles/io.cloudbeaver.model/plugin.xml index c49a85863b5..13d24f69e94 100644 --- a/server/bundles/io.cloudbeaver.model/plugin.xml +++ b/server/bundles/io.cloudbeaver.model/plugin.xml @@ -48,10 +48,8 @@ class="io.cloudbeaver.websocket.event.client.WSSessionTaskWithParametersConfirmationEvent"/> - - + diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index ee71669c45d..c5afcf3a151 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -1071,12 +1071,12 @@ public void handleActionCancelledEvent(@NotNull String actionId) { removeAttribute(actionId); } - public void handleActionConfirmation(@NotNull String actionId, boolean confirmed) { + public void handleAiFunctionConfirmation(@NotNull String taskId, boolean confirmed) { if (confirmed) { - runAsyncTaskJob(actionId); + runAsyncTaskJob(taskId); } else { try { - asyncTaskCancel(actionId); + asyncTaskCancel(taskId); } catch (DBWebException e) { log.error("Error cancelling function confirmation task", e); addSessionError(e); @@ -1084,16 +1084,6 @@ public void handleActionConfirmation(@NotNull String actionId, boolean confirmed } } - public void handleActionResult(@NotNull String actionId, @NotNull Object result) { - CompletableFuture future = getAttribute(actionId); - if (future != null) { - future.complete(result); - removeAttribute(actionId); - } else { - log.error("Received unexpected action result event for actionId: " + actionId); - } - } - @NotNull private String getTaskConfirmationAttributeName(@NotNull String taskId) { return WebSQLConstants.TASK_CONFIRMATION_ATTR_PREFIX + taskId; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java deleted file mode 100644 index 3fcba47ac4f..00000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionResultClientEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2026 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudbeaver.websocket.event.client; - -import org.jkiss.code.NotNull; -import org.jkiss.dbeaver.model.websocket.WSConstants; -import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; - -public class WSActionResultClientEvent extends WSClientEvent { - - public static final String ID = "cb_client_action_result"; - - @NotNull - private final String actionId; - @NotNull - private final Object result; - - public WSActionResultClientEvent( - @NotNull String actionId, - @NotNull Object result - ) { - super(ID, WSConstants.TOPIC_SESSION_ACTION); - this.actionId = actionId; - this.result = result; - } - - @NotNull - public String getActionId() { - return actionId; - } - - @NotNull - public Object getResult() { - return result; - } -} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionConfirmationClientEvent.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java similarity index 56% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionConfirmationClientEvent.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java index aaffdadbd0a..7373c7f0bc0 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSActionConfirmationClientEvent.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java @@ -20,26 +20,44 @@ import org.jkiss.dbeaver.model.websocket.WSConstants; import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; -public class WSActionConfirmationClientEvent extends WSClientEvent { +public class WSAiFunctionCallConfirmationClientEvent extends WSClientEvent { - public static final String ID = "cb_client_action_confirmation"; + public static final String ID = "cb_client_ai_function_call_confirmation"; @NotNull - private final String actionId; + private final String conversationId; + @NotNull + private final String messageId; + @NotNull + private final String taskId; private final boolean confirmed; - public WSActionConfirmationClientEvent( - @NotNull String actionId, + public WSAiFunctionCallConfirmationClientEvent( + @NotNull String conversationId, + @NotNull String messageId, + @NotNull String taskId, boolean confirmed ) { - super(ID, WSConstants.TOPIC_SESSION_ACTION); - this.actionId = actionId; + super(ID, WSConstants.TOPIC_AI); + this.conversationId = conversationId; + this.messageId = messageId; + this.taskId = taskId; this.confirmed = confirmed; } @NotNull - public String getActionId() { - return actionId; + public String getConversationId() { + return conversationId; + } + + @NotNull + public String getMessageId() { + return messageId; + } + + @NotNull + public String getTaskId() { + return taskId; } public boolean isConfirmed() { diff --git a/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls index d4bf6ba5a82..bd3b47d3213 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.events.graphqls @@ -40,8 +40,6 @@ enum CBClientEventId { cb_client_projects_active, cb_client_session_ping, cb_client_cancel_action @since(version: "26.0.2") - cb_client_action_confirmation @since(version: "26.0.3") - cb_client_action_result @since(version: "26.0.3") } "Client subscribes on topic to receive only related events" @@ -146,22 +144,6 @@ type CBActionCancelledEvent implements CBClientEvent @since(version: "26.0.2") { actionId: String! } -"User's action result" -type CBActionResultEvent implements CBClientEvent @since(version: "26.0.3") { - id: CBClientEventId! - topicId: CBEventTopic - actionId: String! - result: Object! -} - -"User's action confirmation" -type CBActionConfirmationEvent implements CBClientEvent @since(version: "26.0.3") { - id: CBClientEventId! - topicId: CBEventTopic - actionId: String! - confirmed: Boolean -} - "Async task info status event" type WSAsyncTaskInfo @since(version: "24.3.1") { id: CBServerEventId! diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java index 55ca50be9ad..f20670d9eaa 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java @@ -98,17 +98,10 @@ public void process(@Nullable String message) { } break; } - case WSActionConfirmationClientEvent.ID: { + case WSAiFunctionCallConfirmationClientEvent.ID: { if (webSession instanceof WebSession session) { - var event = (WSActionConfirmationClientEvent) clientEvent; - session.handleActionConfirmation(event.getActionId(), event.isConfirmed()); - } - break; - } - case WSActionResultClientEvent.ID: { - if (webSession instanceof WebSession session) { - var event = (WSActionResultClientEvent) clientEvent; - session.handleActionResult(event.getActionId(), event.getResult()); + var event = (WSAiFunctionCallConfirmationClientEvent) clientEvent; + session.handleAiFunctionConfirmation(event.getTaskId(), event.isConfirmed()); } break; } From b7121ef64544c8e3ca04d3f9f8fe8809c350111b Mon Sep 17 00:00:00 2001 From: naumov Date: Tue, 7 Apr 2026 17:16:50 +0200 Subject: [PATCH 5/8] Revert "dbeaver/pro#8655 support function role" This reverts commit 7343af5e97c6bb62bc61592a5bfcd4634e265407. --- .../core-connections/src/ConnectionFolderEventHandler.ts | 2 +- .../core-connections/src/ConnectionInfoEventHandler.ts | 2 +- .../core-connections/src/ConnectionStateEventHandler.ts | 2 +- .../packages/core-projects/src/ProjectInfoEventHandler.ts | 2 +- .../src/ResourceManagerEventHandler.ts | 2 +- .../core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts | 2 +- webapp/packages/core-root/src/SessionEventSource.ts | 8 ++++---- webapp/packages/core-root/src/SessionInfoEventHandler.ts | 2 +- .../core-root/src/SessionPermissionEventHandler.ts | 2 +- .../src/ServerNotificationsEventHandler.ts | 7 ++++++- .../src/SessionActionsEventHandler.ts | 4 ++-- .../src/TransactionLog/TransactionLogCountEventHandler.ts | 2 +- 12 files changed, 21 insertions(+), 16 deletions(-) diff --git a/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts b/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts index 3418dbd6f6d..8b01f34d545 100644 --- a/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts +++ b/webapp/packages/core-connections/src/ConnectionFolderEventHandler.ts @@ -12,7 +12,7 @@ import type { CbDatasourceFolderEvent as IConnectionFolderEvent } from '@cloudbe export type { IConnectionFolderEvent }; @injectable(() => [SessionEventSource]) -export class ConnectionFolderEventHandler extends TopicEventHandler { +export class ConnectionFolderEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbDatasourceFolder, sessionEventSource); } diff --git a/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts b/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts index da105d8ec98..37ff2fe6fc0 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoEventHandler.ts @@ -12,7 +12,7 @@ import type { CbDatasourceEvent as IConnectionInfoEvent } from '@cloudbeaver/cor export type { IConnectionInfoEvent }; @injectable(() => [SessionEventSource]) -export class ConnectionInfoEventHandler extends TopicEventHandler { +export class ConnectionInfoEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbDatasource, sessionEventSource); } diff --git a/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts b/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts index 103c5ef602b..7afdf3070f6 100644 --- a/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts +++ b/webapp/packages/core-connections/src/ConnectionStateEventHandler.ts @@ -15,7 +15,7 @@ export type IWsDataSourceConnectEvent = WsDataSourceConnectEvent; type ConnectionStateEvent = IWsDataSourceConnectEvent | IWsDataSourceDisconnectEvent; @injectable(() => [SessionEventSource]) -export class ConnectionStateEventHandler extends TopicEventHandler { +export class ConnectionStateEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbDatasourceConnection, sessionEventSource); } diff --git a/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts b/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts index 6aa14135e79..58bdd1d030d 100644 --- a/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts +++ b/webapp/packages/core-projects/src/ProjectInfoEventHandler.ts @@ -20,7 +20,7 @@ import { isArraysEqual } from '@cloudbeaver/core-utils'; export type { IProjectInfoEvent }; @injectable(() => [SessionEventSource]) -export class ProjectInfoEventHandler extends TopicEventHandler { +export class ProjectInfoEventHandler extends TopicEventHandler { private lastActiveProjects: string[]; constructor(sessionEventSource: SessionEventSource) { diff --git a/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts b/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts index 11fb293a519..54fb2dabf3e 100644 --- a/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts +++ b/webapp/packages/core-resource-manager/src/ResourceManagerEventHandler.ts @@ -10,7 +10,7 @@ import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEve import type { CbrmEvent as IResourceManagerEvent } from '@cloudbeaver/core-sdk'; @injectable(() => [SessionEventSource]) -export class ResourceManagerEventHandler extends TopicEventHandler { +export class ResourceManagerEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbScripts, sessionEventSource); } diff --git a/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts b/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts index 7c1ce6b2235..a7a9dc17208 100644 --- a/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts +++ b/webapp/packages/core-root/src/AsyncTask/AsyncTaskInfoEventHandler.ts @@ -12,7 +12,7 @@ import { TopicEventHandler } from '../ServerEventEmitter/TopicEventHandler.js'; import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEventTopic } from '../SessionEventSource.js'; @injectable(() => [SessionEventSource]) -export class AsyncTaskInfoEventHandler extends TopicEventHandler { +export class AsyncTaskInfoEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbSessionTask, sessionEventSource); } diff --git a/webapp/packages/core-root/src/SessionEventSource.ts b/webapp/packages/core-root/src/SessionEventSource.ts index b1b50f6a9d3..439e6a9a7c6 100644 --- a/webapp/packages/core-root/src/SessionEventSource.ts +++ b/webapp/packages/core-root/src/SessionEventSource.ts @@ -47,22 +47,22 @@ export { ServerEventId, SessionEventTopic, ClientEventId }; export type SessionEventId = ServerEventId | ClientEventId | string; -export interface ISessionEvent extends IBaseServerEvent { +export interface ISessionEvent extends IBaseServerEvent { id: SessionEventId; - topicId?: string; + topicId?: SessionEventTopic; [key: string]: any; } export interface ITopicSubEvent extends ISessionEvent { id: ClientEventId.CbClientTopicSubscribe | ClientEventId.CbClientTopicUnsubscribe; - topicId: string; + topicId: SessionEventTopic; } const RETRY_INTERVALS = [1000, 5000, 30000, 60000]; // 1s, 5s, 30s, 1m const MAX_RETRY_ATTEMPTS = 4; @injectable(() => [SessionExpireService, EnvironmentService]) -export class SessionEventSource implements IServerEventEmitter { +export class SessionEventSource implements IServerEventEmitter { readonly eventsSubject: Observable; readonly onActivate: IExecutor; readonly onInit: ISyncExecutor; diff --git a/webapp/packages/core-root/src/SessionInfoEventHandler.ts b/webapp/packages/core-root/src/SessionInfoEventHandler.ts index 620397d030a..f1c3e0454ab 100644 --- a/webapp/packages/core-root/src/SessionInfoEventHandler.ts +++ b/webapp/packages/core-root/src/SessionInfoEventHandler.ts @@ -14,7 +14,7 @@ import { ClientEventId, type ISessionEvent, type SessionEventId, SessionEventSou export { type ISessionStateEvent }; @injectable(() => [SessionEventSource]) -export class SessionInfoEventHandler extends TopicEventHandler { +export class SessionInfoEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbSession, sessionEventSource); } diff --git a/webapp/packages/core-root/src/SessionPermissionEventHandler.ts b/webapp/packages/core-root/src/SessionPermissionEventHandler.ts index 61ff5487fed..40e07ce2e77 100644 --- a/webapp/packages/core-root/src/SessionPermissionEventHandler.ts +++ b/webapp/packages/core-root/src/SessionPermissionEventHandler.ts @@ -14,7 +14,7 @@ import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEve export type { ISessionPermissionEvent }; @injectable(() => [SessionEventSource]) -export class SessionPermissionEventHandler extends TopicEventHandler { +export class SessionPermissionEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbSubjectPermissions, sessionEventSource); } diff --git a/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts b/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts index 2a36c6b2b7f..8c8b97e705e 100644 --- a/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts +++ b/webapp/packages/core-server-notifications/src/ServerNotificationsEventHandler.ts @@ -30,7 +30,12 @@ interface ServerNotificationEventMapped extends IBaseServerEvent [SessionEventSource]) -export class ServerNotificationsEventHandler extends TopicEventHandler { +export class ServerNotificationsEventHandler extends TopicEventHandler< + ServerNotificationEventMapped, + ISessionEvent, + SessionEventId, + SessionEventTopic +> { constructor(sessionEventSource: SessionEventSource) { super(CbEventTopic.CbNotification, sessionEventSource); } diff --git a/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts b/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts index 6fa90dec7a2..0d897305d82 100644 --- a/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts +++ b/webapp/packages/core-session-actions/src/SessionActionsEventHandler.ts @@ -6,11 +6,11 @@ * you may not use this file except in compliance with the License. */ import { injectable } from '@cloudbeaver/core-di'; -import { type ISessionEvent, type SessionEventId, SessionEventSource, TopicEventHandler } from '@cloudbeaver/core-root'; +import { type ISessionEvent, type SessionEventId, SessionEventSource, SessionEventTopic, TopicEventHandler } from '@cloudbeaver/core-root'; import { CbEventTopic, type WsOpenUrlEvent } from '@cloudbeaver/core-sdk'; @injectable(() => [SessionEventSource]) -export class SessionActionsEventHandler extends TopicEventHandler { +export class SessionActionsEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(CbEventTopic.CbSessionAction, sessionEventSource); } diff --git a/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts b/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts index 844830b5780..790a7aef832 100644 --- a/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts +++ b/webapp/packages/plugin-datasource-transaction-manager/src/TransactionLog/TransactionLogCountEventHandler.ts @@ -14,7 +14,7 @@ export type IWsTransactionCountEvent = WsTransactionalCountEvent; type TransactionCountEvent = IWsTransactionCountEvent; @injectable(() => [SessionEventSource]) -export class TransactionLogCountEventHandler extends TopicEventHandler { +export class TransactionLogCountEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbTransaction, sessionEventSource); } From c7bda565e8ed478a529335600ab0e01f31c0cba8 Mon Sep 17 00:00:00 2001 From: naumov Date: Tue, 7 Apr 2026 17:48:56 +0200 Subject: [PATCH 6/8] dbeaver/pro#8655 simplify types --- webapp/packages/core-root/src/SessionEventSource.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/packages/core-root/src/SessionEventSource.ts b/webapp/packages/core-root/src/SessionEventSource.ts index 439e6a9a7c6..4ba360e488b 100644 --- a/webapp/packages/core-root/src/SessionEventSource.ts +++ b/webapp/packages/core-root/src/SessionEventSource.ts @@ -47,9 +47,9 @@ export { ServerEventId, SessionEventTopic, ClientEventId }; export type SessionEventId = ServerEventId | ClientEventId | string; -export interface ISessionEvent extends IBaseServerEvent { +export interface ISessionEvent extends IBaseServerEvent { id: SessionEventId; - topicId?: SessionEventTopic; + topicId?: T; [key: string]: any; } From 3902b88b732e7a52a88e81735a73945c7cc02967 Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Tue, 7 Apr 2026 18:44:31 +0200 Subject: [PATCH 7/8] dbeaver/pro#8867 Add custom WS event handlers. Move AI-related function top pro. --- .../bundles/io.cloudbeaver.model/plugin.xml | 2 - .../cloudbeaver/model/session/WebSession.java | 30 +-------- ...AiFunctionCallConfirmationClientEvent.java | 66 ------------------- .../websockets/CBClientEventProcessor.java | 20 ++++-- 4 files changed, 15 insertions(+), 103 deletions(-) delete mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java diff --git a/server/bundles/io.cloudbeaver.model/plugin.xml b/server/bundles/io.cloudbeaver.model/plugin.xml index 13d24f69e94..de60a463385 100644 --- a/server/bundles/io.cloudbeaver.model/plugin.xml +++ b/server/bundles/io.cloudbeaver.model/plugin.xml @@ -48,8 +48,6 @@ class="io.cloudbeaver.websocket.event.client.WSSessionTaskWithParametersConfirmationEvent"/> - diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index c5afcf3a151..a66f9cdf15e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -607,26 +607,13 @@ public List findTasksByJob(@NotNull Class runnable) { WebAsyncTaskInfo asyncTask = createAsyncTask(taskName); return runAsyncTask(asyncTask, runnable); } - @Nullable - public WebAsyncTaskInfo runAsyncTaskJob(@NotNull String taskId) { - WebAsyncTaskInfo asyncTask; - synchronized (asyncTasks) { - asyncTask = asyncTasks.get(taskId); - } - if (asyncTask == null || asyncTask.getJob() == null) { - addSessionError(new DBWebException("Task '" + taskId + "' should exist and have a job")); - return null; - } - asyncTask.setRunning(true); - asyncTask.getJob().schedule(); - return asyncTask; - } - + @NotNull public WebAsyncTaskInfo runAsyncTask(@NotNull WebAsyncTaskInfo asyncTask, @NotNull WebAsyncTaskProcessor runnable) { AbstractJob job = new AbstractCancelableJob(asyncTask.getName()) { @NotNull @@ -1071,19 +1058,6 @@ public void handleActionCancelledEvent(@NotNull String actionId) { removeAttribute(actionId); } - public void handleAiFunctionConfirmation(@NotNull String taskId, boolean confirmed) { - if (confirmed) { - runAsyncTaskJob(taskId); - } else { - try { - asyncTaskCancel(taskId); - } catch (DBWebException e) { - log.error("Error cancelling function confirmation task", e); - addSessionError(e); - } - } - } - @NotNull private String getTaskConfirmationAttributeName(@NotNull String taskId) { return WebSQLConstants.TASK_CONFIRMATION_ATTR_PREFIX + taskId; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java deleted file mode 100644 index 7373c7f0bc0..00000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/websocket/event/client/WSAiFunctionCallConfirmationClientEvent.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2026 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudbeaver.websocket.event.client; - -import org.jkiss.code.NotNull; -import org.jkiss.dbeaver.model.websocket.WSConstants; -import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; - -public class WSAiFunctionCallConfirmationClientEvent extends WSClientEvent { - - public static final String ID = "cb_client_ai_function_call_confirmation"; - - @NotNull - private final String conversationId; - @NotNull - private final String messageId; - @NotNull - private final String taskId; - private final boolean confirmed; - - public WSAiFunctionCallConfirmationClientEvent( - @NotNull String conversationId, - @NotNull String messageId, - @NotNull String taskId, - boolean confirmed - ) { - super(ID, WSConstants.TOPIC_AI); - this.conversationId = conversationId; - this.messageId = messageId; - this.taskId = taskId; - this.confirmed = confirmed; - } - - @NotNull - public String getConversationId() { - return conversationId; - } - - @NotNull - public String getMessageId() { - return messageId; - } - - @NotNull - public String getTaskId() { - return taskId; - } - - public boolean isConfirmed() { - return confirmed; - } -} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java index f20670d9eaa..89bc08f5c79 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java @@ -25,6 +25,8 @@ import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.websocket.WSUtils; import org.jkiss.dbeaver.model.websocket.event.WSClientEvent; +import org.jkiss.dbeaver.model.websocket.registry.WSClientEventDescriptor; +import org.jkiss.dbeaver.model.websocket.registry.WSEventRegistry; import org.jkiss.utils.CommonUtils; public class CBClientEventProcessor { @@ -50,6 +52,17 @@ public void process(@Nullable String message) { return; } + // Handle with custom handlers + WSClientEventDescriptor ced = WSEventRegistry.getInstance().getClientEvent(clientEvent.getId()); + if (ced != null && ced.getHandler() != null) { + try { + ced.getHandler().handleEvent(webSession, clientEvent); + } catch (Exception e) { + log.error("Error handling event '" + clientEvent.getId() + "'", e); + } + return; + } + switch (clientEvent.getId()) { case WSSubscribeOnTopicClientEvent.ID: { webSession.getEventsFilter().subscribeOnEventTopic(clientEvent.getTopicId()); @@ -98,13 +111,6 @@ public void process(@Nullable String message) { } break; } - case WSAiFunctionCallConfirmationClientEvent.ID: { - if (webSession instanceof WebSession session) { - var event = (WSAiFunctionCallConfirmationClientEvent) clientEvent; - session.handleAiFunctionConfirmation(event.getTaskId(), event.isConfirmed()); - } - break; - } default: var e = new DBWebException("Unknown client event: " + clientEvent.getId()); log.error(e.getMessage(), e); From 21c76b7f651831f06d871bca876313dd0aebac58 Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Wed, 8 Apr 2026 11:21:31 +0200 Subject: [PATCH 8/8] dbeaver/pro#8655 Remove async tasks from chat workflow --- .../cloudbeaver/server/websockets/CBClientEventProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java index 89bc08f5c79..0bb70b84a5a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBClientEventProcessor.java @@ -53,7 +53,7 @@ public void process(@Nullable String message) { } // Handle with custom handlers - WSClientEventDescriptor ced = WSEventRegistry.getInstance().getClientEvent(clientEvent.getId()); + WSClientEventDescriptor ced = WSEventRegistry.getInstance().getClientEvent(clientEvent.getId()); if (ced != null && ced.getHandler() != null) { try { ced.getHandler().handleEvent(webSession, clientEvent);