Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bee81952d | ||
|
|
698dc8a312 | ||
|
|
180ec65dd9 | ||
|
|
79d5702744 | ||
|
|
603b94c551 | ||
|
|
ad6973d069 | ||
|
|
231da5b0b8 | ||
|
|
57e77b7cd1 | ||
|
|
58c4744aa7 | ||
|
|
39c7346e0a | ||
|
|
131b1e13f4 | ||
|
|
3914461f55 | ||
|
|
5dc6e5ca38 | ||
|
|
c747c30063 | ||
|
|
ad225404f4 | ||
|
|
d9fe873bb5 | ||
|
|
0193e67f72 | ||
|
|
8ebf7eba9c | ||
|
|
848b95113a | ||
|
|
d4c304f725 | ||
|
|
444ff0d672 | ||
|
|
bf49a94642 | ||
|
|
3a2e41fa69 | ||
|
|
36e8d1fac9 | ||
|
|
dcc13811e8 | ||
|
|
2ba910386f | ||
|
|
a7c5d53f0a | ||
|
|
59f0da9caa | ||
|
|
4d5c58316c | ||
|
|
bae21e5b2e | ||
|
|
5ce5f6e10d | ||
|
|
db28b2ad2c | ||
|
|
d58b3e14a2 | ||
|
|
c476a56661 | ||
|
|
79804619d3 | ||
|
|
1c7300cdf1 | ||
|
|
9b2cb7cc92 | ||
|
|
5022c01468 | ||
|
|
60fb6c5a3b | ||
|
|
6889b51ab6 | ||
|
|
a7e09b5e16 | ||
|
|
0746a7a2c4 | ||
|
|
f5380093ca | ||
|
|
dd4691c650 | ||
|
|
55db159560 | ||
|
|
dcdea93687 | ||
|
|
54b5db9480 | ||
|
|
aa84d79e93 | ||
|
|
9bc28083fd | ||
|
|
cb03b507b3 | ||
|
|
9ffa5088db | ||
|
|
e7dcc93706 | ||
|
|
ad3ae4547c | ||
|
|
dce7797bba | ||
|
|
7c0d666b0a | ||
|
|
c5a2bcdcbf | ||
|
|
85a242bf34 | ||
|
|
2117840e40 | ||
|
|
9fec1ce5a5 | ||
|
|
88ef237566 | ||
|
|
cb84409701 | ||
|
|
69330aa0fe | ||
|
|
76fab9d179 | ||
|
|
feed398b6d | ||
|
|
8422e695ea | ||
|
|
7fd2548c9c | ||
|
|
dc8407ad35 | ||
|
|
4379ba8ce7 | ||
|
|
eaeb493d6b | ||
|
|
9de5f9508f | ||
|
|
93cbaa673f | ||
|
|
646ec5c901 | ||
|
|
beecc84d14 | ||
|
|
ab0df706bb | ||
|
|
5edd0142af | ||
|
|
3c49650bc3 | ||
|
|
f286ab4b3c | ||
|
|
7dc9a9daa7 | ||
|
|
7f353e9169 | ||
|
|
33757a96e8 | ||
|
|
47a6ba4632 | ||
|
|
507aa096dd | ||
|
|
c28af2a722 | ||
|
|
1d01db34ff | ||
|
|
6d70e03a9e | ||
|
|
d69eb04b11 | ||
|
|
f891c26ee2 | ||
|
|
12ef593bd7 | ||
|
|
3f17ec4abc | ||
|
|
f0010494fa | ||
|
|
5c17cc660d | ||
|
|
41ff7485d5 | ||
|
|
fbdb5cd49a | ||
|
|
c920f84e13 | ||
|
|
84d85ea28e | ||
|
|
dd060e8b42 | ||
|
|
786babc988 | ||
|
|
9739ab3b46 | ||
|
|
ab31ddda40 | ||
|
|
08d65c4410 | ||
|
|
f7cd98ae4e | ||
|
|
419f8b562e | ||
|
|
927ba55dff | ||
|
|
28aea99a3b | ||
|
|
e7c6c11342 | ||
|
|
d2d915a8ea | ||
|
|
6b8bcfbc1a | ||
|
|
31be26e167 | ||
|
|
9c788a56cd |
@@ -19,6 +19,16 @@
|
||||
"group": "test",
|
||||
"args": ["test"]
|
||||
},
|
||||
{
|
||||
"label": "Run Tests Common Typescript",
|
||||
"type": "shell",
|
||||
"command": "yarn",
|
||||
"group": "test",
|
||||
"args": ["test"],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/common-typescript"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run DevServer CE",
|
||||
"group": "build",
|
||||
@@ -107,6 +117,15 @@
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/webapp/packages"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run Ui Kit Preview",
|
||||
"type": "shell",
|
||||
"command": "yarn",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/common-react/@dbeaver/ui-kit"
|
||||
},
|
||||
"args": ["docs"]
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
|
||||
@@ -25,74 +25,56 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
### 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).
|
||||
### 25.1.3 2025-07-21
|
||||
- A password confirmation field has been added for administrators in the Easy Config section to help prevent accidental misconfigurations;
|
||||
- Added column descriptions in the Data Editor to provide more metadata context. You can disable this in Preferences > Data Viewer;
|
||||
- Added the option to display tabs across multiple rows, allowing you to see all tabs without scrolling. You can enable this in Preferences > Interface;
|
||||
- Changed the default engine used for autocompletion in the SQL Editor. This Semantic engine offers improved suggestions for database objects, keywords, and functions. You can switch back to the Legacy engine in Preferences -> SQL Editor;
|
||||
- Clickhouse: fixed the presentation of tuples and map data types in the data editor.
|
||||
|
||||
### 25.0.4 2025-05-05
|
||||
### 25.1.2 2025-07-07
|
||||
- The CloudBeaver default theme matches the device theme by default now. You can change this behavior in user preferences under the Theme section;
|
||||
- Added a button “Clear” to the Output panel;
|
||||
- Changed the data transfer mechanism to avoid intermediate file creation. The parameter dataExportFileSizeLimit was removed from the server configuration as deprecated;
|
||||
- PostgresSQL: fixed misplaced comment for table DDL generation.
|
||||
|
||||
### 25.1.1 2025-06-23
|
||||
### Changes since 25.1.0:
|
||||
- Added a search panel for SQL Editor and Value panel: press Ctrl+F to open a panel that allows searching and replacing by keyword or regular expression.
|
||||
- Added a new welcome screen for a freshly opened application. This screen contains shortcuts to create a new connection, open SQL editor or documentation.
|
||||
- Databend database support has been added.
|
||||
|
||||
### 25.1.0 2025-06-02
|
||||
### Changes since 25.0.0:
|
||||
- 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:
|
||||
- Added transaction log viewing for connections with manual commit mode. This allows users to see all modifying statements before committing;
|
||||
- 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:
|
||||
- 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.
|
||||
- Log records now capture create, update, and delete actions for users, teams, and connections for improved tracking and transparency.
|
||||
- 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.
|
||||
- Added support for secure [LDAP authentication over SSL](https://github.com/dbeaver/cloudbeaver/wiki/LDAP-Authentication);
|
||||
- Brute force protection is now supported for LDAP authentication. All authentication methods on the application level have this security mechanism.
|
||||
- SQL Editor:
|
||||
- A new setting to autosave scripts in the SQL editor appeared in global and users' preferences;
|
||||
- Auto-completion has been improved for aliases and camelCase entities.
|
||||
- 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:
|
||||
- The MariaDB driver has been updated to version 3.5.1;
|
||||
- The SQLite driver has been updated to version 3.48.0.0.
|
||||
- Improved table rendering to scale column width depending on the content;
|
||||
- Accessibility: improved keyboard navigation by sorting buttons in column headers.
|
||||
- General:
|
||||
- Added the ability to configure the default database or schema in the connection configuration;
|
||||
- Enhanced initial configuration stage security: a server needs to be restarted if the initial setup time exceeds 1 hour;
|
||||
- Improved Navigation tree performance: lost connection does not lead to the application freezing anymore;
|
||||
- Data transfer: Improved export/import functionality performance by optimizing disk memory consumption;
|
||||
- Vietnamese localization has been added (thanks to [0xhanh](https://github.com/0xhanh)).
|
||||
- Databases and drivers:
|
||||
- Clickhouse: driver has been updated to version 0.8.5;
|
||||
- DuckDB: expanded the list of system objects that can be hidden in the Navigation tree;
|
||||
- LibSQL: added the ability to connect using token authentication;
|
||||
- Oracle: users' DDL in Oracle is displayed in the metadata editor on the corresponding tab for users with Oracle administration permissions;
|
||||
- SQLite: added information about a table's Strict mode to the table metadata section (thanks to [eusebe-cda](https://github.com/eusebe-cda)).
|
||||
|
||||
## Contribution
|
||||
As a community-driven open-source project, we warmly welcome contributions through GitHub pull requests.
|
||||
|
||||
[We are happy to reward](https://dbeaver.com/help-dbeaver/) our most active contributors every major sprint.
|
||||
The most significant contribution to our code for the major release 24.3.0 was made by:
|
||||
1. [cashlifei](https://github.com/cashlifei)
|
||||
The most significant contribution to our code for the major release 25.1.0 was made by:
|
||||
1. [0xhanh](https://github.com/0xhanh) - for Vietnamese localization.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "prettier",
|
||||
"version": "3.5.3-sdk",
|
||||
"version": "3.6.2-sdk",
|
||||
"main": "./index.cjs",
|
||||
"type": "commonjs",
|
||||
"bin": "./bin/prettier.cjs"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
Root;
|
||||
}
|
||||
|
||||
.mlln6zg7-0-0-beta-50 {
|
||||
.mlln6zg7-0-0-beta-55 {
|
||||
@layer rdg.MeasuringCell {
|
||||
contain: strict;
|
||||
grid-row: 1;
|
||||
@@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
|
||||
.cj343x07-0-0-beta-50 {
|
||||
.cj343x07-0-0-beta-55 {
|
||||
@layer rdg.Cell {
|
||||
/* max-content does not work with size containment
|
||||
* dynamically switching between different containment styles incurs a heavy relayout penalty
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.csofj7r7-0-0-beta-50 {
|
||||
.csofj7r7-0-0-beta-55 {
|
||||
@layer rdg.Cell {
|
||||
position: sticky;
|
||||
/* Should have a higher value than 0 to show up above unfrozen cells */
|
||||
@@ -66,8 +66,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ch2wcw87-0-0-beta-55 {
|
||||
@layer rdg.DragHandle {
|
||||
--rdg-drag-handle-size: 8px;
|
||||
z-index: 0;
|
||||
cursor: move;
|
||||
inline-size: var(--rdg-drag-handle-size);
|
||||
block-size: var(--rdg-drag-handle-size);
|
||||
background-color: var(--rdg-selection-color);
|
||||
place-self: end;
|
||||
|
||||
.c1bn88vv7-0-0-beta-50 {
|
||||
&:hover {
|
||||
--rdg-drag-handle-size: 16px;
|
||||
border: 2px solid var(--rdg-selection-color);
|
||||
background-color: var(--rdg-background-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c1wvphzh7-0-0-beta-55 {
|
||||
@layer rdg.DragHandle {
|
||||
z-index: 1;
|
||||
position: sticky;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.c1bn88vv7-0-0-beta-55 {
|
||||
@layer rdg.CheckboxInput {
|
||||
display: block;
|
||||
margin: auto;
|
||||
@@ -86,13 +111,13 @@
|
||||
}
|
||||
|
||||
|
||||
.g1s9ylgp7-0-0-beta-50 {
|
||||
.g1s9ylgp7-0-0-beta-55 {
|
||||
@layer rdg.GroupCellContent {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cz54e4y7-0-0-beta-50 {
|
||||
.cz54e4y7-0-0-beta-55 {
|
||||
@layer rdg.GroupCellCaret {
|
||||
margin-inline-start: 4px;
|
||||
stroke: currentColor;
|
||||
@@ -107,13 +132,13 @@
|
||||
}
|
||||
|
||||
|
||||
.h44jtk67-0-0-beta-50 {
|
||||
.h44jtk67-0-0-beta-55 {
|
||||
@layer rdg.SortableHeaderCell {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.hcgkhxz7-0-0-beta-50 {
|
||||
.hcgkhxz7-0-0-beta-55 {
|
||||
@layer rdg.SortableHeaderCellName {
|
||||
flex-grow: 1;
|
||||
overflow: clip;
|
||||
@@ -122,69 +147,33 @@
|
||||
}
|
||||
|
||||
|
||||
.c6ra8a37-0-0-beta-50 {
|
||||
.c6ra8a37-0-0-beta-55 {
|
||||
@layer rdg.Cell {
|
||||
background-color: #ccccff;
|
||||
}
|
||||
}
|
||||
|
||||
.cq910m07-0-0-beta-50 {
|
||||
@layer rdg.Cell {
|
||||
background-color: #ccccff;
|
||||
|
||||
&.c6ra8a37-0-0-beta-50 {
|
||||
background-color: #9999ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.c1w9bbhr7-0-0-beta-50 {
|
||||
@layer rdg.DragHandle {
|
||||
--rdg-drag-handle-size: 8px;
|
||||
z-index: 0;
|
||||
cursor: move;
|
||||
inline-size: var(--rdg-drag-handle-size);
|
||||
block-size: var(--rdg-drag-handle-size);
|
||||
background-color: var(--rdg-selection-color);
|
||||
place-self: end;
|
||||
|
||||
&:hover {
|
||||
--rdg-drag-handle-size: 16px;
|
||||
border: 2px solid var(--rdg-selection-color);
|
||||
background-color: var(--rdg-background-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c1creorc7-0-0-beta-50 {
|
||||
@layer rdg.DragHandle {
|
||||
z-index: 1;
|
||||
position: sticky;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.cis5rrm7-0-0-beta-50 {
|
||||
.cis5rrm7-0-0-beta-55 {
|
||||
@layer rdg.EditCell {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.c6l2wv17-0-0-beta-50 {
|
||||
.c6l2wv17-0-0-beta-55 {
|
||||
@layer rdg.HeaderCell {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.c1kqdw7y7-0-0-beta-50 {
|
||||
.c1kqdw7y7-0-0-beta-55 {
|
||||
@layer rdg.HeaderCell {
|
||||
touch-action: none;
|
||||
}
|
||||
}
|
||||
|
||||
.r1y6ywlx7-0-0-beta-50 {
|
||||
.r1y6ywlx7-0-0-beta-55 {
|
||||
@layer rdg.HeaderCell {
|
||||
cursor: col-resize;
|
||||
position: absolute;
|
||||
@@ -195,16 +184,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
.c1bezg5o7-0-0-beta-50 {
|
||||
opacity: 0.5;
|
||||
.c1bezg5o7-0-0-beta-55 {
|
||||
@layer rdg.HeaderCell {
|
||||
background-color: var(--rdg-header-draggable-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
.c1vc96037-0-0-beta-50 {
|
||||
background-color: var(--rdg-header-draggable-background-color);
|
||||
.c1vc96037-0-0-beta-55 {
|
||||
@layer rdg.HeaderCell {
|
||||
background-color: var(--rdg-header-draggable-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
.d8rwc9w7-0-0-beta-55 {
|
||||
@layer rdg.HeaderCell {
|
||||
border-radius: 4px;
|
||||
width: fit-content;
|
||||
outline: 2px solid hsl(207, 100%, 50%);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.r1upfr807-0-0-beta-50 {
|
||||
.r1upfr807-0-0-beta-55 {
|
||||
@layer rdg.Row {
|
||||
display: contents;
|
||||
background-color: var(--rdg-background-color);
|
||||
@@ -223,14 +225,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.r190mhd37-0-0-beta-50 {
|
||||
.r190mhd37-0-0-beta-55 {
|
||||
@layer rdg.FocusSink {
|
||||
outline: 2px solid var(--rdg-selection-color);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.r139qu9m7-0-0-beta-50 {
|
||||
.r139qu9m7-0-0-beta-55 {
|
||||
@layer rdg.FocusSink {
|
||||
&::before {
|
||||
content: '';
|
||||
@@ -244,26 +246,26 @@
|
||||
}
|
||||
|
||||
|
||||
.h10tskcx7-0-0-beta-50 {
|
||||
.h10tskcx7-0-0-beta-55 {
|
||||
@layer rdg.HeaderRow {
|
||||
display: contents;
|
||||
background-color: var(--rdg-header-background-color);
|
||||
font-weight: bold;
|
||||
|
||||
& > .cj343x07-0-0-beta-50 {
|
||||
& > .cj343x07-0-0-beta-55 {
|
||||
/* 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-50 {
|
||||
& > .csofj7r7-0-0-beta-55 {
|
||||
z-index: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.a3ejtar7-0-0-beta-50 {
|
||||
.a3ejtar7-0-0-beta-55 {
|
||||
@layer rdg.SortIcon {
|
||||
fill: currentColor;
|
||||
|
||||
@@ -274,7 +276,7 @@
|
||||
}
|
||||
|
||||
|
||||
.rnvodz57-0-0-beta-50 {
|
||||
.rnvodz57-0-0-beta-55 {
|
||||
@layer rdg.Defaults {
|
||||
*,
|
||||
*::before,
|
||||
@@ -285,7 +287,7 @@
|
||||
|
||||
@layer rdg.Root {
|
||||
--rdg-color: #000; --rdg-border-color: #ddd; --rdg-summary-border-color: #aaa; --rdg-background-color: hsl(0deg 0% 100%); --rdg-header-background-color: hsl(0deg 0% 97.5%); --rdg-header-draggable-background-color: hsl(0deg 0% 90.5%); --rdg-row-hover-background-color: hsl(0deg 0% 96%); --rdg-row-selected-background-color: hsl(207deg 76% 92%); --rdg-row-selected-hover-background-color: hsl(207deg 76% 88%); --rdg-checkbox-focus-color: hsl(207deg 100% 69%);
|
||||
--rdg-selection-color: #66afe9;
|
||||
--rdg-selection-color: hsl(207, 75%, 66%);
|
||||
--rdg-font-size: 14px;
|
||||
--rdg-cell-frozen-box-shadow: 2px 0 5px -2px rgba(136, 136, 136, 0.3);
|
||||
|
||||
@@ -334,30 +336,30 @@
|
||||
}
|
||||
|
||||
> :nth-last-child(1 of .rdg-top-summary-row) {
|
||||
> .cj343x07-0-0-beta-50 {
|
||||
> .cj343x07-0-0-beta-55 {
|
||||
border-block-end: 2px solid var(--rdg-summary-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
> :nth-child(1 of .rdg-bottom-summary-row) {
|
||||
> .cj343x07-0-0-beta-50 {
|
||||
> .cj343x07-0-0-beta-55 {
|
||||
border-block-start: 2px solid var(--rdg-summary-border-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vlqv91k7-0-0-beta-50 {
|
||||
.vlqv91k7-0-0-beta-55 {
|
||||
@layer rdg.Root {
|
||||
user-select: none;
|
||||
|
||||
& .r1upfr807-0-0-beta-50 {
|
||||
& .r1upfr807-0-0-beta-55 {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.f1lsfrzw7-0-0-beta-50 {
|
||||
.f1lsfrzw7-0-0-beta-55 {
|
||||
@layer rdg.FocusSink {
|
||||
grid-column: 1/-1;
|
||||
pointer-events: none;
|
||||
@@ -366,7 +368,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.f1cte0lg7-0-0-beta-50 {
|
||||
.f1cte0lg7-0-0-beta-55 {
|
||||
@layer rdg.FocusSink {
|
||||
/* Should have a higher value than 3 to show up above header and summary rows */
|
||||
z-index: 3;
|
||||
@@ -374,7 +376,7 @@
|
||||
}
|
||||
|
||||
|
||||
.s8wc6fl7-0-0-beta-50 {
|
||||
.s8wc6fl7-0-0-beta-55 {
|
||||
@layer rdg.SummaryCell {
|
||||
inset-block-start: var(--rdg-summary-row-top);
|
||||
inset-block-end: var(--rdg-summary-row-bottom);
|
||||
@@ -382,42 +384,42 @@
|
||||
}
|
||||
|
||||
|
||||
.skuhp557-0-0-beta-50 {
|
||||
.skuhp557-0-0-beta-55 {
|
||||
@layer rdg.SummaryRow {
|
||||
> .cj343x07-0-0-beta-50 {
|
||||
> .cj343x07-0-0-beta-55 {
|
||||
position: sticky;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tf8l5ub7-0-0-beta-50 {
|
||||
.tf8l5ub7-0-0-beta-55 {
|
||||
@layer rdg.SummaryRow {
|
||||
> .cj343x07-0-0-beta-50 {
|
||||
> .cj343x07-0-0-beta-55 {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
> .csofj7r7-0-0-beta-50 {
|
||||
> .csofj7r7-0-0-beta-55 {
|
||||
z-index: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.g1yxluv37-0-0-beta-50 {
|
||||
.g1yxluv37-0-0-beta-55 {
|
||||
@layer rdg.GroupedRow {
|
||||
&:not([aria-selected='true']) {
|
||||
background-color: var(--rdg-header-background-color);
|
||||
}
|
||||
|
||||
> .cj343x07-0-0-beta-50:not(:last-child, .csofj7r7-0-0-beta-50),
|
||||
> :nth-last-child(n + 2 of .csofj7r7-0-0-beta-50) {
|
||||
> .cj343x07-0-0-beta-55:not(:last-child, .csofj7r7-0-0-beta-55),
|
||||
> :nth-last-child(n + 2 of .csofj7r7-0-0-beta-55) {
|
||||
border-inline-end: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.t7vyx3i7-0-0-beta-50 {
|
||||
.t7vyx3i7-0-0-beta-55 {
|
||||
@layer rdg.TextEditor {
|
||||
appearance: none;
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "react-data-grid",
|
||||
"version": "7.0.0-beta.50",
|
||||
"version": "7.0.0-beta.55",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./lib/styles.css": "./lib/styles.css",
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"default": "./lib/bundle.js"
|
||||
"default": "./lib/index.js"
|
||||
}
|
||||
},
|
||||
"browser": "./lib/bundle.js",
|
||||
"main": "./lib/bundle.js",
|
||||
"module": "./lib/bundle.js",
|
||||
"browser": "./lib/index.js",
|
||||
"main": "./lib/index.js",
|
||||
"module": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"@types/react": "^19",
|
||||
|
||||
@@ -15,13 +15,18 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
|
||||
const tooltip = useGridReactiveValue(cellContext?.cellTooltip, rowIdx, dataColIdx);
|
||||
|
||||
function handleClick(event: React.MouseEvent<HTMLDivElement>) {
|
||||
props.onClick?.(
|
||||
props.onCellClick?.(
|
||||
{
|
||||
rowIdx,
|
||||
row: props.row,
|
||||
column: props.column,
|
||||
selectCell(enableEditor) {
|
||||
props.selectCell({ rowIdx, idx: virtualColIdx }, enableEditor);
|
||||
props.selectCell(
|
||||
{ rowIdx, idx: virtualColIdx },
|
||||
{
|
||||
enableEditor,
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
createCellMouseEvent(event),
|
||||
@@ -29,13 +34,13 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
|
||||
}
|
||||
|
||||
function handleDoubleClick(event: React.MouseEvent<HTMLDivElement>) {
|
||||
props.onDoubleClick?.(
|
||||
props.onCellDoubleClick?.(
|
||||
{
|
||||
rowIdx,
|
||||
row: props.row,
|
||||
column: props.column,
|
||||
selectCell(enableEditor) {
|
||||
props.selectCell({ rowIdx, idx: virtualColIdx }, enableEditor);
|
||||
props.selectCell({ rowIdx, idx: virtualColIdx }, { enableEditor });
|
||||
},
|
||||
},
|
||||
createCellMouseEvent(event),
|
||||
@@ -43,13 +48,13 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
|
||||
}
|
||||
|
||||
function handleContextMenu(event: React.MouseEvent<HTMLDivElement>) {
|
||||
props.onContextMenu?.(
|
||||
props.onCellContextMenu?.(
|
||||
{
|
||||
rowIdx,
|
||||
row: props.row,
|
||||
column: props.column,
|
||||
selectCell(enableEditor) {
|
||||
props.selectCell({ rowIdx, idx: virtualColIdx }, enableEditor);
|
||||
props.selectCell({ rowIdx, idx: virtualColIdx }, { enableEditor });
|
||||
},
|
||||
},
|
||||
createCellMouseEvent(event),
|
||||
@@ -57,7 +62,16 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
|
||||
}
|
||||
|
||||
const mappedProps = useMemo(
|
||||
() => ({ ...props, isFocused: props.isCellSelected, onClick: handleClick, onDoubleClick: handleDoubleClick, onContextMenu: handleContextMenu }),
|
||||
() => ({
|
||||
...props,
|
||||
onCellClick: undefined,
|
||||
onCellContextMenu: undefined,
|
||||
onCellDoubleClick: undefined,
|
||||
isFocused: props.isCellSelected,
|
||||
onClick: handleClick,
|
||||
onDoubleClick: handleDoubleClick,
|
||||
onContextMenu: handleContextMenu,
|
||||
}),
|
||||
Object.values(props),
|
||||
);
|
||||
|
||||
@@ -68,9 +82,9 @@ export const BaseCell = memo(function BaseCell<TRow, TSummaryRow>(props: CellRen
|
||||
<Cell
|
||||
{...props}
|
||||
title={tooltip}
|
||||
onClick={(_, event) => onClick?.(event)}
|
||||
onDoubleClick={(_, event) => onDoubleClick?.(event)}
|
||||
onContextMenu={(_, event) => onContextMenu?.(event)}
|
||||
onCellClick={(_, event) => onClick?.(event)}
|
||||
onCellDoubleClick={(_, event) => onDoubleClick?.(event)}
|
||||
onCellContextMenu={(_, event) => onContextMenu?.(event)}
|
||||
{...rest}
|
||||
isCellSelected={props.isCellSelected || rest.isFocused || false}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
|
||||
import { DataGrid as DataGridBase, type ColumnOrColumnGroup, type CellSelectArgs, type DataGridHandle } from 'react-data-grid';
|
||||
import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||
import { DataGrid as DataGridBase, type ColumnOrColumnGroup, type CellSelectArgs, type DataGridHandle, type ColumnWidth, type ColumnWidths } from 'react-data-grid';
|
||||
import { rowRenderer } from './renderers/rowRenderer.js';
|
||||
import { cellRenderer } from './renderers/cellRenderer.js';
|
||||
import { DataGridCellHeaderContext, type IDataGridHeaderCellContext } from './DataGridHeaderCellContext.js';
|
||||
@@ -70,16 +70,17 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
onFocus,
|
||||
onCellChange,
|
||||
onColumnSort,
|
||||
onHeaderKeyDown,
|
||||
children,
|
||||
className,
|
||||
onCellKeyDown,
|
||||
},
|
||||
ref,
|
||||
) {
|
||||
const [columnWidths, setColumnWidths] = useState<ColumnWidths>(() => new Map<string, ColumnWidth>());
|
||||
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)
|
||||
@@ -110,7 +111,9 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
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);
|
||||
innerGridRef.current?.selectCell({ idx: dndHeaderContext.getDataColIdx(position.colIdx), rowIdx: position.rowIdx }, {
|
||||
enableEditor: true,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -119,12 +122,11 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
rowsCountRef.current = rowsCount;
|
||||
|
||||
if (previousRowCount === 0) {
|
||||
// we trigger columns size recalculation when rows are added
|
||||
gridKey.current++;
|
||||
setColumnWidths(new Map<string, ColumnWidth>());
|
||||
}
|
||||
}
|
||||
|
||||
const rows = useMemo(
|
||||
let rows = useMemo(
|
||||
() =>
|
||||
new Array<IInnerRow>(rowsCount).fill({ idx: 0 }).map((_, i) => ({
|
||||
idx: i,
|
||||
@@ -140,29 +142,36 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
|
||||
onCellKeyDown?.({ colIdx: dndHeaderContext.getDataColIdx(args.column.idx), rowIdx: args.rowIdx }, event);
|
||||
}
|
||||
|
||||
const isMeasurementRender = columnWidths.size === 0 && columnCount.get() > 0;
|
||||
|
||||
if (isMeasurementRender) {
|
||||
rows = rows.slice(0, 100);
|
||||
}
|
||||
|
||||
return (
|
||||
<HeaderDnDContext value={dndHeaderContext}>
|
||||
<DataGridRowContext value={{ rowCount, onScrollToBottom }}>
|
||||
<DataGridCellContext value={{ cell, cellText, cellElement, cellTooltip, onCellChange }}>
|
||||
<DataGridCellHeaderContext value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState }}>
|
||||
<DataGridCellHeaderContext value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState, onHeaderKeyDown }}>
|
||||
<DataGridBase
|
||||
key={gridKey.current}
|
||||
ref={innerGridRef}
|
||||
columns={dndHeaderContext.columns}
|
||||
enableVirtualization={!isMeasurementRender}
|
||||
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}
|
||||
columnWidths={columnWidths}
|
||||
renderers={{
|
||||
renderRow: rowRenderer,
|
||||
renderCell: cellRenderer,
|
||||
noRowsFallback: children,
|
||||
}}
|
||||
minimumRowsToRender={100}
|
||||
onScroll={onScroll}
|
||||
onSelectedCellChange={handleCellFocus}
|
||||
onCellKeyDown={handleCellKeyDown}
|
||||
onColumnWidthsChange={setColumnWidths}
|
||||
/>
|
||||
</DataGridCellHeaderContext>
|
||||
</DataGridCellContext>
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface IDataGridHeaderCellContext {
|
||||
columnSortingState?: IGridReactiveValue<'asc' | 'desc' | undefined | null, [colIdx: number]>;
|
||||
columnSortable?: IGridReactiveValue<boolean, [colIdx: number]>;
|
||||
onColumnSort?: (colIdx: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
|
||||
onHeaderKeyDown?: (event: React.KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
export const DataGridCellHeaderContext = createContext<IDataGridHeaderCellContext | null>(null);
|
||||
|
||||
@@ -4,11 +4,12 @@ import { Checkbox, clsx, Focusable } from '@dbeaver/ui-kit';
|
||||
interface Props {
|
||||
value: boolean | null;
|
||||
className?: string;
|
||||
focusable?: boolean;
|
||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
|
||||
}
|
||||
|
||||
export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props) {
|
||||
export function BooleanFormatter({ value, className, onClick, onKeyDown, focusable }: Props) {
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (event.code === 'Enter' || event.code === 'Space') {
|
||||
event.preventDefault();
|
||||
@@ -17,6 +18,7 @@ export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props
|
||||
};
|
||||
return (
|
||||
<Focusable
|
||||
focusable={focusable}
|
||||
className={clsx('tw:flex tw:items-center tw:outline-none tw:hover:cursor-pointer', className)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onClick={onClick}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { memo, use, useRef } from 'react';
|
||||
import { memo, use } from 'react';
|
||||
import { useDrag, useDrop, type DnDStoreProvider } from '@dbeaver/react-dnd';
|
||||
import { DataGridCellHeaderContext } from '../DataGridHeaderCellContext.js';
|
||||
import { useGridReactiveValue } from '../useGridReactiveValue.js';
|
||||
@@ -9,6 +9,7 @@ interface Props {
|
||||
colIdx: number;
|
||||
tabIndex?: number;
|
||||
}
|
||||
|
||||
export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer({ colIdx, tabIndex }: Props) {
|
||||
const dndHeaderContext = use(HeaderDnDContext);
|
||||
const cellHeaderContext = use(DataGridCellHeaderContext);
|
||||
@@ -16,11 +17,9 @@ export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer
|
||||
const getHeaderText = useGridReactiveValue(headerElement ? undefined : cellHeaderContext?.headerText, colIdx);
|
||||
const isColumnSortable = useGridReactiveValue(cellHeaderContext?.columnSortable, colIdx);
|
||||
const onColumnSort = cellHeaderContext?.onColumnSort;
|
||||
const onHeaderKeyDown = cellHeaderContext?.onHeaderKeyDown;
|
||||
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,
|
||||
@@ -55,26 +54,32 @@ export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer
|
||||
},
|
||||
});
|
||||
|
||||
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();
|
||||
function handleSort(e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) {
|
||||
if (!onColumnSort) return;
|
||||
|
||||
const nextSortState = sortingState === 'asc' ? 'desc' : sortingState === 'desc' ? null : 'asc';
|
||||
onColumnSort(colIdx, nextSortState, e.ctrlKey || e.metaKey);
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLElement>) {
|
||||
onHeaderKeyDown?.(event);
|
||||
|
||||
if ((event.key === 'Enter' || event.key === ' ') && isColumnSortable && onColumnSort) {
|
||||
event.preventDefault();
|
||||
handleSort(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
onKeyDown={onKeyDown}
|
||||
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} />}
|
||||
<span className="tw:overflow-hidden tw:h-full tw:text-ellipsis">{headerElement ?? getHeaderText ?? ''}</span>
|
||||
{isColumnSortable && onColumnSort && <OrderButton sortState={sortingState} onClick={handleSort} />}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
import { clsx, IconButton } from '@dbeaver/ui-kit';
|
||||
import { clsx, IconButton, Icon } from '@dbeaver/ui-kit';
|
||||
|
||||
interface OrderButtonProps {
|
||||
colIdx: number;
|
||||
sortState?: 'asc' | 'desc' | null;
|
||||
onSort: (attributePosition: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
|
||||
onClick: (e: React.MouseEvent<HTMLElement>) => 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';
|
||||
export function OrderButton({ sortState, onClick, tabIndex }: OrderButtonProps) {
|
||||
const svgSortAsc = 'sort-asc';
|
||||
const svgSortDesc = 'sort-desc';
|
||||
const svgSortUnknown = 'sort-unknown';
|
||||
|
||||
const iconSrc = sortState === 'asc' ? svgSortAsc : sortState === 'desc' ? svgSortDesc : svgSortUnknown;
|
||||
|
||||
@@ -24,9 +17,8 @@ export function OrderButton({ colIdx, sortState, onSort, tabIndex, ref }: OrderB
|
||||
<IconButton
|
||||
variant="secondary"
|
||||
size="small"
|
||||
onClick={handleClick}
|
||||
onClick={onClick}
|
||||
tabIndex={tabIndex}
|
||||
ref={ref}
|
||||
title="Sort by column"
|
||||
aria-label="Sort by column"
|
||||
className={clsx(
|
||||
@@ -34,9 +26,7 @@ export function OrderButton({ colIdx, sortState, onSort, tabIndex, ref }: OrderB
|
||||
sortState && 'tw:opacity-100',
|
||||
)}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16">
|
||||
<use href={iconSrc} />
|
||||
</svg>
|
||||
<Icon name={iconSrc} />
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"@types/react": "^19",
|
||||
|
||||
@@ -1,2 +1,14 @@
|
||||
import '../src/index.css';
|
||||
import './global.css';
|
||||
import Icons from '../assets/icons/icons.svg?react';
|
||||
|
||||
import type { GlobalProvider } from '@ladle/react';
|
||||
|
||||
export const Provider: GlobalProvider = ({ children }) => {
|
||||
return (
|
||||
<div>
|
||||
<Icons style={{ display: 'none' }} />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="15" y="2" width="2" height="26" />
|
||||
<rect class="cls-1" x="13.21" y="23.28" width="14.14" height="2.02"
|
||||
transform="translate(-11.23 21.46) rotate(-45)" />
|
||||
<rect class="cls-1" x="10.7" y="17.21" width="2.02" height="14.14"
|
||||
transform="translate(-13.74 15.4) rotate(-45)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 540 B |
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="11.17" y="2" width="1.67" height="18.33" />
|
||||
<rect class="cls-1" x="9.68" y="16.4" width="11.78" height="1.68"
|
||||
transform="translate(-7.63 16.06) rotate(-45)" />
|
||||
<rect class="cls-1" x="7.59" y="11.35" width="1.68" height="11.79"
|
||||
transform="translate(-9.72 11.01) rotate(-45)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 546 B |
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="7.5" y="1" width="1" height="13" />
|
||||
<rect class="cls-1" x="6.61" y="11.35" width="7.07" height="1.01"
|
||||
transform="translate(-5.41 10.64) rotate(-45)" />
|
||||
<rect class="cls-1" x="5.35" y="8.32" width="1.01" height="7.07"
|
||||
transform="translate(-6.67 7.61) rotate(-45)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 535 B |
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="15" y="4" width="2" height="26" />
|
||||
<rect class="cls-1" x="4.64" y="6.7" width="14.14" height="2.02"
|
||||
transform="translate(-2.02 10.54) rotate(-45)" />
|
||||
<rect class="cls-1" x="19.28" y=".64" width="2.02" height="14.14"
|
||||
transform="translate(.49 16.6) rotate(-45)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 532 B |
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="11.17" y="3.67" width="1.67" height="18.33" />
|
||||
<rect class="cls-1" x="2.54" y="5.92" width="11.78" height="1.68"
|
||||
transform="translate(-2.31 7.94) rotate(-45)" />
|
||||
<rect class="cls-1" x="14.73" y=".87" width="1.68" height="11.79"
|
||||
transform="translate(-.22 12.99) rotate(-45)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 546 B |
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="7.5" y="2" width="1" height="13" />
|
||||
<rect class="cls-1" x="2.32" y="3.64" width="7.07" height="1.01"
|
||||
transform="translate(-1.21 5.36) rotate(-45)" />
|
||||
<rect class="cls-1" x="9.64" y=".61" width="1.01" height="7.07"
|
||||
transform="translate(.04 8.39) rotate(-45)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 530 B |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M5.76,18.69l-2.07,6.28H1.02L7.84,5h3.08l6.82,19.97h-2.76l-2.13-6.28h-7.08ZM12.34,16.68l-1.99-5.75c-.44-1.3-.74-2.49-1.04-3.65h-.06c-.3,1.16-.59,2.4-1.01,3.62l-1.96,5.78h6.05Z" />
|
||||
<path class="cls-1"
|
||||
d="M30.77,21.31c0,1.22.06,2.41.21,3.37h-2.34l-.21-1.77h-.09c-.8,1.1-2.34,2.09-4.39,2.09-2.9,0-4.39-2-4.39-4.04,0-3.4,3.08-5.26,8.62-5.23v-.29c0-1.13-.33-3.25-3.26-3.22-1.36,0-2.76.38-3.76,1.05l-.59-1.71c1.19-.73,2.93-1.22,4.74-1.22,4.39,0,5.45,2.93,5.45,5.72v5.26ZM28.25,17.51c-2.84-.06-6.08.43-6.08,3.17,0,1.68,1.13,2.44,2.43,2.44,1.9,0,3.11-1.16,3.53-2.35.09-.29.12-.58.12-.81v-2.44Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 856 B |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M4.48,14.37l-1.52,4.61h-1.96L6.01,4.31h2.26l5.01,14.67h-2.02l-1.57-4.61h-5.2ZM9.31,12.89l-1.46-4.22c-.33-.96-.54-1.83-.76-2.68h-.04c-.22.85-.44,1.76-.74,2.65l-1.44,4.24h4.44Z" />
|
||||
<path class="cls-1"
|
||||
d="M22.85,16.29c0,.9.04,1.77.15,2.47h-1.72l-.15-1.3h-.07c-.59.81-1.72,1.53-3.22,1.53-2.13,0-3.22-1.47-3.22-2.96,0-2.5,2.26-3.86,6.33-3.84v-.21c0-.83-.24-2.39-2.39-2.37-1,0-2.02.28-2.76.77l-.44-1.26c.87-.53,2.15-.9,3.48-.9,3.22,0,4,2.15,4,4.2v3.86ZM21,13.5c-2.09-.04-4.46.32-4.46,2.32,0,1.24.83,1.79,1.78,1.79,1.39,0,2.29-.85,2.59-1.73.07-.21.09-.43.09-.6v-1.79Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 832 B |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M2.53,9.63l-1.11,3.36H0L3.64,2.32h1.65l3.64,10.67h-1.47l-1.14-3.36h-3.78ZM6.05,8.55l-1.06-3.07c-.24-.7-.4-1.33-.55-1.95h-.03c-.16.62-.32,1.28-.54,1.93l-1.04,3.09h3.23Z" />
|
||||
<path class="cls-1"
|
||||
d="M15.89,11.03c0,.65.03,1.29.11,1.8h-1.25l-.11-.95h-.05c-.43.59-1.25,1.12-2.34,1.12-1.55,0-2.34-1.07-2.34-2.16,0-1.81,1.65-2.81,4.61-2.79v-.15c0-.6-.17-1.74-1.74-1.72-.73,0-1.47.2-2.01.56l-.32-.91c.63-.39,1.57-.65,2.53-.65,2.34,0,2.91,1.57,2.91,3.06v2.81ZM14.54,9c-1.52-.03-3.24.23-3.24,1.69,0,.9.6,1.3,1.3,1.3,1.01,0,1.66-.62,1.88-1.26.05-.15.06-.31.06-.43v-1.3Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 828 B |
@@ -1,11 +1,36 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol id="icon-sort-unknown" viewBox="0 0 24 24" fill="currentColor">
|
||||
<!-- SORTING ICONS -->
|
||||
<symbol id="icon-sort-unknown" 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" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-sort-unknown_m" 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"
|
||||
|
||||
<symbol id="icon-sort-unknown_sm" 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" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-sort-desc" 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" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-sort-desc_m" 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" />
|
||||
@@ -13,16 +38,265 @@
|
||||
<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">
|
||||
|
||||
<symbol id="icon-sort-desc_sm" 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" />
|
||||
</symbol>
|
||||
|
||||
|
||||
<symbol id="icon-sort-asc" 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" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-sort-asc_m" 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">
|
||||
|
||||
<symbol id="icon-sort-asc_sm" 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" />
|
||||
</symbol>
|
||||
<!-- SORTING ICONS END -->
|
||||
|
||||
<!-- CROSS ICON (ONLY ONE SIZE)-->
|
||||
<symbol id="icon-cross_m" 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>
|
||||
<!-- CROSS ICON END -->
|
||||
|
||||
<!-- REPLACE ICONS -->
|
||||
<symbol id="icon-replace_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path
|
||||
d="M10.03,1h1.04v2.39h.02c.24-.42.68-.69,1.3-.69.95,0,1.61.79,1.61,1.93,0,1.36-.86,2.04-1.71,2.04-.55,0-.99-.21-1.28-.71h-.02l-.04.62h-.95c.02-.26.03-.64.03-.98V1ZM11.06,4.97c0,.07,0,.13.03.19.11.37.48.62.93.62.65,0,1.03-.45,1.03-1.12,0-.59-.35-1.09-1.02-1.09-.41,0-.81.25-.93.65-.02.07-.04.14-.04.22v.52Z" />
|
||||
<path
|
||||
d="M8.99,13.78c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.4-1.04,1.19,0,.88.51,1.13,1.02,1.13.39,0,.77-.08.97-.17v.8Z" />
|
||||
<path d="M13,9v6H3v-6h10M14,8H2v8h12V8h0Z" />
|
||||
<path
|
||||
d="M5,5h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
|
||||
<polygon points="4.5 6 3 4 6 4 4.5 6" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-replace_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M15.62.88h1.64v3.75h.02c.38-.67,1.07-1.09,2.04-1.09,1.49,0,2.53,1.24,2.53,3.04,0,2.14-1.36,3.2-2.69,3.2-.86,0-1.56-.33-2.01-1.11h-.02l-.06.98h-1.49c.02-.41.05-1.01.05-1.54V.88ZM17.23,7.12c0,.1.01.21.04.3.18.58.75.98,1.46.98,1.03,0,1.62-.71,1.62-1.77,0-.92-.55-1.71-1.6-1.71-.65,0-1.27.4-1.47,1.03-.03.1-.06.22-.06.35v.82Z" />
|
||||
<path
|
||||
d="M13.98,19.4c-.28.14-.91.35-1.72.35-1.8,0-2.98-1.22-2.98-3.05s1.26-3.19,3.21-3.19c.64,0,1.21.16,1.51.32v1.29c-.27-.14-.91-.36-1.51-.36-.93,0-1.64.64-1.64,1.87,0,1.38.81,1.77,1.6,1.77.62,0,1.21-.13,1.52-.26v1.26Z" />
|
||||
<path d="M20.29,11.88v9.43H4.57v-9.43h15.71M21.86,10.31H3v12.57h18.86v-12.57h0Z" />
|
||||
<path
|
||||
d="M7.71,7.17h-1.57v-2.34c0-2.18,1.77-3.95,3.95-3.95h3.91v1.57h-3.91c-1.31,0-2.37,1.07-2.37,2.37v2.34Z" />
|
||||
<polygon points="6.93 8.74 4.57 5.6 9.29 5.6 6.93 8.74" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-replace" viewBox="0 0 32 32" fill="currentColor">
|
||||
<path
|
||||
d="M20.06,2h2.09v4.78h.03c.49-.85,1.37-1.38,2.59-1.38,1.9,0,3.22,1.57,3.22,3.87,0,2.72-1.73,4.07-3.43,4.07-1.1,0-1.98-.42-2.56-1.41h-.03l-.08,1.24h-1.9c.03-.52.06-1.29.06-1.96V2ZM22.11,9.94c0,.13.01.27.06.39.22.74.95,1.24,1.85,1.24,1.3,0,2.06-.91,2.06-2.25,0-1.17-.7-2.17-2.03-2.17-.83,0-1.61.51-1.87,1.3-.04.13-.07.28-.07.45v1.04Z" />
|
||||
<path
|
||||
d="M17.97,25.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.81-2.09,2.38,0,1.76,1.03,2.25,2.04,2.25.79,0,1.54-.16,1.94-.33v1.6Z" />
|
||||
<path d="M26,16v12H6v-12h20M28,14H4v16h24V14h0Z" />
|
||||
<path
|
||||
d="M10,10h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
|
||||
<polygon points="9 12 6 8 12 8 9 12" />
|
||||
</symbol>
|
||||
<!-- REPLACE ICONS END -->
|
||||
|
||||
<!-- REPLACE ALL ICONS -->
|
||||
<symbol id="icon-replace-all" viewBox="0 0 32 32" fill="currentColor">
|
||||
<path
|
||||
d="M13,24.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM11.59,23.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
|
||||
<path
|
||||
d="M22.05,8.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM20.64,7.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
|
||||
<path
|
||||
d="M23.06,1.07h1.83v4.33h.03c.43-.77,1.2-1.25,2.27-1.25,1.66,0,2.82,1.42,2.82,3.5,0,2.46-1.51,3.69-3,3.69-.96,0-1.73-.38-2.24-1.28h-.03l-.07,1.12h-1.66c.03-.47.06-1.17.06-1.78V1.07ZM24.85,8.26c0,.12.01.24.05.35.2.67.84,1.13,1.62,1.13,1.14,0,1.8-.82,1.8-2.03,0-1.06-.61-1.97-1.78-1.97-.72,0-1.41.46-1.63,1.18-.04.12-.06.25-.06.4v.94Z" />
|
||||
<path
|
||||
d="M20.97,26.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.77-2.09,2.34,0,1.76,1.03,2.29,2.04,2.29.79,0,1.54-.16,1.94-.33v1.6Z" />
|
||||
<path d="M24,18v10H4v-10h20M26,16H2v14h24v-14h0Z" />
|
||||
<polygon points="9 12 9 14 28 14 28 28 30 28 30 12 9 12" />
|
||||
<g>
|
||||
<path
|
||||
d="M6,13h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
|
||||
<polygon points="5 15 2 11 8 11 5 15" />
|
||||
</g>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-replace-all_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M9.25,19.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM8.19,17.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
|
||||
<path
|
||||
d="M16.04,7.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM14.98,5.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
|
||||
<path
|
||||
d="M16.79,1.07h1.37v3.24h.02c.32-.58.9-.94,1.7-.94,1.25,0,2.12,1.07,2.12,2.63,0,1.85-1.13,2.76-2.25,2.76-.72,0-1.3-.29-1.68-.96h-.02l-.05.84h-1.25c.02-.35.04-.88.04-1.33V1.07ZM18.14,6.46c0,.09,0,.18.04.26.15.5.63.84,1.22.84.86,0,1.35-.61,1.35-1.53,0-.8-.46-1.48-1.34-1.48-.54,0-1.06.34-1.22.89-.03.09-.05.19-.05.3v.7Z" />
|
||||
<path
|
||||
d="M15.23,20.19c-.27.13-.87.33-1.64.33-1.72,0-2.84-1.17-2.84-2.91s1.2-3.04,3.07-3.04c.61,0,1.16.15,1.44.31v1.23c-.25-.13-.87-.34-1.44-.34-.89,0-1.57.58-1.57,1.76,0,1.32.77,1.72,1.53,1.72.59,0,1.16-.12,1.45-.25v1.2Z" />
|
||||
<path d="M17.5,13.77v7.5H2.5v-7.5h15M19,12.27H1v10.5h18v-10.5h0Z" />
|
||||
<polygon
|
||||
points="6.25 9.27 6.25 10.77 20.5 10.77 20.5 21.27 22 21.27 22 9.27 6.25 9.27" />
|
||||
<g>
|
||||
<path
|
||||
d="M4,10.02h-1.5v-2.23c0-2.08,1.69-3.77,3.77-3.77h3.73v1.5h-3.73c-1.25,0-2.27,1.02-2.27,2.27v2.23Z" />
|
||||
<polygon points="3.25 11.52 1 8.52 5.5 8.52 3.25 11.52" />
|
||||
</g>
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-replace-all_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path
|
||||
d="M6.5,13.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM5.8,12.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
|
||||
<path
|
||||
d="M11.02,4.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM10.32,3.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
|
||||
<path
|
||||
d="M11.53.54h.91v2.16h.01c.21-.38.6-.63,1.13-.63.83,0,1.41.71,1.41,1.75,0,1.23-.76,1.84-1.5,1.84-.48,0-.87-.19-1.12-.64h-.01l-.03.56h-.83c.01-.23.03-.58.03-.89V.54ZM12.43,4.13c0,.06,0,.12.02.17.1.33.42.56.81.56.57,0,.9-.41.9-1.02,0-.53-.31-.98-.89-.98-.36,0-.71.23-.82.59-.02.06-.03.13-.03.2v.47Z" />
|
||||
<path
|
||||
d="M10.48,14.28c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.38-1.04,1.17,0,.88.51,1.15,1.02,1.15.39,0,.77-.08.97-.17v.8Z" />
|
||||
<path d="M12,10v5H2v-5h10M13,9H1v7h12v-7h0Z" />
|
||||
<polygon points="4.5 7 4.5 8 14 8 14 15 15 15 15 7 4.5 7" />
|
||||
<g>
|
||||
<path
|
||||
d="M3,7h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
|
||||
<polygon points="2.5 8 1 6 4 6 2.5 8" />
|
||||
</g>
|
||||
</symbol>
|
||||
<!-- REPLACE ALL ICONS END -->
|
||||
|
||||
<!-- REGEX ICONS -->
|
||||
<symbol id="icon-regex" viewBox="0 0 32 32" fill="currentColor">
|
||||
<rect x="20.04" y="2" width="2" height="22" />
|
||||
<rect x="20.04" y="2" width="2" height="22"
|
||||
transform="translate(-.9 24.42) rotate(-59.21)" />
|
||||
<rect x="10.04" y="12" width="22" height="2"
|
||||
transform="translate(-3.69 13.25) rotate(-32.29)" />
|
||||
<rect x="2.04" y="22" width="8" height="8" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-regex_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<rect x="14.46" y="2" width="1.38" height="15.14" />
|
||||
<rect x="14.46" y="2" width="1.38" height="15.14"
|
||||
transform="translate(-.83 17.68) rotate(-59.21)" />
|
||||
<rect x="7.58" y="8.88" width="15.14" height="1.38"
|
||||
transform="translate(-2.77 9.57) rotate(-32.29)" />
|
||||
<rect x="2.08" y="16.5" width="5.5" height="5.5" />
|
||||
</symbol>
|
||||
<symbol id="icon-regex_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<rect x="10" y="1" width="1" height="11" />
|
||||
<rect x="10" y="1" width="1" height="11"
|
||||
transform="translate(-.46 12.19) rotate(-59.21)" />
|
||||
<rect x="5" y="6" width="11" height="1"
|
||||
transform="translate(-1.85 6.61) rotate(-32.29)" />
|
||||
<rect x="1" y="11" width="4" height="4" />
|
||||
</symbol>
|
||||
<!-- REGEX ICONS END -->
|
||||
|
||||
<!-- MATCH WORD ICONS -->
|
||||
<symbol id="icon-match-word" viewBox="0 0 32 32" fill="currentColor">
|
||||
<path
|
||||
d="M13.82,20.03c0,1.12.05,2.22.18,3.1h-2.01l-.18-1.63h-.08c-.69,1.02-2.01,1.92-3.76,1.92-2.49,0-3.76-1.84-3.76-3.71,0-3.13,2.64-4.84,7.4-4.81v-.27c0-1.04-.28-2.99-2.8-2.97-1.17,0-2.36.35-3.23.96l-.51-1.58c1.02-.67,2.52-1.12,4.07-1.12,3.76,0,4.68,2.7,4.68,5.26v4.84ZM11.66,16.53c-2.44-.05-5.21.4-5.21,2.91,0,1.55.97,2.24,2.08,2.24,1.63,0,2.67-1.07,3.02-2.16.08-.27.1-.53.1-.75v-2.24Z" />
|
||||
<path
|
||||
d="M17.11,5h2.44v7.28h-.75c.87-1.44,2.44-2.35,4.62-2.35,3.39,0,5.75,2.67,5.75,6.57,0,4.62-3.08,6.92-6.11,6.92-1.96,0-2.72-.72-3.76-2.4h-.3l.1,2.11h-2.1c.06-.88.11-2.19.11-3.34V5ZM19.38,17.94c0,.29.08.59.17.85.45,1.63,1.21,2.75,3,2.75,2.61,0,4.12-2,4.12-4.97,0-2.59-1.4-4.81-4.06-4.81-1.65,0-2.55,1.12-3.06,2.89-.08.29-.17.61-.17.99v2.3Z" />
|
||||
<rect x="1" y="23" width="2" height="4" />
|
||||
<rect x="29" y="23" width="2" height="4" />
|
||||
<rect x="1.67" y="25" width="29.33" height="2" />
|
||||
</symbol>
|
||||
<symbol id="icon-match-word_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M10.41,14.93c0,.82.04,1.61.13,2.25h-1.47l-.13-1.18h-.06c-.5.74-1.47,1.4-2.76,1.4-1.83,0-2.76-1.34-2.76-2.7,0-2.27,1.94-3.52,5.43-3.5v-.19c0-.76-.2-2.18-2.05-2.16-.86,0-1.73.25-2.37.7l-.37-1.15c.75-.49,1.85-.82,2.98-.82,2.76,0,3.43,1.96,3.43,3.83v3.52ZM8.82,12.38c-1.79-.04-3.82.29-3.82,2.12,0,1.13.71,1.63,1.53,1.63,1.19,0,1.96-.78,2.22-1.57.06-.19.07-.39.07-.54v-1.63Z" />
|
||||
<path
|
||||
d="M12.82,4h1.79v5.29h-.55c.64-1.05,1.79-1.71,3.39-1.71,2.49,0,4.21,1.94,4.21,4.78,0,3.36-2.26,5.03-4.48,5.03-1.44,0-2-.52-2.76-1.75h-.22l.08,1.54h-1.54c.04-.64.08-1.59.08-2.43V4ZM14.49,13.41c0,.21.06.43.12.62.33,1.19.89,2,2.2,2,1.91,0,3.02-1.46,3.02-3.61,0-1.88-1.03-3.5-2.98-3.5-1.21,0-1.87.82-2.24,2.1-.06.21-.12.45-.12.72v1.67Z" />
|
||||
<rect x="1" y="17" width="1.47" height="3" />
|
||||
<rect x="21.54" y="17" width="1.47" height="3" />
|
||||
<rect x="1.49" y="18.55" width="21.52" height="1.45" />
|
||||
</symbol>
|
||||
<symbol id="icon-match-word_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path
|
||||
d="M6.9,10.2c0,.61.03,1.21.1,1.69h-1.15l-.1-.89h-.04c-.39.55-1.15,1.05-2.16,1.05-1.43,0-2.16-1.01-2.16-2.03,0-1.71,1.52-2.64,4.24-2.62v-.15c0-.57-.16-1.63-1.6-1.62-.67,0-1.35.19-1.85.52l-.29-.86c.58-.36,1.44-.61,2.33-.61,2.16,0,2.68,1.47,2.68,2.87v2.64ZM5.66,8.29c-1.4-.03-2.99.22-2.99,1.59,0,.85.55,1.22,1.19,1.22.93,0,1.53-.58,1.73-1.18.04-.15.06-.29.06-.41v-1.22Z" />
|
||||
<path
|
||||
d="M8.73,2h1.27v3.97h-.39c.45-.79,1.27-1.28,2.4-1.28,1.76,0,2.99,1.46,2.99,3.58,0,2.52-1.6,3.77-3.18,3.77-1.02,0-1.42-.39-1.95-1.31h.13l-.23,1.15h-1.09c.03-.48.06-1.19.06-1.82V2ZM9.93,9.06c0,.16.01.32.06.47.23.89.64,1.5,1.58,1.5,1.35,0,2.14-1.09,2.14-2.71,0-1.41-.73-2.62-2.11-2.62-.86,0-1.33.61-1.59,1.57-.04.16-.07.33-.07.54v1.25Z" />
|
||||
|
||||
<rect y="12" width="1" height="2" />
|
||||
<rect x="15" y="12.02" width="1" height="1.98" />
|
||||
<rect y="13" width="16" height="1" />
|
||||
</symbol>
|
||||
<!-- MATCH WORD ICONS END -->
|
||||
|
||||
<!-- CASE ICONS -->
|
||||
<symbol id="icon-case" viewBox="0 0 32 32" fill="currentColor">
|
||||
<path
|
||||
d="M5.76,18.69l-2.07,6.28H1.02L7.84,5h3.08l6.82,19.97h-2.76l-2.13-6.28h-7.08ZM12.34,16.68l-1.99-5.75c-.44-1.3-.74-2.49-1.04-3.65h-.06c-.3,1.16-.59,2.4-1.01,3.62l-1.96,5.78h6.05Z" />
|
||||
<path
|
||||
d="M30.77,21.31c0,1.22.06,2.41.21,3.37h-2.34l-.21-1.77h-.09c-.8,1.1-2.34,2.09-4.39,2.09-2.9,0-4.39-2-4.39-4.04,0-3.4,3.08-5.26,8.62-5.23v-.29c0-1.13-.33-3.25-3.26-3.22-1.36,0-2.76.38-3.76,1.05l-.59-1.71c1.19-.73,2.93-1.22,4.74-1.22,4.39,0,5.45,2.93,5.45,5.72v5.26ZM28.25,17.51c-2.84-.06-6.08.43-6.08,3.17,0,1.68,1.13,2.44,2.43,2.44,1.9,0,3.11-1.16,3.53-2.35.09-.29.12-.58.12-.81v-2.44Z" />
|
||||
</symbol>
|
||||
<symbol id="icon-case_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M4.48,14.37l-1.52,4.61h-1.96L6.01,4.31h2.26l5.01,14.67h-2.02l-1.57-4.61h-5.2ZM9.31,12.89l-1.46-4.22c-.33-.96-.54-1.83-.76-2.68h-.04c-.22.85-.44,1.76-.74,2.65l-1.44,4.24h4.44Z" />
|
||||
<path
|
||||
d="M22.85,16.29c0,.9.04,1.77.15,2.47h-1.72l-.15-1.3h-.07c-.59.81-1.72,1.53-3.22,1.53-2.13,0-3.22-1.47-3.22-2.96,0-2.5,2.26-3.86,6.33-3.84v-.21c0-.83-.24-2.39-2.39-2.37-1,0-2.02.28-2.76.77l-.44-1.26c.87-.53,2.15-.9,3.48-.9,3.22,0,4,2.15,4,4.2v3.86ZM21,13.5c-2.09-.04-4.46.32-4.46,2.32,0,1.24.83,1.79,1.78,1.79,1.39,0,2.29-.85,2.59-1.73.07-.21.09-.43.09-.6v-1.79Z" />
|
||||
</symbol>
|
||||
<symbol id="icon-case_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path
|
||||
d="M2.53,9.63l-1.11,3.36H0L3.64,2.32h1.65l3.64,10.67h-1.47l-1.14-3.36h-3.78ZM6.05,8.55l-1.06-3.07c-.24-.7-.4-1.33-.55-1.95h-.03c-.16.62-.32,1.28-.54,1.93l-1.04,3.09h3.23Z" />
|
||||
<path
|
||||
d="M15.89,11.03c0,.65.03,1.29.11,1.8h-1.25l-.11-.95h-.05c-.43.59-1.25,1.12-2.34,1.12-1.55,0-2.34-1.07-2.34-2.16,0-1.81,1.65-2.81,4.61-2.79v-.15c0-.6-.17-1.74-1.74-1.72-.73,0-1.47.2-2.01.56l-.32-.91c.63-.39,1.57-.65,2.53-.65,2.34,0,2.91,1.57,2.91,3.06v2.81ZM14.54,9c-1.52-.03-3.24.23-3.24,1.69,0,.9.6,1.3,1.3,1.3,1.01,0,1.66-.62,1.88-1.26.05-.15.06-.31.06-.43v-1.3Z" />
|
||||
</symbol>
|
||||
<!-- CASE ICONS END -->
|
||||
|
||||
<!-- ARROW ICONS-->
|
||||
<symbol id="icon-arrow-up" viewBox="0 0 32 32" fill="currentColor">
|
||||
<rect x="15" y="4" width="2" height="26" />
|
||||
<rect x="4.64" y="6.7" width="14.14" height="2.02"
|
||||
transform="translate(-2.02 10.54) rotate(-45)" />
|
||||
<rect x="19.28" y=".64" width="2.02" height="14.14"
|
||||
transform="translate(.49 16.6) rotate(-45)" />
|
||||
</symbol>
|
||||
<symbol id="icon-arrow-up_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<rect x="11.17" y="3.67" width="1.67" height="18.33" />
|
||||
<rect x="2.54" y="5.92" width="11.78" height="1.68"
|
||||
transform="translate(-2.31 7.94) rotate(-45)" />
|
||||
<rect x="14.73" y=".87" width="1.68" height="11.79"
|
||||
transform="translate(-.22 12.99) rotate(-45)" />
|
||||
</symbol>
|
||||
<symbol id="icon-arrow-up_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<rect x="7.5" y="2" width="1" height="13" />
|
||||
<rect x="2.32" y="3.64" width="7.07" height="1.01"
|
||||
transform="translate(-1.21 5.36) rotate(-45)" />
|
||||
<rect x="9.64" y=".61" width="1.01" height="7.07"
|
||||
transform="translate(.04 8.39) rotate(-45)" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="icon-arrow-down" viewBox="0 0 32 32" fill="currentColor">
|
||||
<rect x="15" y="2" width="2" height="26" />
|
||||
<rect x="13.21" y="23.28" width="14.14" height="2.02"
|
||||
transform="translate(-11.23 21.46) rotate(-45)" />
|
||||
<rect x="10.7" y="17.21" width="2.02" height="14.14"
|
||||
transform="translate(-13.74 15.4) rotate(-45)" />
|
||||
</symbol>
|
||||
<symbol id="icon-arrow-down_m" viewBox="0 0 24 24" fill="currentColor">
|
||||
<rect x="11.17" y="2" width="1.67" height="18.33" />
|
||||
<rect x="9.68" y="16.4" width="11.78" height="1.68"
|
||||
transform="translate(-7.63 16.06) rotate(-45)" />
|
||||
<rect x="7.59" y="11.35" width="1.68" height="11.79"
|
||||
transform="translate(-9.72 11.01) rotate(-45)" />
|
||||
</symbol>
|
||||
<symbol id="icon-arrow-down_sm" viewBox="0 0 16 16" fill="currentColor">
|
||||
<rect x="7.5" y="1" width="1" height="13" />
|
||||
<rect x="6.61" y="11.35" width="7.07" height="1.01"
|
||||
transform="translate(-5.41 10.64) rotate(-45)" />
|
||||
<rect x="5.35" y="8.32" width="1.01" height="7.07"
|
||||
transform="translate(-6.67 7.61) rotate(-45)" />
|
||||
</symbol>
|
||||
<!-- ARROW ICONS END -->
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M13.82,20.03c0,1.12.05,2.22.18,3.1h-2.01l-.18-1.63h-.08c-.69,1.02-2.01,1.92-3.76,1.92-2.49,0-3.76-1.84-3.76-3.71,0-3.13,2.64-4.84,7.4-4.81v-.27c0-1.04-.28-2.99-2.8-2.97-1.17,0-2.36.35-3.23.96l-.51-1.58c1.02-.67,2.52-1.12,4.07-1.12,3.76,0,4.68,2.7,4.68,5.26v4.84ZM11.66,16.53c-2.44-.05-5.21.4-5.21,2.91,0,1.55.97,2.24,2.08,2.24,1.63,0,2.67-1.07,3.02-2.16.08-.27.1-.53.1-.75v-2.24Z" />
|
||||
<path class="cls-1"
|
||||
d="M17.11,5h2.44v7.28h-.75c.87-1.44,2.44-2.35,4.62-2.35,3.39,0,5.75,2.67,5.75,6.57,0,4.62-3.08,6.92-6.11,6.92-1.96,0-2.72-.72-3.76-2.4h-.3l.1,2.11h-2.1c.06-.88.11-2.19.11-3.34V5ZM19.38,17.94c0,.29.08.59.17.85.45,1.63,1.21,2.75,3,2.75,2.61,0,4.12-2,4.12-4.97,0-2.59-1.4-4.81-4.06-4.81-1.65,0-2.55,1.12-3.06,2.89-.08.29-.17.61-.17.99v2.3Z" />
|
||||
<rect class="cls-1" x="1" y="23" width="2" height="4" />
|
||||
<rect class="cls-1" x="29" y="23" width="2" height="4" />
|
||||
<rect class="cls-1" x="1.67" y="25" width="29.33" height="2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M10.41,14.93c0,.82.04,1.61.13,2.25h-1.47l-.13-1.18h-.06c-.5.74-1.47,1.4-2.76,1.4-1.83,0-2.76-1.34-2.76-2.7,0-2.27,1.94-3.52,5.43-3.5v-.19c0-.76-.2-2.18-2.05-2.16-.86,0-1.73.25-2.37.7l-.37-1.15c.75-.49,1.85-.82,2.98-.82,2.76,0,3.43,1.96,3.43,3.83v3.52ZM8.82,12.38c-1.79-.04-3.82.29-3.82,2.12,0,1.13.71,1.63,1.53,1.63,1.19,0,1.96-.78,2.22-1.57.06-.19.07-.39.07-.54v-1.63Z" />
|
||||
<path class="cls-1"
|
||||
d="M12.82,4h1.79v5.29h-.55c.64-1.05,1.79-1.71,3.39-1.71,2.49,0,4.21,1.94,4.21,4.78,0,3.36-2.26,5.03-4.48,5.03-1.44,0-2-.52-2.76-1.75h-.22l.08,1.54h-1.54c.04-.64.08-1.59.08-2.43V4ZM14.49,13.41c0,.21.06.43.12.62.33,1.19.89,2,2.2,2,1.91,0,3.02-1.46,3.02-3.61,0-1.88-1.03-3.5-2.98-3.5-1.21,0-1.87.82-2.24,2.1-.06.21-.12.45-.12.72v1.67Z" />
|
||||
<rect class="cls-1" x="1" y="17" width="1.47" height="3" />
|
||||
<rect class="cls-1" x="21.54" y="17" width="1.47" height="3" />
|
||||
<rect class="cls-1" x="1.49" y="18.55" width="21.52" height="1.45" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g>
|
||||
<path class="cls-1"
|
||||
d="M6.9,10.2c0,.61.03,1.21.1,1.69h-1.15l-.1-.89h-.04c-.39.55-1.15,1.05-2.16,1.05-1.43,0-2.16-1.01-2.16-2.03,0-1.71,1.52-2.64,4.24-2.62v-.15c0-.57-.16-1.63-1.6-1.62-.67,0-1.35.19-1.85.52l-.29-.86c.58-.36,1.44-.61,2.33-.61,2.16,0,2.68,1.47,2.68,2.87v2.64ZM5.66,8.29c-1.4-.03-2.99.22-2.99,1.59,0,.85.55,1.22,1.19,1.22.93,0,1.53-.58,1.73-1.18.04-.15.06-.29.06-.41v-1.22Z" />
|
||||
<path class="cls-1"
|
||||
d="M8.73,2h1.27v3.97h-.39c.45-.79,1.27-1.28,2.4-1.28,1.76,0,2.99,1.46,2.99,3.58,0,2.52-1.6,3.77-3.18,3.77-1.02,0-1.42-.39-1.95-1.31h.13l-.23,1.15h-1.09c.03-.48.06-1.19.06-1.82V2ZM9.93,9.06c0,.16.01.32.06.47.23.89.64,1.5,1.58,1.5,1.35,0,2.14-1.09,2.14-2.71,0-1.41-.73-2.62-2.11-2.62-.86,0-1.33.61-1.59,1.57-.04.16-.07.33-.07.54v1.25Z" />
|
||||
</g>
|
||||
<rect class="cls-1" y="12" width="1" height="2" />
|
||||
<rect class="cls-1" x="15" y="12.02" width="1" height="1.98" />
|
||||
<rect class="cls-1" y="13" width="16" height="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="20.04" y="2" width="2" height="22" />
|
||||
<rect class="cls-1" x="20.04" y="2" width="2" height="22"
|
||||
transform="translate(-.9 24.42) rotate(-59.21)" />
|
||||
<rect class="cls-1" x="10.04" y="12" width="22" height="2"
|
||||
transform="translate(-3.69 13.25) rotate(-32.29)" />
|
||||
<rect class="cls-1" x="2.04" y="22" width="8" height="8" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 590 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="14.46" y="2" width="1.38" height="15.14" />
|
||||
<rect class="cls-1" x="14.46" y="2" width="1.38" height="15.14"
|
||||
transform="translate(-.83 17.68) rotate(-59.21)" />
|
||||
<rect class="cls-1" x="7.58" y="8.88" width="15.14" height="1.38"
|
||||
transform="translate(-2.77 9.57) rotate(-32.29)" />
|
||||
<rect class="cls-1" x="2.08" y="16.5" width="5.5" height="5.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 615 B |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="cls-1" x="10" y="1" width="1" height="11" />
|
||||
<rect class="cls-1" x="10" y="1" width="1" height="11"
|
||||
transform="translate(-.46 12.19) rotate(-59.21)" />
|
||||
<rect class="cls-1" x="5" y="6" width="11" height="1"
|
||||
transform="translate(-1.85 6.61) rotate(-32.29)" />
|
||||
<rect class="cls-1" x="1" y="11" width="4" height="4" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 576 B |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M13,24.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM11.59,23.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
|
||||
<path class="cls-1"
|
||||
d="M22.05,8.99c0,.67-.03,1.49.05,2.01h-1.25l-.11-1.14h-.05c-.43.6-1.25,1.14-2.34,1.14-1.55,0-2.34-1.09-2.34-2.2,0-1.85,1.65-2.87,4.61-2.85v-.16c0-.62-.17-1.33-1.74-1.31-.73,0-1.47.3-2.01.66l-.79-1.19c.63-.4,2.05-.95,3.01-.95,2.34,0,2.98,1.6,2.98,3.12v2.87ZM20.64,7.14c-1.21-.03-3.03.19-3.03,1.38,0,.73.39,1.06,1.48,1.06.81,0,1.33-.51,1.51-1.02.04-.13.05-.25.05-.35v-1.06Z" />
|
||||
<path class="cls-1"
|
||||
d="M23.06,1.07h1.83v4.33h.03c.43-.77,1.2-1.25,2.27-1.25,1.66,0,2.82,1.42,2.82,3.5,0,2.46-1.51,3.69-3,3.69-.96,0-1.73-.38-2.24-1.28h-.03l-.07,1.12h-1.66c.03-.47.06-1.17.06-1.78V1.07ZM24.85,8.26c0,.12.01.24.05.35.2.67.84,1.13,1.62,1.13,1.14,0,1.8-.82,1.8-2.03,0-1.06-.61-1.97-1.78-1.97-.72,0-1.41.46-1.63,1.18-.04.12-.06.25-.06.4v.94Z" />
|
||||
<path class="cls-1"
|
||||
d="M20.97,26.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.77-2.09,2.34,0,1.76,1.03,2.29,2.04,2.29.79,0,1.54-.16,1.94-.33v1.6Z" />
|
||||
<path class="cls-1" d="M24,18v10H4v-10h20M26,16H2v14h24v-14h0Z" />
|
||||
<polygon class="cls-1" points="9 12 9 14 28 14 28 28 30 28 30 12 9 12" />
|
||||
<g>
|
||||
<path class="cls-1"
|
||||
d="M6,13h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
|
||||
<polygon class="cls-1" points="5 15 2 11 8 11 5 15" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M9.25,19.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM8.19,17.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
|
||||
<path class="cls-1"
|
||||
d="M16.04,7.01c0,.5-.02,1.12.04,1.51h-.94l-.08-.86h-.04c-.32.45-.94.86-1.76.86-1.16,0-1.76-.82-1.76-1.65,0-1.39,1.24-2.15,3.46-2.14v-.12c0-.46-.13-1-1.31-.98-.55,0-1.1.22-1.51.5l-.6-.89c.48-.3,1.53-.71,2.26-.71,1.76,0,2.23,1.2,2.23,2.34v2.15ZM14.98,5.63c-.91-.02-2.28.14-2.28,1.03,0,.55.29.8,1.11.8.61,0,1-.38,1.13-.77.03-.09.04-.19.04-.27v-.8Z" />
|
||||
<path class="cls-1"
|
||||
d="M16.79,1.07h1.37v3.24h.02c.32-.58.9-.94,1.7-.94,1.25,0,2.12,1.07,2.12,2.63,0,1.85-1.13,2.76-2.25,2.76-.72,0-1.3-.29-1.68-.96h-.02l-.05.84h-1.25c.02-.35.04-.88.04-1.33V1.07ZM18.14,6.46c0,.09,0,.18.04.26.15.5.63.84,1.22.84.86,0,1.35-.61,1.35-1.53,0-.8-.46-1.48-1.34-1.48-.54,0-1.06.34-1.22.89-.03.09-.05.19-.05.3v.7Z" />
|
||||
<path class="cls-1"
|
||||
d="M15.23,20.19c-.27.13-.87.33-1.64.33-1.72,0-2.84-1.17-2.84-2.91s1.2-3.04,3.07-3.04c.61,0,1.16.15,1.44.31v1.23c-.25-.13-.87-.34-1.44-.34-.89,0-1.57.58-1.57,1.76,0,1.32.77,1.72,1.53,1.72.59,0,1.16-.12,1.45-.25v1.2Z" />
|
||||
<path class="cls-1" d="M17.5,13.77v7.5H2.5v-7.5h15M19,12.27H1v10.5h18v-10.5h0Z" />
|
||||
<polygon class="cls-1"
|
||||
points="6.25 9.27 6.25 10.77 20.5 10.77 20.5 21.27 22 21.27 22 9.27 6.25 9.27" />
|
||||
<g>
|
||||
<path class="cls-1"
|
||||
d="M4,10.02h-1.5v-2.23c0-2.08,1.69-3.77,3.77-3.77h3.73v1.5h-3.73c-1.25,0-2.27,1.02-2.27,2.27v2.23Z" />
|
||||
<polygon class="cls-1" points="3.25 11.52 1 8.52 5.5 8.52 3.25 11.52" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M6.5,13.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM5.8,12.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
|
||||
<path class="cls-1"
|
||||
d="M11.02,4.49c0,.33-.01.74.02,1.01h-.63l-.06-.57h-.02c-.21.3-.63.57-1.17.57-.78,0-1.17-.55-1.17-1.1,0-.93.82-1.43,2.3-1.43v-.08c0-.31-.09-.66-.87-.66-.36,0-.74.15-1.01.33l-.4-.59c.32-.2,1.02-.48,1.51-.48,1.17,0,1.49.8,1.49,1.56v1.43ZM10.32,3.57c-.61-.01-1.52.09-1.52.69,0,.37.19.53.74.53.4,0,.66-.25.75-.51.02-.06.03-.13.03-.18v-.53Z" />
|
||||
<path class="cls-1"
|
||||
d="M11.53.54h.91v2.16h.01c.21-.38.6-.63,1.13-.63.83,0,1.41.71,1.41,1.75,0,1.23-.76,1.84-1.5,1.84-.48,0-.87-.19-1.12-.64h-.01l-.03.56h-.83c.01-.23.03-.58.03-.89V.54ZM12.43,4.13c0,.06,0,.12.02.17.1.33.42.56.81.56.57,0,.9-.41.9-1.02,0-.53-.31-.98-.89-.98-.36,0-.71.23-.82.59-.02.06-.03.13-.03.2v.47Z" />
|
||||
<path class="cls-1"
|
||||
d="M10.48,14.28c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.38-1.04,1.17,0,.88.51,1.15,1.02,1.15.39,0,.77-.08.97-.17v.8Z" />
|
||||
<path class="cls-1" d="M12,10v5H2v-5h10M13,9H1v7h12v-7h0Z" />
|
||||
<polygon class="cls-1" points="4.5 7 4.5 8 14 8 14 15 15 15 15 7 4.5 7" />
|
||||
<g>
|
||||
<path class="cls-1"
|
||||
d="M3,7h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
|
||||
<polygon class="cls-1" points="2.5 8 1 6 4 6 2.5 8" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M20.06,2h2.09v4.78h.03c.49-.85,1.37-1.38,2.59-1.38,1.9,0,3.22,1.57,3.22,3.87,0,2.72-1.73,4.07-3.43,4.07-1.1,0-1.98-.42-2.56-1.41h-.03l-.08,1.24h-1.9c.03-.52.06-1.29.06-1.96V2ZM22.11,9.94c0,.13.01.27.06.39.22.74.95,1.24,1.85,1.24,1.3,0,2.06-.91,2.06-2.25,0-1.17-.7-2.17-2.03-2.17-.83,0-1.61.51-1.87,1.3-.04.13-.07.28-.07.45v1.04Z" />
|
||||
<path class="cls-1"
|
||||
d="M17.97,25.56c-.36.17-1.16.44-2.19.44-2.3,0-3.79-1.56-3.79-3.88s1.6-4.06,4.09-4.06c.82,0,1.54.2,1.92.41v1.65c-.34-.17-1.16-.46-1.92-.46-1.19,0-2.09.81-2.09,2.38,0,1.76,1.03,2.25,2.04,2.25.79,0,1.54-.16,1.94-.33v1.6Z" />
|
||||
<path class="cls-1" d="M26,16v12H6v-12h20M28,14H4v16h24V14h0Z" />
|
||||
<path class="cls-1"
|
||||
d="M10,10h-2v-2.98c0-2.77,2.25-5.02,5.02-5.02h4.98v2h-4.98c-1.67,0-3.02,1.36-3.02,3.02v2.98Z" />
|
||||
<polygon class="cls-1" points="9 12 6 8 12 8 9 12" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M15.62.88h1.64v3.75h.02c.38-.67,1.07-1.09,2.04-1.09,1.49,0,2.53,1.24,2.53,3.04,0,2.14-1.36,3.2-2.69,3.2-.86,0-1.56-.33-2.01-1.11h-.02l-.06.98h-1.49c.02-.41.05-1.01.05-1.54V.88ZM17.23,7.12c0,.1.01.21.04.3.18.58.75.98,1.46.98,1.03,0,1.62-.71,1.62-1.77,0-.92-.55-1.71-1.6-1.71-.65,0-1.27.4-1.47,1.03-.03.1-.06.22-.06.35v.82Z" />
|
||||
<path class="cls-1"
|
||||
d="M13.98,19.4c-.28.14-.91.35-1.72.35-1.8,0-2.98-1.22-2.98-3.05s1.26-3.19,3.21-3.19c.64,0,1.21.16,1.51.32v1.29c-.27-.14-.91-.36-1.51-.36-.93,0-1.64.64-1.64,1.87,0,1.38.81,1.77,1.6,1.77.62,0,1.21-.13,1.52-.26v1.26Z" />
|
||||
<path class="cls-1" d="M20.29,11.88v9.43H4.57v-9.43h15.71M21.86,10.31H3v12.57h18.86v-12.57h0Z" />
|
||||
<path class="cls-1"
|
||||
d="M7.71,7.17h-1.57v-2.34c0-2.18,1.77-3.95,3.95-3.95h3.91v1.57h-3.91c-1.31,0-2.37,1.07-2.37,2.37v2.34Z" />
|
||||
<polygon class="cls-1" points="6.93 8.74 4.57 5.6 9.29 5.6 6.93 8.74" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path class="cls-1"
|
||||
d="M10.03,1h1.04v2.39h.02c.24-.42.68-.69,1.3-.69.95,0,1.61.79,1.61,1.93,0,1.36-.86,2.04-1.71,2.04-.55,0-.99-.21-1.28-.71h-.02l-.04.62h-.95c.02-.26.03-.64.03-.98V1ZM11.06,4.97c0,.07,0,.13.03.19.11.37.48.62.93.62.65,0,1.03-.45,1.03-1.12,0-.59-.35-1.09-1.02-1.09-.41,0-.81.25-.93.65-.02.07-.04.14-.04.22v.52Z" />
|
||||
<path class="cls-1"
|
||||
d="M8.99,13.78c-.18.09-.58.22-1.09.22-1.15,0-1.89-.78-1.89-1.94s.8-2.03,2.04-2.03c.41,0,.77.1.96.2v.82c-.17-.09-.58-.23-.96-.23-.59,0-1.04.4-1.04,1.19,0,.88.51,1.13,1.02,1.13.39,0,.77-.08.97-.17v.8Z" />
|
||||
<path class="cls-1" d="M13,9v6H3v-6h10M14,8H2v8h12V8h0Z" />
|
||||
<path class="cls-1"
|
||||
d="M5,5h-1v-1.49c0-1.38,1.13-2.51,2.51-2.51h2.49v1h-2.49c-.83,0-1.51.68-1.51,1.51v1.49Z" />
|
||||
<polygon class="cls-1" points="4.5 6 3 4 6 4 4.5 6" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -15,7 +15,7 @@
|
||||
"docs": "ladle serve",
|
||||
"clean": "rimraf --glob lib"
|
||||
},
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"@ladle/react": "^5",
|
||||
@@ -27,7 +27,8 @@
|
||||
"rimraf": "^6",
|
||||
"tailwindcss": "4.0.7",
|
||||
"typescript": "^5",
|
||||
"vite": "^6"
|
||||
"vite": "^7",
|
||||
"vite-plugin-svgr": "^4.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ariakit/react": "^0",
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import clsx from 'clsx';
|
||||
|
||||
type IconNames =
|
||||
| 'replace'
|
||||
| 'replace-all'
|
||||
| 'match-word'
|
||||
| 'case'
|
||||
| 'regex'
|
||||
| 'sort-asc'
|
||||
| 'sort-desc'
|
||||
| 'cross'
|
||||
| 'sort-unknown'
|
||||
| 'arrow-up'
|
||||
| 'arrow-down';
|
||||
|
||||
export interface IconProps {
|
||||
name: IconNames;
|
||||
className?: string;
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
color?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export function Icon({ name, className, size = 'small', color, style }: IconProps) {
|
||||
const sizeAffix = size === 'small' ? '_sm' : size === 'large' ? '' : '_m';
|
||||
const w = size === 'small' ? 16 : size === 'large' ? 32 : 24;
|
||||
return (
|
||||
<svg width={w} height={w} viewBox={`0 0 ${w} ${w}`} className={clsx('dbv-kit-icon', className)} style={{ color, ...style }}>
|
||||
<use href={`#icon-${name}${sizeAffix}`} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -6,23 +6,49 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { type ComponentPropsWithRef } from 'react';
|
||||
import { type ComponentPropsWithRef, type ReactElement, useId } from 'react';
|
||||
import './Input.css';
|
||||
import clsx from 'clsx';
|
||||
import { componentProviderWrapper } from '../componentProviderWrapper.js';
|
||||
|
||||
export interface InputProps extends Omit<ComponentPropsWithRef<'input'>, 'size'> {
|
||||
size?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
label?: React.ReactNode;
|
||||
}
|
||||
export type InputProps = Omit<ComponentPropsWithRef<'input'>, 'size'> & {
|
||||
label?: ReactElement | string;
|
||||
size?: 'small' | 'medium' | 'large' | 'xlarge';
|
||||
};
|
||||
|
||||
export const InputBase: React.FC<InputProps> = function Input({ size, className, ...props }) {
|
||||
export const InputBase: React.FC<InputProps> = function Input({
|
||||
size,
|
||||
className,
|
||||
label,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
'aria-label': ariaLabel,
|
||||
...props
|
||||
}) {
|
||||
const labelId = useId();
|
||||
const classNameToApply = clsx(`dbv-kit-input`, `dbv-kit-input--${size ?? 'medium'}`, className);
|
||||
|
||||
if (label) {
|
||||
return (
|
||||
<label className="dbv-kit-input-wrapper">
|
||||
<div id={labelId} className={clsx('dbv-kit-input__title', props.required && 'dbv-kit-input__title--required')}>
|
||||
{label}
|
||||
</div>
|
||||
<input
|
||||
className={classNameToApply}
|
||||
aria-labelledby={labelId}
|
||||
{...props}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<label className="dbv-kit-input-wrapper">
|
||||
{props.label && <div className={clsx('dbv-kit-input__title', props.required && 'dbv-kit-input__title--required')}>{props.label}</div>}
|
||||
<input className={classNameToApply} {...props} />
|
||||
</label>
|
||||
<input
|
||||
className={classNameToApply}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
aria-label={ariaLabel}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
@layer base {
|
||||
.dbv-kit-radio-group {
|
||||
display: flex;
|
||||
gap: calc(var(--dbv-kit-radio-gap) * 4);
|
||||
|
||||
&.dbv-kit-radio-group--vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&:not(.dbv-kit-radio-group--vertical) .dbv-kit-radio {
|
||||
margin-inline-end: calc(var(--dbv-kit-radio-gap) * 4);
|
||||
gap: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export function RadioGroup({ className, children, labelledBy, label, ['aria-labe
|
||||
</div>
|
||||
)}
|
||||
<_RadioGroup
|
||||
aria-labelledby={labelledById}
|
||||
aria-labelledby={ariaLabel ? undefined : labelledById}
|
||||
aria-label={ariaLabel}
|
||||
className={clsx('dbv-kit-radio-group', className, props.vertical && 'dbv-kit-radio-group--vertical')}
|
||||
>
|
||||
|
||||
@@ -20,19 +20,20 @@
|
||||
font-weight: var(--dbv-kit-select-font-weight);
|
||||
font-size: var(--dbv-kit-select-font-size);
|
||||
outline-width: var(--dbv-kit-control-outline-width);
|
||||
outline-offset: var(--dbv-kit-control-outline-offset);
|
||||
outline-color: var(--dbv-kit-control-outline-color);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--dbv-kit-color-control-hover);
|
||||
&:hover:not(:disabled) {
|
||||
border-color: var(--dbv-kit-select-hover-border-color);
|
||||
}
|
||||
|
||||
&[aria-disabled='true'] {
|
||||
opacity: var(--dbv-kit-control-disabled-opacity);
|
||||
color: var(--dbv-kit-select-disabled-foreground);
|
||||
background-color: var(--dbv-kit-select-disabled-background);
|
||||
}
|
||||
&[data-focus-visible],
|
||||
&:focus-visible {
|
||||
outline-style: solid;
|
||||
outline-offset: var(--dbv-kit-control-outline-offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +75,8 @@
|
||||
.dbv-kit-select__item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: var(--dbv-kit-select-font-weight);
|
||||
font-size: var(--dbv-kit-select-font-size);
|
||||
padding-inline: var(--dbv-kit-select-item-padding-inline);
|
||||
padding-block: var(--dbv-kit-select-item-padding-block);
|
||||
text-align: left;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { SelectProvider, Select, SelectPopover, SelectItem, SelectLabel } from './Select.js';
|
||||
import { SelectProvider, Select, SelectPopover, SelectItem, SelectLabel, type SelectProviderProps } from './Select.js';
|
||||
import './SelectField.css';
|
||||
|
||||
export interface SelectItem<T> {
|
||||
@@ -57,6 +57,8 @@ export interface SelectFieldProps<T, ItemType = SelectItem<T>> {
|
||||
|
||||
className?: string;
|
||||
|
||||
noItemsPlaceholder?: React.ReactNode;
|
||||
|
||||
/**
|
||||
* Custom renderer for the selected value, overrides itemRenderer for the selected state
|
||||
* Only needed for special formatting of the selected value different from list items
|
||||
@@ -67,6 +69,16 @@ export interface SelectFieldProps<T, ItemType = SelectItem<T>> {
|
||||
* Custom arrow icon React Node that will be rendered instead default one
|
||||
*/
|
||||
arrowIcon?: React.ReactNode;
|
||||
|
||||
store?: SelectProviderProps['store'];
|
||||
|
||||
autoFocusItemsOnShow?: boolean;
|
||||
|
||||
'aria-labelledby'?: string,
|
||||
|
||||
'aria-label'?: string
|
||||
|
||||
id?: string;
|
||||
}
|
||||
|
||||
// Utility function to get value by it's key or using getter function
|
||||
@@ -82,13 +94,17 @@ export function SelectField<T, ItemType extends {} = SelectItem<T>>({
|
||||
itemRender,
|
||||
itemDisabled,
|
||||
label,
|
||||
noItemsPlaceholder = 'No items',
|
||||
description,
|
||||
disabled,
|
||||
required,
|
||||
className,
|
||||
selectedRender,
|
||||
arrowIcon,
|
||||
store,
|
||||
autoFocusItemsOnShow,
|
||||
name,
|
||||
id,
|
||||
}: SelectFieldProps<T, ItemType>) {
|
||||
const getItemValue = (item: ItemType): T =>
|
||||
getValueByPath<ItemType, T>(item, itemValue, i => ('value' in i ? (i as unknown as SelectItem<T>).value : (i as unknown as T)));
|
||||
@@ -115,29 +131,28 @@ export function SelectField<T, ItemType extends {} = SelectItem<T>>({
|
||||
|
||||
const selectedItem = items.find(item => getItemValue(item) === currentValue);
|
||||
|
||||
const displayValue = selectedItem ? (selectedRender ? selectedRender(currentValue, selectedItem) : renderItem(selectedItem)) : '';
|
||||
const displayValue = selectedRender ? selectedRender(currentValue, selectedItem) : selectedItem ? renderItem(selectedItem) : '';
|
||||
|
||||
return (
|
||||
<div className={clsx('dbv-kit-select-field', className)}>
|
||||
<SelectProvider value={currentValue as any} setValue={val => handleChange(val as T)}>
|
||||
<SelectProvider value={currentValue as any} setValue={val => handleChange(val as T)} store={store}>
|
||||
{label && <SelectLabel className={clsx(required && 'dbv-kit-select__label--required')}>{label}</SelectLabel>}
|
||||
|
||||
<Select name={name} disabled={disabled}>
|
||||
<Select id={id} name={name} disabled={disabled} required={required}>
|
||||
{displayValue}
|
||||
{arrowIcon ?? <Select.Arrow />}
|
||||
{arrowIcon ?? <Select.Arrow className='dbv-kit-select__arrow-icon' />}
|
||||
</Select>
|
||||
{description && <span className="dbv-kit-select__description">{description}</span>}
|
||||
|
||||
<SelectPopover gutter={4} unmountOnHide>
|
||||
<SelectPopover autoFocusOnShow={autoFocusItemsOnShow} gutter={4} unmountOnHide>
|
||||
{items.length === 0 ? (
|
||||
<div className="dbv-kit-select__empty">No items</div>
|
||||
<div className="dbv-kit-select__empty">{noItemsPlaceholder}</div>
|
||||
) : (
|
||||
items.map(item => (
|
||||
<SelectItem
|
||||
key={String(getItemValue(item))}
|
||||
value={getItemValue(item) as any}
|
||||
disabled={isItemDisabled(item)}
|
||||
className="dbv-kit-select__item"
|
||||
>
|
||||
{renderItem(item)}
|
||||
</SelectItem>
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
--dbv-kit-select-foreground: var(--dbv-kit-color-foreground);
|
||||
--dbv-kit-select-background: var(--dbv-kit-color-background);
|
||||
--dbv-kit-select-disabled-foreground: var(--dbv-kit-control-disabled-foreground);
|
||||
--dbv-kit-select-disabled-background: var(--dbv-kit-control-disabled-background);
|
||||
|
||||
--dbv-kit-select-border-width: var(--dbv-kit-control-border-width);
|
||||
--dbv-kit-select-border-color: var(--dbv-kit-color-control-inactive);
|
||||
--dbv-kit-select-border-style: solid;
|
||||
--dbv-kit-select-border-radius: var(--dbv-kit-control-border-radius);
|
||||
--dbv-kit-select-hover-border-color: var(--dbv-kit-color-control-hover);
|
||||
|
||||
--dbv-kit-select-font-weight: var(--tw-font-weight-normal);
|
||||
--dbv-kit-select-font-size: calc(var(--dbv-kit-font-size-base) * 0.875);
|
||||
|
||||
@@ -38,10 +38,12 @@
|
||||
stroke-linecap: var(--dbv-kit-spinner-stroke-linecap);
|
||||
|
||||
animation: var(--dbv-kit-animate-spin);
|
||||
animation-delay: var(--dbv-kit-spinner-animation-delay);
|
||||
}
|
||||
|
||||
.dbv-kit-spinner__circle {
|
||||
animation: var(--dbv-kit-animate-stroke);
|
||||
animation-delay: var(--dbv-kit-spinner-animation-delay);
|
||||
|
||||
@media screen and (prefers-reduced-motion: reduce) {
|
||||
animation: none;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
:root {
|
||||
--dbv-kit-spinner-height: var(--dbv-kit-control-height-medium);
|
||||
--dbv-kit-spinner-animation-duration: 1.8s;
|
||||
--dbv-kit-spinner-animation-delay: -0.3s;
|
||||
|
||||
--dbv-kit-spinner-stroke-width: 2.5px;
|
||||
--dbv-kit-spinner-stroke-color: var(--dbv-kit-color-primary-600);
|
||||
|
||||
@@ -38,5 +38,6 @@ export {
|
||||
export { SelectField, type SelectFieldProps, type SelectItem } from './Select/SelectField.js';
|
||||
export { Spinner, type SpinnerProps } from './Spinner/Spinner.js';
|
||||
export { Radio, RadioGroup, useRadioContext, useRadioStore, type RadioProviderProps, type RadioProps, type RadioGroupProps } from './Radio/index.js';
|
||||
export { Icon, type IconProps } from './Icon/Icon.js';
|
||||
export * from './utils/clsx.js';
|
||||
export * from './ComponentProvider.js';
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import { Button, ButtonIcon, Icon, type IconProps } from '../../../index.js';
|
||||
|
||||
// All available icon names from the IconNames type
|
||||
const iconNames = [
|
||||
'replace',
|
||||
'replace-all',
|
||||
'match-word',
|
||||
'case',
|
||||
'regex',
|
||||
'sort-asc',
|
||||
'sort-desc',
|
||||
'cross',
|
||||
'sort-unknown',
|
||||
'arrow-up',
|
||||
'arrow-down',
|
||||
] as Array<IconProps['name']>;
|
||||
|
||||
const sizes = ['small', 'medium', 'large'] as const;
|
||||
|
||||
export function Documentation() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Icon</h1>
|
||||
<p>Icon component for displaying SVG icons using the symbol/use pattern.</p>
|
||||
<h2>Usage</h2>
|
||||
<p>Use the Icon component to display predefined SVG icons in your application.</p>
|
||||
<h2>Anatomy</h2>
|
||||
<p>
|
||||
The Icon component consists of an SVG element that references icon symbols via the <code><use></code> element. Icons are sized
|
||||
automatically based on the size prop and support color customization.
|
||||
</p>
|
||||
<pre className="codeblock">
|
||||
{`
|
||||
<svg class="dbv-kit-icon" width="16" height="16" viewBox="0 0 16 16">
|
||||
<use href="#icon-search_sm" />
|
||||
</svg>
|
||||
`}
|
||||
</pre>
|
||||
<h2>Class names</h2>
|
||||
<p>
|
||||
The Icon component uses the following class names:
|
||||
<ul>
|
||||
<li>
|
||||
<code>dbv-kit-icon</code>: Base class for the icon.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
<h2>Props</h2>
|
||||
<table className="tw:table tw:w-full tw:border-collapse">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="tw:py-2 tw:border tw:px-2">Prop</th>
|
||||
<th className="tw:py-2 tw:border tw:px-2">Type</th>
|
||||
<th className="tw:py-2 tw:border tw:px-2">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="tw:border tw:p-2">name</td>
|
||||
<td className="tw:border tw:p-2">
|
||||
<pre>IconNames (required)</pre>
|
||||
</td>
|
||||
<td className="tw:border tw:p-2">The name of the icon to display.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="tw:border tw:p-2">size</td>
|
||||
<td className="tw:border tw:p-2">
|
||||
<pre>small | medium | large</pre>
|
||||
</td>
|
||||
<td className="tw:border tw:p-2">Size of the icon. Default is 'small'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="tw:border tw:p-2">className</td>
|
||||
<td className="tw:border tw:p-2">
|
||||
<pre>string | undefined</pre>
|
||||
</td>
|
||||
<td className="tw:border tw:p-2">Additional CSS class name.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="tw:border tw:p-2">color</td>
|
||||
<td className="tw:border tw:p-2">
|
||||
<pre>string | undefined</pre>
|
||||
</td>
|
||||
<td className="tw:border tw:p-2">Color of the icon.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="tw:border tw:p-2">style</td>
|
||||
<td className="tw:border tw:p-2">
|
||||
<pre>React.CSSProperties | undefined</pre>
|
||||
</td>
|
||||
<td className="tw:border tw:p-2">Inline styles for the icon.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AllIcons() {
|
||||
return (
|
||||
<div>
|
||||
<h1>All Available Icons</h1>
|
||||
<p>Here are all the available icons in the default (small) size:</p>
|
||||
<div className="tw:grid tw:grid-cols-4 tw:gap-4 tw:mt-4">
|
||||
{iconNames.map(iconName => (
|
||||
<div key={iconName} className="tw:flex tw:flex-col tw:items-center tw:p-4">
|
||||
<Icon name={iconName} />
|
||||
<code className="tw:text-xs tw:mt-2">{iconName}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Sizes() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Icon Sizes</h1>
|
||||
<p>Icons come in three different sizes: small (16px), medium (24px), and large (32px).</p>
|
||||
<div className="tw:space-y-6 tw:mt-4">
|
||||
{sizes.map(size => (
|
||||
<div key={size} className="tw:space-y-2">
|
||||
<h3 className="tw:text-lg tw:font-semibold tw:capitalize">
|
||||
{size} ({size === 'small' ? '16px' : size === 'medium' ? '24px' : '32px'})
|
||||
</h3>
|
||||
<div className="tw:flex tw:gap-4 tw:flex-wrap">
|
||||
{iconNames.map(iconName => (
|
||||
<div key={`${size}-${iconName}`} className="tw:flex tw:flex-col tw:items-center tw:p-2">
|
||||
<Icon name={iconName} size={size} />
|
||||
<code className="tw:text-xs tw:mt-1">{iconName}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function WithColors() {
|
||||
const colors = ['red', 'green', 'blue'];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Icons with Colors</h1>
|
||||
<p>Icons can be customized with different colors using the color prop.</p>
|
||||
<div className="tw:space-y-4 tw:mt-4">
|
||||
{colors.map(color => (
|
||||
<div key={color} className="tw:space-y-2">
|
||||
<h3 className="tw:text-lg tw:font-semibold" style={{ color }}>
|
||||
Color: {color}
|
||||
</h3>
|
||||
<div className="tw:flex tw:gap-4 tw:flex-wrap">
|
||||
{iconNames.slice(0, 5).map(iconName => (
|
||||
<div key={`${color}-${iconName}`} className="tw:flex tw:flex-col tw:items-center tw:p-2 tw:border tw:rounded">
|
||||
<Icon name={iconName} size="medium" color={color} />
|
||||
<code className="tw:text-xs tw:mt-1">{iconName}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function UsageExamples() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Usage Examples</h1>
|
||||
<div className="tw:space-y-6 tw:mt-4">
|
||||
<div>
|
||||
<h3 className="tw:text-lg tw:font-semibold">In Buttons</h3>
|
||||
<Button>
|
||||
<ButtonIcon placement="start">
|
||||
<Icon name="cross" size="medium" color="white" className="tw:h-4 tw:w-4" />
|
||||
</ButtonIcon>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="tw:text-lg tw:font-semibold">As Status Indicators</h3>
|
||||
<div className="tw:space-y-2">
|
||||
<div className="tw:flex tw:items-center tw:gap-2">
|
||||
<Icon name="sort-asc" size="medium" color="green" />
|
||||
<span>Sorted ascending</span>
|
||||
</div>
|
||||
<div className="tw:flex tw:items-center tw:gap-2">
|
||||
<Icon name="sort-desc" size="medium" color="red" />
|
||||
<span>Sorted descending</span>
|
||||
</div>
|
||||
<div className="tw:flex tw:items-center tw:gap-2">
|
||||
<Icon name="sort-unknown" size="medium" color="gray" />
|
||||
<span>Unsorted</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="tw:text-lg tw:font-semibold">With Custom Styling</h3>
|
||||
<div className="tw:flex tw:items-center tw:gap-4">
|
||||
<Icon
|
||||
name="replace"
|
||||
size="large"
|
||||
style={{
|
||||
filter: 'drop-shadow(2px 2px 4px rgba(0,0,0,0.2))',
|
||||
transform: 'rotate(15deg)',
|
||||
}}
|
||||
/>
|
||||
<Icon name="regex" size="medium" className="tw:opacity-50 tw:hover:opacity-100 tw:transition-opacity" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -132,6 +132,10 @@ export function Tokens() {
|
||||
<li>
|
||||
<code>--dbv-kit-spinner-animation-duration</code>: Controls the duration of the spinner's animation (default: 1.8s)
|
||||
</li>
|
||||
<li>
|
||||
<code>--dbv-kit-spinner-animation-delay</code>: Controls the delay of the spinner's animation (default: -0.3s). This is used to start
|
||||
spinner animation not from the small dot but with semi-filled circle, which looks better.
|
||||
</li>
|
||||
<li>
|
||||
<code>--dbv-kit-animate-stroke</code>: Defines the animation for the spinner's stroke
|
||||
</li>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { assetResolverPlugin } from '@wroud/vite-plugin-asset-resolver';
|
||||
import { tscPlugin } from '@wroud/vite-plugin-tsc';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
export default {
|
||||
plugins: [
|
||||
svgr(),
|
||||
tailwindcss(),
|
||||
assetResolverPlugin(),
|
||||
tscPlugin({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "common-react",
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"@dbeaver/*",
|
||||
@@ -12,7 +12,7 @@
|
||||
"devDependencies": {
|
||||
"@dbeaver/prettier-config": "workspace:^",
|
||||
"@wroud/ts-template": "^0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier": "^3.6.2",
|
||||
"rimraf": "^6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "prettier",
|
||||
"version": "3.5.3-sdk",
|
||||
"version": "3.6.2-sdk",
|
||||
"main": "./index.cjs",
|
||||
"type": "commonjs",
|
||||
"bin": "./bin/prettier.cjs"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"@types/node": "^22",
|
||||
|
||||
@@ -12,18 +12,7 @@ export default defineConfig({
|
||||
include: ['**/lib/**/*.test.js'],
|
||||
exclude: ['node_modules/**'],
|
||||
isolate: false,
|
||||
poolOptions: {
|
||||
forks: {
|
||||
isolate: false,
|
||||
},
|
||||
},
|
||||
fileParallelism: false,
|
||||
watch: false,
|
||||
environmentOptions: {
|
||||
// This will force JSDOM to use the default export condition when importing msw/node, resulting in correct imports.
|
||||
// https://mswjs.io/docs/migrations/1.x-to-2.x#cannot-find-module-mswnode-jsdom
|
||||
customExportConditions: [''],
|
||||
},
|
||||
},
|
||||
esbuild: false,
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"rimraf": "^6",
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"rimraf": "^6",
|
||||
"typescript": "^5"
|
||||
"typescript": "^5",
|
||||
"vitest": "^3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { parseJdbcUri } from './parseJdbcUri.js';
|
||||
|
||||
describe('parseJdbcUri', () => {
|
||||
describe('invalid inputs', () => {
|
||||
it('should handle null input', () => {
|
||||
const result = parseJdbcUri(null);
|
||||
expect(result).toEqual({
|
||||
raw: '',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle undefined input', () => {
|
||||
const result = parseJdbcUri(undefined);
|
||||
expect(result).toEqual({
|
||||
raw: '',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
const result = parseJdbcUri('');
|
||||
expect(result).toEqual({
|
||||
raw: '',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle non-string input', () => {
|
||||
const result = parseJdbcUri(123 as any);
|
||||
expect(result).toEqual({
|
||||
raw: '123',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('non-jdbc URLs', () => {
|
||||
it('should handle non-jdbc URLs', () => {
|
||||
const result = parseJdbcUri('https://example.com');
|
||||
expect(result).toEqual({
|
||||
raw: 'https://example.com',
|
||||
subprotocol: '',
|
||||
subname: 'https://example.com',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle plain text', () => {
|
||||
const result = parseJdbcUri('just some text');
|
||||
expect(result).toEqual({
|
||||
raw: 'just some text',
|
||||
subprotocol: '',
|
||||
subname: 'just some text',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('malformed jdbc URLs', () => {
|
||||
it('should handle jdbc: without subprotocol', () => {
|
||||
const result = parseJdbcUri('jdbc:');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:',
|
||||
subprotocol: '',
|
||||
subname: '',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle jdbc: with only subprotocol', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql',
|
||||
subprotocol: '',
|
||||
subname: 'mysql',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SQLite URLs', () => {
|
||||
it('should parse SQLite file path', () => {
|
||||
const result = parseJdbcUri('jdbc:sqlite:/path/to/file.db');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:sqlite:/path/to/file.db',
|
||||
subprotocol: 'sqlite',
|
||||
subname: '/path/to/file.db',
|
||||
database: '/path/to/file.db',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse SQLite relative path', () => {
|
||||
const result = parseJdbcUri('jdbc:sqlite:file.db');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:sqlite:file.db',
|
||||
subprotocol: 'sqlite',
|
||||
subname: 'file.db',
|
||||
database: 'file.db',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse SQLite in-memory database', () => {
|
||||
const result = parseJdbcUri('jdbc:sqlite::memory:');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:sqlite::memory:',
|
||||
subprotocol: 'sqlite',
|
||||
subname: ':memory:',
|
||||
database: ':memory:',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Oracle Thin URLs', () => {
|
||||
it('should parse Oracle Thin with host, port, and SID', () => {
|
||||
const result = parseJdbcUri('jdbc:oracle:thin:@localhost:1521:XE');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:oracle:thin:@localhost:1521:XE',
|
||||
subprotocol: 'oracle',
|
||||
subname: 'thin:@localhost:1521:XE',
|
||||
host: 'localhost',
|
||||
port: '1521',
|
||||
database: 'XE',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle malformed Oracle Thin URL', () => {
|
||||
const result = parseJdbcUri('jdbc:oracle:thin:@localhost');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:oracle:thin:@localhost',
|
||||
subprotocol: 'oracle',
|
||||
subname: 'thin:@localhost',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle Oracle Thin with different format', () => {
|
||||
const result = parseJdbcUri('jdbc:oracle:thin:@localhost:1521');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:oracle:thin:@localhost:1521',
|
||||
subprotocol: 'oracle',
|
||||
subname: 'thin:@localhost:1521',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('standard JDBC URLs with //', () => {
|
||||
it('should parse MySQL URL with host and port', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse PostgreSQL URL without port', () => {
|
||||
const result = parseJdbcUri('jdbc:postgresql://localhost/mydb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:postgresql://localhost/mydb',
|
||||
subprotocol: 'postgresql',
|
||||
subname: '//localhost/mydb',
|
||||
host: 'localhost',
|
||||
port: undefined,
|
||||
database: 'mydb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse URL with credentials', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://user:pass@localhost:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://user:pass@localhost:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//user:pass@localhost:3306/testdb',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse URL with query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb?useSSL=false&serverTimezone=UTC',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {
|
||||
useSSL: 'false',
|
||||
serverTimezone: 'UTC',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse URL with empty query parameter', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb?param1=¶m2=value');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb?param1=¶m2=value',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb?param1=¶m2=value',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {
|
||||
param1: '',
|
||||
param2: 'value',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL-encoded query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/testdb?param1=value%20with%20spaces¶m2=value%3Dtest');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/testdb?param1=value%20with%20spaces¶m2=value%3Dtest',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/testdb?param1=value%20with%20spaces¶m2=value%3Dtest',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {
|
||||
param1: 'value with spaces',
|
||||
param2: 'value=test',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle malformed URL gracefully', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//:3306/testdb',
|
||||
host: undefined,
|
||||
port: '3306',
|
||||
database: 'testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template placeholders', () => {
|
||||
it('should handle host placeholder', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://{host}:3306/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://{host}:3306/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//{host}:3306/testdb',
|
||||
host: undefined,
|
||||
port: '3306',
|
||||
database: '/{host}:3306/testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle port placeholder', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:{port}/testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:{port}/testdb',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:{port}/testdb',
|
||||
host: 'localhost',
|
||||
port: undefined,
|
||||
database: '/localhost:{port}/testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle database placeholder', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/{database}');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/{database}',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/{database}',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: '/localhost:3306/{database}',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple placeholders', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://{host}:{port}/{database}');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://{host}:{port}/{database}',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//{host}:{port}/{database}',
|
||||
host: undefined,
|
||||
port: undefined,
|
||||
database: '/{host}:{port}/{database}',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle placeholders with query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://{host}:{port}/{database}?useSSL=false');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://{host}:{port}/{database}?useSSL=false',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//{host}:{port}/{database}?useSSL=false',
|
||||
host: undefined,
|
||||
port: undefined,
|
||||
database: '/{host}:{port}/{database}',
|
||||
queryParams: {
|
||||
useSSL: 'false',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('other JDBC formats', () => {
|
||||
it('should handle simple subname as database', () => {
|
||||
const result = parseJdbcUri('jdbc:hsqldb:mem:testdb');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:hsqldb:mem:testdb',
|
||||
subprotocol: 'hsqldb',
|
||||
subname: 'mem:testdb',
|
||||
database: 'mem:testdb',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle Derby embedded', () => {
|
||||
const result = parseJdbcUri('jdbc:derby:testdb;create=true');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:derby:testdb;create=true',
|
||||
subprotocol: 'derby',
|
||||
subname: 'testdb;create=true',
|
||||
database: 'testdb;create=true',
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle URL with only host', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost',
|
||||
host: 'localhost',
|
||||
port: undefined,
|
||||
database: undefined,
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL with host and port but no database', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: undefined,
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL with empty database', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: undefined,
|
||||
username: undefined,
|
||||
password: undefined,
|
||||
queryParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle URL with only query parameters', () => {
|
||||
const result = parseJdbcUri('jdbc:mysql://localhost:3306/?param1=value1');
|
||||
expect(result).toEqual({
|
||||
raw: 'jdbc:mysql://localhost:3306/?param1=value1',
|
||||
subprotocol: 'mysql',
|
||||
subname: '//localhost:3306/?param1=value1',
|
||||
host: 'localhost',
|
||||
port: '3306',
|
||||
database: undefined,
|
||||
username: undefined,
|
||||
password: undefined,
|
||||
queryParams: {
|
||||
param1: 'value1',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -23,12 +23,15 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/cli": "workspace:^",
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"rimraf": "^6",
|
||||
"typescript": "^5",
|
||||
"vitest": "^3"
|
||||
},
|
||||
"dependencies": {
|
||||
"async-mutex": "^0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './isDefined.js';
|
||||
export * from './isNotNullDefined.js';
|
||||
export * from './mutex.js';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * as mutex from 'async-mutex';
|
||||
@@ -23,7 +23,7 @@
|
||||
"!lib/tests",
|
||||
"!.tsbuildinfo"
|
||||
],
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"devDependencies": {
|
||||
"@dbeaver/tsconfig": "workspace:^",
|
||||
"rimraf": "^6",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@dbeaver/tsconfig",
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"dependencies": {
|
||||
"typescript": "^5",
|
||||
"typescript-plugin-css-modules": "^5",
|
||||
"vite": "^6"
|
||||
"vite": "^7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "common-typescript",
|
||||
"type": "module",
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"@dbeaver/*"
|
||||
@@ -14,7 +14,7 @@
|
||||
"@dbeaver/cli": "workspace:^",
|
||||
"@dbeaver/prettier-config": "workspace:^",
|
||||
"@wroud/ts-template": "^0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier": "^3.6.2",
|
||||
"rimraf": "^6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
server: {
|
||||
serverPort: "${CLOUDBEAVER_WEB_SERVER_PORT:8978}",
|
||||
forceHttps: "${CLOUDBEAVER_FORCE_HTTPS:false}",
|
||||
|
||||
contentRoot: "web",
|
||||
driversLocation: "drivers",
|
||||
@@ -9,10 +10,11 @@
|
||||
|
||||
rootURI: "${CLOUDBEAVER_ROOT_URI:/}",
|
||||
serviceURI: "/api/",
|
||||
supportedHosts: [],
|
||||
|
||||
productSettings: {
|
||||
# Global properties
|
||||
core.theming.theme: "${CLOUDBEAVER_CORE_THEMING_THEME:light}",
|
||||
core.theming.theme: "${CLOUDBEAVER_CORE_THEMING_THEME:system}",
|
||||
core.localization.language: "${CLOUDBEAVER_CORE_LOCALIZATION:en}",
|
||||
plugin.sql-editor.autoSave: "${CLOUDBEAVER_SQL_EDITOR_AUTOSAVE:true}",
|
||||
plugin.sql-editor.disabled: "${CLOUDBEAVER_SQL_EDITOR_DISABLED:false}",
|
||||
@@ -21,11 +23,12 @@
|
||||
plugin.log-viewer.disabled: "${CLOUDBEAVER_LOG_VIEWER_DISABLED:false}",
|
||||
plugin.log-viewer.logBatchSize: "${CLOUDBEAVER_LOG_VIEWER_LOG_BATCH_SIZE:1000}",
|
||||
plugin.log-viewer.maxLogRecords: "${CLOUDBEAVER_LOG_VIEWER_MAX_LOG_RECORDS:2000}",
|
||||
sql.proposals.insert.table.alias: "${CLOUDBEAVER_SQL_PROPOSALS_INSERT_TABLE_ALIAS:PLAIN}"
|
||||
sql.proposals.insert.table.alias: "${CLOUDBEAVER_SQL_PROPOSALS_INSERT_TABLE_ALIAS:PLAIN}",
|
||||
SQLEditor.ContentAssistant.experimental.mode: "${CLOUDBEAVER_SQL_EDITOR_CONTENT_ASSISTANT_EXPERIMENTAL_MODE:NEW}"
|
||||
},
|
||||
|
||||
expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}",
|
||||
|
||||
bindSessionToIp: "${CLOUDBEAVER_BIND_SESSION_TO_IP:disable}",
|
||||
develMode: "${CLOUDBEAVER_DEVEL_MODE:false}",
|
||||
|
||||
enableSecurityManager: false,
|
||||
@@ -77,7 +80,6 @@
|
||||
resourceManagerEnabled: "${CLOUDBEAVER_APP_RESOURCE_MANAGER_ENABLED:true}",
|
||||
|
||||
resourceQuotas: {
|
||||
dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}",
|
||||
resourceManagerFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_RESOURCE_MANAGER_FILE_SIZE_LIMIT:500000}",
|
||||
sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}",
|
||||
sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}",
|
||||
|
||||
@@ -5,7 +5,8 @@ MAINTAINER DBeaver Corp, devops@dbeaver.com
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get update && \
|
||||
apt-get dist-upgrade -y --no-install-recommends && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
# curl required for historical reasons, see https://github.com/adoptium/containers/issues/255
|
||||
curl \
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
FROM dbeaver/base-java
|
||||
ARG BASE_JAVA_TAG="stable"
|
||||
FROM dbeaver/base-java:${BASE_JAVA_TAG}
|
||||
|
||||
MAINTAINER DBeaver Corp, devops@dbeaver.com
|
||||
|
||||
ENV DBEAVER_GID=8978
|
||||
ENV DBEAVER_UID=8978
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade -y
|
||||
|
||||
RUN groupadd -g $DBEAVER_GID dbeaver && \
|
||||
useradd -g $DBEAVER_GID -m -u $DBEAVER_UID -s /bin/bash dbeaver
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
SET mypath=%~dp0
|
||||
|
||||
.\..\idea-rcp-launch-config-generator\runGenerator.cmd -f %mypath%
|
||||
@echo off
|
||||
%~dp0\..\idea-rcp-launch-config-generator\runGenerator.cmd -f %~dp0
|
||||
@@ -1 +1,6 @@
|
||||
./../idea-rcp-launch-config-generator/runGenerator.sh -f "$PWD"
|
||||
#!/usr/bin/env sh
|
||||
|
||||
script_dir="$(realpath "$(dirname "$0")")"
|
||||
repositories_root_dir="$(realpath "$script_dir/..")"
|
||||
|
||||
"$repositories_root_dir"/idea-rcp-launch-config-generator/runGenerator.sh "$script_dir"
|
||||
|
||||
@@ -5,6 +5,9 @@ output: false
|
||||
pre-commit:
|
||||
commands:
|
||||
check-license:
|
||||
skip:
|
||||
- merge
|
||||
- rebase
|
||||
root: webapp
|
||||
glob: "*.{ts,tsx}"
|
||||
exclude:
|
||||
|
||||
@@ -16,7 +16,7 @@ testLibraries=\
|
||||
org.hamcrest.core;\
|
||||
org.hamcrest
|
||||
repositories=\
|
||||
https://p2.dev.dbeaver.com/eclipse-repo/;\
|
||||
https://repo.dbeaver.net/p2/ce/latest/;\
|
||||
https://download.eclipse.org/releases/${eclipse-version}/;
|
||||
testBundles=\
|
||||
org.junit;\
|
||||
|
||||
@@ -3,11 +3,10 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Model
|
||||
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
|
||||
Bundle-Version: 1.0.79.qualifier
|
||||
Bundle-Release-Date: 20250616
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-Version: 1.0.82.qualifier
|
||||
Bundle-Release-Date: 20250804
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.cli;visibility:=reexport,
|
||||
@@ -16,7 +15,7 @@ Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.nio;visibility:=reexport,
|
||||
org.jkiss.dbeaver.registry;visibility:=reexport,
|
||||
org.jkiss.dbeaver.net.ssh,
|
||||
org.jkiss.bundle.graphql.java;visibility:=reexport,
|
||||
org.jkiss.bundle.graphql;visibility:=reexport,
|
||||
org.jkiss.bundle.apache.dbcp,
|
||||
com.google.gson;visibility:=reexport,
|
||||
jakarta.servlet-api;bundle-version:="6.0.0";visibility:=reexport
|
||||
@@ -30,6 +29,7 @@ Export-Package: io.cloudbeaver,
|
||||
io.cloudbeaver.model,
|
||||
io.cloudbeaver.model.app,
|
||||
io.cloudbeaver.model.config,
|
||||
io.cloudbeaver.model.apilog,
|
||||
io.cloudbeaver.model.cli,
|
||||
io.cloudbeaver.model.events,
|
||||
io.cloudbeaver.model.fs,
|
||||
|
||||
@@ -25,10 +25,4 @@
|
||||
label="Default secret controller" description="Default void secret controller"/>
|
||||
</extension>
|
||||
|
||||
|
||||
<extension point="org.jkiss.dbeaver.ws.event.handler">
|
||||
<eventHandler class="io.cloudbeaver.model.events.WSEventHandlerWorkspaceConfigUpdate">
|
||||
<topic id="cb_workspace_configuration"/>
|
||||
</eventHandler>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model</artifactId>
|
||||
<version>1.0.79-SNAPSHOT</version>
|
||||
<version>1.0.82-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -30,6 +30,7 @@ public interface DBWConstants {
|
||||
String PERMISSION_PRIVATE_PROJECT_ACCESS = "private-project-access";
|
||||
String PERMISSION_SECRET_MANAGER = "secret-manager";
|
||||
|
||||
String GLOBAL_PERMISSION_SCRIPT_EXECUTE = "permission.sql.script.execution";
|
||||
|
||||
String PERMISSION_EDIT_STRUCTURE = "edit-meta";
|
||||
String PERMISSION_EDIT_DATA = "edit-data";
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBPEvent;
|
||||
import org.jkiss.dbeaver.model.DBPEventListener;
|
||||
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceConnectEvent;
|
||||
|
||||
/**
|
||||
* Sends a WebSocket event when a data source is connected.
|
||||
*/
|
||||
public class WebDataSourceConnectEventListener implements DBPEventListener {
|
||||
|
||||
@NotNull
|
||||
private final WebSession webSession;
|
||||
|
||||
public WebDataSourceConnectEventListener(@NotNull WebSession webSession) {
|
||||
this.webSession = webSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDataSourceEvent(DBPEvent event) {
|
||||
if (!(event.getObject() instanceof DBPDataSourceContainer container)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() == DBPEvent.Action.AFTER_CONNECT && event.getEnabled()) {
|
||||
webSession.addSessionEvent(
|
||||
new WSDataSourceConnectEvent(
|
||||
container.getProject().getId(),
|
||||
container.getId(),
|
||||
webSession.getSessionId(),
|
||||
webSession.getUserId()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -90,6 +90,7 @@ public class WebSessionProjectImpl extends WebProjectImpl {
|
||||
protected DataSourceRegistry<?> createRegistryWithCredentialsProvider() {
|
||||
DataSourceRegistry<?> dataSourceRegistry = createRMRegistry();
|
||||
dataSourceRegistry.setAuthCredentialsProvider(webSession);
|
||||
dataSourceRegistry.addDataSourceListener(webSession.getDataSourceConnectListener());
|
||||
return dataSourceRegistry;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,27 +30,50 @@ import java.util.Map;
|
||||
public interface SMAuthProviderFederated extends SMSignOutLinkProvider {
|
||||
|
||||
@NotNull
|
||||
String getSignInLink(String id) throws DBException;
|
||||
String getSignInLink(@NotNull String id, @NotNull String origin) throws DBException;
|
||||
|
||||
@Override
|
||||
default String getUserSignOutLink(
|
||||
@NotNull SMAuthProviderCustomConfiguration providerConfig,
|
||||
@NotNull Map<String, Object> userCredentials
|
||||
@NotNull Map<String, Object> userCredentials,
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
return getCommonSignOutLink(providerConfig.getId(), providerConfig.getParameters());
|
||||
return getCommonSignOutLink(providerConfig.getId(), providerConfig.getParameters(), origin);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getMetadataLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException;
|
||||
default String getMetadataLink(
|
||||
@NotNull String providerId,
|
||||
@NotNull Map<String, Object> providerConfig,
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getAcsLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException;
|
||||
default String getAcsLink(
|
||||
@NotNull String providerId,
|
||||
@NotNull Map<String, Object> providerConfig,
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getEntityIdLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException;
|
||||
default String getEntityIdLink(
|
||||
@NotNull String providerId,
|
||||
@NotNull Map<String, Object> providerConfig,
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default String getRedirectLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException {
|
||||
default String getRedirectLink(
|
||||
@NotNull String providerId,
|
||||
@NotNull Map<String, Object> providerConfig,
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,10 +28,15 @@ public interface SMSignOutLinkProvider {
|
||||
* @return a common link for logout, not related with the user context
|
||||
*/
|
||||
@NotNull
|
||||
String getCommonSignOutLink(String id, @NotNull Map<String, Object> providerConfig) throws DBException;
|
||||
String getCommonSignOutLink(
|
||||
@NotNull String providerId,
|
||||
@NotNull Map<String, Object> providerConfig,
|
||||
@NotNull String origin
|
||||
) throws DBException;
|
||||
|
||||
String getUserSignOutLink(
|
||||
@NotNull SMAuthProviderCustomConfiguration providerConfig,
|
||||
@NotNull Map<String, Object> userCredentials
|
||||
@NotNull Map<String, Object> userCredentials,
|
||||
@NotNull String origin
|
||||
) throws DBException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.model.apilog;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interceptor for API call events.
|
||||
* This interface allows to intercept and log API call events in a web application.
|
||||
*/
|
||||
public interface ApiCallInterceptor {
|
||||
|
||||
/**
|
||||
* Intercept API call event.
|
||||
*
|
||||
*/
|
||||
void onApiCallEvent(
|
||||
@NotNull HttpServletRequest request,
|
||||
@Nullable Map<String, Object> variables,
|
||||
@NotNull String apiCall,
|
||||
@NotNull LocalDateTime startTime,
|
||||
@Nullable String errorMessage,
|
||||
@NotNull String apiProtocol
|
||||
);
|
||||
}
|
||||
@@ -55,9 +55,9 @@ public abstract class BaseServerConfigurationController<T extends ServletServerC
|
||||
@NotNull
|
||||
protected abstract GsonBuilder getGsonBuilder();
|
||||
|
||||
@NotNull
|
||||
public abstract T getServerConfiguration();
|
||||
|
||||
|
||||
@NotNull
|
||||
protected synchronized Path initWorkspacePath() {
|
||||
Path defaultWorkspaceLocation = homeDirectory.resolve("workspace");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,12 +18,15 @@
|
||||
package io.cloudbeaver.model.app;
|
||||
|
||||
import io.cloudbeaver.auth.CBAuthConstants;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
public interface ServletAuthApplication extends ServletApplication {
|
||||
ServletAuthConfiguration getAuthConfiguration();
|
||||
|
||||
String getAuthServiceURL();
|
||||
@Nullable
|
||||
String getAuthServiceUriSegment();
|
||||
|
||||
default long getMaxSessionIdleTime() {
|
||||
return CBAuthConstants.MAX_SESSION_IDLE_TIME;
|
||||
@@ -32,4 +35,8 @@ public interface ServletAuthApplication extends ServletApplication {
|
||||
void flushConfiguration() throws DBException;
|
||||
|
||||
String getDefaultAuthRole();
|
||||
|
||||
default String modifyOrigin(@NotNull String origin) {
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,12 @@ package io.cloudbeaver.model.config;
|
||||
*/
|
||||
public class ConnectionBruteForceConfiguration {
|
||||
private static final int DEFAULT_ERROR_ATTEMPTS_CHECK_MINUTES = 24 * 60;
|
||||
private static final int BLOCK_TIME_IN_MINUTES = 60;
|
||||
private static final int DEFAULT_MAX_CONNECT_ATTEMPTS = 5;
|
||||
private boolean enabled = false;
|
||||
private int maxFailedConnectAttempts = DEFAULT_MAX_CONNECT_ATTEMPTS;
|
||||
private int errorAttemptsPeriodInMinutes = DEFAULT_ERROR_ATTEMPTS_CHECK_MINUTES;
|
||||
private int blockTimeInMinutes = BLOCK_TIME_IN_MINUTES;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
@@ -49,4 +51,12 @@ public class ConnectionBruteForceConfiguration {
|
||||
public void setErrorAttemptsPeriodInMinutes(int errorAttemptsPeriodInMinutes) {
|
||||
this.errorAttemptsPeriodInMinutes = errorAttemptsPeriodInMinutes;
|
||||
}
|
||||
|
||||
public int getBlockTimeInMinutes() {
|
||||
return blockTimeInMinutes;
|
||||
}
|
||||
|
||||
public void setBlockTimeInMinutes(int blockTimeInMinutes) {
|
||||
this.blockTimeInMinutes = blockTimeInMinutes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBFileController;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBPEventListener;
|
||||
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
|
||||
import org.jkiss.dbeaver.model.access.DBACredentialsProvider;
|
||||
import org.jkiss.dbeaver.model.auth.*;
|
||||
@@ -48,7 +49,6 @@ import org.jkiss.dbeaver.model.fs.DBFFileSystemManager;
|
||||
import org.jkiss.dbeaver.model.meta.Association;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNModel;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
|
||||
import org.jkiss.dbeaver.model.rm.RMController;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.rm.RMProjectType;
|
||||
@@ -90,7 +90,7 @@ public class WebSession extends BaseWebSession
|
||||
public static String RUNTIME_PARAM_AUTH_INFOS = "auth-infos";
|
||||
private final AtomicInteger taskCount = new AtomicInteger();
|
||||
|
||||
private String lastRemoteAddr;
|
||||
private final String lastRemoteAddr;
|
||||
private String lastRemoteUserAgent;
|
||||
|
||||
private String locale;
|
||||
@@ -108,6 +108,7 @@ public class WebSession extends BaseWebSession
|
||||
private DBNModel navigatorModel;
|
||||
private final DBRProgressMonitor progressMonitor = new SessionProgressMonitor();
|
||||
private final Map<String, DBWSessionHandler> sessionHandlers;
|
||||
private final WebDataSourceConnectEventListener connectListener = new WebDataSourceConnectEventListener(this);
|
||||
|
||||
public WebSession(
|
||||
@NotNull WebHttpRequestInfo requestInfo,
|
||||
@@ -117,7 +118,8 @@ public class WebSession extends BaseWebSession
|
||||
this(requestInfo.getId(),
|
||||
CommonUtils.toString(requestInfo.getLocale()),
|
||||
application,
|
||||
sessionHandlers
|
||||
sessionHandlers,
|
||||
requestInfo.getLastRemoteAddress()
|
||||
);
|
||||
updateSessionParameters(requestInfo);
|
||||
}
|
||||
@@ -126,9 +128,14 @@ public class WebSession extends BaseWebSession
|
||||
@NotNull String id,
|
||||
@Nullable String locale,
|
||||
@NotNull ServletApplication application,
|
||||
@NotNull Map<String, DBWSessionHandler> sessionHandlers
|
||||
@NotNull Map<String, DBWSessionHandler> sessionHandlers,
|
||||
@NotNull String remoteAddr
|
||||
) throws DBException {
|
||||
super(id, application);
|
||||
if (CommonUtils.isEmpty(remoteAddr)) {
|
||||
throw new DBException("Remote address cannot be empty");
|
||||
}
|
||||
this.lastRemoteAddr = remoteAddr;
|
||||
this.lastAccessTime = this.createTime;
|
||||
this.sessionHandlers = sessionHandlers;
|
||||
setLocale(CommonUtils.toString(locale, this.locale));
|
||||
@@ -262,6 +269,11 @@ public class WebSession extends BaseWebSession
|
||||
clearSessionContext();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DBPEventListener getDataSourceConnectListener() {
|
||||
return connectListener;
|
||||
}
|
||||
|
||||
private void initNavigatorModel() {
|
||||
|
||||
// Cleanup current data
|
||||
@@ -452,7 +464,6 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
public synchronized void updateSessionParameters(WebHttpRequestInfo requestInfo) {
|
||||
this.lastRemoteAddr = requestInfo.getLastRemoteAddress();
|
||||
this.lastRemoteUserAgent = requestInfo.getLastRemoteUserAgent();
|
||||
this.cacheExpired = false;
|
||||
}
|
||||
@@ -523,6 +534,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebAsyncTaskInfo asyncTaskStatus(String taskId, boolean removeOnFinish) throws DBWebException {
|
||||
synchronized (asyncTasks) {
|
||||
WebAsyncTaskInfo taskInfo = asyncTasks.get(taskId);
|
||||
@@ -989,7 +1001,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DBPPreferenceStore getUserPreferenceStore() {
|
||||
public WebSessionPreferenceStore getUserPreferenceStore() {
|
||||
return getUserContext().getPreferenceStore();
|
||||
}
|
||||
|
||||
@@ -1010,6 +1022,9 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasGlobalPermission(String permissionId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private record PersistentAttribute(Object value) {
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package io.cloudbeaver.model.session;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.impl.preferences.AbstractUserPreferenceStore;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
|
||||
|
||||
@@ -24,10 +25,16 @@ import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebSessionPreferenceStore extends AbstractUserPreferenceStore {
|
||||
|
||||
@NotNull
|
||||
private final WebUserContext userContext;
|
||||
|
||||
public WebSessionPreferenceStore(
|
||||
@NotNull WebUserContext userContext,
|
||||
@NotNull DBPPreferenceStore parentStore
|
||||
) {
|
||||
super(parentStore);
|
||||
this.userContext = userContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -36,7 +43,10 @@ public class WebSessionPreferenceStore extends AbstractUserPreferenceStore {
|
||||
}
|
||||
|
||||
// to avoid redundant sm api call
|
||||
public void updatePreferenceValues(@NotNull Map<String, Object> newValues) {
|
||||
public void updatePreferenceValues(@NotNull Map<String, Object> newValues) throws DBException {
|
||||
if (userContext.getUser() != null) {
|
||||
userContext.getSecurityController().setCurrentUserParameters(newValues);
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : newValues.entrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
userPreferences.remove(entry.getKey());
|
||||
|
||||
@@ -47,6 +47,10 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
this.workspaceAuthContext = new SessionContextImpl(null);
|
||||
}
|
||||
|
||||
public BaseWebSession getWebSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DBPPlatform getPlatform() {
|
||||
|
||||
@@ -73,7 +73,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
this.securityController = application.createSecurityController(this);
|
||||
this.rmController = application.createResourceController(this, workspace);
|
||||
this.fileController = application.createFileController(this);
|
||||
this.preferenceStore = new WebSessionPreferenceStore(DBWorkbench.getPlatform().getPreferenceStore());
|
||||
this.preferenceStore = new WebSessionPreferenceStore(this, DBWorkbench.getPlatform().getPreferenceStore());
|
||||
setUserPermissions(getDefaultPermissions());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import io.cloudbeaver.auth.CBAuthConstants;
|
||||
import io.cloudbeaver.auth.SMAuthProviderFederated;
|
||||
import io.cloudbeaver.auth.SMSignOutLinkProvider;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.auth.SMAuthProvider;
|
||||
@@ -35,12 +36,21 @@ public class WebAuthProviderConfiguration {
|
||||
|
||||
private static final Log log = Log.getLog(WebAuthProviderConfiguration.class);
|
||||
|
||||
@NotNull
|
||||
private final WebAuthProviderDescriptor providerDescriptor;
|
||||
@NotNull
|
||||
private final SMAuthProviderCustomConfiguration config;
|
||||
@NotNull
|
||||
private final String origin;
|
||||
|
||||
public WebAuthProviderConfiguration(WebAuthProviderDescriptor providerDescriptor, SMAuthProviderCustomConfiguration config) {
|
||||
public WebAuthProviderConfiguration(
|
||||
@NotNull WebAuthProviderDescriptor providerDescriptor,
|
||||
@NotNull SMAuthProviderCustomConfiguration config,
|
||||
@NotNull String origin
|
||||
) {
|
||||
this.providerDescriptor = providerDescriptor;
|
||||
this.config = config;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
public String getProviderId() {
|
||||
@@ -75,19 +85,19 @@ public class WebAuthProviderConfiguration {
|
||||
public String getSignInLink() throws DBException {
|
||||
SMAuthProvider<?> instance = providerDescriptor.getInstance();
|
||||
return instance instanceof SMAuthProviderFederated smAuthProviderFederated ?
|
||||
buildRedirectUrl(smAuthProviderFederated.getSignInLink(getId()))
|
||||
buildRedirectUrl(smAuthProviderFederated.getSignInLink(getId(), origin), origin)
|
||||
: null;
|
||||
}
|
||||
|
||||
private String buildRedirectUrl(String baseUrl) {
|
||||
return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + ServletAppUtils.getFullServerUrl();
|
||||
private String buildRedirectUrl(@NotNull String baseUrl, @NotNull String origin) {
|
||||
return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + origin;
|
||||
}
|
||||
|
||||
@Property
|
||||
public String getSignOutLink() throws DBException {
|
||||
SMAuthProvider<?> instance = providerDescriptor.getInstance();
|
||||
return instance instanceof SMSignOutLinkProvider smSignOutLinkProvider
|
||||
? smSignOutLinkProvider.getCommonSignOutLink(getId(), config.getParameters())
|
||||
? smSignOutLinkProvider.getCommonSignOutLink(getId(), config.getParameters(), origin)
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -95,7 +105,7 @@ public class WebAuthProviderConfiguration {
|
||||
public String getRedirectLink() throws DBException {
|
||||
SMAuthProvider<?> instance = providerDescriptor.getInstance();
|
||||
return instance instanceof SMAuthProviderFederated smAuthProviderFederated
|
||||
? smAuthProviderFederated.getRedirectLink(getId(), config.getParameters())
|
||||
? smAuthProviderFederated.getRedirectLink(getId(), config.getParameters(), origin)
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -103,7 +113,7 @@ public class WebAuthProviderConfiguration {
|
||||
public String getMetadataLink() throws DBException {
|
||||
SMAuthProvider<?> instance = providerDescriptor.getInstance();
|
||||
return instance instanceof SMAuthProviderFederated smAuthProviderFederated
|
||||
? smAuthProviderFederated.getMetadataLink(getId(), config.getParameters())
|
||||
? smAuthProviderFederated.getMetadataLink(getId(), config.getParameters(), origin)
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -111,7 +121,7 @@ public class WebAuthProviderConfiguration {
|
||||
public String getAcsLink() throws DBException {
|
||||
SMAuthProvider<?> instance = providerDescriptor.getInstance();
|
||||
return instance instanceof SMAuthProviderFederated smAuthProviderFederated
|
||||
? smAuthProviderFederated.getAcsLink(getId(), config.getParameters())
|
||||
? smAuthProviderFederated.getAcsLink(getId(), config.getParameters(), origin)
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -119,7 +129,7 @@ public class WebAuthProviderConfiguration {
|
||||
public String getEntityIdLink() throws DBException {
|
||||
SMAuthProvider<?> instance = providerDescriptor.getInstance();
|
||||
return instance instanceof SMAuthProviderFederated smAuthProviderFederated
|
||||
? smAuthProviderFederated.getEntityIdLink(getId(), config.getParameters())
|
||||
? smAuthProviderFederated.getEntityIdLink(getId(), config.getParameters(), origin)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ public class CBConstants {
|
||||
public static final String PARAM_SERVER_PORT = "serverPort";
|
||||
public static final String PARAM_SERVER_HOST = "serverHost";
|
||||
public static final String PARAM_SERVER_NAME = "serverName";
|
||||
public static final String PARAM_FORCE_HTTPS = "forceHttps";
|
||||
public static final String PARAM_BIND_SESSION_TO_IP = "bindSessionToIp";
|
||||
public static final String PARAM_SUPPORTED_HOSTS = "supportedHosts";
|
||||
public static final String PARAM_SSL_CONFIGURATION_PATH = "sslConfigurationPath";
|
||||
public static final String PARAM_CONTENT_ROOT = "contentRoot";
|
||||
public static final String PARAM_SERVER_URL = "serverURL";
|
||||
@@ -89,8 +92,10 @@ public class CBConstants {
|
||||
|
||||
public static final String APPLICATION_JSON = "application/json";
|
||||
|
||||
public static final String QUOTA_PROP_FILE_LIMIT = "dataExportFileSizeLimit";
|
||||
public static final String ADMIN_AUTO_GRANT = "auto-grant";
|
||||
public static final String HOST_LOCALHOST = "localhost";
|
||||
public static final String HOST_127_0_0_1 = "127.0.0.1";
|
||||
|
||||
public static final String BIND_SESSION_ENABLE = "enable";
|
||||
public static final String BIND_SESSION_DISABLE = "disable";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,11 @@
|
||||
package io.cloudbeaver.service;
|
||||
|
||||
import io.cloudbeaver.model.app.ServletApplication;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Servlet service
|
||||
*/
|
||||
@@ -28,4 +31,9 @@ public interface DBWServiceBindingServlet<APPLICATION extends ServletApplication
|
||||
}
|
||||
|
||||
void addServlets(APPLICATION application, DBWServletContext servletContext) throws DBException;
|
||||
|
||||
@NotNull
|
||||
default List<String> getExcludedServletPaths(@NotNull APPLICATION application) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,12 +36,24 @@ import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.dbeaver.utils.GeneralUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ServletAppUtils {
|
||||
private static final String HEADER_ORIGIN = "Origin";
|
||||
private static final String HEADER_X_ORIGIN = "X-Origin";
|
||||
private static final String HEADER_REFERER = "Referer";
|
||||
|
||||
private static final String HEADER_FORWARDED_SCHEME = "X-Forwarded-Scheme";
|
||||
private static final String HEADER_FORWARDED_HOST = "X-Forwarded-Host";
|
||||
private static final Set<Integer> DEFAULT_PORTS = Set.of(
|
||||
80,
|
||||
443
|
||||
);
|
||||
|
||||
|
||||
private static final Log log = Log.getLog(ServletAppUtils.class);
|
||||
|
||||
public static String getRelativePath(String path, String curDir) {
|
||||
@@ -168,16 +180,24 @@ public class ServletAppUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StringBuilder getAuthApiPrefix(String serviceId) throws DBException {
|
||||
return getAuthApiPrefix(getAuthApplication(), serviceId);
|
||||
public static StringBuilder getAuthApiUri(@NotNull String serviceId, @NotNull String origin) throws DBException {
|
||||
return getAuthApiUri(getAuthApplication(), serviceId, origin);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StringBuilder getAuthApiPrefix(ServletAuthApplication webAuthApplication, String serviceId) {
|
||||
String authUrl = removeSideSlashes(webAuthApplication.getAuthServiceURL());
|
||||
StringBuilder apiPrefix = new StringBuilder(authUrl);
|
||||
apiPrefix.append("/").append(serviceId).append("/");
|
||||
return apiPrefix;
|
||||
public static StringBuilder getAuthApiUri(
|
||||
@NotNull ServletAuthApplication webAuthApplication,
|
||||
@NotNull String serviceId,
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
String finalOrigin = webAuthApplication.modifyOrigin(origin);
|
||||
StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin));
|
||||
String serviceUriSegment = removeSideSlashes(webAuthApplication.getAuthServiceUriSegment());
|
||||
if (CommonUtils.isNotEmpty(serviceUriSegment)) {
|
||||
authUriBuilder.append("/").append(serviceUriSegment);
|
||||
}
|
||||
authUriBuilder.append("/").append(serviceId).append("/");
|
||||
return authUriBuilder;
|
||||
}
|
||||
|
||||
public static void addResponseCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, long maxSessionIdleTime) {
|
||||
@@ -272,12 +292,68 @@ public class ServletAppUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getFullServerUrl() {
|
||||
ServletApplication application = ServletAppUtils.getServletApplication();
|
||||
return Stream.of(application.getServerURL(), application.getRootURI())
|
||||
.map(ServletAppUtils::removeSideSlashes)
|
||||
.filter(CommonUtils::isNotEmpty)
|
||||
.collect(Collectors.joining("/"));
|
||||
public static String getOriginFromRequestOrThrow(HttpServletRequest request) throws DBWebException {
|
||||
String origin = request.getHeader(HEADER_ORIGIN);
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
origin = request.getHeader(HEADER_X_ORIGIN);
|
||||
}
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
origin = request.getHeader(HEADER_REFERER);
|
||||
}
|
||||
String forwardedScheme = request.getHeader(HEADER_FORWARDED_SCHEME);
|
||||
String forwardedHost = request.getHeader(HEADER_FORWARDED_HOST);
|
||||
if (CommonUtils.isNotEmpty(forwardedScheme) && CommonUtils.isNotEmpty(forwardedHost)) {
|
||||
origin = forwardedScheme + "://" + forwardedHost;
|
||||
}
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
URI requestUrl = URI.create(request.getRequestURL().toString());
|
||||
origin = getRootUrlFromUri(requestUrl) + "/";
|
||||
}
|
||||
origin = removeSideSlashes(origin);
|
||||
var app = ServletAppUtils.getServletApplication();
|
||||
String rootUri = removeSideSlashes(app.getRootURI());
|
||||
if (!origin.endsWith(rootUri)) {
|
||||
origin = origin + "/" + rootUri + "/";
|
||||
}
|
||||
|
||||
origin = removeSideSlashes(origin);
|
||||
URI uri = URI.create(origin);
|
||||
if (DEFAULT_PORTS.contains(uri.getPort())) {
|
||||
try {
|
||||
origin = new URI(
|
||||
uri.getScheme(),
|
||||
uri.getUserInfo(),
|
||||
uri.getHost(),
|
||||
-1,
|
||||
uri.getPath(),
|
||||
uri.getQuery(),
|
||||
uri.getFragment()
|
||||
).toString();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Failed to create URI without port", e);
|
||||
}
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
|
||||
public static String getRootUrlFromUri(@NotNull URI uri) {
|
||||
var builder = new StringBuilder()
|
||||
.append(uri.getScheme())
|
||||
.append("://")
|
||||
.append(uri.getHost());
|
||||
if (uri.getPort() > 0) {
|
||||
builder.append(":").append(uri.getPort());
|
||||
}
|
||||
return removeSideSlashes(substringBeforeRootURI(builder.toString()));
|
||||
}
|
||||
|
||||
public static String substringBeforeRootURI(@NotNull String uri) {
|
||||
String rootUri = removeSideSlashes(getServletApplication().getRootURI());
|
||||
if (CommonUtils.isEmpty(rootUri)) {
|
||||
return uri;
|
||||
}
|
||||
String[] split = uri.split(rootUri);
|
||||
return split[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Community Product
|
||||
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
|
||||
Bundle-Version: 25.1.1.qualifier
|
||||
Bundle-Release-Date: 20250616
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-Version: 25.1.4.qualifier
|
||||
Bundle-Release-Date: 20250804
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
Automatic-Module-Name: io.cloudbeaver.product.ce
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce</artifactId>
|
||||
<version>25.1.1-SNAPSHOT</version>
|
||||
<version>25.1.4-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||