Compare commits

..
246 Commits
Author SHA1 Message Date
AinurandEvgenia Bezborodova e1887714ab CB-5737 global project path fix (#2955)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-10-01 16:52:43 +00:00
serge-rider f5ac3cfe2a dbeaver/pro#1441 Redundant parameter remove 2024-10-01 17:48:24 +02:00
434a988919 dbeaver/pro#1441 Universal Database Tunnel POC (#2941)
* dbeaver/pro#1441 Universal Database Tunnel POC

* dbeaver/pro#1441 Resolve data source on the server side

* dbeaver/pro#1441 Use service binding for registering web sockets

* dbeaver/pro#1441 Fix compile

* dbeaver/pro#1441 Construct WebSocket endpoint from service endpoint

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: serge-rider <serge@dbeaver.com>
2024-10-01 17:42:28 +02:00
AinurandDaria Marutkina 3fbc227734 CB-5559 include root uri in redirect urls (#2950)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-10-01 12:53:12 +00:00
AlexeyandEvgenia Bezborodova bb9a62da63 CB-5295 set enable flag on create user (#2940)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-30 22:45:30 +03:00
Alexander Skoblikov 34c6e6c9be fix vs-code compilation (#2953) 2024-09-30 16:58:39 +00:00
Alexander Skoblikov b35e3f83ed fix test (#2951) 2024-09-30 15:42:16 +00:00
a42c7dc8de CB-5589. Remove script and sqllite database config (#2919)
* CB-5589. Remove script and sqllite database config

* CB-5589. Remove script and sqllite database config

* CB-5589 remove sample database

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-30 15:16:48 +00:00
eb33e0e895 CB-5570 do not load data sources in web session init (#2887)
* CB-5570 do not load data sources in web session init

* CB-5570 extract methods about web connection info from web session

* CB-5570 remove accessible connections from web session

* CB-5570 add javadoc

* CB-5570 Merge conflicts resolve

* CB-5570 return emply list for template connections in te

* chore: reorganize localization for connections

---------

Co-authored-by: serge-rider <serge@dbeaver.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-30 15:15:35 +00:00
alexandDaria Marutkina c3c15bf7cc CB-5719 always treat form as changed in easy config (#2946)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-09-30 16:33:11 +03:00
serge-rider 6604b0887c dbeaver/dbeaver-vscode#16 Platform shutdown fix 2024-09-30 14:54:36 +02:00
Alexander Skoblikovandmr-anton-t 735024b57b dbeaver/dbeaver-vscode#16 fix SQL processor, server port cli arg (#2933)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-30 14:23:01 +02:00
AnastasiyaandEvgenia Bezborodova 3118eac266 CB-5644 change automatically created provider description (#2937)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-30 10:32:08 +02:00
alexandEvgenia Bezborodova 38445f3843 CB-5636 fix resource lag (#2942)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-30 11:14:18 +03:00
sergeyteleshev 01d08fc3ce CB-5709 user create button in settings preloads required reso… (#2936)
* CB-5709 hotfix: user create button in settings preloads required resources

* CB-5709 inverts logic

* CB-5709 fixes tab for TE

* CB-5709 fix for origin info form
2024-09-30 11:13:06 +03:00
sergeyteleshevandEvgenia Bezborodova 9bc6bd022e CB-5625 Show only enabled identity providers in configuration section (#2927)
* CB-5625 makes create auth providers list include only enabled auth providers in checkbox

* Revert "CB-5625 makes create auth providers list include only enabled auth providers in checkbox"

This reverts commit 4b2ac9935f.

* CB-5625 adds disabled providers logic to identity providers

* CB-5625 refactors form loaded task

* CB-5625 adds link for redirect to the server configuration settings

* СB-5625 cleanup

* CB-5625 moves message to the top of the auth providers page

* CB-5625 pr fixes

* CB-5625 cleanup

* CB-5578 pr fixes

* CB-5625 adds tip for create identity provider table

* CB-5625 reverts tip message

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-27 13:21:11 +03:00
AlexeyandEvgenia Bezborodova cf764f5807 CB-4192 fix: users loading (#2939)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-27 12:04:39 +03:00
AlexeyandEvgenia Bezborodova 0bf6783d00 CB-5446 chore: keyboard navigation improvements (#2935)
* chore: keyboard navigation improvements

* CB-5446 chore: use theme color for outline

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-26 19:46:23 +03:00
0e3da49b23 CB-5652 hide data source properties if user does not have edit permis… (#2932)
* CB-5652 hide data source properties if user does not have edit permissions

* CB-5652 return only name property for data source

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-09-26 16:14:02 +00:00
serge-rider f84bd6040f Merge remote-tracking branch 'origin/devel' into devel 2024-09-26 12:42:46 +02:00
serge-rider 6339bee0dc Remove legacy code 2024-09-26 12:40:21 +02:00
8f54e759dd CB-4541 feat: tree filter (#2908)
* CB-4541 feat: tree filter

* CB-4541 feat: tree empty placeholders

* CB-4541 fix: settings overflow scroll effect

* CB-4541 fix: settings groups size

* CB-4541 fix: sync groups when filtering

* CB-4541 chore: performance optimization

* chore: review fixes

* chore: replace inline styles

* chore: replace inline styles

* chore: hide extra settings from UI

* chore: hide groups view from settings

* fix: add override options to devtools

* fix: trim filter in settings search

* chore: localization

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-25 19:46:13 +03:00
Alexey 5f53e0ffa2 fix: windows wildcard path (#2931) 2024-09-25 16:37:30 +03:00
fe020f8f7d CB-4652 migrate server configuration form (#2916)
* CB-4652 migrate server configuration form

* CB-4652 review fixes

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-25 11:46:21 +03:00
Serge Riderandkseniaguzeeva 4b9e1c8b94 dbeaver/pro#3345 vfs refactoring (#2928)
* dbeaver/pro#3345 Navigator model refactoring

* dbeaver/pro#3345 Navigator model refactoring

* dbeaver/pro#3345 Get rid of org.eclipse.core.resources

* dbeaver/pro#3345 SQL dialect model refactoring

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-09-24 16:37:09 +02:00
alexandEvgenia Bezborodova dc5592d052 CB-5162 fix filter at the top (#2925)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-24 11:46:20 +03:00
sergeyteleshevandmr-anton-t 1746d91072 CB-4661 remove includes concept from resources api (#2910)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-23 18:22:05 +03:00
Evgenia Bezborodova d230275768 Merge pull request #2930 from dbeaver/EvgeniaBzzz-patch-1
Update README_24-2-1.md
2024-09-23 12:47:44 +03:00
Evgenia Bezborodova 3b3bb147b7 Update README_24-2-1.md 2024-09-23 12:41:39 +03:00
Alexey 6ad148850d refactor: migrate to pure esm CB-5684 (#2929)
* refactor: migrate to pure esm

* chore: revert `useDefineForClassFields` tsconf

* chore: remove patch.js
2024-09-21 07:06:37 +03:00
Alexey a4130804bf chore: vscode dev env dbeaver/dbeaver-vscode#13 (#2918)
* chore: vscode dev env dbeaver/dbeaver-vscode#15

* chore: update target

* chore: update launch configurations

* chore: revert extensions recommendations
2024-09-20 11:48:40 +03:00
mayerro 37d06ecebd dbeaver/dbeaver-devops#1401 removed commit message validator action 2024-09-19 17:39:35 +02:00
b869bddded CB-5045 move configs to model package (#2705)
* CB-5045 move configs to model package

* CB-5045 jetty 12 fix

* CB-5045 fix conflicts

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-09-19 10:48:30 +00:00
Alexander Skoblikovandmr-anton-t efb42d33a7 Dbeaver/dbeaver vscode#3 remove redundunt plugins (#2891)
* CB-5530 wip

* dbeaver-vscode#3 cleanup servlets

* dbeaver-vscode#3 endpoint fixes

* dbeaver-vscode#3 resolve conflicts

* dbeaver-vscode#3 fix conflict

* dbeaver-vscode# jetty 12 conflict fixes

* dbeaver-vscode#3 servlets filter

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-19 09:14:23 +00:00
Serge Rider 90acaaf00e dbeaver/pro#3336 RCP model refactoring. Remove VFS from base model (#2913)
* dbeaver/pro#3336 RCP model refactoring. Remove VFS from base model

* dbeaver/pro#3336 Simplify DBNNodeWithResource

* dbeaver/pro#3336 Web node info fix

* dbeaver/pro#3336 Code style

* dbeaver/pro#3336 Fix node project get
2024-09-19 08:28:15 +02:00
Anastasiya 46309e9505 Update README.md link (#2923) 2024-09-18 13:58:39 +00:00
serge-rider aebb2d47ef Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2024-09-18 15:41:09 +02:00
serge-rider 12e0107617 24.2.2 version bump 2024-09-18 15:40:15 +02:00
3c5aa6b7e8 CB-5658 CB-5659 fix: pagination resolving (#2922)
* CB-5658 CB-5659 fix: pagination resolving

* CB-5658 fix resources pages

* CB-5667 fix: node rename behavior

* CB-5658 chore: refactor repeated code

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-09-18 16:17:59 +03:00
Vladimir 4df7e01d19 Merge pull request #2915 from dbeaver/readme-img-update
dbeaver/tech-docs#607 updated images in README.md
2024-09-18 08:38:59 +02:00
daelynum 801a55cd38 Merge branch 'devel' into readme-img-update
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2024-09-18 08:28:18 +02:00
Serge Rider 252ff71f03 24.2.1 version bump 2024-09-17 20:46:54 +02:00
sergeyteleshevandDaria Marutkina 2d1bde22a2 Cb 5562 Fix bad this.setState for the new form API (#2903)
* CB-5478 adds useAdministrationUserFormState with flexible id field

* CB-5478 simplifies logic fork form state hooks

* CB-5562 refactors form state and form parts

* CB-5562 fixes disabled param for formState

* CB-5562 comments cleanup

* CB-5562 fixes getting of exceptions

* CB-5562 baseform bad set state fix

* CB-5562 removes load and configure method for forms

* CB-5562 reverts some state.exception changes

* CB-5562 removes bad set state from user form

* CB-5562 cleanup

* CB-5562 cleanup

* CB-5562 removes bad set state from user form

* CB-5562 fixes bad set state for user profile

* CB-5562 pr fixes

* CB-5562 pr fixes

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-09-17 20:14:34 +03:00
4f0db5b854 CB-4896 migrate to jetty 12 (#2847)
* CB-4896 migrate to jetty 12

* CB-4896 fix root uri

* CB-4896 fix proxy handler paths

* CB-4896 resolve conflicts

* CB-4896 fix hidden gql errors

* CB-4896 redirect welcome mode (redirect from '/' to index.html)

* CB-4896 fix url 'blinking'

---------

Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-17 16:50:04 +00:00
5b527872bd CB-4095. Added env variables for configurations parameters (#2905)
* CB-4095. Added env variables for configurations parameters

* CB-4095. Refactor after review

* CB-4095. Refactor after review, added sub group for envs

* CB-4095. Remove unusable env variable

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-09-17 16:30:19 +00:00
alexandEvgenia Bezborodova 30e74ce09f CB-5450 purge cache if quota error happens (#2917)
* CB-5450 purge cache if quota error happens

* CB-5450 cache only images from the same origin

* CB-5450 change window to self

* CB-5450 revert purgeOnQuotaError

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-17 16:44:44 +03:00
Mikhailov Grigorii 3ca9904631 Merge pull request #2920 from dbeaver/dbeaver/dbeaver-devops#1483-fix-critical-cve-docker-upgrade
dbeaver/dbeaver-devops#1483 Added docker apt-get upgrade
2024-09-17 14:27:55 +02:00
Greg Miller ea2246af31 dbeaver/dbeaver-devops#1483 Remove sed before apt-get 2024-09-17 14:09:01 +02:00
Greg Miller 12e1fb57d7 dbeaver/dbeaver-devops#1483 Added docker apt-get upgrade 2024-09-17 14:04:02 +02:00
03d0f26530 CB-5391 remove controller from the plugin-connections-administration (#2876)
* CB-5391 remove controller from the plugin-connections-administration

* CB-5391 remove use controller

* CB-5391 review fixes

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>
2024-09-16 18:17:47 +03:00
AlexeyandEvgenia Bezborodova 9e657d2280 CB-5511 fix: pagination (#2906)
* CB-5511 fix: pagination

* CB-5511 chore: remove unused code

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-16 17:18:27 +03:00
daelynum 461e251753 dbeaver/tech-docs#607 updated images in README.md 2024-09-16 14:29:02 +02:00
daelynum e54bfb3154 Merge branch 'devel' into readme-img-update
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2024-09-16 14:10:55 +02:00
sergeyteleshevandmr-anton-t 6e575d3e7e CB-5478 Add an ability to new forms to edit formState id (#2885)
* CB-5478 adds useAdministrationUserFormState with flexible id field

* CB-5478 simplifies logic fork form state hooks

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-16 14:22:28 +03:00
Anastasiya 24ff77de47 Merge branch 'devel' into readme-img-update 2024-09-13 18:14:37 +03:00
daelynum 5ce49faea0 dbeaver/tech-docs#607 updated images in README.md 2024-09-13 17:09:37 +02:00
d2b6734dd3 Chinese localization (#2869)
* Add or improve Chinese translations

* Add or improve Chinese translations

* chore: Update Chinese translations

* chore: correct some translation

* fix: add mapping for all new zh files

---------

Co-authored-by: 李飞 <lif@tongfun.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-09-13 14:08:33 +00:00
Anastasiya e62943c548 dbeaver/pro#3333 add contributions info to README.md (#2912)
* dbeaver/pro#3333 add contributions info to README.md

* dbeaver/pro#3333 add info about localization

* dbeaver/pro#3333 fix sentence

* dbeaver/pro#3333 update file

* dbeaver/pro#3333 Update README.md
2024-09-13 15:27:10 +02:00
Alexander Skoblikovandkseniaguzeeva ceefea48c5 CB-5587 override default jetty session handler to add ability to use … (#2880)
* CB-5587 override default jetty session handler to add ability to use dynamic setSecure flag

* CB-5587 handle null server url

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-09-12 12:48:16 +00:00
638e5bc97b CB-5274. Added new link for download metadata file (#2900)
* CB-5274. Added new link for download metadata file

* CB-5274. Refactor after review

* CB-5274 add entityIdLink field

* CB-5274. Rename property

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-09-11 16:10:26 +00:00
Alexey 31cbac1c9c CB-5641 fix: skip version check error (#2907) 2024-09-11 15:37:37 +02:00
alexandkseniaguzeeva bb7a5c384c CB-5583 prefetch notification icons (#2878)
* CB-5583 prefetch notification icons

* CB-5583 prefetch small icons

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-09-11 15:50:32 +03:00
AnastasiyaandDaria Marutkina 611d06b2f8 CB-5412 update SQL Server driver to 12.8.0 (#2886)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-09-11 09:35:39 +00:00
Serge Rider e0d2d367dc dbeaver/pro#3077 refactor rcp (#2902)
* dbeaver/pro#3077 Refactor RCP resources

* dbeaver/pro#3077 Refactor RCP resources

* dbeaver/pro#3077 Refactor RCP resources

* dbeaver/pro#3077 Deps fix + replace IResource with NIO path
2024-09-09 17:14:40 +02:00
Georgii b2967257e2 dbeaver-infra#126 add bundle-less test classes to iml generation & docs improvements & debug config (#2901) 2024-09-09 10:43:29 +02:00
Alexander SkoblikovandDaria Marutkina 6af5a32a9d CB-5617 disable array editing (#2895)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-09-05 10:03:22 +00:00
Alexeyandmr-anton-t 8467a592e3 CB-5334 chore: update deps (#2883)
* CB-5334 chore: update deps

* CB-5334 chore: update deps again

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-09-04 19:33:51 +03:00
DenisSinelnikovandDaria Marutkina 0374ddb929 CB-5599. Restricted editing firestore arrays (#2889)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-09-04 15:44:06 +00:00
Alexander Skoblikov 7b5c10b9e2 CB-5602 add flag to force process event (#2888) 2024-09-03 16:09:56 +00:00
Daria Marutkina af31c5cf60 Merge pull request #2884 from dbeaver/dariamarutkina-patch-1
CB_2420 chore: update README
2024-09-02 12:35:09 +02:00
Daria Marutkina 805ae26c3c CB_2420 chore: update README 2024-09-02 12:09:16 +02:00
Alexey f565864124 CB-5228 fix: access token name (#2684)
* CB-5228 fix: access token name

* fix: remove lint triggers
2024-08-30 15:37:12 +03:00
alex a69e760c06 CB-5572 preload lisense status on product tab activate (#2874)
* CB-5572 preload lisense status on product tab activate

* CB-5572 await load
2024-08-28 14:25:41 +03:00
serge-rider cb972cb299 24.2.1 version bump 2024-08-26 19:42:23 +02:00
sergeyteleshevandAleksei Potsetsuev 74aa8c7980 CB-5503 Login form - incorrect password is cleared from the form after pressing Enter (#2853)
* CB-5503 fix: Prevent form submission from erasing password input value

* feat: Add form submission handling to AuthDialog

* Revert "feat: Add form submission handling to AuthDialog"

This reverts commit de19e67c8d.

* Revert "CB-5503 fix: Prevent form submission from erasing password input value"

This reverts commit a5a74ae558.

* CB-5503 adds useValidationStyles for the form inputs

* Revert "CB-5503 adds useValidationStyles for the form inputs"

This reverts commit 7702fdc280.

* CB-5503 removes resets for useForm submit event

* fix: form submitting process

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
2024-08-26 18:37:08 +02:00
443cbfcde5 CB-5549. Added ability to configure server property for Root URI (#2868)
* CB-5549. Added ability to configure server property for Root URI

* CB-5549. Added new SQL

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-08-26 13:39:59 +00:00
Arioko 678ec32c44 Environment variable called "CLOUDBEAVER_ROOT_URI" in cloudbeaver.conf (#2812)
Inclusion of the ability to configure the server property "rootURI" with an environment variable called "CLOUDBEAVER_ROOT_URI" to simplify changing its value in dockenized environments.
2024-08-26 12:28:22 +00:00
Alexander Skoblikov 54544b6334 CB-5561 execute data migration if runtime config contains env variables (#2873) 2024-08-26 12:19:32 +00:00
ab077070c0 CB-5431 Easy config steps are available via url without a license (#2850)
* CB-5431 fixes redirects on unavailable pages during easy config

* CB-5431 cleanup

* Revert "CB-5431 cleanup"

This reverts commit 126e47b7e5.

* Revert "CB-5431 fixes redirects on unavailable pages during easy config"

This reverts commit 0719adc0ab.

* chore: Add ConfigurationWizardScreenService to core-administration manifest

* fix: Handle non-existing pages during route change in AdministrationScreenService

* CB-5431 pr fix

* CB-5431 cleanup

* feat: Remove unused import in AdministrationScreenService

* Fix issue with loading server configuration on non-admin screens

* chore: code style

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
2024-08-26 12:59:14 +03:00
AinurandEvgenia Bezborodova dfd5838f38 CB-3968 prettify error (#2862)
* CB-3968 prettify error

* CB-3968 return only rm error message

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-26 09:21:52 +00:00
00c1cc81ac CB-4708 add localization to some data viewer tokens (#2388)
* CB-4708 add localization to some data viewer tokens

* Fix conflicts

* CB-4708 remove extra code

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-26 11:32:22 +03:00
serge-rider 1ef728ab85 Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2024-08-24 18:18:17 +02:00
serge-rider fe56f61db3 Java version config (use single property) 2024-08-24 18:14:42 +02:00
d186859cb5 CB-5177 fix: allow change unsaved credentials (#2857)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-23 16:19:57 +03:00
AinurandAlexander Skoblikov a51ab7d145 CB-5550 fix npe (#2867)
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-08-23 10:53:25 +00:00
AlexeyandDaria Marutkina bdaf5dc3b4 Fix/cb-5383/sync-grid-focus (#2863)
* CB-5383 fix: sync focus in grid

* CB-5383 fix: don't reset focus on index/column

* CB-5383 fix: typo

* CB-5383 fix: focus sync lag

* refactor: rename users delete fn

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-23 12:37:13 +03:00
alex 4a4f959da8 CB-5548 add overflow to team options container (#2870) 2024-08-22 17:06:29 +02:00
Alexander Skoblikovandmr-anton-t f82660657d CB-5291 ldap integration improvements (#2844)
* CB-5291 wip

* CB-5291 ldap custom user id attribute and user filter

* CB-5291 checkstyle

* CB-5291 npe fix

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-08-22 13:29:27 +00:00
Alexey d650ec104b chore: use esbuild (#2859)
* chore: use esbuild

* chore: update ts lib
2024-08-22 15:10:31 +03:00
7ca8cfe998 CB-5048 ignore undo and redo on codemirror level (#2854)
* CB-5048 ignore undo and redo on codemirror level

* CB-5048 feat: improve query history

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-22 15:07:45 +03:00
Alexeyandalex fd4a503f8b CB-5504 fix: hide tabs for not executable sql editors (#2858)
Co-authored-by: alex <48489896+devnaumov@users.noreply.github.com>
2024-08-22 15:07:10 +03:00
Alexander SkoblikovandDaria Marutkina 5287ec9859 CB-5509 - http only cookie (#2860)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-22 09:24:11 +02:00
alex 542171ad1e CB-5261 add disabled prop to GroupClose component (#2839)
* CB-5261 add disabled prop to GroupClose component

* CB-5261 allow pointer events on disabled fieldset
2024-08-21 15:26:20 +02:00
AinurandDaria Marutkina 10b3a53c4a CB-5436 remove filter feature for tables and views (#2849)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-21 11:02:01 +00:00
alexandkseniaguzeeva 16de895ed4 CB-5252 extend return types (#2843)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-08-20 11:34:41 +02:00
serge-rider cab257d141 Merge remote-tracking branch 'origin/devel' into devel 2024-08-19 15:48:50 +02:00
serge-rider b48e173515 24.2.0 version fix 2024-08-19 15:48:20 +02:00
Daria Marutkina 5617d49597 Merge pull request #2852 from dbeaver/dariamarutkina-patch-3
CB_2415 chore: update README
2024-08-19 11:27:40 +02:00
Daria Marutkina 7fcfe9b5c8 CB_2415 chore: update README 2024-08-19 11:22:18 +02:00
serge-rider 351a323d9c 24.2.0 version config fix 2024-08-16 11:50:57 +02:00
serge-rider 1de2502835 24.2.0 version bump 2024-08-15 12:19:36 +02:00
Serge Rider b07510afc3 24.2.0 version bump 2024-08-14 18:32:22 +03:00
Alexander Skoblikov dd5a39e78a CB-5509 secure session cookie (#2840) 2024-08-14 17:47:01 +03:00
AinurandEvgenia Bezborodova f15c6b5ec9 CB-5386 fix npe (#2837)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-14 17:12:12 +03:00
sergeyteleshevandEvgenia Bezborodova 378f60aa94 feat: Add isNotNullDefined check for valuePlaceholder in PropertyItem.tsx (#2836)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-14 16:51:18 +03:00
Alexey f982b4b552 CB-5512 feat: Refactor QuotasService to use optional chaining (#2841)
The QuotasService has been refactored to use optional chaining when accessing the serverResourceQuotasResource data. This improves the code readability and reduces the need for null checks.
2024-08-14 16:32:29 +03:00
95046f076f CB-5451 adjust regex (#2824)
* CB-5451 adjust regex

* CB-5451 do not validate when deleting rm resource

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: DenisSinelnikov <142215442+DenisSinelnikov@users.noreply.github.com>
Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
2024-08-13 15:55:05 +00:00
92546849f8 CB-5123. Added backend part, added new parameter licenseStatus to ser… (#2831)
* CB-5123. Added backend part, added new parameter licenseStatus to server config gql

* CB-5123 feat: display license status information

* CB-5123 fix: after review

* CB-5123. Added version

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-13 11:16:56 +00:00
Ainurandkseniaguzeeva 2d45b29a07 CB-5025 update cloudbeaver features fix for ai (#2823)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-08-12 11:14:52 +00:00
AinurandEvgenia Bezborodova de00a60aad CB-4511 clear secure props if save password is disabled (#2835)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-12 11:14:27 +00:00
d118287b0e Cb 5378 dm ability to use custom ssl certificate (#2808)
* CB-5378 add getDomainFromUrl util function

* CB-5378 add uplodable prop to textarea

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-08-12 11:12:18 +00:00
sergeyteleshevandmr-anton-t 8d14e42797 CB-4068 adds driver libraries resource (#2826)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-08-09 14:30:32 +03:00
Alexander SkoblikovandEvgenia Bezborodova 36c089ed06 CB-5375 auto migration to postgres DB for default CB EE configuration (#2809)
* CB-5375 auto migration to postgres DB for default CB EE configuration

* CB-5375 fix test

* CB-5375 move legacy db

* CB-5474 async qm data migration

* CB-5375 comment unused field

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-08 22:12:50 +03:00
sergeyteleshevandDaria Marutkina 62393937fc CB-5364 adds context menu for data-viewer (#2810)
* CB-5364 adds context menu for data-viewer

* chore: reverts changes

* CB-5364 feat: adds context menu for object viewer

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-08 16:46:13 +03:00
alex 8e0e0c9193 CB-5474 remove special behaviour for long names (#2834) 2024-08-08 13:33:07 +03:00
sergeyteleshevandDaria Marutkina de85721c8f chore: Update exception message in SpreadsheetBootstrap (#2832)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-07 19:17:15 +03:00
AlexeyandEvgenia Bezborodova f059daf693 CB-4990 feat: add authentication timeout (#2829)
* CB-4990 feat: add authentication timeout

* CB-4990 fix: review

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-07 19:16:57 +03:00
DenisSinelnikovandEvgenia Bezborodova 5d071e5dfd CB-5255. Fixed cb error when you tried delete node twice, return error from database (#2828)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-07 17:12:11 +02:00
AlexeyandEvgenia Bezborodova afb4ea205c CB-5393 fix: modal submenu (#2830)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-07 16:20:36 +03:00
sergeyteleshevandAleksei Potsetsuev 74486b35b4 CB-5340 adds unit tests for basic hooks (#2755)
* CB-5340 adds unit tests for basic hooks

* CB-5340 test: trigger github actions

* CB-5340 fixes unit tests

* CB-5340 fixes unit tests

* CB-5340 fixes unit tests

* CB-5340 adds jest moduled imports for unit tests

* CB-5340 adds jest moduled imports for unit tests

* CB-5340 revert some changes

* CB-5340 cleanup

* CB-5340 replaces global jest to moduled

* CB-5340 uncomment tests and skip it

* CB-5340 cleanup

* chore: enable jest globals

* CB-5340 fix unit tests

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
2024-08-07 12:42:43 +03:00
Alexeyandmr-anton-t babb29f05a CB-5333 chore: update npm dependencies (#2827)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-08-07 12:30:30 +03:00
alexandDaria Marutkina 12b5b2b941 CB-5437 use flex component instead of container (#2818)
* CB-5437 use flex component instead of container

* CB-5437 use data attributes to apply styles

* CB-5437 simplify logic

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-07 12:06:50 +03:00
6ca587a5b0 CB-5447 npe fix (#2819)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
2024-08-06 13:24:44 +00:00
sergeyteleshevandEvgenia Bezborodova 23b70441b8 CB-4618 Profile, changing password - after a successful change red borders appear (#2820)
* CB-4618 removes red border after form submission

* Revert "CB-4618 removes red border after form submission"

This reverts commit 703da4eea9.

* CB-4618 removes red border after form submission in useForm hook

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-08-06 15:53:52 +03:00
sergeyteleshevandDaria Marutkina ffee7a1f2f CB-5414 Import table - wrong description for canceled import (#2821)
* feat: adds correct cancellation message to DataImportService

* Update Russian translation for the data import process fail cancel message

* CB-5414 do not set message on cancelled task during import into table

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-06 12:39:31 +03:00
alexandDaria Marutkina 62d1f05188 CB-5215 move form component (#2815)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-08-05 19:31:23 +03:00
Daria Marutkina ea00ce653e Merge pull request #2825 from dbeaver/dariamarutkina-patch-2
CB_2414 chore: update README
2024-08-05 12:47:01 +02:00
Daria Marutkina b7da47a816 CB_2414 chore: update README 2024-08-05 12:44:48 +02:00
Serge Rider b2dfa0a1bb Copyright update 2024-08-05 11:23:00 +03:00
Serge Rider 6486612c0e Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2024-08-05 06:54:07 +03:00
Alexander Skoblikov c349697fa1 clear test's logs (#2822) 2024-08-02 14:46:16 +02:00
Serge Rider ab7e17900c 24.1.5 version bump 2024-07-31 16:45:10 +03:00
Serge Rider 04e8610b12 dbeaver/pro#3129 model.sql.jdbc module added (#2806) 2024-07-31 16:25:25 +03:00
alexandDaria Marutkina c4f9764e02 CB-3789 make switch color brighter in dark theme (#2799)
* CB-3789 make switch color brighter in dark theme

* CB-3789 fix dense colors

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-30 15:43:40 +02:00
sergeyteleshevandEvgenia Bezborodova 45683f1a48 CB-3733 Close data editor tabs with the middle mouse button (#2805)
* feat: Add closeOnMouseWheelClick prop to Tab components

* fix: close tab on middle mouse button if tab can be closed

* fix: closes tabs for Safari also

* CB-3733 removes closeOnMouseWheelClick prop

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-29 11:23:55 +03:00
00aa2eb3e4 CB-5300 save deployment url after finishing easy config (#2776)
Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-07-25 15:31:24 +00:00
sergeyteleshevandDaria Marutkina 701e681fbd CB-5081 makes search icon always visible for local databases list (#2800)
* CB-5081 makes search icon always visible for local databases list

* CB-5081 renames search icon props

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-25 16:39:19 +03:00
DenisSinelnikovandDaria Marutkina 5be8582bfd CB-5415. Added full name header for RP (#2795)
* CB-5415. Added full name header for RP

* CB-5415. Refactor after review

* CB-5415. Refactor after review

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-25 11:22:31 +00:00
081b0eaead Cb 4653 aws settings form migration (#2785)
* CB-4653 demo fixes

* CB-4653 chore: log message

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-25 07:48:03 +03:00
AnastasiyaandEvgenia Bezborodova fa0cd1ea78 CB-5394 change descriptions for administrator rights (#2794)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-24 17:15:53 +03:00
sergeyteleshev 949722cd5a CB-4537 fixes textarea size for firefox browser in ErrorDialogDetails component (#2801) 2024-07-24 17:15:18 +03:00
sergeyteleshevandDaria Marutkina 0171240ac8 CB-5329 refactors isControlPresented to be more readable (#2798)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-24 14:27:27 +03:00
e4345ffc63 Cb 5178 redesign administration menu (#2775)
* CB-5357 resolves auth dialog on successful login (removes no license notification bug on login)

* CB-5178 fix settings names

* CB-5178 adds to the drawer items the new order

* CB-5178 removes license build and build time info from new "About" menu setting

* CB-5178 renames: plugin product -> plugin-product-information

* CB-5178 adds products info settings tab and page template

* CB-5178 adds product-info tabs

* CB-5178 revert changes from another branch

* CB-5178 fixes disappearing for sub tabs

* CB-5178 removes license redirect memory leaks + redirects correctly

* CB-5178 updates tabs state if license has new available version

* CB-5178 updates locale for new tabs

* CB-5178 moves product and product-info-administration to separate packages

* CB-5178 cleanup

* CB-5178 uses TabsContainer for Product Information Administration tabs

* CB-5178 cleanup

* CB-5178 cleanup

* CB-5178 cleanup

* CB-5178 replace icon

* CB-5178 removes extra icons

* CB-5178 fix: navigation sync with URL

* CB-5178 fix: plugin name

* CB-5178 fix: new version detection

* CB-5178 chore: add comment about style duplication

* Revert "CB-5178 removes extra icons"

This reverts commit 659b5720d5.

* CB-5178 adds about labels

* CB-5178 fixes disabled tabs for invalid license

* Revert "CB-5178 fixes disabled tabs for invalid license"

This reverts commit 2584a73219.

* CB-5178 disables administration items if license is expired (fix)

* CB-5178 disable product info tabs if no license required

* Revert "CB-5178 disable product info tabs if no license required"

This reverts commit e3d6c85313.

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-23 19:24:45 +03:00
sergeyteleshevandEvgenia Bezborodova 7959357668 CB-4823 Result set - no vertical and horizontal scrolls appear for long errors (#2797)
* CB-4823 fixes table error overflow and icon position

* CB-4823 CB-4823 fixes scroll for collapsed error icon

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-23 18:26:26 +03:00
AlexeyandAleksandr Skoblikov 6b91a0e9e6 CB-5288 fix: connection secrets cache (#2748)
Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-07-23 09:36:20 +00:00
AlexeyandDaria Marutkina f834169414 chore: localization (#2406)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-23 12:13:23 +03:00
3a10080956 CB-5134. Added flag for node features (#2770)
* CB-5134. Added flag for node features

* CB-5134 check canFilter feature

* CB-5134. Added filter for connections when connected

* CB-5134. Fix filter for schemas

* CB-5314. Fix diagram view

* CB-5314. Fix diagram view

* CB-5314. Fix diagram view

* CB-5134. Refactor after review

* CB-5134 fix: typescript error

* CB-5134 fix: typescript error

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-07-22 12:32:49 +00:00
2c541b2c98 CB-5075. Fix cancel import message after download file (#2786)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-07-22 12:24:53 +00:00
Anastasiya b967cde145 24.1.4 version bump (#2793) 2024-07-22 12:59:12 +03:00
Daria Marutkina e49086203c Merge pull request #2792 from dbeaver/dariamarutkina-patch-1
CB_2413 chore: update README
2024-07-22 11:21:31 +02:00
Daria Marutkina cf276f6a13 CB_2403 chore: update README 2024-07-22 11:18:15 +02:00
serge-rider 93ddddc913 Merge remote-tracking branch 'origin/devel' into devel 2024-07-18 09:05:11 +02:00
serge-rider 1895f3ab2e 24.1.4 version bump 2024-07-18 09:03:21 +02:00
mayer 5b436463b9 dbeaver/dbeaver-devops#823-web-path-created-in-fronted-step (#2426) 2024-07-17 15:52:56 +02:00
Alexey 75fdc2bcec Fix/cb-3823/typescript-error (#2784)
* CB-5134 fix: typescript error

* CB-5134 fix: typescript error
2024-07-16 19:23:50 +02:00
b48684b65d CB-3823 refactor: introduce service provider (#2774)
* CB-3823 refactor: introduce service provider

* CB-3823 fix: tests

* CB-5361 api for db tools

* CB-3823 feat: table group

* CB-3823 feat: connection tools resource

* CB-3823 refactor: database result action

* CB-3823 feat: session manager

* CB-3823 fix: data viewer error tracking

* CB-5361 add tools for rm admin

* CB-3823 fix: review

* CB-5361 fixes after review

* CB-5361 add comment

* CB-5361 fix permissions

* CB-3823 fix: service provider

* CB-3823 fix: useController services fallback

---------

Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-16 17:38:00 +02:00
Alexey f5149c6324 CB-5337 fix: checkbox color (#2781) 2024-07-16 18:25:28 +03:00
AlexeyandEvgenia Bezborodova 87cd84881d CB-5318 fix: language sync (#2782)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-16 18:25:17 +03:00
Alexey 16e2920937 CB-5380 fix: grid loading (#2779) 2024-07-16 16:31:42 +03:00
alexandEvgenia Bezborodova d0f82d95a6 CB-5121 use different regex for long proposals mode (#2778)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-15 15:26:21 +03:00
sergeyteleshevandDaria Marutkina fb9cd47bed CB-5357 Expiring license notification is not shown after login (#2767)
* CB-5357 resolves auth dialog on successful login (removes no license notification bug on login)

* CB-5357 fix: do not show 2 notifications

* CB-5357 reverts authPromise logic

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-14 17:42:24 +03:00
Alexander Skoblikov 364cb6e516 use driver version as in cb (#2766) 2024-07-13 07:02:00 +02:00
9e74f18be3 CB-5338 simplify data grid styling logic (#2762)
* CB-5338 simplify data grid styling logic

* CB-5338 do not inherit color scheme from react data grid

* CB-5338 remove DataGridContainer

* CB-5338 sync focus status

* CB-5338 review fixes

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-12 16:00:43 +03:00
DenisSinelnikov d94a6f9588 Merge pull request #2759 from dbeaver/CB-5344-big-query-cloud-host-and-port-become-empty-after-connection-editing
CB-5344 set value fix for nullable main property
2024-07-12 13:10:28 +04:00
Evgenia Bezborodova 6afd8698fe Merge branch 'devel' into CB-5344-big-query-cloud-host-and-port-become-empty-after-connection-editing 2024-07-11 12:55:27 +03:00
alexandDaria Marutkina c8436f93e1 CB-4860 change save icon (#2773)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-07-10 19:05:54 +03:00
Serge RiderandMashaKorax 8cd8f83e5f dbeaver/pro#2998 Fix app certificate storage reuse. SSL constants refactoring (#2753)
Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2024-07-10 12:35:57 +02:00
alexandEvgenia Bezborodova 190a9db695 CB-5084 use columnIndex instead of plain (#2769)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-10 12:15:29 +03:00
sergeyteleshev aa52372422 CB-5332 updates frontend dependencies (#2772) 2024-07-10 12:15:07 +03:00
Alexey f88eb8610c chore: remove unused npm command (#2771) 2024-07-09 16:45:49 +03:00
Ainurandkseniaguzeeva 021516ae7f CB-3487 filter applicable drivers fix (#2758)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-07-08 16:06:15 +02:00
Daria Marutkina a40993f77d CB_2412 chore: update README (#2768) 2024-07-08 11:42:20 +02:00
Alexey 1298f7e294 fix: prettier (#2765) 2024-07-05 16:26:31 +03:00
Alexey 3ea4443f48 CB-5341 chore: auto refresh localization (#2761) 2024-07-04 16:30:10 +03:00
Alexey 1be6ddaf1c CB-5342 fix: database data source tasks result (#2756)
* CB-5342 fix: database data source tasks result

* CB-5342 fix: database data source tasks tracking

* CB-5342 fix: add stop auto refresh button
2024-07-04 11:08:39 +03:00
Serge Rider 0d53211b88 24.1.3 version bump 2024-07-04 06:45:10 +02:00
Serge Rider 115efeb613 24.1.3 version bump 2024-07-04 06:43:33 +02:00
Serge Rider 220c72487f dbeaver/pro#3022 Close NIO directory streams (#2760) 2024-07-04 05:41:48 +02:00
Ainur 17dcd9464c CB-5344 set value fix for nullable main property 2024-07-03 14:05:50 +02:00
e259606422 CB-4885 feat: components registry (#2745)
* CB-4885 feat: components registry

* CB-4885 fix: table data loading behaviour

* CB-4885 chore: remove unused comments

* CB-4885 fix: dispose tables correctly

* CB-4885 fix: cache invalidation

* CB-4885 fix: nav tree state persistence

* CB-4885 fix: database disconnect detection

* CB-4885 fix: auto refresh on error

* CB-4885 fix: auto refresh behaviour

* CB-4885 fix: auto refresh behaviour

* CB-4885 fix: top menu bar styles

* CB-4885 fix: auto refresh error handling

* CB-4885 chore: add comment about implementation

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-07-02 20:00:39 +02:00
Alexander Skoblikovandmr-anton-t 042da7cc7c CB-5323 less priority for .product.runtime.conf (#2754)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-07-02 20:00:02 +02:00
Alexander SkoblikovandEvgenia Bezborodova 1e2eee87d3 CB-5138 force use default properties for default database (#2751)
* CB-5138 force use default properties for default database

* CB-5138 review fix

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-02 16:04:42 +00:00
faafcee1a4 CB-4961 Control files downloading ability (#2744)
* CB-4961 adds "disable download" setting to data viewer

* CB-4691 removes unneeded alias for new disable download setting

* CB-4691 pr fixes

* CB-4961 reverts image value presentation canSave logic

* CB-4961 disables download from image context menu

* CB-4691 fixes unit tests

* CB-4691 change new setting to existing one

* CB-4691 renames disable download -> disable export

* CB-4691 pr fixes

* CB-4691 updates tests for new export setting

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-02 16:48:37 +03:00
Elizabethandkseniaguzeeva 6efbd6904a dbeaver/pro#2651 Add all resource properties updating (#2747)
* dbeaver/pro#2651 Add all resource properties updating

* dbeaver/pro#2651 Fix code style

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-07-02 15:04:58 +02:00
Georgii 8f740b732b dbeaver/dbeaver-infra#98 build imls for optional plugins (#2752) 2024-07-02 15:02:30 +02:00
sergeyteleshevandEvgenia Bezborodova 7e4411c0a9 CB-5153 Change description for 'Save credentials' mark on connection auth pop-up + unify (#2746)
* CB-5153 adds more UX friendly texts for connection "save credentials" checkbox

* CB-5153 fix build

* CB-5153 changes admins "Preferences" name to "Global Preferences"

* CB-5153 pr fixes

* CB-5153 adds logic to ssh/ssl login auth connection popup share cred checkboxes

* CB-5153 fixes translations with grammarly

* CB-5153 fixes tooltip texts for all languages

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-02 14:46:28 +03:00
Alexander Skoblikov b6ac0b93e7 CB-5322 limit latest logins by time (#2750)
* CB-5322 limit latest logins by time

* CB-5322 display correct block time

* CB-5322 naming
2024-07-02 10:54:47 +02:00
b2c6306d21 CB-5114 add gql api for bigquery trace info (#2732)
* CB-5114 add gql api for bigquery trace info

* CB-5114 add has dynamic trace to gql

* CB-5114 has dynamic trace prop fix

* CB-5114 fixes after review

* CB-5113 add result trace details panel

* CB-5113 connect plugin

* CB-4882 review fixes

* CB-4882 update references

* CB-4882 use suspense instead of loader

* CB-4882 use metadata to keep promise

* CB-4882 add overflow to container

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-01 13:21:21 +00:00
49875e4dc1 CB-5197 create main connection fields dynamically (#2693)
* CB-5238 add main properties for connections

* CB-5197 render main properties

* CB-5197 render main properties

* CB-5238 set default values to main properties

* CB-5197 fix(ci/cd): respect base and target branches

* CB-5238 fixes after review

* CB-5197 review fixes

* CB-5197 switch to new model

* CB-5238 fixes after review

* CB-5197 remove custom configuration type

* CB-5238 remove custom config type from gql schema

* CB-5197 do not check configuration type for creds

* CB-5197 make argument optional

* CB-5238 fix creating connection with url

* CB-5238 rename param

* CB-5238 rename param

* CB-5197 rename field

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-07-01 12:45:57 +00:00
4433018ed2 Cb 5124 add a notification about the upcoming expiration of the license add to status (#2733)
* CB-5124. Add license status to /status api

* CB-5124. Add license status to /status api

* CB-5124 adds reminder for soon expiring license

* CB-5124. Refactor after review

* CB-5153 adds core-website package

* CB-5124 updates TS references

* CB-5124 refactors website links service

* CB-5124 pr fixes

* CB-5124 update TS references

* CB-5124 removes WebSiteLinks from coreWebsiteManifest

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-28 17:14:33 +00:00
0755561250 CB-5165. Add parameter to api - autocommit (#2737)
* CB-5165. Add parameter to api - autocommit

* CB-5165. Refactor after review

* CB-5165 add auto commit checkbox

* CB-5165 add gap between elements

* CB-5165. Refactor after review

* CB-5165. Refactor after review

* CB-5165. Refactor after review

* CB-5165. Refactor after review

* CB-5165 change category name

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-28 16:26:34 +00:00
sergeyteleshevandEvgenia Bezborodova ea87a48619 CB-5299 fixes border for value panel icon in different browsers (#2740)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-27 17:43:13 +03:00
c2330e9c6a CB-5038 update clickhouse driver (#2731)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-06-27 09:33:42 +00:00
Alexander SkoblikovandEvgenia Bezborodova 09de0c328a CB-4889 CB database env variables (#2739)
* CB-4889 CB database env variables

* CB-4889 fix runtime conf priority

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-26 16:15:09 +00:00
serge-rider dab4a0d033 Merge remote-tracking branch 'origin/devel' into devel 2024-06-26 16:02:37 +02:00
serge-rider 05507db706 24.1.2 version bump 2024-06-26 16:01:46 +02:00
sergeyteleshevandAlexey 6e4f16e824 Cb 5293 unit tests for hooks in core blocks (#2724)
* CB-5293 adds unit tests for useState delay hook

* CB-5293 removes unused helper hook

* СB-5277 adds tests for useClipboard hook

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2024-06-26 16:38:07 +03:00
alexandAlexey 56a2e8c13d Cb 5277 test components (#2721)
* CB-5277 add tests for core blocks components

* CB-5277 add tests for link and status message

* CB-5277 add Cell test

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2024-06-26 16:37:38 +03:00
serge-rider d8b6655da5 24.1.2 version bump 2024-06-26 14:07:27 +02:00
sergeyteleshevandEvgenia Bezborodova 4842cba903 CB-5181 Display User Notification Pop-up When Copy/Paste Functionality is Disabled by Administrator (#2730)
* CB-5181 adds copy event handler for data viewer (cells, value panel)

* CB-5181 makes edit/copy settings independent from each other

* CB-5181 adds disable copy case for read state JsonLine (pre)

* CB-5181 changes message text for popup

* CB-5181 changes message text for popup 2

* СB-5181 fixes rus locale for copy message

---------

Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-25 18:17:40 +03:00
Alexey 4078b6aa16 CB-5250 refactor: move task manager to core manifest (#2726)
* refactor: move task manager to core manifest

* chore: update dependencies
2024-06-25 18:15:32 +03:00
Georgii 241f2393be dbeaver/dbeaver-infra#91 add source links and fix small issues (#2727)
* dbeaver/dbeaver-infra#91 add source links and fix small issues

* dbeaver/dbeaver-infra#91 add a way to add required fragmens manually + fix scripts
2024-06-25 12:58:30 +02:00
Evgenia Bezborodova 5851c8f2c4 CB_2411: update README (#2729) 2024-06-24 17:30:48 +02:00
AlexeyandEvgenia Bezborodova c70c932e9c CB-5279 fix: return counter button for non result set data format (#2719)
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-24 12:38:23 +03:00
alex b155c98c02 CB-5292 add separate group for advanced properties (#2725) 2024-06-24 12:37:52 +03:00
serge-rider 1d0fac3eb0 Legacy constants refactoring 2024-06-24 11:28:48 +02:00
GeorgiiandSerge Rider 124fa7f691 dbeaver/infra#74 update cloudbeaver launch args (#2682)
* dbeaver/infra#74 update cloudbeaver launch args

* dbeaver/dbeaver-infra#74 add generator scripts and move rcp-gen.properties to product repos

* dbeaver/dbeaver-infra#74 add copyright config to generator CE

* dbeaver/dbeaver-infra#74 move to .ide/idea instead

* dbeaver/dbeaver-infra#74 formatting

* dbeaver/dbeaver-infra#74 update vscode configs and rename rcp-gen.properties to osgi-app.properties

* dbeaver/dbeaver-infra#74 generate workspace per osgi-app.properties file

* dbeaver/dbeaver-infra#74 remove workspace from naming

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
2024-06-21 10:55:32 +02:00
Alexander Skoblikov af5cbedf22 CB-5289 load logs config in log service (#2722) 2024-06-21 09:36:13 +02:00
Ainur b46dd9b8a8 CB-5270 gql tests refactoring (#2713) 2024-06-20 09:59:57 +02:00
Alexey cdd3a356ac CB-5278 fix: don't dispose execution context (#2718) 2024-06-18 18:43:05 +02:00
Alexey 9a471bed70 Refactor cb-4018 data context api (#2708)
* CB-4018 refactor: data context api

* CB-4018 refactor: data context api

* CB-4018 refactor: form parts api

* CB-4018 fix: pr review

* CB-4018 fix: track mobx dependencies in useDataContextLink

* CB-4018 fix: unsubscribe behaviour

* CB-3510 feat: data editing actions based on view (#2710)

* CB-3510 feat: data editing actions based on view

* CB-3510 fix: pr review

* CB-3510 fix: table bottom bar styles

* CB-4018 refactor: respect presentation in data viewer

* CB-4018 fix: remove gap in data viewer toolbar

* CB-4018 fix: isolate contexts in data viewer
2024-06-18 18:19:04 +03:00
Alexey e779a23f0e CB-5213 chore: update react-data-grid (#2716) 2024-06-18 09:30:24 +03:00
240dab7c0f Added French translation files (fr.ts) to respective directories (#2670)
* Added French translation file for core-administration (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-administration/src/locales/ directory. This file contains the French translations for various administration-related strings used in the application. The translations include menu entries, configuration wizard titles, and success messages.

* Added French translation file for core-authentication (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-authentication/src/locales/ directory. This file contains the French translations for various authentication-related strings used in the application. The translations include settings group labels, options for disabling anonymous access, and password policy requirements such as minimum length, case sensitivity, digits, and special characters.

* Added French translation file for core-blocks (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-blocks/src/locales/ directory. This file contains the French translations for various core-blocks related strings used in the application. The translations include properties table labels, filter options, add/reset/remove property actions, placeholder texts, error messages, and validation messages.

* Added French translation file for core-browser-settings (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-browser-settings/src/locales/ directory. This file contains the French translations for various browser settings related strings used in the application. The translations include settings for cookies and general browser settings.

* Added French translation file for core-connections (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-connections/src/locales/ directory. This file contains the French translations for various connection-related strings used in the application. The translations include settings for connections, connection templates, error messages, authentication details, network handler configurations, and various tooltips and placeholder texts related to database connections and SSH tunnels.

* Added French translation file for core-localization (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-localization/src/locales/ directory. This file contains the French translations for various UI-related strings used in the application. The translations include messages for renaming, themes, navigation steps, loading states, error handling, clipboard operations, authentication, settings, file operations, and more.

* Added French translation file for core-navigation-tree (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-navigation-tree/src/locales/ directory. This file contains the French translation for the navigation tree settings group string used in the application.

* Added French translation file for core-projects (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-projects/src/locales/ directory. This file contains the French translation for the message indicating that a project is not found.

* Added French translation file for core-resource-manager (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-resource-manager/src/locales/ directory. This file contains the French translation for the resource manager settings group string used in the application.

* Added French translation file for core-settings-localization (fr.ts)

I have created the fr.ts file in the cloudbeaver/webapp/packages/core-settings-localization/src/locales/ directory. This file contains the French translations for the localization settings, including the labels and descriptions for language settings in the application.

* Added French translation file for core-settings-user (fr.ts)

I have created the fr.ts file in the cloudbeaver/webapp/packages/core-settings-user/src/locales/ directory. This file currently does not contain any translations, but it has been set up for future French translations for user settings in the application.

* Added French translation file for core-settings (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-settings/src/locales/ directory. This file contains the French translations for the interface and root settings groups used in the application.

* Added French translation file for core-theming (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-theming/src/locales/ directory. This file contains the French translations for the theming settings, including the labels and descriptions for the application color theme.

* Added French translation file for core-ui (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-ui/src/locales/ directory. This file contains the French translations for various UI-related messages used in the application, including messages for empty states, form save errors, and tab switching errors during form validation.

* Added French translation file for core-version-update (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-version-update/src/locales/ directory. This file contains the French translations for various version update-related messages used in the application, including messages about version status, refresh actions, and update instructions.

* Added French translation file for core-version (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-version/src/locales/ directory. This file contains the French translations for various version-related strings used in the application, including version information, release dates, tags, and error messages for loading version information.

* Added French translation file for core-view (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/core-view/src/locales/ directory. This file contains the French translations for various view-related strings used in the application, including layout settings, zoom actions, and labels for creating and editing items and folders.

* Added French translation file for plugin-administration (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-administration/src/locales/ directory. This file contains the French translations for various administration-related messages used in the application, including server configuration, welcome messages, security settings, and navigation options.

* Added French translation file for plugin-authentication-administration (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-authentication-administration/src/locales/ directory. This file contains the French translations for various authentication and administration-related messages used in the application, including user connections, access management, identity providers, and team management.

* Added French translation file for plugin-authentication (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-authentication/src/locales/ directory. This file contains the French translations for various authentication-related messages used in the application, including login, logout, user credentials, error messages, and identity provider configurations.

* Added French translation file for plugin-browser (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-browser/src/locales/ directory. This file contains the French translations for various update-related messages used in the application, including installation of the application, installation of updates, and restart messages with progress information.

* Added French translation file for plugin-connection-custom (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-connection-custom/src/locales/ directory. This file contains the French translations for various custom connection-related messages used in the application, including parameters, URL, main settings, driver properties, and connection actions like testing and creating connections.

* Added French translation file for plugin-connection-search (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-connection-search/src/locales/ directory. This file contains the French translation for the label used in the plugin-connection-search, specifically the message "Find Local Database" which is translated to "Trouver une base de données locale".

* Added French translation file for plugin-connection-template (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-connection-template/src/locales/ directory. This file contains the French translations for various strings used in the connection template plugin. The translations include labels and messages related to new connections, database connection dialogs, and connection templates. This addition will help French-speaking users interact with the connection template plugin more easily.

* Added French translation file for plugin-connections-administration (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-connections-administration/src/locales/ directory. This file contains the French translations for various connection-related strings used in the application. The translations include menu items for editing connections, confirmation messages for reconnection, and descriptions of the templates used by administrators to create reusable connection parameters.

* Added French translation file for plugin-connections (fr.ts)

I have added the fr.ts file to the cloudbeaver/webapp/packages/plugin-connections/src/locales/ directory. This file contains the French translations for various connection-related strings used in the application. The translations include messages for editing connections, connection status updates, and SSL settings.

* Added French translation file for plugin-data-export (fr.ts)

Added French translations for various data export-related strings in the plugin-data-export module. This includes translations for dialogs, notifications, and settings related to data export functionality.

* Added French translation file for plugin-data-import (fr.ts)

- Added French translations for the data import plugin.
- Included translations for various stages and messages related to data import process.

* Add French translation file for plugin-data-spreadsheet-new (fr.ts)

Added French translations for plugin-data-spreadsheet-new. This includes translations for various table and data grid related functionalities such as table editing, sorting, filtering, and error messages.

* Added French translation file for plugin-data-viewer (fr.ts)

This commit includes the French translation for the plugin-data-viewer module.

* Add French translation for Data Viewer plugin (fr.ts)

Added French translations for the Data Viewer plugin.

* Added French translation to plugin-datasource-context-switch (fr.ts)

Added French translations for the context switch plugin messages.

* Added French translation to plugin-datasource-transaction-manager (fr.ts)

Added French translations for the transaction manager plugin messages.

* Added French translation to plugin-gis-viewer (fr.ts)

Added French translations for the GIS viewer plugin messages.

* Added French translation to plugin-help (fr.ts)

Added French translations for the help plugin messages.

* Added French translation to plugin-log-viewer (fr.ts)

Added French translations for the log viewer plugin messages.

* Added French translation to plugin-navigation-tree-filters (fr.ts)

Added French translations for the navigation tree filters plugin messages.

* Added French translation to plugin-navigation-tree-rm (fr.ts)

Added French translations for the navigation tree remove plugin messages.

* Added French translation to plugin-navigation-tree (fr.ts)

Added French translations for the navigation tree plugin messages.

* Added French translation to plugin-object-viewer (fr.ts)

Added French translations for the object viewer plugin messages.

* Added French translation to plugin-product (fr.ts)

Added French translations for the product plugin messages.

* Added French translation to plugin-projects (fr.ts)

Added French translations for the projects plugin messages.

* Added French translation to plugin-resource-manager-administration (fr.ts)

Added French translations for the resource manager administration plugin messages.

* Added French translation to plugin-resource-manager-scripts (fr.ts)

Added French translations for the resource manager scripts plugin messages.

* Added French translation to plugin-resource-manager (fr.ts)

Added French translations for the resource manager plugin messages.

* Added French translation to plugin-root (fr.ts)

Added French translations for the root plugin messages.

* Added French translation to plugin-session-expiration (fr.ts)

Added an empty template for French translations for the session expiration plugin messages.

* Added French translation to plugin-settings-administration (fr.ts)

Added French translations for the settings administration plugin messages.

* Added French translation to plugin-settings-panel (fr.ts)

Added French translations for the settings panel plugin messages.

* Added French translation to plugin-sql-editor-navigation-tab-script (fr.ts)

Added French translations for the SQL editor navigation tab script plugin messages.

* Added French translation to plugin-sql-editor-navigation-tab (fr.ts)

Added French translations for the SQL editor navigation tab plugin messages.

* Added French translation to plugin-sql-editor-new (fr.ts)

Added French translations for the new SQL editor plugin messages.

* Added French translation to plugin-sql-editor-screen (fr.ts)

Added French translations for the SQL editor screen plugin messages.

* Added French translation to plugin-sql-editor (fr.ts)

Added French translations for the SQL editor plugin messages.

* Added French translation to plugin-sql-generator (fr.ts)

Added fr.ts to cloudbeaver/webapp/packages/plugin-sql-generator/src/locales

* Added French translation to plugin-task-manager (fr.ts)

Added French translations for the task manager plugin messages.

* Added French translation to plugin-tools-panel (fr.ts)

Added French translations for the tools panel plugin messages.

* Added French translation to plugin-user-profile-settings (fr.ts)

Added French translations for the user profile settings plugin messages.

* Added French translation to plugin-user-profile (fr.ts)

Added French translations for the user profile plugin messages.

* Added French translation to plugin-version-update-administration (fr.ts)

Added French translations for the version update administration plugin messages.

* Added French translation to product-default (fr.ts)

Added French translations for the default product plugin messages.

* CB-5266 registers french localization all over the app

* CB-5266 adds core-app localization from other PR

* CB-5266 shorter translate for log-viewer french action enable label

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-14 17:52:23 +03:00
Alexey 422e6283df CB-5276 fix: auth fallback (#2712) 2024-06-14 17:30:57 +03:00
0b98569c9e CB-5129. Implemented add and delete logic for user team api (#2695)
* CB-5129. Implemented add and delete logic for user team api

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2024-06-14 13:59:17 +00:00
Serge Riderandmr-anton-t 340c6e850c CB-2070 DBException refactoring (#2703)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-06-14 13:41:57 +00:00
AnastasiyaandDaria Marutkina bdfb637633 CB-4870 add tooltip for Disable Table presentation setting; add Germa… (#2704)
* CB-4870 add tooltip for Disable Table presentation setting; add German localization

* CB-4870 Update ru localization

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-06-14 12:36:10 +03:00
Anastasiya df4b88c7e4 dbeaver/dbeaver#17169 Update FireBird driver to version 5.0.4 (#2707) 2024-06-13 19:13:16 +02:00
Alexander SkoblikovandElizabeth e7f6cbd2fc dbeaver/pro#2116 send user deleted event for headless session (#2659)
Co-authored-by: Elizabeth <e1izabeth.k@outlook.com>
2024-06-13 16:50:37 +02:00
Alexander SkoblikovandMashaKorax a84f822124 dbeaver/pro#1803 send permissions update to headless session (#2698)
Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2024-06-13 16:00:49 +02:00
Alexey c5399de7af fix: remove extra files (#2701) 2024-06-13 12:34:32 +03:00
a65dff32d6 Cb 4760 add to value panel more clear abstractions and separation of the logic (#2688)
* CB-4760 refactors value panel boolean presentation

* CB-4760 refactors value panel image presentation

* CB-4760 refactors value panel text presentation (part 1)

* CB-4760 refactors value panel text presentation (part 2)

* CB-4760 moves ValuePanel presentation layer to ValuePanel folder

* CB-4760 fixes type in file name

* CB-4760 modifies isBlob truncated logic

* CB-4760 booleanValuePresentation uses actions helper

* CB-4760 reverts value panel helpers location

* CB-4760 reverts getResultSetActions

* CB-4760 add preprocessBooleanValue helper instead of hook

* CB-4760 reverts truncated message isTruncated logic

* CB-4760 cleanup

* CB-4760 cleanup

* CB-4760 test commit for save file history

* CB-4760 test commit for save file history [2]

* CB-4760 test commit for save file history [3]

* CB-4760 moves back ValuePanelPresentation directory to src folder to save git history

* CB-4760 pr fixes

* CB-4760 adds placeholder for non selected elements in boolean value presentation (value panel)

* CB-4760 fixes placeholder translation for non selected elements in boolean value presentation (value panel)

* CB-4760 fix: app restart process

* CB-4760 fix: app restart process

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
2024-06-13 08:04:22 +03:00
alexandmr-anton-t 1c9b4f1ece CB-4706 remove duplicated styles (#2689)
* CB-4705 remove duplicated styles

* CB-4706 pass ref

* CB-4706 review fixes

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-06-13 08:03:39 +03:00
Serge Rider b13b58b589 dbeaver/dbeaver#23203 Optional monitor for nav API (#2687)
* dbeaver/dbeaver#23203 Optional monitor for nav API

* #23203 Local cache progress monitor
2024-06-12 08:56:35 +02:00
alexandmr-anton-t 3d56701dc6 CB-4705 make data viewer model loaders more flexible (#2690)
* CB-4705 make data viewer model loaders more flexible

* CB-4705 review fixes

* CB-4705 remove unused import

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-06-11 16:51:57 +03:00
AnastasiyaandDaria Marutkina 078c11c657 CB-5268 fix tooltip; add localization (#2699)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2024-06-11 15:45:25 +03:00
Alexander Skoblikov baffbfd838 CB-5263 fix null projectId in gql (#2697) 2024-06-11 10:06:48 +02:00
serge-rider 0134b79ee0 24.1.1 version bump 2024-06-10 17:44:50 +02:00
serge-rider 791da679fe 24.1.1 version bump 2024-06-10 17:42:07 +02:00
sergeyteleshevandAlexey dc0e3075fa Cb 5198 unit tests (#2674)
* CB-5198 adds errorOf unit test

* CB-5198 adds unit tests for metadata map

* CB-5198 open centered popup covered with unit tests

* CB-5198 removed unused utils helper

* CB-5198 adds unit tests for utf8 to base64 helper

* СB-5198 adds unit tests fro TempMap

* СB-5198 adds unit tests for GlobalConstants

* CB-5198 removes unused helper

* CB-5198 fix: unit tests for global consts

* СB-5198 adds unit tests for ILoadableState

* СB-5198 adds unit tests for CancellablePromise and cancellableTimeout

* CB-5198 unit tests cleanup

* CB-5198 unit tests cleanup

* CB-5198 updates TS references

* CB-5198 adds PR fixes

* CB-5186 cleanup

* CB-5198 adds correct window object mock for global consts tests

* Revert "CB-5198 updates TS references"

This reverts commit 9388477a79.

* CB-5198 fixes PR comments

* CB-5198 fixes PR comments

* CB-4760 fix: metadatamap return non observed values correctly

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2024-06-10 16:52:08 +03:00
f04c2b1452 Cb 5188 support page outdating for object properties table (#2686)
* CB-5188 marks page outdated on onDisconnect event for DBObjectPageResource

* CB-5188 removes properties table error on logout

* Revert "CB-5188 removes properties table error on logout"

This reverts commit aa4d64cc83.

* Revert "CB-5188 marks page outdated on onDisconnect event for DBObjectPageResource"

This reverts commit cdab1b76c9.

* CB-5188 makes cached map resource

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
2024-06-07 16:36:40 +03:00
ce6cfd3e3c CB-5196 Update GraphQL usage (#2671)
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-06-07 11:03:52 +00:00
Alexander Skoblikovandkseniaguzeeva 776b6d5c6d CB-5253 store only changed common runtime properties (#2692)
* CB-5253 store only changed common runtime properties

* CB-5253 remove null properties

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2024-06-07 10:55:11 +00:00
Anastasiya 9a729cb47f Add info about contributors in our readme file (#2691) 2024-06-06 17:24:45 +02:00
c3ae4acdfb Cb 5164 deps update (#2675)
* CB-5164 update sup deps

* CB-5164 update typescript and mobx

* CB-5164 update react

* CB-5164 fix: specify only major versions

* CB-5164 fix class format

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-06-05 13:29:38 +03:00
4cb171ed19 CB-5180 rename .m -> .module (#2679)
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2024-06-04 20:31:45 +03:00
Daria Marutkina b3952e7247 Merge pull request #2685 from dbeaver/cb_readme_duplication
Fix release notes duplication
2024-06-04 14:10:46 +02:00
LonwoLonwo d83822d4ad Fix release notes duplication 2024-06-04 12:59:17 +02:00
Alexey 5579970447 fix: dev mode (#2683) 2024-06-03 16:07:26 +03:00
Daria Marutkina c216a77f23 Merge pull request #2681 from dbeaver/dariamarutkina-patch-2
CB_2410 chore: update README
2024-06-03 13:01:20 +02:00
Anastasiya e7ff007151 Update README.md
fix driver version
2024-06-03 11:29:54 +02:00
Daria Marutkina b62b144ced CB_2410 chore: update README 2024-06-03 11:21:41 +02:00
Alexey 8eaabce90b CB-5228 feat: fast frontend unit tests (#2677)
* fix: try to fix make docker container.sh

* fix: specify correct docker build scripts folder

* fix: validate branch to valid docker tag name

* feat: combined workflows

* feat: add readable names for github actions

* feat: add docker pull command comment

* fix: comment publishing comment with docker instructions

* feat: improve build & test performance

* feat: add option to skip cache

* fix: flush cache

* fix: flush cache

* feat: merge tests and build steps

* fix: github action outputs keys

* feat: add lint job

* feat: change file to trigger lint

* fix: omit webapp path

* fix: trigger lint

* fix: continue  on linting errors

* feat: add publishing container to github docker registry

* feat: add lint status

* chore: re-trigger-lint

* feat: add java checkstyle

* fix: java linting

* fix: github token

* fix: update jave checkstyle action

* chore: simplify frontend lint action

* chore: remove changed java files

* feat: revert lint trigger frontend

* feat: add docker credentials helper

* fix: remove credentials warning

* fix: tests and clean command

* CB-5228 feat: run frontend tests for every build

* fix: clean tasks

* feat: update cli tools
2024-05-31 21:34:57 +03:00
Alexey 6077a52181 fix: docker container build (#2676) 2024-05-30 17:13:01 +03:00
Alexey 7b728311c0 fix: backend build action (#2673)
* fix: backend build action

* chore: update github actions version
2024-05-30 15:24:03 +02:00
Alexey baad9d6f98 chore: add build github actions (#2672)
* chore: add build github actions

* chore: remove docker push

* chore: update cache maven
2024-05-29 19:24:39 +02:00
3090 changed files with 38063 additions and 25939 deletions
-35
View File
@@ -1,35 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
"name": "Java",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/java:1-17-bookworm",
"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "true",
"installGradle": "false"
},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/node:1": {}
},
"hostRequirements": {
"cpus": 8,
"memory": "16gb",
"storage": "64gb"
}
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "java -version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
+56
View File
@@ -0,0 +1,56 @@
name: Backend Build
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
jobs:
build-backend:
name: Backend
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
cache: maven
- uses: stCarolas/setup-maven@v5
with:
maven-version: 3.9.0
- name: Give permissions
run: |
sudo chmod 777 ../
shell: bash
- name: Determine branches
id: determine-branch
run: |
echo "pr_branch=${{ github.head_ref }}" >> $GITHUB_ENV
echo "base_branch=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV
- name: Clone dbeaver/dbeaver
id: clone-repo
run: |
git clone -b ${{ env.pr_branch }} https://github.com/dbeaver/dbeaver.git ../dbeaver || git clone -b ${{ env.base_branch }} https://github.com/dbeaver/dbeaver.git ../dbeaver
- name: Run build script
run: ./build-backend.sh
shell: bash
working-directory: ./deploy
- name: Archive build artifacts
uses: actions/upload-artifact@v4
with:
name: backend-build-artifacts
path: deploy/cloudbeaver
if-no-files-found: error
+40
View File
@@ -0,0 +1,40 @@
name: Backend Lint
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
inputs:
skip_cache:
required: false
type: string
jobs:
lint:
name: Backend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout checkstyle config repository
uses: actions/checkout@v4
with:
repository: dbeaver/dbeaver
path: dbeaver-config
- name: Copy checkstyle config
run: cp dbeaver-config/dbeaver-checkstyle-config.xml ./dbeaver-checkstyle-config.xml
- name: Remove checkstyle config directory
run: rm -rf dbeaver-config
- uses: dbelyaev/action-checkstyle@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-review
filter_mode: diff_context
checkstyle_config: ./dbeaver-checkstyle-config.xml
fail_on_error: true
+57
View File
@@ -0,0 +1,57 @@
name: Cleanup checks
on:
pull_request:
types: [closed]
jobs:
delete-caches:
runs-on: ubuntu-latest
steps:
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
# delete-docker-image:
# name: Delete Docker Image
# if: github.event.pull_request.merged == true
# runs-on: ubuntu-latest
# steps:
# - name: Check out the repository
# uses: actions/checkout@v4
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v3
# - name: Determine Docker Image Tag
# run: |
# REPO_NAME=$(basename ${{ github.repository }})
# IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/$REPO_NAME
# BRANCH_NAME=${{ github.event.pull_request.head.ref }}
# TAG_NAME=$(echo $BRANCH_NAME | sed 's/[^a-zA-Z0-9._-]/-/g')
# echo "image=$IMAGE_NAME:$TAG_NAME" >> $GITHUB_ENV
# - name: Log in to GitHub Container Registry
# run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
# - name: Delete Docker Image
# run: |
# docker rmi ${{ env.image }}
# echo "Deleted image: ${{ env.image }}"
+56
View File
@@ -0,0 +1,56 @@
name: Check
on:
push:
branches:
- devel
pull_request:
branches:
- devel
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
skip_cache:
description: "Skip cache restoration"
required: false
default: "false"
jobs:
call-backend-build:
name: Build
uses: ./.github/workflows/backend-build.yml
call-frontend-build:
name: Build
uses: ./.github/workflows/frontend-build.yml
with:
skip_cache: ${{ github.event.inputs.skip_cache }}
call-frontend-lint:
name: Lint
needs: call-frontend-build
uses: ./.github/workflows/frontend-lint.yml
call-backend-lint:
name: Lint
uses: ./.github/workflows/backend-lint.yml
# call-frontend-tests:
# name: Frontend Unit Tests
# needs: call-frontend-build
# runs-on: ubuntu-latest
# steps:
# - name: Check if tests passed
# if: ${{ needs.call-frontend-build.outputs.test-status != 'success' }}
# run: |
# echo "Tests failed"
# exit 1
# - name: Continue if tests passed
# if: ${{ needs.call-frontend-build.outputs.test-status == 'success' }}
# run: echo "Tests passed"
# call-docker-build-and-push:
# name: Run
# needs: [call-backend-build, call-frontend-build]
# uses: ./.github/workflows/docker-build-and-push.yml
@@ -0,0 +1,93 @@
name: Build and Push Docker Image
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
jobs:
build-and-push-docker:
name: Build and Push Docker Image
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download backend artifacts
uses: actions/download-artifact@v4
with:
name: backend-build-artifacts
path: deploy/cloudbeaver/
- name: Download frontend artifacts
uses: actions/download-artifact@v4
with:
name: frontend-build-artifacts
path: deploy/cloudbeaver/web
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Run custom Docker build script
run: ./make-docker-container.sh
shell: bash
working-directory: ./deploy/docker
- name: Tag Docker Image
run: |
REPO_NAME=$(basename ${{ github.repository }})
IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/$REPO_NAME
BRANCH_NAME=${{ github.head_ref || github.ref_name }}
TAG_NAME=$(echo $BRANCH_NAME | sed 's/[^a-zA-Z0-9._-]/-/g')
docker tag dbeaver/cloudbeaver:dev $IMAGE_NAME:$TAG_NAME
echo "image=$IMAGE_NAME:$TAG_NAME" >> $GITHUB_ENV
# - name: Install Docker Credential Helper
# run: |
# sudo apt-get update
# sudo apt-get install -y gnupg2 pass
# curl -fsSL https://github.com/docker/docker-credential-helpers/releases/download/v0.6.4/docker-credential-pass-v0.6.4-amd64.tar.gz -o docker-credential-pass.tar.gz
# tar xzvf docker-credential-pass.tar.gz
# sudo mv docker-credential-pass /usr/local/bin/docker-credential-pass
# sudo chmod +x /usr/local/bin/docker-credential-pass
# - name: Configure Docker to use Credential Helper
# run: |
# mkdir -p ~/.docker
# echo '{"credsStore":"pass"}' > ~/.docker/config.json
# - name: Initialize Password Store
# run: |
# gpg --batch --gen-key <<EOF
# %no-protection
# Key-Type: default
# Subkey-Type: default
# Name-Real: Docker Credential Helper
# Expire-Date: 0
# %commit
# EOF
# pass init "$(gpg --list-keys --with-colons | grep '^pub' | cut -d: -f5)"
- name: Log in to GitHub Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
- name: Push Docker Image
run: docker push ${{ env.image }}
# - name: Comment on Pull Request
# if: github.event_name == 'pull_request'
# uses: actions/github-script@v6
# with:
# github-token: ${{ secrets.PAT }}
# script: |
# const tag = process.env.TAG_NAME;
# const commentBody = `The Docker image has been built and pushed to Docker Hub.\n\nYou can pull the image using the following command:\n\`\`\`\ndocker pull dbeaver/cloudbeaver:${tag}\n\`\`\``;
# github.rest.issues.createComment({
# owner: context.repo.owner,
# repo: context.repo.repo,
# issue_number: context.issue.number,
# body: commentBody
# });
+91
View File
@@ -0,0 +1,91 @@
name: Frontend Build
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
outputs:
build-status:
description: "Build status"
value: ${{ jobs.frontend-build.outputs.build-status }}
test-status:
description: "Test status"
value: ${{ jobs.frontend-build.outputs.test-status }}
inputs:
skip_cache:
required: false
type: string
jobs:
frontend-build:
name: Frontend
runs-on: ubuntu-latest
outputs:
build-status: ${{ steps.build.outcome }}
test-status: ${{ steps.test.outcome }}
defaults:
run:
working-directory: ./webapp
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: yarn
cache-dependency-path: webapp/yarn.lock
- name: restore node_modules
uses: actions/cache@v4
with:
path: "**/node_modules"
key: ${{ runner.os }}-node_modules-${{ hashFiles('webapp/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: restore typescript cache
uses: actions/cache@v4
with:
path: "**/packages/*/dist"
key: ${{ runner.os }}-dist-${{ hashFiles('webapp/yarn.lock') }}
restore-keys: |
${{ runner.os }}-dist-
- name: yarn clean
if: env.skip_cache == 'true'
uses: borales/actions-yarn@v5
with:
dir: webapp
cmd: clean
- name: yarn install --frozen-lockfile
uses: borales/actions-yarn@v5
with:
dir: webapp
cmd: install
- name: build
id: build
uses: borales/actions-yarn@v5
with:
dir: webapp/packages/product-default
cmd: bundle
- name: test
id: test
uses: borales/actions-yarn@v5
with:
dir: webapp
cmd: test
- name: Archive build artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-build-artifacts
path: webapp/packages/product-default/lib
if-no-files-found: error
-76
View File
@@ -1,76 +0,0 @@
name: frontend-cache
on:
push:
branches: ["devel"]
paths:
- "webapp/**"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build_and_test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./webapp
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: restore yarn cache
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: restore node_modules
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: restore typescript cache
uses: actions/cache@v3
with:
path: "**/packages/*/dist"
key: ${{ runner.os }}-dist-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-dist-
- name: yarn install
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: install
- name: yarn lerna bootstrap
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna bootstrap
- name: build
uses: borales/actions-yarn@v4
with:
dir: webapp/packages/product-default
cmd: build # build tyescript source code
- name: test
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna run test # build packages that have test script
-29
View File
@@ -1,29 +0,0 @@
name: cleanup caches by a branch
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
+45
View File
@@ -0,0 +1,45 @@
name: Frontend Lint
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
jobs:
lint:
name: Frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: yarn
cache-dependency-path: webapp/yarn.lock
- name: restore node_modules
uses: actions/cache@v4
with:
path: "**/node_modules"
key: ${{ runner.os }}-node_modules-${{ hashFiles('webapp/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: yarn install --frozen-lockfile
uses: borales/actions-yarn@v5
with:
dir: webapp
cmd: install
- name: Lint
uses: reviewdog/action-eslint@v1
with:
reporter: github-pr-review
filter_mode: file
workdir: webapp
fail_on_error: true
eslint_flags: "--ext .ts,.tsx"
-80
View File
@@ -1,80 +0,0 @@
name: frontend
on:
# Triggers the workflow on push or pull request events but only for the "devel" branch
pull_request:
branches: ["devel"]
paths:
- "webapp/**" # monitor for the frontend changes
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
jobs:
build_and_test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./webapp
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "20"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: restore yarn cache
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: restore node_modules
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: restore typescript cache
uses: actions/cache@v3
with:
path: "**/packages/*/dist"
key: ${{ runner.os }}-dist-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-dist-
- name: yarn install
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: install
- name: yarn lerna bootstrap
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna bootstrap
- name: build
uses: borales/actions-yarn@v4
with:
dir: webapp/packages/product-default
cmd: bundle
- name: test
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna run test
-17
View File
@@ -1,17 +0,0 @@
name: validation
on:
pull_request:
branches:
- devel
types:
- opened
- synchronize
- reopened
- edited
- ready_for_review
- labeled
jobs:
commit-message:
uses: dbeaver/dbeaver/.github/workflows/reused-commit-msgs-validator.yml@devel
+1 -1
View File
@@ -26,7 +26,7 @@ dist/
*.iml
/idea/
.idea/
## Mac OS
.DS_Store
-1
View File
@@ -15,7 +15,6 @@
"streetsidesoftware.code-spell-checker",
"streetsidesoftware.code-spell-checker-russian",
"syler.sass-indented",
"VisualStudioExptTeam.intellicode-api-usage-examples",
"VisualStudioExptTeam.vscodeintellicode",
"yzhang.markdown-all-in-one",
"GraphQL.vscode-graphql-syntax",
+53 -68
View File
@@ -4,7 +4,7 @@
{
"type": "chrome",
"request": "launch",
"name": "Chrome",
"name": "CloudBeaver CE",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}/..",
"outFiles": [
@@ -17,75 +17,60 @@
},
{
"type": "java",
"name": "CloudBeaver CE",
"cwd": "${workspaceFolder}/workspace-dev-ce",
"name": "CloudBeaver CE Server",
"cwd": "${workspaceFolder}/../opt/cbce",
"request": "launch",
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
"windows": {
"type": "java",
"name": "CloudBeaver CE",
"request": "launch",
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
"args": [
"-product",
"io.cloudbeaver.product.ce.product",
"-configuration",
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/",
"-dev",
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/dev.properties",
"-os",
"win32",
"-ws",
"win32",
"-arch",
"x86_64",
"-nl",
"en",
"-showsplash",
"-web-config",
"conf/cloudbeaver.conf"
],
"vmArgs": [
"-XX:+IgnoreUnrecognizedVMOptions",
"--add-modules=ALL-SYSTEM",
"-Xms64m",
"-Xmx1024m",
"-Declipse.pde.launch=true"
]
},
"osx": {
"type": "java",
"name": "CloudBeaver CE",
"request": "launch",
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
"args": [
"-product",
"io.cloudbeaver.product.ce.product",
"-configuration",
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/",
"-dev",
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/dev.properties",
"-os",
"macosx",
"-ws",
"cocoa",
"-arch",
"aarch64",
"-nl",
"en",
"-showsplash",
"-web-config",
"conf/cloudbeaver.conf"
],
"vmArgs": [
"-XX:+IgnoreUnrecognizedVMOptions",
"--add-modules=ALL-SYSTEM",
"-Xms64m",
"-Xmx1024m",
"-Declipse.pde.launch=true",
"-XstartOnFirstThread"
]
}
"args": [
"-product",
"io.cloudbeaver.product.ce.product",
"-configuration",
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/",
"-dev",
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/dev.properties",
"-nl",
"en",
"-web-config",
"conf/cloudbeaver.conf",
"-registryMultiLanguage"
],
// "windows": {
// "args": ["-os", "win32", "-ws", "win32", "-arch", "x86_64"]
// },
// "osx": {
// "args": ["-os", "macosx", "-ws", "cocoa", "-arch", "aarch64"]
// },
"vmArgs": [
"-XX:+IgnoreUnrecognizedVMOptions",
"-Xms64m",
"-Xmx1024m",
"-Declipse.pde.launch=true",
"-XstartOnFirstThread",
"-Dfile.encoding=UTF-8",
"--add-modules=ALL-SYSTEM",
"--add-opens=java.base/java.io=ALL-UNNAMED",
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
"--add-opens=java.base/java.net=ALL-UNNAMED",
"--add-opens=java.base/java.nio=ALL-UNNAMED",
"--add-opens=java.base/java.nio.charset=ALL-UNNAMED",
"--add-opens=java.base/java.text=ALL-UNNAMED",
"--add-opens=java.base/java.time=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
"--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED",
"--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED",
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED",
"--add-opens=java.base/sun.security.ssl=ALL-UNNAMED",
"--add-opens=java.base/sun.security.action=ALL-UNNAMED",
"--add-opens=java.base/sun.security.util=ALL-UNNAMED",
"--add-opens=java.security.jgss/sun.security.jgss=ALL-UNNAMED",
"--add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED",
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
"--add-opens=java.sql/java.sql=ALL-UNNAMED"
]
}
]
}
+15 -18
View File
@@ -17,7 +17,7 @@
"type": "shell",
"command": "yarn",
"group": "test",
"args": ["lerna", "run", "test", "--no-bail", "--stream", "--"]
"args": ["test"]
},
{
"label": "Run DevServer CE",
@@ -34,27 +34,16 @@
}
},
{
"label": "Generate dev proprties for CBCE",
"label": "Generate Eclipse PDE CloudBeaver",
"type": "shell",
"command": "mvn",
"osx": {
"args": [
"package",
"-q",
"exec:java",
"-Dexec.args= -eclipse.version ${eclipse-version} -config ${workspaceFolder}/../idea-workspace-dbeaver/rcp-gen.properties -productFile ${workspaceFolder}/server/product/web-server/CloudbeaverServer.product -projectsFolder ${workspaceFolder}/../ -eclipse ${workspaceFolder}/../dbeaver-workspace/dependencies -output ${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product"
]
"command": "./generate_workspace.sh"
},
"windows": {
"args": [
"package",
"-q",
"exec:java",
"-Dexec.args= -eclipse.version ${eclipse-version} -config ${workspaceFolder}/../idea-workspace-dbeaver/rcp-gen.properties -productFile ${workspaceFolder}/server/product/web-server/CloudbeaverServer.product -projectsFolder ${workspaceFolder}/../ -eclipse ${workspaceFolder}/../dbeaver-workspace/dependencies -output ${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product"
]
"command": "./generate_workspace.cmd"
},
"options": {
"cwd": "${workspaceFolder}/../idea-rcp-launch-config-generator"
"cwd": "${workspaceFolder}/../cloudbeaver"
},
"presentation": {
"reveal": "silent",
@@ -95,7 +84,7 @@
{
"label": "Yarn Install",
"type": "shell",
"command": "yarn install; yarn lerna bootstrap",
"command": "yarn install",
"args": [],
"presentation": {
"reveal": "silent",
@@ -106,7 +95,15 @@
{
"label": "Update TS references CE",
"type": "shell",
"command": "yarn lerna run update-ts-references --stream",
"command": "yarn run update-ts-references",
"options": {
"cwd": "${workspaceFolder}/webapp"
}
},
{
"label": "Clean CE",
"type": "shell",
"command": "yarn clean",
"options": {
"cwd": "${workspaceFolder}/webapp"
}
+46 -42
View File
@@ -1,13 +1,16 @@
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/cloudbeaver-logo.png" align="right" width="250"/>
# CloudBeaver Community
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/cloudbeaver-logo.png" width="250"/>
Cloud Database Manager - Community Edition.
CloudBeaver is a web server which provides rich web interface. Server itself is a Java application, web part is written on TypeScript and React.
CloudBeaver is a web server that provides a rich web interface. The server itself is a Java application, and the web part is written in TypeScript and React.
It is free to use and open-source (licensed under [Apache 2](https://github.com/dbeaver/cloudbeaver/blob/devel/LICENSE) license).
See out [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
See our [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
![](https://github.com/dbeaver/cloudbeaver/wiki/images/demo_screenshot_1.png)
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/connection-creation-demo.png" width="400"/>
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/gis-demo.png" width="400"/>
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/data-transfer-demo.png" width="400"/>
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/sql-editor-demo.png" width="400"/>
## Run in Docker
@@ -16,48 +19,49 @@ See out [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
## Demo server
You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io
You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
[Database access instructions](https://github.com/dbeaver/cloudbeaver/wiki/Demo-Server)
## Changelog
### 24.0.5. 2024-05-20
- The process of application update was improved - you can track the application update process now;
- All popup dialogs became available for screen readers, including JAWS, to improve the experience for users with disabilities;
### 24.2.1. 2024-09-23
- Chinese localization has been improved (thanks to [cashlifei](https://github.com/cashlifei));
- Environment variables configuration has been improved - now you can configure more variables on the initial stage of the Docker setup;
- SQL Server driver has been updated to version 12.8.0.
### 24.2.0. 2024-09-02
### Changes since 24.1.0:
- General:
- French language support was added (thanks to [matthieukhl](https://github.com/matthieukhl))
- Added the ability to close editor tabs with the middle mouse button
- Added right-click support to open the context menu in the Metadata Editor
- The list of forbidden characters for naming and renaming resource manager files has been updated, and now it includes the following characters: / : " \ ' <> | ? *
- Application cookies security was improved
- Authentication:
- Improved LDAP authentication: added the ability to filter users via service account parameters and ability to specify custom unique user identifiers
- Data Editor:
- Large text values (more than 100 Kb) are now automatically opened in the Value panel;
- DuckDB:
- Spatial data visualization support was added;
- The driver has been updated to version 0.10.2;
- Different bug fixes and enhancements have been made.
- Added additional notifications about the restricted operations
- Enhanced IPv6 and DateTime32 data representation for Clickhouse
- Data editing was fixed for DuckDB
- SQL Editor:
- SQL Editor auto-completion was enhanced to get column, table, and function names faster
- Fixed the dollar-quoted string parsing in the SQL Editor for PostgreSQL
- Improved display of the long error messages in the SQL Editor and Log viewer
- Changed the save script icon to a floppy disk for better recognition
- Improved application behavior when closing a connection - open editors won't be closed on disconnect
- Administration:
- Redesigned administration navigation panel - now it is more compact and clear
- Added the ability to change the default commit mode for each connection separately
- Added the ability to configure the server property rootURI parameter (thanks to [arioko](https://github.com/arioko))
- Databases:
- Added the "Keep alive" setting for Db2 LUW and IMB i, Apache Kyuubi, Clickhouse, Firebird, and Trino
- Updated Firebird driver to version 5.0.4
- DDL generation for Oracle Tablespaces was added (thanks to [pandya09](https://github.com/pandya09))
### 24.0.4. 2024-05-06
- Added the ability to stop the process of file upload in the table;
- Row count calculation in the grid can be cancelled for Data Editor and SQL Editor;
- Added the ability to set null values for BLOB and GIS data via the cell's context menu in the table;
- Oracle driver has been updated to version 23.2.0.0.0;
- SQLite driver has been updated to version 3.44.1.0;
- Different bug fixes and enhancements have been made.
## Contribution
As a community-driven open-source project, we warmly welcome contributions through GitHub pull requests.
### 24.0.3. 2024-04-22
- Unauthorized access vulnerability was fixed;
- Added the ability for users to configure personal settings for the interface, SQL editor, and data viewer through the settings panel;
- Added the ability to backup of the internal database before schema migration (for H2);
- Different bug fixes and enhancements have been made.
### 24.0.2. 2024-04-08
- Added the ability to import data to the database from CSV file;
- Implemented support for utilizing environment variables within connection configurations;
- The ability to select a case for column names has been added to CSV export;
- A new Apache Kyuubi driver has been added;
- Trino driver has been updated to version 438;
- Clickhouse driver has been updated to version 0.6.0-patch2;
- Have enhanced security of H2 connection;
- Different bug fixes and enhancements have been made.
### 24.0.1. 2024-03-25
- Added support for two modes for committing changes to the database:
- Auto-commit transfers all changes that you make immediately to the database;
- Manual commit requires your confirmation before committing a change to the database or rolling it back.
- Different bug fixes and enhancements have been made.
[We are happy to reward](https://dbeaver.com/help-dbeaver/) our most active contributors every major sprint.
The most significant contribution to our code for the major release 24.2.0 was made by:
1. [matthieukhl](https://github.com/matthieukhl)
+1 -1
View File
@@ -17,7 +17,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.220</version>
<version>2.1.214</version>
</dependency>
</dependencies>
<build>
+104
View File
@@ -0,0 +1,104 @@
{
server: {
serverPort: "${CLOUDBEAVER_SERVICE_PORT:8978}",
workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}",
contentRoot: "web",
driversLocation: "drivers",
sslConfigurationPath:"${CLOUDBEAVER_SSL_CONF_PATH:workspace/.data/ssl-config.xml}",
rootURI: "${CLOUDBEAVER_ROOT_URI:/}",
serviceURI: "/api/",
productSettings: {
# Global properties
core.theming.theme: 'light',
core.localization.localization: 'en',
plugin.sql-editor.autoSave: true,
plugin.sql-editor.disabled: false,
# max size of the file that can be uploaded to the editor (in kilobytes)
plugin.sql-editor.maxFileSize: 10240,
plugin.log-viewer.disabled: false,
plugin.log-viewer.logBatchSize: 1000,
plugin.log-viewer.maxLogRecords: 2000,
sql.proposals.insert.table.alias: PLAIN
},
expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}",
develMode: "${CLOUDBEAVER_DEVEL_MODE:false}",
enableSecurityManager: false,
sm: {
enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}",
maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}",
minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}",
passwordPolicy: {
minLength: "${CLOUDBEAVER_POLICY_MIN_LENGTH:8}",
requireMixedCase: "${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}",
minNumberCount: "${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}",
minSymbolCount: "${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}"
}
},
database: {
driver: "${CLOUDBEAVER_DB_DRIVER:h2_embedded_v2}",
url: "${CLOUDBEAVER_DB_URL:jdbc:h2:${workspace}/.data/cb.h2v2.dat}",
schema: "${CLOUDBEAVER_DB_SCHEMA:''}",
user: "${CLOUDBEAVER_DB_USER:''}",
password: "${CLOUDBEAVER_DB_PASSWORD:''}",
initialDataConfiguration: "${CLOUDBEAVER_DB_INITIAL_DATA:conf/initial-data.conf}",
pool: {
minIdleConnections: "${CLOUDBEAVER_DB_MIN_IDLE_CONNECTIONS:4}",
maxIdleConnections: "${CLOUDBEAVER_DB_MAX_IDLE_CONNECTIONS:10}",
maxConnections: "${CLOUDBEAVER_DB_MAX_CONNECTIONS:100}",
validationQuery: "${CLOUDBEAVER_DB_VALIDATION_QUERY:SELECT 1}"
},
backupEnabled: "${CLOUDBEAVER_DB_BACKUP_ENABLED:true}"
}
},
app: {
anonymousAccessEnabled: "${CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED:true}",
anonymousUserRole: user,
defaultUserTeam: "${CLOUDBEAVER_APP_DEFAULT_USER_TEAM:user}",
grantConnectionsAccessToAnonymousTeam: "${CLOUDBEAVER_APP_GRANT_CONNECTIONS_ACCESS_TO_ANONYMOUS_TEAM:false}",
supportsCustomConnections: "${CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS:false}",
showReadOnlyConnectionInfo: "${CLOUDBEAVER_APP_READ_ONLY_CONNECTION_INFO:false}",
systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",
forwardProxy: "${CLOUDBEAVER_APP_FORWARD_PROXY:false}",
publicCredentialsSaveEnabled: "${CLOUDBEAVER_APP_PUBLIC_CREDENTIALS_SAVE_ENABLED:true}",
adminCredentialsSaveEnabled: "${CLOUDBEAVER_APP_ADMIN_CREDENTIALS_SAVE_ENABLED:true}",
resourceManagerEnabled: "${CLOUDBEAVER_APP_RESOURCE_MANAGER_ENABLED:true}",
resourceQuotas: {
dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}",
resourceManagerFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_RESOURCE_MANAGER_FILE_SIZE_LIMIT:500000}",
sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}",
sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}",
sqlTextPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_TEXT_PREVIEW_MAX_LENGTH:4096}",
sqlBinaryPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_BINARY_PREVIEW_MAX_LENGTH:261120}"
},
enabledAuthProviders: [
"local"
],
disabledDrivers: [
"sqlite:sqlite_jdbc",
"h2:h2_embedded",
"h2:h2_embedded_v2",
"clickhouse:yandex_clickhouse"
],
disabledBetaFeatures: [
]
}
}
@@ -1,104 +0,0 @@
{
server: {
serverPort: 8978,
workspaceLocation: "workspace",
contentRoot: "web",
driversLocation: "drivers",
sslConfigurationPath:"${CLOUDBEAVER_SSL_CONF_PATH:workspace/.data/ssl-config.xml}",
rootURI: "/",
serviceURI: "/api/",
productSettings: {
# Global properties
core.theming.theme: 'light',
core.localization.localization: 'en',
plugin.sql-editor.autoSave: true,
plugin.sql-editor.disabled: false,
# max size of the file that can be uploaded to the editor (in kilobytes)
plugin.sql-editor.maxFileSize: 10240,
plugin.log-viewer.disabled: false,
plugin.log-viewer.logBatchSize: 1000,
plugin.log-viewer.maxFailedRequests: 3,
plugin.log-viewer.maxLogRecords: 2000,
plugin.log-viewer.refreshTimeout: 3000,
sql.proposals.insert.table.alias: PLAIN
},
expireSessionAfterPeriod: 1800000,
develMode: false,
enableSecurityManager: false,
sm: {
enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}",
maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}",
minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}",
passwordPolicy: {
minLength: "${CLOUDBEAVER_POLICY_MIN_LENGTH:8}",
requireMixedCase: "${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}",
minNumberCount: "${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}",
minSymbolCount: "${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}"
}
},
database: {
driver: "h2_embedded_v2",
url: "jdbc:h2:${workspace}/.data/cb.h2v2.dat",
initialDataConfiguration: "conf/initial-data.conf",
pool: {
minIdleConnections: 4,
maxIdleConnections: 10,
maxConnections: 100,
validationQuery: "SELECT 1"
},
backupEnabled: "${CLOUDBEAVER_DB_BACKUP_ENABLED:true}"
}
},
app: {
anonymousAccessEnabled: true,
anonymousUserRole: "user",
defaultUserTeam: "user",
grantConnectionsAccessToAnonymousTeam: false,
supportsCustomConnections: false,
showReadOnlyConnectionInfo: false,
systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",
forwardProxy: false,
publicCredentialsSaveEnabled: true,
adminCredentialsSaveEnabled: true,
resourceManagerEnabled: true,
resourceQuotas: {
dataExportFileSizeLimit: 10000000,
resourceManagerFileSizeLimit: 500000,
sqlMaxRunningQueries: 100,
sqlResultSetRowsLimit: 100000,
sqlResultSetMemoryLimit: 2000000,
sqlTextPreviewMaxLength: 4096,
sqlBinaryPreviewMaxLength: 261120
},
enabledAuthProviders: [
"local"
],
disabledDrivers: [
"sqlite:sqlite_jdbc",
"h2:h2_embedded",
"h2:h2_embedded_v2",
"clickhouse:yandex_clickhouse"
],
disabledBetaFeatures: [
]
}
}
-3
View File
@@ -1,3 +0,0 @@
### Sample databases
Provides access to locally deployed SQLite sample database
@@ -1,39 +0,0 @@
{
"folders": {},
"connections": {
"sqlite_xerial-sample-database": {
"provider": "generic",
"driver": "sqlite_jdbc",
"name": "SQLite - Chinook (Sample)",
"save-password": true,
"navigator-show-only-entities": false,
"navigator-hide-folders": false,
"read-only": false,
"template": false,
"configuration": {
"database": "${application.path}/../samples/db/Chinook.sqlitedb",
"type": "dev",
"auth-model": "native"
}
},
"postgresql-template-1": {
"provider": "postgresql",
"driver": "postgres-jdbc",
"name": "PostgreSQL (Template)",
"save-password": false,
"show-system-objects": false,
"read-only": true,
"template": true,
"configuration": {
"host": "localhost",
"port": "5432",
"database": "postgres",
"url": "jdbc:postgresql://localhost:5432/postgres",
"type": "dev",
"provider-properties": {
"@dbeaver-show-non-default-db@": "false"
}
}
}
}
}
@@ -1,4 +0,0 @@
{
"folders": {},
"connections": {}
}
@@ -1,99 +0,0 @@
{
server: {
serverPort: 8978,
workspaceLocation: "workspace",
contentRoot: "web",
driversLocation: "drivers",
rootURI: "/",
serviceURI: "/api/",
productSettings: {
# Global properties
core.theming.theme: 'light',
core.localization.localization: 'en',
plugin.sql-editor.autoSave: true,
plugin.sql-editor.disabled: false,
# max size of the file that can be uploaded to the editor (in kilobytes)
plugin.sql-editor.maxFileSize: 10240,
plugin.log-viewer.disabled: false,
plugin.log-viewer.logBatchSize: 1000,
plugin.log-viewer.maxFailedRequests: 3,
plugin.log-viewer.maxLogRecords: 2000,
plugin.log-viewer.refreshTimeout: 3000,
sql.proposals.insert.table.alias: PLAIN
},
expireSessionAfterPeriod: 1800000,
develMode: false,
enableSecurityManager: false,
database: {
driver:"h2_embedded_v2",
url: "jdbc:h2:${workspace}/.data/cb.h2v2.dat",
initialDataConfiguration: "conf/initial-data.conf",
pool: {
minIdleConnections: 4,
maxIdleConnections: 10,
maxConnections: 100,
validationQuery: "SELECT 1"
},
backupEnabled: "${CLOUDBEAVER_DB_BACKUP_ENABLED:true}"
},
sm: {
enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}",
maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}",
minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}",
passwordPolicy: {
minLength: "${CLOUDBEAVER_POLICY_MIN_LENGTH:8}",
requireMixedCase: "${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}",
minNumberCount: "${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}",
minSymbolCount: "${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}"
}
}
},
app: {
anonymousAccessEnabled: true,
anonymousUserRole: "user",
grantConnectionsAccessToAnonymousTeam: false,
supportsCustomConnections: false,
showReadOnlyConnectionInfo: false,
systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",
forwardProxy: false,
publicCredentialsSaveEnabled: true,
adminCredentialsSaveEnabled: true,
resourceManagerEnabled: true,
resourceQuotas: {
dataExportFileSizeLimit: 10000000,
resourceManagerFileSizeLimit: 500000,
sqlMaxRunningQueries: 100,
sqlResultSetRowsLimit: 100000,
sqlResultSetMemoryLimit: 2000000,
sqlTextPreviewMaxLength: 4096,
sqlBinaryPreviewMaxLength: 261120
},
enabledAuthProviders: [
"local"
],
disabledDrivers: [
"h2:h2_embedded",
"h2:h2_embedded_v2",
"clickhouse:yandex_clickhouse"
],
disabledBetaFeatures: [
]
}
}
Binary file not shown.
-6
View File
@@ -1,6 +0,0 @@
Chinook Database - Version 1.3
Script: Chinook_Sqlite.sql
Description: Creates and populates the Chinook database.
DB Server: Sqlite
Author: Luis Rocha
License: http://www.codeplex.com/ChinookDatabase/license
+1 -20
View File
@@ -2,12 +2,6 @@
set -Eeo pipefail
set +u
# #command line arguments
# CONFIGURATION_PATH=${1-"../config/sample-databases/DefaultConfiguration"}
# SAMPLE_DATABASE_PATH=${2-""}
# echo $CONFIGURATION_PATH
# echo $SAMPLE_DATABASE_PATH
echo "Clone and build Cloudbeaver"
rm -rf ./drivers
@@ -16,7 +10,6 @@ mkdir ./cloudbeaver
mkdir ./cloudbeaver/server
mkdir ./cloudbeaver/conf
mkdir ./cloudbeaver/workspace
mkdir ./cloudbeaver/web
echo "Pull cloudbeaver platform"
@@ -44,20 +37,8 @@ cp -rp ../server/product/web-server/target/products/io.cloudbeaver.product/all/a
cp -p ./scripts/* ./cloudbeaver
mkdir cloudbeaver/samples
if [[ -z $SAMPLE_DATABASE_PATH ]]; then
SAMPLE_DATABASE_PATH=""
else
mkdir cloudbeaver/samples/db
cp -rp "${SAMPLE_DATABASE_PATH}" cloudbeaver/samples/
fi
if [[ -z "$CONFIGURATION_PATH" ]]; then
CONFIGURATION_PATH="../config/sample-databases/DefaultConfiguration"
fi
cp -rp ../config/core/* cloudbeaver/conf
cp -rp "${CONFIGURATION_PATH}"/GlobalConfiguration/.dbeaver/data-sources.json cloudbeaver/conf/initial-data-sources.conf
cp -p "${CONFIGURATION_PATH}"/*.conf cloudbeaver/conf/
cp -rp ../config/GlobalConfiguration/.dbeaver/data-sources.json cloudbeaver/conf/initial-data-sources.conf
mv drivers cloudbeaver
echo "End of backend build"
+12 -2
View File
@@ -3,15 +3,25 @@ set -Eeuo pipefail
echo "Build static content"
mkdir ./cloudbeaver/web
cd ../../cloudbeaver/webapp
yarn
yarn lerna run bootstrap
yarn lerna run bundle --no-bail --stream --scope=@cloudbeaver/product-default #-- -- --env source-map
cd ./packages/product-default
yarn run bundle
if [[ "$?" -ne 0 ]] ; then
echo 'Application build failed'; exit $rc
fi
cd ../../
yarn test
if [[ "$?" -ne 0 ]] ; then
echo 'Frontend tests failed'; exit $rc
fi
cd ../deploy
echo "Copy static content"
-1
View File
@@ -1 +0,0 @@
@call build.bat ..\config\sample-databases\SQLiteConfiguration ..\config\sample-databases\db
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -Eeuo pipefail
#command line arguments
CONFIGURATION_PATH='../config/sample-databases/SQLiteConfiguration'
SAMPLE_DATABASE_PATH='../config/sample-databases/db'
source build-backend.sh
source build-frontend.sh
+2 -11
View File
@@ -1,11 +1,6 @@
@echo off
rem command line arguments
SET CONFIGURATION_PATH=%1
SET SAMPLE_DATABASE_PATH=%2
IF "%CONFIGURATION_PATH%"=="" SET CONFIGURATION_PATH="..\config\sample-databases\DefaultConfiguration"
echo "Configuration path=%CONFIGURATION_PATH%"
echo Clone and build Cloudbeaver
@@ -40,13 +35,9 @@ xcopy /E /Q ..\server\product\web-server\target\products\io.cloudbeaver.product\
copy scripts\* cloudbeaver >NUL
mkdir cloudbeaver\samples
IF NOT "%SAMPLE_DATABASE_PATH%"=="" (
mkdir cloudbeaver\samples\db
xcopy /E /Q %SAMPLE_DATABASE_PATH% cloudbeaver\samples\db >NUL
)
copy ..\config\core\* cloudbeaver\conf >NUL
copy %CONFIGURATION_PATH%\GlobalConfiguration\.dbeaver\data-sources.json cloudbeaver\conf\initial-data-sources.conf >NUL
copy %CONFIGURATION_PATH%\*.conf cloudbeaver\conf >NUL
copy ..\config\DefaultConfiguration\GlobalConfiguration\.dbeaver\data-sources.json cloudbeaver\conf\initial-data-sources.conf >NUL
move drivers cloudbeaver >NUL
-4
View File
@@ -1,9 +1,5 @@
#!/bin/bash
set -Eeuo pipefail
#command line arguments
CONFIGURATION_PATH="../config/sample-databases/DefaultConfiguration"
SAMPLE_DATABASE_PATH=""
source build-backend.sh
source build-frontend.sh
+3
View File
@@ -2,6 +2,9 @@ FROM dbeaver/base-java
MAINTAINER DBeaver Corp, devops@dbeaver.com
RUN apt-get update; \
apt-get upgrade -y;
COPY cloudbeaver /opt/cloudbeaver
EXPOSE 8978
+3
View File
@@ -0,0 +1,3 @@
SET mypath=%~dp0
.\..\idea-rcp-launch-config-generator\runGenerator.cmd -f %mypath%
+1
View File
@@ -0,0 +1 @@
./../idea-rcp-launch-config-generator/runGenerator.sh -f "$PWD"
-1
View File
@@ -1,4 +1,3 @@
{
"projects": ["../dbeaver-common", "../dbeaver", "../cloudbeaver/server"],
"targetPlatform": "./org.jkiss.cloudbeaver.tp.target"
}
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
<target name="org.jkiss.tp.cloudbeaver">
<target name="org.jkiss.cloudbeaver.tp">
<locations>
<location path="../dbeaver-workspace/dependencies/plugins" type="Directory"/>
</locations>
+33
View File
@@ -0,0 +1,33 @@
workspaceName=cloudbeaver-ce
featuresPaths=\
dbeaver/features;\
cloudbeaver/server/features;
bundlesPaths=\
dbeaver-common/modules;\
dbeaver/plugins;\
cloudbeaver/server/bundles;
testLibraries=\
org.junit;\
org.mockito.mockito-core;\
junit-jupiter-api;\
org.opentest4j
repositories=\
https://p2.dev.dbeaver.com/eclipse-repo/;\
https://download.eclipse.org/releases/${eclipse-version}/;
testBundles=\
org.junit;\
org.mockito.mockito-core;\
junit-jupiter-api;\
org.opentest4j
productsPaths=\
dbeaver/product/community/DBeaver.product;\
cloudbeaver/server/product/web-server/CloudbeaverServer.product:../../opt/cloudbeaver;
ideaConfigurationFilesPaths=\
dbeaver/.ide/.idea;
testBundlePaths=\
dbeaver/test;\
cloudbeaver/server/test;
additionalModuleRoots=\
opt;
optionalFeatureRepositories=\
dbeaver/product/repositories
@@ -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.54.qualifier
Bundle-Release-Date: 20240603
Bundle-Version: 1.0.62.qualifier
Bundle-Release-Date: 20241007
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
@@ -18,7 +18,7 @@ Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
org.jkiss.bundle.graphql.java;visibility:=reexport,
org.jkiss.bundle.apache.dbcp,
com.google.gson;visibility:=reexport,
jakarta.servlet;visibility:=reexport
jakarta.servlet-api;bundle-version:="6.0.0";visibility:=reexport
Export-Package: io.cloudbeaver,
io.cloudbeaver.auth,
io.cloudbeaver.auth.provider,
@@ -28,7 +28,9 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.websocket,
io.cloudbeaver.model,
io.cloudbeaver.model.app,
io.cloudbeaver.model.config,
io.cloudbeaver.model.fs,
io.cloudbeaver.model.log,
io.cloudbeaver.model.rm,
io.cloudbeaver.model.rm.local,
io.cloudbeaver.model.rm.lock,
@@ -41,6 +43,7 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.service.admin,
io.cloudbeaver.service.security,
io.cloudbeaver.service.sql,
io.cloudbeaver.test,
io.cloudbeaver.utils,
io.cloudbeaver.utils.file
Automatic-Module-Name: io.cloudbeaver.model
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.model</artifactId>
<version>1.0.54-SNAPSHOT</version>
<version>1.0.62-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -16,23 +16,21 @@
*/
package io.cloudbeaver;
import org.eclipse.core.resources.IProject;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMControllerProvider;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.registry.BaseProjectImpl;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.Pair;
import java.nio.file.Path;
import java.util.Collection;
public class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerProvider {
public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerProvider {
@NotNull
private final RMProject project;
@@ -40,21 +38,18 @@ public class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerP
@NotNull
private final Path path;
@NotNull
protected final DataSourceFilter dataSourceFilter;
private final RMController resourceController;
public BaseWebProjectImpl(
@NotNull DBPWorkspace workspace,
@NotNull RMController resourceController,
@NotNull SMSessionContext sessionContext,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
@NotNull RMProject project
) {
super(workspace, sessionContext);
this.resourceController = resourceController;
this.path = RMUtils.getProjectPath(project);
this.project = project;
this.dataSourceFilter = dataSourceFilter;
}
@NotNull
@@ -91,12 +86,6 @@ public class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerP
return path;
}
@Nullable
@Override
public IProject getEclipseProject() {
return null;
}
@Override
public boolean isOpen() {
return true;
@@ -112,11 +101,6 @@ public class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerP
return false;
}
@NotNull
public RMProject getRmProject() {
return this.project;
}
/**
* Method for Bulk Update of resources properties paths
*
@@ -35,6 +35,7 @@ public interface DBWConstants {
String PERMISSION_EDIT_DATA = "edit-data";
String STATE_ATTR_SIGN_IN_STATE = "state.signin";
String WORK_DATA_FOLDER_NAME = ".work-data";
enum SignInState {
GLOBAL,
@@ -21,7 +21,7 @@ import graphql.ErrorType;
import graphql.GraphQLError;
import graphql.language.SourceLocation;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.sql.SQLState;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
@@ -38,6 +38,7 @@ public class DBWebException extends DBException implements GraphQLError {
public static final String ERROR_CODE_SESSION_EXPIRED = "sessionExpired";
public static final String ERROR_CODE_ACCESS_DENIED = "accessDenied";
public static final String ERROR_CODE_SERVER_NOT_INITIALIZED = "serverNotInitialized";
public static final String ERROR_CODE_LICENSE_DENIED = "licenseRequired";
public static final String ERROR_CODE_IDENT_REQUIRED = "identRequired";
public static final String ERROR_CODE_AUTH_REQUIRED = "authRequired";
@@ -65,12 +66,8 @@ public class DBWebException extends DBException implements GraphQLError {
this.webErrorCode = errorCode;
}
public DBWebException(Throwable cause, DBPDataSource dataSource) {
super(cause, dataSource);
}
public DBWebException(String message, Throwable cause, DBPDataSource dataSource) {
super(makeMessage(message, cause), cause, dataSource);
public DBWebException(Throwable cause) {
super(null, cause);
}
public String getWebErrorCode() {
@@ -128,14 +125,14 @@ public class DBWebException extends DBException implements GraphQLError {
//stString = stString.substring(divPos + 1).trim();
}
extensions.put("stackTrace", stString.trim());
int errorCode = getErrorCode();
int errorCode = SQLState.getCodeFromException(this);
if (errorCode != ERROR_CODE_NONE) {
extensions.put("errorCode", errorCode);
}
if (!CommonUtils.isEmpty(webErrorCode)) {
extensions.put("webErrorCode", webErrorCode);
}
String databaseState = getDatabaseState();
String databaseState = SQLState.getStateFromException(this);
if (databaseState != null) {
extensions.put("databaseState", databaseState);
}
@@ -261,7 +261,7 @@ public class WebDataSourceRegistryProxy implements DBPDataSourceRegistry, DataSo
}
@Override
public void removeAuthProfile(DBAAuthProfile profile) {
public void removeAuthProfile(@NotNull DBAAuthProfile profile) {
dataSourceRegistry.removeAuthProfile(profile);
}
@@ -0,0 +1,36 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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;
import io.cloudbeaver.model.session.WebHeadlessSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.rm.RMProject;
public class WebHeadlessSessionProjectImpl extends WebProjectImpl {
public WebHeadlessSessionProjectImpl(
@NotNull WebHeadlessSession session,
@NotNull RMProject project
) {
super(
session.getWorkspace(),
session.getUserContext().getRmController(),
session.getSessionContext(),
project,
session.getUserContext().getPreferenceStore()
);
}
}
@@ -26,22 +26,22 @@ import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.task.DBTTaskManager;
import org.jkiss.dbeaver.registry.rm.DataSourceRegistryRM;
import org.jkiss.dbeaver.runtime.DBWorkbench;
public abstract class WebProjectImpl extends BaseWebProjectImpl {
private static final Log log = Log.getLog(WebProjectImpl.class);
@NotNull
private final DBPPreferenceStore preferenceStore;
protected final DBPPreferenceStore preferenceStore;
public WebProjectImpl(
@NotNull DBPWorkspace workspace,
@NotNull RMController resourceController,
@NotNull SMSessionContext sessionContext,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter,
@NotNull DBPPreferenceStore preferenceStore
) {
super(workspace, resourceController, sessionContext, project, dataSourceFilter);
super(workspace, resourceController, sessionContext, project);
this.preferenceStore = preferenceStore;
}
@@ -70,13 +70,24 @@ public abstract class WebProjectImpl extends BaseWebProjectImpl {
return DBWorkbench.isDistributed();
}
@NotNull
@Override
public DBTTaskManager getTaskManager() {
throw new IllegalStateException("Task manager not supported");
}
@NotNull
@Override
protected DBPDataSourceRegistry createDataSourceRegistry() {
return new WebDataSourceRegistryProxy(
new DataSourceRegistryRM(this, getResourceController(), preferenceStore),
dataSourceFilter
getDataSourceFilter()
);
}
@NotNull
public DataSourceFilter getDataSourceFilter() {
return (ds) -> true;
}
}
@@ -0,0 +1,118 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPEvent;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.security.user.SMObjectPermissions;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Global project.
* Connections there can be not accessible.
*/
public class WebSessionGlobalProjectImpl extends WebSessionProjectImpl {
private static final Log log = Log.getLog(WebSessionGlobalProjectImpl.class);
private Set<String> accessibleConnectionIds = Collections.emptySet();
public WebSessionGlobalProjectImpl(@NotNull WebSession webSession, @NotNull RMProject project) {
super(webSession, project);
}
/**
* Update info about accessible connections from a database.
*/
public synchronized void refreshAccessibleConnectionIds() {
this.accessibleConnectionIds = readAccessibleConnectionIds();
}
@NotNull
private Set<String> readAccessibleConnectionIds() {
try {
return webSession.getSecurityController()
.getAllAvailableObjectsPermissions(SMObjectType.datasource)
.stream()
.map(SMObjectPermissions::getObjectId)
.collect(Collectors.toSet());
} catch (DBException e) {
webSession.addSessionError(e);
log.error("Error reading connection grants", e);
return Collections.emptySet();
}
}
/**
* Checks if connection is accessible for current user.
*/
public boolean isDataSourceAccessible(@NotNull DBPDataSourceContainer dataSource) {
return dataSource.isExternallyProvided() ||
dataSource.isTemporary() ||
webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) ||
accessibleConnectionIds.contains(dataSource.getId());
}
/**
* Adds a connection if it became accessible.
* The method is processed when connection permissions were updated.
*/
public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) {
if (!getRMProject().isGlobal()) {
return;
}
this.accessibleConnectionIds.add(dsId);
var registry = getDataSourceRegistry();
var dataSource = registry.getDataSource(dsId);
if (dataSource != null) {
addConnection(dataSource);
// reflect changes is navigator model
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true));
}
}
/**
* Removes a connection if it became not accessible.
* The method is processed when connection permissions were updated.
*/
public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) {
if (!getRMProject().isGlobal()) {
return;
}
var registry = getDataSourceRegistry();
var dataSource = registry.getDataSource(dsId);
if (dataSource != null) {
this.accessibleConnectionIds.remove(dsId);
removeConnection(dataSource);
// reflect changes is navigator model
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource));
dataSource.dispose();
}
}
@NotNull
public DataSourceFilter getDataSourceFilter() {
return this::isDataSourceAccessible;
}
}
@@ -16,27 +16,39 @@
*/
package io.cloudbeaver;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.runtime.jobs.DisconnectJob;
import java.util.*;
import java.util.stream.Collectors;
public class WebSessionProjectImpl extends WebProjectImpl {
private final WebSession webSession;
private static final Log log = Log.getLog(WebSessionProjectImpl.class);
protected final WebSession webSession;
private final Map<String, WebConnectionInfo> connections = new HashMap<>();
private boolean registryIsLoaded = false;
public WebSessionProjectImpl(
@NotNull WebSession webSession,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
@NotNull RMProject project
) {
super(
webSession.getWorkspace(),
webSession.getRmController(),
webSession.getSessionContext(),
project,
dataSourceFilter,
webSession.getUserPreferenceStore()
);
this.webSession = webSession;
@@ -47,4 +59,156 @@ public class WebSessionProjectImpl extends WebProjectImpl {
public DBNModel getNavigatorModel() {
return webSession.getNavigatorModel();
}
@NotNull
@Override
protected DBPDataSourceRegistry createDataSourceRegistry() {
DBPDataSourceRegistry dataSourceRegistry = super.createDataSourceRegistry();
dataSourceRegistry.setAuthCredentialsProvider(webSession);
return dataSourceRegistry;
}
private synchronized void addDataSourcesToCache() {
if (registryIsLoaded) {
return;
}
getDataSourceRegistry().getDataSources().forEach(this::addConnection);
Throwable lastError = getDataSourceRegistry().getLastError();
if (lastError != null) {
webSession.addSessionError(lastError);
log.error("Error refreshing connections from project '" + getId() + "'", lastError);
}
registryIsLoaded = true;
}
@Override
public void dispose() {
super.dispose();
Map<String, WebConnectionInfo> conCopy;
synchronized (this.connections) {
conCopy = new HashMap<>(this.connections);
this.connections.clear();
}
for (WebConnectionInfo connectionInfo : conCopy.values()) {
if (connectionInfo.isConnected()) {
new DisconnectJob(connectionInfo.getDataSourceContainer()).schedule();
}
}
}
/**
* Returns web connection info from cache (if exists).
*/
@Nullable
public WebConnectionInfo findWebConnectionInfo(@NotNull String connectionId) {
synchronized (connections) {
return connections.get(connectionId);
}
}
/**
* Returns web connection info from cache, adds it to cache if not present.
* Throws exception if connection is not found.
*/
@NotNull
public WebConnectionInfo getWebConnectionInfo(@NotNull String connectionId) throws DBWebException {
WebConnectionInfo connectionInfo = findWebConnectionInfo(connectionId);
if (connectionInfo != null) {
return connectionInfo;
}
DBPDataSourceContainer dataSource = getDataSourceRegistry().getDataSource(connectionId);
if (dataSource != null) {
return addConnection(dataSource);
}
throw new DBWebException("Connection '%s' not found".formatted(connectionId));
}
/**
* Adds connection to project cache.
*/
@NotNull
public synchronized WebConnectionInfo addConnection(@NotNull DBPDataSourceContainer dataSourceContainer) {
WebConnectionInfo connection = new WebConnectionInfo(webSession, dataSourceContainer);
synchronized (connections) {
connections.put(dataSourceContainer.getId(), connection);
}
return connection;
}
/**
* Removes connection from project cache.
*/
public void removeConnection(@NotNull DBPDataSourceContainer dataSourceContainer) {
WebConnectionInfo webConnectionInfo = connections.get(dataSourceContainer.getId());
if (webConnectionInfo != null) {
webConnectionInfo.clearCache();
synchronized (connections) {
connections.remove(dataSourceContainer.getId());
}
}
}
/**
* Loads connection from registry if they are not loaded.
*
* @return connections from cache.
*/
public List<WebConnectionInfo> getConnections() {
if (!registryIsLoaded) {
addDataSourcesToCache();
registryIsLoaded = true;
}
synchronized (connections) {
return new ArrayList<>(connections.values());
}
}
/**
* updates data sources based on event in web session
*
* @param dataSourceIds list of updated connections
* @param type type of event
*/
public synchronized boolean updateProjectDataSources(@NotNull List<String> dataSourceIds, @NotNull WSEventType type) {
var sendDataSourceUpdatedEvent = false;
DBPDataSourceRegistry registry = getDataSourceRegistry();
// save old connections
var oldDataSources = dataSourceIds.stream()
.map(registry::getDataSource)
.filter(Objects::nonNull)
.collect(Collectors.toMap(
DBPDataSourceContainer::getId,
ds -> new DataSourceDescriptor((DataSourceDescriptor) ds, ds.getRegistry())
));
if (type == WSEventType.DATASOURCE_CREATED || type == WSEventType.DATASOURCE_UPDATED) {
registry.refreshConfig(dataSourceIds);
}
for (String dsId : dataSourceIds) {
DataSourceDescriptor ds = (DataSourceDescriptor) registry.getDataSource(dsId);
if (ds == null) {
continue;
}
switch (type) {
case DATASOURCE_CREATED -> {
addConnection(ds);
sendDataSourceUpdatedEvent = true;
}
case DATASOURCE_UPDATED -> // if settings were changed we need to send event
sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId));
case DATASOURCE_DELETED -> {
WebDataSourceUtils.disconnectDataSource(webSession, ds);
if (registry instanceof DBPDataSourceRegistryCache dsrc) {
dsrc.removeDataSourceFromList(ds);
}
removeConnection(ds);
sendDataSourceUpdatedEvent = true;
}
default -> {
}
}
}
return sendDataSourceUpdatedEvent;
}
}
@@ -46,6 +46,9 @@ public interface SMAuthProviderFederated extends SMSignOutLinkProvider {
@Nullable
String getAcsLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException;
@Nullable
String getEntityIdLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException;
@Nullable
default String getRedirectLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException {
return null;
@@ -24,12 +24,11 @@ import io.cloudbeaver.service.sql.WebDataFormat;
import io.cloudbeaver.utils.CBModelConstants;
import io.cloudbeaver.utils.WebAppUtils;
import io.cloudbeaver.utils.WebCommonUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPDataSourceFolder;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.admin.sessions.DBAServerSessionManager;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPAuthModelDescriptor;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
@@ -40,6 +39,7 @@ import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
import org.jkiss.dbeaver.model.navigator.DBNDataSource;
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.runtime.DBWorkbench;
@@ -56,6 +56,17 @@ public class WebConnectionInfo {
private static final Log log = Log.getLog(WebConnectionInfo.class);
public static final String SECURED_VALUE = "********";
private static final String FEATURE_HAS_TOOLS = "hasTools";
private static final String FEATURE_CONNECTED = "connected";
private static final String FEATURE_VIRTUAL = "virtual";
private static final String FEATURE_TEMPORARY = "temporary";
private static final String FEATURE_READ_ONLY = "readOnly";
private static final String FEATURE_PROVIDED = "provided";
private static final String FEATURE_MANAGEABLE = "manageable";
private static final String TOOL_SESSION_MANAGER = "sessionManager";
private final WebSession session;
private final DBPDataSourceContainer dataSourceContainer;
private WebServerError connectError;
@@ -243,22 +254,25 @@ public class WebConnectionInfo {
List<String> features = new ArrayList<>();
if (dataSourceContainer.isConnected()) {
features.add("connected");
features.add(FEATURE_CONNECTED);
if (!getTools().isEmpty()) {
features.add(FEATURE_HAS_TOOLS);
}
}
if (dataSourceContainer.isHidden()) {
features.add("virtual");
features.add(FEATURE_VIRTUAL);
}
if (dataSourceContainer.isTemporary()) {
features.add("temporary");
features.add(FEATURE_TEMPORARY);
}
if (dataSourceContainer.isConnectionReadOnly()) {
features.add("readOnly");
features.add(FEATURE_READ_ONLY);
}
if (dataSourceContainer.isProvided()) {
features.add("provided");
features.add(FEATURE_PROVIDED);
}
if (dataSourceContainer.isManageable()) {
features.add("manageable");
features.add(FEATURE_MANAGEABLE);
}
return features.toArray(new String[0]);
@@ -384,6 +398,16 @@ public class WebConnectionInfo {
}
}
@Property
public Map<String, String> getMainPropertyValues() {
Map<String, String> mainProperties = new LinkedHashMap<>();
mainProperties.put(DBConstants.PROP_HOST, getHost());
mainProperties.put(DBConstants.PROP_PORT, getPort());
mainProperties.put(DBConstants.PROP_DATABASE, getDatabaseName());
mainProperties.put(DBConstants.PROP_SERVER, getServerName());
return mainProperties;
}
@Property
public Map<String, String> getProviderProperties() {
return dataSourceContainer.getConnectionConfiguration().getProviderProperties();
@@ -421,10 +445,10 @@ public class WebConnectionInfo {
private boolean hasProjectPermission(RMProjectPermission projectPermission) {
DBPProject project = dataSourceContainer.getProject();
if (!(project instanceof WebProjectImpl)) {
if (!(project instanceof WebProjectImpl webProject)) {
return false;
}
return SMUtils.hasProjectPermission(session, ((WebProjectImpl) project).getRmProject(), projectPermission);
return SMUtils.hasProjectPermission(session, webProject.getRMProject(), projectPermission);
}
private boolean canViewReadOnlyConnections() {
@@ -448,6 +472,15 @@ public class WebConnectionInfo {
return dataSourceContainer.getConnectionConfiguration().getKeepAliveInterval();
}
@Property
public boolean isAutocommit() {
Boolean isAutoCommit = dataSourceContainer.getConnectionConfiguration().getBootstrap().getDefaultAutoCommit();
if (isAutoCommit == null) {
return true;
}
return isAutoCommit;
}
@Property
public List<WebSecretInfo> getSharedSecrets() throws DBException {
return dataSourceContainer.listSharedCredentials()
@@ -456,4 +489,18 @@ public class WebConnectionInfo {
.collect(Collectors.toList());
}
@NotNull
@Property
public List<String> getTools() {
if (!session.hasPermission(RMConstants.PERMISSION_DATABASE_DEVELOPER)) {
return List.of();
}
List<String> tools = new ArrayList<>();
// checks inside that datasource is not null in container, and it is adaptable to session manager class
if (DBUtils.getAdapter(DBAServerSessionManager.class, dataSourceContainer) != null) {
tools.add(TOOL_SESSION_MANAGER);
}
return tools;
}
}
@@ -53,11 +53,13 @@ public class WebProjectInfo {
}
@Property
public boolean isGlobal() { return project.getRmProject().isGlobal(); }
public boolean isGlobal() {
return project.getRMProject().isGlobal();
}
@Property
public boolean isShared() {
return project.getRmProject().isShared();
return project.getRMProject().isShared();
}
@Property
@@ -72,7 +74,7 @@ public class WebProjectInfo {
@Property
public boolean isCanEditDataSources() {
if (project.getRmProject().getType() == RMProjectType.USER && !customPrivateConnectionsEnabled) {
if (project.getRMProject().getType() == RMProjectType.USER && !customPrivateConnectionsEnabled) {
return false;
}
return hasDataSourcePermission(RMProjectPermission.DATA_SOURCES_EDIT);
@@ -94,12 +96,12 @@ public class WebProjectInfo {
}
private boolean hasDataSourcePermission(RMProjectPermission permission) {
return SMUtils.hasProjectPermission(session, project.getRmProject(), permission);
return SMUtils.hasProjectPermission(session, project.getRMProject(), permission);
}
@Property
public RMResourceType[] getResourceTypes() {
RMResourceType[] resourceTypes = project.getRmProject().getResourceTypes();
RMResourceType[] resourceTypes = project.getRMProject().getResourceTypes();
if(resourceTypes == null) {
return ArrayUtils.toArray(RMResourceType.class, new ArrayList<>());
@@ -17,8 +17,8 @@
package io.cloudbeaver.model;
import io.cloudbeaver.DBWebException;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.sql.DBQuotaException;
import org.jkiss.dbeaver.model.sql.SQLState;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -28,22 +28,18 @@ import java.io.StringWriter;
*/
public class WebServerError {
private String message;
private String stackTrace;
private String errorType;
private String errorCode;
private final String message;
private final String stackTrace;
private final String errorType;
private final String errorCode;
public WebServerError(Throwable ex) {
this.message = ex.getMessage();
StringWriter buf = new StringWriter();
ex.printStackTrace(new PrintWriter(buf, true));
this.stackTrace = buf.toString();
if (ex instanceof DBException) {
errorCode = String.valueOf(((DBException) ex).getErrorCode());
}
if (ex instanceof DBQuotaException) {
errorType = DBWebException.ERROR_CODE_QUOTA_EXCEEDED;
}
errorCode = String.valueOf(SQLState.getCodeFromException(ex));
errorType = ex instanceof DBQuotaException ? DBWebException.ERROR_CODE_QUOTA_EXCEEDED : null;
}
public String getMessage() {
@@ -1,144 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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.app;
import com.google.gson.annotations.Expose;
import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderRegistry;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import org.jkiss.utils.ArrayUtils;
import java.util.*;
public abstract class BaseAuthWebAppConfiguration extends BaseWebAppConfiguration implements WebAuthConfiguration {
private String defaultAuthProvider;
private String[] enabledAuthProviders;
private final Set<SMAuthProviderCustomConfiguration> authConfigurations;
// Legacy auth configs, left for backward compatibility
@Expose(serialize = false)
private final Map<String, SMAuthProviderCustomConfiguration> authConfiguration;
public BaseAuthWebAppConfiguration() {
super();
this.defaultAuthProvider = LocalAuthProviderConstants.PROVIDER_ID;
this.enabledAuthProviders = null;
this.authConfigurations = new LinkedHashSet<>();
this.authConfiguration = new LinkedHashMap<>();
}
public BaseAuthWebAppConfiguration(BaseAuthWebAppConfiguration src) {
super(src);
this.defaultAuthProvider = src.defaultAuthProvider;
this.enabledAuthProviders = src.enabledAuthProviders;
this.authConfigurations = new LinkedHashSet<>(src.authConfigurations);
this.authConfiguration = new LinkedHashMap<>(src.authConfiguration);
}
@Override
public String getDefaultAuthProvider() {
return defaultAuthProvider;
}
public void setDefaultAuthProvider(String defaultAuthProvider) {
this.defaultAuthProvider = defaultAuthProvider;
}
@Override
public String[] getEnabledAuthProviders() {
if (enabledAuthProviders == null) {
// No config - enable all providers (+backward compatibility)
return WebAuthProviderRegistry.getInstance().getAuthProviders()
.stream().map(WebAuthProviderDescriptor::getId).toArray(String[]::new);
}
return enabledAuthProviders;
}
public void setEnabledAuthProviders(String[] enabledAuthProviders) {
this.enabledAuthProviders = enabledAuthProviders;
}
@Override
public boolean isAuthProviderEnabled(String id) {
var authProviderDescriptor = WebAuthProviderRegistry.getInstance().getAuthProvider(id);
if (authProviderDescriptor == null) {
return false;
}
if (!ArrayUtils.contains(getEnabledAuthProviders(), id)) {
return false;
}
if (!ArrayUtils.isEmpty(authProviderDescriptor.getRequiredFeatures())) {
for (String rf : authProviderDescriptor.getRequiredFeatures()) {
if (!isFeatureEnabled(rf)) {
return false;
}
}
}
return true;
}
////////////////////////////////////////////
// Auth provider configs
@Override
public Set<SMAuthProviderCustomConfiguration> getAuthCustomConfigurations() {
return authConfigurations;
}
@Override
@Nullable
public SMAuthProviderCustomConfiguration getAuthProviderConfiguration(@NotNull String id) {
synchronized (authConfigurations) {
return authConfigurations.stream().filter(c -> c.getId().equals(id)).findAny().orElse(null);
}
}
public void addAuthProviderConfiguration(@NotNull SMAuthProviderCustomConfiguration config) {
synchronized (authConfigurations) {
authConfigurations.removeIf(c -> c.getId().equals(config.getId()));
authConfigurations.add(config);
}
}
public void setAuthProvidersConfigurations(Collection<SMAuthProviderCustomConfiguration> authProviders) {
synchronized (authConfigurations) {
authConfigurations.clear();
authConfigurations.addAll(authProviders);
}
}
public boolean deleteAuthProviderConfiguration(@NotNull String id) {
synchronized (authConfigurations) {
return authConfigurations.removeIf(c -> c.getId().equals(id));
}
}
public void loadLegacyCustomConfigs() {
// Convert legacy map of configs into list
if (!authConfiguration.isEmpty()) {
for (Map.Entry<String, SMAuthProviderCustomConfiguration> entry : authConfiguration.entrySet()) {
entry.getValue().setId(entry.getKey());
authConfigurations.add(entry.getValue());
}
authConfiguration.clear();
}
}
}
@@ -18,13 +18,16 @@ package io.cloudbeaver.model.app;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.jkiss.code.NotNull;
/**
* Abstract class that contains methods for loading configuration with gson.
*/
public abstract class BaseServerConfigurationController<T extends WebServerConfiguration> implements WebServerConfigurationController<T> {
public abstract class BaseServerConfigurationController<T extends WebServerConfiguration>
implements WebServerConfigurationController<T> {
protected Gson getGson() {
@NotNull
public Gson getGson() {
return getGsonBuilder().create();
}
@@ -16,13 +16,7 @@
*/
package io.cloudbeaver.model.app;
import io.cloudbeaver.DataSourceFilter;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.WebSessionProjectImpl;
import io.cloudbeaver.model.log.SLF4JLogHandler;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.WebGlobalWorkspace;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.app.IApplicationContext;
import org.jkiss.code.NotNull;
@@ -30,18 +24,16 @@ 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.DBPPlatform;
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.impl.app.ApplicationRegistry;
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.websocket.event.WSEventController;
import org.jkiss.dbeaver.registry.BaseApplicationImpl;
import org.jkiss.dbeaver.registry.BaseWorkspaceImpl;
import org.jkiss.dbeaver.runtime.IVariableResolver;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.RuntimeUtils;
@@ -62,17 +54,10 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
public static final String CLI_PARAM_WEB_CONFIG = "-web-config";
public static final String LOGBACK_FILE_NAME = "logback.xml";
private static final Log log = Log.getLog(BaseWebApplication.class);
private String instanceId;
@NotNull
@Override
public DBPWorkspace createWorkspace(@NotNull DBPPlatform platform, @NotNull IWorkspace eclipseWorkspace) {
return new WebGlobalWorkspace(platform, eclipseWorkspace);
}
@Override
public RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@@ -170,19 +155,6 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
return Files.exists(customConfigPath) ? customConfigPath : configPath.resolve(fileName);
}
@Override
public WebProjectImpl createProjectImpl(
@NotNull WebSession webSession,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
) {
return new WebSessionProjectImpl(
webSession,
project,
dataSourceFilter
);
}
/**
* There is no secret controller in base web app.
* Method returns VoidSecretController instance.
@@ -16,9 +16,6 @@
*/
package io.cloudbeaver.model.app;
import io.cloudbeaver.DataSourceFilter;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBFileController;
@@ -27,13 +24,13 @@ 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.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMController;
import org.jkiss.dbeaver.model.websocket.event.WSEventController;
import java.nio.file.Path;
import java.util.Map;
/**
* Base interface for web application
@@ -41,6 +38,10 @@ import java.nio.file.Path;
public interface WebApplication extends DBPApplication {
boolean isConfigurationMode();
default boolean isInitializationMode() {
return false;
}
WebAppConfiguration getAppConfiguration();
WebServerConfiguration getServerConfiguration();
@@ -53,12 +54,6 @@ public interface WebApplication extends DBPApplication {
boolean isMultiNode();
WebProjectImpl createProjectImpl(
@NotNull WebSession webSession,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
);
SMController createSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
SMAdminController getAdminSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
@@ -95,4 +90,8 @@ public interface WebApplication extends DBPApplication {
int getServerPort();
boolean isLicenseRequired();
default void getStatusInfo(Map<String, Object> infoMap) {
}
}
@@ -16,9 +16,12 @@
*/
package io.cloudbeaver.model.app;
import com.google.gson.Gson;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import java.nio.file.Path;
import java.util.Map;
/**
* Server configuration controller.
@@ -31,4 +34,11 @@ public interface WebServerConfigurationController<T extends WebServerConfigurati
*/
void loadServerConfiguration(Path configPath) throws DBException;
@NotNull
default Map<String, Object> getOriginalConfigurationProperties() {
return Map.of();
}
@NotNull
Gson getGson();
}
@@ -14,21 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server;
package io.cloudbeaver.model.config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.app.BaseAuthWebAppConfiguration;
import com.google.gson.annotations.Expose;
import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants;
import io.cloudbeaver.model.app.BaseWebAppConfiguration;
import io.cloudbeaver.model.app.WebAuthConfiguration;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderRegistry;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
@@ -38,11 +36,15 @@ import java.util.*;
/**
* Application configuration
*/
public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthConfiguration {
public class CBAppConfig extends BaseWebAppConfiguration implements WebAuthConfiguration {
private static final Log log = Log.getLog(CBAppConfig.class);
public static final DataSourceNavigatorSettings.Preset PRESET_WEB = new DataSourceNavigatorSettings.Preset("web", "Web", "Default view");
public static final DataSourceNavigatorSettings DEFAULT_VIEW_SETTINGS = PRESET_WEB.getSettings();
private final Set<SMAuthProviderCustomConfiguration> authConfigurations;
// Legacy auth configs, left for backward compatibility
@Expose(serialize = false)
private final Map<String, SMAuthProviderCustomConfiguration> authConfiguration;
private boolean supportsCustomConnections;
private boolean supportsConnectionBrowser;
@@ -66,9 +68,14 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
private DataSourceNavigatorSettings defaultNavigatorSettings;
private final Map<String, Object> resourceQuotas;
private String defaultAuthProvider;
private String[] enabledAuthProviders;
public CBAppConfig() {
super();
this.defaultAuthProvider = LocalAuthProviderConstants.PROVIDER_ID;
this.enabledAuthProviders = null;
this.authConfigurations = new LinkedHashSet<>();
this.authConfiguration = new LinkedHashMap<>();
this.anonymousAccessEnabled = false;
this.anonymousUserRole = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
this.anonymousUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
@@ -91,6 +98,10 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
public CBAppConfig(CBAppConfig src) {
super(src);
this.defaultAuthProvider = src.defaultAuthProvider;
this.enabledAuthProviders = src.enabledAuthProviders;
this.authConfigurations = new LinkedHashSet<>(src.authConfigurations);
this.authConfiguration = new LinkedHashMap<>(src.authConfiguration);
this.anonymousAccessEnabled = src.anonymousAccessEnabled;
this.anonymousUserRole = src.anonymousUserRole;
this.anonymousUserTeam = src.anonymousUserTeam;
@@ -169,6 +180,10 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
return enabledDrivers;
}
public void setEnabledDrivers(String[] enabledDrivers) {
this.enabledDrivers = enabledDrivers;
}
public String[] getDisabledDrivers() {
return disabledDrivers;
}
@@ -204,19 +219,6 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
return getPluginConfig(pluginId, false);
}
public <T> T getPluginOptions(@NotNull String pluginId, @NotNull String option, Class<T> theClass) throws DBException {
Map<String, Object> iamSettingsMap = CBPlatform.getInstance().getApplication().getAppConfiguration().getPluginOption(
pluginId, option);
if (CommonUtils.isEmpty(iamSettingsMap)) {
throw new DBException("Settings '" + option + "' not specified in plugin '" + pluginId + "' configuration");
}
Gson gson = new GsonBuilder().create();
return gson.fromJson(
gson.toJsonTree(iamSettingsMap),
theClass);
}
////////////////////////////////////////////
// Quotas
@@ -264,38 +266,6 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
return grantConnectionsAccessToAnonymousTeam;
}
// we disable embedded drivers by default and enable it in enabled drivers list
// that's why we need so complicated logic for disabling drivers
public void updateDisabledDriversConfig(String[] disabledDriversConfig) {
Set<String> disabledIds = new LinkedHashSet<>(Arrays.asList(disabledDriversConfig));
Set<String> enabledIds = new LinkedHashSet<>(Arrays.asList(this.enabledDrivers));
// remove all disabled embedded drivers from enabled drivers list
enabledIds.removeAll(disabledIds);
// enable embedded driver if it is not in disabled drivers list
for (String driverId : this.disabledDrivers) {
if (disabledIds.contains(driverId)) {
// driver is also disabled
continue;
}
// driver is removed from disabled list
// we need to enable if it is embedded
try {
DBPDriver driver = WebServiceUtils.getDriverById(driverId);
if (driver.isEmbedded()) {
enabledIds.add(driverId);
}
} catch (DBWebException e) {
log.error("Failed to find driver by id", e);
}
}
this.disabledDrivers = disabledDriversConfig;
this.enabledDrivers = enabledIds.toArray(String[]::new);
}
public boolean isDriverForceEnabled(@NotNull String driverId) {
return ArrayUtils.containsIgnoreCase(getEnabledDrivers(), driverId);
}
@@ -303,4 +273,93 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
public boolean isSystemVariablesResolvingEnabled() {
return systemVariablesResolvingEnabled;
}
@Override
public String getDefaultAuthProvider() {
return defaultAuthProvider;
}
public void setDefaultAuthProvider(String defaultAuthProvider) {
this.defaultAuthProvider = defaultAuthProvider;
}
@Override
public String[] getEnabledAuthProviders() {
if (enabledAuthProviders == null) {
// No config - enable all providers (+backward compatibility)
return WebAuthProviderRegistry.getInstance().getAuthProviders()
.stream().map(WebAuthProviderDescriptor::getId).toArray(String[]::new);
}
return enabledAuthProviders;
}
public void setEnabledAuthProviders(String[] enabledAuthProviders) {
this.enabledAuthProviders = enabledAuthProviders;
}
@Override
public boolean isAuthProviderEnabled(String id) {
var authProviderDescriptor = WebAuthProviderRegistry.getInstance().getAuthProvider(id);
if (authProviderDescriptor == null) {
return false;
}
if (!ArrayUtils.contains(getEnabledAuthProviders(), id)) {
return false;
}
if (!ArrayUtils.isEmpty(authProviderDescriptor.getRequiredFeatures())) {
for (String rf : authProviderDescriptor.getRequiredFeatures()) {
if (!isFeatureEnabled(rf)) {
return false;
}
}
}
return true;
}
////////////////////////////////////////////
// Auth provider configs
@Override
public Set<SMAuthProviderCustomConfiguration> getAuthCustomConfigurations() {
return authConfigurations;
}
@Override
@Nullable
public SMAuthProviderCustomConfiguration getAuthProviderConfiguration(@NotNull String id) {
synchronized (authConfigurations) {
return authConfigurations.stream().filter(c -> c.getId().equals(id)).findAny().orElse(null);
}
}
public void addAuthProviderConfiguration(@NotNull SMAuthProviderCustomConfiguration config) {
synchronized (authConfigurations) {
authConfigurations.removeIf(c -> c.getId().equals(config.getId()));
authConfigurations.add(config);
}
}
public void setAuthProvidersConfigurations(Collection<SMAuthProviderCustomConfiguration> authProviders) {
synchronized (authConfigurations) {
authConfigurations.clear();
authConfigurations.addAll(authProviders);
}
}
public boolean deleteAuthProviderConfiguration(@NotNull String id) {
synchronized (authConfigurations) {
return authConfigurations.removeIf(c -> c.getId().equals(id));
}
}
public void loadLegacyCustomConfigs() {
// Convert legacy map of configs into list
if (!authConfiguration.isEmpty()) {
for (Map.Entry<String, SMAuthProviderCustomConfiguration> entry : authConfiguration.entrySet()) {
entry.getValue().setId(entry.getKey());
authConfigurations.add(entry.getValue());
}
authConfiguration.clear();
}
}
}
@@ -14,19 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.server;
package io.cloudbeaver.model.config;
import com.google.gson.annotations.SerializedName;
import io.cloudbeaver.auth.CBAuthConstants;
import io.cloudbeaver.model.app.WebServerConfiguration;
import io.cloudbeaver.service.security.SMControllerConfiguration;
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
import io.cloudbeaver.server.CBConstants;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.utils.CommonUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
@@ -58,18 +54,6 @@ public class CBServerConfig implements WebServerConfiguration {
private String staticContent = "";
public String getServerURL() {
if (serverURL == null) {
String hostName = serverHost;
if (CommonUtils.isEmpty(hostName)) {
try {
hostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
log.debug("Error resolving localhost address: " + e.getMessage());
hostName = CBApplication.HOST_LOCALHOST;
}
}
serverURL = "http://" + hostName + ":" + serverPort;
}
return serverURL;
}
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service.security;
package io.cloudbeaver.model.config;
import org.jkiss.dbeaver.model.meta.Property;
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package io.cloudbeaver.service.security;
package io.cloudbeaver.model.config;
public class SMControllerConfiguration {
//in minutes
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service.security.db;
package io.cloudbeaver.model.config;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.connection.InternalDatabaseConfig;
@@ -63,6 +63,7 @@ public class WebDatabaseConfig implements InternalDatabaseConfig {
return user;
}
@Override
public String getPassword() {
return password;
@@ -84,4 +85,16 @@ public class WebDatabaseConfig implements InternalDatabaseConfig {
public String getSchema() {
return schema;
}
public void setPassword(String password) {
this.password = password;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setUser(String user) {
this.user = user;
}
}
@@ -20,7 +20,6 @@ package io.cloudbeaver.model.rm;
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.DBIcon;
import org.jkiss.dbeaver.model.DBPImage;
import org.jkiss.dbeaver.model.DBPObject;
@@ -37,7 +36,6 @@ import java.util.ArrayList;
import java.util.List;
public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
private static final Log log = Log.getLog(DBNResourceManagerProject.class);
private final RMProject project;
@@ -93,8 +91,8 @@ public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
}
@Override
public DBNResourceManagerResource[] getChildren(DBRProgressMonitor monitor) throws DBException {
if (children == null) {
public DBNResourceManagerResource[] getChildren(@NotNull DBRProgressMonitor monitor) throws DBException {
if (children == null && !monitor.isForceCacheUsage()) {
List<DBNResourceManagerResource> rfList = new ArrayList<>();
for (RMResource resource : getResourceController().listResources(
project.getId(), null, null, true, false, false)) {
@@ -123,21 +121,15 @@ public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
return this;
}
@Nullable
@Override
public String toString() {
return getNodeDisplayName();
}
@Override
public DBPProject getOwnerProject() {
public DBPProject getOwnerProjectOrNull() {
List<? extends DBPProject> globalProjects = getModel().getModelProjects();
if (globalProjects == null) {
return null;
}
for (DBPProject modelProject : globalProjects) {
if (CommonUtils.equalObjects(modelProject.getId(), project.getId())) {
return modelProject;
if (globalProjects != null) {
for (DBPProject modelProject : globalProjects) {
if (CommonUtils.equalObjects(modelProject.getId(), project.getId())) {
return modelProject;
}
}
}
return null;
@@ -148,4 +140,10 @@ public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
public DBPObject getObjectDetails(@NotNull DBRProgressMonitor monitor, @NotNull SMSessionContext sessionContext, @NotNull Object dataSource) throws DBException {
return project;
}
@Override
public String toString() {
return getNodeDisplayName();
}
}
@@ -110,8 +110,8 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
}
@Override
public DBNNode[] getChildren(DBRProgressMonitor monitor) throws DBException {
if (children == null) {
public DBNNode[] getChildren(@NotNull DBRProgressMonitor monitor) throws DBException {
if (children == null && !monitor.isForceCacheUsage()) {
List<DBNResourceManagerResource> rfList = new ArrayList<>();
for (RMResource resource : getResourceController().listResources(
getResourceProject().getId(), getResourceFolder(), null, true, false, false)) {
@@ -203,9 +203,10 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
return resource;
}
@Nullable
@Override
public DBPProject getOwnerProject() {
return getParentNode().getOwnerProject();
public DBPProject getOwnerProjectOrNull() {
return getParentNode().getOwnerProjectOrNull();
}
public RMResource getResource() {
@@ -19,6 +19,7 @@ package io.cloudbeaver.model.rm;
import io.cloudbeaver.model.session.WebSession;
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.DBPHiddenObject;
@@ -81,8 +82,8 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
}
@Override
public DBNResourceManagerProject[] getChildren(DBRProgressMonitor monitor) throws DBException {
if (projects == null) {
public DBNResourceManagerProject[] getChildren(@NotNull DBRProgressMonitor monitor) throws DBException {
if (projects == null && !monitor.isForceCacheUsage()) {
List<? extends DBPProject> projectList = getParentNode().getModel().getModelProjects();
if (CommonUtils.isEmpty(projectList)) {
return new DBNResourceManagerProject[0];
@@ -37,6 +37,7 @@ import org.jkiss.dbeaver.model.app.DBPProject;
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.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
@@ -130,12 +131,7 @@ public class LocalResourceController implements RMController {
if (project == null || refresh) {
SessionContextImpl sessionContext = new SessionContextImpl(null);
RMProject rmProject = makeProjectFromId(projectId, false);
project = new BaseWebProjectImpl(
workspace,
this,
sessionContext,
rmProject,
(container) -> true);
project = new InternalWebProjectImpl(sessionContext, rmProject);
projectRegistries.put(projectId, project);
}
return project;
@@ -256,18 +252,20 @@ public class LocalResourceController implements RMController {
return new RMProject[0];
}
var projects = new ArrayList<RMProject>();
var allPaths = Files.list(sharedProjectsPath).collect(Collectors.toList());
for (Path path : allPaths) {
var projectPerms = getProjectPermissions(
makeProjectIdFromPath(path, RMProjectType.SHARED),
RMProjectType.SHARED
);
var rmProject = makeProjectFromPath(path, projectPerms, RMProjectType.SHARED, false);
projects.add(rmProject);
try (Stream<Path> list = Files.list(sharedProjectsPath)) {
var allPaths = list.toList();
for (Path path : allPaths) {
var projectPerms = getProjectPermissions(
makeProjectIdFromPath(path, RMProjectType.SHARED),
RMProjectType.SHARED
);
var rmProject = makeProjectFromPath(path, projectPerms, RMProjectType.SHARED, false);
projects.add(rmProject);
}
return projects.stream()
.filter(Objects::nonNull)
.toArray(RMProject[]::new);
}
return projects.stream()
.filter(Objects::nonNull)
.toArray(RMProject[]::new);
} catch (IOException e) {
throw new DBException("Error reading shared projects", e);
}
@@ -581,7 +579,7 @@ public class LocalResourceController implements RMController {
@NotNull String resourcePath,
boolean isFolder
) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "createResource")) {
try (var ignoredLock = lockController.lockProject(projectId, "createResource")) {
validateResourcePath(resourcePath);
Path targetPath = getTargetPath(projectId, resourcePath);
if (Files.exists(targetPath)) {
@@ -613,7 +611,7 @@ public class LocalResourceController implements RMController {
@NotNull String oldResourcePath,
@NotNull String newResourcePath
) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "moveResource")) {
try (var ignoredLock = lockController.lockProject(projectId, "moveResource")) {
var normalizedOldResourcePath = CommonUtils.normalizeResourcePath(oldResourcePath);
var normalizedNewResourcePath = CommonUtils.normalizeResourcePath(newResourcePath);
if (log.isDebugEnabled()) {
@@ -628,6 +626,9 @@ public class LocalResourceController implements RMController {
}
Path newTargetPath = getTargetPath(projectId, normalizedNewResourcePath);
validateResourcePath(newTargetPath.toString());
if (Files.exists(newTargetPath)) {
throw new DBException("Resource with name %s already exists".formatted(newTargetPath.getFileName()));
}
try {
Files.move(oldTargetPath, newTargetPath);
} catch (IOException e) {
@@ -679,11 +680,10 @@ public class LocalResourceController implements RMController {
@Override
public void deleteResource(@NotNull String projectId, @NotNull String resourcePath, boolean recursive) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "deleteResource")) {
try (var ignoredLock = lockController.lockProject(projectId, "deleteResource")) {
if (log.isDebugEnabled()) {
log.debug("Removing resource from '" + resourcePath + "' in project '" + projectId + "'" + (recursive ? " recursive" : ""));
}
validateResourcePath(resourcePath);
Path targetPath = getTargetPath(projectId, resourcePath);
doFileWriteOperation(projectId, targetPath, () -> {
if (!Files.exists(targetPath)) {
@@ -768,7 +768,7 @@ public class LocalResourceController implements RMController {
@NotNull byte[] data,
boolean forceOverwrite
) throws DBException {
try (var lock = lockController.lockProject(projectId, "setResourceContents")) {
try (var ignoredLock = lockController.lockProject(projectId, "setResourceContents")) {
validateResourcePath(resourcePath);
Number fileSizeLimit = WebAppUtils.getWebApplication()
.getAppConfiguration()
@@ -822,7 +822,7 @@ public class LocalResourceController implements RMController {
@NotNull String propertyName,
@Nullable Object propertyValue
) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "resourcePropertyUpdate")) {
try (var ignoredLock = lockController.lockProject(projectId, "resourcePropertyUpdate")) {
validateResourcePath(resourcePath);
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
@@ -836,6 +836,27 @@ public class LocalResourceController implements RMController {
}
}
@NotNull
@Override
public String setResourceProperties(
@NotNull String projectId,
@NotNull String resourcePath,
@NotNull Map<String, Object> properties
) throws DBException {
try (var ignoredLock = lockController.lockProject(projectId, "resourcePropertyUpdate")) {
validateResourcePath(resourcePath);
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
() -> {
log.debug("Updating resource '" + resourcePath + "' properties in project '" + projectId + "'");
webProject.setResourceProperties(resourcePath, properties);
return null;
}
);
return DEFAULT_CHANGE_ID;
}
}
private void validateResourcePath(String resourcePath) throws DBException {
var fullPath = Paths.get(resourcePath);
for (Path path : fullPath) {
@@ -1089,7 +1110,7 @@ public class LocalResourceController implements RMController {
);
}
if (readProperties) {
final BaseProjectImpl project = (BaseProjectImpl) getWebProject(projectId, true);
final BaseProjectImpl project = getWebProject(projectId, true);
final String resourcePath = getProjectRelativePath(projectId, path);
final Map<String, Object> properties = project.getResourceProperties(resourcePath);
@@ -1134,7 +1155,7 @@ public class LocalResourceController implements RMController {
);
}
private void fireRmProjectAddEvent(@NotNull RMProject project) throws DBException {
private void fireRmProjectAddEvent(@NotNull RMProject project) {
RMEventManager.fireEvent(
new RMEvent(
RMEvent.Action.RESOURCE_ADD,
@@ -1264,4 +1285,20 @@ public class LocalResourceController implements RMController {
}
private class InternalWebProjectImpl extends BaseWebProjectImpl {
public InternalWebProjectImpl(SessionContextImpl sessionContext, RMProject rmProject) {
super(
LocalResourceController.this.workspace,
LocalResourceController.this,
sessionContext,
rmProject);
}
@NotNull
@Override
protected DBPDataSourceRegistry createDataSourceRegistry() {
return new DataSourceRegistry(this);
}
}
}
@@ -51,14 +51,14 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
@NotNull
protected final WebUserContext userContext;
@NotNull
protected final WebAuthApplication application;
protected final WebApplication application;
protected volatile long lastAccessTime;
private final List<CBWebSessionEventHandler> sessionEventHandlers = new CopyOnWriteArrayList<>();
private WebSessionEventsFilter eventsFilter = new WebSessionEventsFilter();
private final WebSessionWorkspace workspace;
public BaseWebSession(@NotNull String id, @NotNull WebAuthApplication application) throws DBException {
public BaseWebSession(@NotNull String id, @NotNull WebApplication application) throws DBException {
this.id = id;
this.application = application;
this.createTime = System.currentTimeMillis();
@@ -72,6 +72,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
return new WebUserContext(this.application, this.workspace);
}
@NotNull
public WebSessionWorkspace getWorkspace() {
return workspace;
}
@@ -232,6 +233,9 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
@Property
public long getRemainingTime() {
return application.getMaxSessionIdleTime() + lastAccessTime - System.currentTimeMillis();
if (application instanceof WebAuthApplication authApplication) {
return authApplication.getMaxSessionIdleTime() + lastAccessTime - System.currentTimeMillis();
}
return Integer.MAX_VALUE;
}
}
@@ -0,0 +1,57 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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;
import jakarta.servlet.http.HttpServletRequest;
public class WebHttpRequestInfo {
private final String id;
private final Object locale;
private final String lastRemoteAddress;
private final String lastRemoteUserAgent;
public WebHttpRequestInfo(HttpServletRequest request) {
this.id = request.getSession().getId();
this.locale = request.getAttribute("locale");
this.lastRemoteAddress = request.getRemoteAddr();
this.lastRemoteUserAgent = request.getHeader("User-Agent");
}
public WebHttpRequestInfo(String id, Object locale, String lastRemoteAddress, String lastRemoteUserAgent) {
this.id = id;
this.locale = locale;
this.lastRemoteAddress = lastRemoteAddress;
this.lastRemoteUserAgent = lastRemoteUserAgent;
}
public String getId() {
return id;
}
public Object getLocale() {
return locale;
}
public String getLastRemoteAddress() {
return lastRemoteAddress;
}
public String getLastRemoteUserAgent() {
return lastRemoteUserAgent;
}
}
@@ -19,21 +19,18 @@ package io.cloudbeaver.model.session;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.DataSourceFilter;
import io.cloudbeaver.WebProjectImpl;
import com.google.gson.Strictness;
import io.cloudbeaver.*;
import io.cloudbeaver.model.WebAsyncTaskInfo;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebServerMessage;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.app.WebAuthApplication;
import io.cloudbeaver.model.user.WebUser;
import io.cloudbeaver.service.DBWSessionHandler;
import io.cloudbeaver.service.sql.WebSQLConstants;
import io.cloudbeaver.utils.CBModelConstants;
import io.cloudbeaver.utils.WebAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -43,12 +40,8 @@ import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBFileController;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPEvent;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.access.DBACredentialsProvider;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.auth.*;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.exec.DBCException;
@@ -68,15 +61,11 @@ import org.jkiss.dbeaver.model.runtime.ProxyProgressMonitor;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMConstants;
import org.jkiss.dbeaver.model.security.SMController;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.security.user.SMObjectPermissions;
import org.jkiss.dbeaver.model.sql.DBQuotaException;
import org.jkiss.dbeaver.model.websocket.event.MessageType;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.jobs.DisconnectJob;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
@@ -89,6 +78,7 @@ import java.util.stream.Collectors;
* Web session.
* Is the main source of data in web application
*/
//TODO: split to authenticated and non authenticated context
public class WebSession extends BaseWebSession
implements SMSessionWithAuth, SMCredentialsProvider, DBACredentialsProvider, IAdaptable {
@@ -105,12 +95,10 @@ public class WebSession extends BaseWebSession
private String lastRemoteAddr;
private String lastRemoteUserAgent;
private Set<String> accessibleConnectionIds = Collections.emptySet();
private String locale;
private boolean cacheExpired;
private final Map<String, WebConnectionInfo> connections = new HashMap<>();
protected WebSessionGlobalProjectImpl globalProject;
private final List<WebServerMessage> sessionMessages = new ArrayList<>();
private final Map<String, WebAsyncTaskInfo> asyncTasks = new HashMap<>();
@@ -124,21 +112,34 @@ public class WebSession extends BaseWebSession
private final Map<String, DBWSessionHandler> sessionHandlers;
public WebSession(
@NotNull HttpServletRequest request,
@NotNull WebHttpRequestInfo requestInfo,
@NotNull WebAuthApplication application,
@NotNull Map<String, DBWSessionHandler> sessionHandlers
) throws DBException {
super(request.getSession().getId(), application);
this(requestInfo.getId(),
CommonUtils.toString(requestInfo.getLocale()),
application,
sessionHandlers
);
updateSessionParameters(requestInfo);
}
protected WebSession(
@NotNull String id,
@Nullable String locale,
@NotNull WebApplication application,
@NotNull Map<String, DBWSessionHandler> sessionHandlers
) throws DBException {
super(id, application);
this.lastAccessTime = this.createTime;
setLocale(CommonUtils.toString(request.getSession().getAttribute(ATTR_LOCALE), this.locale));
this.sessionHandlers = sessionHandlers;
setLocale(CommonUtils.toString(locale, this.locale));
//force authorization of anonymous session to avoid access error,
//because before authorization could be called by any request,
//but now 'updateInfo' is called only in special requests,
//and the order of requests is not guaranteed.
//look at CB-4747
refreshSessionAuth();
updateSessionParameters(request);
}
@Nullable
@@ -152,8 +153,8 @@ public class WebSession extends BaseWebSession
}
}
@NotNull
public DBPProject getSingletonProject() {
@Nullable
public WebSessionProjectImpl getSingletonProject() {
return getWorkspace().getActiveProject();
}
@@ -250,69 +251,6 @@ public class WebSession extends BaseWebSession
initNavigatorModel();
}
/**
* updates data sources based on event in web session
*
* @param project project of connection
* @param dataSourceIds list of updated connections
* @param type type of event
*/
public synchronized boolean updateProjectDataSources(
DBPProject project,
List<String> dataSourceIds,
WSEventType type
) {
var sendDataSourceUpdatedEvent = false;
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
// save old connections
var oldDataSources = dataSourceIds.stream()
.map(registry::getDataSource)
.filter(Objects::nonNull)
.collect(Collectors.toMap(
DBPDataSourceContainer::getId,
ds -> new DataSourceDescriptor((DataSourceDescriptor) ds, ds.getRegistry())
));
if (type == WSEventType.DATASOURCE_CREATED || type == WSEventType.DATASOURCE_UPDATED) {
registry.refreshConfig(dataSourceIds);
}
for (String dsId : dataSourceIds) {
DataSourceDescriptor ds = (DataSourceDescriptor) registry.getDataSource(dsId);
if (ds == null) {
continue;
}
switch (type) {
case DATASOURCE_CREATED -> {
WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds);
this.connections.put(getConnectionId(ds), connectionInfo);
sendDataSourceUpdatedEvent = true;
}
case DATASOURCE_UPDATED -> // if settings were changed we need to send event
sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId));
case DATASOURCE_DELETED -> {
WebDataSourceUtils.disconnectDataSource(this, ds);
if (registry instanceof DBPDataSourceRegistryCache dsrc) {
dsrc.removeDataSourceFromList(ds);
}
this.connections.remove(getConnectionId(ds));
sendDataSourceUpdatedEvent = true;
}
default -> {
}
}
}
return sendDataSourceUpdatedEvent;
}
@NotNull
private String getConnectionId(@NotNull DBPDataSourceContainer container) {
return getConnectionId(container.getProject().getId(), container.getId());
}
@NotNull
private String getConnectionId(@NotNull String projectId, @NotNull String dsId) {
return projectId + ":" + dsId;
}
// Note: for admin use only
public synchronized void resetUserState() throws DBException {
clearAuthTokens();
@@ -333,7 +271,7 @@ public class WebSession extends BaseWebSession
this.navigatorModel.dispose();
this.navigatorModel = null;
}
this.connections.clear();
this.globalProject = null;
loadProjects();
@@ -353,7 +291,6 @@ public class WebSession extends BaseWebSession
// No anonymous mode in distributed apps
return;
}
refreshAccessibleConnectionIds();
try {
RMController controller = getRmController();
RMProject[] rmProjects = controller.listAccessibleProjects();
@@ -373,57 +310,28 @@ public class WebSession extends BaseWebSession
}
}
public WebProjectImpl createWebProject(RMProject project) {
// Do not filter data sources from user project
DataSourceFilter filter = project.getType() == RMProjectType.GLOBAL
? this::isDataSourceAccessible
: x -> true;
WebProjectImpl sessionProject = application.createProjectImpl(this, project, filter);
private WebSessionProjectImpl createWebProject(RMProject project) {
WebSessionProjectImpl sessionProject;
if (project.isGlobal()) {
sessionProject = createGlobalProject(project);
} else {
sessionProject = new WebSessionProjectImpl(this, project);
}
// do not load data sources for anonymous project
if (project.getType() == RMProjectType.USER && userContext.getUser() == null) {
sessionProject.setInMemory(true);
}
DBPDataSourceRegistry dataSourceRegistry = sessionProject.getDataSourceRegistry();
dataSourceRegistry.setAuthCredentialsProvider(this);
addSessionProject(sessionProject);
if (!project.isShared() || application.isConfigurationMode()) {
getWorkspace().setActiveProject(sessionProject);
}
for (DBPDataSourceContainer ds : dataSourceRegistry.getDataSources()) {
addConnection(new WebConnectionInfo(this, ds));
}
Throwable lastError = dataSourceRegistry.getLastError();
if (lastError != null) {
addSessionError(lastError);
log.error("Error refreshing connections from project '" + project.getId() + "'", lastError);
}
return sessionProject;
}
public void filterAccessibleConnections(List<WebConnectionInfo> connections) {
connections.removeIf(c -> !isDataSourceAccessible(c.getDataSourceContainer()));
}
private boolean isDataSourceAccessible(DBPDataSourceContainer dataSource) {
return dataSource.isExternallyProvided() ||
dataSource.isTemporary() ||
this.hasPermission(DBWConstants.PERMISSION_ADMIN) ||
accessibleConnectionIds.contains(dataSource.getId());
}
@NotNull
private Set<String> readAccessibleConnectionIds() {
try {
return getSecurityController()
.getAllAvailableObjectsPermissions(SMObjectType.datasource)
.stream()
.map(SMObjectPermissions::getObjectId)
.collect(Collectors.toSet());
} catch (DBException e) {
addSessionError(e);
log.error("Error reading connection grants", e);
return Collections.emptySet();
}
protected WebSessionProjectImpl createGlobalProject(RMProject project) {
globalProject = new WebSessionGlobalProjectImpl(this, project);
globalProject.refreshAccessibleConnectionIds();
return globalProject;
}
private void resetSessionCache() throws DBCException {
@@ -441,17 +349,7 @@ public class WebSession extends BaseWebSession
}
private void resetNavigationModel() {
Map<String, WebConnectionInfo> conCopy;
synchronized (this.connections) {
conCopy = new HashMap<>(this.connections);
this.connections.clear();
}
for (WebConnectionInfo connectionInfo : conCopy.values()) {
if (connectionInfo.isConnected()) {
new DisconnectJob(connectionInfo.getDataSourceContainer()).schedule();
}
}
getWorkspace().getProjects().forEach(WebSessionProjectImpl::dispose);
if (this.navigatorModel != null) {
this.navigatorModel.dispose();
@@ -465,7 +363,9 @@ public class WebSession extends BaseWebSession
authAsAnonymousUser();
} else if (getUserId() != null) {
userContext.refreshPermissions();
refreshAccessibleConnectionIds();
if (globalProject != null) {
globalProject.refreshAccessibleConnectionIds();
}
}
} catch (Exception e) {
@@ -474,32 +374,6 @@ public class WebSession extends BaseWebSession
}
}
private synchronized void refreshAccessibleConnectionIds() {
this.accessibleConnectionIds = readAccessibleConnectionIds();
}
public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) {
this.accessibleConnectionIds.add(dsId);
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
var dataSource = registry.getDataSource(dsId);
if (dataSource != null) {
connections.put(getConnectionId(dataSource), new WebConnectionInfo(this, dataSource));
// reflect changes is navigator model
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true));
}
}
public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) {
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
var dataSource = registry.getDataSource(dsId);
if (dataSource != null) {
this.accessibleConnectionIds.remove(dsId);
connections.remove(getConnectionId(dataSource));
// reflect changes is navigator model
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource));
dataSource.dispose();
}
}
private synchronized void authAsAnonymousUser() throws DBException {
if (!application.getAppConfiguration().isAnonymousAccessEnabled()) {
@@ -558,75 +432,12 @@ public class WebSession extends BaseWebSession
}
}
public synchronized void updateSessionParameters(HttpServletRequest request) {
this.lastRemoteAddr = request.getRemoteAddr();
this.lastRemoteUserAgent = request.getHeader("User-Agent");
public synchronized void updateSessionParameters(WebHttpRequestInfo requestInfo) {
this.lastRemoteAddr = requestInfo.getLastRemoteAddress();
this.lastRemoteUserAgent = requestInfo.getLastRemoteUserAgent();
this.cacheExpired = false;
}
@Association
public List<WebConnectionInfo> getConnections() {
synchronized (connections) {
return new ArrayList<>(connections.values());
}
}
@NotNull
public WebConnectionInfo getWebConnectionInfo(@Nullable String projectId, String connectionID) throws DBWebException {
WebConnectionInfo connectionInfo = null;
synchronized (connections) {
if (projectId != null) {
connectionInfo = connections.get(getConnectionId(projectId, connectionID));
} else {
addWarningMessage("Project id is not defined in request. Try to find it from connection cache");
for (Map.Entry<String, WebConnectionInfo> entry : connections.entrySet()) {
String k = entry.getKey();
WebConnectionInfo v = entry.getValue();
if (k.contains(connectionID)) {
connectionInfo = v;
break;
}
}
}
}
if (connectionInfo == null) {
WebProjectImpl project = getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found in web workspace");
}
DBPDataSourceContainer dataSource = project.getDataSourceRegistry().getDataSource(connectionID);
if (dataSource != null) {
connectionInfo = new WebConnectionInfo(this, dataSource);
synchronized (connections) {
connections.put(getConnectionId(dataSource), connectionInfo);
}
} else {
throw new DBWebException("Connection '" + connectionID + "' not found");
}
}
return connectionInfo;
}
@Nullable
public WebConnectionInfo findWebConnectionInfo(String projectId, String connectionId) {
synchronized (connections) {
return connections.get(getConnectionId(projectId, connectionId));
}
}
public void addConnection(WebConnectionInfo connectionInfo) {
synchronized (connections) {
connections.put(getConnectionId(connectionInfo.getDataSourceContainer()), connectionInfo);
}
}
public void removeConnection(WebConnectionInfo connectionInfo) {
connectionInfo.clearCache();
synchronized (connections) {
connections.remove(getConnectionId(connectionInfo.getDataSourceContainer()));
}
}
@Override
public void close() {
try {
@@ -810,7 +621,7 @@ public class WebSession extends BaseWebSession
synchronized (attributes) {
Object value = attributes.get(name);
if (value instanceof PersistentAttribute persistentAttribute) {
value = persistentAttribute.getValue();
value = persistentAttribute.value();
}
return (T) value;
}
@@ -826,7 +637,7 @@ public class WebSession extends BaseWebSession
synchronized (attributes) {
Object value = attributes.get(name);
if (value instanceof PersistentAttribute persistentAttribute) {
value = persistentAttribute.getValue();
value = persistentAttribute.value();
}
if (value == null) {
value = creator.apply(null);
@@ -969,9 +780,12 @@ public class WebSession extends BaseWebSession
}
configuration.setRuntimeAttribute(RUNTIME_PARAM_AUTH_INFOS, getAllAuthInfo());
WebConnectionInfo webConnectionInfo = findWebConnectionInfo(dataSourceContainer.getProject().getId(), dataSourceContainer.getId());
if (webConnectionInfo != null) {
WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration);
WebSessionProjectImpl project = getProjectById(dataSourceContainer.getProject().getId());
if (project != null) {
WebConnectionInfo webConnectionInfo = project.findWebConnectionInfo(dataSourceContainer.getId());
if (webConnectionInfo != null) {
WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration);
}
}
// uncommented because we had the problem with non-native auth models
@@ -980,7 +794,7 @@ public class WebSession extends BaseWebSession
InstanceCreator<DBAAuthCredentials> credTypeAdapter = type -> credentials;
Gson credGson = new GsonBuilder()
.setLenient()
.setStrictness(Strictness.LENIENT)
.registerTypeAdapter(credentials.getClass(), credTypeAdapter)
.create();
@@ -1062,12 +876,17 @@ public class WebSession extends BaseWebSession
}
@Nullable
public WebProjectImpl getProjectById(@Nullable String projectId) {
public WebSessionProjectImpl getProjectById(@Nullable String projectId) {
return getWorkspace().getProjectById(projectId);
}
public WebProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException {
WebProjectImpl project = null;
/**
* Returns project info from session cache.
*
* @throws DBWebException if project with provided id is not found.
*/
public WebSessionProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException {
WebSessionProjectImpl project = null;
if (projectId != null) {
project = getWorkspace().getProjectById(projectId);
}
@@ -1077,18 +896,24 @@ public class WebSession extends BaseWebSession
return project;
}
public List<WebProjectImpl> getAccessibleProjects() {
public List<WebSessionProjectImpl> getAccessibleProjects() {
return getWorkspace().getProjects();
}
public void addSessionProject(@NotNull WebProjectImpl project) {
/**
* Adds project to session cache and navigator tree.
*/
public void addSessionProject(@NotNull WebSessionProjectImpl project) {
getWorkspace().addProject(project);
if (navigatorModel != null) {
navigatorModel.getRoot().addProject(project, false);
}
}
public void deleteSessionProject(@Nullable WebProjectImpl project) {
/**
* Removes project from session cache and navigator tree.
*/
public void deleteSessionProject(@Nullable WebSessionProjectImpl project) {
if (project != null) {
project.dispose();
}
@@ -1113,10 +938,6 @@ public class WebSession extends BaseWebSession
return;
}
deleteSessionProject(project);
var projectConnections = project.getDataSourceRegistry().getDataSources();
for (DBPDataSourceContainer c : projectConnections) {
removeConnection(new WebConnectionInfo(this, c));
}
}
@NotNull
@@ -1133,6 +954,11 @@ public class WebSession extends BaseWebSession
return getUserContext().getPreferenceStore();
}
@Nullable
public WebSessionGlobalProjectImpl getGlobalProject() {
return globalProject;
}
private class SessionProgressMonitor extends BaseProgressMonitor {
@Override
public void beginTask(String name, int totalWork) {
@@ -1167,15 +993,6 @@ public class WebSession extends BaseWebSession
}
}
private static class PersistentAttribute {
private final Object value;
public PersistentAttribute(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
private record PersistentAttribute(Object value) {
}
}
@@ -50,6 +50,9 @@ public class WebSessionEventsFilter {
}
public boolean isEventAllowed(WSEvent event) {
if (event.isForceProcessed()) {
return true;
}
if (!subscribedEventTopics.isEmpty() && !subscribedEventTopics.contains(event.getTopicId())
) {
return false;
@@ -16,11 +16,12 @@
*/
package io.cloudbeaver.model.session;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.WebSessionProjectImpl;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.DBPAdaptable;
import org.jkiss.dbeaver.model.DBPImage;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
import org.jkiss.dbeaver.model.rm.RMUtils;
@@ -38,8 +39,8 @@ public class WebSessionWorkspace implements DBPWorkspace {
private final BaseWebSession session;
private final SessionContextImpl workspaceAuthContext;
private final List<WebProjectImpl> accessibleProjects = new ArrayList<>();
private WebProjectImpl activeProject;
private final List<WebSessionProjectImpl> accessibleProjects = new ArrayList<>();
private WebSessionProjectImpl activeProject;
public WebSessionWorkspace(BaseWebSession session) {
this.session = session;
@@ -81,20 +82,20 @@ public class WebSessionWorkspace implements DBPWorkspace {
@NotNull
@Override
public List<WebProjectImpl> getProjects() {
public List<WebSessionProjectImpl> getProjects() {
return accessibleProjects;
}
@Nullable
@Override
public DBPProject getActiveProject() {
public WebSessionProjectImpl getActiveProject() {
return activeProject;
}
@Nullable
@Override
public WebProjectImpl getProject(@NotNull String projectName) {
for (WebProjectImpl project : accessibleProjects) {
public WebSessionProjectImpl getProject(@NotNull String projectName) {
for (WebSessionProjectImpl project : accessibleProjects) {
if (project.getName().equals(projectName)) {
return project;
}
@@ -104,11 +105,11 @@ public class WebSessionWorkspace implements DBPWorkspace {
@Nullable
@Override
public WebProjectImpl getProjectById(@NotNull String projectId) {
public WebSessionProjectImpl getProjectById(@NotNull String projectId) {
if (projectId == null) {
return activeProject;
}
for (WebProjectImpl project : accessibleProjects) {
for (WebSessionProjectImpl project : accessibleProjects) {
if (project.getId().equals(projectId)) {
return project;
}
@@ -122,26 +123,36 @@ public class WebSessionWorkspace implements DBPWorkspace {
return workspaceAuthContext;
}
@Override
public void initializeProjects() {
// noop
}
@Override
public void dispose() {
clearProjects();
}
public void setActiveProject(DBPProject activeProject) {
this.activeProject = (WebProjectImpl) activeProject;
@Override
public DBPImage getResourceIcon(DBPAdaptable resourceAdapter) {
return null;
}
void addProject(WebProjectImpl project) {
public void setActiveProject(WebSessionProjectImpl activeProject) {
this.activeProject = activeProject;
}
void addProject(WebSessionProjectImpl project) {
accessibleProjects.add(project);
}
void removeProject(WebProjectImpl project) {
void removeProject(WebSessionProjectImpl project) {
accessibleProjects.remove(project);
}
void clearProjects() {
if (!this.accessibleProjects.isEmpty()) {
for (WebProjectImpl project : accessibleProjects) {
for (WebSessionProjectImpl project : accessibleProjects) {
project.dispose();
}
this.activeProject = null;
@@ -46,6 +46,7 @@ import java.util.stream.Collectors;
* Web user context.
* Contains user state and services based on available permissions
*/
//TODO: split to authenticated and non authenticated context
public class WebUserContext implements SMCredentialsProvider {
private static final Log log = Log.getLog(WebUserContext.class);
@@ -80,7 +80,7 @@ public class WebAuthProviderConfiguration {
}
private String buildRedirectUrl(String baseUrl) {
return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + WebAppUtils.getWebApplication().getServerURL();
return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + WebAppUtils.getFullServerUrl();
}
@Property
@@ -109,6 +109,14 @@ public class WebAuthProviderConfiguration {
return instance instanceof SMAuthProviderFederated ? ((SMAuthProviderFederated) instance).getAcsLink(getId(), config.getParameters()) : null;
}
@Property
public String getEntityIdLink() throws DBException {
SMAuthProvider<?> instance = providerDescriptor.getInstance();
return instance instanceof SMAuthProviderFederated
? ((SMAuthProviderFederated) instance).getEntityIdLink(getId(), config.getParameters())
: null;
}
@Override
public String toString() {
return getDisplayName();
@@ -0,0 +1,147 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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 io.cloudbeaver.DBWConstants;
import org.eclipse.core.runtime.Plugin;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.app.DBACertificateStorage;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.impl.app.DefaultCertificateStorage;
import org.jkiss.dbeaver.model.qm.QMRegistry;
import org.jkiss.dbeaver.model.qm.QMUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.registry.BasePlatformImpl;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.runtime.SecurityProviderUtils;
import org.jkiss.dbeaver.runtime.qm.QMLogFileWriter;
import org.jkiss.dbeaver.runtime.qm.QMRegistryImpl;
import org.jkiss.dbeaver.utils.ContentUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public abstract class BaseGQLPlatform extends BasePlatformImpl {
private static final Log log = Log.getLog(BaseGQLPlatform.class);
public static final String WORK_DATA_FOLDER_NAME = ".work-data";
private Path tempFolder;
private QMRegistryImpl queryManager;
private QMLogFileWriter qmLogWriter;
private DBACertificateStorage certificateStorage;
private WebGlobalWorkspace workspace;
@Override
protected synchronized void initialize() {
// Register BC security provider
SecurityProviderUtils.registerSecurityProvider();
// Register properties adapter
this.workspace = new WebGlobalWorkspace(this);
this.workspace.initializeProjects();
QMUtils.initApplication(this);
this.queryManager = new QMRegistryImpl();
this.qmLogWriter = new QMLogFileWriter();
this.queryManager.registerMetaListener(qmLogWriter);
this.certificateStorage = new DefaultCertificateStorage(
WebPlatformActivator.getInstance()
.getStateLocation()
.toFile()
.toPath()
.resolve(DBConstants.CERTIFICATE_STORAGE_FOLDER));
super.initialize();
}
@Override
protected Plugin getProductPlugin() {
return WebPlatformActivator.getInstance();
}
@NotNull
@Override
public DBACertificateStorage getCertificateStorage() {
return certificateStorage;
}
@NotNull
@Override
public DBPWorkspace getWorkspace() {
return workspace;
}
@NotNull
public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String name) {
if (tempFolder == null) {
// Make temp folder
monitor.subTask("Create temp folder");
tempFolder = workspace.getAbsolutePath().resolve(DBWConstants.WORK_DATA_FOLDER_NAME);
}
if (!Files.exists(tempFolder)) {
try {
Files.createDirectories(tempFolder);
} catch (IOException e) {
log.error("Can't create temp directory " + tempFolder, e);
}
}
Path folder = tempFolder.resolve(name);
if (!Files.exists(folder)) {
try {
Files.createDirectories(folder);
} catch (IOException e) {
log.error("Error creating temp folder '" + folder.toAbsolutePath() + "'", e);
}
}
return folder;
}
@Override
public synchronized void dispose() {
super.dispose();
if (this.qmLogWriter != null) {
this.queryManager.unregisterMetaListener(qmLogWriter);
this.qmLogWriter.dispose();
this.qmLogWriter = null;
}
if (this.queryManager != null) {
this.queryManager.dispose();
//queryManager = null;
}
DataSourceProviderRegistry.dispose();
// Remove temp folder
if (tempFolder != null) {
if (!ContentUtils.deleteFileRecursive(tempFolder.toFile())) {
log.warn("Can't delete temp folder '" + tempFolder.toAbsolutePath() + "'");
}
tempFolder = null;
}
}
@NotNull
public QMRegistry getQueryManager() {
return queryManager;
}
}
@@ -87,4 +87,6 @@ public class CBConstants {
public static final String QUOTA_PROP_FILE_LIMIT = "dataExportFileSizeLimit";
public static final String ADMIN_AUTO_GRANT = "auto-grant";
public static final String HOST_LOCALHOST = "localhost";
public static final String HOST_127_0_0_1 = "127.0.0.1";
}
@@ -0,0 +1,85 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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.Log;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.registry.DataSourceRegistry;
import java.nio.file.Path;
/**
* Web global project.
*/
public class WebGlobalProject extends BaseProjectImpl {
private static final Log log = Log.getLog(WebGlobalProject.class);
private final String projectName;
public WebGlobalProject(
@NotNull DBPWorkspace workspace,
@Nullable SMSessionContext sessionContext,
@NotNull String projectName
) {
super(workspace, sessionContext);
this.projectName = projectName;
}
@Override
public boolean isVirtual() {
return false;
}
@NotNull
@Override
public String getName() {
return projectName;
}
@NotNull
@Override
public Path getAbsolutePath() {
return getWorkspace().getAbsolutePath().resolve(projectName);
}
@Override
public boolean isOpen() {
return true;
}
@Override
public void ensureOpen() {
}
@Override
public boolean isUseSecretStorage() {
return false;
}
@NotNull
@Override
protected DBPDataSourceRegistry createDataSourceRegistry() {
return new DataSourceRegistry(this);
}
}
@@ -16,23 +16,102 @@
*/
package io.cloudbeaver.server;
import org.eclipse.core.resources.IWorkspace;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.utils.WebAppUtils;
import org.eclipse.core.runtime.Platform;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.registry.EclipseWorkspaceImpl;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
import org.jkiss.utils.CommonUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Web global workspace.
* <p>
* Basically just a wrapper around Eclipse workspace.
*/
public class WebGlobalWorkspace extends EclipseWorkspaceImpl {
public class WebGlobalWorkspace extends BaseWorkspaceImpl {
public WebGlobalWorkspace(DBPPlatform platform, IWorkspace eclipseWorkspace) {
super(platform, eclipseWorkspace);
private static final Log log = Log.getLog(WebGlobalWorkspace.class);
protected final Map<String, WebProjectImpl> projects = new LinkedHashMap<>();
private WebGlobalProject globalProject;
public WebGlobalWorkspace(DBPPlatform platform) {
super(platform,
platform.getApplication().isMultiuser()
? Path.of(getWorkspaceURI())
: ((WebApplication) platform.getApplication()).getWorkspaceDirectory());
}
@NotNull
private static URI getWorkspaceURI() {
String workspacePath = Platform.getInstanceLocation().getURL().toString();
try {
return new URI(workspacePath);
} catch (URISyntaxException e) {
throw new IllegalStateException("Workspace path is invalid: " + workspacePath, e);
}
}
@Override
protected String initWorkspaceId() {
public void initializeProjects() {
initializeWorkspaceSession();
// Load global project
Path globalProjectPath = getAbsolutePath().resolve(WebAppUtils.getGlobalProjectId());
if (!Files.exists(globalProjectPath)) {
try {
Files.createDirectories(globalProjectPath);
} catch (IOException e) {
log.error("Error creating global project path: " + globalProject, e);
}
}
globalProject = new WebGlobalProject(
this,
getAuthContext(),
CommonUtils.notEmpty(WebAppUtils.getWebApplication().getDefaultProjectName())
);
activeProject = globalProject;
}
@NotNull
@Override
public String getWorkspaceId() {
return readWorkspaceIdProperty();
}
@Nullable
@Override
public DBPProject getActiveProject() {
return super.getActiveProject();
}
@NotNull
@Override
public List<BaseProjectImpl> getProjects() {
return Collections.singletonList(globalProject);
}
@Nullable
@Override
public BaseProjectImpl getProject(@NotNull String projectName) {
if (globalProject.getId().equals(projectName)) {
return globalProject;
}
return null;
}
}
@@ -16,8 +16,6 @@
*/
package io.cloudbeaver.server;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Plugin;
import org.jkiss.dbeaver.ModelPreferences;
import org.jkiss.dbeaver.model.impl.preferences.BundlePreferenceStore;
@@ -76,13 +74,6 @@ public class WebPlatformActivator extends Plugin {
return preferences;
}
/**
* Returns the workspace instance.
*/
public static IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
protected void shutdownPlatform() {
}
@@ -23,6 +23,9 @@ import org.jkiss.dbeaver.DBException;
* Servlet service
*/
public interface DBWServiceBindingServlet<APPLICATION extends WebApplication> extends DBWServiceBinding {
default boolean isApplicable(WebApplication application) {
return true;
}
void addServlets(APPLICATION application, DBWServletContext servletContext) throws DBException;
}
@@ -18,6 +18,7 @@ package io.cloudbeaver.service;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.app.WebServerConfiguration;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
@@ -31,6 +32,7 @@ public interface DBWServiceServerConfigurator extends DBWServiceBinding {
void configureServer(
@NotNull WebApplication application,
@Nullable WebSession session,
@NotNull WebServerConfiguration serverConfiguration,
@NotNull WebAppConfiguration appConfig
) throws DBException;
@@ -22,7 +22,6 @@ package io.cloudbeaver.service.sql;
public class WebSQLConstants {
public static final String QUOTA_PROP_ROW_LIMIT = "sqlResultSetRowsLimit";
public static final String QUOTA_PROP_MEMORY_LIMIT = "sqlResultSetMemoryLimit";
public static final String QUOTA_PROP_QUERY_LIMIT = "sqlMaxRunningQueries";
public static final String QUOTA_PROP_SQL_QUERY_TIMEOUT = "sqlQueryTimeout";
public static final String QUOTA_PROP_TEXT_PREVIEW_MAX_LENGTH = "sqlTextPreviewMaxLength";
@@ -22,6 +22,7 @@ import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
import org.jkiss.dbeaver.model.data.DBDRowIdentifier;
import org.jkiss.dbeaver.model.exec.trace.DBCTrace;
import org.jkiss.dbeaver.model.struct.*;
import java.util.HashSet;
@@ -38,6 +39,7 @@ public class WebSQLResultsInfo {
@NotNull
private final String id;
private DBDAttributeBinding[] attributes;
private DBCTrace trace;
private String queryText;
public WebSQLResultsInfo(@NotNull DBSDataContainer dataContainer, @NotNull String id) {
@@ -132,4 +134,11 @@ public class WebSQLResultsInfo {
(!(entity instanceof DBSDocumentContainer) && !entity.getDataSource().getInfo().isDynamicMetadata());
}
public DBCTrace getTrace() {
return trace;
}
public void setTrace(@NotNull DBCTrace trace) {
this.trace = trace;
}
}
@@ -0,0 +1,124 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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.test;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.utils.GeneralUtils;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* GraphQL client for tests.
*/
public class WebGQLClient {
private static final Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
public static final String GQL_AUTHENTICATE = """
query authLogin($provider: ID!, $configuration: ID, $credentials: Object, $linkUser: Boolean, $forceSessionsLogout: Boolean) {
result: authLogin(
provider: $provider
configuration: $configuration
credentials: $credentials
linkUser: $linkUser
forceSessionsLogout: $forceSessionsLogout
) {
authId
authStatus
}
}""";
@NotNull
private final HttpClient httpClient;
@NotNull
private final String apiUrl;
public WebGQLClient(@NotNull HttpClient httpClient, @NotNull String apiUrl) {
this.httpClient = httpClient;
this.apiUrl = apiUrl;
}
/**
* Sends GraphQL request without additional headers
*
* @param query GraphQL query
* @param variables GraphQL query variables
* @return GraphQL response
*/
@NotNull
public <T> T sendQuery(@NotNull String query, @Nullable Map<String, Object> variables) throws Exception {
return sendQueryWithHeaders(query, variables, List.of());
}
/**
* Sends GraphQL request without additional headers
*
* @param query GraphQL query
* @param variables GraphQL query variables
* @param headers HTTP request headers
* @return GraphQL response
*/
@NotNull
public <T> T sendQueryWithHeaders(
@NotNull String query,
@Nullable Map<String, Object> variables,
@NotNull List<String> headers
) throws Exception {
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.POST(HttpRequest.BodyPublishers.ofString(makeGQLRequest(query, variables)))
.setHeader("TE-Client-Version", GeneralUtils.getMajorVersion())
.header("Content-Type", "application/json");
if (!headers.isEmpty()) {
requestBuilder.headers(headers.toArray(String[]::new));
}
HttpRequest request = requestBuilder.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Map<String, Object> body = gson.fromJson(
response.body(),
JSONUtils.MAP_TYPE_TOKEN
);
if (body.containsKey("errors")) {
String message = JSONUtils.getString(JSONUtils.getObjectList(body, "errors").get(0), "message");
throw new DBException(message);
}
// graphql response will be in "data" key
return (T) JSONUtils.getObject(body, "data").get("result");
}
@NotNull
private String makeGQLRequest(@NotNull String text, @Nullable Map<String, Object> variables) {
Map<String, Object> request = new LinkedHashMap<>();
request.put("query", text);
if (variables != null && !variables.isEmpty()) {
request.put("variables", variables);
}
return gson.toJson(request, Map.class);
}
}
@@ -38,6 +38,8 @@ import org.jkiss.utils.CommonUtils;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class WebAppUtils {
private static final Log log = Log.getLog(WebAppUtils.class);
@@ -199,7 +201,7 @@ public class WebAppUtils {
path = path.concat("; SameSite=" + sameSite);
}
}
sessionCookie.setHttpOnly(true);
sessionCookie.setPath(path);
response.addCookie(sessionCookie);
}
@@ -269,4 +271,13 @@ public class WebAppUtils {
}
}
@NotNull
public static String getFullServerUrl() {
WebApplication application = WebAppUtils.getWebApplication();
return Stream.of(application.getServerURL(), application.getRootURI())
.map(WebAppUtils::removeSideSlashes)
.filter(CommonUtils::isNotEmpty)
.collect(Collectors.joining("/"));
}
}
@@ -18,9 +18,9 @@ package io.cloudbeaver.utils;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebSessionProjectImpl;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
@@ -37,6 +37,7 @@ import org.jkiss.utils.CommonUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class WebDataSourceUtils {
@@ -97,6 +98,10 @@ public class WebDataSourceUtils {
private static void setSecureProperties(DBWHandlerConfiguration handlerConfig, WebNetworkHandlerConfigInput cfgInput, boolean ignoreNulls) {
var secureProperties = cfgInput.getSecureProperties();
if (secureProperties == null) {
if (!handlerConfig.isSavePassword()) {
// clear all secure properties from handler config
handlerConfig.setSecureProperties(Map.of());
}
return;
}
for (var pr : secureProperties.entrySet()) {
@@ -109,14 +114,22 @@ public class WebDataSourceUtils {
@Nullable
public static DBPDataSourceContainer getLocalOrGlobalDataSource(
WebApplication application, WebSession webSession, @Nullable String projectId, String connectionId
WebSession webSession, @Nullable String projectId, String connectionId
) throws DBWebException {
DBPDataSourceContainer dataSource = null;
if (!CommonUtils.isEmpty(connectionId)) {
dataSource = webSession.getProjectById(projectId).getDataSourceRegistry().getDataSource(connectionId);
if (dataSource == null && (webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || application.isConfigurationMode())) {
WebSessionProjectImpl project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
dataSource = project.getDataSourceRegistry().getDataSource(connectionId);
if (dataSource == null &&
(webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || webSession.getApplication().isConfigurationMode())) {
// If called for new connection in admin mode then this connection may absent in session registry yet
dataSource = getGlobalDataSourceRegistry().getDataSource(connectionId);
project = webSession.getGlobalProject();
if (project != null) {
dataSource = project.getDataSourceRegistry().getDataSource(connectionId);
}
}
}
return dataSource;
@@ -153,4 +166,28 @@ public class WebDataSourceUtils {
}
return false;
}
/**
* The method that seeks for web connection in session cache by connection id.
* Mostly used when project id is not defined.
*/
@NotNull
public static WebConnectionInfo getWebConnectionInfo(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
if (projectId == null) {
webSession.addWarningMessage("Project id is not defined in request. Try to find it from connection cache");
// try to find connection in all accessible projects
Optional<WebConnectionInfo> optional = webSession.getAccessibleProjects().stream()
.flatMap(p -> p.getConnections().stream()) // get connection cache from web projects
.filter(e -> e.getId().contains(connectionId))
.findFirst();
if (optional.isPresent()) {
return optional.get();
}
}
return webSession.getAccessibleProjectById(projectId).getWebConnectionInfo(connectionId);
}
}
@@ -17,62 +17,15 @@
package io.cloudbeaver.utils;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.utils.GeneralUtils;
import java.io.File;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class WebTestUtils {
public static final String GQL_TEMPLATE_AUTH_LOGIN = "authLogin.json";
public static String readScriptTemplate(String templateName, Path scriptsPath) throws Exception {
Path templatePath = new File(String.valueOf(scriptsPath), templateName).toPath();
return Files.readString(templatePath);
}
public static Map<String, Object> doPost(String apiUrl, String input, HttpClient client) throws Exception {
return doPostWithHeaders(apiUrl, input, client, List.of());
}
public static Map<String, Object> doPostWithHeaders(
String apiUrl,
String input,
HttpClient client,
List<String> headers
) throws Exception {
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.POST(HttpRequest.BodyPublishers.ofString(input))
.setHeader("TE-Client-Version", GeneralUtils.getMajorVersion())
.header("Content-Type", "application/json");
if (!headers.isEmpty()) {
requestBuilder.headers(headers.toArray(String[]::new));
}
HttpRequest request = requestBuilder.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return new GsonBuilder().create().fromJson(
response.body(),
new TypeToken<Map<String, Object>>() {
}.getType()
);
}
public static boolean getServerStatus(HttpClient client, String apiUrl) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
@@ -86,14 +39,4 @@ public class WebTestUtils {
return false;
}
}
public static Map<String, Object> authenticateUser(HttpClient client, Path scriptsPath, String apiUrl) throws Exception {
String input = WebTestUtils.readScriptTemplate(GQL_TEMPLATE_AUTH_LOGIN, scriptsPath);
Map<String, Object> map = WebTestUtils.doPost(apiUrl, input, client);
Map<String, Object> data = JSONUtils.getObjectOrNull(map, "data");
if (data != null) {
return JSONUtils.getObjectOrNull(data, "authInfo");
}
return Collections.emptyMap();
}
}
@@ -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: 24.1.0.qualifier
Bundle-Release-Date: 20240603
Bundle-Version: 24.2.2.qualifier
Bundle-Release-Date: 20241007
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.product.ce</artifactId>
<version>24.1.0-SNAPSHOT</version>
<version>24.2.2-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Base JDBC drivers
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
Bundle-Version: 1.0.99.qualifier
Bundle-Release-Date: 20240603
Bundle-Version: 1.0.107.qualifier
Bundle-Release-Date: 20241007
Bundle-Vendor: DBeaver Corp
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
@@ -9,6 +9,6 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
<version>1.0.99-SNAPSHOT</version>
<version>1.0.107-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,14 +3,13 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Server
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
Bundle-Version: 24.1.0.qualifier
Bundle-Release-Date: 20240603
Bundle-Version: 24.2.2.qualifier
Bundle-Release-Date: 20241007
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
Bundle-ClassPath: .
Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
org.eclipse.core.resources;visibility:=reexport,
org.apache.commons.jexl,
org.jkiss.utils;visibility:=reexport,
org.jkiss.dbeaver.model.sql;visibility:=reexport,
@@ -29,8 +28,11 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.server.events,
io.cloudbeaver.server,
io.cloudbeaver.server.actions,
io.cloudbeaver.server.jetty,
io.cloudbeaver.server.graphql,
io.cloudbeaver.server.jobs,
io.cloudbeaver.server.servlets,
io.cloudbeaver.server.websockets,
io.cloudbeaver.service,
io.cloudbeaver.service.navigator,
io.cloudbeaver.service.session,
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.server</artifactId>
<version>24.1.0-SNAPSHOT</version>
<version>24.2.2-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -143,11 +143,13 @@ type ServerConfig {
licenseRequired: Boolean!
licenseValid: Boolean!
licenseStatus: String @since(version: "24.1.5")
sessionExpireTime: Int!
localHostAddress: String
configurationMode: Boolean!
# initializationMode: Boolean! @since(version: "24.1.5")
developmentMode: Boolean!
redirectOnFederatedAuth: Boolean!
distributed: Boolean!
@@ -229,6 +231,7 @@ type DriverInfo {
enabled: Boolean!
requiresServerName: Boolean
requiresDatabaseName: Boolean
useCustomPage: Boolean! @since(version: "24.1.2") # if host, port, database, server name fields are custom
licenseRequired: Boolean
license: String
@@ -248,6 +251,10 @@ type DriverInfo {
# Driver parameters (map name->value)
driverParameters: Object!
# Main driver properties
# Contains info about main fields (host, port, database, server name)
mainProperties: [ObjectPropertyInfo!]! @since(version: "24.1.2")
# Additional driver provider properties
# These properties can be configured by user on main connection page
# to provide important connection settings
@@ -340,7 +347,10 @@ type ConnectionInfo {
databaseName: String
url: String
mainPropertyValues: Object @since(version: "24.1.2")
keepAliveInterval: Int!
autocommit: Boolean
properties: Object
@@ -393,6 +403,8 @@ type ConnectionInfo {
projectId: ID!
requiredAuth: String
tools: [String!]! @since(version: "24.1.3")
}
type ConnectionFolderInfo {
@@ -498,6 +510,10 @@ input ConnectionConfig {
port: String
serverName: String
databaseName: String
# Host, port, serverName, databaseName are also stored in mainPropertyValues for custom pages
mainPropertyValues: Object @since(version: "24.1.2")
# Connection url jdbc:{driver}://{host}[:{port}]/[{database}]
url: String
# Properties
@@ -505,6 +521,7 @@ input ConnectionConfig {
# Keep-Alive interval
keepAliveInterval: Int
autocommit: Boolean
# Template connection
template: Boolean
@@ -120,6 +120,7 @@ type SQLResultSet {
# can't update data or load LOB file if hasRowIdentifier = false
hasRowIdentifier: Boolean!
hasChildrenCollection: Boolean!
hasDynamicTrace: Boolean! @since(version: "24.1.2")
isSupportsDataFilter: Boolean!
}
@@ -211,6 +212,16 @@ type SQLScriptQuery {
start: Int!
end: Int!
}
####################################################
# Dynamic trace info
####################################################
type DynamicTraceProperty {
name: String!
value: String
description: String
}
####################################################
# Query and Mutation
####################################################
@@ -402,6 +413,14 @@ extend type Mutation {
asyncSqlRowDataCountResult(taskId: ID!): Int!
@since(version: "24.1.2")
sqlGetDynamicTrace(
projectId: ID,
connectionId: ID!,
contextId: ID!,
resultsId: ID!
): [DynamicTraceProperty!]!
@since(version: "24.0.1")
asyncSqlSetAutoCommit(
projectId: ID!,
@@ -0,0 +1,27 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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;
/**
* "Access denied" exception
*/
public class DBWebExceptionServerNotInitialized extends DBWebException {
public DBWebExceptionServerNotInitialized(String message) {
super(message, ERROR_CODE_SERVER_NOT_INITIALIZED);
}
}
@@ -33,4 +33,6 @@ public @interface WebAction {
boolean authRequired() default true;
boolean initializationRequired() default true;
}
@@ -21,19 +21,23 @@ import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.WebPropertyInfo;
import io.cloudbeaver.model.config.CBAppConfig;
import io.cloudbeaver.model.session.WebActionParameters;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderRegistry;
import io.cloudbeaver.server.CBAppConfig;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.utils.WebAppUtils;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.service.navigator.WebPropertyFilter;
import io.cloudbeaver.utils.WebCommonUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPObject;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
@@ -44,6 +48,7 @@ import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.navigator.DBNProject;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
@@ -52,10 +57,12 @@ import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.driver.DriverDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.properties.PropertyCollector;
import org.jkiss.utils.CommonUtils;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* Various constants
@@ -90,10 +97,6 @@ public class WebServiceUtils extends WebCommonUtils {
return WebDataSourceUtils.getGlobalDataSourceRegistry();
}
public static DBPDataSourceRegistry getGlobalRegistry(WebSession session) {
return session.getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
}
public static InputStream openStaticResource(String path) {
return WebServiceUtils.class.getClassLoader().getResourceAsStream(path);
}
@@ -150,22 +153,7 @@ public class WebServiceUtils extends WebCommonUtils {
}
public static void setConnectionConfiguration(DBPDriver driver, DBPConnectionConfiguration dsConfig, WebConnectionConfig config) {
if (!CommonUtils.isEmpty(config.getUrl())) {
dsConfig.setUrl(config.getUrl());
} else {
if (config.getHost() != null) {
dsConfig.setHostName(config.getHost());
}
if (config.getPort() != null) {
dsConfig.setHostPort(config.getPort());
}
if (config.getDatabaseName() != null) {
dsConfig.setDatabaseName(config.getDatabaseName());
}
if (config.getServerName() != null) {
dsConfig.setServerName(config.getServerName());
}
}
setMainProperties(dsConfig, config);
if (config.getProperties() != null) {
Map<String, String> newProps = new LinkedHashMap<>();
for (Map.Entry<String, Object> pe : config.getProperties().entrySet()) {
@@ -185,6 +173,9 @@ public class WebServiceUtils extends WebCommonUtils {
if (config.getKeepAliveInterval() >= 0) {
dsConfig.setKeepAliveInterval(config.getKeepAliveInterval());
}
if (config.isDefaultAutoCommit() != null) {
dsConfig.getBootstrap().setDefaultAutoCommit(config.isDefaultAutoCommit());
}
// Save provider props
if (config.getProviderProperties() != null) {
dsConfig.setProviderProperties(new LinkedHashMap<>());
@@ -219,6 +210,40 @@ public class WebServiceUtils extends WebCommonUtils {
}
}
private static void setMainProperties(DBPConnectionConfiguration dsConfig, WebConnectionConfig config) {
if (CommonUtils.isNotEmpty(config.getUrl())) {
dsConfig.setUrl(config.getUrl());
return;
}
if (config.getMainPropertyValues() != null) {
for (Map.Entry<String, Object> e : config.getMainPropertyValues().entrySet()) {
if (e.getValue() == null) {
continue;
}
switch (e.getKey()) {
case DBConstants.PROP_HOST -> dsConfig.setHostName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_PORT -> dsConfig.setHostPort(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_DATABASE -> dsConfig.setDatabaseName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_SERVER -> dsConfig.setServerName(CommonUtils.toString(e.getValue()));
default -> throw new IllegalStateException("Unexpected value: " + e.getKey());
}
}
return;
}
if (config.getHost() != null) {
dsConfig.setHostName(config.getHost());
}
if (config.getPort() != null) {
dsConfig.setHostPort(config.getPort());
}
if (config.getDatabaseName() != null) {
dsConfig.setDatabaseName(config.getDatabaseName());
}
if (config.getServerName() != null) {
dsConfig.setServerName(config.getServerName());
}
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@@ -331,4 +356,44 @@ public class WebServiceUtils extends WebCommonUtils {
return result;
}
/**
* Returns set of applicable ids of drivers.
*/
@NotNull
public static Set<String> getApplicableDriversIds() {
return CBPlatform.getInstance().getApplicableDrivers().stream()
.map(DBPDriver::getId)
.collect(Collectors.toSet());
}
/**
* Returns filtered properties collected from object.
*/
@NotNull
public static WebPropertyInfo[] getObjectFilteredProperties(
@NotNull WebSession session,
@NotNull DBPObject object,
@Nullable WebPropertyFilter filter
) {
PropertyCollector propertyCollector = new PropertyCollector(object, true);
propertyCollector.setLocale(session.getLocale());
propertyCollector.collectProperties();
List<WebPropertyInfo> webProps = new ArrayList<>();
for (DBPPropertyDescriptor prop : propertyCollector.getProperties()) {
if (filter != null && !CommonUtils.isEmpty(filter.getIds()) && !filter.getIds().contains(CommonUtils.toString(prop.getId()))) {
continue;
}
WebPropertyInfo webProperty = new WebPropertyInfo(session, prop, propertyCollector);
if (filter != null) {
if (!CommonUtils.isEmpty(filter.getFeatures()) && !webProperty.hasAnyFeature(filter.getFeatures())) {
continue;
}
if (!CommonUtils.isEmpty(filter.getCategories()) && !filter.getCategories().contains(webProperty.getCategory())) {
continue;
}
}
webProps.add(webProperty);
}
return webProps.toArray(new WebPropertyInfo[0]);
}
}

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