From e32e6eac397397bd98b90c4d5e7b91003b2ad90b Mon Sep 17 00:00:00 2001 From: Sychev Andrey <44414066+SychevAndrey@users.noreply.github.com> Date: Tue, 19 Aug 2025 17:39:13 +0200 Subject: [PATCH 1/5] dbeaver/pro#6325 fix: set cursor to the beginning of the file when opened (#3669) In previous ticket CB-5555 we fixed cursor position on undo/redo actions by adding a check that if selection was not set. In that case we put the cursor to the end of inserted text. Due to previous fixes in CB-4134 we don't set a selection if cursor don't change it's position and initially it's 0. So our check from 5555 is being fired on initially opened script and cursor goes to the end. To avoid that situation, this solution introduces a new isInitialScriptOpening flag that is used to check the first insertion. When initially opening a script, the cursor will stay at the position where we explicitly set it (e.g., position 0). After the first actual content change, the flag isInitialScriptOpening gets set to false. Subsequent changes will then follow the normal cursor behavior (moving to end when there are changes but no explicit cursor position). Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> --- webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx b/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx index cd831342ba..e5cd6ffd51 100644 --- a/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx +++ b/webapp/packages/plugin-codemirror6/src/ReactCodemirror.tsx @@ -42,6 +42,7 @@ export const ReactCodemirror = observer( ref, ) { value = value ?? getValue?.(); + const isInitialScriptOpening = useRef(true); const currentExtensions = useRef>(new Map()); const readOnlyFacet = useMemo(() => { if (readonly) { @@ -214,7 +215,7 @@ export const ReactCodemirror = observer( } } - if (hasInsertProperty(transaction.changes) && !transaction.selection) { + if (hasInsertProperty(transaction.changes) && !transaction.selection && !isInitialScriptOpening.current) { transaction.selection = { anchor: transaction.changes.insert?.length ?? 0, head: transaction.changes.insert?.length ?? 0, @@ -223,6 +224,7 @@ export const ReactCodemirror = observer( if (transaction.changes) { view.dispatch({ changes: transaction.changes }); + isInitialScriptOpening.current = false; } if (transaction.selection) { From a547b85ef28dd00f1c639a3117e9b081da96c7ef Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:43:51 +0200 Subject: [PATCH 2/5] dbeaver/pro#6598 open panel on tab select (#3662) Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> --- webapp/packages/core-app/src/AppScreen/Main.tsx | 13 ++++++++++++- .../core-ui/src/SideBarPanel/SideBarPanel.tsx | 3 +-- .../core-ui/src/Tabs/TabsContainer/TabsContainer.ts | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/webapp/packages/core-app/src/AppScreen/Main.tsx b/webapp/packages/core-app/src/AppScreen/Main.tsx index 9b2a73fbb5..1d0c530c1f 100644 --- a/webapp/packages/core-app/src/AppScreen/Main.tsx +++ b/webapp/packages/core-app/src/AppScreen/Main.tsx @@ -7,7 +7,7 @@ */ import { observer } from 'mobx-react-lite'; -import { getComputed, Loader, Pane, ResizerControls, s, Split, useS, useSplitUserState } from '@cloudbeaver/core-blocks'; +import { getComputed, Loader, Pane, ResizerControls, s, Split, useExecutor, useS, useSplitUserState } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { LeftBarPanelService, SideBarPanel, SideBarPanelService } from '@cloudbeaver/core-ui'; @@ -25,6 +25,17 @@ export const Main = observer(function Main() { const sideBarDisabled = getComputed(() => sideBarPanelService.tabsContainer.getDisplayed().length === 0); const leftBarDisabled = getComputed(() => leftBarPanelService.tabsContainer.getDisplayed().length === 0); + useExecutor({ + executor: sideBarPanelService.tabsContainer.onTabSelect, + handlers: [ + function showPanel() { + if (splitRightState.mode === 'minimize' && !sideBarDisabled) { + splitRightState.onModeChange?.('resize'); + } + }, + ], + }); + return (
diff --git a/webapp/packages/core-ui/src/SideBarPanel/SideBarPanel.tsx b/webapp/packages/core-ui/src/SideBarPanel/SideBarPanel.tsx index e85440821a..d44dc9fbf3 100644 --- a/webapp/packages/core-ui/src/SideBarPanel/SideBarPanel.tsx +++ b/webapp/packages/core-ui/src/SideBarPanel/SideBarPanel.tsx @@ -42,10 +42,9 @@ const sideBarPanelRegistry: StyleRegistry = [ export const SideBarPanel = observer(function SideBarPanel({ container }) { const style = useS(styles); - return ( - + container.select(tab.tabId, tab.props)}>
diff --git a/webapp/packages/core-ui/src/Tabs/TabsContainer/TabsContainer.ts b/webapp/packages/core-ui/src/Tabs/TabsContainer/TabsContainer.ts index ba2b03c6d8..d74ac35a1f 100644 --- a/webapp/packages/core-ui/src/Tabs/TabsContainer/TabsContainer.ts +++ b/webapp/packages/core-ui/src/Tabs/TabsContainer/TabsContainer.ts @@ -8,12 +8,14 @@ import { makeObservable, observable } from 'mobx'; import type { MetadataMap, MetadataValueGetter, schema } from '@cloudbeaver/core-utils'; +import { SyncExecutor } from '@cloudbeaver/core-executor'; import type { ITabInfo, ITabInfoOptions, ITabsContainer } from './ITabsContainer.js'; export class TabsContainer | unknown = unknown> implements ITabsContainer { readonly areaLabel: string; readonly tabInfoMap: Map>; + readonly onTabSelect: SyncExecutor; get tabInfoList(): Array> { return Array.from(this.tabInfoMap.values()).sort((a, b) => a.order - b.order); @@ -29,6 +31,7 @@ export class TabsContainer | this.tabInfoMap = new Map(); this.currentTabId = null; this.areaLabel = areaLabel; + this.onTabSelect = new SyncExecutor(); makeObservable, 'currentTabId'>(this, { tabInfoMap: observable.shallow, @@ -58,6 +61,7 @@ export class TabsContainer | }); this.currentTabId = tabId; + this.onTabSelect.execute(tabId); } getTabInfo(tabId: string): ITabInfo | undefined { From 426fd40c820b9deb1bb75d4f0b4c48f9d2e96597 Mon Sep 17 00:00:00 2001 From: Ruslan Musaev <43766501+HocKu7@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:16:41 +0200 Subject: [PATCH 3/5] dbeaver/pro#6622 preference fixes after the demo (#3670) --- .../src/io/cloudbeaver/model/session/BaseWebSession.java | 8 ++++++++ .../src/io/cloudbeaver/model/user/WebUser.java | 4 ++++ .../events/WSSubjectPermissionUpdatedEventHandler.java | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java index d763f4b12d..40a1e84267 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java @@ -29,6 +29,7 @@ import org.jkiss.dbeaver.model.auth.SMAuthSpace; import org.jkiss.dbeaver.model.auth.SMSessionContext; import org.jkiss.dbeaver.model.auth.impl.AbstractSessionPersistent; import org.jkiss.dbeaver.model.meta.Property; +import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.websocket.event.WSEvent; import org.jkiss.dbeaver.model.websocket.event.WSEventDeleteTempFile; import org.jkiss.dbeaver.model.websocket.event.session.WSSessionExpiredEvent; @@ -36,6 +37,7 @@ import org.jkiss.dbeaver.model.websocket.event.session.WSSessionExpiredEvent; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -122,6 +124,12 @@ public abstract class BaseWebSession extends AbstractSessionPersistent { userContext.refreshPermissions(); if (userContext.isAuthorizedInSecurityManager()) { userContext.refreshAccessibleProjects(); + if (userContext.getUser() != null) { + List userTeamIds = Arrays.stream(userContext.getSecurityController().getCurrentUserTeams()) + .map(SMTeam::getTeamId) + .toList(); + userContext.getUser().setTeams(userTeamIds.toArray(new String[0])); + } } } catch (DBException e) { addSessionError(e); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java index a41c5aa21e..4297584009 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java @@ -77,6 +77,10 @@ public class WebUser { return user.getUserTeams(); } + public void setTeams(@NotNull String[] teams) { + user.setUserTeams(teams); + } + @Override public int hashCode() { return user.getUserId().hashCode(); diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java index 513b4eca5b..c742bb976e 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java @@ -40,7 +40,6 @@ public class WSSubjectPermissionUpdatedEventHandler extends WSDefaultEventHandle activeUserSession.addSessionError(e); log.error("Error refreshing session", e); } - activeUserSession.refreshUserData(); var newUserPermissions = activeUserSession.getUserContext().getUserPermissions(); boolean shouldUpdateData = activeUserSession instanceof WebHeadlessSession || !(SMUtils.isRMAdmin(oldUserPermissions) && SMUtils.isRMAdmin(newUserPermissions)); @@ -54,6 +53,7 @@ public class WSSubjectPermissionUpdatedEventHandler extends WSDefaultEventHandle if (!super.isAcceptableInSession(activeUserSession, event)) { return false; } + activeUserSession.refreshUserData(); var user = activeUserSession.getUserContext().getUser(); if (user == null) { return false; From 8a4d88e721fba2a26c68aa9c0d514fbdf71ae75c Mon Sep 17 00:00:00 2001 From: Alexander Skoblikov Date: Wed, 20 Aug 2025 13:33:11 +0300 Subject: [PATCH 4/5] dbeaver/pro#6622 preference fixes after the demo (#3670) revert (#3679) This reverts commit 426fd40c820b9deb1bb75d4f0b4c48f9d2e96597. --- .../src/io/cloudbeaver/model/session/BaseWebSession.java | 8 -------- .../src/io/cloudbeaver/model/user/WebUser.java | 4 ---- .../events/WSSubjectPermissionUpdatedEventHandler.java | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java index 40a1e84267..d763f4b12d 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/BaseWebSession.java @@ -29,7 +29,6 @@ import org.jkiss.dbeaver.model.auth.SMAuthSpace; import org.jkiss.dbeaver.model.auth.SMSessionContext; import org.jkiss.dbeaver.model.auth.impl.AbstractSessionPersistent; import org.jkiss.dbeaver.model.meta.Property; -import org.jkiss.dbeaver.model.security.user.SMTeam; import org.jkiss.dbeaver.model.websocket.event.WSEvent; import org.jkiss.dbeaver.model.websocket.event.WSEventDeleteTempFile; import org.jkiss.dbeaver.model.websocket.event.session.WSSessionExpiredEvent; @@ -37,7 +36,6 @@ import org.jkiss.dbeaver.model.websocket.event.session.WSSessionExpiredEvent; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; -import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -124,12 +122,6 @@ public abstract class BaseWebSession extends AbstractSessionPersistent { userContext.refreshPermissions(); if (userContext.isAuthorizedInSecurityManager()) { userContext.refreshAccessibleProjects(); - if (userContext.getUser() != null) { - List userTeamIds = Arrays.stream(userContext.getSecurityController().getCurrentUserTeams()) - .map(SMTeam::getTeamId) - .toList(); - userContext.getUser().setTeams(userTeamIds.toArray(new String[0])); - } } } catch (DBException e) { addSessionError(e); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java index 4297584009..a41c5aa21e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/user/WebUser.java @@ -77,10 +77,6 @@ public class WebUser { return user.getUserTeams(); } - public void setTeams(@NotNull String[] teams) { - user.setUserTeams(teams); - } - @Override public int hashCode() { return user.getUserId().hashCode(); diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java index c742bb976e..513b4eca5b 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/events/WSSubjectPermissionUpdatedEventHandler.java @@ -40,6 +40,7 @@ public class WSSubjectPermissionUpdatedEventHandler extends WSDefaultEventHandle activeUserSession.addSessionError(e); log.error("Error refreshing session", e); } + activeUserSession.refreshUserData(); var newUserPermissions = activeUserSession.getUserContext().getUserPermissions(); boolean shouldUpdateData = activeUserSession instanceof WebHeadlessSession || !(SMUtils.isRMAdmin(oldUserPermissions) && SMUtils.isRMAdmin(newUserPermissions)); @@ -53,7 +54,6 @@ public class WSSubjectPermissionUpdatedEventHandler extends WSDefaultEventHandle if (!super.isAcceptableInSession(activeUserSession, event)) { return false; } - activeUserSession.refreshUserData(); var user = activeUserSession.getUserContext().getUser(); if (user == null) { return false; From 55c776f3e41f683cf287b5c8c3be0895f89010e8 Mon Sep 17 00:00:00 2001 From: Ruslan Musaev <43766501+HocKu7@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:38:55 +0200 Subject: [PATCH 5/5] dbeaver/pro#6326 fixes (#3674) --- .../src/io/cloudbeaver/model/apilog/ApiCallInterceptor.java | 1 + .../src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java | 2 +- .../src/io/cloudbeaver/service/WebServiceServletBase.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/apilog/ApiCallInterceptor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/apilog/ApiCallInterceptor.java index 40a74c7eeb..f323842090 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/apilog/ApiCallInterceptor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/apilog/ApiCallInterceptor.java @@ -37,6 +37,7 @@ public interface ApiCallInterceptor { @NotNull HttpServletRequest request, @Nullable Map variables, @NotNull String apiCall, + @Nullable String userId, @NotNull LocalDateTime startTime, @Nullable String errorMessage, @NotNull String apiProtocol diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java index 49f19c97bb..ca011b8bb7 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java @@ -271,7 +271,7 @@ public class GraphQLEndpoint extends HttpServlet { errorMessage = executionException.getMessage(); } if (WebAppUtils.getWebApplication() instanceof ApiCallInterceptor apiCallInterceptor) { - apiCallInterceptor.onApiCallEvent(request, variables, operationName, startTime, errorMessage, API_PROTOCOL); + apiCallInterceptor.onApiCallEvent(request, variables, operationName, userId, startTime, errorMessage, API_PROTOCOL); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java index 8fbd1b8888..a7709f7db2 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java @@ -75,7 +75,7 @@ public abstract class WebServiceServletBase extends HttpServlet { } finally { if (WebAppUtils.getWebApplication() instanceof ApiCallInterceptor apiCallInterceptor) { apiCallInterceptor.onApiCallEvent( - request, getVariables(request), request.getRequestURI(), startTime, errorMessage, API_PROTOCOL + request, getVariables(request), request.getRequestURI(), null, startTime, errorMessage, API_PROTOCOL ); } }