Compare commits

...
Author SHA1 Message Date
Alexander Skoblikovandkseniaguzeeva d7ded85ff0 dbeaver/pro#9508 use proto header without host (#4379)
* dbeaver/pro#9508 use proto header without host

* dbeaver/pro#9508 review fixes

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2026-06-10 09:17:54 +02:00
Ainur 6364581b5b dbeaver/pro#9511 fix unknown struct presentation 2026-06-04 14:37:41 +02:00
Serge Rider bfcc7764d8 Merge branch 'release_26_1_0' of https://github.com/dbeaver/cloudbeaver into release_26_1_0 2026-06-04 14:37:35 +02:00
Sychev Andrey 798adb4787 dbeaver/pro#9438 fix: fix the export lib version (#4369) (#4372)
* dbeaver/pro#9438 fix: fix the export lib version

* dbeaver/pro#9438 fix: update modern-screenshot dependency to version 4.6.8
2026-06-01 15:10:59 +02:00
Ainur 211ca65acb dbeaver/pro#9447 validate project path fix (#4367)
* dbeaver/pro#9447 validate project path fix

* dbeaver/pro#9447 validate project name on creating project

* dbeaver/pro#9447 validate project using general utils
2026-05-29 10:27:42 +02:00
Sychev AndreyandEvgenia 4c71bd6005 dbeaver/pro#9407 fix: long values wrapping (#4364)
we mimic here the old input's behaviour, when we can't see the scroll but can navigate through the 1-line value with keyboard or mouse drag/selection

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-27 20:38:46 +02:00
Serge Riderandkseniaguzeeva 74a5877e6d dbeaver/pro#9397 Initialize datasource registry flow fix (#4360)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2026-05-26 17:47:26 +02:00
sergeyteleshevandEvgenia 961430f988 [CB] Menu is displayed under opened forms in the Administration page (#4358)
* dbeaver/pro#9362 fixes z-indexes issues for dialogs and notifications

* moves getPersistentElements to dialog level so all dialogs can handle it

* adds data-dialog-persistent-notification

* fixes resize controls layering

* fixes issue with panel buttons layering

* cleanup

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-25 17:53:03 +02:00
759b30a24b dbeaver/pro#9182 remove global secret controller for server apps (#4340)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-05-25 17:52:50 +02:00
Sychev AndreyandEvgenia 225ce91fd7 dbeaver/pro#8486 feat: add DataReadonlyReason API for data sources (#4354)
* dbeaver/pro#8486 feat: add DataReadonlyReason API for data sources

Previously TableStatusIndicator relied on model.isReadonly() which lost reasons. This caused the "Read-only connection" tooltip to show in grouping panel even on
editable connections — the connection wasn't read-only, the
presentation was.

Each data source now declares its specific reason via getReadonlyReason(). UI maps the typed reason to an accurate
message

* dbeaver/pro#8486 refactor: remove DataReadonlyReason references and use hasFeature flag

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-25 12:36:20 +02:00
f7bdd80e9f dbeaver/pro#9131 use visual keys for copy & paste (#4350)
Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-22 16:55:18 +02:00
sergeyteleshevandDaria Marutkina e42d34ac58 [CB] Ability to add a new MCP agent (#4329)
* dbeaver/pro#9126 initial commit for PR message

* adds validations

* adds json linter

* reverts safeParseSchema

* removes reset button

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-22 10:11:59 +02:00
sergeyteleshevandDaria Marutkina 89a1af2df9 [CB] Fix table spacing regression in admin UI (#4353)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-21 19:49:34 +02:00
sergeyteleshevandDaria Marutkina e4260b4cd2 [CB] API token generation dropdown doesn't fit to the island (#4351)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-21 19:47:45 +02:00
AinurandEvgenia 956ebaa515 dbeaver/pro#9306 disconnect event send fix (#4356)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-21 19:45:55 +02:00
alexandDaria Marutkina bccf47020e dbeaver/pro#9095 load active connections before checking execution context (#4355)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-21 18:22:42 +02:00
alexandEvgenia dcd2b608ea dbeaver/pro#9370 check all passwords, not only the first one (#4357)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-21 18:20:29 +02:00
84af14d2f7 Closes dbeaver/pro#9327 Extract LibSQL driver from build (#4344)
* Closes dbeaver/pro#9327 Extract LibSQL driver from build

* dbeaver/pro#9327 load libsql from maven for cloudbeaver ce

---------

Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-21 14:52:16 +02:00
sergeyteleshevandEvgenia f513f7dc44 [CB] Many warnings in the console when creating a new connection (#4352)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-21 14:50:12 +02:00
Sychev AndreyandDaria Marutkina ffa7f730de dbeaver/pro#8741 fix: update container label visibility logic when no… (#4347)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-21 12:24:15 +02:00
Sychev AndreyandDaria Marutkina 694d3b241f dbeaver/pro#9342 build: update node version to 24.13.1 in CI workflows (#4349)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-20 21:38:49 +02:00
9c8f3c47e6 [CB] Add shortcut for the cell context menu in data and metadata editors (#4332)
* dbeaver/pro#8424 adds shortcut top open/close context menu for the data editor

* moves helper into parseHotkeys + simplifies it

* adds unit tests

* adds autoFocusOnShow prop to support backward compatibility

* dbeaver/pro#8424 use current state

* adds few test cases for the extra buttons pressed

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-20 16:38:03 +02:00
sergeyteleshev f918c9e25e dbeaver/pro#8621 hides upload button for viewers roles and for disabled edit setting in data editor (#4348) 2026-05-20 16:37:43 +02:00
b84031bb84 dbeaver/cloudbeaver#4138 feat: support inline editing of multi-line v… (#4341)
* dbeaver/cloudbeaver#4138 feat: support inline editing of multi-line values in data grid cells

- TextEditor: switch <input> to <textarea rows=1> so newlines are preserved when editing. Suppress the trailing insertLineBreak from the Enter that opens the editor (would otherwise wipe the auto-selected value).
- ResultSetFormatAction.truncateText: substitute \n, \r, \r\n, \t with
  visible glyphs (↵, ␍, →) and collapse other control chars to a space
  in a single pass.

Perf note: the new replace should be faster than the prior
split('') + map + join. No intermediate array allocations, and the
callback runs only on matched chars (which are sparse in display text). \p{Cc} also expands coverage from charCode < 32 to include DEL and C1 controls (U+007F, U+0080–U+009F). (closer to Dbeaver behavior)

* dbeaver/pro#4138 feat: show raw text in title for text cells

* dbeaver/pro#4138 treat one cell differently

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
2026-05-20 14:28:08 +02:00
af651f9d10 dbeaver/pro#8459 trim username (#4343)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-19 19:00:53 +02:00
sergeyteleshevandDaria Marutkina 3245943f3d [CB] It is impossible to open edit forms from entity tables via keyboard (Users, Teams, Drivers, Providers, Secret Management) (#4345)
* dbeaver/pro#8404 adds onCellKeyDownTableOpen helper to all side modal tables

* replaces onKeyDown with Command

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-19 12:10:59 +02:00
Sychev AndreyandEvgenia fe01b23fce dbeaver/pro#9090 refactor: use new getters for sql execution plan (#4333)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-18 17:36:20 +02:00
alexandDaria Marutkina 8ec052e1b1 dbeaver/pro#9274 update whereFilter even if there is no result (#4336)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-18 13:48:51 +02:00
Daria Marutkina b10b407270 dbeaver/pro#9290 Update README file (#4346)
Added changelog for version 26.0.5, detailing new features, fixes, and updates across various components including authorization, data editor, SQL editor, database drivers, and security improvements.
2026-05-18 12:30:10 +02:00
alexandDaria Marutkina 5f5a6743eb dbeaver/pro#9133 use common GridSelectAction (#4342)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-18 11:22:26 +02:00
sergeyteleshev 4b30dc3ba5 [CB] Refresh of disconnected connection leads to 'Something went wrong' error (#4338)
* dbeaver/pro#8294 allows to refresh only connection root nodes for non-established connections

* renames variable

* checks if connection is connected to refresh it properly

* adds node check instead of connection directly
2026-05-15 13:27:33 +02:00
Ruslan Musaev 86e114d471 dbeaver/pro#9134 fix ldap error log (#4339) 2026-05-15 11:34:15 +02:00
dbeaver-devops d4d2e2d1fa dbeaver/pro#9290 26.1.0 version bump 2026-05-12 19:52:53 +02:00
6670cc81ae dbeaver/pro#7990 qmdb csv export (#4306)
* dbeaver/pro#7990 refactor: make onRemove prop optional in Tag component

* dbeaver/pro#7990 feat: add postForBlob helper function for using with export qm history servlets

* dbeaver/pro#7990 feat: replace postForBlob with submitForm for form submissions

Co-authored-by: Copilot <copilot@github.com>

* dbeaver/pro#7990 tests: add tests for submitForm and objectToFormFields functions

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-12 17:45:59 +02:00
f8a107256b 9089 core optimize command line execution (#4317)
* dbeaver/pro#9089 wip

* dbeaver/pro#9089 optimize cli execution

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: Anton Radchenko <34737043+RadAnton@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-12 15:30:41 +02:00
4f796e5f9c [CB] Add Ask AI Feature for the Execution Plan (#4326)
* dbeaver/pro#9046 adds vertical tabs for execution plan to add more space for new button or panel with buttons

* adds ask AI feature for execution plan

* removes editor id and uses context state

* makes ai feature spotlighted in the ui

* rotates the icon also

* removes bold label

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-12 13:28:50 +02:00
fb6f3c8246 Dbeaver/cloudbeaver#4120 support token header (#4259)
* dbeaver/cloudbeaver#4120 support token header

* dbeaver/cloudbeaver#4120 support token header

* dbeaver/cloudbeaver#4120 support token header

* dbeaver/cloudbeaver#4120 support token header

* dbeaver/cloudbeaver#4120 support token header

* dbeaver/cloudbeaver#4120 support token header

* dbeaver/cloudbeaver#4120 support token header

* dbeaver/pro#4120 added tests, now session in session holder

* dbeaver/pro#4120 review fix naming

* dbeaver/pro#4120 review fixes

* dbeaver/cloudbeaver#4120 review fixes

* dbeaver/cloudbeaver#4120 session type now final

* dbeaver/cloudbeaver#4120 remove part from ce

* dbeaver/cloudbeaver#4120 remove part from ce

* dbeaver/cloudbeaver#4120 fix header name

* dbeaver/cloudbeaver#4120 review fix

* dbeaver/cloudbeaver#4120 review fix

* dbeaver/cloudbeaver#4120 fix review

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-11 16:15:39 +02:00
sergeyteleshev f3eaed955f [CB] Add ability to interrupt connection establishment (front-end) (#4321)
* dbeaver/pro#8810 adds cancel action for auth via link

* lint fix + handles edge case when no popup appeared

* reverts eslint fix

* adds synchronization to connection init with oauth cancelling to remove stuck loading state

* reverts abort logic

* removes onAuthCancelled
2026-05-11 16:14:13 +02:00
339f19ff24 dbeaver/pro#9096 add ability for restricting ssh connections (#4320)
* dbeaver/pro#9096 add ability for restricting ssh connections

* dbeaver/pro#9096 validate ssh tunnelling for te desktop

* dbeaver/pro#9096 remove unused constant

* dbeaver/pro#9096 show alert if ssh is disabled

* Revert "dbeaver/pro#9096 show alert if ssh is disabled"

This reverts commit cce94063b0.

* dbeaver/pro#9096 do not show ssh for TE product

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
2026-05-11 15:52:51 +02:00
Dmitrii BarnukovandDaria Marutkina 0229ed1327 dbeaver/pro#9241 updated postgres to 42.7.11 (#4330)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-09 06:57:13 +02:00
sergeyteleshevandDaria Marutkina 6a6c29f38e [CB] Auth form - change display of saved secrets from placeholder to asterisks (#4327)
* dbeaver/pro#8416 adds masks for connection fields with password

* adds placeholder for password with mask

* Revert "dbeaver/pro#8416 adds masks for connection fields with password"

This reverts commit 4f89c46207.

* keeps old translation for file

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-08 17:39:55 +02:00
Serge Rider c3054c1f26 Merge remote-tracking branch 'origin/devel' into devel 2026-05-08 17:22:46 +02:00
Serge Rider 20b129d5a2 Revert "dbeaver/cloudbeaver#4249 added session rotation (#4274)"
This reverts commit d79054a5d8.
2026-05-08 17:21:40 +02:00
alexandkseniaguzeeva a08b9c2f2b dbeaver/pro#9030 remove dead links (#4322)
* dbeaver/pro#9030 remove dead links

* dbeaver/pro#9030 show support only in administration part

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2026-05-08 12:16:29 +02:00
sergeyteleshev 3a250e2e7a dbeaver/pro#9239 fixes top bar so it doesn't overlap the context menu (#4328) 2026-05-07 17:39:51 +02:00
alexandEvgenia 951b51b403 dbeaver/pro#9132 use closest instead of current (#4325)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-07 17:39:22 +02:00
72fcd7bfe2 [CB] Bump NPM dependencies (#4270)
* dbeaver/pro#8943 updates yarn locks

* updates vite

* updates vite-plugin-svgr

* removes CVEs

* reverts vite to update it later

* updates yarn lock

* updates yarn lock

* updates uuid

* removes axios CVE

* reverts @codemirror/search in order to fix the issue with replace 1 symbol (broken focus next)

* locks versions of other codemirror packages in order to keep versions consistent

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-05-07 11:25:25 +02:00
Dmitrii Barnukov 9ea3de9edf dbeaver/pro#9049 update oauth description (#4323) 2026-05-06 17:10:24 +02:00
sergeyteleshevandEvgenia 729d47fda1 [CB] SQL Query generation: Add the CREATE option for tables (#4316)
* dbeaver/pro#8327 adds CREATE menu item for result set generate SQL menu

* renames create to DDL

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-05 19:12:51 +02:00
Sychev AndreyandEvgenia ebda152b6b dbeaver/pro#9156 build: update packageManager version to yarn@4.14.1 … (#4309)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-05 16:09:30 +02:00
sergeyteleshevandEvgenia 430ae8e5cc [CB-6208] Dropdown is in front of the modal window (#4312)
* dbeaver/pro#5172 adds ui kit popover context with portal in order to reduce popover overlays

* makes menu to be under the dialog's backdrop

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-05 13:33:56 +02:00
sergeyteleshevandDaria Marutkina 97c12d026b dbeaver/pro#8750 adds fields length to the team for input fields (#4315)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-05 12:12:48 +02:00
Serge Rider ea0997d3b0 Merge remote-tracking branch 'origin/devel' into devel 2026-05-04 14:37:12 +02:00
Ainurandkseniaguzeeva 04a2eed596 dbeaver/pro#8724 save agreement id in app config (#4308)
* dbeaver/pro#8724 save agreement id in app config

* dbeaver/pro#8724 fix sending info to marketplace

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2026-05-04 14:35:08 +02:00
10d8741403 Make manifest.webmanifest dynamic based on CLOUDBEAVER_ROOT_URI dbeaver/cloudbeaver#4074 (#4293)
This PR implements dynamic generation of the manifest.webmanifest file to respect the CLOUDBEAVER_ROOT_URI environment variable configuration. Previously, the manifest was a static file with hardcoded values that didn't adapt to custom ro
ot URI configurations.

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-05-04 14:34:03 +02:00
Serge Rider ded139584c Merge remote-tracking branch 'origin/devel' into devel 2026-05-04 14:33:52 +02:00
alexandEvgenia 04b3bd9e2b dbeaver/pro#9073 rearrange context items (#4307)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-05-04 12:26:54 +02:00
Daria Marutkina 9303f4dacf dbeaver/pro#9160 Update README file (#4319)
Added changelog for version 26.0.4, detailing new features, improvements, and security updates.
2026-05-04 10:32:57 +02:00
Serge Rider 7b258d7ba6 Merge remote-tracking branch 'origin/devel' into devel 2026-05-04 10:22:22 +02:00
Serge Rider 76c2d4b7fe dbeaver/pro#9197 Data editor annotations (#4314) 2026-05-01 10:39:24 +02:00
Serge Rider 61d0c43bd2 dbeaver/pro#9202 GQL logging fix (#4318) 2026-05-01 10:34:43 +02:00
Serge Rider 0c07a5cd09 dbeaver/pro#9197 Data editor annotations 2026-04-30 14:09:07 +02:00
dbeaver-devops 3dcae7063c dbeaver/pro#9160 26.0.5 version bump 2026-04-28 19:32:51 +02:00
alexandEvgenia 635d2f8d7f dbeaver/pro#8473 add function confirmation (#4301)
* dbeaver/pro#8473 add function confirmation

* dbeaver/pro#8473 pass class to inner

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-28 18:37:01 +02:00
Dmitrii BarnukovandEvgenia cea06eecae dbeaver/pro#9047 added sql plan explain to CB (#4302)
* dbeaver/pro#9047 added sql plan explain to CB

* dbeaver/pro#9047 added nullability annotations

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-28 15:15:57 +02:00
ElizabethandDiana 0e402cd27d dbeaver/pro#8775 Introduce value path to getCellValue method (#4304)
Co-authored-by: Diana <31996417+uslss@users.noreply.github.com>
2026-04-28 15:12:38 +02:00
Dmitrii BarnukovandEvgenia d79054a5d8 dbeaver/cloudbeaver#4249 added session rotation (#4274)
* dbeaver/cloudbeaver#4249 added session rotation

* dbeaver/pro#4249 update web session id

* dbeaver/pro#4249 remove log

* dbeaver/pro#4249 remove unused params

* dbeaver/pro#4249 revert non-related changes

* dbeaver/cloudbeaver#4249 rotate session before login

* dbeaver/cloudbeaver#4249 fix code style

* dbeaver/cloudbeaver#4249 rotate only for anon users

* dbeaver/cloudbeaver#4249 added notnulls

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-28 12:32:41 +02:00
0903025942 [CB] SQL Query generation: add settings for the Generated SQL window (#4275)
* dbeaver/pro#8716 added generate sql options

* dbeaver/pro#8328 adds settings to generate sql dialog

* fixes error message

* removes refresh btn and settings title + notification

* dbeaver/pro#8328 add generator options

* show button "open in sql editor" for all sql generation popups

* adds regenerate query method for different context call

* cleanup

* pr fixes

* adds action.bound

* adds delayed loader

---------

Co-authored-by: Dmitrii <dmitrii.barnukov@dbeaver.com>
Co-authored-by: Dmitrii Barnukov <29237913+Nexus6v2@users.noreply.github.com>
Co-authored-by: Ruslan <pupkinvasya7000@gmail.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Nikita Akilov <26031301+flambchap@users.noreply.github.com>
2026-04-28 07:52:24 +02:00
b36b11008f dbeaver/pro#8978 paste multiple values (#4299)
* dbeaver/pro#8978 paste multiple values

* dbeaver/pro#8978 do not use bound on fn method

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-27 17:30:14 +02:00
f8acdb58af dbeaver/pro#8107 [CB] increase the contrast of some elements (#4300)
* dbeaver/pro#8107 fix: caption contrast in disabled checkbox

* dbeaver/pro#8107 fix: contrast for NULL formatter element

* dbeaver/pro#8107 fix: update color for blob formatter to enhance contrast

* dbeaver/pro#8107 fix: enhance contrast for theme elements in dark mode

* dbeaver/pro#8107 fix: update title color for improved contrast

* dbeaver/pro#8107 fix: enhance button secondary colors for improved contrast

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-27 14:04:38 +02:00
Sychev AndreyandCopilot 4e4292376e dbeaver/pro#8961 fix: make checkboxes clickable in main toolbar dropdown menu (#4303)
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 09:22:44 +02:00
serge-rider d5860dc9e8 dbeaver/pro#9005 Optimize manifests 2026-04-25 17:09:19 +02:00
Ruslan Musaev 5301adaed4 dbeaver/pro#5680 removed swagger deps for rest api documentation (#4282) 2026-04-24 16:31:12 +02:00
Serge Rider fc9ef33e1d Merge remote-tracking branch 'origin/devel' into devel 2026-04-22 16:38:10 +02:00
Serge Rider 2a8f34682f dbeaver/pro#9005 Driver provider model 2026-04-22 16:37:33 +02:00
9c6f301fa9 dbeaver/pro#7562 [CB] keep data editor filter state during session (#4261)
* dbeaver/pro#7562 feat: persist data editor filter state after reconnect

* dbeaver/pro#7562 feat: update data viewer to persist filter state

* dbeaver/pro#7562 feat: enhance constraint resolution in WebSQLDataFilter

allow using attrName without attrPosition

* dbeaver/pro#7562 refactor: don't use options

replaced private restorePendingState()  with public restoreViewState(pinnedColumnNames, columnOrderNames?) that takes data directly as arguments

* dbeaver/pro#7562 fix: stale constraints in UI

bug with skipping constraints if any without a position.
if (!prevColumn) {
        return;
      }

* dbeaver/pro#7562 refactor: add method to retrieve pinned column names in GridViewAction

* dbeaver/pro#7562 refactor: simplify state validation using schema

* dbeaver/pro#7562 refactor: simplify state management in useDataViewerPanel

* dbeaver/pro#7562 refactor: move persisted state to IDataViewerPageState

* dbeaver/pro#7562 fix: initial pageState

* dbeaver/pro#7562 refactor: simplify getPinnedColumnNames method in GridViewAction

* dbeaver/pro#7562 refactor: shadowed column renamed to c for clarity

* dbeaver/pro#7562 refactor: change type of value in IPersistedConstraint to unknown

* dbeaver/pro#7562 refactor: remove manual state operations

* dbeaver/pro#7562 refactor: introduce DatabasePersistedStateAction for centralized state persistence

* dbeaver/pro#7562 fix

* dbeaver/pro#7562 refactor: replace reaction with when

* Revert "dbeaver/pro#7562 feat: enhance constraint resolution in WebSQLDataFilter"

This reverts commit 3e0e86f4b2.

Last test showed that we don't need any additional logic on BE. It handles all constraints properly.

* dbeaver/pro#7562 fix: make pinColumns optional

* dbeaver/pro#7562 refactor: simplify pinned column handling

* dbeaver/pro#7562 refactor: initialize store in DatabasePersistedStateAction constructor as observable

* dbeaver/pro#7562 refactor: rename getColumnNameByPosition to getColumnNameAt for clarity

* dbeaver/pro#7562 refactor: move DatabasePersistedStateAction to source level, simplify persisted state sync

- Make DatabasePersistedStateAction a standalone class on DatabaseDataSource instead of per-result action
- Convert options to getter
- Auto-sync constraints to persisted state via autorun + action batching
- Restore view state (pinned columns, column order) in GridViewAction constructor

* dbeaver/pro#7562 refactor: replace DatabasePersistedStateAction with DatabasePersistedStateStore and update related references

* dbeaver/pro#7562 refactor: simplify view-state persistence

- DatabasePersistedStateStore: pure KV (observable.ref + actions)
- DatabaseDataSource: add loadPersistedState() + onPersistedStateLoaded() hook
- DatabaseDataConstraintAction: own the constraint persist
- ResultSetDataSource: thin dispatcher
- GridViewAction: columnsOrder/pinnedColumns become computed getters

* dbeaver/pro#7562 refactor: create universal ColumnReference

* dbeaver/pro#7562 refactor: simplify persistence flow, remove extra guards, simplify persisted data filter state handling

* dbeaver/pro#7562 refactor: simplify GridViewAction column-ref handling and layout resolution

* dbeaver/pro#7562 refactor: per-key reactive persisted state store, drop constraint persistence hacks

* dbeaver/pro#7562 refactor: simplify setOptions method to use superclass implementation

* dbeaver/pro#7562 add missing fields

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
2026-04-22 14:52:59 +02:00
sergeyteleshev a2ccd0b0f7 [CB] Support real tab characters in SQL Editor (#4298)
* dbeaver/pro#7864 adds tabulation with actual tab indent for code mirror

* adds EDITOR_INDENT_UNIT to unify indent for sql editor and vqb
2026-04-22 12:35:53 +02:00
acc3e42f1c dbeaver/pro#8352 do not unlink connection (#4278)
* dbeaver/pro#8352 do not unlink connection

* dbeaver/pro#8352 simplify logic

* dbeaver/pro#8352 add connection bar

* dbeaver/pro#8352 revert opened state

* dbeaver/pro#8352 do not fetch hints if not connected

* dbeaver/pro#8352 fix build

* dbeaver/pro#8352 move database icon to core package

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-04-22 12:32:58 +02:00
Sychev Andrey 075fa916f0 dbeaver/pro#8909 fix: collapsible side bar buttons are not visible wi… (#4297) 2026-04-22 11:47:33 +02:00
alexandDaria Marutkina f7b96db2de dbeaver/pro#8895 apply overflow to the grid root div (#4296)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-22 11:38:26 +02:00
alex dff9adaf34 dbeaver/pro#9084 update gql schema (#4294)
* dbeaver/pro#9084 update gql schema

* dbeaver/pro#9084 move fields
2026-04-21 10:24:25 +02:00
Ruslan Musaev 86c50a1557 dbeaver/pro#8711 sql execution plan improvements (#4287)
* dbeaver/pro#8711 sql execution plan improvements

* dbeaver/pro#8711 sql execution plan improvements
2026-04-20 17:38:43 +02:00
alexandDaria Marutkina 7d6c05f50c dbeaver/pro#8707 remove folder feature from ui (#4267)
* dbeaver/pro#8707 remove folder feature from ui

* dbeaver/pro#8707 remove folder tree ui for navigator

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-20 16:24:43 +02:00
Viktor Kirst 022778f95c dbeaver/pro#9061 Support custom lock manager id in servlet applications (#4291)
* dbeaver/pro#9061 Support custom lock manager id in servlet applications

* dbeaver/pro#9061 Remove unused metadata lock manager overload
2026-04-20 14:52:49 +02:00
Daria Marutkina d752d8ac26 dbeaver/pro#9037 Update README file (#4292)
Added changelog for version 26.0.3, detailing new features, fixes, and security updates.
2026-04-20 11:47:05 +02:00
serge-rider e1a029b238 dbeaver/pro#9060 Optimize manifest dependencies 2026-04-19 16:04:30 +02:00
Serge Rider 644dc2a136 dbeaver/pro#9048 CB NPE fix + QM deadlock fix (#4288) 2026-04-16 21:13:18 +02:00
Alexander Skoblikov 768fe00f6a dbeaver/pro#8839 remove referer (#4279) 2026-04-16 10:35:22 +02:00
dbeaver-devops 1e1f684379 dbeaver/pro#9037 26.0.4 version bump 2026-04-15 22:46:10 +02:00
alexandDaria Marutkina ac3ce9e085 dbeaver/pro#8728 add pricing policy (#4281)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-15 16:30:06 +02:00
Sychev AndreyandEvgenia 3cc9c3ce86 dbeaver/pro#8274 feat: add key icons for key columns in data editor (#4283)
* dbeaver/pro#8274 feat: add key icons for key columns in data editor

* dbeaver/pro#8274 feat: change key icon. put to core

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-15 16:29:02 +02:00
1660e62391 Save scripts to custom locations (use import/export buttons) (#4258)
* dbeaver/pro#7880 adds MVP for saving script to cloud storage

* removes registerScriptExportController

* finalizes the ui

* adds missing locales

* introduces footer slot to use CommonDialog api

* adds locales

* moves success message to the tab components itself

* pr small fixes

* saves file with timestamp

* send notification with correct filename

* fixes locales

* uses different approach for handling dialog save

* cleanup

* self review fixes

* adds lazy import for export dialog

* uses form API to save the dialog

* fixes imports (tab -> panel)

* uses react state for filename

* build fix

* handles form validation

* sanitizes file name

* removes redundant form layout

* fixes bug: allows to load tree root with useTreeData

* uses context api to resolve export script dialog instead of throwing errors approach

* dbeaver/pro#7880 do not show notification on local export

* dbeaver/pro#7880 remove notification from local export

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
2026-04-15 15:12:32 +02:00
Sychev AndreyandEvgenia c27fca442b dbeaver/pro#8687 fix(formatNumber): fix unit selection for floats and… (#4276)
- Use Math.log10 instead of toString().length to count integer digits — toString() on a float
  like 4036.29 has length 7, which incorrectly bucketed thousands-range values into millions
- Fix exponent formula for 3n-digit numbers (e.g. 100000 gave exponent=6→M instead of 3→k)
- Apply precision param d below 1000 (was hardcoded 2); default to 2
- Add formatNumber.test.ts

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-15 15:10:57 +02:00
318100300f Dbeaver/pro#8044 add api for database user preference (#4104)
* dbeaver/pro#8044 add api for database user preference

* dbeaver/pro#8044 set to prefstore

* dbeaver/pro#8044 add api for database user preference

* dbeaver/pro#8044 add api for database pref

* dbeaver/pro#8044 add api for database pref

* dbeaver/pro#8044 add api for database pref

* dbeaver/pro#8044 refactor api for database preferences

* dbeaver/pro#8044 refactor api for database preferences

* dbeaver/pro#8044 refactor api for database preferences

* dbeaver/pro#8044 add api for database user preference

* dbeaver/pro#8044 set to prefstore

* dbeaver/pro#8044 add api for database user preference

* dbeaver/pro#8044 add api for database pref

* dbeaver/pro#8044 add api for database pref

* dbeaver/pro#8044 add api for database pref

* dbeaver/pro#8044 refactor api for database preferences

* dbeaver/pro#8044 refactor api for database preferences

* dbeaver/pro#8044 refactor api for database preferences

* dbeaver/pro#8044 review fixes

* dbeaver/pro#8044 review fixes

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-04-15 13:57:51 +02:00
9c9e8e4496 dbeaver/pro#8716 added generate sql options (#4262)
* dbeaver/pro#8716 added generate sql options

* dbeaver/pro#8716 extract typed options

* dbeaver/pro#8716 added annotations

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-14 17:09:12 +02:00
alexandmr-anton-t 4789acb76a dbeaver/pro#8996 remove cve (#4280)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-04-14 13:08:55 +02:00
alexandmr-anton-t 39ad4568d0 dbeaver/pro#8962 add block padding to the menus (#4273)
* dbeaver/pro#8962 add block padding to the menus

* dbeaver/pro#8962 adjust padding size

* dbeaver/pro#8962 make inner radius smaller

* dbeaver/pro#8962 use separate tokens

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-04-13 17:15:02 +02:00
Serge Rider 860b8e2e16 dbeaver/pro#8559 Workbench launch redesign (#4277) 2026-04-10 20:16:35 +02:00
sergeyteleshevandDaria Marutkina 4b9ba00663 [CB] Multi-paste support in Data Editor (#4271)
* dbeaver/pro#8670 adds simple multiple paste for the selected cells

* cleanup

* moves logic to useGridSelectedCellsPaste

* cleanup

* adds getSelectedElementsWithFocused

* cleanup

* pr fixes

* adds readonly guard for paste cells

* adds check for is cell editable

* cleanup

* Revert "cleanup"

This reverts commit 309e254453.

* Revert "adds check for is cell editable"

This reverts commit 00b6b63cfa.

* allows to copy blobs base64 but forbids to paste to blob cell

* reuses isCellEditable

* fixes source

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-09 19:39:43 +02:00
MalteandDaria Marutkina 897dd994ba Pass arguments from entrypoint script (#4269)
* dbeaver/cloudbeaver#4268 fix order of arguments

This allows overriding the -web-config argument.

* dbeaver/cloudbeaver#4268 pass arguments to run-cloudbeaver-server.sh

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-09 19:39:21 +02:00
e81a150287 Dbeaver/pro#8655 cb ai functions support (#4254)
* dbeaver/pro#8655 added function confirmation and result events

* dbeaver/pro#8655 refactor action function processing

* dbeaver/pro#8655 support function role

* dbeaver/pro#8655 revert ai function changes

* Revert "dbeaver/pro#8655 support function role"

This reverts commit 7343af5e97.

* dbeaver/pro#8655 simplify types

* dbeaver/pro#8867 Add custom WS event handlers. Move AI-related function top pro.

* dbeaver/pro#8655 Remove async tasks from chat workflow

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: Serge Rider <serge@dbeaver.com>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
2026-04-09 19:38:15 +02:00
0d17208be4 dbeaver/pro#8746 add useQuery hook (#4241)
* dbeaver/pro#8746 add useQuery hook

* dbeaver/pro#8746 add language tokens

* dbeaver/pro#8746 set loading to false in case of abort

* dbeaver/pro#8746 use more advanced useQuery

* dbeaver/pro#8746 fix code style

* dbeaver/pro#8746 remove useQuery hook

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
2026-04-08 20:22:06 +02:00
9c1678c256 dbeaver/pro#8824 Inject lock manager into CloudBeaver RM controllers (#4242)
* dbeaver/pro#8824 Inject lock manager into CloudBeaver RM controllers

* dbeaver/pro#8824 Use application lock manager provider in servlet applications

* dbeaver/pro#8824 Use default application lock manager

* dbeaver/pro#8824 Fix codestyle warnings

---------

Co-authored-by: Daria Markaryan <43252954+DariaMarkaryan@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
2026-04-08 19:23:38 +02:00
Ainurandkseniaguzeeva 321d45bd48 dbeaver/pro#7912 support external oauth in te desktop (#4255)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2026-04-08 17:15:40 +02:00
alex 0f33fb5514 dbeaver/pro#4158 add special filter operators (#4264)
* dbeaver/pro#4158 add special filter operators

* dbeaver/pro#4158 rename arg
2026-04-08 13:15:13 +02:00
sergeyteleshevandDaria Marutkina e7648b1b4c [CB] Toggle switches are rendered incorrectly (#4272)
* dbeaver/pro#8946 adds specifity for dense switches

* wraps with field

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-04-08 13:04:34 +02:00
45cfded51f [CB] DB Navigator - add subgroup to context menu to reduce the list of actions (#4246)
* dbeaver/pro#8236 adds submenus for the connection tree

* adds disabled state for submenu with no items

* removes variable

* loads first menus then draws it

* reverts submenu fix

* splits manage handlers from root handlers

* removes loader for manage menu to prevent bug

* cleanup

* removes action leaks for tables

* removes leak of the action delete

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-04-08 11:06:12 +02:00
Ruslan Musaev 9822147d68 dbeaver/pro#8954 fix cloudbeaver driver properties (#4266) 2026-04-07 15:49:40 +02:00
Ruslan MusaevandEvgenia 3b0f52f3ed dbeaver/pro#5124 fix case-insensitive username in import (#4251)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-04-07 13:47:11 +02:00
Daria Marutkina 3b032a275d dbeaver/pro#8893 Update README file (#4263)
* dbeaver/pro#8893 Update README file

Added changelog entry for version 26.0.2 with UI improvements, authentication fixes, database updates, and security vulnerability resolutions.

* Update README.md
2026-04-06 11:17:33 +02:00
Sychev Andrey a11ca992fe dbeaver/pro#7251 feat: add skip navigation feature for improved acces… (#4245)
* dbeaver/pro#7251 feat: add skip navigation feature for improved accessibility

* dbeaver/pro#7251 refactor: replace direct import with lazy loading for SkipNavLinks and SkipNavShortcutsLink

* dbeaver/pro#7251 refactor: use css modules for skip nav styles

* dbeaver/pro#7251 refactor: remove SkipNavBootstrap
2026-04-06 10:59:22 +02:00
serge-rider 5138c73ae5 dbeaver/pro#8894 Fix object search + annotations 2026-04-03 15:28:05 +02:00
sergeyteleshevandmr-anton-t ea36247797 [CB] Replace material ui with native css variables and tailwind utilities (#4188)
* dbeaver/pro#8433 initial version of material ui refactor

* fixes arrow colors

* fixes arrow colors 2

* fixes colors

* pr fixes

* removes layers due to it loses styles specificity race

* fixes autocomplete styles

* adds variables for typography

* moves switch logic to module styles

* removes elevation styles

* removes unused code

* migrates ripple effect to tw class

* Revert "migrates ripple effect to tw class"

This reverts commit 78229ac007.

* uses classname theme-typography for button

* adds elevation styles

* adds elevation styles 2

* moves theme ripple

* reverts scss for sql editor

* reverts scss for sql editor 2

* adds tailwindcss utilities + example

* Revert "adds tailwindcss utilities + example"

This reverts commit 20ca1b787c.

* creates tailwindcss plugin with shadow tokens + spread it across the app

* moves typography to the tailwindcss styles

* refactors sql editor styles

* moves styles from tailwindcss folder to styles

* moves ripple to tailwindcss plugin

* removes unused files

* removes unused file index

* removes redundant tailwindcss import

* adds animation layer for tailwindcss

* refactors animations

* build fix

* removes redundant imports of tailwindcss for styles

* removes layer components to keep some styles for switch

* removes animation from ripple effect

* makes ripple effect more contrast

* fixes fonts across the app to json view has correct font-mono from the tailwindcss box

* deletes module ts

* Revert "removes layer components to keep some styles for switch"

This reverts commit ee8b0e199e.

* fixes race for switch bold style

* changes ripple from 7% to 9%

* Reduce hover opacity in ripple effect (#4260)

* Reduce hover opacity in ripple effect

* Update ripple.css

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-04-02 18:24:19 +02:00
Serge Rider a6a1916299 dbeaver/pro#8894 Fix tests 2026-04-02 16:09:06 +02:00
Viktor Kirst b8699e6bcb dbeaver/pro#8896 Fix driver description (#4257) 2026-04-02 16:01:58 +02:00
Serge Rider 8cff50b0cf dbeaver/pro#8894 Workspace dispose and session cleanup fixes (#4256)
* dbeaver/pro#8894 Workspace dispose and session cleanup fixes

* dbeaver/pro#8894 Fix session cleanup

* Revert "dbeaver/pro#8894 Fix session cleanup"

This reverts commit 170882f69d.

* dbeaver/pro#8894 Fix session cleanup
2026-04-02 11:54:52 +02:00
dbeaver-devops b06a96dc31 dbeaver/pro#8893 26.0.3 version bump 2026-03-31 23:17:03 +02:00
Viktor KirstandMashaKorax 446bd81e08 dbeaver/pro#8392 Add H2 2.4 JDBC driver (#4227)
* dbeaver/pro#8392 Add H2 2.4 JDBC driver

* dbeaver/pro#8392 Fixed h2 driver description

* dbeaver/pro#8392 Add H2 V.2.4 module

* dbeaver/pro#8392 Fixed module name

* dbeaver/pro#8392 Rename H2 v2.4 driver to v3

---------

Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2026-03-31 17:28:50 +02:00
Dmitrii Barnukov 09863ea260 dbeaver/pro#7963 extended openurl event, added client event (#4247)
* dbeaver/pro#7963 extended openurl event, added client event

* dbeaver/pro#7963 fix typo
2026-03-31 16:52:46 +02:00
sergeyteleshev 34b4556773 [CB] New and repeat passwords can be different (#4234)
* dbeaver/pro#8572 fixes password validity on blur

* Revert "dbeaver/pro#8572 fixes password validity on blur"

This reverts commit cefd174254.

* adds context to the form for correct validation + handles validation on change also to keep the actual validity state

* adds context check to prevent validation inconsistent behavior

* adds revalidate to handle depended validations cases

* adds useFormCustomInputValidation

* cleanup

* uses useFormCustomInputValidation to avoid regression after refactor
2026-03-31 14:07:47 +02:00
alexandmr-anton-t 9b4c874e51 dbeaver/pro#8805 do not move focus on programmatic tab select (#4248)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-03-31 14:00:57 +02:00
Serge Rider ddbc9789e7 Merge remote-tracking branch 'origin/devel' into devel 2026-03-30 16:43:02 +02:00
Serge Rider 810d0215cb dbeaver#40616 update sql server driver to 13.4.0 2026-03-30 16:42:39 +02:00
alexandEvgenia 3dadc17ff1 dbeaver/pro#8644 add temp icon for base sql tab (#4243)
* dbeaver/pro#8644 add temp icon for base sql tab

* dbeaver/pro#8644 replace old icons

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-03-30 12:20:27 +02:00
sergeyteleshevandEvgenia 8c69985083 dbeaver/pro#8518 adds message for string parameters (#4233)
* dbeaver/pro#8518 adds message for string parameters

* aligned message with dbeaver: "string values must be quoted"

* reverts branding and uses it optionally for bind parameters popup

* renames prop

* makes few versions of alert

* Revert "makes few versions of alert"

This reverts commit 5b9f09009e.

* adds gray message

* adds icon

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-03-27 19:04:39 +01:00
1d5b475482 dbeaver/pro#8553 sql execution plan diagram (#4218)
* dbeaver/pro#8553 feat: add execution plan diagram component

* dbeaver/pro#8553 feat: enhance ExecutionPlanDiagram component with selectedNodeId prop

* dbeaver/pro#8553 feat: add flex-shrink to metric value for better layout

* dbeaver/pro#8553 refactor: remove queryString from IPlanData interface

* dbeaver/pro#8553 feat: integrate execution plan diagram component

* dbeaver/pro#8553 refactor: execution plan diagram

separate state, add l10n, make toolbar composable

* dbeaver/pro#8553 feat: implement keyboard navigation for execution plan nodes

* dbeaver/pro#8553 feat: add translation support for execution plan diagram labels

* dbeaver/pro#8553 fix: execution plan node dimensions

* dbeaver/pro#8553 refactor: move formatNumber to helpers to use it

* dbeaver/pro#8553 feat: add translation support for execution plan diagram API

* dbeaver/pro#8553 docs: add README and API documentation for execution plan diagram component

* dbeaver/pro#8553 feat: adjust cost bar height and collapse indicator position

* dbeaver/pro#8553 feat: update PRIMARY_AXIS_WEIGHT for improved directional navigation

* dbeaver/pro#8553 feat: refactor diagram actions and add collapse state management

* dbeaver/pro#8553 refactor: move execution plan diagram to separate EE plugin

* dbeaver/pro#8553 docs: remove redundant comment

* dbeaver/pro#8553 docs: update comments for source and target anchors in ILayoutEdge interface

* dbeaver/pro#8553 docs: update comment in ILayoutNode interface

* dbeaver/pro#8553 refactor: simplify heavy route computation

* dbeaver/pro#8553 refactor: optimize node handling in computePlanLayout function

* dbeaver/pro#8553 refactor: improve tree structure handling in usePlanTree and buildTree functions

* dbeaver/pro#8553 refactor: simplify usePlanTree

* dbeaver/pro#8553 refactor: extract actions from useExecutionPlanDiagramState

* dbeaver/pro#8553 refactor: improve configuration in execution plan diagram

* dbeaver/pro#8553 refactor: simplify metric rendering in PlanNode component

* dbeaver/pro#8553 feat: collapse by hotkey, not an extra element

* dbeaver/pro#8553 feat: add tooltip hints for plan node interactions

* dbeaver/pro#8553 refactor: remove high cost calculation and add node kind attribute

* dbeaver/pro#8553 style: fix formatting in index.ts for ISqlExecutionPlanViewProps export

* dbeaver/pro#8553 ci: remove unused dependency on @dbeaver/ui-kit

* dbeaver/pro#8553 refactor: remove SQL execution plan diagram translations from locale files

* dbeaver/pro#8553 refactor: update translation keys for SQL execution plan components

* dbeaver/pro#8553 refactor: rename components

* dbeaver/pro#8553 style: const

* dbeaver/pro#8553 refactor: reset execution plan diagram state properties

* dbeaver/pro#8553 refactor: update component imports and extract a component

* dbeaver/pro#8553 refactor: rename PlanNodeKind to EPlanNodeKind and update references

* dbeaver/pro#8553 feat: add zoom icons and update action references

* dbeaver/pro#8553 refactor: enhance translation functionality by adding args interpolation

* dbeaver/pro#8553 fix: Polynomial regular expression used on uncontrolled data

* dbeaver/pro#8553 refactor: update ActionsCapture to use ref for toolbar actions

* dbeaver/pro#8553 refactor: use jsx

* dbeaver/pro#8553 refactor: simplify

* dbeaver/pro#8553 refactor: replace useContext with use in DiagramContext

* dbeaver/pro#8553 refactor: convert ExecutionPlanEdge to memoized component

* dbeaver/pro#8553 refactor: convert ExecutionPlanNode to memoized component

* dbeaver/pro#8553 refactor: unify ref prop in ExecutionPlanNode and ExecutionPlanViewport

* dbeaver/pro#8553 refactor: extract ExecutionPlanViewportContent component and clean up CSS

* dbeaver/pro#8553 refactor: convert ExecutionPlanNodeMetric to memoized component

* dbeaver/pro#8553 refactor: improve usePlanLayout hook by utilizing useEffectEvent for stable callback

* dbeaver/pro#8553 refactor: simplify diagram actions handling in createExecutionPlanDiagram

* dbeaver/pro#8553 refactor:  move out execution plan diagram component from

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
2026-03-27 16:07:31 +01:00
sergeyteleshev b779b9d855 [CB] Fix high CVE-2026-33671 in picomatch (#4244)
* dbeaver/pro#8836 fixes picomatch CVE

* fixes happy-dom CVE
2026-03-27 14:24:43 +01:00
Sychev Andrey df676913a0 dbeaver/pro#8808 feat: add shortcut for search in data viewer (#4239)
* dbeaver/pro#8808 feat: add shortcut for search in data viewer

* dbeaver/pro#8808 feat: update shortcut ID for search functionality
2026-03-27 14:22:14 +01:00
fab9d1dd43 dbeaver/pro#7806 remove MenuBarSmallItem (#4224)
* dbeaver/pro#7806 remove MenuBarSmallItem

* dbeaver/pro#7806 remove reakit

* dbeaver/pro#7806 remove extra class

* dbeaver/pro#7806 increase base padding and background color

* dbeaver/pro#7806 use more safe style

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-03-27 14:18:35 +01:00
36dfdc8b33 dbeaver/pro#8825 Add tests for translating SQL CREATE/ALTER TABLE sta… (#4237)
* dbeaver/pro#8825 Add tests for translating SQL CREATE/ALTER TABLE statements with ASCII columns

* dbeaver/pro#8825 improve script normalization

* dbeaver/pro#8825 Update `SQLQueryTranslatorTest` to include `NOT NULL` constraint for ASCII column validation

---------

Co-authored-by: Ivan Gagarkin <gagarkin@Ivans-MacBook-Pro.local>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-03-25 13:51:45 +01:00
Alexander Skoblikovandkseniaguzeeva 8b0a20cfd7 dbeaver/pro#8768 fix federated logout (#4230)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2026-03-25 08:22:55 +01:00
Sychev AndreyandEvgenia 9553c30ee5 dbeaver/pro#8739 feat: add isEnabled option to tree filter for enhanc… (#4236)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-03-24 19:26:36 +01:00
Sychev AndreyandDaria Marutkina 9c36651aa0 dbeaver/pro#8760 feat: set max width for search panel in SQL editor (#4231)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2026-03-24 16:44:14 +01:00
sergeyteleshev 24a251cd5b [CB] Fix high CVE-2026-33228 in flatted (2) (#4228) 2026-03-24 16:43:43 +01:00
alexandEvgenia a44ba89cd9 dbeaver/pro#8339 show array value as array (#4229)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-03-24 15:00:59 +01:00
44077ad27a dbeaver/pro#8260 Provide a method to create or restore a WebSession… (#4222)
* dbeaver/pro#8260 Provide a method to create or restore a `WebSession` from `smAccessToken`

* dbeaver/pro#8260 Annotations and constants

---------

Co-authored-by: Ivan Gagarkin <gagarkin@Ivans-MacBook-Pro.local>
Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: serge-rider <serge@dbeaver.com>
2026-03-24 10:56:19 +01:00
Dmitrii BarnukovandEvgenia 3ae74763ff dbeaver/pro#8635 added message description (#4220)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2026-03-23 16:42:49 +01:00
Daria Marutkina 45a63f70ee dbeaver/pro#8732 Update README file (#4232)
Added detailed changelog for version 26.0.1, including updates to Data Editor, SQL Editor, general improvements, driver updates, and security fixes.
2026-03-23 12:42:04 +01:00
1bafe29e99 dbeaver/pro#7696 feat: replace slide component with dialog for improv… (#4192)
* dbeaver/pro#7696 feat: replace slide component with dialog for improved UI interaction

* dbeaver/pro#7696 refactor: update persistent elements getter

* dbeaver/pro#7696 fix: notifications persistence

* dbeaver/pro#7696 fix: add min-width to container in RightArea and Administration CSS

* dbeaver/pro#7696 refactor: remove persist prop from SideBarPanel component

make SideBarPanel persist by default

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2026-03-19 18:11:31 +01:00
Dmitrii Barnukov 10ad601f8b dbeaver/pro#5562 revert hide password if not applicable (#4225) 2026-03-19 10:31:47 +01:00
592 changed files with 9178 additions and 6272 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ jobs:
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version: "24.13.1"
cache: "yarn"
cache-dependency-path: |
cloudbeaver/webapp/yarn.lock
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version: "24.13.1"
cache: "yarn"
cache-dependency-path: "./cloudbeaver/webapp/yarn.lock"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vscode-java-configs",
"packageManager": "yarn@4.9.2",
"packageManager": "yarn@4.14.1",
"devDependencies": {
"typescript": "^5.8.3"
}
+120
View File
@@ -25,6 +25,126 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
## Changelog
### 26.0.5 2026-05-18
- Authorization:
- Added HTTP header authentication support for GraphQL queries. Users can provide API tokens via Authorization or X-Api-Key headers, allowing external data tools to authenticate without modifying request bodies.
- Data Editor:
- Added a DDL generation option to the Data Editor and Result Set. Users can view table schemas directly while editing or reviewing records.
- Fixed the copying of Boolean values in the clipboard in the Data Editor.
- SQL Editor:
- Updated the SQL Editor to use real tab characters for indentation. The application displayed tabs as four-space gaps with a distinct visual marker.
- Added an ability to view and edit scripts without connecting to the database.
- Added more settings to the Generated SQL window, including the ability to select fully qualified names for query or use compact SQL formatting.
- Added the ability to open generated queries right from the Generate SQL window.
- General:
- Updated the manifest.webmanifest file to dynamically generate the environment variable according to the CLOUDBEAVER_ROOT_URI. (thanks to @houssemexo26 )
- Databases:
- PostgreSQL:
- Updated driver to version 42.7.11.
- Fixed missing INOUT parameters in CHECK generation for procedures and functions.
- Fixed handling of 24:xx values in time columns.
- Snowflake: Updated driver to version 4.1.0.
- SQL Server: Fixed the issue with connecting to the database after the Java update.
- Security:
- Added an administrative setting to restrict SSH tunneling capabilities. Administrators can now limit tunnel configuration to authorized users, reducing the risk of unauthorized network access.
- Fixed the high vulnerability (CVE-2026-42035) in the axios library. The library was updated to version 1.15.1.
- Fixed the medium vulnerability (CVE-2026-41305) in the postcss library. The library was updated to version 8.5.14.
### 26.0.4 2026-05-04
- Data Editor:
- Added the ability to copy-paste multiple cells at once. Pasted values will be distributed across separate cells, not put in a single cell.
- Data Editor started to keep the state of column configurations, such as filters, sorting, and ordering, after the reconnect, page refresh, and re-login.
- SQL Editor:
- Updated the SQL Editor to use real tab characters for indentation. The application displayed tabs as four-space gaps with a distinct visual marker.
- Added the ability to view and edit scripts without connecting to the database.
- Added more settings to the Generated SQL window, including the ability to select fully qualified names for query or use compact SQL formatting.
- Added the ability to open in the SQL Editor generated queries right from the Generate SQL window.
- Accessibility:
- Fixed contrast for elements across different application parts in the light and dark themes to meet WCAG requirements.
- General:
- Removed the "Folders" setting from the available settings for the Navigator Tree.
- Databases:
- DuckDB: Fixed map rendering for GEOMETRY types with CRS parameters.
- Firebird: Expanded database-specific SQL dialect coverage for the SQL Editor. Added more keywords, built-in functions, and SQL generators.
- MySQL: Fixed query boundaries recognition in the SQL Editor for scripts with the DELIMITER keyword.
- SQL Server: Fixed DDL generation for external tables.
- Security:
- Updated session handling to prompt the application to generate a new session identifier for each login.
- Fixed the high vulnerability (CVE-2026-3505) in the bcpg-jdk18on library. The library was updated to version 1.84.0.
### 26.0.3 2026-04-20
- Data Editor:
- Added key column mark for tables with unique keys in the data grid.
- Added the ability to paste a copied cell into multiple cells and to set multiple cells to NULL.
- Fixed the ability to calculate row count for non-standard SELECT statements. (thanks to @fdcastel)
- Navigator Tree:
- Reorganized the context menu on the connection level to make it more compact.
- Added support for special symbols (pipe, comma, and asterisk) for the search field.
- Accessibility:
- Added the Skip to content option for quick keyboard access to the Navigator Tree, editors, and shortcuts to improve application accessibility.
- General:
- SQL Editor: Fixed keyword autocompletion for partially typed keywords. There are no extra letters for them after completion.
- Added support for custom startup arguments when running CloudBeaver in a container. Administrators can specify configuration file locations to adapt the application to their environment. (thanks to @MalteHei)
- Fixed custom driver properties display for the connection page.
- Fixed data export in SQL format for values containing single quotes.
- Databases:
- ClickHouse: Fixed the display of Array(JSON) types in the data grid.
- Added support for the "prompt=false" connection property for DB2 for IBM i to turn off interactive prompts and prevent related errors.
- Security:
- Fixed the critical vulnerability (CVE-2025-62718) in the axios library. The library was updated to version 1.15.0.
- Fixed the high vulnerability (CVE-2026-4800) in the lodash library. The library was updated to version 4.18.0.
- Fixed the high vulnerability (CVE-2026-39363) in the vite library. The library was updated to version 7.3.2.
### 26.0.2 2026-04-06
- UI improvements:
- Marked icons for non-saved (temporary) scripts with the hourglass symbol to add visual distinction from the saved ones.
- Added the tooltip about quoting rules for the Bind variables parameters dialog.
- Improved keyboard navigation for context menu and buttons for Data Editor, SQL Editor, and Navigator tree.
- Authentication:
- Fixed the bug with the authentication form. Now the same password is required for the password change operation.
- Fixed the display of authentication fields for SQL Server with Active Directory - MSI. The unnecessary Password field was removed.
- Databases and drivers:
- DuckDB: Fixed geometry type display for database versions > 1.5. (thanks @EastLord).
- H2 database:
- Added new embedded driver version 2.4.2.
- Updated server driver to the version 2.4.2.
- Security:
- Fixed the high vulnerability (CVE-2026-33671) in the picomatch library. The library was updated to version 2.3.2.
- Fixed the high vulnerability (CVE-2026-33943) in the happy-dom library. The library was updated to version 20.8.8.
- Fixed the high vulnerability (CVE-2026-33228) in the flatted library. The library was updated to version 3.4.2.
### 26.0.1 2026-03-23
- Data Editor:
- Added the Find and Replace functionality for the Data Editor with the ability to find data by matching case, whole word, or using regular expressions.
- Added support for adding, duplicating, deleting, or setting values to NULL in multiple highlighted rows via the Data Editor context menu.
- SQL query generation in the Data Editor is now available for columns containing large object data.
- Improved column drag-and-drop behavior in the Data Editor. Users could drag columns from any area within the header and drop them onto any part of the target column or table body.
- SQL Editor:
- Added fuzzy search to SQL Editor auto-completion for object names. The feature allowed users to find tables and containers even with typos or incorrect letter ordering by matching strings that start with, contain, or resemble the input.
- Fixed data editing for SQL scripts with variables.
- General:
- Added a close button to the right tab when it is the only open tab (ex. Scripts). Users no longer needed to use the main menu to close a single tab.
- Replaced the generic "Something went wrong" message with a specific network error notification when the application cannot connect to the server.
- Null or empty values can now be assigned to the Driver properties for all drivers.
- Fixed an issue where re-selecting an existing SSH key file during connection edits caused problems.
- Fixed the ability to switch tabs in the Data editor using the keyboard.
- Fixed error notification spelling. Thanks to @Malcolm-B-Breaks.
- ClickHouse:
- Updated driver version to 0.9.7.
- Fixed IP address display in the Data Editor by removing the leading slash.
- PostgreSQL: Fixed an error when connecting via URL if the database name contains a hyphen.
- Security:
- Fixed the high vulnerability (CVE-2025-45141) in the tar library. The library was updated to version 7.5.11.
- Fixed the high vulnerability (CVE-2026-27148) in the storybook library. The library was updated to version 10.2.10.
- Fixed the high vulnerability (CVE-2026-27606) in the rollup library. The library was updated to version 4.59.0.
- Fixed the high vulnerability (CVE-2026-27904) in the minimatch library. The library was updated to version 3.1.3.
- Fixed the high vulnerability (CVE-2026-27959) in the koa library. The library was updated to version 2.16.4.
- Fixed the high vulnerability (CVE-2026-32141) in the flatted library. The library was updated to version 4.4.0.
### 26.0.0 2026-03-02
### Changes since 25.3.0:
-1
View File
@@ -18,7 +18,6 @@ cd ../..
echo "Pull dbeaver platform"
[ ! -d dbeaver ] && git clone --depth 1 https://github.com/dbeaver/dbeaver.git
[ ! -d dbeaver-common ] && git clone --depth 1 https://github.com/dbeaver/dbeaver-common.git
[ ! -d dbeaver-jdbc-libsql ] && git clone --depth 1 https://github.com/dbeaver/dbeaver-jdbc-libsql.git
cd cloudbeaver/deploy
-1
View File
@@ -20,7 +20,6 @@ echo Pull dbeaver platform
IF NOT EXIST dbeaver git clone https://github.com/dbeaver/dbeaver.git
IF NOT EXIST dbeaver-common git clone https://github.com/dbeaver/dbeaver-common.git
IF NOT EXIST dbeaver-jdbc-libsql git clone https://github.com/dbeaver/dbeaver-jdbc-libsql.git
cd cloudbeaver\deploy
+3 -3
View File
@@ -13,7 +13,7 @@ if [ "$(id -u)" -eq 0 ]; then
chown -R $DBEAVER_UID:$DBEAVER_GID $PWD/workspace
# Execute run-cloudbeaver-server.sh as the dbeaver user with the JAVA_HOME and PATH environment variables
exec su "$TARGET_USER" -c "JAVA_HOME=$JAVA_HOME PATH=$PATH ./run-cloudbeaver-server.sh"
exec su "$TARGET_USER" -c "JAVA_HOME=$JAVA_HOME PATH=$PATH ./run-cloudbeaver-server.sh $*"
else
exec ./run-cloudbeaver-server.sh
fi
exec ./run-cloudbeaver-server.sh "$@"
fi
+1 -1
View File
@@ -35,7 +35,7 @@ exec java ${JAVA_OPTS} \
--add-opens=java.sql/java.sql=ALL-UNNAMED \
-jar ${launcherJar} \
-product io.cloudbeaver.product.ce.product \
-web-config conf/cloudbeaver.conf \
"$@" \
-web-config conf/cloudbeaver.conf \
-nl en \
-registryMultiLanguage
-1
View File
@@ -1,3 +1,2 @@
dbeaver-common
dbeaver-jdbc-libsql
dbeaver
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Model
Bundle-SymbolicName: io.cloudbeaver.model.cli;singleton:=true
Bundle-Version: 1.0.7.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.11.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.jkiss.dbeaver.model.cli;visibility:=reexport
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.model.cli</artifactId>
<version>1.0.7-SNAPSHOT</version>
<version>1.0.11-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -22,8 +22,11 @@ import org.jkiss.dbeaver.model.cli.ApplicationCommandLine;
import org.jkiss.dbeaver.model.cli.ApplicationInstanceController;
import org.jkiss.dbeaver.model.cli.CLIContextImpl;
import org.jkiss.dbeaver.model.cli.CLIRunMeta;
import org.jkiss.dbeaver.model.cli.registry.CLICommandDescriptor;
import picocli.CommandLine;
import java.util.List;
public class CloudBeaverCommandLine extends ApplicationCommandLine<ApplicationInstanceController> {
private final CloudBeaverMixin mixin;
@@ -53,9 +56,10 @@ public class CloudBeaverCommandLine extends ApplicationCommandLine<ApplicationIn
protected CommandLine initCommandLine(
@Nullable ApplicationInstanceController applicationInstanceController,
@NotNull CLIContextImpl context,
@NotNull CLIRunMeta runMeta
@NotNull CLIRunMeta runMeta,
@NotNull List<CLICommandDescriptor> commandsToExecute
) {
var cmd = super.initCommandLine(applicationInstanceController, context, runMeta);
var cmd = super.initCommandLine(applicationInstanceController, context, runMeta, commandsToExecute);
cmd.addMixin("cloudbeaver", mixin);
return cmd;
}
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Model
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
Bundle-Version: 1.0.98.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.102.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
@@ -17,7 +17,6 @@ Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
org.jkiss.bundle.logback;visibility:=reexport,
org.jkiss.bundle.graphql;visibility:=reexport,
org.jkiss.bundle.apache.dbcp,
com.google.gson;visibility:=reexport,
jakarta.servlet-api;bundle-version:="6.0.0";visibility:=reexport
Export-Package: io.cloudbeaver,
io.cloudbeaver.auth,
@@ -29,6 +28,11 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.websocket.event.client,
io.cloudbeaver.websocket.event.task,
io.cloudbeaver.model,
io.cloudbeaver.model.api.annotation,
io.cloudbeaver.model.api.annotation.enums,
io.cloudbeaver.model.api.annotation.media,
io.cloudbeaver.model.api.annotation.responses,
io.cloudbeaver.model.api.annotation.tags,
io.cloudbeaver.model.app,
io.cloudbeaver.model.config,
io.cloudbeaver.model.apilog,
@@ -25,6 +25,11 @@
label="Default secret controller" description="Default void secret controller"/>
</extension>
<extension point="io.cloudbeaver.feature">
<feature id="ssh" label="SSH tunnels for databases" description="Enables SSH tunnels for secure database connections, allowing access to remote databases through encrypted channels" enabledByDefault="true"/>
</extension>
<extension point="org.jkiss.dbeaver.ws.event">
<event topicId="cb_session_task" id="cb_session_task_info_updated"
class="io.cloudbeaver.websocket.event.task.WSSessionTaskInfoEvent"/>
@@ -46,6 +51,8 @@
class="io.cloudbeaver.websocket.event.client.WSSessionTaskConfirmationEvent"/>
<clientEvent id="cb_client_session_task_with_parameters_confirmation"
class="io.cloudbeaver.websocket.event.client.WSSessionTaskWithParametersConfirmationEvent"/>
<clientEvent id="cb_client_cancel_action"
class="io.cloudbeaver.websocket.event.client.WSSessionCancelActionClientEvent"/>
</extension>
</plugin>
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.model</artifactId>
<version>1.0.98-SNAPSHOT</version>
<version>1.0.102-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -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.
@@ -27,6 +27,7 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourcePreferenceStore;
import org.jkiss.utils.CommonUtils;
public class WebConnectionConfigInputHandler<T extends WebConnectionConfig, C extends DataSourceDescriptor> {
@@ -93,6 +94,9 @@ public class WebConnectionConfigInputHandler<T extends WebConnectionConfig, C ex
input.isSharedCredentials()
);
dataSource.setConnectionReadOnly(input.isReadOnly());
DataSourcePreferenceStore preferenceStore = dataSource.getPreferenceStore();
preferenceStore.clear();
preferenceStore.setProperties(input.getDefaultUserPreferences());
}
@NotNull
@@ -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.
@@ -377,6 +377,11 @@ public class WebGlobalProjectRegistryProxy implements DBPDataSourceRegistry, Dat
return dataSourceRegistry.getPreferenceStore();
}
@Override
public void initializeDataSources() {
dataSourceRegistry.initializeDataSources();
}
@Override
public DataSourceParseResults loadDataSources(
@NotNull List<DBPDataSourceConfigurationStorage> storages,
@@ -407,12 +412,12 @@ public class WebGlobalProjectRegistryProxy implements DBPDataSourceRegistry, Dat
}
@Override
public void persistSecrets(DBSSecretController secretController) throws DBException {
public void persistSecrets(@NotNull DBSSecretController secretController) throws DBException {
dataSourceRegistry.persistSecrets(secretController);
}
@Override
public void resolveSecrets(DBSSecretController secretController) throws DBException {
public void resolveSecrets(@NotNull DBSSecretController secretController) throws DBException {
dataSourceRegistry.resolveSecrets(secretController);
}
@@ -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.
@@ -252,14 +252,14 @@ public class WebSessionProjectImpl extends WebProjectImpl implements DBPAdaptabl
}
case WSDataSourceEvent.UPDATED -> {
if (event.getProperty() == WSDataSourceProperty.CONFIGURATION) {
WebDataSourceUtils.disconnectDataSource(webSession, ds);
WebDataSourceUtils.disconnectDataSource(webSession, ds, true);
}
if (event.getProperty() != WSDataSourceProperty.INTERNAL) {
sendDataSourceUpdatedEvent = true;
}
}
case WSDataSourceEvent.DELETED -> {
WebDataSourceUtils.disconnectDataSource(webSession, ds);
WebDataSourceUtils.disconnectDataSource(webSession, ds, false);
if (registry instanceof DBPDataSourceRegistryCache dsrc) {
dsrc.removeDataSourceFromList(ds);
}
@@ -345,7 +345,7 @@ public class WebSessionProjectImpl extends WebProjectImpl implements DBPAdaptabl
@NotNull
private WebConnectionInfo closeAndDeleteConnection(@NotNull WebConnectionInfo connectionInfo) throws DBWebException {
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer, false);
DBPDataSourceRegistry registry = getDataSourceRegistry();
registry.removeDataSource(dataSourceContainer);
removeConnection(dataSourceContainer);
@@ -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.
@@ -23,6 +23,7 @@ import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.meta.Property;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -64,6 +65,8 @@ public class WebConnectionConfig {
private Boolean defaultAutoCommit;
private String defaultCatalogName;
private String defaultSchemaName;
@NotNull
private Map<String, String> defaultUserPreferences = new LinkedHashMap<>();
public WebConnectionConfig() {
}
@@ -111,6 +114,8 @@ public class WebConnectionConfig {
String configType = JSONUtils.getString(params, "configurationType");
configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType);
Map<String, Object> stringObjectUserPrefMap = JSONUtils.getObject(params, "defaultUserPreferences");
stringObjectUserPrefMap.forEach((key, value) -> defaultUserPreferences.put(key, value.toString()));
networkHandlersConfig = new ArrayList<>();
for (Map<String, Object> nhc : JSONUtils.getObjectList(params, "networkHandlersConfig")) {
networkHandlersConfig.add(new WebNetworkHandlerConfigInput(nhc));
@@ -367,4 +372,13 @@ public class WebConnectionConfig {
public void setDefaultSchemaName(String defaultSchemaName) {
this.defaultSchemaName = defaultSchemaName;
}
@NotNull
public Map<String, String> getDefaultUserPreferences() {
return defaultUserPreferences;
}
public void setDefaultUserPreferences(@NotNull Map<String, String> defaultUserPreferences) {
this.defaultUserPreferences = defaultUserPreferences;
}
}
@@ -40,11 +40,13 @@ import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
import org.jkiss.dbeaver.model.navigator.DBNDataSource;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.dbeaver.model.rm.RMConstants;
import org.jkiss.dbeaver.model.rm.RMProjectPermission;
import org.jkiss.dbeaver.model.runtime.DBRRunnableParametrized;
import org.jkiss.dbeaver.registry.DataSourcePreferenceStore;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
@@ -293,6 +295,16 @@ public class WebConnectionInfo {
return dataSourceContainer.getNavigatorSettings().getOriginalSettings();
}
@Property
@NotNull
public Map<String, String> getDefaultUserPreferences() {
DBPPreferenceStore preferenceStore = dataSourceContainer.getPreferenceStore();
if (preferenceStore instanceof DataSourcePreferenceStore dataSourcePreferenceStore) {
return dataSourcePreferenceStore.getProperties();
}
return Collections.emptyMap();
}
@Property
@NotNull
public List<WebDataFormat> getSupportedDataFormats() {
@@ -578,4 +590,5 @@ public class WebConnectionInfo {
public void setCredentialsSavedInSession(@Nullable Boolean credentialsSavedInSession) {
this.credentialsSavedInSession = credentialsSavedInSession;
}
}
@@ -16,6 +16,8 @@
*/
package io.cloudbeaver.model;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.utils.CommonUtils;
@@ -28,12 +30,14 @@ import java.util.Map;
*/
public class WebNetworkHandlerConfigInput {
@NotNull
private final Map<String, Object> cfg;
public WebNetworkHandlerConfigInput(Map<String, Object> cfg) {
public WebNetworkHandlerConfigInput(@NotNull Map<String, Object> cfg) {
this.cfg = cfg;
}
@Nullable
public DBWHandlerType getType() {
return CommonUtils.valueOf(DBWHandlerType.class, JSONUtils.getString(cfg, "type"), null);
}
@@ -42,6 +46,7 @@ public class WebNetworkHandlerConfigInput {
return JSONUtils.getString(cfg, "id");
}
@Nullable
public Boolean isEnabled() {
if (cfg.containsKey("enabled")) {
return JSONUtils.getBoolean(cfg, "enabled");
@@ -62,11 +67,13 @@ public class WebNetworkHandlerConfigInput {
return JSONUtils.getString(cfg, "password");
}
@Deprecated // use secured properties
// Deprecated. Use secured properties
@Nullable
public String getKey() {
return JSONUtils.getString(cfg, "key");
}
@Nullable
public Boolean isSavePassword() {
if (cfg.containsKey("savePassword")) {
return JSONUtils.getBoolean(cfg, "savePassword");
@@ -75,10 +82,12 @@ public class WebNetworkHandlerConfigInput {
}
}
@Nullable
public Map<String, Object> getProperties() {
return JSONUtils.getObjectOrNull(cfg, "properties");
}
@Nullable
public Map<String, String> getSecureProperties() {
var secureProperties = JSONUtils.getObjectOrNull(cfg, "secureProperties");
if (secureProperties == null) {
@@ -0,0 +1,41 @@
/*
* 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.model.api.annotation;
import io.cloudbeaver.model.api.annotation.responses.ApiResponse;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Operation {
String summary() default "";
String description() default "";
String operationId() default "";
String method() default "";
Parameter[] parameters() default {};
ApiResponse[] responses() default {};
}
@@ -0,0 +1,51 @@
/*
* 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.model.api.annotation;
import io.cloudbeaver.model.api.annotation.enums.Explode;
import io.cloudbeaver.model.api.annotation.enums.ParameterIn;
import io.cloudbeaver.model.api.annotation.enums.ParameterStyle;
import io.cloudbeaver.model.api.annotation.media.ArraySchema;
import io.cloudbeaver.model.api.annotation.media.Schema;
import java.lang.annotation.*;
@Repeatable(Parameters.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
public @interface Parameter {
String name() default "";
String description() default "";
boolean required() default false;
String example() default "";
ParameterIn in() default ParameterIn.DEFAULT;
Schema schema() default @Schema;
ArraySchema array() default @ArraySchema;
ParameterStyle style() default ParameterStyle.DEFAULT;
Explode explode() default Explode.DEFAULT;
boolean hidden() default false;
}
@@ -0,0 +1,29 @@
/*
* 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.model.api.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
public @interface Parameters {
Parameter[] value();
}
@@ -0,0 +1,34 @@
/*
* 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.model.api.annotation.enums;
public enum Explode {
TRUE("true"),
FALSE("false"),
DEFAULT("default");
private final String value;
Explode(final String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
@@ -0,0 +1,36 @@
/*
* 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.model.api.annotation.enums;
public enum ParameterIn {
DEFAULT("default"),
QUERY("query"),
HEADER("header"),
PATH("path"),
COOKIE("cookie");
private final String value;
ParameterIn(final String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
@@ -0,0 +1,39 @@
/*
* 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.model.api.annotation.enums;
public enum ParameterStyle {
MATRIX("matrix"),
LABEL("label"),
FORM("form"),
SIMPLE("simple"),
SPACEDELIMITED("spaceDelimited"),
PIPEDELIMITED("pipeDelimited"),
DEEPOBJECT("deepObject"),
DEFAULT("default");
private final String value;
ParameterStyle(final String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
@@ -0,0 +1,29 @@
/*
* 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.model.api.annotation.media;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
public @interface ArraySchema {
Schema schema() default @Schema;
}
@@ -0,0 +1,29 @@
/*
* 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.model.api.annotation.media;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface Content {
Schema schema() default @Schema;
}
@@ -0,0 +1,37 @@
/*
* 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.model.api.annotation.media;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
public @interface Schema {
String description() default "";
String example() default "";
String type() default "";
Class<?> implementation() default Void.class;
boolean required() default false;
}
@@ -0,0 +1,35 @@
/*
* 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.model.api.annotation.responses;
import io.cloudbeaver.model.api.annotation.media.Content;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface ApiResponse {
String responseCode() default "default";
String description() default "";
Content[] content() default {};
}
@@ -0,0 +1,31 @@
/*
* 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.model.api.annotation.tags;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Tag {
String name() default "";
String description() default "";
}
@@ -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.
@@ -25,10 +25,13 @@ import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBFileController;
import org.jkiss.dbeaver.model.app.DBPLockManagerProvider;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.fs.lock.LockManager;
import org.jkiss.dbeaver.model.fs.lock.shared.SharedFileLockManager;
import org.jkiss.dbeaver.model.impl.app.ApplicationRegistry;
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
@@ -48,7 +51,7 @@ import java.util.Map;
/**
* Servlet application
*/
public abstract class BaseServletApplication extends BaseApplicationImpl implements ServletApplication {
public abstract class BaseServletApplication extends BaseApplicationImpl implements ServletApplication, DBPLockManagerProvider {
public static final String DEFAULT_CONFIG_FILE_PATH = "/etc/cloudbeaver.conf";
public static final String CUSTOM_CONFIG_FOLDER = "custom";
@@ -59,6 +62,7 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
private String instanceId;
@NotNull
@Override
public RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@@ -73,6 +77,18 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
throw new IllegalStateException("File controller is not supported by " + getClass().getSimpleName());
}
@NotNull
@Override
public LockManager createLockManager(@NotNull String applicationId, @NotNull Path metadataFolder) throws DBException {
return new SharedFileLockManager(applicationId, metadataFolder);
}
@NotNull
@Override
public LockManager createLockManager() throws DBException {
return new SharedFileLockManager(getApplicationInstanceId());
}
@Nullable
@Override
public Path getDefaultWorkingFolder() {
@@ -26,7 +26,9 @@ import org.jkiss.dbeaver.model.DBPDataSourceFolder;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
import org.jkiss.dbeaver.model.fs.lock.LockManager;
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMEvent;
import org.jkiss.dbeaver.model.rm.RMEventManager;
@@ -53,11 +55,11 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull
protected final DBPWorkspace workspace;
@NotNull
protected final FileLockController lockController;
protected final LockManager lockController;
protected BaseLocalResourceController(
@NotNull DBPWorkspace workspace,
@NotNull FileLockController lockController
@NotNull LockManager lockController
) {
this.workspace = workspace;
this.lockController = lockController;
@@ -157,7 +159,7 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull String configuration,
@Nullable List<String> dataSourceIds
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "updateProjectDataSources")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProjectDataSources"))) {
DBPProject project = getWebProject(projectId, false);
return doFileWriteOperation(
projectId, project.getMetadataFolder(false),
@@ -188,7 +190,7 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull String projectId,
@NotNull String[] dataSourceIds
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "deleteDataSources")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteDataSources"))) {
DBPProject project = getWebProject(projectId, false);
doFileWriteOperation(projectId, project.getMetadataFolder(false), () -> {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
@@ -213,7 +215,7 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull String projectId,
@NotNull String folderPath
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
DBPProject project = getWebProject(projectId, false);
log.debug("Creating data source folder '" + folderPath + "' in project '" + projectId + "'");
doFileWriteOperation(projectId, project.getMetadataFolder(false),
@@ -241,7 +243,7 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull String[] folderPaths,
boolean dropContents
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
DBPProject project = getWebProject(projectId, false);
doFileWriteOperation(projectId, project.getMetadataFolder(false),
() -> {
@@ -267,7 +269,7 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull String oldPath,
@NotNull String newPath
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
DBPProject project = getWebProject(projectId, false);
log.debug("Moving data source folder from '" + oldPath + "' to '" + newPath + "' in project '" + projectId + "'");
doFileWriteOperation(projectId, project.getMetadataFolder(false),
@@ -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.
@@ -33,7 +33,9 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMCredentials;
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
import org.jkiss.dbeaver.model.fs.lock.LockManager;
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
import org.jkiss.dbeaver.model.navigator.DBNLocalFolder;
@@ -51,6 +53,7 @@ import org.jkiss.dbeaver.registry.DataSourceParseResults;
import org.jkiss.dbeaver.registry.ResourceTypeDescriptor;
import org.jkiss.dbeaver.registry.ResourceTypeRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;
import org.jkiss.utils.Pair;
@@ -90,9 +93,10 @@ public class LocalResourceController extends BaseLocalResourceController {
@NotNull Path rootPath,
@NotNull Path userProjectsPath,
@NotNull Path sharedProjectsPath,
@NotNull Supplier<SMAdminController> smControllerSupplier
@NotNull Supplier<SMAdminController> smControllerSupplier,
@NotNull LockManager lockController
) throws DBException {
super(workspace, new FileLockController(ServletAppUtils.getServletApplication().getApplicationInstanceId()));
super(workspace, lockController);
this.credentialsProvider = credentialsProvider;
this.rootPath = rootPath;
this.userProjectsPath = userProjectsPath;
@@ -101,7 +105,7 @@ public class LocalResourceController extends BaseLocalResourceController {
this.globalProjectName = DBWorkbench.getPlatform().getApplication().getDefaultProjectName();
this.fileHandlers = RMFileOperationHandlersRegistry.getInstance().getFileHandlers();
this.sharedProjectsMetadataInfo = new ProjectsMetadataInfo(sharedProjectsPath);
this.sharedProjectsMetadataInfo = new ProjectsMetadataInfo(sharedProjectsPath, lockController);
}
@NotNull
@@ -280,7 +284,7 @@ public class LocalResourceController extends BaseLocalResourceController {
throw new DBException("Error creating shared project path", e);
}
}
validateResourcePath(name);
GeneralUtils.validateResourceNameUnconditionally(name);
validateProjectName(null, name);
var projectPath = sharedProjectsPath.resolve(name);
if (Files.exists(projectPath)) {
@@ -303,7 +307,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@Override
public RMProject updateProject(@NotNull String projectId, @NotNull RMProjectInfo projectInfo) throws DBException {
validateProjectName(projectId, projectInfo.getName());
try (var ignoredLock = lockController.lock(projectId, "updateProject")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProject"))) {
RMLocalProject project = getWebProject(projectId, false);
Path targetPath = getProjectPath(projectId);
if (!Files.exists(targetPath)) {
@@ -330,7 +334,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@Override
public void deleteProject(@NotNull String projectId) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "deleteProject")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteProject"))) {
Path targetPath = getProjectPath(projectId);
if (!Files.exists(targetPath)) {
log.error(MessageFormat.format("Project folder ''{0}'' is not found", projectId));
@@ -699,7 +703,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@NotNull String resourcePath,
boolean isFolder
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "createResource")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createResource"))) {
validateResourcePath(resourcePath);
Path targetPath = getTargetPath(projectId, resourcePath);
if (Files.exists(targetPath)) {
@@ -731,7 +735,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@NotNull String oldResourcePath,
@NotNull String newResourcePath
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "moveResource")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("moveResource"))) {
var normalizedOldResourcePath = CommonUtils.normalizeResourcePath(oldResourcePath);
var normalizedNewResourcePath = CommonUtils.normalizeResourcePath(newResourcePath);
if (log.isDebugEnabled()) {
@@ -803,7 +807,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@Override
public void deleteResource(@NotNull String projectId, @NotNull String resourcePath, boolean recursive) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "deleteResource")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteResource"))) {
if (log.isDebugEnabled()) {
log.debug("Removing resource from '" + resourcePath + "' in project '" + projectId + "'" + (recursive ? " recursive" : ""));
}
@@ -891,7 +895,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@NotNull byte[] data,
boolean forceOverwrite
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "setResourceContents")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("setResourceContents"))) {
validateResourcePath(resourcePath);
Number fileSizeLimit = ServletAppUtils.getServletApplication()
.getAppConfiguration()
@@ -936,7 +940,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@NotNull String propertyName,
@Nullable Object propertyValue
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("resourcePropertyUpdate"))) {
validateResourcePath(resourcePath);
RMLocalProject webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
@@ -957,7 +961,7 @@ public class LocalResourceController extends BaseLocalResourceController {
@NotNull String resourcePath,
@NotNull Map<String, Object> properties
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("resourcePropertyUpdate"))) {
validateResourcePath(resourcePath);
RMLocalProject webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
@@ -1103,6 +1107,7 @@ public class LocalResourceController extends BaseLocalResourceController {
RMProjectName project = WebRMUtils.parseProjectName(projectId);
RMProjectType type = project.getType();
String projectName = project.getName();
GeneralUtils.validateResourceNameUnconditionally(projectName);
switch (type) {
case GLOBAL:
if (!projectName.equals(globalProjectName)) {
@@ -1204,12 +1209,14 @@ public class LocalResourceController extends BaseLocalResourceController {
return getProjectPath(projectId).toAbsolutePath().relativize(path).toString().replace('\\', IPath.SEPARATOR);
}
@NotNull
public static Builder builder(
SMCredentialsProvider credentialsProvider,
DBPWorkspace workspace,
Supplier<SMAdminController> smControllerSupplier
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace,
@NotNull LockManager lockController,
@NotNull Supplier<SMAdminController> smControllerSupplier
) {
return new Builder(workspace, credentialsProvider, smControllerSupplier);
return new Builder(workspace, credentialsProvider, lockController, smControllerSupplier);
}
@Override
@@ -1225,10 +1232,13 @@ public class LocalResourceController extends BaseLocalResourceController {
protected Path rootPath;
protected Path userProjectsPath;
protected Path sharedProjectsPath;
protected LockManager lockController;
protected Builder(
DBPWorkspace workspace, SMCredentialsProvider credentialsProvider,
Supplier<SMAdminController> smControllerSupplier
@NotNull DBPWorkspace workspace,
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull LockManager lockController,
@NotNull Supplier<SMAdminController> smControllerSupplier
) {
this.workspace = workspace;
this.credentialsProvider = credentialsProvider;
@@ -1236,25 +1246,38 @@ public class LocalResourceController extends BaseLocalResourceController {
this.rootPath = RMUtils.getRootPath();
this.userProjectsPath = RMUtils.getUserProjectsPath();
this.sharedProjectsPath = RMUtils.getSharedProjectsPath();
this.lockController = lockController;
}
public Builder setRootPath(Path rootPath) {
@NotNull
public Builder setRootPath(@NotNull Path rootPath) {
this.rootPath = rootPath;
return this;
}
public Builder setUserProjectsPath(Path userProjectsPath) {
@NotNull
public Builder setUserProjectsPath(@NotNull Path userProjectsPath) {
this.userProjectsPath = userProjectsPath;
return this;
}
public Builder setSharedProjectsPath(Path sharedProjectsPath) {
@NotNull
public Builder setSharedProjectsPath(@NotNull Path sharedProjectsPath) {
this.sharedProjectsPath = sharedProjectsPath;
return this;
}
@NotNull
public LocalResourceController build() throws DBException {
return new LocalResourceController(workspace, credentialsProvider, rootPath, userProjectsPath, sharedProjectsPath, smController);
return new LocalResourceController(
workspace,
credentialsProvider,
rootPath,
userProjectsPath,
sharedProjectsPath,
smController,
lockController
);
}
}
@@ -17,14 +17,15 @@
package io.cloudbeaver.model.rm.local;
import com.google.gson.reflect.TypeToken;
import io.cloudbeaver.utils.ServletAppUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
import org.jkiss.dbeaver.model.fs.lock.LockManager;
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.rm.RMProjectInfo;
import org.jkiss.dbeaver.model.rm.RMProjectType;
@@ -45,12 +46,12 @@ public class ProjectsMetadataInfo {
private final Map<String, RMProjectInfo> projectsInfo = new LinkedHashMap<>();
private final Path projectsPath;
private final FileLockController lockController;
private final LockManager lockController;
public ProjectsMetadataInfo(@NotNull Path projectsPath) throws DBException {
public ProjectsMetadataInfo(@NotNull Path projectsPath, @NotNull LockManager lockController) throws DBException {
this.projectsPath = projectsPath;
this.lockController = new FileLockController(ServletAppUtils.getServletApplication().getApplicationInstanceId());
this.lockController = lockController;
readProjectInfos(projectsPath);
}
@@ -139,7 +140,7 @@ public class ProjectsMetadataInfo {
}
private void saveProjectsInfo() {
try (var lock = lockController.lock(PROJECTS_INFO_FILE_NAME, "saveProjectsInfo")) {
try (var lock = lockController.lock(LockTarget.of(PROJECTS_INFO_FILE_NAME), LockOptions.of("saveProjectsInfo"))) {
log.info("Saving project information");
Files.writeString(projectsPath.resolve(PROJECTS_INFO_FILE_NAME), JSONUtils.GSON.toJson(projectsInfo));
} catch (IOException e) {
@@ -148,4 +149,4 @@ public class ProjectsMetadataInfo {
log.error("Error locking file " + PROJECTS_INFO_FILE_NAME + ": " + e.getMessage());
}
}
}
}
@@ -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.
@@ -55,14 +55,21 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
@NotNull
protected final ServletApplication application;
protected volatile long lastAccessTime;
@NotNull
private final SessionType sessionType;
private final List<CBWebSessionEventHandler> sessionEventHandlers = new CopyOnWriteArrayList<>();
private WebSessionEventsFilter eventsFilter;
private final WebSessionWorkspace workspace;
public BaseWebSession(@NotNull String id, @NotNull ServletApplication application) throws DBException {
public BaseWebSession(
@NotNull String id,
@NotNull ServletApplication application,
@NotNull SessionType sessionType
) throws DBException {
this.id = id;
this.application = application;
this.sessionType = sessionType;
this.createTime = System.currentTimeMillis();
this.lastAccessTime = this.createTime;
this.workspace = createWebWorkspace();
@@ -151,7 +158,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
}
protected synchronized void clearSessionContext() {
this.workspace.getAuthContext().clear();
this.workspace.getAuthContext().clearContext(false);
this.workspace.getAuthContext().addSession(this);
}
@@ -176,6 +183,11 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
return lastAccessTime;
}
@NotNull
public SessionType getSessionType() {
return sessionType;
}
public void touchSession() {
this.lastAccessTime = System.currentTimeMillis();
}
@@ -187,12 +199,13 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
@Override
public void close() {
super.close();
cleanUpSession(true);
super.close();
}
public void close(boolean clearTokens, boolean sendSessionExpiredEvent) {
cleanUpSession(sendSessionExpiredEvent);
super.close();
}
private void cleanUpSession(boolean sendSessionExpiredEvent) {
@@ -0,0 +1,23 @@
/*
* 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.model.session;
public enum SessionType {
WEB,
HEADLESS,
API_TOKEN
}
@@ -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.
@@ -31,7 +31,7 @@ public class WebHeadlessSession extends BaseWebSession {
@NotNull String id,
@NotNull ServletAuthApplication application
) throws DBException {
super(id, application);
super(id, application, SessionType.HEADLESS);
}
@Override
@@ -17,6 +17,7 @@
package io.cloudbeaver.model.session;
import jakarta.servlet.http.HttpServletRequest;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.utils.HttpConstants;
@@ -31,12 +32,16 @@ public class WebHttpRequestInfo {
private final String lastRemoteAddress;
@Nullable
private final String lastRemoteUserAgent;
@NotNull
private final SessionType sessionType;
public WebHttpRequestInfo(HttpServletRequest request) {
this.id = request.getSession() == null ? null : request.getSession().getId();
this.locale = request.getAttribute("locale");
this.lastRemoteAddress = request.getRemoteAddr();
this.lastRemoteUserAgent = request.getHeader(USER_AGENT);
this(
request.getSession() == null ? null : request.getSession().getId(),
request.getAttribute("locale"),
request.getRemoteAddr(),
request.getHeader(USER_AGENT)
);
}
public WebHttpRequestInfo(
@@ -44,11 +49,22 @@ public class WebHttpRequestInfo {
@Nullable Object locale,
@Nullable String lastRemoteAddress,
@Nullable String lastRemoteUserAgent
) {
this(id, locale, lastRemoteAddress, lastRemoteUserAgent, SessionType.WEB);
}
public WebHttpRequestInfo(
@Nullable String id,
@Nullable Object locale,
@Nullable String lastRemoteAddress,
@Nullable String lastRemoteUserAgent,
@NotNull SessionType sessionType
) {
this.id = id;
this.locale = locale;
this.lastRemoteAddress = lastRemoteAddress;
this.lastRemoteUserAgent = lastRemoteUserAgent;
this.sessionType = sessionType;
}
@Nullable
@@ -70,4 +86,9 @@ public class WebHttpRequestInfo {
public String getLastRemoteUserAgent() {
return lastRemoteUserAgent;
}
@NotNull
public SessionType getSessionType() {
return sessionType;
}
}
@@ -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.
@@ -116,7 +116,8 @@ public class WebSession extends BaseWebSession
CommonUtils.toString(requestInfo.getLocale()),
application,
sessionHandlers,
requestInfo.getLastRemoteAddress()
requestInfo.getLastRemoteAddress(),
requestInfo.getSessionType()
);
updateSessionParameters(requestInfo);
}
@@ -128,7 +129,18 @@ public class WebSession extends BaseWebSession
@NotNull Map<String, DBWSessionHandler<WebSession>> sessionHandlers,
@Nullable String remoteAddr
) throws DBException {
super(id, application);
this(id, locale, application, sessionHandlers, remoteAddr, SessionType.WEB);
}
protected WebSession(
@NotNull String id,
@Nullable String locale,
@NotNull ServletApplication application,
@NotNull Map<String, DBWSessionHandler<WebSession>> sessionHandlers,
@Nullable String remoteAddr,
@NotNull SessionType sessionType
) throws DBException {
super(id, application, sessionType);
if (CommonUtils.isEmpty(remoteAddr)) {
throw new DBException("Remote address cannot be empty");
}
@@ -492,7 +504,6 @@ public class WebSession extends BaseWebSession
public void close() {
try {
resetNavigationModel();
resetSessionCache();
} catch (Throwable e) {
log.error(e);
}
@@ -509,7 +520,6 @@ public class WebSession extends BaseWebSession
public void close(boolean clearTokens, boolean sendSessionExpiredEvent) {
try {
resetNavigationModel();
resetSessionCache();
} catch (Throwable e) {
log.error(e);
}
@@ -609,11 +619,13 @@ public class WebSession extends BaseWebSession
}
}
@NotNull
public WebAsyncTaskInfo createAndRunAsyncTask(@NotNull String taskName, @NotNull WebAsyncTaskProcessor<?> runnable) {
WebAsyncTaskInfo asyncTask = createAsyncTask(taskName);
return runAsyncTask(asyncTask, runnable);
}
@NotNull
public WebAsyncTaskInfo runAsyncTask(@NotNull WebAsyncTaskInfo asyncTask, @NotNull WebAsyncTaskProcessor<?> runnable) {
AbstractJob job = new AbstractCancelableJob(asyncTask.getName()) {
@NotNull
@@ -1037,7 +1049,6 @@ public class WebSession extends BaseWebSession
}
}
public void handleTaskConfirmationWithParameters(@NotNull String taskId, @NotNull Map<String, Object> parameters) {
String attributeName = getTaskConfirmationAttributeName(taskId);
CompletableFuture<Map<String, Object>> confirmationFuture = getAttribute(attributeName);
@@ -1049,6 +1060,16 @@ public class WebSession extends BaseWebSession
}
}
public void handleActionCancelledEvent(@NotNull String actionId) {
Object attributeValue = getAttribute(actionId);
if (!(attributeValue instanceof CompletableFuture<?> future)) {
log.info("Action to be cancelled not found, skipping: " + actionId);
return;
}
future.completeExceptionally(new DBWebException("Action cancelled by user: " + actionId));
removeAttribute(actionId);
}
@NotNull
private String getTaskConfirmationAttributeName(@NotNull String taskId) {
return WebSQLConstants.TASK_CONFIRMATION_ATTR_PREFIX + taskId;
@@ -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.
@@ -17,6 +17,7 @@
package io.cloudbeaver.model.session;
import io.cloudbeaver.WebSessionProjectImpl;
import io.cloudbeaver.utils.ServletAppUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
@@ -199,12 +200,15 @@ public class WebSessionWorkspace implements DBPWorkspace {
@Override
public boolean hasRealmPermission(@NotNull String permission) {
if (getWebSession() instanceof WebSession webSession) {
return webSession.getSessionPermissions().contains(permission);
}
return false;
}
@Override
public boolean supportsRealmFeature(@NotNull String feature) {
return false;
return ServletAppUtils.getServletApplication().getAppConfiguration().isFeatureEnabled(feature);
}
}
@@ -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.
@@ -31,6 +31,8 @@ import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.security.SMAuthCredentialsProfile;
import org.jkiss.dbeaver.model.security.SMAuthProviderDescriptor;
import org.jkiss.dbeaver.model.security.SMSubjectType;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.SystemVariablesResolver;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
@@ -110,7 +112,9 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor {
}
public String getDescription() {
return cfg.getAttribute(WebRegistryConstant.ATTR_DESCRIPTION);
return GeneralUtils.replaceVariables(
cfg.getAttribute(WebRegistryConstant.ATTR_DESCRIPTION), SystemVariablesResolver.INSTANCE
);
}
public DBPImage getIcon() {
@@ -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.
@@ -20,11 +20,14 @@ import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.app.ServletApplication;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.auth.SMSession;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.utils.CommonUtils;
import java.io.IOException;
@@ -55,8 +58,14 @@ public class ServerGlobalWorkspace extends BaseWorkspaceImpl {
this.application = application;
}
@NotNull
@Override
public void initializeProjects() {
protected SMSession acquireWorkspaceSession(@NotNull DBRProgressMonitor monitor) throws DBException {
return new ServerGlobalWorkspaceSession(this);
}
@Override
public void initializeProjects() throws DBException {
initializeWorkspaceSession();
// Load global project
@@ -106,4 +115,9 @@ public class ServerGlobalWorkspace extends BaseWorkspaceImpl {
}
return null;
}
@Override
public boolean supportsRealmFeature(@NotNull String feature) {
return application.getAppConfiguration().isFeatureEnabled(feature);
}
}
@@ -0,0 +1,36 @@
/*
* 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.server;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.impl.app.LocalWorkspaceSession;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
public class ServerGlobalWorkspaceSession extends LocalWorkspaceSession {
public ServerGlobalWorkspaceSession(@NotNull DBPWorkspace workspace) {
super(workspace);
}
@Nullable
@Override
public DBSSecretController getSecretController() {
return null;
}
}
@@ -193,8 +193,12 @@ public class ServletAppUtils {
@NotNull String origin
) throws DBException {
String finalOrigin = webAuthApplication.modifyOrigin(origin);
StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin));
String serviceUriSegment = removeSideSlashes(webAuthApplication.getAuthServiceUriSegment());
String rootUri = removeSideSlashes(getServletApplication().getRootURI());
if (finalOrigin.endsWith("/" + rootUri) && serviceUriSegment.startsWith(rootUri + "/")) {
finalOrigin = finalOrigin.substring(0, finalOrigin.length() - rootUri.length());
}
StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin));
if (CommonUtils.isNotEmpty(serviceUriSegment)) {
authUriBuilder.append("/").append(serviceUriSegment);
}
@@ -305,12 +309,6 @@ public class ServletAppUtils {
log.trace("X-Origin header: " + origin);
}
}
if (CommonUtils.isEmpty(origin)) {
origin = request.getHeader(HEADER_REFERER);
if (log.isTraceEnabled()) {
log.trace("Referer header: " + origin);
}
}
String forwardedScheme = request.getHeader(HEADER_FORWARDED_SCHEME);
if (CommonUtils.isEmpty(forwardedScheme)) {
forwardedScheme = request.getHeader(HEADER_FORWARDED_PROTO);
@@ -321,8 +319,7 @@ public class ServletAppUtils {
if (log.isTraceEnabled()) {
log.trace("forwarded origin: " + origin);
}
}
if (CommonUtils.isEmpty(origin)) {
} else if (CommonUtils.isEmpty(origin)) {
URI requestUrl = URI.create(request.getRequestURL().toString());
if (log.isTraceEnabled()) {
log.trace("Request URL: " + requestUrl);
@@ -346,13 +343,34 @@ public class ServletAppUtils {
log.error("Failed to parse port from header: " + request.getHeader(HEADER_FORWARDED_PORT), e);
}
}
String finalScheme = uri.getScheme();
String finalHost = uri.getHost();
int finalPort = port;
boolean changed = false;
if (CommonUtils.isNotEmpty(forwardedScheme) && !forwardedScheme.equals(finalScheme)) {
finalScheme = forwardedScheme;
changed = true;
}
if (CommonUtils.isNotEmpty(forwardedHost) && !forwardedHost.equals(finalHost)) {
finalHost = forwardedHost;
changed = true;
}
if (DEFAULT_PORTS.contains(port)) {
finalPort = -1;
changed = true;
}
if (log.isTraceEnabled()) {
log.trace("Origin URI: " + origin);
}
if (changed) {
try {
origin = new URI(
uri.getScheme(),
finalScheme,
uri.getUserInfo(),
uri.getHost(),
-1,
finalHost,
finalPort,
uri.getPath(),
uri.getQuery(),
uri.getFragment()
@@ -361,9 +379,6 @@ public class ServletAppUtils {
log.error("Failed to create URI without port", e);
}
}
if (log.isTraceEnabled()) {
log.trace("Origin URI: " + origin);
}
return origin;
}
@@ -162,18 +162,24 @@ public class WebDataSourceUtils {
}
public static boolean disconnectDataSource(@NotNull WebSession webSession, @NotNull DBPDataSourceContainer dataSource) {
public static boolean disconnectDataSource(
@NotNull WebSession webSession,
@NotNull DBPDataSourceContainer dataSource,
boolean sendDisconnectEvent
) {
if (dataSource.isConnected()) {
try {
dataSource.disconnect(webSession.getProgressMonitor());
webSession.addSessionEvent(
new WSDataSourceDisconnectEvent(
dataSource.getProject().getId(),
dataSource.getId(),
webSession.getSessionId(),
webSession.getUserId()
)
);
if (sendDisconnectEvent) {
webSession.addSessionEvent(
new WSDataSourceDisconnectEvent(
dataSource.getProject().getId(),
dataSource.getId(),
webSession.getSessionId(),
webSession.getUserId()
)
);
}
return true;
} catch (DBException e) {
log.error("Error closing connection", e);
@@ -0,0 +1,40 @@
/*
* 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 WSSessionCancelActionClientEvent extends WSClientEvent {
public static final String ID = "cb_client_cancel_action";
@NotNull
private final String actionId;
public WSSessionCancelActionClientEvent(
@NotNull String actionId
) {
super(ID, WSConstants.TOPIC_SESSION_ACTION);
this.actionId = actionId;
}
@NotNull
public String getActionId() {
return actionId;
}
}
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Community Product
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
Bundle-Version: 26.0.2.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 26.1.0.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.product.ce</artifactId>
<version>26.0.2-SNAPSHOT</version>
<version>26.1.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Cloudbeaver Base JDBC drivers
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
Bundle-Version: 1.0.143.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.147.qualifier
Bundle-Release-Date: 20260601
Bundle-Vendor: DBeaver Corp
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
@@ -14,7 +14,9 @@
<resource name="drivers/jaybird"/>
<resource name="drivers/h2"/>
<resource name="drivers/h2_v2"/>
<resource name="drivers/h2_v3"/>
<resource name="drivers/sqlite/xerial"/>
<resource name="drivers/libsql"/>
<resource name="drivers/mssql/new"/>
<resource name="drivers/trino"/>
<resource name="drivers/kyuubi"/>
@@ -35,7 +37,9 @@
<bundle id="drivers.firebird" label="Firebird drivers"/>
<bundle id="drivers.h2" label="H2 drivers"/>
<bundle id="drivers.h2_v2" label="H2 v2 drivers"/>
<bundle id="drivers.h2_v3" label="H2 v3 drivers"/>
<bundle id="drivers.sqlite.xerial" label="SQLite drivers"/>
<bundle id="drivers.libsql" label="LibSQL drivers"/>
<bundle id="drivers.mssql.new" label="SQL Server drivers"/>
<bundle id="drivers.trino" label="Trino drivers"/>
<bundle id="drivers.kyuubi" label="Apache Kyuubi drivers"/>
@@ -55,6 +59,7 @@
<driver id="clickhouse:com_clickhouse"/>
<driver id="h2:h2_embedded"/>
<driver id="h2:h2_embedded_v2"/>
<driver id="h2:h2_embedded_v3"/>
<driver id="sqlite:sqlite_jdbc"/>
<driver id="sqlite:libsql_jdbc"/>
<driver id="sqlserver:microsoft"/>
@@ -9,6 +9,6 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
<version>1.0.143-SNAPSHOT</version>
<version>1.0.147-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: CloudBeaver Community
Bundle-SymbolicName: io.cloudbeaver.server.ce;singleton:=true
Bundle-Version: 26.0.2.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 26.1.0.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.server.ce</artifactId>
<version>26.0.2-SNAPSHOT</version>
<version>26.1.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -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.
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver.server;
import graphql.execution.instrumentation.Instrumentation;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
import io.cloudbeaver.model.CBWebServerConfig;
@@ -29,6 +30,7 @@ import io.cloudbeaver.model.config.CBAppConfig;
import io.cloudbeaver.model.config.CBServerConfig;
import io.cloudbeaver.registry.WebDriverRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import io.cloudbeaver.server.jetty.CBJettyServer;
import io.cloudbeaver.service.DBWServiceInitializer;
import io.cloudbeaver.service.DBWServiceServerConfigurator;
@@ -685,6 +687,11 @@ public abstract class CBApplication<T extends CBServerConfig>
return new CBSessionManager(this);
}
@NotNull
public GraphQLEndpoint createGraphQLEndpoint(@NotNull Instrumentation instrumentation) {
return new GraphQLEndpoint(instrumentation);
}
@NotNull
public WebDriverRegistry getDriverRegistry() {
return WebDriverRegistry.getInstance();
@@ -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.
@@ -75,13 +75,16 @@ public class CBApplicationCE extends CBApplication<CBServerConfig> {
);
}
@NotNull
@Override
public RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace) throws DBException {
return LocalResourceController.builder(credentialsProvider, workspace, this::getSecurityController).build();
public RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace
) throws DBException {
var lockManager = createLockManager();
return LocalResourceController
.builder(credentialsProvider, workspace, lockManager, this::getSecurityController)
.build();
}
@NotNull
@@ -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.
@@ -21,6 +21,7 @@ import io.cloudbeaver.server.jobs.SessionStateJob;
import io.cloudbeaver.server.jobs.WebDataSourceMonitorJob;
import io.cloudbeaver.server.jobs.WebSessionMonitorJob;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPRegistryListener;
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
@@ -51,7 +52,7 @@ public class CBPlatform extends BaseWebPlatform {
}
@Override
protected synchronized void initialize() {
protected synchronized void initialize() throws DBException {
long startTime = System.currentTimeMillis();
log.info("Initialize web platform " + getClass().getSimpleName());
this.preferenceStore = new WebServerPreferenceStore(WebPlatformActivator.getInstance().getPreferences());
@@ -24,6 +24,7 @@ import io.cloudbeaver.server.CBConstants;
import io.cloudbeaver.server.filters.ServerConfigurationTimeLimitFilter;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
import io.cloudbeaver.server.servlets.CBImageServlet;
import io.cloudbeaver.server.servlets.CBManifestServlet;
import io.cloudbeaver.server.servlets.CBStaticServlet;
import io.cloudbeaver.server.servlets.WebStatusServlet;
import io.cloudbeaver.server.websockets.CBEventsLongPollingServlet;
@@ -119,12 +120,15 @@ public class CBJettyServer {
ServletHolder imagesServletHolder = new ServletHolder("images", new CBImageServlet());
servletContextHandler.addServlet(imagesServletHolder, serverConfiguration.getServicesURI() + "images/*");
ServletHolder manifestServletHolder = new ServletHolder("manifest", new CBManifestServlet(contentRootPath));
servletContextHandler.addServlet(manifestServletHolder, "/manifest.webmanifest");
servletContextHandler.addServlet(new ServletHolder("status", new WebStatusServlet()), "/status");
ServletHolder eventsServletHolder = new ServletHolder("events", new CBEventsLongPollingServlet());
servletContextHandler.addServlet(eventsServletHolder, serverConfiguration.getServicesURI() + "events/*");
GraphQLEndpoint endpoint = new GraphQLEndpoint(new ServerConfigurationTimeLimitFilter(application));
GraphQLEndpoint endpoint = application.createGraphQLEndpoint(new ServerConfigurationTimeLimitFilter(application));
application.addApplicationContextValue(GraphQL.class.getName(), endpoint.getGraphQL());
String gqlServletPath = serverConfiguration.getServicesURI() + "gql/*";
servletContextHandler.addServlet(
@@ -257,4 +261,4 @@ public class CBJettyServer {
cbSessionHandler.setSecureCookies(application.getServerConfiguration().isForceHttps());
}
}
}
}
@@ -0,0 +1,119 @@
/*
* 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.server.servlets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.cloudbeaver.model.config.CBServerConfig;
import io.cloudbeaver.server.CBApplication;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.utils.MimeTypes;
import org.jkiss.utils.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@WebServlet(urlPatterns = "/manifest.webmanifest")
public class CBManifestServlet extends HttpServlet {
private static final Log log = Log.getLog(CBManifestServlet.class);
private static final String MANIFEST_FILE = "manifest.webmanifest";
// Fix: Create Gson instance with HTML escaping disabled to prevent \u003d escaping
private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping() // This prevents escaping = to \u003d
.create();
@NotNull
private final Path contentRoot;
public CBManifestServlet(@NotNull Path contentRoot) {
this.contentRoot = contentRoot;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Path manifestPath = contentRoot.resolve(MANIFEST_FILE).normalize();
if (!manifestPath.startsWith(contentRoot) || !Files.exists(manifestPath)) {
log.error("Manifest file not found or path is invalid: " + manifestPath);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
try {
// Read the original manifest file
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (InputStream fis = Files.newInputStream(manifestPath)) {
IOUtils.copyStream(fis, baos);
}
String manifestContent = baos.toString(StandardCharsets.UTF_8);
// Parse the JSON and update dynamic fields
CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration();
String rootURI = serverConfig.getRootURI();
// Ensure rootURI ends with / for proper scope and path handling
String normalizedRootURI = rootURI;
if (!normalizedRootURI.endsWith("/")) {
normalizedRootURI += "/";
}
// Use JsonParser to parse the existing manifest
JsonObject manifest = JsonParser.parseString(manifestContent).getAsJsonObject();
// Update scope to match the rootURI
manifest.addProperty("scope", normalizedRootURI);
// Update start_url and id to match the rootURI
String startUrl = normalizedRootURI + "?source=pwa";
manifest.addProperty("start_url", startUrl);
manifest.addProperty("id", startUrl);
// Convert back to JSON string using the Gson instance with HTML escaping disabled
String updatedManifest = GSON.toJson(manifest);
byte[] manifestBytes = updatedManifest.getBytes(StandardCharsets.UTF_8);
// Set appropriate headers
response.setHeader(HttpHeader.CONTENT_TYPE.toString(), "application/manifest+json");
response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate");
response.setHeader(HttpHeader.EXPIRES.toString(), "0");
response.setContentLength(manifestBytes.length);
// Write the response
response.getOutputStream().write(manifestBytes);
} catch (Exception e) {
log.error("Error processing manifest file", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
}
@@ -51,7 +51,7 @@ public class CBSessionManager implements WebAppSessionManager {
private static final Log log = Log.getLog(CBSessionManager.class);
private final CBApplication<?> application;
private final Map<String, BaseWebSession> sessionMap = new HashMap<>();
protected final Map<String, BaseWebSession> sessionMap = new HashMap<>();
public CBSessionManager(CBApplication<?> application) {
this.application = application;
@@ -379,6 +379,63 @@ public class CBSessionManager implements WebAppSessionManager {
}
}
@Nullable
public WebSession getWebSession(
@Nullable String smAccessToken,
@NotNull WebHttpRequestInfo requestInfo,
boolean create
) throws DBException {
if (CommonUtils.isEmpty(smAccessToken)) {
return null;
}
synchronized (sessionMap) {
var tempCredProvider = new SMTokenCredentialProvider(smAccessToken);
SMAuthPermissions authPermissions = application.createSecurityController(tempCredProvider).getTokenPermissions();
var sessionId = requestInfo.getId() != null ? requestInfo.getId()
: authPermissions.getSessionId();
var existSession = sessionMap.get(sessionId);
if (existSession instanceof WebSession webSession) {
var creds = webSession.getUserContext().getActiveUserCredentials();
if (creds == null || !smAccessToken.equals(creds.getSmAccessToken())) {
if (webSession.getUserContext().refresh(
smAccessToken,
null,
authPermissions
)) {
webSession.refreshUserData();
}
}
return webSession;
}
if (existSession != null) {
//session exist but it not web session
return null;
}
if (!create) {
return null;
}
if (requestInfo.getId() == null) {
requestInfo = new WebHttpRequestInfo(
sessionId,
requestInfo.getLocale(),
requestInfo.getLastRemoteAddress(),
requestInfo.getLastRemoteUserAgent()
);
}
var webSession = createWebSessionImpl(requestInfo);
webSession.getUserContext().refresh(
smAccessToken,
null,
authPermissions
);
webSession.refreshUserData();
sessionMap.put(sessionId, webSession);
return webSession;
}
}
/**
* Send session state with remaining alive time to all cached session
*/
@@ -470,4 +527,5 @@ public class CBSessionManager implements WebAppSessionManager {
log.debug("> Expire session '" + session.getSessionId() + "'");
session.close();
}
}
@@ -3,17 +3,13 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Server
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
Bundle-Version: 26.0.2.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 26.1.0.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
org.apache.commons.jexl,
org.jkiss.utils;visibility:=reexport,
org.jkiss.dbeaver.model.sql;visibility:=reexport,
Require-Bundle: org.jkiss.dbeaver.model.sql;visibility:=reexport,
org.jkiss.dbeaver.data.gis,
org.jkiss.bundle.jetty.server;visibility:=reexport,
com.google.gson;visibility:=reexport,
org.jkiss.bundle.graphql;visibility:=reexport,
org.jkiss.bundle.apache.dbcp,
org.jkiss.dbeaver.net.ssh,
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.server</artifactId>
<version>26.0.2-SNAPSHOT</version>
<version>26.1.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -565,6 +565,8 @@ type ConnectionInfo {
requiredAuth: String
defaultCatalogName: String @since(version: "25.0.5")
defaultSchemaName: String @since(version: "25.0.5")
"Default user settings for connection"
defaultUserPreferences: Object @since(version: "26.0.2")
"List of tools that can be used with this connection. Returns empty list if no tools are available"
tools: [String!]! @since(version: "24.1.3")
@@ -741,6 +743,8 @@ input ConnectionConfig {
defaultCatalogName: String @since(version: "25.0.5") @deprecated(reason: "25.2.1 use expertPropertyValues instead")
"Sets schema name for the connection"
defaultSchemaName: String @since(version: "25.0.5") @deprecated(reason: "25.2.1 use expertPropertyValues instead")
"Default user settings for connection"
defaultUserPreferences: Object @since(version: "26.0.2")
}
####################################################
@@ -846,6 +850,7 @@ extend type Mutation {
"Sets to default navigator settings for connection. Resets all user navigator settings for this connection."
clearConnectionNavigatorSettings(projectId: ID!, id: ID!): ConnectionInfo! @since(version: "25.3.2")
setObjectSettingsForDatasource(id: ID!, projectId:ID, settings: Object!): Object! @since(version: "25.3.5")
#### Generic async functions
"Cancel async task by ID"
@@ -38,7 +38,8 @@ enum CBClientEventId {
cb_client_topic_subscribe,
cb_client_topic_unsubscribe,
cb_client_projects_active,
cb_client_session_ping
cb_client_session_ping,
cb_client_cancel_action @since(version: "26.0.2")
}
"Client subscribes on topic to receive only related events"
@@ -136,6 +137,13 @@ type CBProjectsActiveEvent implements CBClientEvent {
projectIds: [String!]!
}
"Action cancelled by user"
type CBActionCancelledEvent implements CBClientEvent @since(version: "26.0.2") {
id: CBClientEventId!
topicId: CBEventTopic
actionId: String!
}
"Async task info status event"
type WSAsyncTaskInfo @since(version: "24.3.1") {
id: CBServerEventId!
@@ -167,6 +175,7 @@ type WSOpenUrlEvent implements CBServerEvent @since(version: "25.3.1") {
topicId: CBEventTopic!
timestamp: Int!
url: String!
actionId: String!
}
extend type Query {
@@ -228,6 +228,10 @@ type DataTypeLogicalOperation {
type SQLExecutionPlan {
query: String!
nodes: [SQLExecutionPlanNode!]!
hasCost: Boolean! @since(version: "26.0.3")
hasRows: Boolean! @since(version: "26.0.3")
hasDuration: Boolean! @since(version: "26.0.3")
durationMeasure: String @since(version: "26.0.3")
}
type SQLExecutionPlanNode {
@@ -240,6 +244,10 @@ type SQLExecutionPlanNode {
condition: String
description: String
properties: [ObjectPropertyInfo!]!
cost: Float @since(version: "26.0.3")
rowCount: Float @since(version: "26.0.3")
duration: Float @since(version: "26.0.3")
percent: Float @since(version: "26.0.3")
}
####################################################
@@ -254,6 +262,11 @@ type SQLQueryGenerator {
multiObject: Boolean!
}
input SQLQueryGeneratorOptions {
useFullyQualifiedNames: Boolean!
compactSql: Boolean!
}
####################################################
# SQL Query info
####################################################
@@ -338,19 +351,12 @@ extend type Query {
"""
Generates SQL query for the specified entity query generator.
Available options:
fullyQualifiedNames - Use fully qualified names for entities
compactSQL - Use compact SQL format
showComments - Show comments in generated SQL
showPermissions - Show permissions in generated SQL
showFullDdl - Show full DDL in generated SQL
excludeAutoGeneratedColumn - Exclude auto-generated columns in generated SQL
useCustomDataFormat - Use custom data format for generated SQL
"""
sqlGenerateEntityQuery(
generatorId: String!,
options: Object!,
nodePathList: [String!]!
options: Object @deprecated(reason: "use generatorOptions (26.0.3)")
nodePathList: [String!]!,
generatorOptions: SQLQueryGeneratorOptions
): String!
"""
@@ -364,6 +370,7 @@ extend type Query {
generatorId: SQLResultSetGeneratorId!,
resultsId: ID!,
selectedRows: [SQLResultRow!]!,
generatorOptions: SQLQueryGeneratorOptions
): String!
"Parses SQL script and returns script info with queries start and end positions"
@@ -20,10 +20,7 @@ import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.WebCommonUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.connection.DBPAuthModelDescriptor;
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
@@ -77,6 +74,7 @@ public class WebDatabaseAuthModel {
@Property
public WebPropertyInfo[] getProperties() throws DBWebException {
DBPPropertySource credentialsSource = model.createCredentialsSource(null, null);
Predicate<DBPPropertyDescriptor> predicate = CommonUtils.isEmpty(getRequiredAuth())
? p -> true
@@ -84,18 +82,9 @@ public class WebDatabaseAuthModel {
return Arrays.stream(credentialsSource.getProperties())
.filter(predicate)
.filter(p -> !isPassword(p) || isPasswordApplicable())
.filter(p -> !p.isDesktop())
.map(p -> new WebPropertyInfo(webSession, p, credentialsSource))
.toArray(WebPropertyInfo[]::new);
.map(p -> new WebPropertyInfo(webSession, p, credentialsSource)).toArray(WebPropertyInfo[]::new);
}
private boolean isPassword(@NotNull DBPPropertyDescriptor property) {
return property.hasFeature(DBConstants.PROP_FEATURE_PASSWORD);
}
private boolean isPasswordApplicable() {
return model.getInstance() instanceof AuthModelDatabaseNative<?> nativeModel &&
nativeModel.isUserPasswordApplicable();
}
}
@@ -23,6 +23,7 @@ import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.connection.*;
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
@@ -186,10 +187,28 @@ public class WebDatabaseDriverInfo {
cfg.setDatabaseName(driver.getDefaultDatabase());
cfg.setUrl(driver.getConnectionURL(cfg));
DBPPropertyDescriptor[] properties = driver.getDataSourceProvider().getConnectionProperties(webSession.getProgressMonitor(), driver, cfg);
Map<String, Object> connectionProperties = driver.getConnectionProperties();
for (Map.Entry<String, Object> connProp : connectionProperties.entrySet()) {
String propName = connProp.getKey();
Object propValue = connProp.getValue();
DBPPropertyDescriptor dbpPropertyDescriptor = new PropertyDescriptor(
null,
propName,
propName,
null,
false,
String.class,
propValue,
null
);
properties = ArrayUtils.add(DBPPropertyDescriptor.class, properties, dbpPropertyDescriptor);
cfg.setProperty(propName, (String) propValue);
}
if (properties == null) {
return new WebPropertyInfo[0];
}
PropertySourceCustom propertySource = new PropertySourceCustom(
properties,
cfg.getProperties());
@@ -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.
@@ -19,6 +19,7 @@ package io.cloudbeaver.server;
import io.cloudbeaver.server.websockets.WebSocketPingPongJob;
import org.eclipse.core.runtime.Plugin;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.app.DBACertificateStorage;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
@@ -35,7 +36,7 @@ public abstract class BaseWebPlatform extends BaseServletPlatform {
private ServerGlobalWorkspace workspace;
@Override
protected synchronized void initialize() {
protected synchronized void initialize() throws DBException {
// Register BC security provider
SecurityProviderUtils.registerSecurityProvider();
@@ -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.
@@ -239,6 +239,14 @@ public class GraphQLEndpoint extends HttpServlet {
@Nullable Map<String, Object> variables,
@Nullable String operationName
) throws IOException {
String userId = GraphQLLoggerUtil.getUserId(request);
LocalDateTime startTime = LocalDateTime.now();
if (isQueryHandledBeforeExecution(request, response, variables, operationName, userId)) {
return;
}
Map<String, Object> mapOfContext =
Map.of(
"request", request,
@@ -254,8 +262,6 @@ public class GraphQLEndpoint extends HttpServlet {
if (operationName != null) {
contextBuilder.operationName(operationName);
}
String userId = GraphQLLoggerUtil.getUserId(request);
LocalDateTime startTime = LocalDateTime.now();
ExecutionInput executionInput = contextBuilder.build();
ExecutionResult executionResult = null;
Exception executionException = null;
@@ -271,23 +277,54 @@ public class GraphQLEndpoint extends HttpServlet {
} else if (executionException != null) {
errorMessage = executionException.getMessage();
}
if (WebAppUtils.getWebApplication() instanceof ApiCallInterceptor apiCallInterceptor) {
apiCallInterceptor.onApiCallEvent(
request,
variables,
CommonUtils.notEmpty(operationName), userId, startTime,
errorMessage,
API_PROTOCOL
);
}
notifyApiCallInterceptor(request, variables, operationName, userId, startTime, errorMessage);
}
if (executionResult != null) {
Map<String, Object> resJSON = executionResult.toSpecification();
String resString = gson.toJson(resJSON);
setDevelHeaders(request, response);
response.setContentType(GraphQLConstants.CONTENT_TYPE_JSON_UTF8);
response.getWriter().print(resString);
writeExecutionResult(request, response, executionResult);
}
}
protected boolean isQueryHandledBeforeExecution(
@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response,
@Nullable Map<String, Object> variables,
@Nullable String operationName,
@Nullable String userId
) throws IOException {
return false;
}
protected void writeExecutionResult(
@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response,
@NotNull ExecutionResult executionResult
) throws IOException {
Map<String, Object> resJSON = executionResult.toSpecification();
String resString = gson.toJson(resJSON);
setDevelHeaders(request, response);
response.setContentType(GraphQLConstants.CONTENT_TYPE_JSON_UTF8);
response.getWriter().print(resString);
}
protected void notifyApiCallInterceptor(
@NotNull HttpServletRequest request,
@Nullable Map<String, Object> variables,
@Nullable String operationName,
@Nullable String userId,
@NotNull LocalDateTime startTime,
@Nullable String errorMessage
) {
if (WebAppUtils.getWebApplication() instanceof ApiCallInterceptor apiCallInterceptor) {
apiCallInterceptor.onApiCallEvent(
request,
variables,
CommonUtils.notEmpty(operationName),
userId,
startTime,
errorMessage,
API_PROTOCOL
);
}
}
@@ -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.
@@ -27,6 +27,7 @@ import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.qm.QMConstants;
import org.jkiss.utils.CommonUtils;
@@ -122,6 +123,9 @@ public class GraphQLLoggerUtil {
if (value instanceof String sv && CommonUtils.isEmpty(sv)) {
continue;
}
if (value instanceof DBNNode node) {
value = node.getNodeUri();
}
if (value != null && !isSimple(value.getClass())) {
String stringValue;
@@ -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.
@@ -25,6 +25,8 @@ import org.jkiss.code.Nullable;
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 class CBClientEventProcessor {
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());
@@ -91,6 +104,13 @@ public class CBClientEventProcessor {
}
break;
}
case WSSessionCancelActionClientEvent.ID: {
if (webSession instanceof WebSession session) {
var cancelActionEvent = (WSSessionCancelActionClientEvent) clientEvent;
session.handleActionCancelledEvent(cancelActionEvent.getActionId());
}
break;
}
default:
var e = new DBWebException("Unknown client event: " + clientEvent.getId());
log.error(e.getMessage(), e);
@@ -24,7 +24,6 @@ import jakarta.websocket.HandshakeResponse;
import jakarta.websocket.server.HandshakeRequest;
import jakarta.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.ee11.websocket.jakarta.server.internal.JakartaWebSocketCreator;
import org.eclipse.jetty.http.BadMessageException;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
@@ -89,7 +88,7 @@ public class CBWebSocketServerConfigurator extends ServerEndpointConfig.Configur
throw new RuntimeException(e.getMessage(), e);
}
if (sec.getUserProperties().get(PROP_WEB_SESSION) == null) {
throw new BadMessageException("No web session found for websocket request");
throw new RuntimeException("No web session found for websocket request");
}
}
@@ -97,8 +96,8 @@ public class CBWebSocketServerConfigurator extends ServerEndpointConfig.Configur
private String getSessionId(@NotNull HandshakeRequest request) {
// complex auth uses bearer authentication
List<String> authHeaders = WSClientUtils.getHeaders(request.getHeaders(), HttpConstants.HEADER_AUTHORIZATION);
if (!CommonUtils.isEmpty(authHeaders) && authHeaders.get(0).startsWith("Bearer ")) {
return authHeaders.get(0).substring(7);
if (!CommonUtils.isEmpty(authHeaders) && authHeaders.getFirst().startsWith(HttpConstants.BEARER_PREFIX)) {
return authHeaders.getFirst().substring(7);
}
return request.getHttpSession() instanceof HttpSession httpSession ? httpSession.getId() : null;
}
@@ -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.
@@ -108,11 +108,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
}
protected static WebSession getWebSession(DataFetchingEnvironment env) throws DBWebException {
if (env.getGraphQlContext().getBoolean(CloudbeaverCliConstants.CLI_MODE)) {
return getSessionFromContextOrThrow(env);
}
return WebAppUtils.getWebApplication().getSessionManager().getWebSession(
GraphQLEndpoint.getServletRequestOrThrow(env), getServletResponse(env));
return getWebSession(env, true);
}
@Nullable
@@ -353,9 +349,13 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
}
String sessionId = GraphQLLoggerUtil.getSmSessionId(request);
String userId = GraphQLLoggerUtil.getUserId(request);
String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, method, args);
try {
String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, method, args);
log.debug("API > " + method.getName() + loggerMessage);
log.debug("API > " + method.getName() + loggerMessage);
} catch (Throwable e) {
log.error("Logging error", e);
}
setLogContext(method, args);
}
@@ -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.
@@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.rm.RMConstants;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
@@ -218,6 +219,14 @@ public interface DBWServiceCore extends DBWService {
@NotNull String id
) throws DBWebException;
@NotNull
Map<String, String> setObjectSettingsForDatasource(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String objectId,
@NotNull Map<String, String> settings
) throws DBException;
///////////////////////////////////////////
// Async tasks
@@ -163,6 +163,12 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
getArgumentVal(env, "id")
)
)
.dataFetcher("setObjectSettingsForDatasource", env -> getService(env).setObjectSettingsForDatasource(
getWebSession(env),
getProjectReference(env),
getArgumentVal(env, "id"),
getArgumentVal(env, "settings")
))
.dataFetcher("asyncTaskInfo", env -> getService(env).getAsyncTaskInfo(
getWebSession(env),
@@ -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.
@@ -58,12 +58,14 @@ import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettingsUtils;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.registry.project.BaseProjectSettings;
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
import org.jkiss.dbeaver.registry.settings.ProductSettingsRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
@@ -676,7 +678,7 @@ public class WebServiceCore implements DBWServiceCore {
WebConnectionInfo connectionInfo = project.getWebConnectionInfo(connectionId);
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer, true);
return connectionInfo;
}
@@ -795,6 +797,25 @@ public class WebServiceCore implements DBWServiceCore {
return connectionInfo;
}
@Override
@NotNull
public Map<String, String> setObjectSettingsForDatasource(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String objectId,
@NotNull Map<String, String> settings
) throws DBException {
WebSessionProjectImpl projectById = webSession.getProjectById(projectId);
if (projectById == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
BaseProjectSettings projectSettings = projectById.getProjectSettings();
projectSettings.setObjectSettings(SMObjectType.datasource, objectId, settings);
Map<String, String> objectSettings = projectSettings.getObjectSettings(SMObjectType.datasource, objectId);
return objectSettings == null ? new HashMap<>() : objectSettings;
}
@Override
public WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish)
throws DBWebException {
@@ -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.
@@ -63,11 +63,12 @@ public interface DBWServiceNavigator extends DBWService {
@Nullable Boolean recursive) throws DBWebException;
@WebAction
@NotNull
WebStructContainers getStructContainers(
String projectId,
WebConnectionInfo connectionInfo,
String contextId,
String catalog) throws DBWebException;
@NotNull String projectId,
@NotNull WebConnectionInfo connectionInfo,
@NotNull String contextId,
@Nullable String catalog) throws DBWebException;
@WebAction
String renameNode(
@@ -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.
@@ -60,7 +60,6 @@ import org.jkiss.utils.CommonUtils;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;
/**
* Web service implementation
@@ -314,12 +313,13 @@ public class WebServiceNavigator implements DBWServiceNavigator {
}
}
@NotNull
@Override
public WebStructContainers getStructContainers(
String projectId,
WebConnectionInfo connection,
String contextId,
String catalog
@NotNull String projectId,
@NotNull WebConnectionInfo connection,
@NotNull String contextId,
@Nullable String catalog
) throws DBWebException {
DBPDataSource dataSource = connection.getDataSource();
DBCExecutionContext executionContext = DBUtils.getDefaultContext(connection.getDataSource(), false);
@@ -344,9 +344,9 @@ public class WebServiceNavigator implements DBWServiceNavigator {
DBRProgressMonitor monitor = connection.getSession().getProgressMonitor();
List<? extends DBSObject> dbsObjects = this.getCatalogs(
monitor,
connection.getDataSourceContainer().getDataSource(),
contextDefaults);
monitor,
connection.getDataSourceContainer().getDataSource(),
contextDefaults);
for (DBSObject dbsObject : dbsObjects) {
if (!dataSource.getContainer().getNavigatorSettings().isShowSystemObjects()
@@ -404,26 +404,36 @@ public class WebServiceNavigator implements DBWServiceNavigator {
return structContainers;
}
protected List<? extends DBSObject> getCatalogs(DBRProgressMonitor monitor, DBSObject rootObject, DBCExecutionContextDefaults<?, ?> contextDefaults) throws DBWebException {
if (rootObject instanceof DBSObjectContainer) {
@NotNull
protected List<? extends DBSObject> getCatalogs(
@NotNull DBRProgressMonitor monitor,
@NotNull DBSObject rootObject,
@Nullable DBCExecutionContextDefaults<?, ?> contextDefaults
) throws DBWebException {
if (rootObject instanceof DBSObjectContainer objectContainer) {
try {
Collection<? extends DBSObject> objectsCollection;
if (rootObject instanceof DBSCatalog && contextDefaults != null && !contextDefaults.supportsCatalogChange()) {
objectsCollection = Collections.singletonList(contextDefaults.getDefaultCatalog());
} else {
objectsCollection = ((DBSObjectContainer) rootObject).getChildren(monitor);
objectsCollection = objectContainer.getChildren(monitor);
}
if (objectsCollection == null) {
return Collections.emptyList();
}
return new ArrayList<>(objectsCollection);
} catch (DBException e) {
throw new DBWebException("Error reading context defaults", e);
// return Collections.emptyList();
}
}
return Collections.emptyList();
}
@Nullable
protected WebNavigatorNodeInfo getNodeFromObject(WebSession session, DBSObject object) throws DBWebException {
protected WebNavigatorNodeInfo getNodeFromObject(
@NotNull WebSession session,
@NotNull DBSObject object
) throws DBWebException {
DBRProgressMonitor monitor = session.getProgressMonitor();
DBNNode node = session.getNavigatorModelOrThrow().getNodeByObject(monitor, object, false);
@@ -454,10 +464,10 @@ public class WebServiceNavigator implements DBWServiceNavigator {
}
return node.getNodeItemPath();
}
if (node instanceof DBNDatabaseNode) {
if (node instanceof DBNDatabaseNode dbNode) {
return renameDatabaseObject(
session,
(DBNDatabaseNode) node,
dbNode,
CommonUtils.trim(CommonUtils.notEmpty(newName)));
}
throw new DBException("Rename is not supported");
@@ -466,7 +476,11 @@ public class WebServiceNavigator implements DBWServiceNavigator {
}
}
private void renameConnectionFolder(@NotNull WebSession session, DBNNode node, @NotNull String newName) throws DBException {
private void renameConnectionFolder(
@NotNull WebSession session,
DBNNode node,
@NotNull String newName
) throws DBException {
WebConnectionFolderUtils.validateConnectionFolder(newName);
DBNNode[] children = ((DBNLocalFolder) node).getLogicalParent().getChildren(session.getProgressMonitor());
if (children != null) {
@@ -480,7 +494,11 @@ public class WebServiceNavigator implements DBWServiceNavigator {
node.rename(session.getProgressMonitor(), newName);
}
private void renameRmResourceNode(@NotNull WebSession session, DBNNode node, @NotNull String newName) throws DBException {
private void renameRmResourceNode(
@NotNull WebSession session,
DBNNode node,
@NotNull String newName
) throws DBException {
if (newName.contains("/") || newName.contains("\\")) {
throw new DBWebException("New node name has prohibited symbols: \\ /");
}
@@ -496,9 +514,9 @@ public class WebServiceNavigator implements DBWServiceNavigator {
private void addRmMoveEvent(
@NotNull WebSession session,
String projectId,
String oldResourcePath,
String newResourcePath
@NotNull String projectId,
@NotNull String oldResourcePath,
@NotNull String newResourcePath
) {
WebEventUtils.addRmResourceUpdatedEvent(
projectId,
@@ -566,8 +584,7 @@ public class WebServiceNavigator implements DBWServiceNavigator {
}
} else if (node instanceof DBNLocalFolder) {
node.getOwnerProject().getDataSourceRegistry().removeFolder(((DBNLocalFolder) node).getFolder(), false);
} else if (node instanceof DBNResourceManagerResource) {
DBNResourceManagerResource rmResource = ((DBNResourceManagerResource) node);
} else if (node instanceof DBNResourceManagerResource rmResource) {
String resourceProjectId = rmResource.getResourceProject().getId();
String resourcePath = rmResource.getResourceFolder();
session.getRmController().deleteResource(resourceProjectId, resourcePath, true);
@@ -589,14 +606,18 @@ public class WebServiceNavigator implements DBWServiceNavigator {
}
}
private void checkProjectEditAccess(DBNNode node, WebSession session) throws DBException {
private void checkProjectEditAccess(@NotNull DBNNode node, @NotNull WebSession session) throws DBException {
BaseWebProjectImpl project = (BaseWebProjectImpl) node.getOwnerProject();
if (project == null || !hasNodeEditPermission(session, node, project.getRMProject())) {
throw new DBException("Access denied");
}
}
private boolean hasNodeEditPermission(WebSession session, DBNNode node, RMProject rmProject) {
private boolean hasNodeEditPermission(
@NotNull WebSession session,
@NotNull DBNNode node,
@NotNull RMProject rmProject
) {
if (node instanceof DBNDataSource || node instanceof DBNLocalFolder) {
return SMUtils.hasProjectPermission(session, rmProject, RMProjectPermission.DATA_SOURCES_EDIT);
} else if (node instanceof DBNAbstractResourceManagerNode) {
@@ -644,7 +665,7 @@ public class WebServiceNavigator implements DBWServiceNavigator {
if (parentFolder != null) {
List<String> siblings = Arrays.stream(parentFolder.getChildren())
.map(DBPDataSourceFolder::getName)
.collect(Collectors.toList());
.toList();
if (siblings.contains(node.getName())) {
throw new DBWebException("Node " + folderNodePath + " contains folder with name '" + node.getName() + "'");
}
@@ -655,9 +676,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
);
node.getOwnerProject().getDataSourceRegistry().checkForErrors();
WebServiceUtils.refreshDatabases(session, node.getOwnerProject().getId());
} else if (node instanceof DBNResourceManagerResource) {
} else if (node instanceof DBNResourceManagerResource rmOldNode) {
boolean rmNewNode = folderNode instanceof DBNAbstractResourceManagerNode;
DBNResourceManagerResource rmOldNode = (DBNResourceManagerResource) node;
if (!rmNewNode) {
throw new DBWebException("Navigator node '" + folderNodePath + "' is not a resource manager node");
}
@@ -665,8 +685,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
String projectId = rmOldNode.getResourceProject().getId();
// Get paths from nodes
String newPath = rmOldNode.getResource().getName();
if (folderNode instanceof DBNResourceManagerResource) {
newPath = ((DBNResourceManagerResource) folderNode).getResourceFolder() + "/" + newPath;
if (folderNode instanceof DBNResourceManagerResource rmr) {
newPath = rmr.getResourceFolder() + "/" + newPath;
}
String resourcePath = rmOldNode.getResourceFolder();
session.getRmController().moveResource(projectId, resourcePath, newPath);
@@ -710,7 +730,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
throw new DBException("Node " + node.getNodeUri() + " rename is not supported");
}
public DBCExecutionContext getCommandExecutionContext(DBSObject object) {
@Nullable
public DBCExecutionContext getCommandExecutionContext(@NotNull DBSObject object) {
DBCExecutionContext executionContext = DBUtils.getDefaultContext(object, true);
if (executionContext == null) {
// It may happen in case of lazy context initialization
@@ -72,20 +72,24 @@ public interface DBWServiceSQL extends DBWService {
@NotNull WebSession session,
@NotNull List<String> nodePathList) throws DBWebException;
@NotNull
@WebAction
String generateEntityQuery(
@NotNull WebSession session,
@NotNull String generatorId,
@NotNull Map<String, Object> options,
@NotNull List<String> nodePathList) throws DBWebException;
@NotNull List<String> nodePathList,
@NotNull WebSQLGeneratorOptions options
) throws DBWebException;
@NotNull
@WebAction
String sqlGenerateResultSetQuery(
@NotNull WebSession session,
@NotNull WebSQLContextInfo sqlContext,
@NotNull String generatorId,
@NotNull String resultsId,
@NotNull List<WebSQLResultsRow> selectedRows
@NotNull List<WebSQLResultsRow> selectedRows,
@NotNull WebSQLGeneratorOptions options
) throws DBWebException;
@WebAction
@@ -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.
@@ -17,9 +17,12 @@
package io.cloudbeaver.service.sql;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.exec.plan.DBCPlan;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode;
import org.jkiss.utils.CommonUtils;
import java.util.*;
@@ -30,18 +33,45 @@ public class WebSQLExecutionPlan {
private static final Log log = Log.getLog(WebSQLExecutionPlan.class);
@NotNull
private final WebSession webSession;
@NotNull
private final DBCPlan plan;
public WebSQLExecutionPlan(WebSession webSession, DBCPlan plan) {
public WebSQLExecutionPlan(@NotNull WebSession webSession, @NotNull DBCPlan plan) {
this.webSession = webSession;
this.plan = plan;
}
@NotNull
public DBCPlan getPlan() {
return plan;
}
public String getQuery() {
return plan.getQueryString();
}
public boolean isHasCost() {
return CommonUtils.toBoolean(plan.getPlanFeature(DBCPlanCostNode.FEATURE_PLAN_COST));
}
public boolean isHasRows() {
return CommonUtils.toBoolean(plan.getPlanFeature(DBCPlanCostNode.FEATURE_PLAN_ROWS));
}
public boolean isHasDuration() {
return CommonUtils.toBoolean(plan.getPlanFeature(DBCPlanCostNode.FEATURE_PLAN_DURATION));
}
public String getDurationMeasure() {
if (!isHasDuration()) {
return null;
}
Object value = plan.getPlanFeature(DBCPlanCostNode.PLAN_DURATION_MEASURE);
return value == null ? null : String.valueOf(value);
}
public WebSQLExecutionPlanNode[] getNodes() {
Map<String, Object> options = new LinkedHashMap<>();
Map<DBCPlanNode, String> idMap = new IdentityHashMap<>();
@@ -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.
@@ -19,7 +19,9 @@ package io.cloudbeaver.service.sql;
import io.cloudbeaver.model.WebPropertyInfo;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode;
import org.jkiss.dbeaver.runtime.properties.ObjectPropertyDescriptor;
import org.jkiss.dbeaver.runtime.properties.PropertyCollector;
@@ -73,12 +75,32 @@ public class WebSQLExecutionPlanNode {
return node.getNodeDescription();
}
@Nullable
public Double getCost() {
return node instanceof DBCPlanCostNode cn && cn.getNodeCost() != null ? cn.getNodeCost().doubleValue() : null;
}
@Nullable
public Number getRowCount() {
return node instanceof DBCPlanCostNode cn ? cn.getNodeRowCount() : null;
}
@Nullable
public Double getDuration() {
return node instanceof DBCPlanCostNode cn && cn.getNodeDuration() != null ? cn.getNodeDuration().doubleValue() : null;
}
@Nullable
public Double getPercent() {
return node instanceof DBCPlanCostNode cn && cn.getNodePercent() != null ? cn.getNodePercent().doubleValue() : null;
}
@NotNull
public WebPropertyInfo[] getProperties() {
PropertyCollector propertyCollector = new PropertyCollector(node, false);
propertyCollector.collectProperties();
return Arrays.stream(propertyCollector.getProperties())
.filter(p -> !(p instanceof ObjectPropertyDescriptor && ((ObjectPropertyDescriptor) p).isHidden()))
.filter(p -> !(p instanceof ObjectPropertyDescriptor && p.isHidden()))
.map(p -> new WebPropertyInfo(webSession, p, propertyCollector)).toArray(WebPropertyInfo[]::new);
}
@@ -0,0 +1,23 @@
/*
* 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.service.sql;
public record WebSQLGeneratorOptions(
boolean useFullyQualifiedNames,
boolean compactSql
) {
}
@@ -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.
@@ -116,8 +116,7 @@ public class WebSQLUtils {
Map<String, Object> map = createMapOfType(WebSQLConstants.VALUE_TYPE_COLLECTION);
map.put("value", items);
return map;
} else if (value instanceof DBDComposite) {
DBDComposite composite = (DBDComposite)value;
} else if (value instanceof DBDComposite composite && composite.getAttributes().length > 0) {
Map<String, Object> struct = new LinkedHashMap<>();
for (DBSAttributeBase attr : composite.getAttributes()) {
struct.put(attr.getName(), makeWebCellValue(session, attr, composite.getAttributeValue(attr), dataFormat));
@@ -90,8 +90,9 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
getService(env).generateEntityQuery(
getWebSession(env),
getArgumentVal(env, "generatorId"),
getArgumentVal(env, "options"),
getArgumentVal(env, "nodePathList"))
getArgumentVal(env, "nodePathList"),
getGeneratorOptions(env)
)
)
.dataFetcher("sqlGenerateResultSetQuery", env ->
getService(env).sqlGenerateResultSetQuery(
@@ -99,7 +100,8 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
getSQLContext(env),
getArgumentVal(env, "generatorId"),
getArgumentVal(env, "resultsId"),
getResultsRow(env, "selectedRows")
getResultsRow(env, "selectedRows"),
getGeneratorOptions(env)
)
)
.dataFetcher("sqlParseScript", env ->
@@ -415,4 +417,16 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
return mapList.stream().map(WebSQLResultsRow::new).collect(Collectors.toList());
}
@NotNull
private static WebSQLGeneratorOptions getGeneratorOptions(@NotNull DataFetchingEnvironment env) {
Map<String, Object> optionsMap = getArgument(env, "generatorOptions");
if (optionsMap == null) {
return new WebSQLGeneratorOptions(true, false);
}
return new WebSQLGeneratorOptions(
CommonUtils.toBoolean(optionsMap.get("useFullyQualifiedNames")),
CommonUtils.toBoolean(optionsMap.get("compactSql"))
);
}
}
@@ -25,12 +25,10 @@ import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
import org.jkiss.dbeaver.model.data.DBDResultSetDataProvider;
import org.jkiss.dbeaver.model.data.DBDRowIdentifier;
import org.jkiss.dbeaver.model.data.DBDValueRow;
import org.jkiss.dbeaver.model.data.*;
import org.jkiss.dbeaver.model.data.hints.DBDValueHintContext;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.impl.data.ResultSetHintContext;
import org.jkiss.dbeaver.model.struct.DBSEntity;
import org.jkiss.dbeaver.model.struct.DBSObject;
@@ -43,6 +41,7 @@ public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DB
private final String resultsId;
private final WebSQLContextInfo contextInfo;
private final List<WebSQLResultsRow> selectedRows;
private final DBDValueHintContext hintContext;
WebDBDResultSetDataProvider(
@NotNull String resultsId,
@@ -52,6 +51,7 @@ public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DB
this.resultsId = resultsId;
this.contextInfo = contextInfo;
this.selectedRows = selectedRows;
this.hintContext = new ResultSetHintContext(() -> null, () -> null);
}
@NotNull
@@ -122,15 +122,20 @@ public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DB
@NotNull DBDAttributeBinding attribute,
@NotNull DBDValueRow row,
@Nullable int[] rowIndexes,
@Nullable ResultSetValuePath valuePath,
boolean retrieveDeepestCollectionElement
) throws DBWebException {
return DBUtils.getAttributeValue(attribute, getAttributes(), row.getValues());
if (valuePath != null) {
return DBUtils.getRowValueByPath(row, valuePath);
} else {
return DBUtils.getAttributeValue(attribute, getAttributes(), row.getValues());
}
}
@Nullable
@NotNull
@Override
public DBDValueHintContext getHintContext() {
return null;
return hintContext;
}
@Nullable
@@ -243,23 +243,37 @@ public class WebServiceSQL implements DBWServiceSQL {
return SQLGeneratorConfigurationRegistry.getInstance().getApplicableGenerators(objectList, session).toArray(new SQLGeneratorDescriptor[0]);
}
@NotNull
@Override
public String generateEntityQuery(@NotNull WebSession session, @NotNull String generatorId, @NotNull Map<String, Object> options, @NotNull List<String> nodePathList) throws DBWebException {
public String generateEntityQuery(
@NotNull WebSession session,
@NotNull String generatorId,
@NotNull List<String> nodePathList,
@NotNull WebSQLGeneratorOptions options
) throws DBWebException {
List<DBSObject> objectList = getObjectListFromNodeIds(session, nodePathList);
return createAndRunGenerator(session, generatorId, objectList);
return createAndRunGenerator(
session, generatorId, objectList,
options.useFullyQualifiedNames(), options.compactSql()
);
}
@NotNull
@Override
public String sqlGenerateResultSetQuery(
@NotNull WebSession webSession,
@NotNull WebSQLContextInfo sqlContext,
@NotNull String generatorId,
@NotNull String resultsId,
@NotNull List<WebSQLResultsRow> selectedRows
@NotNull List<WebSQLResultsRow> selectedRows,
@NotNull WebSQLGeneratorOptions options
) throws DBWebException {
checkAndFillTruncatedData(sqlContext, resultsId, selectedRows);
WebDBDResultSetDataProvider dataProvider = new WebDBDResultSetDataProvider(resultsId, sqlContext, selectedRows);
return createAndRunGenerator(webSession, generatorId, Collections.singletonList(dataProvider));
return createAndRunGenerator(
webSession, generatorId, Collections.singletonList(dataProvider),
options.useFullyQualifiedNames(), options.compactSql()
);
}
private void checkAndFillTruncatedData(
@@ -289,10 +303,13 @@ public class WebServiceSQL implements DBWServiceSQL {
dataKind.equals(DBPDataKind.BINARY);
}
@NotNull
private String createAndRunGenerator(
@NotNull WebSession session,
@NotNull String generatorId,
@NotNull List<DBSObject> objectList
@NotNull List<DBSObject> objectList,
boolean useFullyQualifiedNames,
boolean compactSql
) throws DBWebException {
SQLGeneratorDescriptor generator = SQLGeneratorConfigurationRegistry.getInstance().getGenerator(generatorId);
if (generator == null) {
@@ -300,6 +317,8 @@ public class WebServiceSQL implements DBWServiceSQL {
}
try {
SQLGenerator<DBSObject> generatorInstance = generator.createGenerator(objectList);
generatorInstance.setFullyQualifiedNames(useFullyQualifiedNames);
generatorInstance.setCompactSQL(compactSql);
generatorInstance.run(session.getProgressMonitor());
return generatorInstance.getResult();
} catch (DBException e) {
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Administration
Bundle-SymbolicName: io.cloudbeaver.service.admin;singleton:=true
Bundle-Version: 1.0.142.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.146.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.admin</artifactId>
<version>1.0.142-SNAPSHOT</version>
<version>1.0.146-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -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.
@@ -163,7 +163,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
if (userName.isEmpty()) {
throw new DBWebException("Empty user name");
}
String userId = userName.toLowerCase();
String userId = userName.trim().toLowerCase();
try {
GeneralUtils.validateResourceNameUnconditionally(userId);
} catch (DBException e) {
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Authentication
Bundle-SymbolicName: io.cloudbeaver.service.auth;singleton:=true
Bundle-Version: 1.0.142.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.146.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.auth</artifactId>
<version>1.0.142-SNAPSHOT</version>
<version>1.0.146-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Data Transfer
Bundle-SymbolicName: io.cloudbeaver.service.data.transfer;singleton:=true
Bundle-Version: 1.0.143.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.147.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.data.transfer</artifactId>
<version>1.0.143-SNAPSHOT</version>
<version>1.0.147-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - File System
Bundle-SymbolicName: io.cloudbeaver.service.fs;singleton:=true
Bundle-Version: 1.0.60.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.64.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.fs</artifactId>
<version>1.0.60-SNAPSHOT</version>
<version>1.0.64-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -35,6 +35,7 @@ import org.jkiss.dbeaver.runtime.DBWorkbench;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Arrays;
@@ -213,6 +214,8 @@ public class WebServiceFS implements DBWServiceFS {
oldParentNode.removeChildResource(oldNode.getPath());
parentNode.addChildResource(to);
return new FSFile(parentNode.getChild(to));
} catch (NoSuchFileException e) {
throw new DBWebException("File not found. Please refresh the catalog and check if file exists.");
} catch (Exception e) {
throw new DBWebException("Failed to move file: " + e.getMessage(), e);
}
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Name: Cloudbeaver Web Service - LDAP
Bundle-Vendor: DBeaver Corp
Bundle-SymbolicName: io.cloudbeaver.service.ldap.auth;singleton:=true
Bundle-Version: 1.0.25.qualifier
Bundle-Release-Date: 20260406
Bundle-Version: 1.0.29.qualifier
Bundle-Release-Date: 20260601
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.ldap.auth</artifactId>
<version>1.0.25-SNAPSHOT</version>
<version>1.0.29-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>

Some files were not shown because too many files have changed in this diff Show More