Compare commits

..
183 Commits
Author SHA1 Message Date
Alexey fc2e6f6cff dbeaver/pro#5910 fix: sorting only for result sets (#3506)
* dbeaver/pro#5910 fix: sorting only for result sets

* dbeaver/pro#5910 fix: require result set constraints only when needed
2025-06-04 22:24:00 +08:00
aba27cf9d3 dbeaver/pro#5711 Add validation for team id (#3459)
* dbeaver/pro#5711 Add validation for team id

* dbeaver/pro#5711 Add validation for user id

* dbeaver/pro#5711 add user name and team id validation

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-27 17:53:09 +02:00
sergeyteleshev a098db62c3 [CB] hotkeys with "/" and "\" dont work after hotkeys library version upgrade #5781 (#3478)
* dbeaver/pro#5781 fixes shortcuts with slashes symbols + correctly translates it in the shortcut tips section

* moves display logic in SHORCUTS_DATA helpers

* adds replace all for shorcuts to consider sequential shorcuts cases

* adds formatShortcutKeys helper

* removes useless code

* adds alt -> option conversion

* refactors formatKey logic to switch

* cleanup

* cleanup

* cleanup

* switch with lowerCaseCode

* moves shortcut helpers to core-utils + uses it everywhere

* Revert "moves shortcut helpers to core-utils + uses it everywhere"

This reverts commit b4eeda5adf.
2025-05-27 17:50:17 +02:00
c4886127a6 dbeaver/pro#5821 Style fixes (#3479)
* dbeaver/pro#5821 fix: add cursor pointer to icon button

* dbeaver/pro#5821 refactor: change view button type

* dbeaver/pro#5821 feat: add UiSpinner styles for theme integration

* dbeaver/pro#5821 fix: update button class

* dbeaver/pro#5821 fix: improve buttons in driver management

---------

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>
2025-05-27 17:49:05 +02:00
Alexander Skoblikovandkseniaguzeeva 343d671575 dbeaver/pro#5778 custom certs folder in conf folder (#3477)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-27 16:14:11 +02:00
AlexeyandEvgenia 06a0411f84 dbeaver/pro#5200 feat: fast connection / folder creation in the explorer (#3464)
* dbeaver/pro#5200 feat: fast connection / folder creation in the explorer

* chore: update icons

* chore: update icons

* chore: remove important from style

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-27 21:33:23 +08:00
ffe3d45017 dbeaver/pro#5789 replace Buttons styles (#3468)
* dbeaver/pro#5789 refactor: add ButtonIcon component instead of Button.Icon

* dbeaver/pro#5789 refactor: button components across whole application to use UIKit button and UIKit variables

- Rewrite Button.css(former button.module.css) file to define button styles for better maintainability and scalability
- Added props to the Button component for Icons: 'size' and 'placement', currently used only in PropertiesTable (Add property)
- Changed button modifiers to 'variant' swapping unelevated mod to primary(default one, so mod just deleted) and outlined mod to variant secondary.
- In one case changed raised mod to danger variant (deleting a license)

* dbeaver/pro#5789 refactor: fix Button component styling and removed redundant css file

* dbeaver/pro#5789 style: clean up button formatting across multiple components

* dbeaver/pro#5789 refactor: update Tailwind CSS import to use layer directive

* dbeaver/pro#5789 refactor[kit]: add disabled state styles for buttons

* dbeaver/pro#5789 refactor: enhance button styles for disabled state

* dbeaver/pro#5789 fix button problems

* dbeaver/pro#5789 fix: change layer name from theme to base in color styles

* dbeaver/pro#5789 refactor: update button padding from 16px to 15px

* dbeaver/pro#5789 refactor: adjust button gap and update InputFiles button props

* dbeaver/pro#5789 style: center align button in SSHKeyUploader component

* dbeaver/pro#5789 fix: update button classes to use inline-flex for better alignment

* dbeaver/pro#5789 fix: remove initial background from tab styles

* dbeaver/pro#5789 fix: move cursor pointer rule to button container

* dbeaver/pro#5789 fix: update checkbox SVG fill property for proper rendering

* dbeaver/pro#5789 fix: add variant prop to Button component for styling options

* dbeaver/pro#5789 fix: add InlineEditor to CSS layer to compete with theme Important! border-color

* dbeaver/pro#5789 fix: add min-width to button styles for consistency

* dbeaver/pro#5789 refactor: adjust margin for trigger element in context menu

first of all it's done to fix autotests and the second reason is to visually balance the cell with menu

* dbeaver/pro#5789 fix: make boolean great again

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-27 16:59:01 +08:00
ElizabethandDiana 16005be3e6 dbeaver/dbeaver#37602 Add the setting for column names completion (#3474)
* dbeaver/dbeaver#37602 Add the setting for column names completion

* dbeaver/dbeaver#37602 Fix formatting

---------

Co-authored-by: Diana <31996417+uslss@users.noreply.github.com>
2025-05-27 06:20:47 +02:00
alexandEvgenia 005adb10ce dbeaver/pro#5215 track close event on layout close (#3472)
* dbeaver/pro#5215 track close event on layout close

* dbeaver/pro#5215 support old close behaviour

* dbeaver/pro#5215 add event data check to user form

* dbeaver/pro#5215 change naming

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-27 00:39:06 +08:00
Sychev Andrey 0a7d9e6a25 dbeaver/pro#5814 fix: wrap checkbox styles in base layer (#3473)
* dbeaver/pro#5814 ашч: wrap checkbox styles in base layer

* dbeaver/pro#5814 style: wrap disabled styles in base layer
2025-05-26 21:24:09 +08:00
Ainur 0edfb29851 dbeaver/pro#5523 add reason for enable user log (#3463) 2025-05-26 08:31:34 +00:00
52f567fded dbeaver/pro#5553 Add Sorting functionality to base grid (#3456)
* dbeaver/pro#5553 feat: add column sorting functionality to DataGrid

* dbeaver/pro#5553 feat: enhance column sorting functionality to support multiple selection

* dbeaver/pro#5553 feat: add keyboard navigation to order button

* dbeaver/pro#5553 feat: add constraints handling logic for column sorting in DataGrid

* Revert "dbeaver/pro#5553 feat: add constraints handling logic for column sorting in DataGrid"

This reverts commit 6028a48b13.

* dbeaver/pro#5553 feat: add icon generation script to UIKit, add sample icons

* dbeaver/pro#5553 refactor: use inner react-data-grid API for column sorting

* dbeaver/pro#5553 feat: add IconCross component and update icon-related files

* dbeaver/pro#5553 feat: replace Button with IconButton in OrderButton component

* dbeaver/pro#5553 style: update foreground color variables for IconButton component

* dbeaver/pro#5553 refactor: add normalization rules to layers, use IconButton in Common DialogHeader

checked if new IconButton works well in light and dark mode by using in CommonDialogHeader

* dbeaver/pro#5553 style: format code and update dependencies in CommonDialogHeader and DataGridTable components

* dbeaver/pro#5553 style: move onColumnSort prop to correct position in DataGridTable component

* dbeaver/pro#5553 refactor: remove icons component generation, use svg sprite

* dbeaver/pro#5553 refactor: update OrderButton component and inline icons sprite in Body

we decided to go with this solution for now just adding icons to a sprite and use them by id. Imports by ?url  don't work in VSCode if try to use them in <use> href, so we need to find another solution or stick to that approach.

* dbeaver/pro#5553 refactor: update column sorting and sortable logic in DataGrid components

* dbeaver/pro#5553 style: format whitespace in Body component

* dbeaver/pro#5553 feat: add new sorting icons for ascending, descending, and unsorted states

* dbeaver/pro#5553 refactor:styling for header cell and order button components

* dbeaver/pro#5553 refactor: update sorting logic in DataGrid and OrderButton components

* dbeaver/pro#5553 refactor: value deps

* dbeaver/pro#5553 feat: update sorting icons for ascending, descending, and unsorted states

* dbeaver/pro#5553 style: update aria-label and title for OrderButton component

* dbeaver/pro#5553 fix: double focus

* dbeaver/pro#5553 fix: after merge

* dbeaver/pro#5553 refactor: removed outline offset for sort button

* dbeaver/pro#5553 refactor: update Tailwind CSS import to use layer directive

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>
2025-05-24 00:21:37 +08:00
Ainur 116b1a3be8 dbeaver/pro#5160 check length of meta param values (#3471) 2025-05-23 16:01:09 +02:00
AlexeyandDaria Marutkina 84cc6fcf60 dbeaver/pro#5753 feat: react-dnd (#3454)
* dbeaver/pro#5753 feat: react-dnd

* chore: fix after review

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-23 18:52:22 +08:00
1f4266ec95 dbeaver/pro#5745 [CB] Bump NPM dependencies #5745 (#3457)
* dbeaver/pro#5745 updates frontend deps

* updates graphql-request

* updates yarn locks for common-typescript, common-react

* updates engines node version

* react-hotkeys-hook + fixes hotkeys so it continues to work

* code cleanup for parseHotKey

* uses fixed version of tailwindcss

* adds 4.0.6 versions for tailwindcss with resolutions

* reverts tailwind 4.0.6 version for yarn.lock

* removes redundant resolutions for tailwindcss

* Update readme.md with new NodeJS version

* Update README.md with correct nodejs version according to our documentation

* updates talewindcss version 4.0.7

* fix: hotkeys types

---------

Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-05-23 17:31:13 +08:00
Alexey c85b3ccd24 dbeaver/pro#5779 fix: external app plugin naming (#3467) 2025-05-22 17:05:18 +02:00
Ruslan MusaevandEvgenia 7687943ecf dbeaver/pro#5649 Do not send update event if a user teams are same (#3453)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-22 11:14:21 +02:00
alexandEvgenia 587d25bb40 dbeaver/pro#5709 close panel before deleting user (#3458)
* dbeaver/pro#5709 close panel before deleting user

* dbeaver/pro#5709 bump licence year

* dbeaver/pro#5709 remove unnecessary resource hook

* dbeaver/pro#5709 remove unused import

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-22 16:48:42 +08:00
5561d37ce8 dbeaver/pro#4888 Ldap support ssl (#3438)
* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 Ldap support ssl

* dbeaver/pro#4888 fix connection on TE

* dbeaver/pro#4888 ldaps fix

* fix: check configuration id for auth token

* dbeaver/pro#4888 one authentication per provider and configuration

* dbeaver/pro#4888 one authentication per provider and configuration

* Revert "fix: check configuration id for auth token"

This reverts commit 517cc717a8.

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Wroud <wrouds@gmail.com>
2025-05-21 12:26:11 +02:00
alexandkseniaguzeeva fffbea22af dbeaver/pro#5458 add toggleDisabled setting (#3455)
* dbeaver/pro#5458 add toggleDisabled setting

* dbeaver/pro#5458 change setting name

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-21 17:39:50 +08:00
Ainur 934d45617a dbeaver/pro#4372 add new attribute for a property group (#3461) 2025-05-20 18:13:38 +02:00
Ainur ccb6f2208c dbeaver/pro#5404 add complex auth servlet handler (#3418) 2025-05-20 14:33:40 +00:00
alexandDaria Marutkina d9e4383b22 dbeaver/pro#5382 fallback undefined to false (#3452)
* dbeaver/pro#5382 fallback undefined to false

* dbeaver/pro#5382 bump year

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-20 16:34:18 +08:00
Ruslan MusaevandEvgenia cbd8458776 dbeaver/pro#5638 Multi team mapping (#3441)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-20 10:32:59 +02:00
Ruslan MusaevandEvgenia 3352b66a26 dbeaver/pro#5694 Fix auth providers init (#3442)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-20 10:32:27 +02:00
Ruslan MusaevandEvgenia 9b5ceed501 dbeaver/pro#5693 Fix ldap bruteforce protection (#3446)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-20 10:32:02 +02:00
alexandDaria Marutkina 3687a0807d dbeaver/pro#5678 use new api command (#3440)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-19 15:29:30 +02:00
sergeyteleshevandDaria Marutkina bda9966330 dbeaver/pro#5561 removes tiny style from checkboxes for AuthModelCredentialsForm (#3445)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-19 19:39:19 +08:00
Sychev Andreyandmr-anton-t f0be7b6af6 dbeaver/pro#5554 [CB] [UI kit] create IconButton component (#3424)
* dbeaver/pro#5554 feat: first iteration of IconButton

* dbeaver/pro#5554 refactor: css var changes

* dbeaver/pro#5554 feat: add loading state to IconButton component

* dbeaver/pro#5554 style: update background color for loading state in IconButton

* dbeaver/pro#5554 feat: separate icon button styles and loader variables

* dbeaver/pro#5554 refactor: extract ButtonRoot component to use as a base for Button and IconButton components

That approach lets us use common logic (loading) but don't mixup styles and tokens and have better control

* dbeaver/pro#5554 refactor: update loading state styles for IconButton component

* dbeaver/pro#5554 refactor: ButtonRootProps

* dbeaver/pro#5554 refactor: remove opacity from loading state in Button and IconButton components

* dbeaver/pro#5554 refactor: create content wrapper, move general styles there, add loader wrapper

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-05-19 19:38:30 +08:00
serge-rider 3b0f0ddf1e Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2025-05-19 11:44:14 +02:00
serge-rider 85526b45dd Revert "dbeaver/dbeaver#37928 Downgrade ClickHouse driver to 0.7.2 (#3447)"
This reverts commit 7a48102df4.
2025-05-19 11:42:15 +02:00
Daria Marutkina a6a7aeb97f dbeaver/pro#5684 Update README file (#3451)
* dbeaver/pro#5684 Update README file
2025-05-19 11:14:21 +02:00
serge-rider edf54d3b72 dbeaver/pro#5668 Annotations 2025-05-18 10:07:17 +02:00
ShadelessFox 7a48102df4 dbeaver/dbeaver#37928 Downgrade ClickHouse driver to 0.7.2 (#3447) 2025-05-17 05:14:19 +02:00
Ruslan Musaev a16d03d5a6 dbeaver/pro#5695 Revert "Add Driver for Databend (#3174)" (#3443) 2025-05-15 11:12:01 +02:00
serge-rider 8410df4fa9 dbeaver/pro#5684 25.1.0 version bump 2025-05-13 19:23:55 +02:00
295fcf8701 dbeaver/pro#5087 feat: gql api (#3400)
* dbeaver/pro#5087 Add role settings

* dbeaver/pro#5087 feat: gql api

* dbeaver/pro#5087 feat: gql api

* dbeaver/pro#5087 Add role settings

* feat: user role settings

* chore: add tailwind intellisense

* chore: remove mock data

* dbeaver/pro#5087 Add role settings

* dbeaver/pro#5087 Add role settings

* dbeaver/pro#5087 Add role settings

* fix: update roles enum

* feat: settings restore and set status

* dbeaver/pro#5087 fix roles

* chore: hide single settings tab, allow reset for settings that doesn't support full reset

* chore: remove `isSet` method from settings API

* refactor: extract repeatable logic

* chore: add server setting

* chore: better settings grouping

* dbeaver/pro#5087 fixes

* fix: review

* chore: remove roles related code

* chore: hide spreadsheet hiding setting

* dbeaver/pro#5087 Removed everything related with authRole

* chore: hide some settings from UI

* chore: hide per-setting reset

* fix: selecting empty settings groups

---------

Co-authored-by: Ruslan <pupkinvasya7000@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-14 00:01:08 +08:00
Ruslan MusaevandDaria Marutkina ba4f1c9db7 Dbeaver/pro#5652 add security to endpoints (#3435)
* dbeaver/pro#5652 add security to endpoints

* dbeaver/pro#5652 add security to endpoints

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 23:59:39 +08:00
Sychev AndreyandDaria Marutkina bde5c93740 dbeaver/pro#5599 refactor: simplify manualChunks function (#3436)
* dbeaver/pro#5599 refactor: simplify manualChunks function by removing async and circular dependency check

* Revert "dbeaver/pro#5599 refactor: simplify manualChunks function by removing async and circular dependency check"

This reverts commit a8faed50fa.

* dbeaver/pro#5599 fix: configure Vite to prevent CSS code splitting

* dbeaver/pro#5599 refactor: move splitting setting to plugin, add comment

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 20:49:39 +08:00
Pat BuxtonandDaria Marutkina 2421e4806a dbeaver/cloudbeaver#3174 Add Driver for Databend (#3175)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 12:59:02 +02:00
27a9cf3d58 dbeaver/pro#4958 Add default catalog and default schema (#3420)
* dbeaver/pro#4958 Add default catalog and default schema

* dbeaver/pro#4958 add catalog and schema

* dbeaver/pro#4958 remove field duplication

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-13 12:56:12 +02:00
sergeyteleshev cddbb1c876 dbeaver/pro#5377 adds redownload button for drivers installation (#3432) 2025-05-12 22:21:42 +08:00
sergeyteleshevandEvgenia 2ab9d2f450 dbeaver/pro#5405 adds autosave for scripts (#3427)
* dbeaver/pro#5405 adds autosave for scripts

* fixes russian locale

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-12 22:21:21 +08:00
alex 750d66c4ae dbeaver/pro#4405 return version update styles (#3434)
* dbeaver/pro#4405 return version update styles

* dbeaver/pro#4405 fix styles in docker instruction
2025-05-12 22:21:04 +08:00
Ainur 844c01dc75 Revert "dbeaver/pro#5214 get timestamp with calendar fix (#3423)" (#3431)
* Revert "dbeaver/pro#5214 get timestamp with calendar fix (#3423)"

This reverts commit 7b0c6ebe66.

* Revert "dbeaver/pro#5214 set timestamp with utc calendar fix (#3404)"

This reverts commit 0095cc8d37.
2025-05-08 16:25:14 +02:00
154082e6bd vietnamese-localization (#3395)
* vietnamese-localization

* dbeaver/pro#3395 remove extra files

* dbeaver/pro#3395 remove tokens duplication

* dbeaver/pro#3395 fix formatting

* dbeaver/pro#3395 add locale on the backend

* dbeaver/pro#3395 add hardcoded ordering

---------

Co-authored-by: hanhvd <hanhvd@gmail.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
2025-05-08 16:21:35 +02:00
sergeyteleshevandDaria Marutkina 5d90858fa3 prevents default behavior if shortcut executed in it is own scope #3402 (#3417)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-08 14:43:10 +02:00
Sychev AndreyandEvgenia 0ae505fd32 dbeaver/pro#5497 fix: update disabled state logic in BooleanFormatter (#3425)
* dbeaver/pro#5497 fix: update disabled state logic in BooleanFormatter

* dbeaver/pro#5497 style: format disabled state logic

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-08 19:34:39 +08:00
AinurandDaria Marutkina 7b0c6ebe66 dbeaver/pro#5214 get timestamp with calendar fix (#3423)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-08 11:50:02 +02:00
Sychev AndreyandDaria Marutkina 591083435d 5490 cb create spinner UI kit component (#3415)
* #5490 feat: create basic spin component

* #5490 refactor: use new Spin component in button loading state

* #5490 refactor: add tokens to Spin component

add SpecialLoader story to show how to change Spin appearance for special use cases

* #5490 fix: reverts f4d9b6b101

Element should not get focus visible after mouse interactions

* 5490 fix: lost dash

* #5490 refactor: rename Spin to Spinner

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-07 16:23:06 +02:00
d23959a9b5 dbeaver/pro#5460 Add redirect field to provider creation form (#3409)
Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-07 15:33:36 +02:00
Ruslan MusaevandEvgenia 1799768389 dbeaver/pro#5542 change ldap uuid to cn or login (#3410)
* dbeaver/pro#5542 change ldap uuid to cn or login

* dbeaver/pro#5542 fixes

* dbeaver/pro#5542 fixes

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-05-07 15:14:18 +02:00
Alexey 250547f329 dbeaver/cloudbeaver#3402 fix: yarn.lock (#3422) 2025-05-07 16:10:58 +08:00
Georgii 4f52c445fc dbeaver/pro#4075 fix naming (#3416)
* dbeaver/pro#4075 fix naming

* dbeaver/pro#4075 fix rmnio

* dbeaver/pro#4075 fix test launch

* dbeaver/pro#4075 fix test launch
2025-05-06 20:48:40 +02:00
0c70890258 dbeaver/pro#4066 run cli client from launcher, add cli server to CB (#3352)
* dbeaver/pro#4066 run cli client from launcher, add cli server to CB

* dbeaver/pro#4066 special scripts to execute cli commands

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-05-06 20:47:36 +02:00
Sychev AndreyandAlexey bc656de886 #3389 docs: update cb webapp readme (#3399)
* #3389 docs: update cb webapp readme

* #3389 docs: add part about node.js

* #3389 docs: add section about VSCode

* #3389 docs: add OS-specific instructions

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2025-05-06 23:06:37 +08:00
alexandDaria Marutkina fb6e6f6f13 dbeaver/pro#5593 move property value getter to common place (#3414)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-06 22:26:19 +08:00
a0d79ff9b1 dbeaver/pro#5480 Fixed unauthorized access to ldap (#3381)
* dbeaver/pro#5480 Fixed unauthorized access to ldap

* dbeaver/pro#5480 Unauthorized attempt to fetch ldaps groups

* dbeaver/pro#5480 unauthorize attempt to fetch ldaps groups

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mayer <57711367+mayerro@users.noreply.github.com>
2025-05-06 14:25:06 +02:00
f5dfd8726a dbeaver/pro#5312 chore: update typescript sdk (#3407)
* dbeaver/pro#5312 chore: update typescript sdk

* dbeaver/pro#5312 chore: update eslint config

* dbeaver/pro#5312 chore: delete unused file

* dbeaver/pro#5572 remove deprecated annotations (#3405)

* Markup fix (#3408)

* dbeaver/pro#5588 25.0.5 version bump

* #5509 fix: checkbox doesn't get focused on click (#3406)

* dbeaver/pro#5588 Update README file (#3412)

---------

Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: serge-rider <serge@dbeaver.com>
Co-authored-by: Sychev Andrey <44414066+SychevAndrey@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-06 18:09:45 +08:00
AinurandDaria Marutkina 0095cc8d37 dbeaver/pro#5214 set timestamp with utc calendar fix (#3404)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-05-06 10:04:00 +02:00
Daria Marutkina 16fcc21346 dbeaver/pro#5588 Update README file (#3412) 2025-05-05 11:27:23 +02:00
Sychev Andrey f5e4f14159 #5509 fix: checkbox doesn't get focused on click (#3406) 2025-05-05 15:24:34 +08:00
serge-rider 0c1d47ef10 dbeaver/pro#5588 25.0.5 version bump 2025-05-05 07:33:25 +02:00
Serge Rider 2d82e85491 Markup fix (#3408) 2025-04-30 12:27:09 +02:00
Alexander Skoblikov 87e9c79e43 dbeaver/pro#5572 remove deprecated annotations (#3405) 2025-04-30 08:31:20 +00:00
Serge Rider c3042d5aa4 dbeaver/pro#5588 25.0.5 version bump 2025-04-29 19:43:34 +02:00
Ruslan Musaev d06575af9c dbeaver/pro#5249 Migrate authUpdateStatus to websocket (#3369) 2025-04-29 16:36:55 +00:00
Ainur 90eb0520a7 CB-3798 poc api for visibility of properties (#3311) 2025-04-29 14:54:03 +00:00
ShadelessFox dd2869f4bd dbeaver/dbeaver#37727 Update Clickhouse driver to 0.8.5 (#3401) 2025-04-29 14:41:10 +02:00
07e0c63b6a #5362 refactor: move blob formatter to shared codebase (#3374)
* #5362 refactor: move blob formatter to shared codebase

* #5362 refactor: remove value prop from BlobFormatter

* #5362 refactor: move some of result set value checkers to common

* #5362 feat: update some result set api methods

make value type for safe using unknown instead of any,
added string fallback representation for complex values

* fix: getStringFallbackForComplexValue

* #5362 fix: getStringFallbackForComplexValue always cast to string

* #5362 fix: format

* #5362 chore: update deps

* #5362 fix: double imports

* #5362 fix: yarn lock

* chore: update yarn

* fix: reset yarn lock to devel state

* #5362 ci: change chunking

Previous implementation couldn't handle cyclic dependencies correctly. We noticed it in that ticket because we started to move some logic to common packages and changed existing packages connections. I tried many options to organize chunks from very simple(just putting everything to one bundle) to very complex(by adding helper to find circular deps between modules and putting them to one chunk) but none of them looked ideal. Complex solution is prone to errors, especially with vendor packages. I find this solution at least bearable until Vite ships Rolldown, then we can rethink it one more time.

* #5362 fix: arrow-body-style

* fix: improve chunk splitting

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-04-29 16:39:06 +08:00
alexandmr-anton-t 4253c640cf dbeaver/pro#5550 fallback to checked state first (#3398)
* dbeaver/pro#5550 fallback to checked state first

* dbeaver/pro#5550 check for boolean type

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-04-28 14:49:30 +08:00
alexandEvgenia 298ce286f1 dbeaver/pro#5406 use more specific resource (#3397)
* dbeaver/pro#5406 use more specific resource

* dbeaver/pro#5406 use new resource to get flag

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-04-25 21:21:51 +08:00
34c377a17e dbeaver/pro#5438 case-insensitive ws headers (#3393)
* dbeaver/pro#5438 case-insensitive ws headers

* dbeaver/pro#5438 update ping timeout

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2025-04-25 11:59:13 +02:00
9551beca7a CB-5465 fixes checkbox defaultChecked wrong behavior (#3384)
* CB-5465 fixes checkbox defaultChecked wrong behavior

* fix: after review

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-24 12:56:56 +02:00
dfbb2846a5 Dbeaver/pro#5168 avoid leakage of lincense (#3343)
* dbeaver/pro#5168 avoid leakage of license

* dbeaver/pro#5168 avoid leakage of license

* dbeaver/pro#5168 avoid leakage of license

* dbeaver/pro#5168 avoid leakage of license

* CB-5168 fix schema

* [#113] Add clsx dependency to UI kit (#3335)

* chore: add clsx dependency to ui-kit

* chore: import clsx from ui-kit

* refactor: use clsx for class management in Button

* refactor: use clsx in Checkbox

* refactor: use clsx in Input component

* feat: use clsx in radio and radiogroup

* feat: use clsx in Select component

* feat: reexport VisuallyHidden and Focus trap components from ariakit

* CB-5839 fix: resource blocking (#3199)

* CB-5839 fix: resource blocking

* CB-5839 fix: unlock nav resources

* fix: connections loading

* feat: select new folder or connection

* chore: localization

* chore: revert improvements

* fix: load connections list for connection selector

* fix: error

* fix: wrong action handler

* CB-5839 fix: resources tree validation

* fix: reaction concurrency

* CB-5839 fixes build for new CellFormatter (ObjectMenuCell) after merge conflicts

* СB-5839 changes delay for menu item loaders

* CB-5839 fix: keys intersection detection in resources

* CB-5839 fix: keys intersection detection in resources

---------

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: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>

* CB-6308 fix: grid auto-size (#3298)

* CB-6308 fix: grid auto-size

* CB-6308 fix: grid auto size

* CB-6308 fix: icons sizing in grid

* CB-6308 fix: grid header

* CB-6308 fix: types

* fix: min-width for columns

---------

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>

* CB 6296 Delete row shortcut not working (#3340)

* CB-6296 fix: delete keystroke marks selected row for deletion

* CB-6296 fix: focus first element on load, remove extra handler

It was noticed that just after the open, onKeyDown event doesn't reach DataGrid, because focus was not in sync with lib.
Also fixes CB-6229 since they have the same root problem with encountered bag

* CB-6286 refactor: change onCellKeyDown handler interface inside DataGridProps

* CB-6296 refactor: set initial focus differently

* CB-6296 refactor: remove manual scroll control

We use grid inner scrollToCell method and don't need additional native scrolling

* refactor: don't expose inner data-grid type

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>

* CB-5168 fix

* CB-5168 fix schema

* dbeaver#pro5168 hide product config for anonym

* dbeaver/pro#5168 avoid leakage of lincense

* dbeaver/pro#5168 avoid leakage of lincense

* dbeaver/pro#5168 avoid leakage of lincense

---------

Co-authored-by: Sychev Andrey <44414066+SychevAndrey@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.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: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
2025-04-24 12:55:53 +02:00
873861c759 CB-5774 add connection brute force protection (#3337)
* CB-5774 add connection brute force protection

* CB-5774 api for additional info of disabled user

* CB-5774 fix deserialization

* CB-5574 adds disabled user info in editing user form

* CB-5774 save all connect errors to db

* CB-5774 resolve conflicts

* CB-5774 resolve conflicts

* CB-5574 fixes userId

* CB-5774 fix fetch user and test

* CB-5774 resolve conflicts

* CB-5774 handle brute force on desktop

* CB-5774 fix send event for killing user sessions

* CB-5774 build fix

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Wroud <wrouds@gmail.com>
2025-04-23 14:08:23 +02:00
d4e8329528 CB-5790 remove template plugin (#3339)
* CB-5790 remove template plugin

* dbeaver/pro#5038 Remove connection template

* CB-5790 update yarn lock

* CB-5790 fix

* CB-5790 remove templates

* CB-5790 remove template field from fragment

* CB-5790 return access tab

---------

Co-authored-by: Ruslan <pupkinvasya7000@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-04-23 12:34:53 +02:00
Alexey 08346ebc12 dbeaver/pro#5494 feat: refactor tests (#3388)
* dbeaver/pro#5494 feat: refactor tests

* chore: update yarn.lock

* chore: strict build script

* fix: review
2025-04-23 18:18:13 +08:00
d093301983 dbeaver/pro#4245 avoid workspace not initialized warning spam (#3353)
* dbeaver/pro#4245 avoid workspace not initialized warning spam

* dbeaver/pro#4245 use workpsace path from app

* dbeaver/pro#4245 avoid workspace not initialized warning spam

* dbeaver/pro#4245 use workpsace path from app

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2025-04-22 17:56:50 +02:00
Daria Marutkina 8dcc92f7b6 dbeaver/pro#5485 Update README file (#3391) 2025-04-22 09:26:22 +03:00
Serge Rider d29550667b dbeaver/pro#5503 OSGI manifests fix 2025-04-17 17:58:57 +02:00
mayerro 3c2e4fb646 removed wget from java-base-image 2025-04-17 11:27:42 +02:00
alex f286926526 dbeaver/pro#4412 remove license files from locales (#3385) 2025-04-17 16:52:42 +08:00
Alexey 9dc0863e3a dbeaver/pro#5417 feat: table statistics (#3383) 2025-04-16 22:50:16 +08:00
63f31d0a08 Cb 6160 ldap user provisioning (#3354)
* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap provisioning

* CB-6160-ldap-user-provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning

* CB-6160 ldap user provisioning. Added copyrights

---------

Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-04-16 12:18:15 +02:00
Serge Rider 8bce3f2357 dbeaver/pro#5485 25.0.4 version bump 2025-04-15 19:02:17 +02:00
f06b769cfc Dbeaver/pro#5141 improve logging (#3367)
* dbeaver/pro#5141 Improve logging

* dbeaver/pro#5141 Improve logging

* dbeaver/pro#5141 improve logging

* dbeaver/pro#5141 improve logging

* dbeaver/pro#5141 improve logging

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-15 18:10:53 +02:00
Anastasiya 2aca70043e dbeaver/pro#4266 fix templates (#3380)
* dbeaver/pro#4266 Update tickets templates, add config file

* dbeaver/pro#4266 remove Feature commit
2025-04-15 15:01:00 +02:00
Alexander Skoblikov bcbaae3fb4 dbeaver/pro#4353 shutdown executor service (#3332) 2025-04-15 12:16:45 +00:00
AinurandDaria Marutkina bc4d83cbbb dbeaver/pro#5473 show only error message for driver properties (#3378)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-15 13:50:28 +02:00
alexandDaria Marutkina dd1947beaa dbeaver/pro#5255 scroll into view only if there is a cursor and (#3376)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-15 18:39:18 +08:00
sergeyteleshevandmr-anton-t 4aa6ccf495 CB-5472 adds to chunks files from lib directory (#3377)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-04-15 16:43:42 +08:00
4dd8ddbefd CB-4067 Migrate Connection form to form template (#3288)
* CB-4067 adds connection form state, service and options part

* CB-4067 adds connection origin info tab to new form

* CB-4067 adds SSH part

* CB-4067 adds driver properties part

* CB-4067 changes driverId and submitType location for connection form

* CB-4067 adds SSL part

* CB-4067 adds connection form access part

* CB-4067 uses new form parts for connection form

* CB-4067 resets form on open

* CB-4067 fixes configure case for connection form

* CB-4067 adds selected driver on edit mode form

* CB-4067 reloads form when it is needed

* CB-4067 adds button actions for the form

* CB-4067 adds notifications on form save/error

* CB-4067 fixes form ssl saving and driver properties

* CB-4067 refactors some parts

* CB-4067 refactors form options part so it works fine

* CB-4067 fixes driver properties part

* CB-4067 fixes SSH part

* CB-4067 fixes SSL part

* CB-4067 fixes Access part

* CB-4067 refactors origin tab

* CB-4067 refactors shared credentials part

* CB-4067 fixes: secret providers, SSH, SSL, test - features

* CB-4067 removes refactor postfix for new state, service and types

* CB-4067 fixes connection test

* CB-4067 cleanup

* CB-4067 gets back ask credentials window and removes connectionCredentialsStateContext

* CB-4067 adds translation to test connection success message

* CB-4067 fixes ssh and ssl adding to networkHandlers. also fixes extra request for driver properties

* CB-4067 fixes host and port for switching connections

* CB-4067 removes redundant code

* CB-4067 fixes exception error on retest connection + fixes SSH field key saved incorrect prop

* CB-4067 cleanup testContext info

* CB-4076 fixes SSH and SSL ask credentials and parameters saving for both: test and submit connection create/edit action

* CB-4067 fixes access tab reminder

* CB-4067 fixes handling of info message for cloud connection origin tabs

* CB-4067 fixes checkboxes behavior for TE shared credentials feature

* CB-4067 fixes create connection template popup SSH form

* CB-4067 fixes notification for closing ask credentials popup if before we had an error of test submit

* CB-6115 adds dispose API for forms

* CB-6115 adds git workspace helper extension for repo recommendations

* CB-4067 cleanup

* CB-6115 pr fixes

* CB-4067 gets back behavior with dispose connection form state

* CB-4067 cleanup

* СB-4067 splits states to ui and form part in access form part

* СB-4067 pr fixes

* CB-4067 removes config from form state

* CB-4067 removes console warnings + clean up

* CB-4067 moves synchronization mechanisms from ConnectionFormState to ConnectionOptionsFormPart

* CB-4067 fixes bug with incorrect host or port during search or changing driverId during connection creation

* CB-4067 fixes opening connection forms from different entry points so it shows consistent initial data

* СB-4067 brings back saving the form

* CB-4067 fixes logic of showing popup askCredentials

* CB-4067 fixes origin tab name so it shows correctly + fixes unneeded loaders of resources

* CB-4067 reverts isOutdated

* CB-4067 fixes loading of driver properties

* CB-4067 cleanup for connection access part

* Revert "CB-4067 reverts isOutdated"

This reverts commit ecb195ee2a.

* CB-4067 adds isOutdated to the parts

* CB-4067 fixes origin tab info message

* CB-4067 fixes driver properties state + origin info status message shows on load

* CB-4067 fixes password autofill during form save

* CB-4067 fixes linter

* CB-4067 fixes linter

* CB-4067 cleanup + fixes bug with search database host,name fields

* CB-4067 linter fix

* CB-4067 pr fixes

* CB-4067 removes unused post handler for formstate loaded task

* CB-4067 small pr fixes

* CB-4067 adds setDriver + handles name autocomplete

* chore: review

* CB-4067 connection part correct loading

* CB-4067 adds formState.state.connectionId default value

* refactor: pr review

* CB-4067 fixes bug with infinite loading of the origin info details

* CB-4067 fix: allows askCredentials to edit fields + does not affects part state

* CB-4067 resets driver properties if changed driverId

* CB-4067 updates yarn lock for common-react

* CB-4067 lint fix

* CB-6265 fix: do not include index files for import/export eslint rules

* CB-4067 fixes behavior for aksCredentials so it acts correctly during testing/saving/editing inputs for the form

* CB-4067 cleanup

* CB-4067 fixes connection templates initial loaded state

* CB-4067 pr fixes: dialog credentials; adds todo to the ssh tab; eslint revert; cleanup

* CB-4067 makes askCredentials to be part state independent

* CB-4067 qa fixes: test translation + removes db name form connection name

* CB-4067 adds readonly state for connection form

* CB-4067 fixes application freezes on disconnect

* CB-4067 fixes empty properties when switching cloud connections

* CB-4067 connection is created -> connection was created

* CB-4067 connection is updated -> connection was updated

* CB-4067 fixes outdated logic for parts

* CB-4067 build fix

* CB-4067 fix: do not show askCredential popup for drivers with only anonymous access

* CB-4067 removes includeCredentialsSaved

* CB-4067 removes includeAuthProperties

* CB-4067 removes customIncludeOptions

* CB-4067 removes includeProperties

* CB-4067 removes includeProviderProperties

* CB-4067 removes includeNetworkHandlers

* CB-4067 refactors isOutdated for originInfoPart and AccessPart

* CB-4067 removes savedCredentials resource + updates CustomOptionsResource + reuses new include resources in connection form components

* CB-4067 reverts spreading of new connectionInfoResources

* CB-4067 fixes sharedCreds checkbox default value on form switch

* CB-4067 closes connection form when layout closes

* CB-4067 disposes connection form on change

* CB-4067 handles closing of the connection form correctly

* Revert "CB-4067 handles closing of the connection form correctly"

This reverts commit 3a6f1a6a0a.

* CB-4067 handles closing of the connection form correctly [2]

* CB-4067 fits info messages in one line

* CB-4067 presaves isChanged state for form part before applying initialState to prevent bugs

* CB-4067 fixes length of the error message for connection form top bar

---------

Co-authored-by: Alexey <wrouds@gmail.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>
2025-04-15 00:35:27 +08:00
08e6d9631f dbeaver/pro#5440 feat: display boolean as checkbox in grid (#3372)
* dbeaver/pro#5440 feat: display boolean as checkbox in grid

* #5440 refactor: make checkboxes disabled inside grid

It's a very strange UX when checkbox is inside a cell of a table and behaves like a real one. It's much more expected when only cell takes focus and checkbox only represents the value in a way we want without acting like a real input. Moreover, using Focusable component enables smooth toggling between all 3 states of a boolean cell from a keyboard.

* #5440 fix: remove inline padding

* #5440 feat: add hover effect for boolean formatter

* #5440 refactor: revert full width

* #5440 refactor: split onClick and onKeyDown interfaces

* #5440 fix: return onClick

---------

Co-authored-by: Andrey Sychev <nukemoore@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-04-14 22:42:44 +08:00
sergeyteleshev 143cbb0d88 Cb 6265 Return front unit tests after migration (#3338)
* СB-6265 sets up vitest instead of jest

* CB-6265 gets back core-utils tests

* СB-6265 gets back react-testing-library tests

* СB-6265 gets back some tests from another plugins

* CB-6265 renames dist -> lib in each plugin + removes all jest from the repo

* CB-6265 disables watch mode so build can go on

* CB-6265 extends tests types for react-testing-library

* CB-6265 reverts dist->lib rename cause it contains other assets also

* CB-6265 moves setupFiles to the vitest.config.ts

* CB-6265 pr fixes

* CB-6265 fixes tests run for Windows

* CB-6265 removes global: true in config + uses jest-dom/vitest lib to have extended expect types

* CB-6565 removes unused deps

* СB-6265 improves performance of the test x10 times

* CB-6265 gets back renderInApp, fixes vitest setup reset config for mocks, cleans up

* CB-6265 reset -> restore all mocks

* CB-6265 fixes unit tests

* CB-6265 vitest.setup.ts cleanup

* CB-6265 timestamp to date shows military time both: on unix and windows (win tests fix)

* CB-6265 improves tests running (sequential run instead of parallel)

* CB-6265 cleanup

* CB-6265 eslint fix

* CB-6265 eslint fix 2

* CB-6265 reverts useCombined handler

* CB-6265 reverts some tests

* CB-6265 removes all redundant timer configs

* Merge branch 'devel' into CB-6265-return-front-unit-tests-after-migration

* CB-6265 pr fixes

* CB-6265 fixes time for windows

* CB-6265 removes default fake timers before each test
2025-04-14 18:48:33 +08:00
alexandEvgenia efec971177 dbeaver/pro#5234 mark children nodes as deleted (#3370)
* dbeaver/pro#5234 mark children nodes as deleted

* dbeaver/pro#5234 make getParent optional

* dbeaver/pro#5234 pass default value before make observable

* dbeaver/pro#5234 move default value outside of component

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-04-14 18:41:13 +08:00
Ainur edc671f428 dbeaver/pro#5375 normalize table names in one place (#3349) 2025-04-14 09:52:38 +00:00
7f91dbc207 CB-5303 [CB] Driver form has the wrong state after download jar from repo (#3371)
* CB-5303 covers edge case with initial state changed by other tab during outdate part process

* СB-5303 loaded = true on any load result

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-11 22:10:37 +08:00
Alexander Skoblikov 1cc6f6f308 dbeaver/pro#4319 global provider config type (#3330) 2025-04-10 09:19:59 +00:00
Ruslan Musaev 02a8226196 Cb 5875 creating schemas only for pro (#3324) 2025-04-10 09:06:09 +00:00
Sychev AndreyandDaria Marutkina 42da37830f #5140 (CB-6127) the cell values are duplicated when adding multiple rows to the read only table (#3368)
* #5140 fix: duplicate hotkeys should work in tables without primary key

* #5140 fix: force update table data on save if model doesn't have element identifier

* #5140 refactor: move refresh model logic to datasource saveData method

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-10 17:00:55 +08:00
Ainur 3714d7d3a5 dbeaver/pro#5164 remove disabled drivers from core config (#3363) 2025-04-10 08:30:37 +00:00
alexandEvgenia b51ac6bd38 dbeaver/pro#5237 do not dispatch transaction if cursor and main in sync (#3361)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-04-09 15:23:40 +08:00
Sychev AndreyandDaria Marutkina e819af4f90 #5258 fix: See permission error after finish easy config (#3350)
* #5258 fix: don't skip auth dialog for anonymous

* #5258 refactor: use isAuthenticated

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-09 15:20:29 +08:00
Ruslan MusaevandDaria Marutkina 584b27eea2 dbeaver/pro#5272 Do not return private project if they are disabled (#3347)
* dbeaver/pro#5272 Do not return private project if they are disabled

* dbeaver/pro#5272 Do not return private project if they are disabled

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-09 15:20:13 +08:00
Alexeyandmr-anton-t 9c3cc17bd9 dbeaver/pro#5394 feat: null and boolean formatter for base grid (#3359)
* dbeaver/pro#5394 feat: null and boolean formatter for base grid

* feat: reuse base grid formatters

* chore: try to adjust workflow concurrency

* chore: trigger workflow

* chore: trigger workflow cancel

* chore: fix label styles

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-04-09 15:06:32 +08:00
alexandDaria Marutkina e1a05496cb dbeaver/pro#5192 adjust loading state process (#3360)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-04-08 15:51:03 +08:00
Sychev Andrey 947dcb367e #3355 cloudbeaver typescript path resolution problem (#3365)
* #3355 fix: add yarn sdks to git

* #3355 fix: offer to use workspace version of typescript
2025-04-07 21:28:37 +08:00
Daria MarutkinaandAnastasiya b4557ae3a2 dbeaver/pro#5379 Update README file (#3364)
* dbeaver/pro#5379 Update README file

* Update README.md

---------

Co-authored-by: Anastasiya <45152336+LonwoLonwo@users.noreply.github.com>
2025-04-07 14:19:40 +02:00
alexandEvgenia 63acb114df dbeaver/pro#5155 omit " when compare display strings (#3351)
* dbeaver/pro#5155 omit " when compare display strings

* dbeaver/pro#5155 add semicolon

* dbeaver/pro#5155 fix eslint

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-04-04 15:05:54 +02:00
Sychev Andrey a3d8e92b5c fix: wrap input styles in base layer (#3358) 2025-04-03 18:00:51 +08:00
Serge Rider 8681d5f5f5 dbeaver/pro#5379 25.0.3 version bump 2025-04-01 19:57:24 +02:00
Sychev Andrey 3a4a4c53ae #5265 fix: no icons for users and connections on permission tables ( (#3345)
* #5265 fix: no icons for users and connections on permission tables (CB-6373)

* #5265 refactor: remove redundant width prop
2025-04-01 23:10:47 +08:00
600833c068 CB-6372 No 'Set to null' option in cell's context menu (#3331)
* CB-6372 fix: set null for applicable cells in context menu

* CB-6372 fix read-only for cells

CB-6367: don't let activate cell inline editor by double click if model is read-only

---------

Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-04-01 22:05:54 +08:00
164b59b37a CB 6296 Delete row shortcut not working (#3340)
* CB-6296 fix: delete keystroke marks selected row for deletion

* CB-6296 fix: focus first element on load, remove extra handler

It was noticed that just after the open, onKeyDown event doesn't reach DataGrid, because focus was not in sync with lib.
Also fixes CB-6229 since they have the same root problem with encountered bag

* CB-6286 refactor: change onCellKeyDown handler interface inside DataGridProps

* CB-6296 refactor: set initial focus differently

* CB-6296 refactor: remove manual scroll control

We use grid inner scrollToCell method and don't need additional native scrolling

* refactor: don't expose inner data-grid type

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>
2025-03-28 23:01:58 +08:00
b8952c87b8 CB-6308 fix: grid auto-size (#3298)
* CB-6308 fix: grid auto-size

* CB-6308 fix: grid auto size

* CB-6308 fix: icons sizing in grid

* CB-6308 fix: grid header

* CB-6308 fix: types

* fix: min-width for columns

---------

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>
2025-03-28 22:52:46 +08:00
e961d7cda7 CB-5839 fix: resource blocking (#3199)
* CB-5839 fix: resource blocking

* CB-5839 fix: unlock nav resources

* fix: connections loading

* feat: select new folder or connection

* chore: localization

* chore: revert improvements

* fix: load connections list for connection selector

* fix: error

* fix: wrong action handler

* CB-5839 fix: resources tree validation

* fix: reaction concurrency

* CB-5839 fixes build for new CellFormatter (ObjectMenuCell) after merge conflicts

* СB-5839 changes delay for menu item loaders

* CB-5839 fix: keys intersection detection in resources

* CB-5839 fix: keys intersection detection in resources

---------

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: sergeyteleshev <iamsergeyteleshev@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-03-27 20:03:37 +08:00
Sychev Andrey 348d6b3161 [#113] Add clsx dependency to UI kit (#3335)
* chore: add clsx dependency to ui-kit

* chore: import clsx from ui-kit

* refactor: use clsx for class management in Button

* refactor: use clsx in Checkbox

* refactor: use clsx in Input component

* feat: use clsx in radio and radiogroup

* feat: use clsx in Select component

* feat: reexport VisuallyHidden and Focus trap components from ariakit
2025-03-27 20:02:00 +08:00
Alexander SkoblikovandMashaKorax 9ab000d604 dbeaver/pro#4118 separate limits for service auth (#3322)
Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2025-03-26 16:06:18 +01:00
Alexander SkoblikovandMashaKorax a4532dd430 dbeaver/pro#3896 migrate auth process to websockets (#3315)
* dbeaver/pro#3896 new auth flow

* dbeaver/pro#3896 wip

* dbeaver/pro#3896 websocket authentication

* dbeaver/pro#3896 send error info

---------

Co-authored-by: MashaKorax <84867187+MashaKorax@users.noreply.github.com>
2025-03-25 17:52:07 +01:00
Serge Rider 1d21c677ab 3122 dynamic classpath (#3323)
* dbeaver/pro#3122 Driver loader model

* dbeaver/pro#3122 Driver loader model
2025-03-25 17:24:58 +01:00
Daria Marutkina d330b60f35 dbeaver/pro#4354 Update README file (#3336) 2025-03-24 11:46:40 +01:00
Sychev Andrey 584e5bb260 103 create radio and radio group components (#3313)
* refactor: rename css variable in order to be more descriptive and stick to the naming convention

* refactor: unify controls, add new global control css variables

* feat: add radio component

* docs: add radio stories

* docs: add input docs story

* docs: add simple form story

* refactor: change default radio dot size

* refactor: change class name for radio children wrapper

* refactor: don't reexport inner radio elements

* refactor: simplify RadioGroup interface by removing items props, make label(any) required

The radiogroup must have an accessible name either by a visible label referenced by aria-labelledby or has a label specified with aria-label.
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/radiogroup_role

* refactor: use label wrapper for input component to simplify structure

* refactor: add classname for radio group container
2025-03-21 18:52:39 +08:00
sergeyteleshev 71f77186c4 CB-6369 fixes onFinish during easy config for Server Configuration Form (#3328) 2025-03-19 21:32:41 +08:00
Alexander Skoblikov fe6174755b fix ldap version (#3326) 2025-03-18 20:08:25 +00:00
serge-rider d9ba55df54 dbeaver/pro#4354 25.0.2 version bump 2025-03-18 19:32:21 +01:00
serge-rider 70381f38f9 dbeaver/pro#4354 25.0.2 version bump 2025-03-18 19:29:35 +01:00
d9a5ea053b CB-6115 Add dispose to FormState instances (#3317)
* CB-6115 adds dispose API for forms

* CB-6115 adds git workspace helper extension for repo recommendations

* CB-6115 pr fixes

* CB-6115 adds dispose methods to tables

* CB-6115 eslint fix

* CB-6115 fixes dispose leaks for freshly created states

* CB-6115 fixes infinite loading of state

---------

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>
2025-03-18 18:27:23 +01:00
Ainur 06e2aa9f0e CB-6346 add api for read only data sources (#3321) 2025-03-18 17:26:53 +00:00
alexandDaria Marutkina 219ab7c22d CB-6363 return cross button width (#3325)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-03-18 21:39:57 +08:00
Sychev Andrey cdb65a8caa fix: rename default localization property from core.localization.localization to core.localization.language (#3319)
It seems like it was a misspelling initially, because we have never read such key in source code.
2025-03-18 17:07:10 +08:00
Sychev Andrey bd6b4112b0 fix: serve assets relatively with Vite (#3318) 2025-03-18 09:43:23 +01:00
34f4063114 CB-6271 add timeout of inaction in configuration mode (#3289)
* CB-6271 add timeout of inaction in configuration mode

* CB-6271 add timeout of inaction in configuration mode

* CB-6271 add timeout of inaction in configuration mode

* CB-6271 add timeout of inaction in configuration mode

* CB-6271 fix insecure default configuration set timeout to 2 mins

* CB-6271 fix insecure default configuration set timeout to one min

* CB-6271 handle configuration error properly

* CB-6271 catch unhandled error on validation step

* CB-6271 add return type

* CB-6271 fix insecure default configuration set timeout to one min

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: naumov <iamemptyhuh@gmail.com>
2025-03-18 06:21:27 +01:00
AinurandDaria Marutkina 6c44f8c432 CB-5440 extract abstract class for internal db models (#3303)
* CB-5440 extract abstract class for internal db models

* CB-5440 code style fix

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-03-17 12:21:05 +01:00
alexandmr-anton-t 34ff5a34cb Cb 6263 lefthook (#3291)
* CB-6263 migrate to lefthook

* CB-6263 remove old pre-commit

* CB-6263 specify how to execute lefthook

* CB-6263 add config file

* CB-6263 get license from configuration file

* CB-6263 remove old script

* CB-6263 remove old license

* CB-6263 add locales check

* CB-6283 fix vscode commit msg

* CB-6263 filter staged files on lib level

* CB-6263 do not run hooks sync in CI

* CB-6263 change script

* CB-6263 revert postinstall

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-03-17 16:07:16 +08:00
Ainur cb350cc56e CB-6294 read initial data config file before connecting db (#3300) 2025-03-13 10:27:48 +00:00
alexandDaria Marutkina 6dc0b6d8a4 CB-6042 extend sync dep (#3309)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-03-12 20:37:19 +01:00
655613ccf1 CB-6089 write file stream directly to http response (#3301)
* CB-6089 write file stream directly to http response

* CB-6089 write file stream directly to http response

* CB-6089 write file stream directly to http response

* CB-6089 write file stream directly to http response

* CB-6089 write file stream directly to http response

* CB-6089 remove deprecated method

* CB-6089 change ParquetExporter buffer size

* CB-6089 remove extra async

* CB-6089 add info text

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
2025-03-11 17:45:24 +01:00
Ruslan Musaev e87e3397e2 CB-6033 fix message type for cb session log updated ws event (#3310) 2025-03-11 17:29:05 +01:00
Alexander Skoblikovandkseniaguzeeva 3c1766cd14 dbeaver/pro#4204 move file lock logic to dbeaver (#3287)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-03-11 12:46:07 +01:00
alexandmr-anton-t 039407b9db CB-6207 add order to setting group (#3306)
* CB-6207 add order to setting group

* CB-6207 use method instead of const value

* CB-6207 remove const

* CB-6207 sort on tree level

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-03-10 16:44:51 +01:00
serge-rider e02300e34d Logging fix 2025-03-10 14:17:23 +01:00
alexandmr-anton-t 295ce2d46a CB-6286 add className prop (#3297)
* CB-6286 add className prop

* CB-6286 fix virtualisation

* CB-6286 remove extra prop

* CB-6286 fix prop order

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-03-07 23:39:44 +08:00
Sychev Andrey 36102cdee5 88 create select component (#3302)
* feat: add simple select

* feat: add items states vars and popover animation

* feat: add SelectField component

* feat: select field uses getters to get value/label/selected value, update stories to demonstrate

* docs: update select stories

* refactor: remove margin top because we use gutter in SelectField and for reexported aria popover we don't want to setup such default

* fix: select field - set not the very first value by default, but the first not disabled value

* refactor: add popover height variable, remove padding to look more like select in cloudbeaver by default

* feat: add styles for Select Field description

* refactor: rename properties

* refactor: remove redundant docs for props, remove placeholder props because it's not how aria select is supposed to work, you need to use extra select item to create a placeholder

* refactor: remove support for property path, keep only support for property name or custom getter in sake of simplicity and ease of maintenance

* fix: story for key getters

* fix: return type

* fix: don't set disabled value if all items are disabled

* fix: controlled mode, respect value prop over selectedValue

* refactor: remove width property

* refactor: typesafe key getter

The type iterates through every property key in ItemType.
For each property key, it evaluates whether the property's type is assignable to ValueType and creates a union type of all keys that passed the type check

* refactor: fixes after merge and item hover variable

* fix: input

* feat: add custom arrow icon prop

* refactor: remove ability to use object keys as getters, rename options to items in all places

* fix: rename token
2025-03-06 23:32:41 +08:00
c532298eba 87 create checkbox component (#3294)
* refactor: remove --dbv-kit-color-text variable in favor of --dbv-kit-color-foreground, add --dbv-kit-control-disabled-opacity to use for all controls, remove --dbv-kit-btn-disabled-opacity, update docs

* refactor: add ControlSize type

* feat: create checkbox component

* docs: add checkbox stories, update button docs

* refactor: polish checkbox component, added some vars, add docs, change some defaults

* feat: add indeterminate state

* fix: prioritize check prop over inner state

* fix: button styles layer

* fix: comments

* fix: change checkbox checked style

* Revert "fix: change checkbox checked style"

This reverts commit eba1e21eb9.

---------

Co-authored-by: Wroud <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-03-05 15:25:55 +08:00
Daria Marutkina 254da45290 dbeaver/pro#4230 Update README file (#3299) 2025-03-03 14:17:38 +01:00
serge-rider 2c3b44cbdf Merge remote-tracking branch 'origin/devel' into devel 2025-02-27 11:25:27 +01:00
serge-rider 05b0cddab9 dbeaver/pro#4230 25.0.1 version bump 2025-02-27 11:23:59 +01:00
Alexander Skoblikov a118e1c33d CB-6305 throw error if no session for websocket (#3292) 2025-02-26 17:41:42 +00:00
Alexey cc2a8dab63 CB-6301 fix: grid styles (#3290) 2025-02-26 19:00:57 +08:00
Alexey 080317d710 dbeaver/dbeaver-vscode#83 refactor: data grid (#3265)
* dbeaver/dbeaver-vscode#83 refactor: data grid

* chore: try to fix build scripts

* chore: commit artifacts

* chore: update yarn.lock

* fix: adjust grid auto-sizing

* chore: fix prettier

* chore: add documentation about typescript crashes

* fix: cell menu

* fix: grid inline editor styles

* fix: cell menu styles

* fix: cell items alignment

* fix: data sync

* feat: support reactive values in grid

* chore: try to fix strange build bug

* chore: restore original file name

* fix: add specific to inline editor styles

* fix: remove delete row shortcut (not working)

* chore: enable common cache
2025-02-26 01:04:03 +08:00
Sychev Andreyandmr-anton-t a4102b28dd Feat/dbeaver/vscode#86/storybook integration (#3251)
* feat: add ui-kit package to common-react

* feat: add tailwind and ladle to ui-kit, use ui-kit in ce

* feat: create custom properties for button and checkbox using tailwind values as default

* feat: create simple button with 2 variants

* feat: create simple checkbox

* refactor: update after rebase

* feat: experiments with button and checkbox

* feat: add buttons sizes, adjust btn loader, add interactive story instead of many stories

* fix: add license

* fix: a11y issues with color contrast

* fix: mdx stories support

* feat: experiments with icons

* feat: try custom rendering

* docs: add small kinda docs for button

* refactor:  css layers

* chore: deps

* chore: remove buildinfo from git

* chore: remove tsbuildinfo from git

* fix: vertical tab overflow

* feat: use UIKit button as base for Cloudbeaver button

* fix: box-sizing problems

* refactor: button styles use BEM model

* refactor: separate base tokens from aliases

* refactor: add some defaults, write all properties in snake case

* refactor: rename button classes, add ui-kit prefix

* refactor: remove redundant story, omit a couple of props, add example to ladle

* refactor: add general sizes tokens, update license

* feat: add scaffold for input component

* refactor: update deps

* refactor: remove links

* refactor: change props naming, add prefixes in checkbox, removes validation nodes in input

* refactor: partially revert "feat: use UIKit button as base for Cloudbeaver button" to keep the old Button interface without changes

Original commit SHA: 62bb1fe9a0.

* Revert "refactor: update deps"

This reverts commit f7d6533967.

* refactor: update deps once again

* refactor: rename ui-kit prefix

* chore: update deps

* refactor: Button Icon Interface

* refactor: use JSDoc for placement comment

* refactor css custom props for Button

* refactor: introduce opacity custom property, fix icon margin property

* fix: button text should not wrap;

* fix: tailwindcss version

* fix: tailwindcss version

* refactor: remove checkbox styles, keep only wireframe

* refactor: move input-related css variables to the dedicated folder

* refactor: remove unused input props

* refactor: btn loader animation

* refactor: use nesting for states, refactor classnames using BEM delimiters

* refactor: introduce btn-border-width prop, removed redundant btn-padding-block since we use fixed heights

* refactor: input and button

* fix: input

* chore: deps

* chore: deps

* chore: add vite as dev dep

* refactor: button variants

* chore: yarn install

* fix: loading button should not react on hover

* docs: add stories about tokens

* chore:  remove lint command

* refactor: add prefix to css variables

* refactor: add base border-radius and border-width for controls

* fix: don't import tailwind in style files

* fix: add tailwindcss import for ladle

* fix: base radius variable

* refactor: rename css var

* refactor: add tw prefix for tailwind classes and vars

* fix: styles in easy-config

* fix: after tailwind reset paddings don't in width anymore, compensate

* fix: don't show outline on mouse click

* refactor: change btn state classes, remove not loading for hover because it's strange that button reacts on click when in loading state, but not on hover.

* fix: icons

* fix: add letter-spacing to normalize to prevent tailwind reset it with inherit value

* fix: welcome page selector

* fix: button outline uses a variable for width,  proper loading state in aria, icon class name

* feat: add global styles for UI-kit ladle

* docs: refactored stories composition, added stories

* refactor: simplify loader, enable custom loaders, introduced token for btn loader, fix class names, updated stories

* docs: add global styles for ladle

* feat: use custom loader in cloudbeaver

* refactor: use oklch color space for color mixing in loaders

* docs: add readme

* fix: tsconfig, format ladle config

* docs: add short command for ladle, update readme

* fix: module export

* build: add vite plugin

* fix: remove aria-label for loading

* fix: yarn

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2025-02-25 21:04:57 +08:00
serge-rider d40e46739a dbeaver/pro#4230 25.0.1 version bump 2025-02-24 19:37:57 +01:00
f4ba5065c0 CB-6255 Show message/notification for embedded drivers un-disabling (#3277)
* CB-6255 adds warning message for insecure embedded drivers on enabling in server config

* CB-6255 adds warning icon + fixes translations

* CB-6255 add safeEmbeddedDriver parameter to api

* CB-6255 adds safeEmbedded prop to the enabling drivers

* CB-6255 add since to safeEmbeddedDriver

* СB-6255 fixes translation and adds popup size setting

* CB-6255 eslint fix

* CB-6255 cleanup

* CB-6255 removes redundant component

* CB-6255 removes redundant useCallback

---------

Co-authored-by: Ruslan <pupkinvasya7000@gmail.com>
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
2025-02-24 15:31:42 +01:00
Alexander Skoblikovandkseniaguzeeva 50dc9121b6 dbeaver/pro#4207 do not create web session when trying to access static resources (#3284)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-02-24 14:25:41 +01:00
alexandDaria Marutkina 901854f9d1 CB-6284 remove extra symbol from labels (#3286)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-24 16:00:55 +08:00
alex d7d02f2c93 CB-6242 add tooltip for the connection (#3281) 2025-02-21 18:58:12 +00:00
Ainur 12ff40361d CB-6236 fix checking read only status for a column with invalid key identifier (#3276) 2025-02-21 17:05:30 +00:00
Ainur 8d7165b47b CB-4874 api for updating results data using async function (#3280) 2025-02-21 16:59:29 +00:00
sergeyteleshevandEvgenia c7e19a5780 CB-6249 No icons in the app for windows builds (#3267)
* CB-6249 fixes adding assets to the build for windows machines

* СB-6249 fixes the path for windows

* CB-6249 normalizes paths for build assets

* CB-6249 adds comment for assets

* CB-6249 normalizes paths to posix format

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-02-21 22:47:13 +08:00
alexandDaria Marutkina 0ac2bc7346 CB-6279 revert combobox z-index (#3285)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-21 13:52:48 +01:00
AinurandEvgenia 5a7b84c075 CB-6227 fix npe (#3261)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-02-21 10:15:40 +01:00
sergeyteleshevandDaria Marutkina 377a77dd58 CB-6264 Filter field hint list is shown when filter is added manually and focus is out of the field (#3278)
* CB-6264 adds ability to where filter to consider only typed text for suggestions

* CB-6264 adds case with tab

* CB-6224 cleanup

* CB-6264 add fix with focus check

* Revert "CB-6264 add fix with focus check"

This reverts commit 152f38a5c4.

* CB-6264 adds fix via isFocused

* CB-6264 cleanup

* CB-6264 resets state on proposal submission/cancelling

* CB-6264 adds resetState on any replacement case

* CB-6264 adds reset state on menu being invisible

* CB-6264 reverts outside click

* CB-6264 adds resetState on press Tab button

* CB-6264 cleanup

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-21 16:26:49 +08:00
sergeyteleshevandDaria Marutkina 2561583021 CB-3771 Incorrect autocomplete of the Host field while connecting to the local db in the local env (via Search) (#3266)
* CB-3771 loads host form searchDatabases for connections

* CB-3771 fixes overlap for connection host and port values

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-20 21:24:08 +08:00
Ruslan MusaevandEvgenia 4a2c4749f2 CB-6223 enable flat files drive by default (#3256)
* CB-6223 enable flat files drive by default

* CB-6223 enable flat files driver by default

* CB-6223 enable flat files driver by default

* CB-6223 enable flat files driver by default

* CB-6223 enable flat files driver by default

* CB-6223 enable flat files driver by default

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-02-20 14:08:33 +01:00
ShadelessFoxandMatvey16 179c73424a dbeaver/pro#3964 Refactor document (de-)serialization (#3275)
Co-authored-by: Matvey16 <82543000+Matvey16@users.noreply.github.com>
2025-02-19 20:07:05 +01:00
alexandDaria Marutkina 0b924da666 CB-6171 show alert instead of icon (#3263)
* CB-6171 show alert instead of icon

* CB-6171 change locales

* CB-6171 add missing dep

* CB-6171 add flag check

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-19 23:12:36 +08:00
alexandDaria Marutkina 24117dbf3f CB-4013 fix action trigger (#3268)
* CB-4013 fix action trigger

* CB-4013 revert ctrl

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-19 22:18:32 +08:00
Ainur bb23a2d587 CB-6069 grouping panel fix for a complex data type (#3271) 2025-02-19 12:42:35 +00:00
Ainur e93a3d1e62 CB-6102 add event listener filter for a session global project (#3259) 2025-02-19 12:14:10 +00:00
Alexander Skoblikovandkseniaguzeeva 0f7477e2b6 dbeaver/pro#4072 fix missing TE event (#3262)
Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com>
2025-02-19 12:18:46 +01:00
alexandDaria Marutkina df49cef865 CB-6208 adjust z index (#3270)
* CB-6208 adjust z index

* CB-6208 adjust z index to menus

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-19 11:08:01 +01:00
sergeyteleshevandEvgenia 356950bb78 CB-5612 JSON view - filter is cleared after switching to JSON tab (#3264)
* CB-5612 sets where filter on context menu filter actions

* CB-5612 cleanup

---------

Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-02-19 17:47:36 +08:00
sergeyteleshevandDaria Marutkina 0aafa78926 CB-5863 Redirect to the Server Configuration page when refreshing the Identity Providers page (#3257)
* CB-5863 loads administration items loaders before redirects

* CB-5863 removes redirect blockers for administration routes

* CB-5863 loads route loaders on route change

* CB-5863 cleanup

* CB-5863 reverts administration.tsx changes

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-19 17:46:57 +08:00
sergeyteleshevandDaria Marutkina d3ed80219e CB-6135 Database objects do not open after disconnecting (#3254)
* CB-6135 allows to reconnect to the table

* CB-6135 fixes linter issues

* CB-6135 reverts freeze logic

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2025-02-19 17:46:13 +08:00
04388a7cfe CB-5834 fixes shrinking for properties table (#3260)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>
2025-02-19 17:45:20 +08:00
sergeyteleshevandEvgenia 0fea710705 CB-5698 allows to create user with 1 character in username (#3249)
Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
2025-02-19 17:44:31 +08:00
Vladimir Ivanov 56d296558e dbeaver/tech-docs#674 README.md (upd deploy link) (#3274) 2025-02-18 17:25:32 +03:00
Evgenia 87b0087e52 Merge pull request #3272 from dbeaver/dariamarutkina-patch-1
dbeaver/pro#4166 Update README file
2025-02-18 12:52:26 +03:00
Daria Marutkina b79287d327 dbeaver/pro#4166 Update README file 2025-02-18 10:20:06 +01:00
4cdfa5b07f Cb 6041 system information (#3245)
* CB-6041 add system information plugin

* CB-6041 api for system information

* CB-6041 api for system information

* CB-6041 api for system information

* CB-6041 simplify system info ui

* CB-6041 remove extra props

* CB-6041 api for internal database information

* CB-6041 remove hint

* CB-6041 add missing field

* CB-6041 use categories for database info

* CB-6041 add categories

* CB-6041 add category to copy info

* CB-6041 code style fix

* CB-6041 fix get property ids

* CB-6041 updates react version to 19

---------

Co-authored-by: Ainur <ainur.iagudin@dbeaver.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: sergeyteleshev <iamsergeyteleshev@gmail.com>
2025-02-12 12:44:07 +01:00
Serge Rider f542534fdc dbeaver/pro#4166 25.0.0 version bump 2025-02-11 21:17:35 +01:00
Serge Rider b06f28bd83 dbeaver/pro#4166 25.0.0 version bump 2025-02-11 21:16:19 +01:00
1825 changed files with 40574 additions and 27341 deletions
-29
View File
@@ -1,29 +0,0 @@
---
name: Bug report
about: Create a report to help us improve CloudBeaver
title: ''
labels: bug, wait for review
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here, e.g. error log.
+61
View File
@@ -0,0 +1,61 @@
name: 🐛 Bug Report
description: Create a report to help us improve our product
labels: [wait for review]
type: Bug
body:
- type: markdown
attributes:
value: |
Thank you for reporting a bug in CloudBeaver!
To ensure we can address the issue as quickly and efficiently as possible, please provide as much detail as you can in the fields below.
- type: textarea
id: description
attributes:
label: Description
description: |
A clear and concise description of the issue being addressed.
- Describe the actual problematic behavior.
- Ensure private information is redacted.
- Include console output or log files if relevant.
- If applicable, add screenshots or screen recordings to help explain your problem.
placeholder: |
Please enter a description of the issue. Here you can also attach log files, screenshots or a video
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: Describe the steps to reproduce the bug
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
- type: textarea
id: expected
attributes:
label: Expected/Desired Behavior
description: |
A clear and concise description of what happens in the software **after** a fix is created and merged.
validations:
required: true
- type: input
id: version
attributes:
label: CloudBeaver Version
description: What version of CloudBeaver are you running?
placeholder: ex. CloudBeaver Community 25.0.0
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Any additional context about the environment
placeholder: |
Example:
1. OS: [e.g. iOS, Ubuntu, Windows 11]
2. Browser: [e.g. Chrome, Safari]
validations:
required: false
+14
View File
@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Read our documentations
url: https://dbeaver.com/docs/cloudbeaver
about: Many articles about product deployment and features.
- name: Try advanced database management features in DBeaver PRO or CloudBeaver EE
url: https://dbeaver.com/download/?utm_source=github&utm_medium=social&utm_campaign=issue
about: Download a 14-day free trial on dbeaver.com. No credit card is needed.
- name: Learn how to use CloudBeaver effectively with our tutorial videos
url: https://www.youtube.com/channel/UC-yOjsQLSaJVEghg6UB3N7A
about: Subscribe to our YouTube channel and watch new tutorials every week.
- name: Follow us on X (ex. Twitter)
url: https://x.com/dbeaver_news
about: Get everyday tips, fresh news, and DBeaver/CloudBeaver feature overviews.
+10 -3
View File
@@ -1,8 +1,9 @@
---
name: Feature request
about: Suggest an idea for CloudBeaver
name: Feature Request
about: Provide a description of your feature request for CloudBeaver. Include the problem you are trying to solve, why it is important, and any specific functionality you believe would improve the platform.
title: ''
labels: feature request, wait for review
labels: wait for review
type: Feature
assignees: ''
---
@@ -12,3 +13,9 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+3 -2
View File
@@ -1,8 +1,9 @@
---
name: Question
about: Is there something unclear?
about: Is there something unclear? Ask your question.
title: ''
labels: question, wait for review
labels: wait for review
type: Question
assignees: ''
---
+24 -2
View File
@@ -40,7 +40,7 @@ jobs:
- name: Clone Deps Repositories
uses: dbeaver/github-actions/clone-repositories@devel
with:
project_deps_path: './cloudbeaver/project.deps'
project_deps_path: "./cloudbeaver/project.deps"
token: ${{ secrets.DEVOPS_ISSUE_RO_TOKEN }}
- run: corepack enable
@@ -48,7 +48,17 @@ jobs:
with:
node-version: "lts/*"
cache: "yarn"
cache-dependency-path: './cloudbeaver/webapp/yarn.lock'
cache-dependency-path: |
cloudbeaver/common-*/yarn.lock
cloudbeaver/webapp/yarn.lock
- name: restore cloudbeaver-common typescript cache
uses: actions/cache@v4
with:
path: "cloudbeaver/common-*/**/*/lib"
key: ${{ runner.os }}-common-dist-${{ hashFiles('cloudbeaver/common-*/yarn.lock') }}
restore-keys: |
${{ runner.os }}-common-dist-
- name: restore typescript cache
uses: actions/cache@v4
@@ -61,11 +71,23 @@ jobs:
- if: inputs.clean-cache
run: yarn clear
- run: yarn install --immutable
working-directory: ./cloudbeaver/common-typescript
- run: yarn install --immutable
working-directory: ./cloudbeaver/common-react
- run: yarn install --immutable
- run: yarn bundle
working-directory: ./cloudbeaver/webapp/packages/product-default
- run: yarn test
working-directory: ./cloudbeaver/common-typescript
# - run: yarn test
# working-directory: ./cloudbeaver/common-react
- run: yarn test
# - name: Archive build artifacts
+6
View File
@@ -29,6 +29,12 @@ jobs:
cache: "yarn"
cache-dependency-path: "./cloudbeaver/webapp/yarn.lock"
# - run: yarn install --immutable
# working-directory: ./cloudbeaver/common-typescript
# - run: yarn install --immutable
# working-directory: ./cloudbeaver/common-react
- run: |
yarn install --immutable
git fetch origin "${{ github.base_ref }}" --depth=1
+1 -1
View File
@@ -10,7 +10,7 @@ on:
branches: [devel]
concurrency:
group: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'push-pr-devel' }}
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true
jobs:
+2 -1
View File
@@ -19,6 +19,7 @@
"yzhang.markdown-all-in-one",
"GraphQL.vscode-graphql-syntax",
"mrmlnc.vscode-json5",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"devnaumov.licensify"
]
}
-15
View File
@@ -1,15 +0,0 @@
{
"license": {
"scope": "typescript,typescriptreact,javascript,javascriptreact,css,scss",
"prefix": "license",
"body": [
"/*",
" * CloudBeaver - Cloud Database Manager",
" * Copyright (C) 2020-2025 DBeaver Corp and others",
" *",
" * Licensed under the Apache License, Version 2.0.",
" * you may not use this file except in compliance with the License.",
" */"
]
}
}
+5 -9
View File
@@ -2,21 +2,18 @@
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.linkedEditing": true,
"task.autoDetect": "off",
"java.configuration.updateBuildConfiguration": "automatic",
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx16G -Xms100m -Xlog:disable",
"java.compile.nullAnalysis.mode": "automatic",
"typescript.preferences.useAliasesForRenames": false,
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.preferences.includePackageJsonAutoImports": "on",
"typescript.preferences.quoteStyle": "single",
"typescript.tsdk": "webapp/.yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"prettier.prettierPath": "webapp/.yarn/sdks/prettier/index.cjs",
"eslint.nodePath": "webapp/.yarn/sdks",
"eslint.enable": true,
"eslint.validate": [
"javascript",
@@ -24,8 +21,9 @@
"typescript",
"typescriptreact"
],
"eslint.workingDirectories": ["webapp"],
"eslint.workingDirectories": [
"webapp"
],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
@@ -42,12 +40,10 @@
"[java]": {
"editor.defaultFormatter": "redhat.java"
},
"files.eol": "\n",
"files.associations": {
"*.css": "postcss"
},
"java.checkstyle.configuration": "${workspaceFolder}/../dbeaver-common/.github/dbeaver-checkstyle-config.xml",
"java.checkstyle.version": "10.12.0"
}
}
+1 -9
View File
@@ -92,18 +92,10 @@
"clear": false
}
},
{
"label": "Update TS references CE",
"type": "shell",
"command": "yarn run update-ts-references",
"options": {
"cwd": "${workspaceFolder}/webapp"
}
},
{
"label": "Clean CE",
"type": "shell",
"command": "yarn clean",
"command": "yarn clear",
"options": {
"cwd": "${workspaceFolder}/webapp"
}
+61 -58
View File
@@ -7,7 +7,7 @@ CloudBeaver is a web server that provides a rich web interface. The server itsel
It is free to use and open-source (licensed under [Apache 2](https://github.com/dbeaver/cloudbeaver/blob/devel/LICENSE) license).
See our [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/connection-creation-demo.png" width="400"/>
<a><img src="https://github.com/dbeaver/cloudbeaver/wiki/images/connection-creation-demo.png" width="400"/></a>
<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"/>
@@ -15,7 +15,7 @@ See our [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
## Run in Docker
- [Official Docker repository](https://hub.docker.com/r/dbeaver/cloudbeaver)
- [Running instructions](https://github.com/dbeaver/cloudbeaver/wiki/Run-Docker-Container)
- [Deployment instructions](https://github.com/dbeaver/cloudbeaver/wiki/CloudBeaver-Deployment)
## Demo server
@@ -25,67 +25,70 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
## Changelog
### 24.3.4. 2025-02-03
- Connections:
- Added a possibility to switch a database connection to the read-only mode. This mode can be activated in the connection dialog. Administrators can set this mode for any connections, the regular users can set it for their own private connections only;
- An ability to use advanced database settings in the URL connection mode was added for Oracle and SQL Server connections.
- General:
- Introduced auto-suggestions for column names in the Data Editor filter field to avoid typing mistakes;
- Fixed the display of objects with long names (more than 32 characters) in the Navigator tree - now, such names will be displayed entirely and not in a cropped format;
- Added the ability to use default spreadsheet names (e.g. Sheet0, Sheet1) for export to XLSX.
- Deployment:
- CloudBeaver base Java image was switched to the JDK 21 version. The new Java version will be applied automatically after the product update if you use standard deployment and upgrade scripts;
- Changed the permissions of the Docker volumes directory from the "root" user to the "dbeaver" user (uid=8978). To enhance security and prevent any insecure actions by the "root" user. These changes will only affect existing deployments.
### 25.0.5 2025-05-19
- Added the ability to configure the default database or schema in the connection configuration;
- A new setting to autosave scripts in the SQL editor appeared in global and users' preferences;
- SQLite: added information about a table Strict mode to the table metadata section (thanks to @eusebe-cda);
- Vietnamese localization has been added (thanks to @0xhanh).
### 24.3.3. 2025-01-20
- Administration:
- Added an ability to match users from LDAP configuration with CloudBeaver users;
- New environment variables were introduced for theme styling, SQL editor, and log viewer settings. You can use them for quick setup during the initial Docker configuration stage.
### 25.0.4 2025-05-05
- Important:
- Connection templates were removed from the application. You can use the Connection Editor to create new connections.
- Databases and drivers:
- LibSQL: added the ability to use token authentication for connecting;
- Clickhouse: driver has been updated to version 0.8.5.
### 25.0.3 2025-04-21
- Administration: log records now capture create, update, and delete actions for users, teams, and connections for improved tracking and transparency;
- SQL Editor: auto-completion has been improved for aliases and camelCase entities;
- Users DDL in Oracle is displayed in metadata editor on corresponding tab for users with Oracle administration permissions;
- Different bug fixes and enhancements have been made.
### 25.0.2 2025-04-07
- Data Editor: improved table rendering to scale column width depending on the content.
- Improved Navigation tree performance: lost connection does not lead to the application freezing anymore.
- Different bug fixes and enhancements have been made.
### 25.0.1 2025-03-24
- Improved performance of the export/import functionality by optimizing disk memory consumption;
- Enhanced initial configuration on stage security: if the initial setup time exceeds 1 hour, the server must be restarted.
### 25.0 2025-03-03
### Changes since 24.3.0:
- General:
- An ability to show metadata object comments was added in the Navigator tree. You can enable it in the database navigator settings panel;
- Added transaction log viewing for connections with manual commit mode. This allows users to see all modifying statements before committing;
- Added an ability to import data in tables without unique keys;
- Added an ability to insert data in tables without unique keys;
- Added Ctrl + Shift + S (Cmd + Shift + S on Mac) shortcut for "Save As Script" action.
### 24.3.2. 2025-01-06
- Added an ability to specify a user login as an attribute parameter for LDAP providers;
- The collapse of the grouping panel doesn't lead to the full panel cleaning anymore.
### 24.3.1. 2024-12-23
- Added an ability to reconnect for all editors if a connection has been lost;
- Added an option to replace line break characters on any custom value when exporting to CSV;
- Added an ability to create connections in the Navigation tree not only on the initial level but in folders and sub-folders directly;
- Updated list of available shortcuts for MacOS.
### 24.3.0. 2024-12-02
### Changes since 24.2.0:
- General:
- The connections Templates feature is declared obsolete and will be removed in future releases;
- Data export: Added the ability to export JSON values as embedded JSON;
- Fixed a proxy issue that excluded the Content-Type header in responses;
- Data editor enhancements: Rows with focused cells are specially marked to make it easier to locate a position in large tables;
- Keyboard navigation has been enhanced. You can now use the arrow keys to move through navigator tree elements and the tab key to switch between editors' tabs;
- Sample SQLite database was removed;
- Chinese localization has been improved (thanks to @cashlifei);
- Brazilian Portuguese localization was enhanced (thanks to @brlarini).
- Added an ability for all editors to reconnect if a connection has been lost;
- Tooltips for metadata objects and SQL Editor tabs now include additional details about catalogs, schemas, and connections;
- Added Ctrl + Shift + S (Cmd + Shift + S on Mac) shortcut for the "Save As Script" action;
- Updated list of available shortcuts for macOS.
- Administration:
- Updated user storage mechanism: New user logins are now stored in lowercase to prevent duplicate entries (e.g., "ADMIN" and "admin"). Note: This update does not affect previously created user logins;
- Added an ability to change a user password even if the user is disabled in a system;
- Refreshed design for the User and Teams tab in the Administration panel;
- A new setting in Global Preferences was added to restrict data import for non-admin users;
- A search option was added for preferences in the Administration part;
- Added detailed logging of GraphQL queries in the server logs, including all provided variables, for improved debugging and monitoring;
- Environment variables configuration has been improved - now you can configure more variables on the initial stage of the Docker setup.
- Databases:
- PostgreSQL, Greenplum, CockroachDB: The URL mode now supports connecting to multiple databases;
- PostgreSQL, H2, and SQL Server: Schemas were added to the SQL autocompletion;
- MySQL: CloudBeaver can now correctly display negative dates;
- DuckDB: The issue with displaying BLOB data types has been resolved.
- Added system information data to the Product Information tab in the Administration panel. This provides administrators with quick access to essential system details, such as the server deployment type (e.g., Docker, Kubernetes), install path, Java version, and Java parameters;
- The global access server URL has been added to the console log, making it easier to locate server installation information directly within the logs;
- New environment variables were introduced for theme styling, SQL editor, and log viewer settings. You can use them for quick setup during the initial Docker configuration stage.
- LDAP authorization:
- Added the ability to match users from LDAP configuration with CloudBeaver users;
- Added an option to specify a user login as an attribute parameter for LDAP providers;
- CloudBeaver now uses EntityID or objectGUID to create new LDAP users in CloudBeaver to ensure uniqueness. This change enhances user identification and prevents conflicts while maintaining backward compatibility for existing users.
- Deployment:
- CloudBeaver now uses JDK 21 as its base Java image. If you use standard deployment and upgrade scripts, the new Java version will be applied automatically after the product update;
- Changed the permission of the Docker volumes directory to enhance security and prevent any insecure actions by the "root" user. All new deployments will use the "dbeaver" user by default. For existing deployments running as the "root" user, this update will automatically adjust file permissions to ensure they are compatible with the new security model. There will be no manual intervention, and the service will continue to run as expected with the updated permissions.
- Connections:
- Enabled the possibility of switching a database connection to read-only mode. This mode can be activated in the connection dialog. Administrators can set this mode for any connection, while regular users can set it for their private connections only;
- For Oracle and SQL Server connections, advanced database settings can now be used in the URL connection mode.
- Data Editor:
- Auto-suggestions for column names in the Data Editor filter field were introduced to avoid typing mistakes;
- Introduced the ability to insert data in tables without unique keys: you can import data from CSV files or insert entire rows directly via UI;
- The collapse of the grouping panel doesn't lead to the complete panel cleaning anymore.
- Data transfer:
- Added the ability to use default spreadsheet names (e.g. Sheet0, Sheet1) for exporting to XLSX;
- An option to replace line break characters on any custom value was added when exporting to CSV.
- Navigator tree:
- An option to show metadata object comments was added. You can enable it in the database navigator settings panel;
- Introduced the ability to create connections not only on the initial level but in folders and sub-folders directly;
- Fixed the display of objects with long names (more than 32 characters) - now, such names will be displayed entirely and not in a cropped format.
- Drivers:
- A new LibSQL/Turso driver was added;
- SQL Server driver has been updated to version 12.8.0;
- DB2i driver has been updated to version 20.0.7.
- The MariaDB driver has been updated to version 3.5.1;
- The SQLite driver has been updated to version 3.48.0.0.
## Contribution
As a community-driven open-source project, we warmly welcome contributions through GitHub pull requests.
+8 -6
View File
@@ -1,9 +1,17 @@
# artifacts
lib
out
dist
node_modules
# Yarn
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!.yarn/sdks/**
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
@@ -11,9 +19,3 @@
#!.yarn/cache
.pnp.*
# artifacts
lib
out
dist
node_modules
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "prettier",
"version": "3.4.2-sdk",
"version": "3.5.3-sdk",
"main": "./index.cjs",
"type": "commonjs",
"bin": "./bin/prettier.cjs"
-10
View File
@@ -1,10 +0,0 @@
{
"name": "typescript",
"version": "5.7.3-sdk",
"main": "./lib/typescript.js",
"type": "commonjs",
"bin": {
"tsc": "./bin/tsc",
"tsserver": "./bin/tsserver"
}
}
+8 -1
View File
@@ -1,3 +1,10 @@
enableTelemetry: false
preferReuse: true
# pnpIgnorePatterns:
# - "**/cloudbeaver/common-typescript/**"
plugins:
- checksum: 50414773926286d8c0fc32e9936a799ad23296281046f03674bc33517b597e1ff7856092c3fcf8d5460a29549ef8b3dca3f59a1732b650a02bf523b255d726e7
path: .yarn/plugins/@yarnpkg/plugin-ts-project-linker.cjs
spec: "https://raw.githubusercontent.com/Wroud/foundation/refs/heads/main/packages/yarn-plugin-ts-project-linker/bundles/%40yarnpkg/plugin-ts-project-linker.js"
@@ -0,0 +1 @@
!lib
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -1,11 +1,10 @@
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { Context } from 'react';
import { JSX } from 'react/jsx-runtime';
import type { Key } from 'react';
import { Provider } from 'react';
import type { ReactElement } from 'react';
import { ReactNode } from 'react';
import { RefAttributes } from 'react';
declare interface BaseRenderRowProps<TRow, TSummaryRow = unknown> extends Omit_2<React.HTMLAttributes<HTMLDivElement>, 'style' | 'children'>, Pick<DataGridProps<TRow, TSummaryRow>, 'onCellClick' | 'onCellDoubleClick' | 'onCellContextMenu'> {
declare interface BaseRenderRowProps<TRow, TSummaryRow = unknown> extends Omit_2<React.ComponentProps<'div'>, 'style' | 'children'>, Pick<DataGridProps<TRow, TSummaryRow>, 'onCellClick' | 'onCellDoubleClick' | 'onCellContextMenu'> {
viewportColumns: readonly CalculatedColumn<TRow, TSummaryRow>[];
rowIdx: number;
selectedCellIdx: number | undefined;
@@ -27,6 +26,7 @@ export declare interface CalculatedColumn<TRow, TSummaryRow = unknown> extends C
readonly draggable: boolean;
readonly frozen: boolean;
readonly renderCell: (props: RenderCellProps<TRow, TSummaryRow>) => ReactNode;
readonly renderHeaderCell: (props: RenderHeaderCellProps<TRow, TSummaryRow>) => ReactNode;
}
export declare type CalculatedColumnOrColumnGroup<R, SR> = CalculatedColumnParent<R, SR> | CalculatedColumn<R, SR>;
@@ -40,9 +40,10 @@ export declare interface CalculatedColumnParent<R, SR> {
readonly headerCellClass?: Maybe<string>;
}
export declare const Cell: <R, SR>(props: CellRendererProps<R, SR> & RefAttributes<HTMLDivElement>) => JSX.Element;
export declare const Cell: <R, SR>(props: CellRendererProps<R, SR>) => React.JSX.Element;
export declare interface CellClickArgs<TRow, TSummaryRow = unknown> {
rowIdx: number;
row: TRow;
column: CalculatedColumn<TRow, TSummaryRow>;
selectCell: (enableEditor?: boolean) => void;
@@ -59,7 +60,7 @@ export declare type CellKeyDownArgs<TRow, TSummaryRow = unknown> = SelectCellKey
export declare type CellMouseEvent = CellEvent<React.MouseEvent<HTMLDivElement>>;
export declare interface CellRendererProps<TRow, TSummaryRow> extends Pick<RenderRowProps<TRow, TSummaryRow>, 'row' | 'rowIdx' | 'selectCell'>, Omit_2<React.HTMLAttributes<HTMLDivElement>, 'style' | 'children' | 'onClick' | 'onDoubleClick' | 'onContextMenu'> {
export declare interface CellRendererProps<TRow, TSummaryRow> extends Pick<RenderRowProps<TRow, TSummaryRow>, 'row' | 'rowIdx' | 'selectCell'>, Omit_2<React.ComponentProps<'div'>, 'children' | 'onClick' | 'onDoubleClick' | 'onContextMenu'> {
column: CalculatedColumn<TRow, TSummaryRow>;
colSpan: number | undefined;
isCopied: boolean;
@@ -73,7 +74,7 @@ export declare interface CellRendererProps<TRow, TSummaryRow> extends Pick<Rende
export declare interface CellSelectArgs<TRow, TSummaryRow = unknown> {
rowIdx: number;
row: TRow;
row: TRow | undefined;
column: CalculatedColumn<TRow, TSummaryRow>;
}
@@ -92,19 +93,25 @@ export declare interface Column<TRow, TSummaryRow = unknown> {
readonly name: string | ReactElement;
/** A unique key to distinguish each column */
readonly key: string;
/** Column width. If not specified, it will be determined automatically based on grid width and specified widths of other columns */
/**
* Column width. If not specified, it will be determined automatically based on grid width and specified widths of other columns
* @default 'auto'
*/
readonly width?: Maybe<number | string>;
/** Minimum column width in px. */
/**
* Minimum column width in px
* @default '50px'
*/
readonly minWidth?: Maybe<number>;
/** Maximum column width in px. */
readonly maxWidth?: Maybe<number>;
readonly cellClass?: Maybe<string | ((row: TRow) => Maybe<string>)>;
readonly headerCellClass?: Maybe<string>;
readonly summaryCellClass?: Maybe<string | ((row: TSummaryRow) => Maybe<string>)>;
/** Render function used to render the content of the column's header cell */
readonly renderHeaderCell?: Maybe<(props: RenderHeaderCellProps<TRow, TSummaryRow>) => ReactNode>;
/** Render function used to render the content of cells */
readonly renderCell?: Maybe<(props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>;
/** Render function used to render the content of the column's header cell */
readonly renderHeaderCell?: Maybe<(props: RenderHeaderCellProps<TRow, TSummaryRow>) => ReactNode>;
/** Render function used to render the content of summary cells */
readonly renderSummaryCell?: Maybe<(props: RenderSummaryCellProps<TSummaryRow, TRow>) => ReactNode>;
/** Render function used to render the content of group cells */
@@ -151,16 +158,25 @@ export declare interface CopyEvent<TRow> {
sourceRow: TRow;
}
export declare const DataGridDefaultRenderersProvider: Provider<Maybe<Renderers<any, any>>>;
/**
* Main API Component to render a data grid of rows and columns
*
* @example
*
* <DataGrid columns={columns} rows={rows} />
*/
export declare function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridProps<R, SR, K>): JSX.Element;
export declare const DataGridDefaultRenderersContext: Context<Maybe<Renderers<any, any>>>;
export declare interface DataGridHandle {
element: HTMLDivElement | null;
selectedCell: Position;
scrollToCell: (position: PartialPosition) => void;
selectCell: (position: Position, enableEditor?: Maybe<boolean>) => void;
}
export declare interface DataGridProps<R, SR = unknown, K extends Key = Key> extends SharedDivProps {
ref?: Maybe<React.Ref<DataGridHandle>>;
/**
* Grid and data Props
*/
@@ -228,7 +244,7 @@ export declare interface DataGridProps<R, SR = unknown, K extends Key = Key> ext
/** Called when the grid is scrolled */
onScroll?: Maybe<(event: React.UIEvent<HTMLDivElement>) => void>;
/** Called when a column is resized */
onColumnResize?: Maybe<(idx: number, width: number) => void>;
onColumnResize?: Maybe<(column: CalculatedColumn<R, SR>, width: number) => void>;
/** Called when a column is reordered */
onColumnsReorder?: Maybe<(sourceColumnKey: string, targetColumnKey: string) => void>;
/**
@@ -236,6 +252,10 @@ export declare interface DataGridProps<R, SR = unknown, K extends Key = Key> ext
*/
/** @default true */
enableVirtualization?: Maybe<boolean>;
/**
* The minimum number of rows to render when virtualization is enabled
*/
minimumRowsToRender?: Maybe<number>;
/**
* Miscellaneous
*/
@@ -244,12 +264,10 @@ export declare interface DataGridProps<R, SR = unknown, K extends Key = Key> ext
/** @default 'ltr' */
direction?: Maybe<Direction>;
'data-testid'?: Maybe<string>;
'data-cy'?: Maybe<string>;
}
declare const _default: <R, SR = unknown, K extends Key = Key>(props: DataGridProps<R, SR, K> & RefAttributes<DataGridHandle>) => React.JSX.Element;
export default _default;
declare type DefaultColumnOptions<R, SR> = Pick<Column<R, SR>, 'renderCell' | 'width' | 'minWidth' | 'maxWidth' | 'resizable' | 'sortable' | 'draggable'>;
export declare type DefaultColumnOptions<R, SR> = Pick<Column<R, SR>, 'renderCell' | 'renderHeaderCell' | 'width' | 'minWidth' | 'maxWidth' | 'resizable' | 'sortable' | 'draggable'>;
declare type Direction = 'ltr' | 'rtl';
@@ -296,7 +314,7 @@ export declare interface PasteEvent<TRow> {
targetRow: TRow;
}
export declare interface Position {
declare interface Position {
readonly idx: number;
readonly rowIdx: number;
}
@@ -310,9 +328,9 @@ export declare interface RenderCellProps<TRow, TSummaryRow = unknown> {
onRowChange: (row: TRow) => void;
}
export declare function renderCheckbox({ onChange, indeterminate, ...props }: RenderCheckboxProps): JSX_2.Element;
export declare function renderCheckbox({ onChange, indeterminate, ...props }: RenderCheckboxProps): JSX.Element;
export declare interface RenderCheckboxProps extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'aria-label' | 'aria-labelledby' | 'checked' | 'tabIndex' | 'disabled'> {
export declare interface RenderCheckboxProps extends Pick<React.ComponentProps<'input'>, 'aria-label' | 'aria-labelledby' | 'checked' | 'tabIndex' | 'disabled'> {
indeterminate?: boolean | undefined;
onChange: (checked: boolean, shift: boolean) => void;
}
@@ -326,10 +344,10 @@ export declare interface RenderEditCellProps<TRow, TSummaryRow = unknown> {
}
export declare interface Renderers<TRow, TSummaryRow> {
renderCell?: Maybe<(key: Key, props: CellRendererProps<TRow, TSummaryRow>) => ReactNode>;
renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>;
renderRow?: Maybe<(key: Key, props: RenderRowProps<TRow, TSummaryRow>) => ReactNode>;
renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>;
renderCell?: Maybe<(key: Key, props: CellRendererProps<TRow, TSummaryRow>) => ReactNode>;
noRowsFallback?: Maybe<ReactNode>;
}
@@ -343,7 +361,7 @@ export declare interface RenderGroupCellProps<TRow, TSummaryRow = unknown> {
toggleGroup: () => void;
}
export declare function renderHeaderCell<R, SR>({ column, sortDirection, priority }: RenderHeaderCellProps<R, SR>): string | JSX_2.Element;
export declare function renderHeaderCell<R, SR>({ column, sortDirection, priority }: RenderHeaderCellProps<R, SR>): string | JSX.Element;
export declare interface RenderHeaderCellProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
@@ -363,7 +381,7 @@ export declare interface RenderRowProps<TRow, TSummaryRow = unknown> extends Bas
setDraggedOverRowIdx: ((overRowIdx: number) => void) | undefined;
}
export declare function renderSortIcon({ sortDirection }: RenderSortIconProps): JSX_2.Element | null;
export declare function renderSortIcon({ sortDirection }: RenderSortIconProps): JSX.Element | null;
export declare interface RenderSortIconProps {
sortDirection: SortDirection | undefined;
@@ -384,11 +402,11 @@ export declare interface RenderSummaryCellProps<TSummaryRow, TRow = unknown> {
tabIndex: number;
}
export declare function renderToggleGroup<R, SR>(props: RenderGroupCellProps<R, SR>): JSX_2.Element;
export declare function renderToggleGroup<R, SR>(props: RenderGroupCellProps<R, SR>): JSX.Element;
export declare function renderValue<R, SR>(props: RenderCellProps<R, SR>): ReactNode;
export declare const Row: <R, SR>(props: RenderRowProps<R, SR> & RefAttributes<HTMLDivElement>) => React.JSX.Element;
export declare const Row: <R, SR>(props: RenderRowProps<R, SR>) => React.JSX.Element;
export declare type RowHeightArgs<TRow> = {
type: 'ROW';
@@ -431,7 +449,7 @@ export declare interface SelectRowEvent<TRow> {
isShiftClick: boolean;
}
declare type SharedDivProps = Pick<React.HTMLAttributes<HTMLDivElement>, 'role' | 'aria-label' | 'aria-labelledby' | 'aria-describedby' | 'aria-rowcount' | 'className' | 'style'>;
declare type SharedDivProps = Pick<React.ComponentProps<'div'>, 'role' | 'aria-label' | 'aria-labelledby' | 'aria-description' | 'aria-describedby' | 'aria-rowcount' | 'className' | 'style'>;
declare type SharedInputProps = Pick<RenderCheckboxProps, 'disabled' | 'tabIndex' | 'aria-label' | 'aria-labelledby' | 'indeterminate' | 'onChange'>;
@@ -442,11 +460,11 @@ export declare interface SortColumn {
export declare type SortDirection = 'ASC' | 'DESC';
export declare function textEditor<TRow, TSummaryRow>({ row, column, onRowChange, onClose }: RenderEditCellProps<TRow, TSummaryRow>): JSX_2.Element;
export declare function textEditor<TRow, TSummaryRow>({ row, column, onRowChange, onClose }: RenderEditCellProps<TRow, TSummaryRow>): JSX.Element;
export declare function ToggleGroup<R, SR>({ groupKey, isExpanded, tabIndex, toggleGroup }: RenderGroupCellProps<R, SR>): JSX_2.Element;
export declare function ToggleGroup<R, SR>({ groupKey, isExpanded, tabIndex, toggleGroup }: RenderGroupCellProps<R, SR>): JSX.Element;
export declare const TreeDataGrid: <R, SR = unknown, K extends Key = Key>(props: TreeDataGridProps<R, SR, K> & RefAttributes<DataGridHandle>) => React.JSX.Element;
export declare function TreeDataGrid<R, SR = unknown, K extends Key = Key>({ columns: rawColumns, rows: rawRows, rowHeight: rawRowHeight, rowKeyGetter: rawRowKeyGetter, onCellKeyDown: rawOnCellKeyDown, onRowsChange, selectedRows: rawSelectedRows, onSelectedRowsChange: rawOnSelectedRowsChange, renderers, groupBy: rawGroupBy, rowGrouper, expandedGroupIds, onExpandedGroupIdsChange, ...props }: TreeDataGridProps<R, SR, K>): JSX.Element;
export declare interface TreeDataGridProps<R, SR = unknown, K extends Key = Key> extends Omit_2<DataGridProps<R, SR, K>, 'columns' | 'role' | 'aria-rowcount' | 'rowHeight' | 'onFill' | 'isRowSelectionDisabled'> {
columns: readonly Column<NoInfer<R>, NoInfer<SR>>[];
@@ -15,7 +15,7 @@
Root;
}
.mlln6zg7-0-0-beta-47 {
.mlln6zg7-0-0-beta-50 {
@layer rdg.MeasuringCell {
contain: strict;
grid-row: 1;
@@ -24,13 +24,13 @@
}
.cj343x07-0-0-beta-47 {
.cj343x07-0-0-beta-50 {
@layer rdg.Cell {
/* max-content does not work with size containment
* dynamically switching between different containment styles incurs a heavy relayout penalty
* Chromium bug: at odd zoom levels or subpixel positioning,
* layout/paint/style containment can make cell borders disappear
* https://bugs.chromium.org/p/chromium/issues/detail?id=1326946
* https://issues.chromium.org/issues/40840864
*/
position: relative; /* needed for absolute positioning to work */
padding-block: 0;
@@ -53,7 +53,7 @@
}
}
.csofj7r7-0-0-beta-47 {
.csofj7r7-0-0-beta-50 {
@layer rdg.Cell {
position: sticky;
/* Should have a higher value than 0 to show up above unfrozen cells */
@@ -67,7 +67,7 @@
}
.c1bn88vv7-0-0-beta-47 {
.c1bn88vv7-0-0-beta-50 {
@layer rdg.CheckboxInput {
display: block;
margin: auto;
@@ -86,13 +86,13 @@
}
.g1s9ylgp7-0-0-beta-47 {
.g1s9ylgp7-0-0-beta-50 {
@layer rdg.GroupCellContent {
outline: none;
}
}
.cz54e4y7-0-0-beta-47 {
.cz54e4y7-0-0-beta-50 {
@layer rdg.GroupCellCaret {
margin-inline-start: 4px;
stroke: currentColor;
@@ -107,24 +107,39 @@
}
.c6ra8a37-0-0-beta-47 {
.h44jtk67-0-0-beta-50 {
@layer rdg.SortableHeaderCell {
display: flex;
}
}
.hcgkhxz7-0-0-beta-50 {
@layer rdg.SortableHeaderCellName {
flex-grow: 1;
overflow: clip;
text-overflow: ellipsis;
}
}
.c6ra8a37-0-0-beta-50 {
@layer rdg.Cell {
background-color: #ccccff;
}
}
.cq910m07-0-0-beta-47 {
.cq910m07-0-0-beta-50 {
@layer rdg.Cell {
background-color: #ccccff;
&.c6ra8a37-0-0-beta-47 {
&.c6ra8a37-0-0-beta-50 {
background-color: #9999ff;
}
}
}
.c1w9bbhr7-0-0-beta-47 {
.c1w9bbhr7-0-0-beta-50 {
@layer rdg.DragHandle {
--rdg-drag-handle-size: 8px;
z-index: 0;
@@ -142,7 +157,7 @@
}
}
.c1creorc7-0-0-beta-47 {
.c1creorc7-0-0-beta-50 {
@layer rdg.DragHandle {
z-index: 1;
position: sticky;
@@ -150,41 +165,26 @@
}
.cis5rrm7-0-0-beta-47 {
.cis5rrm7-0-0-beta-50 {
@layer rdg.EditCell {
padding: 0;
}
}
.h44jtk67-0-0-beta-47 {
@layer rdg.SortableHeaderCell {
display: flex;
}
}
.hcgkhxz7-0-0-beta-47 {
@layer rdg.SortableHeaderCellName {
flex-grow: 1;
overflow: clip;
text-overflow: ellipsis;
}
}
.c6l2wv17-0-0-beta-47 {
.c6l2wv17-0-0-beta-50 {
@layer rdg.HeaderCell {
cursor: pointer;
}
}
.c1kqdw7y7-0-0-beta-47 {
.c1kqdw7y7-0-0-beta-50 {
@layer rdg.HeaderCell {
touch-action: none;
}
}
.r1y6ywlx7-0-0-beta-47 {
.r1y6ywlx7-0-0-beta-50 {
@layer rdg.HeaderCell {
cursor: col-resize;
position: absolute;
@@ -195,16 +195,16 @@
}
}
.c1bezg5o7-0-0-beta-47 {
.c1bezg5o7-0-0-beta-50 {
opacity: 0.5;
}
.c1vc96037-0-0-beta-47 {
.c1vc96037-0-0-beta-50 {
background-color: var(--rdg-header-draggable-background-color);
}
.r1upfr807-0-0-beta-47 {
.r1upfr807-0-0-beta-50 {
@layer rdg.Row {
display: contents;
background-color: var(--rdg-background-color);
@@ -223,14 +223,14 @@
}
}
.r190mhd37-0-0-beta-47 {
.r190mhd37-0-0-beta-50 {
@layer rdg.FocusSink {
outline: 2px solid var(--rdg-selection-color);
outline-offset: -2px;
}
}
.r139qu9m7-0-0-beta-47 {
.r139qu9m7-0-0-beta-50 {
@layer rdg.FocusSink {
&::before {
content: '';
@@ -244,26 +244,26 @@
}
.h10tskcx7-0-0-beta-47 {
.h10tskcx7-0-0-beta-50 {
@layer rdg.HeaderRow {
display: contents;
background-color: var(--rdg-header-background-color);
font-weight: bold;
& > .cj343x07-0-0-beta-47 {
& > .cj343x07-0-0-beta-50 {
/* Should have a higher value than 1 to show up above regular cells and the focus sink */
z-index: 2;
position: sticky;
}
& > .csofj7r7-0-0-beta-47 {
& > .csofj7r7-0-0-beta-50 {
z-index: 3;
}
}
}
.a3ejtar7-0-0-beta-47 {
.a3ejtar7-0-0-beta-50 {
@layer rdg.SortIcon {
fill: currentColor;
@@ -274,7 +274,7 @@
}
.rnvodz57-0-0-beta-47 {
.rnvodz57-0-0-beta-50 {
@layer rdg.Defaults {
*,
*::before,
@@ -334,30 +334,30 @@
}
> :nth-last-child(1 of .rdg-top-summary-row) {
> .cj343x07-0-0-beta-47 {
> .cj343x07-0-0-beta-50 {
border-block-end: 2px solid var(--rdg-summary-border-color);
}
}
> :nth-child(1 of .rdg-bottom-summary-row) {
> .cj343x07-0-0-beta-47 {
> .cj343x07-0-0-beta-50 {
border-block-start: 2px solid var(--rdg-summary-border-color);
}
}
}
}
.vlqv91k7-0-0-beta-47 {
.vlqv91k7-0-0-beta-50 {
@layer rdg.Root {
user-select: none;
& .r1upfr807-0-0-beta-47 {
& .r1upfr807-0-0-beta-50 {
cursor: move;
}
}
}
.f1lsfrzw7-0-0-beta-47 {
.f1lsfrzw7-0-0-beta-50 {
@layer rdg.FocusSink {
grid-column: 1/-1;
pointer-events: none;
@@ -366,7 +366,7 @@
}
}
.f1cte0lg7-0-0-beta-47 {
.f1cte0lg7-0-0-beta-50 {
@layer rdg.FocusSink {
/* Should have a higher value than 3 to show up above header and summary rows */
z-index: 3;
@@ -374,7 +374,7 @@
}
.s8wc6fl7-0-0-beta-47 {
.s8wc6fl7-0-0-beta-50 {
@layer rdg.SummaryCell {
inset-block-start: var(--rdg-summary-row-top);
inset-block-end: var(--rdg-summary-row-bottom);
@@ -382,42 +382,42 @@
}
.skuhp557-0-0-beta-47 {
.skuhp557-0-0-beta-50 {
@layer rdg.SummaryRow {
> .cj343x07-0-0-beta-47 {
> .cj343x07-0-0-beta-50 {
position: sticky;
}
}
}
.tf8l5ub7-0-0-beta-47 {
.tf8l5ub7-0-0-beta-50 {
@layer rdg.SummaryRow {
> .cj343x07-0-0-beta-47 {
> .cj343x07-0-0-beta-50 {
z-index: 2;
}
> .csofj7r7-0-0-beta-47 {
> .csofj7r7-0-0-beta-50 {
z-index: 3;
}
}
}
.g1yxluv37-0-0-beta-47 {
.g1yxluv37-0-0-beta-50 {
@layer rdg.GroupedRow {
&:not([aria-selected='true']) {
background-color: var(--rdg-header-background-color);
}
> .cj343x07-0-0-beta-47:not(:last-child, .csofj7r7-0-0-beta-47),
> :nth-last-child(n + 2 of .csofj7r7-0-0-beta-47) {
> .cj343x07-0-0-beta-50:not(:last-child, .csofj7r7-0-0-beta-50),
> :nth-last-child(n + 2 of .csofj7r7-0-0-beta-50) {
border-inline-end: none;
}
}
}
.t7vyx3i7-0-0-beta-47 {
.t7vyx3i7-0-0-beta-50 {
@layer rdg.TextEditor {
appearance: none;
@@ -446,3 +446,6 @@
}
}
/*# sourceMappingURL=styles.css.map*/
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
{
"name": "react-data-grid",
"version": "7.0.0-beta.50",
"type": "module",
"exports": {
"./lib/styles.css": "./lib/styles.css",
".": {
"types": "./lib/index.d.ts",
"default": "./lib/bundle.js"
}
},
"browser": "./lib/bundle.js",
"main": "./lib/bundle.js",
"module": "./lib/bundle.js",
"types": "./lib/index.d.ts",
"files": [
"lib"
],
"sideEffects": [
"**/*.css"
],
"dependencies": {
"clsx": "^2.0.0"
},
"peerDependencies": {
"react": "^19.0",
"react-dom": "^19.0"
}
}
@@ -4,6 +4,7 @@
"sideEffects": [],
"exports": {
".": "./lib/index.js",
"./*.css": "./src/*.css",
"./*": "./lib/*.js"
},
"scripts": {
@@ -32,8 +33,10 @@
"typescript": "^5"
},
"dependencies": {
"@dbeaver/react-dnd": "workspace:^",
"@dbeaver/ui-kit": "workspace:^",
"react": "^19",
"react-data-grid": "7.0.0-beta.47",
"react-data-grid": "file:./artifacts",
"react-dom": "^19"
}
}
@@ -0,0 +1,86 @@
import { memo, use, useMemo } from 'react';
import { Cell, type CellRendererProps } from 'react-data-grid';
import { DataGridCellContext, type IDataGridCellRenderer } from './DataGridCellContext.js';
import { createCellMouseEvent } from './eventUtils.js';
import { DataGridCellInnerContext, type IDataGridCellInnerContext } from './DataGridCellInnerContext.js';
import { useGridReactiveValue } from './useGridReactiveValue.js';
import { HeaderDnDContext } from './useHeaderDnD.js';
export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRendererProps<TRow, TSummaryRow>) {
const cellContext = use(DataGridCellContext);
const dndContext = use(HeaderDnDContext)!;
const virtualColIdx = props.column.idx;
const dataColIdx = dndContext.getDataColIdx(props.column.idx);
const rowIdx = props.rowIdx;
const tooltip = useGridReactiveValue(cellContext?.cellTooltip, rowIdx, dataColIdx);
function handleClick(event: React.MouseEvent<HTMLDivElement>) {
props.onClick?.(
{
rowIdx,
row: props.row,
column: props.column,
selectCell(enableEditor) {
props.selectCell({ rowIdx, idx: virtualColIdx }, enableEditor);
},
},
createCellMouseEvent(event),
);
}
function handleDoubleClick(event: React.MouseEvent<HTMLDivElement>) {
props.onDoubleClick?.(
{
rowIdx,
row: props.row,
column: props.column,
selectCell(enableEditor) {
props.selectCell({ rowIdx, idx: virtualColIdx }, enableEditor);
},
},
createCellMouseEvent(event),
);
}
function handleContextMenu(event: React.MouseEvent<HTMLDivElement>) {
props.onContextMenu?.(
{
rowIdx,
row: props.row,
column: props.column,
selectCell(enableEditor) {
props.selectCell({ rowIdx, idx: virtualColIdx }, enableEditor);
},
},
createCellMouseEvent(event),
);
}
const mappedProps = useMemo(
() => ({ ...props, isFocused: props.isCellSelected, onClick: handleClick, onDoubleClick: handleDoubleClick, onContextMenu: handleContextMenu }),
Object.values(props),
);
const renderDefaultCell = useMemo<IDataGridCellRenderer>(
() =>
({ onClick, onDoubleClick, onContextMenu, ...rest }) => {
return (
<Cell
{...props}
title={tooltip}
onClick={(_, event) => onClick?.(event)}
onDoubleClick={(_, event) => onDoubleClick?.(event)}
onContextMenu={(_, event) => onContextMenu?.(event)}
{...rest}
isCellSelected={props.isCellSelected || rest.isFocused || false}
/>
);
},
[...Object.values(props), tooltip],
);
const cellElement = useGridReactiveValue(cellContext?.cellElement, rowIdx, dataColIdx, mappedProps, renderDefaultCell);
const innerCellContext = useMemo<IDataGridCellInnerContext>(() => ({ isFocused: props.isCellSelected }), [props.isCellSelected]);
return <DataGridCellInnerContext value={innerCellContext}>{cellElement ?? <Cell title={tooltip} {...props} />}</DataGridCellInnerContext>;
}) as <TRow, TSummaryRow>(props: CellRendererProps<TRow, TSummaryRow>) => React.ReactNode;
@@ -0,0 +1,16 @@
import { Row, type RenderRowProps } from 'react-data-grid';
import { DataGridRowContext } from './DataGridRowContext.js';
import { memo, use, useEffect } from 'react';
import { useGridReactiveValue } from './useGridReactiveValue.js';
export const BaseRow = memo(function BaseRow<TRow, TSummaryRow>(props: RenderRowProps<TRow, TSummaryRow>) {
const rowContext = use(DataGridRowContext);
const rowsCount = useGridReactiveValue(rowContext?.onScrollToBottom ? rowContext?.rowCount : undefined);
useEffect(() => {
if (rowsCount === props.rowIdx + 1) {
rowContext?.onScrollToBottom?.();
}
}, [rowsCount]);
return <Row {...props} />;
}) as <TRow, TSummaryRow>(props: RenderRowProps<TRow, TSummaryRow>) => React.ReactNode;
@@ -0,0 +1,33 @@
@import url('@dbeaver/ui-kit/index.css');
@import url('react-data-grid/lib/styles.css') layer(components);
@layer components.rdg.MeasuringCell {
[data-measuring-cell] {
max-width: var(--rdg-max-auto-size, 350px);
}
}
@layer components.rdg.Cell {
.rdg {
--dbv-kit-icon-btn-outline-width: 1px;
}
@media (prefers-color-scheme: dark) {
.rdg-cell-frozen {
&:nth-last-child(1 of &) {
box-shadow: none;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
background-color: rgba(255, 255, 255, 0.02);
}
}
}
}
}
@@ -1,45 +1,172 @@
// import { useSyncExternalStore } from 'react';
import DataGridBase, { type ColumnOrColumnGroup } from 'react-data-grid';
import 'react-data-grid/lib/styles.css';
import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
import { DataGrid as DataGridBase, type ColumnOrColumnGroup, type CellSelectArgs, type DataGridHandle } from 'react-data-grid';
import { rowRenderer } from './renderers/rowRenderer.js';
import { cellRenderer } from './renderers/cellRenderer.js';
import { DataGridCellHeaderContext, type IDataGridHeaderCellContext } from './DataGridHeaderCellContext.js';
import { DataGridCellContext, type IDataGridCellContext } from './DataGridCellContext.js';
import type { IInnerRow } from './IInnerRow.js';
import type { IGridReactiveValue } from './IGridReactiveValue.js';
import { useGridReactiveValue } from './useGridReactiveValue.js';
import { mapCellContentRenderer } from './mapCellContentRenderer.js';
import { mapRenderHeaderCell } from './mapRenderHeaderCell.js';
import { mapEditCellRenderer } from './mapEditCellRenderer.js';
import { DataGridRowContext, type IDataGridRowContext } from './DataGridRowContext.js';
import './DataGrid.css';
import { HeaderDnDContext, useHeaderDnD } from './useHeaderDnD.js';
export interface DataGridProps {
getHeaderHeight?: () => number;
export interface ICellPosition {
rowIdx: number;
colIdx: number;
}
export interface DataGridCellKeyboardEvent extends React.KeyboardEvent<HTMLDivElement> {
preventGridDefault: () => void;
isGridDefaultPrevented: () => boolean;
}
export interface DataGridProps extends IDataGridCellContext, IDataGridRowContext, IDataGridHeaderCellContext, React.PropsWithChildren {
getRowHeight?: (rowIdx: number) => number;
getHeaderText: (colIdx: number) => string;
getCellText: (rowIdx: number, colIdx: number) => string;
getColumnCount: () => number;
getRowCount: () => number;
subscribeToStore: (onStoreChange: () => void) => () => void;
getRowId?: (rowIdx: number) => React.Key;
columnCount: IGridReactiveValue<number, []>;
getColumnKey?: (colIdx: number) => string;
onScroll?: (event: React.UIEvent<HTMLDivElement>) => void;
onFocus?: (position: ICellPosition) => void;
onEditorOpen?: (position: ICellPosition) => void;
onCellKeyDown?: (position: ICellPosition, event: DataGridCellKeyboardEvent) => void;
className?: string;
}
export const DataGrid: React.FC<DataGridProps> = function DataGrid({
getHeaderText,
getCellText,
getColumnCount,
getRowCount,
getHeaderHeight,
getRowHeight,
subscribeToStore,
className,
}) {
// const store = useSyncExternalStore(subscribeToStore, () => {
// return {
// columns: getColumnCount(),
// rows: getRowCount(),
// };
// });
export interface DataGridRef {
selectCell: (position: ICellPosition) => void;
scrollToCell: (position: Partial<ICellPosition>) => void;
openEditor: (position: ICellPosition) => void;
}
const columns = new Array<ColumnOrColumnGroup<any, unknown>>(getColumnCount()).fill(null as any).map(
(_, i) =>
({
key: i + '',
name: getHeaderText(i),
renderCell: ({ rowIdx }) => getCellText(rowIdx, i),
}) as ColumnOrColumnGroup<any, unknown>,
export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid(
{
headerElement,
getHeaderWidth,
headerText,
getHeaderOrder,
getHeaderResizable,
columnSortable,
getHeaderHeight,
getHeaderPinned,
columnSortingState,
getHeaderDnD,
cell,
cellText,
cellElement,
cellTooltip,
getCellEditable,
columnCount,
getColumnKey,
rowCount,
getRowId,
getRowHeight,
onHeaderReorder,
onScroll,
onScrollToBottom,
onFocus,
onCellChange,
onColumnSort,
children,
className,
onCellKeyDown,
},
ref,
) {
const rowsCount = useGridReactiveValue(rowCount);
const columnsCount = useGridReactiveValue(columnCount);
const gridKey = useRef(0);
const rowsCountRef = useRef(rowsCount);
const innerGridRef = useRef<DataGridHandle>(null);
const columns = new Array<ColumnOrColumnGroup<IInnerRow, unknown>>(columnsCount)
.fill(null as any)
.map((_, i): ColumnOrColumnGroup<IInnerRow, unknown> => {
const width = getHeaderWidth?.(i) ?? 'max-content';
return {
key: getColumnKey?.(i) ?? String(i),
name: '',
resizable: getHeaderResizable?.(i) ?? true,
width,
minWidth: 26,
editable: row => getCellEditable?.(row.idx, i) ?? false,
frozen: getHeaderPinned?.(i),
renderHeaderCell: mapRenderHeaderCell(i),
renderCell: mapCellContentRenderer(i),
renderEditCell: mapEditCellRenderer(i),
};
});
const dndHeaderContext = useHeaderDnD({ columns, onReorder: onHeaderReorder, getCanDrag: getHeaderDnD, getHeaderOrder });
useImperativeHandle(ref, () => ({
selectCell: (position: ICellPosition) => {
innerGridRef.current?.selectCell({ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx });
},
scrollToCell: (position: Partial<ICellPosition>) => {
innerGridRef.current?.scrollToCell({ idx: position.colIdx && dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx });
},
openEditor: (position: ICellPosition) => {
innerGridRef.current?.selectCell({ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx }, true);
},
}));
if (rowsCountRef.current !== rowsCount) {
const previousRowCount = rowsCountRef.current;
rowsCountRef.current = rowsCount;
if (previousRowCount === 0) {
// we trigger columns size recalculation when rows are added
gridKey.current++;
}
}
const rows = useMemo(
() =>
new Array<IInnerRow>(rowsCount).fill({ idx: 0 }).map((_, i) => ({
idx: i,
})),
[rowsCount],
);
const rows = new Array(getRowCount()).fill({});
function handleCellFocus(args: CellSelectArgs<IInnerRow, unknown>) {
onFocus?.({ colIdx: dndHeaderContext.getDataColIdx(args.column.idx), rowIdx: args.rowIdx });
}
return <DataGridBase columns={columns} rows={rows} className={className} headerRowHeight={getHeaderHeight?.()} rowHeight={getRowHeight} />;
};
function handleCellKeyDown(args: CellSelectArgs<IInnerRow, unknown>, event: DataGridCellKeyboardEvent) {
onCellKeyDown?.({ colIdx: dndHeaderContext.getDataColIdx(args.column.idx), rowIdx: args.rowIdx }, event);
}
return (
<HeaderDnDContext value={dndHeaderContext}>
<DataGridRowContext value={{ rowCount, onScrollToBottom }}>
<DataGridCellContext value={{ cell, cellText, cellElement, cellTooltip, onCellChange }}>
<DataGridCellHeaderContext value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState }}>
<DataGridBase
key={gridKey.current}
ref={innerGridRef}
columns={dndHeaderContext.columns}
rows={rows}
className={className}
headerRowHeight={getHeaderHeight?.()}
onScroll={onScroll}
rowHeight={getRowHeight ? row => getRowHeight(row.idx) : undefined}
rowKeyGetter={getRowId ? row => getRowId(row.idx) : undefined}
onSelectedCellChange={handleCellFocus}
onCellKeyDown={handleCellKeyDown}
renderers={{
renderRow: rowRenderer,
renderCell: cellRenderer,
noRowsFallback: children,
}}
minimumRowsToRender={100}
/>
</DataGridCellHeaderContext>
</DataGridCellContext>
</DataGridRowContext>
</HeaderDnDContext>
);
});
@@ -0,0 +1,24 @@
import { createContext } from 'react';
import type { IGridReactiveValue } from './IGridReactiveValue.js';
export interface IDataGridCellProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
isFocused: boolean;
}
export interface IDataGridCellRenderer {
(propsOverride: Partial<IDataGridCellProps> & { [key: string]: any }): React.ReactNode;
}
export interface IDataGridCellContext {
cellElement?: IGridReactiveValue<
React.ReactNode,
[rowIdx: number, colIdx: number, props: IDataGridCellProps, renderDefaultCell: IDataGridCellRenderer]
>;
cell?: IGridReactiveValue<React.ReactNode, [rowIdx: number, colIdx: number]>;
cellText?: IGridReactiveValue<string, [rowIdx: number, colIdx: number]>;
cellTooltip?: IGridReactiveValue<string, [rowIdx: number, colIdx: number]>;
getCellEditable?: (rowIdx: number, colIdx: number) => boolean;
onCellChange?: (rowIdx: number, colIdx: number, value: any) => void;
}
export const DataGridCellContext = createContext<IDataGridCellContext | null>(null);
@@ -0,0 +1,7 @@
import { createContext } from 'react';
export interface IDataGridCellInnerContext {
isFocused: boolean;
}
export const DataGridCellInnerContext = createContext<IDataGridCellInnerContext | null>(null);
@@ -0,0 +1,19 @@
import { createContext } from 'react';
import type { IGridReactiveValue } from './IGridReactiveValue.js';
export interface IDataGridHeaderCellContext {
headerElement?: IGridReactiveValue<React.ReactNode, [colIdx: number]>;
headerText?: IGridReactiveValue<string, [colIdx: number]>;
getHeaderOrder?: () => number[];
getHeaderWidth?: (colIdx: number) => number | string | null;
getHeaderResizable?: (colIdx: number) => boolean;
getHeaderHeight?: () => number;
getHeaderPinned?: (colIdx: number) => boolean;
getHeaderDnD?: (colIdx: number) => boolean;
onHeaderReorder?: (from: number, to: number) => void;
columnSortingState?: IGridReactiveValue<'asc' | 'desc' | undefined | null, [colIdx: number]>;
columnSortable?: IGridReactiveValue<boolean, [colIdx: number]>;
onColumnSort?: (colIdx: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
}
export const DataGridCellHeaderContext = createContext<IDataGridHeaderCellContext | null>(null);
@@ -0,0 +1,9 @@
import { createContext } from 'react';
import type { IGridReactiveValue } from './IGridReactiveValue.js';
export interface IDataGridRowContext {
rowCount: IGridReactiveValue<number, []>;
onScrollToBottom?: () => void;
}
export const DataGridRowContext = createContext<IDataGridRowContext | null>(null);
@@ -0,0 +1,6 @@
export type IGridReactiveValueSubscribe<TArgs extends any[]> = (onValueChange: () => void, ...args: TArgs) => () => void;
export interface IGridReactiveValue<T, TArgs extends any[]> {
get(...args: TArgs): T;
subscribe: IGridReactiveValueSubscribe<TArgs>;
}
@@ -0,0 +1,3 @@
export interface IInnerRow {
idx: number;
}
@@ -0,0 +1,33 @@
:global(.rdg-cell) .editor {
appearance: none;
box-sizing: border-box;
min-height: initial;
inline-size: 100%;
block-size: 100%;
padding-block: 0;
padding-inline: 6px;
border: 2px solid #ccc;
vertical-align: top;
color: var(--rdg-color);
background-color: var(--rdg-background-color);
font: inherit;
font-family: inherit;
font-size: inherit;
line-height: inherit;
font-weight: inherit;
letter-spacing: inherit;
text-decoration: inherit;
text-transform: inherit;
&:focus {
border-color: var(--rdg-selection-color);
outline: none;
}
&::placeholder {
color: #999;
opacity: 1;
}
}
@@ -0,0 +1,39 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { use } from 'react';
import classes from './TextEditor.module.css';
import { DataGridCellContext } from '../DataGridCellContext.js';
import { useGridReactiveValue } from '../useGridReactiveValue.js';
function autoFocusAndSelect(input: HTMLInputElement | null) {
input?.focus();
input?.select();
}
export interface IProps {
rowIdx: number;
colIdx: number;
onClose: () => void;
}
export function TextEditor({ rowIdx, colIdx, onClose }: IProps) {
const cellContext = use(DataGridCellContext);
const value = useGridReactiveValue(cellContext?.cellText, rowIdx, colIdx) ?? '';
return (
<input
className={classes['editor']}
ref={autoFocusAndSelect}
value={value}
onChange={event => cellContext?.onCellChange?.(rowIdx, colIdx, event.target.value)}
onBlur={() => onClose()}
/>
);
}
@@ -0,0 +1,25 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { CellMouseEvent } from 'react-data-grid';
export function createCellMouseEvent<E extends React.MouseEvent<HTMLDivElement>>(event: E): CellMouseEvent {
let defaultPrevented = false;
const cellEvent = {
...event,
preventGridDefault() {
defaultPrevented = true;
},
isGridDefaultPrevented() {
return defaultPrevented;
},
};
Object.setPrototypeOf(cellEvent, Object.getPrototypeOf(event));
return cellEvent;
}
@@ -0,0 +1,14 @@
import { clsx } from '@dbeaver/ui-kit';
interface Props {
className?: string;
onClick?: React.MouseEventHandler<HTMLElement>;
}
export function BlobFormatter({ className, onClick }: Props) {
return (
<span className={clsx('tw:uppercase', className)} onClick={onClick}>
[blob]
</span>
);
}
@@ -0,0 +1,27 @@
import { NullFormatter } from './NullFormatter.js';
import { Checkbox, clsx, Focusable } from '@dbeaver/ui-kit';
interface Props {
value: boolean | null;
className?: string;
onClick?: React.MouseEventHandler<HTMLElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
}
export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props) {
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.code === 'Enter' || event.code === 'Space') {
event.preventDefault();
onKeyDown?.(event);
}
};
return (
<Focusable
className={clsx('tw:flex tw:items-center tw:outline-none tw:hover:cursor-pointer', className)}
onKeyDown={handleKeyDown}
onClick={onClick}
>
{value === null ? <NullFormatter /> : <Checkbox className="tw:data-disabled:opacity-100!" disabled size="small" checked={value} />}
</Focusable>
);
}
@@ -0,0 +1,21 @@
import { NullFormatter } from './NullFormatter.js';
interface Props {
value: Date | null;
type?: 'time' | 'date' | 'datetime';
onClick?: React.MouseEventHandler<HTMLElement>;
}
export function DateFormatter({ value, type = 'datetime', onClick }: Props) {
if (value === null) {
return <NullFormatter />;
}
return (
<div onClick={onClick}>
{value.toLocaleString(undefined, {
dateStyle: type === 'date' ? 'long' : undefined,
timeStyle: type === 'time' ? 'long' : undefined,
})}
</div>
);
}
@@ -0,0 +1,14 @@
import { clsx } from '@dbeaver/ui-kit';
interface Props {
className?: string;
onClick?: React.MouseEventHandler<HTMLElement>;
}
export function NullFormatter({ className, onClick }: Props) {
return (
<span className={clsx('tw:uppercase', 'tw:opacity-65', className)} onClick={onClick}>
[NULL]
</span>
);
}
@@ -0,0 +1,18 @@
import { NullFormatter } from './NullFormatter.js';
interface Props {
value: number | null;
className?: string;
onClick?: React.MouseEventHandler<HTMLElement>;
}
export function NumberFormatter({ value, className, onClick }: Props) {
if (value === null) {
return <NullFormatter className={className} onClick={onClick} />;
}
return (
<div style={{ textAlign: 'right' }} className={className} onClick={onClick}>
{value.toLocaleString()}
</div>
);
}
@@ -1 +1,13 @@
export * from './DataGrid.js';
export * from './DataGridCellContext.js';
export * from './DataGridCellInnerContext.js';
export * from './IGridReactiveValue.js';
export * from './useCreateGridReactiveValue.js';
export * from './useGridReactiveValue.js';
export * from './reorderArray.js';
export * from './formatters/NullFormatter.js';
export * from './formatters/BooleanFormatter.js';
export * from './formatters/NumberFormatter.js';
export * from './formatters/DateFormatter.js';
export * from './formatters/BlobFormatter.js';
@@ -0,0 +1,9 @@
import type { RenderCellProps } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { CellContentRenderer } from './renderers/CellContentRenderer.js';
export function mapCellContentRenderer(colIdx: number) {
return function RenderCell({ rowIdx }: RenderCellProps<IInnerRow, unknown>) {
return <CellContentRenderer rowIdx={rowIdx} colIdx={colIdx} />;
};
}
@@ -0,0 +1,9 @@
import type { RenderEditCellProps } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { TextEditor } from './editors/TextEditor.js';
export function mapEditCellRenderer(colIdx: number) {
return function RenderEditCell({ rowIdx, onClose }: RenderEditCellProps<IInnerRow, unknown>) {
return <TextEditor rowIdx={rowIdx} colIdx={colIdx} onClose={() => onClose()} />;
};
}
@@ -0,0 +1,9 @@
import type { RenderHeaderCellProps } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { HeaderCellContentRenderer } from './renderers/HeaderCellContentRenderer.js';
export function mapRenderHeaderCell(colIdx: number) {
return function RenderHeaderCell({ tabIndex }: RenderHeaderCellProps<IInnerRow, unknown>) {
return <HeaderCellContentRenderer colIdx={colIdx} tabIndex={tabIndex} />;
};
}
@@ -0,0 +1,13 @@
import { use } from 'react';
import { DataGridCellContext } from '../DataGridCellContext.js';
import { useGridReactiveValue } from '../useGridReactiveValue.js';
export interface Props {
rowIdx: number;
colIdx: number;
}
export function CellContentRenderer({ rowIdx, colIdx }: Props) {
const cellContext = use(DataGridCellContext);
return useGridReactiveValue(cellContext?.cell, rowIdx, colIdx);
}
@@ -0,0 +1,80 @@
import { memo, use, useRef } from 'react';
import { useDrag, useDrop, type DnDStoreProvider } from '@dbeaver/react-dnd';
import { DataGridCellHeaderContext } from '../DataGridHeaderCellContext.js';
import { useGridReactiveValue } from '../useGridReactiveValue.js';
import { HeaderDnDContext } from '../useHeaderDnD.js';
import { OrderButton } from './OrderButton.js';
interface Props {
colIdx: number;
tabIndex?: number;
}
export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer({ colIdx, tabIndex }: Props) {
const dndHeaderContext = use(HeaderDnDContext);
const cellHeaderContext = use(DataGridCellHeaderContext);
const headerElement = useGridReactiveValue(cellHeaderContext?.headerElement, colIdx);
const getHeaderText = useGridReactiveValue(headerElement ? undefined : cellHeaderContext?.headerText, colIdx);
const isColumnSortable = useGridReactiveValue(cellHeaderContext?.columnSortable, colIdx);
const onColumnSort = cellHeaderContext?.onColumnSort;
const sortingState = useGridReactiveValue(cellHeaderContext?.columnSortingState, colIdx);
const orderButtonRef = useRef<HTMLButtonElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const draggable = dndHeaderContext?.getCanDrag?.(colIdx) ?? false;
const drag = useDrag({
draggable,
onDragStart(event, store) {
if (dndHeaderContext?.id) {
store.setData('dbeaver-react-data-grid-id', dndHeaderContext?.id);
}
store.setData('dbeaver-react-data-grid-col-idx', colIdx);
},
onDragEnd() {
dndHeaderContext?.onDragEnd(colIdx);
},
});
function canDrop(event: React.DragEvent<HTMLElement>, store: DnDStoreProvider | null) {
const gridId = store?.getData('dbeaver-react-data-grid-id');
return gridId === dndHeaderContext?.id;
}
const drop = useDrop({
canDrop,
onDragOver(event, store) {
if (!canDrop(event, store)) {
return;
}
const dragColIdx = store?.getData('dbeaver-react-data-grid-col-idx');
const position = event.clientX - event.currentTarget.getBoundingClientRect().left;
const width = event.currentTarget.offsetWidth;
const isAfter = position > width / 2;
dndHeaderContext?.onDragOver(dragColIdx, colIdx, isAfter);
},
});
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Tab' && !e.shiftKey && isColumnSortable && onColumnSort && orderButtonRef.current !== document.activeElement) {
e.preventDefault();
e.stopPropagation();
containerRef.current?.parentElement?.setAttribute('aria-selected', 'false');
orderButtonRef.current?.focus();
}
};
return (
<div
ref={containerRef}
tabIndex={tabIndex}
onKeyDown={handleKeyDown}
className="tw:w-full tw:h-full tw:content-center tw:flex tw:items-center tw:justify-between tw:gap-1 tw:outline-none tw:group"
{...drag.props}
{...drop.props}
>
<span className="tw:overflow-hidden tw:text-ellipsis">{headerElement ?? getHeaderText ?? ''}</span>
{isColumnSortable && onColumnSort && <OrderButton ref={orderButtonRef} colIdx={colIdx} sortState={sortingState} onSort={onColumnSort} />}
</div>
);
});
@@ -0,0 +1,42 @@
import { clsx, IconButton } from '@dbeaver/ui-kit';
interface OrderButtonProps {
colIdx: number;
sortState?: 'asc' | 'desc' | null;
onSort: (attributePosition: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
tabIndex?: number;
ref: React.Ref<HTMLButtonElement>;
}
export function OrderButton({ colIdx, sortState, onSort, tabIndex, ref }: OrderButtonProps) {
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
const nextSortState = sortState === 'asc' ? 'desc' : sortState === 'desc' ? null : 'asc';
onSort(colIdx, nextSortState, e.ctrlKey || e.metaKey);
}
const svgSortAsc = '#icon-sort-asc';
const svgSortDesc = '#icon-sort-desc';
const svgSortUnknown = '#icon-sort-unknown';
const iconSrc = sortState === 'asc' ? svgSortAsc : sortState === 'desc' ? svgSortDesc : svgSortUnknown;
return (
<IconButton
variant="secondary"
size="small"
onClick={handleClick}
tabIndex={tabIndex}
ref={ref}
title="Sort by column"
aria-label="Sort by column"
className={clsx(
'tw:opacity-0 tw:group-focus:opacity-100 tw:focus:opacity-100 tw:group-hover:opacity-100 tw:hover:opacity-100 tw:outline-offset-0',
sortState && 'tw:opacity-100',
)}
>
<svg width="16" height="16" viewBox="0 0 16 16">
<use href={iconSrc} />
</svg>
</IconButton>
);
}
@@ -0,0 +1,6 @@
import type { CellRendererProps } from 'react-data-grid';
import { BaseCell } from '../BaseCell.js';
export function cellRenderer<TRow, TSummaryRow>(key: React.Key, props: CellRendererProps<TRow, TSummaryRow>) {
return <BaseCell key={key} {...props} />;
}
@@ -0,0 +1,6 @@
import type { RenderRowProps } from 'react-data-grid';
import { BaseRow } from '../BaseRow.js';
export function rowRenderer<TRow, TSummaryRow>(key: React.Key, props: RenderRowProps<TRow, TSummaryRow>) {
return <BaseRow key={key} {...props} />;
}
@@ -0,0 +1,11 @@
export function reorderArray<T>(array: T[], from: number, to: number): T[] {
const newArray = [...array];
if (from < to) {
newArray.splice(to, 0, array[from]!);
newArray.splice(from, 1);
} else {
newArray.splice(from, 1);
newArray.splice(to, 0, array[from]!);
}
return newArray;
}
@@ -0,0 +1,19 @@
import { useMemo } from 'react';
import type { IGridReactiveValue, IGridReactiveValueSubscribe } from './IGridReactiveValue.js';
type NoInfer<T> = intrinsic;
export function useCreateGridReactiveValue<T, TArgs extends any[]>(
get: (...args: TArgs) => T,
subscribe: NoInfer<IGridReactiveValueSubscribe<TArgs>> | null,
deps: React.DependencyList,
): IGridReactiveValue<T, TArgs> {
const value = useMemo<IGridReactiveValue<T, TArgs>>(
() => ({
get,
subscribe: subscribe ?? (() => () => {}),
}),
deps,
);
return value;
}
@@ -0,0 +1,36 @@
import { useMemo, useSyncExternalStore } from 'react';
import type { IGridReactiveValue } from './IGridReactiveValue.js';
export function useGridReactiveValue<P extends IGridReactiveValue<any, any[]> | undefined>(
value: P,
...args: P extends IGridReactiveValue<any, infer T> ? T : never[]
): P extends IGridReactiveValue<infer T, any[]> ? T : undefined {
const mappedValue = useMemo(
() => ({
cache: null as any,
cacheInvalidated: true,
subscribe: (onValueChange: () => void) => {
if (value) {
return value.subscribe(
() => {
mappedValue.cacheInvalidated = true;
return onValueChange();
},
...args,
);
}
return () => {};
},
get: () => {
if (mappedValue.cacheInvalidated) {
mappedValue.cache = value?.get(...args);
mappedValue.cacheInvalidated = false;
}
return mappedValue.cache;
},
}),
[value, ...args],
);
return useSyncExternalStore(mappedValue.subscribe, mappedValue.get);
}
@@ -0,0 +1,94 @@
import type { ColumnOrColumnGroup } from 'react-data-grid';
import type { IInnerRow } from './IInnerRow.js';
import { createContext, useId, useMemo, useState } from 'react';
import { reorderArray } from './reorderArray.js';
interface IHeaderDnDOptions {
columns: Array<ColumnOrColumnGroup<IInnerRow, unknown>>;
getCanDrag?: (colIdx: number) => boolean;
onReorder?: (from: number, to: number) => void;
getHeaderOrder?: () => number[];
}
interface IHeaderDnD {
id: string;
columns: Array<ColumnOrColumnGroup<IInnerRow, unknown>>;
getDataColIdx: (virtualColIdx: number) => number;
getVirtualColIdx: (dataColIdx: number) => number;
getCanDrag?: (colIdx: number) => boolean;
onDragOver: (dragColIdx: number, dropColIdx: number, isAfter: boolean) => void;
onDragEnd: (colIdx: number) => void;
}
export const HeaderDnDContext = createContext<IHeaderDnD | null>(null);
export function useHeaderDnD({ columns, getCanDrag, onReorder, getHeaderOrder }: IHeaderDnDOptions): IHeaderDnD {
const id = useId();
const [activeDnDElement, setActiveDnDElement] = useState<number | null>(null);
const [dragOverElement, setDragOverElement] = useState<[number, boolean] | null>(null);
function getDataColIdx(virtualColIdx: number) {
// Given a visible (ordered) column index, return the original data column index
const order = getHeaderOrder?.();
if (order) {
return order[virtualColIdx] ?? virtualColIdx;
}
return virtualColIdx;
}
function getVirtualColIdx(dataColIdx: number) {
// Given the original data column index, return its visible (ordered) index
const order = getHeaderOrder?.();
if (order) {
return order.indexOf(dataColIdx);
}
return dataColIdx;
}
function onDragEnd(dragColIdx: number) {
setActiveDnDElement(null);
setDragOverElement(null);
if (dragOverElement) {
const isAfter = dragOverElement?.[1];
let to = dragOverElement?.[0];
if (isAfter) {
to = getDataColIdx(getVirtualColIdx(to) + 1);
}
onReorder?.(dragColIdx, to);
}
}
function onDragOver(dragColIdx: number, dropColIdx: number, isAfter: boolean) {
setActiveDnDElement(dragColIdx);
if (dragColIdx !== dropColIdx) {
setDragOverElement([dropColIdx, isAfter]);
}
}
columns = useMemo(() => columns.map((col, idx) => columns[getDataColIdx(idx)]!), [columns, getHeaderOrder]);
if (activeDnDElement !== null && dragOverElement !== null) {
const from = getVirtualColIdx(activeDnDElement);
let to = getVirtualColIdx(dragOverElement[0]);
const isAfter = dragOverElement[1];
if (isAfter) {
to++;
}
columns = reorderArray(columns, from, to);
}
return {
id,
columns,
getDataColIdx,
getVirtualColIdx,
getCanDrag,
onDragOver,
onDragEnd,
};
}
@@ -12,5 +12,13 @@
},
"include": [
"src"
],
"references": [
{
"path": "../react-dnd"
},
{
"path": "../ui-kit"
}
]
}
@@ -0,0 +1 @@
# @dbeaver/react-dnd
@@ -0,0 +1,36 @@
{
"name": "@dbeaver/react-dnd",
"type": "module",
"sideEffects": [],
"exports": {
".": "./lib/index.js",
"./*": "./lib/*.js"
},
"scripts": {
"clear": "rimraf lib"
},
"files": [
"package.json",
"LICENSE",
"README.md",
"CHANGELOG.md",
"lib",
"!lib/**/*.d.ts.map",
"!lib/**/*.test.js",
"!lib/**/*.test.d.ts",
"!lib/**/*.test.d.ts.map",
"!lib/**/*.test.js.map",
"!lib/tests",
"!.tsbuildinfo"
],
"packageManager": "yarn@4.6.0",
"devDependencies": {
"@dbeaver/tsconfig": "workspace:^",
"@types/react": "^19",
"rimraf": "^6",
"typescript": "^5"
},
"dependencies": {
"react": "^19"
}
}
@@ -0,0 +1,3 @@
export * from './useDrag.js';
export * from './useDrop.js';
export { type DnDStoreProvider } from './store.js';
@@ -0,0 +1,46 @@
export const DND_STORE_PREFIX = 'application/dbeaver-react-dnd-';
export interface DnDStoreProvider {
getData: (key: string) => any;
setData: (key: string, value: any) => void;
removeData: () => void;
}
class DnDStore {
private data: Map<string, Record<string, any>> = new Map();
setData(id: string, key: string, value: any) {
if (!this.data.has(id)) {
this.data.set(id, {});
}
this.data.get(id)![key] = value;
}
getData(id: string, key: string) {
return this.data.get(id)?.[key];
}
removeData(id: string) {
this.data.delete(id);
}
getProvider(id: string) {
return {
getData: (key: string) => this.getData(id, key),
setData: (key: string, value: any) => {
this.setData(id, key, value);
},
removeData: () => {
this.removeData(id);
},
};
}
}
export function getStoreProvider(event: React.DragEvent<HTMLElement>): DnDStoreProvider | null {
const id = event.dataTransfer.types.find(type => type.startsWith(DND_STORE_PREFIX))?.slice(DND_STORE_PREFIX.length);
return id ? globalDnDStore.getProvider(id) : null;
}
// TODO: do we want to use react context here?
// the main idea was to use native DataTransfer, but it's available only for drag start and drop events
// so we need to use a custom store
export const globalDnDStore = new DnDStore();
@@ -0,0 +1,67 @@
import { useId, useMemo, useRef, useState } from 'react';
import { DND_STORE_PREFIX, globalDnDStore, type DnDStoreProvider } from './store.js';
interface IDragOptions {
draggable?: boolean;
onDrag?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider) => void;
onDragStart?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider) => void;
onDragEnd?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider) => void;
}
interface IDrag {
isDragging: boolean;
props: {
draggable?: boolean;
onDrag: (event: React.DragEvent<HTMLElement>) => void;
onDragStart: (event: React.DragEvent<HTMLElement>) => void;
onDragEnd: (event: React.DragEvent<HTMLElement>) => void;
};
}
export function useDrag({ draggable, onDragStart, onDrag, onDragEnd }: IDragOptions = {}): IDrag {
const id = useId();
const [dragging, setDragging] = useState(false);
const optionsRef = useRef<IDragOptions>({ draggable, onDragStart, onDrag, onDragEnd });
optionsRef.current = { draggable, onDragStart, onDrag, onDragEnd };
function handleDragStart(event: React.DragEvent<HTMLElement>) {
if (!optionsRef.current.draggable) {
return;
}
event.stopPropagation();
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData(`${DND_STORE_PREFIX}${id}`, id);
setDragging(true);
optionsRef.current.onDragStart?.(event, globalDnDStore.getProvider(id));
}
function handleDrag(event: React.DragEvent<HTMLElement>) {
if (!optionsRef.current.draggable) {
return;
}
optionsRef.current.onDrag?.(event, globalDnDStore.getProvider(id));
}
function handleDragEnd(event: React.DragEvent<HTMLElement>) {
if (!optionsRef.current.draggable) {
return;
}
setDragging(false);
optionsRef.current.onDragEnd?.(event, globalDnDStore.getProvider(id));
globalDnDStore.removeData(id);
}
return {
isDragging: dragging,
props: {
draggable,
...useMemo(
() => ({
onDrag: handleDrag,
onDragStart: handleDragStart,
onDragEnd: handleDragEnd,
}),
[],
),
},
};
}
@@ -0,0 +1,61 @@
import { useMemo, useRef } from 'react';
import { getStoreProvider, type DnDStoreProvider } from './store.js';
interface IDropOptions {
canDrop?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => boolean;
onDrop?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
onDragOver?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
onDragEnter?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
onDragLeave?: (event: React.DragEvent<HTMLElement>, provider: DnDStoreProvider | null) => void;
}
interface IDrop {
props: {
onDrop: (event: React.DragEvent<HTMLElement>) => void;
onDragOver: (event: React.DragEvent<HTMLElement>) => void;
onDragEnter: (event: React.DragEvent<HTMLElement>) => void;
onDragLeave: (event: React.DragEvent<HTMLElement>) => void;
};
}
export function useDrop({ canDrop, onDrop, onDragOver, onDragEnter, onDragLeave }: IDropOptions = {}): IDrop {
const optionsRef = useRef<IDropOptions>({ canDrop, onDrop, onDragOver, onDragEnter, onDragLeave });
optionsRef.current = { canDrop, onDrop, onDragOver, onDragEnter, onDragLeave };
function handleOver(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
const isDroppable = optionsRef.current.canDrop?.(event, provider);
if (isDroppable) {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
} else {
event.dataTransfer.dropEffect = 'none';
}
optionsRef.current.onDragOver?.(event, provider);
}
function handleEnter(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
optionsRef.current.onDragEnter?.(event, provider);
}
function handleLeave(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
optionsRef.current.onDragLeave?.(event, provider);
}
function handleDrop(event: React.DragEvent<HTMLElement>) {
const provider = getStoreProvider(event);
optionsRef.current.onDrop?.(event, provider);
}
return {
props: useMemo(
() => ({
onDrop: handleDrop,
onDragOver: handleOver,
onDragEnter: handleEnter,
onDragLeave: handleLeave,
}),
[],
),
};
}
@@ -0,0 +1,16 @@
{
"extends": "@dbeaver/tsconfig/tsconfig.webview.json",
"compilerOptions": {
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"rootDirs": [
"src"
],
"outDir": "lib",
"incremental": true,
"composite": true
},
"include": [
"src"
]
}
@@ -1,12 +1,15 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
!lib/
!lib/lib
/lib
# misc
.DS_Store
@@ -16,3 +19,5 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
tsconfig.tsbuildinfo
@@ -0,0 +1,2 @@
import '../src/index.css';
import './global.css';
@@ -0,0 +1,8 @@
/** @type {import('@ladle/react').UserConfig} */
export default {
addons: {
a11y: {
enabled: true,
},
},
};
@@ -0,0 +1,132 @@
@import 'tailwindcss' layer(base) prefix(tw);
@layer theme {
main {
color: var(--dbv-kit-color-foreground);
background-color: var(--tw-color-gray-50);
}
a {
color: var(--tw-color-blue-600);
text-decoration: underline;
&:hover {
color: var(--tw-color-blue-700);
text-decoration-thickness: 2px;
}
}
code {
color: var(--tw-color-orange-700);
}
h1,
h2,
h3,
h3,
h5 {
font-weight: var(--tw-font-weight-semibold);
margin-block-start: 1em;
margin-block-end: 0.5em;
}
h1 {
font-size: var(--tw-text-2xl);
}
h2 {
font-size: var(--tw-text-xl);
}
h3 {
font-size: var(--tw-text-lg);
}
p {
font-size: var(--tw-text-base);
margin-block-start: 0.5em;
margin-block-end: 0.5em;
}
kbd {
background-color: #eee;
border-radius: 3px;
border: 1px solid #b4b4b4;
box-shadow:
0 1px 1px rgba(0, 0, 0, 0.2),
0 2px 0 0 rgba(255, 255, 255, 0.7) inset;
color: #333;
display: inline-block;
font-size: 0.85em;
font-weight: 700;
line-height: 1;
padding: 2px 4px;
white-space: nowrap;
}
.codeblock {
background-color: var(--tw-color-gray-100);
padding: 1em;
border-radius: 0.25em;
margin-block-start: 1em;
margin-block-end: 1em;
}
.comment {
color: var(--tw-color-gray-500);
}
.color-sample {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 0.25em;
}
}
:root[data-theme='dark'] {
--dbv-kit-color-foreground: var(--tw-color-gray-200);
--dbv-kit-color-background: var(--tw-color-gray-900);
--dbv-kit-btn-loader-base-color: var(--tw-color-gray-900);
/* Primary Button */
--dbv-kit-btn-primary-foreground: var(--tw-color-gray-100);
--dbv-kit-btn-primary-background: var(--dbv-kit-color-primary-700);
--dbv-kit-btn-primary-background-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-primary-background-active: var(--dbv-kit-color-primary-500);
/* Secondary Button */
--dbv-kit-btn-secondary-foreground: var(--tw-color-gray-100);
--dbv-kit-btn-secondary-background: transparent;
--dbv-kit-btn-secondary-background-hover: var(--tw-color-gray-800);
--dbv-kit-btn-secondary-background-active: var(--tw-color-gray-700);
--dbv-kit-btn-secondary-border-color: var(--tw-color-gray-200);
/* Danger Button */
--dbv-kit-btn-danger-foreground: var(--tw-color-gray-100);
--dbv-kit-btn-danger-background: var(--tw-color-red-700);
--dbv-kit-btn-danger-background-hover: var(--tw-color-red-600);
--dbv-kit-btn-danger-background-active: var(--tw-color-red-500);
/* Input */
--dbv-kit-input-background: var(--tw-color-gray-800);
--dbv-kit-input-border-color: var(--tw-color-gray-700);
--dbv-kit-input-color: var(--tw-color-gray-100);
--dbv-kit-input-placeholder-foreground: var(--tw-color-gray-400);
main {
background-color: var(--tw-color-gray-900);
}
code {
color: var(--tw-color-orange-400);
}
a {
color: var(--tw-color-blue-300);
}
.codeblock {
background-color: var(--tw-color-gray-800);
}
}
+63
View File
@@ -0,0 +1,63 @@
# DBeaver UI Kit
#### The DBeaver UI Kit is a collection of reusable React components designed to help developers build consistent and visually appealing user interfaces.
## Using Ladle for Component Development
[Ladle](https://ladle.dev/) is a tool that allows you to develop, test, and document your React components in isolation. We use it to create a sandbox environment where you can interact with your components and ensure they work as expected.
To get started with Ladle in the DBeaver UI Kit, write in terminal:
```bash
yarn docs
```
Then open the provided URL to see components.
## How to Customize
DBeaver UI Kit components have basic styles and use some defaults from Tailwind CSS. To change styling, you can use different approaches.
### Global CSS Tokens
The UI kit uses several global CSS tokens described on the Global Tokens page. These tokens help maintain consistency across the UI components. All DBeaver UI tokens are prefixed with `--dbv-kit-`. You can use these tokens to customize the UI kit to fit your application's design. For example, changing the `--dbv-kit-font-size-base` token will change the base font size for text in the UI kit. Changing the `--dbv-kit-control-height-base` token will change all control heights. If you don't want to change all controls, you can change `--dbv-kit-control-height-small`, `--dbv-kit-control-height-medium`, or other tokens separately. They will affect only specific components.
### Component CSS Tokens
Some components have their own tokens. For example, the Button component has tokens for button sizes, padding, and colors. You can change these tokens to customize the Button component. To see the list of tokens, go to sources or start Ladle.
### Component CSS Classes
Each component in the UI kit has a default CSS class name following the `dbv-kit-[component name(in lowercase)]` naming convention that you can use to customize the component. You can find the default class name in the component's documentation.
For button:
```css
.dbv-kit-button {
/* Your custom styles */
}
```
For input:
```css
.dbv-kit-input {
/* Your custom styles */
}
```
Some components have additional classes for different states or sizes. For example, the Button component has classes for different sizes: `.dbv-kit-button--small`, `.dbv-kit-button--large`. We use the BEM convention for class names. If a component has a modifier, it will be separated by two dashes. If a component has a child element, it will be separated by two underscores, for example:
- `.dbv-kit-button__icon` - icon is a child element of the button
- `.dbv-kit-button--large` - large is a size modifier
- `.dbv-kit-button__icon--start` - icon is a child element of the button and has a start placement
Each component accepts the standard `className` and `style` props which enable using vanilla CSS, utility classes (e.g., Tailwind), CSS-in-JS (e.g., Styled Components), etc. A custom `className` can be specified and will be appended to a class list of a component:
```jsx
<Button className="my-custom-button">Button</Button>
```
```jsx
<Button style={{ background: 'red' }}>Button</Button>
```
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor">
<polygon points="2 10 12 10 7 4 2 10" />
<rect x="6" y="6" width="2" height="22" />
<rect x="14" y="6" width="16" height="2" />
<rect x="14" y="15" width="12" height="2" />
<rect x="14" y="24" width="8" height="2" />
</svg>

After

Width:  |  Height:  |  Size: 353 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<polygon points="2 8.14 9.14 8.14 5.57 3.86 2 8.14" />
<rect x="4.86" y="5.29" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</svg>

After

Width:  |  Height:  |  Size: 414 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<polygon points="0 4 5 4 2.5 1 0 4" />
<rect x="2" y="4" width="1" height="11" />
<rect x="6" y="3" width="10" height="1" />
<rect x="6" y="8" width="7" height="1" />
<rect x="6" y="13" width="4" height="1" />
</svg>

After

Width:  |  Height:  |  Size: 346 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor">
<polygon points="12 22 2 22 7 28 12 22" />
<rect x="6" y="4" width="2" height="22" />
<rect x="14" y="6" width="16" height="2" />
<rect x="14" y="15" width="12" height="2" />
<rect x="14" y="24" width="8" height="2" />
</svg>

After

Width:  |  Height:  |  Size: 355 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<polygon points="9.14 16.71 2 16.71 5.57 21 9.14 16.71" />
<rect x="4.86" y="3.86" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</svg>

After

Width:  |  Height:  |  Size: 418 B

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<polygon points="5 12 0 12 2.5 15 5 12" />
<rect x="2" y="1" width="1" height="12" />
<rect x="6" y="3" width="10" height="1" />
<rect x="6" y="8" width="7" height="1" />
<rect x="6" y="13" width="4" height="1" />
</svg>

After

Width:  |  Height:  |  Size: 350 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor">
<polygon points="4 10 14 10 9 4 4 10" />
<rect x="8" y="6" width="2" height="22" />
<polygon points="28 22 18 22 23 28 28 22" />
<rect x="22" y="4" width="2" height="22" />
</svg>

After

Width:  |  Height:  |  Size: 307 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<polygon points="3.4 8.29 10.55 8.29 6.98 4 3.4 8.29" />
<rect x="6.26" y="5.43" width="1.43" height="15.71" />
<polygon points="20.55 16.86 13.4 16.86 16.98 21.14 20.55 16.86" />
<rect x="16.26" y="4" width="1.43" height="15.71" />
</svg>

After

Width:  |  Height:  |  Size: 367 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<polygon points="2 4 7 4 4.5 1 2 4" />
<rect x="4" y="4" width="1" height="11" />
<polygon points="14 12 9 12 11.5 15 14 12" />
<rect x="11" y="1" width="1" height="11" />
</svg>

After

Width:  |  Height:  |  Size: 306 B

@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-sort-unknown" viewBox="0 0 24 24" fill="currentColor">
<polygon points="3.4 8.29 10.55 8.29 6.98 4 3.4 8.29" />
<rect x="6.26" y="5.43" width="1.43" height="15.71" />
<polygon points="20.55 16.86 13.4 16.86 16.98 21.14 20.55 16.86" />
<rect x="16.26" y="4" width="1.43" height="15.71" />
</symbol>
<symbol id="icon-sort-desc" viewBox="0 0 24 24"
fill="currentColor">
<polygon points="9.14 16.71 2 16.71 5.57 21 9.14 16.71" />
<rect x="4.86" y="3.86" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</symbol>
<symbol id="icon-sort-asc" viewBox="0 0 24 24" fill="currentColor">
<polygon points="2 8.14 9.14 8.14 5.57 3.86 2 8.14" />
<rect x="4.86" y="5.29" width="1.43" height="15.71" />
<rect x="10.57" y="5.29" width="11.43" height="1.43" />
<rect x="10.57" y="11.71" width="8.57" height="1.43" />
<rect x="10.57" y="18.14" width="5.71" height="1.43" />
</symbol>
<symbol id="icon-cross" viewBox="0 0 24 24">
<path xmlns="http://www.w3.org/2000/svg" fill="currentColor" fill-rule="evenodd"
clip-rule="evenodd"
d="M3.31579 3.31579C2.89474 3.73684 2.89474 4.42105 3.31579 4.84211L10.4737 12L3.31579 19.1579C2.89474 19.5789 2.89474 20.2632 3.31579 20.6842C3.73684 21.1053 4.42105 21.1053 4.84211 20.6842L12 13.5263L19.1579 20.6842C19.5789 21.1053 20.2632 21.1053 20.6842 20.6842C21.1053 20.2632 21.1053 19.5789 20.6842 19.1579L13.5263 12L20.6842 4.84211C21.1053 4.42105 21.1053 3.73684 20.6842 3.31579C20.2632 2.89474 19.5789 2.89474 19.1579 3.31579L12 10.4737L4.84211 3.31579C4.42105 2.89474 3.73684 2.89474 3.31579 3.31579Z" />
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

+38
View File
@@ -0,0 +1,38 @@
{
"name": "@dbeaver/ui-kit",
"type": "module",
"version": "0.1.0",
"description": "",
"license": "Apache-2.0",
"exports": {
".": "./lib/index.js",
"./*.css": "./src/*.css",
"./*": "./lib/*.js",
"./assets/icons/*.svg": "./assets/icons/*.svg"
},
"scripts": {
"build": "tsc -b",
"docs": "ladle serve",
"clean": "rimraf --glob lib"
},
"packageManager": "yarn@4.6.0",
"devDependencies": {
"@dbeaver/tsconfig": "workspace:^",
"@ladle/react": "^5",
"@tailwindcss/vite": "4.0.7",
"@types/react": "^19",
"@types/react-dom": "^19",
"@wroud/vite-plugin-asset-resolver": "^0",
"@wroud/vite-plugin-tsc": "^0.11.6",
"rimraf": "^6",
"tailwindcss": "4.0.7",
"typescript": "^5",
"vite": "^6"
},
"dependencies": {
"@ariakit/react": "^0",
"clsx": "^2",
"react": "^19",
"react-dom": "^19"
}
}
@@ -0,0 +1,16 @@
export default function template(files) {
const exportLines = files.map((file) => {
const { path } = file;
const fileName = path.split('/').pop();
const componentNameWithExt = fileName.replace(/\.tsx$/, '.js');
const componentName = fileName.replace(/\.tsx$/, '');
return `export { default as ${componentName} } from './${componentNameWithExt}';`;
});
const header = '/* This file is automatically generated by the build:icons script. Do not modify it manually.*/\n\n ';
return header + exportLines.join('\n');
};
@@ -0,0 +1,176 @@
@import './_base.css';
@import './_sizes.css';
@import './_variants.css';
@layer base {
.dbv-kit-button {
height: var(--dbv-kit-btn-height);
padding-inline: var(--dbv-kit-btn-padding-inline);
background-color: var(--dbv-kit-btn-background);
color: var(--dbv-kit-btn-foreground);
border-radius: var(--dbv-kit-btn-border-radius);
border-width: var(--dbv-kit-btn-border-width);
border-color: var(--dbv-kit-btn-border-color);
border-style: var(--dbv-kit-btn-border-style);
font-size: var(--dbv-kit-btn-font-size);
font-weight: var(--dbv-kit-btn-font-weight);
cursor: pointer;
&:focus-visible,
&[data-focus-visible] {
outline: var(--dbv-kit-control-outline-width) solid var(--dbv-kit-btn-outline-color);
outline-offset: var(--dbv-kit-btn-outline-offset);
}
&:hover {
@media (hover: hover) {
color: var(--dbv-kit-btn-foreground-hover);
background-color: var(--dbv-kit-btn-background-hover);
}
}
&:active,
&[data-active] {
color: var(--dbv-kit-btn-foreground-active);
background-color: var(--dbv-kit-btn-background-active);
}
}
/* ---------------------------- */
/* Sizes */
.dbv-kit-button--small {
--dbv-kit-btn-padding-inline: var(--dbv-kit-btn-small-padding-inline);
--dbv-kit-btn-font-size: var(--dbv-kit-btn-small-font-size);
--dbv-kit-btn-height: var(--dbv-kit-btn-small-height);
--dbv-kit-btn-gap: var(--dbv-kit-btn-small-gap);
--dbv-kit-btn-icon-margin-inline: calc(var(--dbv-kit-btn-small-padding-inline) * -0.25);
}
.dbv-kit-button--medium {
--dbv-kit-btn-padding-inline: var(--dbv-kit-btn-medium-padding-inline);
--dbv-kit-btn-font-size: var(--dbv-kit-btn-medium-font-size);
--dbv-kit-btn-height: var(--dbv-kit-btn-medium-height);
--dbv-kit-btn-gap: var(--dbv-kit-btn-medium-gap);
--dbv-kit-btn-icon-margin-inline: calc(var(--dbv-kit-btn-medium-padding-inline) * -0.25);
}
.dbv-kit-button--large {
--dbv-kit-btn-padding-inline: var(--dbv-kit-btn-large-padding-inline);
--dbv-kit-btn-font-size: var(--dbv-kit-btn-large-font-size);
--dbv-kit-btn-height: var(--dbv-kit-btn-large-height);
--dbv-kit-btn-gap: var(--dbv-kit-btn-large-gap);
--dbv-kit-btn-icon-margin-inline: calc(var(--dbv-kit-btn-large-padding-inline) * -0.25);
}
.dbv-kit-button--xlarge {
--dbv-kit-btn-padding-inline: var(--dbv-kit-btn-xlarge-padding-inline);
--dbv-kit-btn-font-size: var(--dbv-kit-btn-xlarge-font-size);
--dbv-kit-btn-height: var(--dbv-kit-btn-xlarge-height);
--dbv-kit-btn-gap: var(--dbv-kit-btn-xlarge-gap);
--dbv-kit-btn-icon-margin-inline: calc(var(--dbv-kit-btn-xlarge-padding-inline) * -0.25);
}
/* ---------------------------- */
/* Variants */
.dbv-kit-button--primary {
--dbv-kit-btn-foreground: var(--dbv-kit-btn-primary-foreground);
--dbv-kit-btn-foreground-hover: var(--dbv-kit-btn-primary-foreground-hover);
--dbv-kit-btn-foreground-active: var(--dbv-kit-btn-primary-foreground-active);
--dbv-kit-btn-background: var(--dbv-kit-btn-primary-background);
--dbv-kit-btn-background-hover: var(--dbv-kit-btn-primary-background-hover);
--dbv-kit-btn-background-active: var(--dbv-kit-btn-primary-background-active);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-primary-foreground);
&:disabled {
background-color: var(--dbv-kit-control-disabled-background);
color: var(--dbv-kit-control-disabled-foreground);
}
}
.dbv-kit-button--secondary {
--dbv-kit-btn-foreground: var(--dbv-kit-btn-secondary-foreground);
--dbv-kit-btn-foreground-hover: var(--dbv-kit-btn-secondary-foreground-hover);
--dbv-kit-btn-foreground-active: var(--dbv-kit-btn-secondary-foreground-active);
--dbv-kit-btn-background: var(--dbv-kit-btn-secondary-background);
--dbv-kit-btn-background-hover: var(--dbv-kit-btn-secondary-background-hover);
--dbv-kit-btn-background-active: var(--dbv-kit-btn-secondary-background-active);
--dbv-kit-btn-border-color: var(--dbv-kit-btn-secondary-border-color);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-secondary-foreground);
&:disabled {
color: var(--dbv-kit-control-disabled-foreground);
border-color: var(--dbv-kit-control-disabled-foreground);
}
}
.dbv-kit-button--danger {
--dbv-kit-btn-foreground: var(--dbv-kit-btn-danger-foreground);
--dbv-kit-btn-foreground-hover: var(--dbv-kit-btn-danger-foreground);
--dbv-kit-btn-foreground-active: var(--dbv-kit-btn-danger-foreground-active);
--dbv-kit-btn-background: var(--dbv-kit-btn-danger-background);
--dbv-kit-btn-background-hover: var(--dbv-kit-btn-danger-background-hover);
--dbv-kit-btn-background-active: var(--dbv-kit-btn-danger-background-active);
--dbv-kit-btn-border-color: var(--dbv-kit-btn-danger-border-color);
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-danger-foreground);
--dbv-kit-btn-outline-color: var(--dbv-kit-btn-danger-color-outline);
&:disabled {
background-color: var(--dbv-kit-control-disabled-background);
color: var(--dbv-kit-control-disabled-foreground);
}
}
/* ---------------------------- */
/* Loader */
.dbv-kit-button[data-loading='true'] {
background-color: var(--dbv-kit-btn-background-hover);
&:hover,
&:active,
&[data-active] {
background-color: var(--dbv-kit-btn-background-active);
}
}
.dbv-kit-button .dbv-kit-spinner {
--dbv-kit-spinner-stroke-color: var(--dbv-kit-btn-loader-color);
--dbv-kit-spinner-height: calc(var(--dbv-kit-btn-height) * 0.6);
--dbv-kit-spinner-stroke-width: 3px;
}
/* ---------------------------- */
/* Icon */
.dbv-kit-button__icon {
display: flex;
align-items: center;
justify-content: center;
fill: currentColor;
}
.dbv-kit-button__icon--start {
margin-inline-start: var(--dbv-kit-btn-icon-margin-inline);
}
.dbv-kit-button__icon--end {
margin-inline-end: var(--dbv-kit-btn-icon-margin-inline);
}
}
@@ -0,0 +1,39 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import clsx from 'clsx';
import type { ControlSize } from '../types/controls.js';
import { componentProviderWrapper } from '../componentProviderWrapper.js';
import { ButtonRoot, type ButtonRootProps } from './ButtonRoot.js';
import './Button.css';
export interface ButtonProps extends ButtonRootProps {
variant?: 'primary' | 'secondary' | 'danger';
size?: ControlSize;
}
export function ButtonBase({ className, variant = 'primary', size = 'medium', ...props }: ButtonProps) {
const classToApply = clsx('dbv-kit-button', `dbv-kit-button--${variant}`, `dbv-kit-button--${size}`, className);
return <ButtonRoot className={classToApply} {...props} />;
}
export interface ButtonIconProps extends React.HTMLAttributes<HTMLSpanElement> {
placement?: 'start' | 'end';
}
/**
* Button Icon component - used to place an icon inside a button, renders span element.;
*
* @param props.placement This property is needed to adjust icon placement inside a button. The icon with placement="start" will cut the inline-start padding. placement="end" will affect the padding-inline-end accordingly. This property supports RTL and LTR, so you don't need to think about it.
*/
export function ButtonBaseIcon({ className, children, placement }: ButtonIconProps) {
const classToApply = clsx('dbv-kit-button__icon', placement && `dbv-kit-button__icon--${placement}`, className);
return <span className={classToApply}>{children}</span>;
}
export const Button = componentProviderWrapper('Button', ButtonBase);
export const ButtonIcon = componentProviderWrapper('ButtonIcon', ButtonBaseIcon);
@@ -0,0 +1,25 @@
@layer base {
.dbv-kit-button__loader {
position: absolute;
display: flex;
top: 0;
left: 0;
right: 0;
bottom: 0;
justify-content: center;
align-items: center;
}
.dbv-kit-button__content {
display: flex;
text-align: center;
text-decoration: none;
user-select: none;
position: relative;
justify-content: center;
align-items: center;
white-space: nowrap;
transition: opacity 0.2s ease-in-out;
gap: var(--dbv-kit-btn-gap);
}
}
@@ -0,0 +1,23 @@
import { Button as AriaButton, type ButtonProps as AriaKitButtonProps } from '@ariakit/react';
import { Spinner } from '../Spinner/Spinner.js';
import { clsx } from '../utils/clsx.js';
import './ButtonRoot.css';
export interface ButtonRootProps extends Omit<AriaKitButtonProps, 'clickOnEnter' | 'clickOnSpace'> {
loading?: boolean;
loader?: React.ReactNode;
}
export function ButtonRoot({ loading, loader, children, onClick, className, ...props }: ButtonRootProps) {
if (loading) {
props['aria-busy'] = true;
props['data-loading'] = true;
}
return (
<AriaButton onClick={loading ? () => null : onClick} className={clsx(className, 'tw:relative')} {...props}>
<div className={clsx('dbv-kit-button__content', loading && 'tw:opacity-0')}>{children}</div>
{loading && <div className="dbv-kit-button__loader">{loader ? loader : <Spinner />}</div>}
</AriaButton>
);
}
@@ -0,0 +1,29 @@
@layer base {
:root {
--dbv-kit-btn-height: var(--dbv-kit-control-height-medium);
--dbv-kit-btn-padding-inline: calc(var(--tw-spacing) * 2.5);
--dbv-kit-btn-gap: calc(var(--dbv-kit-btn-padding-inline) / 2);
--dbv-kit-btn-outline-offset: var(--dbv-kit-control-outline-offset);
--dbv-kit-btn-outline-color: var(--dbv-kit-control-outline-color);
--dbv-kit-btn-foreground: var(--tw-color-white);
--dbv-kit-btn-foreground-hover: var(--tw-color-white);
--dbv-kit-btn-foreground-active: var(--tw-color-white);
--dbv-kit-btn-background: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-background-hover: var(--dbv-kit-color-primary-700);
--dbv-kit-btn-background-active: var(--dbv-kit-color-primary-800);
--dbv-kit-btn-border-width: var(--dbv-kit-control-border-width);
--dbv-kit-btn-border-color: transparent;
--dbv-kit-btn-border-style: solid;
--dbv-kit-btn-border-radius: var(--dbv-kit-control-border-radius);
--dbv-kit-btn-font-weight: var(--tw-font-weight-normal);
--dbv-kit-btn-font-size: calc(var(--dbv-kit-font-size-base) * 0.875);
--dbv-kit-btn-loader-base-color: var(--dbv-kit-btn-foreground);
--dbv-kit-btn-loader-height: calc(var(--dbv-kit-btn-height) * 0.6);
}
}
@@ -0,0 +1,27 @@
@layer base {
:root {
/*Small button*/
--dbv-kit-btn-small-padding-inline: calc(var(--dbv-kit-btn-padding-inline) * 0.5);
--dbv-kit-btn-small-font-size: calc(var(--dbv-kit-btn-font-size) * 0.875);
--dbv-kit-btn-small-height: var(--dbv-kit-control-height-small);
--dbv-kit-btn-small-gap: calc(var(--dbv-kit-btn-gap) * 0.5);
/*Medium button*/
--dbv-kit-btn-medium-padding-inline: var(--dbv-kit-btn-padding-inline);
--dbv-kit-btn-medium-font-size: var(--dbv-kit-btn-font-size);
--dbv-kit-btn-medium-height: var(--dbv-kit-control-height-medium);
--dbv-kit-btn-medium-gap: var(--dbv-kit-btn-gap);
/*Large button*/
--dbv-kit-btn-large-padding-inline: calc(var(--dbv-kit-btn-padding-inline) * 1.25);
--dbv-kit-btn-large-font-size: calc(var(--dbv-kit-btn-font-size) * 1.125);
--dbv-kit-btn-large-height: var(--dbv-kit-control-height-large);
--dbv-kit-btn-large-gap: calc(var(--dbv-kit-btn-gap) * 1.25);
/*Extra large button*/
--dbv-kit-btn-xlarge-padding-inline: calc(var(--dbv-kit-btn-padding-inline) * 1.5);
--dbv-kit-btn-xlarge-font-size: calc(var(--dbv-kit-btn-font-size) * 1.25);
--dbv-kit-btn-xlarge-height: var(--dbv-kit-control-height-xlarge);
--dbv-kit-btn-xlarge-gap: calc(var(--dbv-kit-btn-gap) * 1.5);
}
}
@@ -0,0 +1,31 @@
@layer base {
:root {
/* Primary Button */
--dbv-kit-btn-primary-foreground: var(--tw-color-white);
--dbv-kit-btn-primary-foreground-hover: var(--tw-color-white);
--dbv-kit-btn-primary-foreground-active: var(--tw-color-white);
--dbv-kit-btn-primary-background: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-primary-background-hover: var(--dbv-kit-color-primary-700);
--dbv-kit-btn-primary-background-active: var(--dbv-kit-color-primary-800);
/* Secondary Button */
--dbv-kit-btn-secondary-foreground: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-foreground-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-foreground-active: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-background: transparent;
--dbv-kit-btn-secondary-background-hover: var(--dbv-kit-color-primary-50);
--dbv-kit-btn-secondary-background-active: var(--dbv-kit-color-primary-100);
--dbv-kit-btn-secondary-border-color: var(--dbv-kit-color-primary-600);
--dbv-kit-btn-secondary-border-color-hover: var(--dbv-kit-color-primary-600);
/* Danger Button */
--dbv-kit-btn-danger-foreground: var(--tw-color-white);
--dbv-kit-btn-danger-foreground-hover: var(--tw-color-white);
--dbv-kit-btn-danger-foreground-active: var(--tw-color-white);
--dbv-kit-btn-danger-background: var(--tw-color-red-600);
--dbv-kit-btn-danger-background-hover: var(--tw-color-red-700);
--dbv-kit-btn-danger-background-active: var(--tw-color-red-800);
--dbv-kit-btn-danger-border-color: transparent;
--dbv-kit-btn-danger-color-outline: var(--tw-color-red-300);
}
}
@@ -0,0 +1,94 @@
@import './_base.css';
@import './_sizes.css';
@layer base {
.dbv-kit-checkbox {
display: inline-flex;
user-select: none;
align-items: start;
min-height: var(--dbv-kit-checkbox-height);
gap: var(--dbv-kit-checkbox-gap);
line-height: var(--dbv-kit-checkbox-height);
font-size: var(--dbv-kit-checkbox-font-size);
color: var(--dbv-kit-checkbox-foreground);
outline: var(--dbv-kit-control-outline-color);
&:hover {
cursor: pointer;
.dbv-kit-checkbox__check {
box-shadow: 0 0 0 2px var(--dbv-kit-checkbox-hover-shadow-color);
}
}
&[data-checked='true'] {
border-color: var(--dbv-kit-checkbox-border-color-checked);
}
&[data-disabled='true'] {
pointer-events: none;
opacity: var(--dbv-kit-control-disabled-opacity);
}
}
.dbv-kit-checkbox__check {
--check-size: round(calc(var(--dbv-kit-checkbox-height) * var(--dbv-kit-checkbox-check-size)), 2px);
margin-top: calc(var(--dbv-kit-checkbox-height) * (calc(1 - var(--dbv-kit-checkbox-check-size)) / 2));
height: var(--check-size);
line-height: var(--check-size);
width: var(--check-size);
min-width: var(--check-size);
border-radius: var(--dbv-kit-checkbox-border-radius);
background-color: var(--dbv-kit-checkbox-background);
border-color: var(--dbv-kit-checkbox-border-color);
border-width: var(--dbv-kit-checkbox-border-width);
border-style: var(--dbv-kit-checkbox-border-style);
color: var(--dbv-kit-checkbox-icon-color);
outline-offset: var(--dbv-kit-control-outline-offset);
outline-width: var(--dbv-kit-control-outline-width);
outline-color: var(--dbv-kit-control-outline-color);
transition-property: stroke-dashoffset;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
stroke-dasharray: 20;
stroke-dashoffset: 20;
&[data-focus-visible] {
outline-style: solid;
}
&[data-checked='true'],
&[data-indeterminate='true'] {
background-color: var(--dbv-kit-checkbox-background-checked);
border-color: var(--dbv-kit-checkbox-border-color-checked);
stroke-dashoffset: 0;
}
}
/* ---------------------------- */
/* Sizes */
.dbv-kit-checkbox--small {
--dbv-kit-checkbox-font-size: var(--dbv-kit-checkbox-small-font-size);
--dbv-kit-checkbox-height: var(--dbv-kit-checkbox-small-height);
--dbv-kit-checkbox-gap: var(--dbv-kit-checkbox-small-gap);
}
.dbv-kit-checkbox--medium {
--dbv-kit-checkbox-font-size: var(--dbv-kit-checkbox-medium-font-size);
--dbv-kit-checkbox-height: var(--dbv-kit-checkbox-medium-height);
--dbv-kit-checkbox-gap: var(--dbv-kit-checkbox-medium-gap);
}
.dbv-kit-checkbox--large {
--dbv-kit-checkbox-font-size: var(--dbv-kit-checkbox-large-font-size);
--dbv-kit-checkbox-height: var(--dbv-kit-checkbox-large-height);
--dbv-kit-checkbox-gap: var(--dbv-kit-checkbox-large-gap);
}
.dbv-kit-checkbox--xlarge {
--dbv-kit-checkbox-font-size: var(--dbv-kit-checkbox-xlarge-font-size);
--dbv-kit-checkbox-height: var(--dbv-kit-checkbox-xlarge-height);
--dbv-kit-checkbox-gap: var(--dbv-kit-checkbox-xlarge-gap);
}
}
@@ -0,0 +1,75 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { Checkbox as AriaCheckbox, VisuallyHidden, type CheckboxProps as AriaKitCheckboxProps } from '@ariakit/react';
import { useState } from 'react';
import clsx from 'clsx';
import './Checkbox.css';
import type { ControlSize } from '../types/controls.js';
import { componentProviderWrapper } from '../componentProviderWrapper.js';
export interface CheckboxProps extends Omit<AriaKitCheckboxProps, 'render' | 'size'> {
size?: ControlSize;
icon?: React.ReactNode;
indeterminate?: boolean;
indeterminateIcon?: React.ReactNode;
}
export function CheckboxBase({ children, className, icon, indeterminate, indeterminateIcon, size = 'medium', ...props }: CheckboxProps) {
const [innerChecked, setInnerChecked] = useState(props.defaultChecked ?? false);
const checked = props.checked ?? innerChecked;
const [focusVisible, setFocusVisible] = useState(false);
return (
<label
className={clsx('dbv-kit-checkbox', `dbv-kit-checkbox--${size}`, className)}
data-disabled={props.disabled || undefined}
data-checked={checked}
data-focus-visible={focusVisible || undefined}
>
<VisuallyHidden>
<AriaCheckbox
{...props}
className="dbv-kit-checkbox__input"
clickOnEnter
onFocusVisible={() => setFocusVisible(true)}
onBlur={() => setFocusVisible(false)}
onChange={event => {
setInnerChecked(event.target.checked);
props.onChange?.(event);
}}
/>
</VisuallyHidden>
<div
className="dbv-kit-checkbox__check"
data-indeterminate={indeterminate}
data-checked={checked}
data-focus-visible={focusVisible || undefined}
>
{checked &&
(icon ?? (
<svg stroke="currentColor" strokeWidth="2" viewBox="0 0 16 16">
<polyline fill="none" points="3,7 7,11 13,4" />
</svg>
))}
{indeterminate &&
!checked &&
(indeterminateIcon ?? (
<svg fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 16 16">
<line x1="3" y1="8" x2="13" y2="8" />
</svg>
))}
</div>
<span className="dbv-kit-checkbox__text">{children}</span>
</label>
);
}
export const Checkbox = componentProviderWrapper('Checkbox', CheckboxBase);
@@ -0,0 +1,27 @@
@layer base {
:root {
/* Checkbox sizes */
--dbv-kit-checkbox-height: var(--dbv-kit-control-height-medium);
--dbv-kit-checkbox-gap: calc(var(--tw-spacing) * 1.25);
--dbv-kit-checkbox-check-size: 0.5625;
/* Checkbox colors */
--dbv-kit-checkbox-foreground: var(--tw-color-black);
--dbv-kit-checkbox-background: transparent;
--dbv-kit-checkbox-background-checked: var(--dbv-kit-color-primary-600);
--dbv-kit-checkbox-hover-shadow-color: var(--dbv-kit-color-primary-200);
--dbv-kit-checkbox-icon-color: var(--tw-color-white);
/* Checkbox border */
--dbv-kit-checkbox-border-width: calc(var(--dbv-kit-control-border-width) * 2);
--dbv-kit-checkbox-border-radius: var(--dbv-kit-control-border-radius);
--dbv-kit-checkbox-border-style: solid;
--dbv-kit-checkbox-border-color: var(--dbv-kit-color-control-inactive);
--dbv-kit-checkbox-border-color-checked: var(--dbv-kit-color-primary-600);
/* Checkbox label font */
--dbv-kit-checkbox-font-weight: var(--tw-font-weight-normal);
--dbv-kit-checkbox-font-size: var(--dbv-kit-font-size-base);
}
}
@@ -0,0 +1,23 @@
@layer base {
:root {
/* Small checkbox */
--dbv-kit-checkbox-small-font-size: calc(var(--dbv-kit-checkbox-font-size) * 0.875);
--dbv-kit-checkbox-small-height: var(--dbv-kit-control-height-small);
--dbv-kit-checkbox-small-gap: calc(var(--dbv-kit-checkbox-gap) * 0.5);
/* Medium checkbox */
--dbv-kit-checkbox-medium-font-size: var(--dbv-kit-checkbox-font-size);
--dbv-kit-checkbox-medium-height: var(--dbv-kit-control-height-medium);
--dbv-kit-checkbox-medium-gap: var(--dbv-kit-checkbox-gap);
/* Large checkbox */
--dbv-kit-checkbox-large-font-size: calc(var(--dbv-kit-checkbox-font-size) * 1.125);
--dbv-kit-checkbox-large-height: var(--dbv-kit-control-height-large);
--dbv-kit-checkbox-large-gap: calc(var(--dbv-kit-checkbox-gap) * 1.25);
/* Extra large checkbox */
--dbv-kit-checkbox-xlarge-font-size: calc(var(--dbv-kit-checkbox-font-size) * 1.25);
--dbv-kit-checkbox-xlarge-height: var(--dbv-kit-control-height-xlarge);
--dbv-kit-checkbox-xlarge-gap: calc(var(--dbv-kit-checkbox-gap) * 1.5);
}
}
@@ -0,0 +1,22 @@
import { createContext } from 'react';
import type { ButtonBase, ButtonBaseIcon } from './Button/Button.js';
import type { IconButtonBase } from './IconButton/IconButton.js';
import type { CheckboxBase } from './Checkbox/Checkbox.js';
import type { Radio } from './Radio/Radio.js';
import type { InputBase } from './Input/Input.js';
import type { RadioGroup } from './Radio/RadioGroup.js';
import type { Select } from './Select/Select.js';
import type { SelectField } from './Select/SelectField.js';
export interface IComponentProvider {
Button?: typeof ButtonBase;
ButtonIcon?: typeof ButtonBaseIcon;
IconButton?: typeof IconButtonBase;
Input?: typeof InputBase;
Checkbox?: typeof CheckboxBase;
Radio?: typeof Radio;
RadioGroup?: typeof RadioGroup;
Select?: typeof Select;
SelectField?: typeof SelectField;
}
export const ComponentProvider = createContext<IComponentProvider>({});
@@ -0,0 +1,110 @@
@import './_base.css';
@import './_sizes.css';
@import './_variants.css';
@layer base {
.dbv-kit-icon-button {
min-width: var(--dbv-kit-icon-btn-size);
width: var(--dbv-kit-icon-btn-size);
height: var(--dbv-kit-icon-btn-size);
font-size: calc(var(--dbv-kit-icon-btn-size) * 0.75);
border-radius: var(--dbv-kit-icon-btn-border-radius);
border-color: var(--dbv-kit-icon-btn-border-color);
border-width: var(--dbv-kit-icon-btn-border-width);
border-style: var(--dbv-kit-icon-btn-border-style);
color: var(--dbv-kit-icon-btn-foreground);
background-color: var(--dbv-kit-icon-btn-background);
cursor: pointer;
&:focus-visible,
&[data-focus-visible] {
outline: var(--dbv-kit-icon-btn-outline-width) solid var(--dbv-kit-icon-btn-outline-color);
outline-offset: var(--dbv-kit-icon-btn-outline-offset);
}
&:hover {
@media (hover: hover) {
color: var(--dbv-kit-icon-btn-foreground-hover);
background-color: var(--dbv-kit-icon-btn-background-hover);
}
}
&:active,
&[data-active] {
color: var(--dbv-kit-icon-btn-foreground-active);
background-color: var(--dbv-kit-icon-btn-background-active);
}
&:disabled {
opacity: var(--dbv-kit-control-disabled-opacity);
}
&[data-loading='true'] {
background-color: var(--dbv-kit-icon-btn-background);
&:hover,
&:active,
&[data-active] {
background-color: var(--dbv-kit-icon-btn-background-active);
}
}
.dbv-kit-spinner {
--dbv-kit-spinner-stroke-color: var(--dbv-kit-icon-btn-loader-color);
--dbv-kit-spinner-height: calc(var(--dbv-kit-icon-btn-size) * 0.8);
--dbv-kit-spinner-stroke-width: 3px;
}
}
/* Size variants */
.dbv-kit-icon-button--small {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-small-size);
}
.dbv-kit-icon-button--medium {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-medium-size);
}
.dbv-kit-icon-button--large {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-large-size);
}
.dbv-kit-icon-button--xlarge {
--dbv-kit-icon-btn-size: var(--dbv-kit-icon-btn-xlarge-size);
}
/* Variant styles */
.dbv-kit-icon-button--primary {
--dbv-kit-icon-btn-foreground: var(--dbv-kit-icon-btn-primary-foreground);
--dbv-kit-icon-btn-foreground-hover: var(--dbv-kit-icon-btn-primary-foreground-hover);
--dbv-kit-icon-btn-foreground-active: var(--dbv-kit-icon-btn-primary-foreground-active);
--dbv-kit-icon-btn-background: var(--dbv-kit-icon-btn-primary-background);
--dbv-kit-icon-btn-background-hover: var(--dbv-kit-icon-btn-primary-background-hover);
--dbv-kit-icon-btn-background-active: var(--dbv-kit-icon-btn-primary-background-active);
--dbv-kit-icon-btn-loader-color: var(--dbv-kit-icon-btn-primary-foreground);
}
.dbv-kit-icon-button--secondary {
--dbv-kit-icon-btn-foreground: var(--dbv-kit-icon-btn-secondary-foreground);
--dbv-kit-icon-btn-foreground-hover: var(--dbv-kit-icon-btn-secondary-foreground-hover);
--dbv-kit-icon-btn-foreground-active: var(--dbv-kit-icon-btn-secondary-foreground-active);
--dbv-kit-icon-btn-background: var(--dbv-kit-icon-btn-secondary-background);
--dbv-kit-icon-btn-background-hover: var(--dbv-kit-icon-btn-secondary-background-hover);
--dbv-kit-icon-btn-background-active: var(--dbv-kit-icon-btn-secondary-background-active);
--dbv-kit-icon-btn-border-color: var(--dbv-kit-icon-btn-secondary-border-color);
--dbv-kit-icon-btn-loader-color: var(--dbv-kit-icon-btn-secondary-loader-color);
}
.dbv-kit-icon-button--danger {
--dbv-kit-icon-btn-foreground: var(--dbv-kit-icon-btn-danger-foreground);
--dbv-kit-icon-btn-foreground-hover: var(--dbv-kit-icon-btn-danger-foreground-hover);
--dbv-kit-icon-btn-foreground-active: var(--dbv-kit-icon-btn-danger-foreground-active);
--dbv-kit-icon-btn-background: var(--dbv-kit-icon-btn-danger-background);
--dbv-kit-icon-btn-background-hover: var(--dbv-kit-icon-btn-danger-background-hover);
--dbv-kit-icon-btn-background-active: var(--dbv-kit-icon-btn-danger-background-active);
--dbv-kit-icon-btn-loader-color: var(--dbv-kit-icon-btn-danger-loader-color);
}
}
@@ -0,0 +1,32 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { clsx } from 'clsx';
import { componentProviderWrapper } from '../componentProviderWrapper.js';
import { ButtonRoot, type ButtonRootProps } from '../Button/ButtonRoot.js';
import type { ControlSize } from '../types/controls.js';
import './IconButton.css';
export interface IconButtonProps extends ButtonRootProps {
'aria-label': string;
variant?: 'primary' | 'secondary' | 'danger';
size?: ControlSize;
}
export function IconButtonBase({ className, variant = 'primary', size = 'medium', children, ...props }: IconButtonProps) {
const classToApply = clsx('dbv-kit-icon-button', `dbv-kit-icon-button--${variant}`, `dbv-kit-icon-button--${size}`, className);
return (
<ButtonRoot className={classToApply} {...props}>
{children}
</ButtonRoot>
);
}
export const IconButton = componentProviderWrapper('IconButton', IconButtonBase);
@@ -0,0 +1,30 @@
@layer base {
:root {
/* Icon Button border variables */
--dbv-kit-icon-btn-border-radius: var(--dbv-kit-btn-border-radius);
--dbv-kit-icon-btn-border-width: var(--dbv-kit-btn-border-width);
--dbv-kit-icon-btn-border-style: var(--dbv-kit-btn-border-style);
--dbv-kit-icon-btn-border-color: var(--dbv-kit-btn-border-color);
/* Icon Button outline variables */
--dbv-kit-icon-btn-outline-width: var(--dbv-kit-control-outline-width);
--dbv-kit-icon-btn-outline-style: var(--dbv-kit-control-outline-style);
--dbv-kit-icon-btn-outline-color: var(--dbv-kit-control-outline-color);
--dbv-kit-icon-btn-outline-offset: var(--dbv-kit-control-outline-offset);
/* Default size */
--dbv-kit-icon-btn-size: var(--dbv-kit-control-height-medium);
/* Default colors */
--dbv-kit-icon-btn-foreground: var(--tw-color-gray-600);
--dbv-kit-icon-btn-foreground-hover: var(--tw-color-gray-600);
--dbv-kit-icon-btn-foreground-active: var(--tw-color-gray-700);
--dbv-kit-icon-btn-background: transparent;
--dbv-kit-icon-btn-background-hover: var(--tw-color-gray-100);
--dbv-kit-icon-btn-background-active: var(--tw-color-gray-200);
/* Loader color */
--dbv-kit-btn-loader-color: var(--dbv-kit-btn-foreground-hover);
--dbv-kit-btn-loader-base-color: transparent;
}
}
@@ -0,0 +1,8 @@
@layer base {
:root {
--dbv-kit-icon-btn-small-size: var(--dbv-kit-control-height-small);
--dbv-kit-icon-btn-medium-size: var(--dbv-kit-control-height-medium);
--dbv-kit-icon-btn-large-size: var(--dbv-kit-control-height-large);
--dbv-kit-icon-btn-xlarge-size: var(--dbv-kit-control-height-xlarge);
}
}
@@ -0,0 +1,31 @@
@layer base {
:root {
/* Primary */
--dbv-kit-icon-btn-primary-foreground: var(--tw-color-gray-600);
--dbv-kit-icon-btn-primary-foreground-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-icon-btn-primary-foreground-active: var(--dbv-kit-color-primary-700);
--dbv-kit-icon-btn-primary-background: transparent;
--dbv-kit-icon-btn-primary-background-hover: var(--tw-color-gray-100);
--dbv-kit-icon-btn-primary-background-active: var(--tw-color-gray-200);
--dbv-kit-icon-btn-primary-loader-color: var(--tw-color-gray-300);
/* Secondary */
--dbv-kit-icon-btn-secondary-foreground: var(--tw-color-gray-500);
--dbv-kit-icon-btn-secondary-foreground-hover: var(--dbv-kit-color-primary-600);
--dbv-kit-icon-btn-secondary-foreground-active: var(--dbv-kit-color-primary-700);
--dbv-kit-icon-btn-secondary-background: transparent;
--dbv-kit-icon-btn-secondary-background-hover: transparent;
--dbv-kit-icon-btn-secondary-background-active: transparent;
--dbv-kit-icon-btn-secondary-border-color: transparent;
--dbv-kit-icon-btn-secondary-loader-color: var(--tw-color-gray-300);
/* Danger */
--dbv-kit-icon-btn-danger-foreground: var(--tw-color-red-600);
--dbv-kit-icon-btn-danger-foreground-hover: var(--tw-color-red-700);
--dbv-kit-icon-btn-danger-foreground-active: var(--tw-color-red-800);
--dbv-kit-icon-btn-danger-background: transparent;
--dbv-kit-icon-btn-danger-background-hover: var(--tw-color-red-100);
--dbv-kit-icon-btn-danger-background-active: var(--tw-color-red-200);
--dbv-kit-icon-btn-danger-loader-color: var(--tw-color-red-300);
}
}
@@ -0,0 +1,77 @@
@import './_base.css';
@import './_sizes.css';
@import './_variants.css';
@layer base {
.dbv-kit-input-wrapper {
position: relative;
display: flex;
flex-direction: column;
}
.dbv-kit-input {
background: var(--dbv-kit-input-background);
border-radius: var(--dbv-kit-input-radius);
border-color: var(--dbv-kit-input-border-color);
border-width: var(--dbv-kit-input-border-width);
border-style: var(--dbv-kit-input-border-style);
color: var(--dbv-kit-input-foreground);
padding-inline: var(--dbv-kit-input-padding);
font-size: var(--dbv-kit-input-font-size);
height: var(--dbv-kit-input-height);
&:not(:disabled):hover {
border-color: var(--dbv-kit-color-control-hover);
}
&:disabled {
cursor: not-allowed;
opacity: var(--dbv-kit-control-disabled-opacity);
}
&::placeholder {
color: var(--dbv-kit-input-placeholder-foreground);
}
&:focus-visible,
&[data-focus-visible] {
outline: var(--dbv-kit-control-outline-width) solid var(--dbv-kit-control-outline-color);
outline-offset: var(--dbv-kit-control-outline-offset);
}
}
.dbv-kit-input__title {
color: var(--dbv-kit-input-label-foreground);
padding-inline-start: var(--dbv-kit-input-label-padding);
margin-block-end: var(--tw-spacing);
}
.dbv-kit-input__title--required {
&:after {
content: '*';
color: var(--dbv-kit-color-control-required);
margin-inline-start: 0.125rem;
}
}
/* ---------------------------- */
/* Sizes */
.dbv-kit-input--small {
--dbv-kit-input-height: var(--dbv-kit-input-small-height);
--dbv-kit-input-padding: var(--dbv-kit-input-small-padding);
--dbv-kit-input-font-size: var(--dbv-kit-input-small-font-size);
}
.dbv-kit-input--large {
--dbv-kit-input-height: var(--dbv-kit-input-large-height);
--dbv-kit-input-padding: var(--dbv-kit-input-large-padding);
--dbv-kit-input-font-size: var(--dbv-kit-input-large-font-size);
}
.dbv-kit-input--xlarge {
--dbv-kit-input-height: var(--dbv-kit-input-xlarge-height);
--dbv-kit-input-padding: var(--dbv-kit-input-xlarge-padding);
--dbv-kit-input-font-size: var(--dbv-kit-input-xlarge-font-size);
}
}

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