From 2e5b092ce74be0440801e1a8dce60606a11ba3b1 Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:46:18 +0200 Subject: [PATCH 01/12] CB-5454 add deprecated message (#2976) * CB-5454 add deprecated message * CB-5454 add info icon to connection dialog message * CB-5454 remove add button * CB-5454 remove template --------- Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com> --- .../.dbeaver/data-sources.json | 24 ++----------------- .../core-blocks/src/InfoItem.module.css | 7 ++++++ webapp/packages/core-blocks/src/InfoItem.tsx | 5 ++-- .../core-connections/src/locales/de.ts | 1 + .../core-connections/src/locales/en.ts | 1 + .../core-connections/src/locales/fr.ts | 1 + .../core-connections/src/locales/it.ts | 1 + .../core-connections/src/locales/ru.ts | 1 + .../core-connections/src/locales/zh.ts | 8 +++---- .../src/ConnectionDialog/ConnectionDialog.tsx | 8 ++++++- .../Connections/ConnectionsAdministration.tsx | 16 ++----------- .../ConnectionsAdministrationService.ts | 6 ++++- .../src/locales/en.ts | 4 ---- .../src/locales/fr.ts | 4 ---- .../src/locales/it.ts | 4 ---- .../src/locales/ru.ts | 4 ---- .../src/locales/zh.ts | 1 - 17 files changed, 34 insertions(+), 62 deletions(-) diff --git a/config/GlobalConfiguration/.dbeaver/data-sources.json b/config/GlobalConfiguration/.dbeaver/data-sources.json index c954ec82d9..a5f18e204f 100644 --- a/config/GlobalConfiguration/.dbeaver/data-sources.json +++ b/config/GlobalConfiguration/.dbeaver/data-sources.json @@ -1,24 +1,4 @@ { - "folders": {}, - "connections": { - "postgresql-template-1": { - "provider": "postgresql", - "driver": "postgres-jdbc", - "name": "PostgreSQL (Template)", - "save-password": false, - "show-system-objects": false, - "read-only": true, - "template": true, - "configuration": { - "host": "localhost", - "port": "5432", - "database": "postgres", - "url": "jdbc:postgresql://localhost:5432/postgres", - "type": "dev", - "provider-properties": { - "@dbeaver-show-non-default-db@": "false" - } - } - } - } + "folders": {}, + "connections": {} } diff --git a/webapp/packages/core-blocks/src/InfoItem.module.css b/webapp/packages/core-blocks/src/InfoItem.module.css index 5a8c0a4106..71f2362414 100644 --- a/webapp/packages/core-blocks/src/InfoItem.module.css +++ b/webapp/packages/core-blocks/src/InfoItem.module.css @@ -10,8 +10,15 @@ align-items: center; flex: 0 0 auto; } + .iconOrImage { width: 24px; height: 24px; margin-right: 16px; + + &.compact { + width: 18px; + height: 18px; + margin-right: 8px; + } } diff --git a/webapp/packages/core-blocks/src/InfoItem.tsx b/webapp/packages/core-blocks/src/InfoItem.tsx index f0039e961a..ea73c59c76 100644 --- a/webapp/packages/core-blocks/src/InfoItem.tsx +++ b/webapp/packages/core-blocks/src/InfoItem.tsx @@ -18,19 +18,20 @@ import { useS } from './useS.js'; export interface IInfoItem { info: TLocalizationToken; icon?: string; + compact?: boolean; } interface Props extends IInfoItem { className?: string; } -export const InfoItem = observer(function InfoItem({ info, icon = '/icons/info_icon.svg', className }) { +export const InfoItem = observer(function InfoItem({ info, compact, icon = '/icons/info_icon.svg', className }) { const styles = useS(style); const translate = useTranslate(); return (
- + {translate(info)}
); diff --git a/webapp/packages/core-connections/src/locales/de.ts b/webapp/packages/core-connections/src/locales/de.ts index c92b054ac0..e5ee57cb7f 100644 --- a/webapp/packages/core-connections/src/locales/de.ts +++ b/webapp/packages/core-connections/src/locales/de.ts @@ -58,4 +58,5 @@ export default [ ['core_connections_settings_disable', 'Disable'], ['core_connections_settings_disable_description', 'Disable the ability to create new connections'], + ['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'], ]; diff --git a/webapp/packages/core-connections/src/locales/en.ts b/webapp/packages/core-connections/src/locales/en.ts index ca44fcca48..93133fd7db 100644 --- a/webapp/packages/core-connections/src/locales/en.ts +++ b/webapp/packages/core-connections/src/locales/en.ts @@ -102,4 +102,5 @@ export default [ ['core_connections_settings_disable', 'Disable'], ['core_connections_settings_disable_description', 'Disable the ability to create new connections'], + ['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'], ]; diff --git a/webapp/packages/core-connections/src/locales/fr.ts b/webapp/packages/core-connections/src/locales/fr.ts index c38d142279..808e902f12 100644 --- a/webapp/packages/core-connections/src/locales/fr.ts +++ b/webapp/packages/core-connections/src/locales/fr.ts @@ -111,4 +111,5 @@ export default [ ['core_connections_settings_disable', 'Disable'], ['core_connections_settings_disable_description', 'Disable the ability to create new connections'], + ['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'], ]; diff --git a/webapp/packages/core-connections/src/locales/it.ts b/webapp/packages/core-connections/src/locales/it.ts index 3d3002693b..f5f61ab238 100644 --- a/webapp/packages/core-connections/src/locales/it.ts +++ b/webapp/packages/core-connections/src/locales/it.ts @@ -100,4 +100,5 @@ export default [ ['core_connections_settings_disable', 'Disable'], ['core_connections_settings_disable_description', 'Disable the ability to create new connections'], + ['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'], ]; diff --git a/webapp/packages/core-connections/src/locales/ru.ts b/webapp/packages/core-connections/src/locales/ru.ts index ae8dfeae11..804cb0b13f 100644 --- a/webapp/packages/core-connections/src/locales/ru.ts +++ b/webapp/packages/core-connections/src/locales/ru.ts @@ -103,4 +103,5 @@ export default [ ['core_connections_settings_disable', 'Отключить'], ['core_connections_settings_disable_description', 'Отключить возможность создания новых подключений'], + ['connections_templates_deprecated_message', 'Шаблоны подключений больше не поддерживаются и будут удалены в будущих релизах'], ]; diff --git a/webapp/packages/core-connections/src/locales/zh.ts b/webapp/packages/core-connections/src/locales/zh.ts index 57f7bfbb5b..027ec3a69a 100644 --- a/webapp/packages/core-connections/src/locales/zh.ts +++ b/webapp/packages/core-connections/src/locales/zh.ts @@ -37,10 +37,7 @@ export default [ ['connections_connection_authentication_save_credentials_for_session', '当前会话不再询问'], ['connections_connection_authentication_save_credentials_for_session_tooltip', '注销后将移除凭证'], ['connections_connection_edit_save_credentials_shared', '为所有访问用户保存凭证'], - [ - 'connections_connection_edit_save_credentials_shared_tooltip', - '凭证将用于为所有访问用户自动连接数据库', - ], + ['connections_connection_edit_save_credentials_shared_tooltip', '凭证将用于为所有访问用户自动连接数据库'], ['connections_connection_share_credentials', '分享凭证至团队'], ['connections_connection_share_credentials_tooltip', '凭证将用于为所有团队用户自动连接数据库'], ['connections_connection_credentials_provisioning', '认证凭据'], @@ -52,7 +49,7 @@ export default [ ['connections_connection_edit_search_hosts', '主机名称'], ['connections_connection_address', '地址'], ['connections_connection_folder', '文件夹'], - ['connections_connection_folder_validation', "文件夹名称不得包含以下符号 / : \" \\ ' <> | ? * 且不能以点开头"], + ['connections_connection_folder_validation', '文件夹名称不得包含以下符号 / : " \\ \' <> | ? * 且不能以点开头'], ['connections_connection_name', '连接名称'], ['connections_connection_access_admin_info', '管理员可以查看除其他用户的私有连接之外的所有连接。'], ['connections_connection_description', '描述'], @@ -95,4 +92,5 @@ export default [ ['core_connections_settings_disable', 'Disable'], ['core_connections_settings_disable_description', 'Disable the ability to create new connections'], + ['connections_templates_deprecated_message', 'Template connections are deprecated and will be removed in future releases'], ]; diff --git a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx index 91cb00ceb3..d4c1b95155 100644 --- a/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx +++ b/webapp/packages/plugin-connection-template/src/ConnectionDialog/ConnectionDialog.tsx @@ -14,6 +14,7 @@ import { CommonDialogWrapper, ErrorMessage, Form, + InfoItem, s, useAdministrationSettings, useErrorDetails, @@ -38,7 +39,12 @@ export const ConnectionDialog: DialogComponent = observer(function C const dialog = useConnectionDialog(rejectDialog); const errorDetails = useErrorDetails(dialog.connectException); - const subTitle = dialog.step === ConnectionStep.Connection ? dialog.template?.name : undefined; + const subTitle = + dialog.step === ConnectionStep.Connection ? ( + dialog.template?.name + ) : ( + + ); return ( diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx index e98371c1aa..5472d94c7b 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsAdministration.tsx @@ -14,8 +14,8 @@ import { ExceptionMessageStyles, Group, GroupItem, - GroupSubTitle, GroupTitle, + InfoItem, Loader, s, SContext, @@ -25,13 +25,11 @@ import { useS, useTranslate, } from '@cloudbeaver/core-blocks'; -import { useService } from '@cloudbeaver/core-di'; import ConnectionsAdministrationStyle from './ConnectionsAdministration.module.css'; import { ConnectionsTable } from './ConnectionsTable/ConnectionsTable.js'; import { useConnectionsTable } from './ConnectionsTable/useConnectionsTable.js'; import { CreateConnection } from './CreateConnection/CreateConnection.js'; -import { CreateConnectionService } from './CreateConnectionService.js'; const registry: StyleRegistry = [ [ @@ -50,26 +48,16 @@ export const ConnectionsAdministration = observer - {translate('templates_administration_info_message')} + - - {translate('ui_add')} - this.serverConfigResource.distributed, + isHidden: () => this.serverConfigResource.distributed || !this.connectionInfoResource.values.some(connection => connection.template), getContentComponent: () => ConnectionsAdministration, getDrawerComponent: () => ConnectionsDrawerItem, onDeActivate: this.refreshUserConnections.bind(this), @@ -78,6 +78,10 @@ export class ConnectionsAdministrationService extends Bootstrap { this.connectionDetailsPlaceholder.add(SSH, 2); } + override async load(): Promise { + await this.connectionInfoResource.load(); + } + private async refreshUserConnections(configuration: boolean, outside: boolean, outsideAdminPage: boolean): Promise { // TODO: we have to track users' leaving the page if (outside) { diff --git a/webapp/packages/plugin-connections-administration/src/locales/en.ts b/webapp/packages/plugin-connections-administration/src/locales/en.ts index 3718ace448..ba1aed8728 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/en.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/en.ts @@ -13,9 +13,5 @@ export default [ ['plugin_connections_connection_edit_reconnect_failed', 'Failed to reconnect'], ['connections_administration_deactivate_message', "Your connection's settings will be lost. Do you want to continue?"], - [ - 'templates_administration_info_message', - 'The templates enable administrators to define various reusable connection parameters, subsequently allowing users to create multiple connections based on these templates.', - ], ['connections_administration_connection_create_error', 'Failed to create connection'], ]; diff --git a/webapp/packages/plugin-connections-administration/src/locales/fr.ts b/webapp/packages/plugin-connections-administration/src/locales/fr.ts index a70584acef..6efa32be67 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/fr.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/fr.ts @@ -13,9 +13,5 @@ export default [ ['plugin_connections_connection_edit_reconnect_failed', 'Échec de la reconnexion'], ['connections_administration_deactivate_message', 'Les paramètres de votre connexion seront perdus. Voulez-vous continuer ?'], - [ - 'templates_administration_info_message', - 'Les modèles permettent aux administrateurs de définir divers paramètres de connexion réutilisables, permettant ensuite aux utilisateurs de créer plusieurs connexions basées sur ces modèles.', - ], ['connections_administration_connection_create_error', 'Failed to create connection'], ]; diff --git a/webapp/packages/plugin-connections-administration/src/locales/it.ts b/webapp/packages/plugin-connections-administration/src/locales/it.ts index c1eea9c399..676b42db43 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/it.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/it.ts @@ -8,9 +8,5 @@ export default [ ['plugin_connections_connection_edit_menu_item_title', 'Modifica Connessione'], ['plugin_connections_connection_edit_cancel_title', "Conferma l'annullamento"], - [ - 'templates_administration_info_message', - 'The templates enable administrators to define various reusable connection parameters, subsequently allowing users to create multiple connections based on these templates.', - ], ['connections_administration_connection_create_error', 'Failed to create connection'], ]; diff --git a/webapp/packages/plugin-connections-administration/src/locales/ru.ts b/webapp/packages/plugin-connections-administration/src/locales/ru.ts index 3ffea2835b..d3691ed3af 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/ru.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/ru.ts @@ -13,9 +13,5 @@ export default [ ['plugin_connections_connection_edit_reconnect_failed', 'Не удалось переподключиться'], ['connections_administration_deactivate_message', 'Настройки вашего подключения будут потеряны. Вы хотите продолжить?'], - [ - 'templates_administration_info_message', - 'Шаблоны позволяют администраторам определять различные параметры подключения, а затем позволяют пользователям создавать несколько подключений на основе этих шаблонов.', - ], ['connections_administration_connection_create_error', 'Не удалось создать подключение'], ]; diff --git a/webapp/packages/plugin-connections-administration/src/locales/zh.ts b/webapp/packages/plugin-connections-administration/src/locales/zh.ts index 149fe0a2b0..eabd8240f1 100644 --- a/webapp/packages/plugin-connections-administration/src/locales/zh.ts +++ b/webapp/packages/plugin-connections-administration/src/locales/zh.ts @@ -13,6 +13,5 @@ export default [ ['plugin_connections_connection_edit_reconnect_failed', '重新连接失败'], ['connections_administration_deactivate_message', '您的连接设置将丢失。您要继续吗?'], - ['templates_administration_info_message', '管理员可在数据库连接模板中定义各种可重用的连接参数,之后用户可基于这些模板创建多个数据库连接。'], ['connections_administration_connection_create_error', 'Failed to create connection'], ]; From 3a85f1a4be26ea4e3406a31e8df9da24418bb641 Mon Sep 17 00:00:00 2001 From: Anastasiya <45152336+LonwoLonwo@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:04:33 +0300 Subject: [PATCH 02/12] Update SECURITY.md (#2989) Add current version --- SECURITY.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 9d72644c1e..094ed1ba00 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,9 +9,10 @@ currently being supported with security updates. | ------- | --------- | | 22.x | yes | | 23.x | yes | +| 24.x | yes | ## Reporting a Vulnerability -Please report (suspected) security vulnerabilities to devops@dbeaver.com. -You will receive a response from us within 48 hours. -If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days. +Please report (suspected) security vulnerabilities to devops@dbeaver.com. +You will receive a response from us within 48 hours. +If the issue is confirmed, we will release a patch as soon as possible, depending on complexity, but historically, within a few days. From 1a5192815cb0764c0a89990ffe9d423a1f1176b3 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Thu, 10 Oct 2024 16:20:51 +0200 Subject: [PATCH 03/12] CB-5640-update-fileds-ui-for-dark-and-light-themes (#2985) * CB-5640 adds colors to inputs according to design (disabled, readonly) * CB-5640 merges disable logic into readonly * CB-5640 adds aria-disabled prop and styles to input * CB-5640 adds more styles for input * CB-5640 pr fixes * CB-5640 reverts logic * CB-5640 fixes styles * CB-5640 fixes styles * CB-5640 merges disable logic into readonly for all of the inputs all over the app * CB-5640 reverts form-controls styles * CB-5640 reverts form-controls styles * CB-5640 makes disabled design according to the figma * CB-5640 makes checkbox dissapear * CB-5640 cleanup --------- Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com> --- .../core-blocks/src/FormControls/Filter.tsx | 2 +- .../InputField/InputField.module.css | 2 -- .../ObjectPropertyInfoForm/RenderField.tsx | 9 +++------ .../core-theming/src/styles/_checkbox.scss | 2 +- .../core-theming/src/styles/_form-controls.scss | 15 ++++----------- .../core-theming/src/styles/_theme-dark.scss | 6 +++--- .../core-theming/src/styles/main/color.pure.scss | 3 ++- .../Users/Teams/Options/TeamOptions.tsx | 6 +++--- .../UserForm/Info/UserFormInfoCredentials.tsx | 6 +++--- .../Dialog/AuthProviderForm/AuthProviderForm.tsx | 2 +- .../NetworkHandlerAuthForm.tsx | 4 ++-- .../Options/AdvancedPropertiesForm.tsx | 3 +-- .../src/ConnectionForm/Options/Options.tsx | 8 +++----- .../ConnectionForm/Options/ParametersForm.tsx | 8 ++++---- .../src/ConnectionForm/SSH/SSH.tsx | 16 ++++++---------- .../src/SaveScriptDialog.tsx | 2 +- .../src/SettingsPanel/Setting.tsx | 3 +-- .../UserAuthenticationPart/ChangePassword.tsx | 6 +++--- .../UserInfoPart/UserProfileFormInfo.tsx | 6 +++--- 19 files changed, 45 insertions(+), 64 deletions(-) diff --git a/webapp/packages/core-blocks/src/FormControls/Filter.tsx b/webapp/packages/core-blocks/src/FormControls/Filter.tsx index c7df95ab9f..162ae2a57d 100644 --- a/webapp/packages/core-blocks/src/FormControls/Filter.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Filter.tsx @@ -116,7 +116,7 @@ export const Filter = observer>(functio autoComplete="off" className={s(styles, { inputField: true })} placeholder={placeholder} - disabled={disabled} + readOnly={disabled} name={name} value={value} onChange={handleChange} diff --git a/webapp/packages/core-blocks/src/FormControls/InputField/InputField.module.css b/webapp/packages/core-blocks/src/FormControls/InputField/InputField.module.css index 80befd67bb..6a36510309 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField/InputField.module.css +++ b/webapp/packages/core-blocks/src/FormControls/InputField/InputField.module.css @@ -47,10 +47,8 @@ align-items: center; justify-content: center; } - .input[disabled] + .iconContainer { cursor: auto; - opacity: 0.8; } .input:not(:only-child) { padding-right: 32px !important; diff --git a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx index f3560b3ee2..d8aa15dae7 100644 --- a/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx +++ b/webapp/packages/core-blocks/src/ObjectPropertyInfo/ObjectPropertyInfoForm/RenderField.tsx @@ -221,8 +221,7 @@ export const RenderField = observer(function RenderField({ placeholder={passwordSavedMessage} name={property.id!} value={value} - disabled={disabled} - readOnly={readOnly} + readOnly={readOnly || disabled} className={className} > {property.displayName ?? ''} @@ -243,8 +242,7 @@ export const RenderField = observer(function RenderField({ autoHide={autoHide} description={property.hint} placeholder={passwordSavedMessage} - disabled={disabled} - readOnly={readOnly} + readOnly={readOnly || disabled} autoComplete={RESERVED_KEYWORDS.includes(autofillToken) ? autofillToken : `${autofillToken} ${property.id}`} className={className} canShowPassword={canShowPassword} @@ -266,8 +264,7 @@ export const RenderField = observer(function RenderField({ defaultValue={defaultValue} description={property.hint} placeholder={passwordSavedMessage} - disabled={disabled} - readOnly={readOnly} + readOnly={readOnly || disabled} autoComplete={RESERVED_KEYWORDS.includes(autofillToken) ? autofillToken : `${autofillToken} ${property.id}`} className={className} canShowPassword={canShowPassword} diff --git a/webapp/packages/core-theming/src/styles/_checkbox.scss b/webapp/packages/core-theming/src/styles/_checkbox.scss index 45f2d22161..16b4169927 100644 --- a/webapp/packages/core-theming/src/styles/_checkbox.scss +++ b/webapp/packages/core-theming/src/styles/_checkbox.scss @@ -19,7 +19,7 @@ $mdc-checkbox-icon-size: 16px; @extend .mdc-checkbox__native-control; &:disabled { - opacity: 0; + opacity: 0 !important; } } .theme-checkbox__background { diff --git a/webapp/packages/core-theming/src/styles/_form-controls.scss b/webapp/packages/core-theming/src/styles/_form-controls.scss index a029b59cf6..f188cd8d1f 100644 --- a/webapp/packages/core-theming/src/styles/_form-controls.scss +++ b/webapp/packages/core-theming/src/styles/_form-controls.scss @@ -73,26 +73,19 @@ @include mdc-theme-prop(border-color, primary, false); } - &:not([data-select='true'])[readonly] { + &:not([data-select='true'])[readonly], + &:not([data-select='true'])[disabled] { @include mdc-theme-prop(color, input-color-readonly, false); @include mdc-theme-prop(border-color, input-border-readonly, false); @include mdc-theme-prop(background-color, input-background-readonly, false); opacity: 1; + cursor: text; + pointer-events: all; &:-internal-autofill-selected, &:-internal-autofill-previewed { box-shadow: 0 0 0 50px $input-background-readonly inset; } } - &[disabled] { - @include mdc-theme-prop(color, input-color-disabled, false); - @include mdc-theme-prop(border-color, input-border-disabled, false); - @include mdc-theme-prop(background-color, input-background-disabled, false); - opacity: 1; - &:-internal-autofill-selected, - &:-internal-autofill-previewed { - box-shadow: 0 0 0 50px $input-background-disabled inset; - } - } &[data-embedded='true'] { &[disabled], &:not([data-select='true'])[readonly] { diff --git a/webapp/packages/core-theming/src/styles/_theme-dark.scss b/webapp/packages/core-theming/src/styles/_theme-dark.scss index f32bf4a177..836ecfcf19 100644 --- a/webapp/packages/core-theming/src/styles/_theme-dark.scss +++ b/webapp/packages/core-theming/src/styles/_theme-dark.scss @@ -34,9 +34,9 @@ $input-color-readonly: darken($input-color, 5%); $input-border: #585958; $input-border-disabled: darken($input-border, 10%); $input-border-readonly: darken($input-border, 5%); -$input-background: $mdc-theme-secondary; -$input-background-disabled: $input-background; -$input-background-readonly: $input-background; +$input-background: $mdc-theme-surface; +$input-background-disabled: #3e3e3e; +$input-background-readonly: #3e3e3e; $mdc-theme-text-colors: ( dark: ( diff --git a/webapp/packages/core-theming/src/styles/main/color.pure.scss b/webapp/packages/core-theming/src/styles/main/color.pure.scss index 402a43ecb9..c5f809292d 100644 --- a/webapp/packages/core-theming/src/styles/main/color.pure.scss +++ b/webapp/packages/core-theming/src/styles/main/color.pure.scss @@ -6,7 +6,8 @@ * you may not use this file except in compliance with the License. */ -:disabled, [aria-disabled="true"] { +:disabled, +[aria-disabled='true'] { pointer-events: none; cursor: default; opacity: 0.5; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx index 97082c6e5d..a7a4e82111 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/Options/TeamOptions.tsx @@ -23,13 +23,13 @@ export const TeamOptions: TabContainerPanelComponent = observer( return ( - + {translate('administration_teams_team_id')} - + {translate('administration_teams_team_name')} - diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx index 029371d619..ac13ee727f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoCredentials.tsx @@ -54,7 +54,7 @@ export const UserFormInfoCredentials = observer(function UserFormInfoCred return ( {translate('authentication_user_credentials')} - + {translate('authentication_user_name')} {local && ( @@ -67,7 +67,7 @@ export const UserFormInfoCredentials = observer(function UserFormInfoCred autoComplete="new-password" placeholder={editing ? PASSWORD_PLACEHOLDER : ''} canShowPassword={tabState.state['password'] !== ''} - disabled={disabled} + readOnly={disabled} required={!editing} keepSize tiny @@ -79,7 +79,7 @@ export const UserFormInfoCredentials = observer(function UserFormInfoCred type="password" name="passwordRepeat" placeholder={editing ? PASSWORD_PLACEHOLDER : ''} - disabled={disabled} + readOnly={disabled} required={!editing} canShowPassword keepSize diff --git a/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx b/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx index 1cef309f13..d80bb3d3e0 100644 --- a/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx +++ b/webapp/packages/plugin-authentication/src/Dialog/AuthProviderForm/AuthProviderForm.tsx @@ -51,7 +51,7 @@ export const AuthProviderForm = observer(function AuthProviderForm({ prov type={parameter.encryption === 'none' ? 'text' : 'password'} name={parameter.id} state={credentials.credentials} - disabled={authenticate} + readOnly={authenticate} canShowPassword={false} autoComplete={`section-authentication section-${provider.id} ${configuration?.id ?? ''} ${parameter.id}`} > diff --git a/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx b/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx index d8cc310a91..a6f4298a67 100644 --- a/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionAuthentication/NetworkHandlerAuthForm.tsx @@ -67,10 +67,10 @@ export const NetworkHandlerAuthForm = observer(function NetworkHandlerAut {ssh && ( <> - + {translate(`connections_network_handler_${id}_user`, 'connections_network_handler_default_user')} - + {passwordLabel} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx index 8db7be00af..a949a2ebd5 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/AdvancedPropertiesForm.tsx @@ -35,8 +35,7 @@ export const AdvancedPropertiesForm = observer(function AdvancedPropertie min={0} max={MAX_KEEP_ALIVE_INTERVAL} name="keepAliveInterval" - disabled={disabled} - readOnly={readonly} + readOnly={readonly || disabled} title={translate('connections_connection_keep_alive_tooltip')} state={config} defaultState={DEFAULT_CONFIG} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index d95cd5fa7f..d37e416c24 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -216,8 +216,7 @@ export const Options: TabContainerPanelComponent = observe type="text" name="url" state={config} - disabled={disabled} - readOnly={readonly} + readOnly={readonly || disabled} autoComplete={`section-${config.driverId || 'driver'} section-jdbc`} > {translate('plugin_connections_connection_form_part_main_url_jdbc')} @@ -245,7 +244,7 @@ export const Options: TabContainerPanelComponent = observe - + {translate('connections_connection_name')} {!config.template && ( @@ -262,7 +261,6 @@ export const Options: TabContainerPanelComponent = observe type="text" name="folder" state={config} - disabled={disabled} autoComplete={`section-${config.driverId || 'driver'} section-folder`} autoHide readOnly @@ -273,7 +271,7 @@ export const Options: TabContainerPanelComponent = observe )} - diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx index a83cbc8810..1a557dc05b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ParametersForm.tsx @@ -26,19 +26,19 @@ export const ParametersForm = observer(function ParametersForm({ config, {!embedded && ( - + {translate('plugin_connections_connection_form_part_main_custom_host')} - + {translate('plugin_connections_connection_form_part_main_custom_port')} )} - + {translate('plugin_connections_connection_form_part_main_custom_database')} {requiresServerName && ( - + {translate('plugin_connections_connection_form_part_main_custom_server_name')} )} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx index c52f54f34c..93ca791def 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSH.tsx @@ -109,10 +109,10 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ st {translate('connections_network_handler_ssh_tunnel_auth_type')} - + {translate('connections_network_handler_ssh_tunnel_host')} - + {translate('connections_network_handler_ssh_tunnel_port')} @@ -121,8 +121,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ st type="text" name="userName" state={handlerState} - disabled={disabled || !enabled} - readOnly={readonly} + readOnly={readonly || disabled || !enabled} required={handlerState.savePassword} tiny fill @@ -134,8 +133,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ st name="password" autoComplete={isSafari ? 'section-connection-ssh-authentication section-ssh password' : 'new-password'} state={handlerState} - disabled={disabled || !enabled} - readOnly={readonly} + readOnly={readonly || disabled || !enabled} required={!passwordSaved && !keyAuth && handlerState.savePassword} description={passwordSaved ? translate('ui_processing_saved') : undefined} tiny @@ -171,8 +169,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ st type="number" name="aliveInterval" state={handlerState.properties} - disabled={disabled || !enabled} - readOnly={readonly} + readOnly={readonly || disabled || !enabled} labelTooltip={aliveIntervalLabel} tiny > @@ -182,8 +179,7 @@ export const SSH: TabContainerPanelComponent = observer(function SSH({ st type="number" name="sshConnectTimeout" state={handlerState.properties} - disabled={disabled || !enabled} - readOnly={readonly} + readOnly={readonly || disabled || !enabled} labelTooltip={connectTimeoutLabel} tiny > diff --git a/webapp/packages/plugin-resource-manager-scripts/src/SaveScriptDialog.tsx b/webapp/packages/plugin-resource-manager-scripts/src/SaveScriptDialog.tsx index d31edfd3cc..daca09f857 100644 --- a/webapp/packages/plugin-resource-manager-scripts/src/SaveScriptDialog.tsx +++ b/webapp/packages/plugin-resource-manager-scripts/src/SaveScriptDialog.tsx @@ -115,7 +115,7 @@ export const SaveScriptDialog: DialogComponent name="name" state={state} error={!state.valid} - disabled={state.projectId === null} + readOnly={state.projectId === null} description={errorMessage} onChange={state.validate} > diff --git a/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx b/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx index aa9c6a5feb..de2095aca7 100644 --- a/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx +++ b/webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx @@ -130,8 +130,7 @@ export const Setting = observer(function Setting({ source, setting }) { labelTooltip={description} value={value} description={description} - disabled={disabled} - readOnly={readOnly} + readOnly={readOnly || disabled} small onChange={handleChange} > diff --git a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/ChangePassword.tsx b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/ChangePassword.tsx index 8e9218414a..450929203f 100644 --- a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/ChangePassword.tsx +++ b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserAuthenticationPart/ChangePassword.tsx @@ -35,7 +35,7 @@ export const ChangePassword = observer(function ChangePassword({ state, d type="password" name="oldPassword" state={state} - disabled={disabled} + readOnly={disabled} mapValue={(value?: string) => value?.trim() ?? ''} small required @@ -48,7 +48,7 @@ export const ChangePassword = observer(function ChangePassword({ state, d name="password" autoComplete="new-password" state={state} - disabled={disabled} + readOnly={disabled} mapValue={(value?: string) => value?.trim() ?? ''} small required @@ -60,7 +60,7 @@ export const ChangePassword = observer(function ChangePassword({ state, d type="password" name="repeatedPassword" state={state} - disabled={disabled} + readOnly={disabled} mapValue={(value?: string) => value?.trim() ?? ''} small required diff --git a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfo.tsx b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfo.tsx index fc1a71942d..1c2f1b3bef 100644 --- a/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfo.tsx +++ b/webapp/packages/plugin-user-profile/src/UserProfileForm/UserInfoPart/UserProfileFormInfo.tsx @@ -30,13 +30,13 @@ export const UserProfileFormInfo: TabContainerPanelComponent {translate('plugin_user_profile_info')} - + {translate('plugin_user_profile_info_id')} - + {translate('plugin_user_profile_info_displayName')} - + {translate('authentication_user_role')} From 2e5b71e9dd1427456f2b6a9c65e1c3dde627444f Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Thu, 10 Oct 2024 17:38:54 +0200 Subject: [PATCH 04/12] CB-5563 [TE] Change credentials - 'save credentials' is not marked for auth even if it is saved (#2981) * CB-5563 adds saveCredentials to config when loading DriverInfo during driver authorization * CB-5640 fixes save creds checkbox state for SSL * Revert "CB-5640 fixes save creds checkbox state for SSL" This reverts commit e25fc3b5d44eac616d0428ea3d7a4458fdc4e7fd. --------- Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com> --- .../useDatabaseCredentialsAuthDialog.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseCredentialsAuthDialog/useDatabaseCredentialsAuthDialog.ts b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseCredentialsAuthDialog/useDatabaseCredentialsAuthDialog.ts index fb22afe9cd..04fbd04c8b 100644 --- a/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseCredentialsAuthDialog/useDatabaseCredentialsAuthDialog.ts +++ b/webapp/packages/plugin-connections/src/DatabaseAuthDialog/DatabaseCredentialsAuthDialog/useDatabaseCredentialsAuthDialog.ts @@ -107,6 +107,7 @@ export function useDatabaseCredentialsAuthDialog( } } + this.config.saveCredentials = connection.saveCredentials; this.connection = connection; this.driver = driver; From 6220df48453d37ec5206bd2802bb6602c536b7e8 Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Fri, 11 Oct 2024 06:04:55 +0200 Subject: [PATCH 05/12] dbeaver/pro#3420 Gson refactoring (#2965) --- .../src/io/cloudbeaver/WebServiceUtils.java | 3 ++- .../cloudbeaver/server/CBServerConfigurationController.java | 5 +++-- .../src/io/cloudbeaver/service/security/db/CBDatabase.java | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java index e1ddccf294..46ff6fa6bb 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebServiceUtils.java @@ -19,6 +19,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; +import com.google.gson.Strictness; import io.cloudbeaver.model.WebConnectionConfig; import io.cloudbeaver.model.WebNetworkHandlerConfigInput; import io.cloudbeaver.model.WebPropertyInfo; @@ -294,7 +295,7 @@ public static void saveAuthProperties( // Make new Gson parser with type adapters to deserialize into existing credentials InstanceCreator credTypeAdapter = type -> credentials; Gson credGson = new GsonBuilder() - .setLenient() + .setStrictness(Strictness.LENIENT) .registerTypeAdapter(credentials.getClass(), credTypeAdapter) .create(); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java index 883e326314..83302d3c71 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java @@ -19,6 +19,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; +import com.google.gson.Strictness; import io.cloudbeaver.model.app.BaseServerConfigurationController; import io.cloudbeaver.model.app.BaseWebApplication; import io.cloudbeaver.model.config.CBAppConfig; @@ -336,7 +337,7 @@ protected GsonBuilder getGsonBuilder() { InstanceCreator smPasswordPoliceConfigCreator = type -> securityManagerConfiguration.getPasswordPolicyConfiguration(); return new GsonBuilder() - .setLenient() + .setStrictness(Strictness.LENIENT) .registerTypeAdapter(getServerConfiguration().getClass(), serverConfigCreator) .registerTypeAdapter(CBAppConfig.class, appConfigCreator) .registerTypeAdapter(DataSourceNavigatorSettings.class, navSettingsCreator) @@ -372,7 +373,7 @@ private synchronized void writeRuntimeConfig(Path runtimeConfigPath, Map Date: Fri, 11 Oct 2024 06:20:32 +0200 Subject: [PATCH 06/12] Dbeaver/pro#3420 Use long for serialization of configs --- .../model/app/BaseServerConfigurationController.java | 1 + .../server/CBServerConfigurationController.java | 7 +++---- .../server/CBServerConfigurationControllerEmbedded.java | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java index e9d3887df0..781f904e81 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java @@ -51,6 +51,7 @@ public Gson getGson() { return getGsonBuilder().create(); } + @NotNull protected abstract GsonBuilder getGsonBuilder(); public abstract T getServerConfiguration(); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java index 83302d3c71..637ea382d3 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java @@ -16,10 +16,7 @@ */ package io.cloudbeaver.server; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.InstanceCreator; -import com.google.gson.Strictness; +import com.google.gson.*; import io.cloudbeaver.model.app.BaseServerConfigurationController; import io.cloudbeaver.model.app.BaseWebApplication; import io.cloudbeaver.model.config.CBAppConfig; @@ -327,6 +324,7 @@ public Map readConfigurationFile(Path path) throws DBException { } } + @NotNull protected GsonBuilder getGsonBuilder() { // Stupid way to populate existing objects but ok google (https://github.com/google/gson/issues/431) InstanceCreator appConfigCreator = type -> appConfiguration; @@ -338,6 +336,7 @@ protected GsonBuilder getGsonBuilder() { type -> securityManagerConfiguration.getPasswordPolicyConfiguration(); return new GsonBuilder() .setStrictness(Strictness.LENIENT) + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) .registerTypeAdapter(getServerConfiguration().getClass(), serverConfigCreator) .registerTypeAdapter(CBAppConfig.class, appConfigCreator) .registerTypeAdapter(DataSourceNavigatorSettings.class, navSettingsCreator) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java index d51c1f7cbd..87d28cd7d1 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java @@ -92,6 +92,7 @@ private void savePasswordPolicyConfig(Map originServerConfig, Ma } } + @NotNull @Override protected GsonBuilder getGsonBuilder() { GsonBuilder gsonBuilder = super.getGsonBuilder(); From c7fa466509def8808afe94283f6da37c11de1d2f Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Fri, 11 Oct 2024 10:52:55 +0200 Subject: [PATCH 07/12] CB-5707 Change font size in dialogs (#2973) * CB-5707 increases text size to confirmation dialog title * CB-5707 fixes headerTitle with composes styles * CB-5707 fixes dialogBodyContent with composes styles --------- Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com> Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com> --- .../src/CommonDialog/CommonDialog/CommonDialogBody.module.css | 2 ++ .../src/CommonDialog/CommonDialog/CommonDialogHeader.module.css | 1 + 2 files changed, 3 insertions(+) diff --git a/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogBody.module.css b/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogBody.module.css index a89cd87f49..19f3e2bccf 100644 --- a/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogBody.module.css +++ b/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogBody.module.css @@ -60,7 +60,9 @@ } .dialogBodyContent { + composes: theme-typography--body1 from global; flex: 1; + letter-spacing: normal; position: relative; display: flex; flex-direction: column; diff --git a/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogHeader.module.css b/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogHeader.module.css index b60ff87929..cd70decec4 100644 --- a/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogHeader.module.css +++ b/webapp/packages/core-blocks/src/CommonDialog/CommonDialog/CommonDialogHeader.module.css @@ -27,6 +27,7 @@ } .headerTitle { + composes: theme-typography--headline6 from global; margin: 0; overflow: hidden; text-overflow: ellipsis; From eb41e6156acc04c2578c99ca8cdf38c0659f42af Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Fri, 11 Oct 2024 10:54:13 +0200 Subject: [PATCH 08/12] Cb 5728 update frontend dependencies (#2970) * CB-5728 updates dependencies without react-data-grid * CB-5728 updates react-data-grid library * CB-5728 updates dependencies after react-data-grid updation * CB-5728 fixes align in cells for react-data-grid --------- Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com> --- webapp/package.json | 2 +- .../Formatters/CellFormatter.module.css | 7 +- .../src/DataGrid/Formatters/CellFormatter.tsx | 1 + .../src/DataGrid/Formatters/Menu/CellMenu.tsx | 4 +- .../react-data-grid-dist/lib/bundle.cjs | 394 +-- .../react-data-grid-dist/lib/bundle.cjs.map | 2 +- .../react-data-grid-dist/lib/bundle.js | 2518 +++++++++-------- .../react-data-grid-dist/lib/bundle.js.map | 2 +- .../react-data-grid-dist/lib/index.d.ts | 47 +- .../react-data-grid-dist/lib/styles.css | 151 +- .../react-data-grid-dist/package.json | 57 +- webapp/yarn.lock | 2517 ++++++++-------- 12 files changed, 2847 insertions(+), 2855 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 25dcd27415..8ff63b4aed 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -36,7 +36,7 @@ "@testing-library/user-event": "^14", "@types/react": "^18", "@types/react-dom": "^18", - "concurrently": "^8", + "concurrently": "^9", "husky": "^9", "lerna": "^5", "mobx": "^6", diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.module.css b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.module.css index a8fdcc42a1..f61bab5f30 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.module.css +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.module.css @@ -7,10 +7,10 @@ */ .wrapper { - height: 100%; display: flex; overflow: hidden; box-sizing: border-box; + position: relative; } .container { @@ -28,3 +28,8 @@ display: none; } } + +.cellMenu { + width: 25px; + height: 100%; +} diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx index 549f032835..812c964346 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/CellFormatter.tsx @@ -59,6 +59,7 @@ export const CellFormatter = observer(function CellFormatter({ className, spreadsheetActions={spreadsheetActions} resultIndex={context.resultIndex} simple={context.simple} + className={s(styles, { cellMenu: true })} onStateSwitch={setMenuVisible} /> diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx index 26dc0dabe5..bf0e70927c 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/Formatters/Menu/CellMenu.tsx @@ -21,6 +21,7 @@ interface Props { spreadsheetActions: IDataPresentationActions; resultIndex: number; cellKey: IResultSetElementKey; + className?: string; simple: boolean; onClick?: () => void; onStateSwitch?: (state: boolean) => void; @@ -41,6 +42,7 @@ export const CellMenu = observer(function CellMenu({ actions, spreadsheetActions, resultIndex, + className, cellKey, simple, onClick, @@ -70,7 +72,7 @@ export const CellMenu = observer(function CellMenu({ return ( -
+
diff --git a/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs b/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs index 88e288ac7b..b7987950b1 100644 --- a/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs +++ b/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs @@ -59,7 +59,7 @@ function onEditorNavigation({ return false; } -const measuringCellClassname = "mlln6zg7-0-0-beta-44"; +const measuringCellClassname = "mlln6zg7-0-0-beta-47"; function renderMeasuringCells(viewportColumns) { return viewportColumns.map(({ key, @@ -264,18 +264,12 @@ function canExitGrid({ return shiftKey ? atFirstCellInRow && atFirstRow : atLastCellInRow && atLastRow; } -const cell = "cj343x07-0-0-beta-44"; +const cell = "cj343x07-0-0-beta-47"; const cellClassname = `rdg-cell ${cell}`; -const cellFrozen = "csofj7r7-0-0-beta-44"; +const cellFrozen = "csofj7r7-0-0-beta-47"; const cellFrozenClassname = `rdg-cell-frozen ${cellFrozen}`; -function getRowStyle(rowIdx, height) { - if (height !== undefined) { - return { - '--rdg-grid-row-start': rowIdx, - '--rdg-row-height': `${height}px` - }; - } +function getRowStyle(rowIdx) { return { '--rdg-grid-row-start': rowIdx }; @@ -336,37 +330,32 @@ function getHeaderCellRowSpan(column, rowIdx) { return column.parent === undefined ? rowIdx : column.level - column.parent.level; } -const checkboxLabel = "c1bn88vv7-0-0-beta-44"; -const checkboxLabelClassname = `rdg-checkbox-label ${checkboxLabel}`; -const checkboxInput = "c1qt073l7-0-0-beta-44"; -const checkboxInputClassname = `rdg-checkbox-input ${checkboxInput}`; -const checkbox = "cf71kmq7-0-0-beta-44"; -const checkboxClassname = `rdg-checkbox ${checkbox}`; -const checkboxLabelDisabled = "c1lwve4p7-0-0-beta-44"; -const checkboxLabelDisabledClassname = `rdg-checkbox-label-disabled ${checkboxLabelDisabled}`; +const checkbox = "c1bn88vv7-0-0-beta-47"; +const checkboxClassname = `rdg-checkbox-input ${checkbox}`; function renderCheckbox({ onChange, + indeterminate, ...props }) { function handleChange(e) { onChange(e.target.checked, e.nativeEvent.shiftKey); } - return /*#__PURE__*/jsxRuntime.jsxs("label", { - className: clsx(checkboxLabelClassname, props.disabled && checkboxLabelDisabledClassname), - children: [/*#__PURE__*/jsxRuntime.jsx("input", { - type: "checkbox", - ...props, - className: checkboxInputClassname, - onChange: handleChange - }), /*#__PURE__*/jsxRuntime.jsx("div", { - className: checkboxClassname - })] + return /*#__PURE__*/jsxRuntime.jsx("input", { + ref: el => { + if (el) { + el.indeterminate = indeterminate === true; + } + }, + type: "checkbox", + className: checkboxClassname, + onChange: handleChange, + ...props }); } -const groupCellContent = "g1s9ylgp7-0-0-beta-44"; +const groupCellContent = "g1s9ylgp7-0-0-beta-47"; const groupCellContentClassname = `rdg-group-cell-content ${groupCellContent}`; -const caret = "cz54e4y7-0-0-beta-44"; +const caret = "cz54e4y7-0-0-beta-47"; const caretClassname = `rdg-caret ${caret}`; function renderToggleGroup(props) { return /*#__PURE__*/jsxRuntime.jsx(ToggleGroup, { @@ -421,6 +410,7 @@ function useDefaultRenderers() { function SelectCellFormatter({ value, tabIndex, + indeterminate, disabled, onChange, 'aria-label': ariaLabel, @@ -431,6 +421,7 @@ function SelectCellFormatter({ 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, tabIndex, + indeterminate, disabled, checked: value, onChange @@ -447,33 +438,61 @@ function useRowSelection() { if (rowSelectionContext === undefined || rowSelectionChangeContext === undefined) { throw new Error('useRowSelection must be used within DataGrid cells'); } - return [rowSelectionContext, rowSelectionChangeContext]; + return { + isRowSelectionDisabled: rowSelectionContext.isRowSelectionDisabled, + isRowSelected: rowSelectionContext.isRowSelected, + onRowSelectionChange: rowSelectionChangeContext + }; +} +const HeaderRowSelectionContext = /*#__PURE__*/react.createContext(undefined); +const HeaderRowSelectionProvider = HeaderRowSelectionContext.Provider; +const HeaderRowSelectionChangeContext = /*#__PURE__*/react.createContext(undefined); +const HeaderRowSelectionChangeProvider = HeaderRowSelectionChangeContext.Provider; +function useHeaderRowSelection() { + const headerRowSelectionContext = react.useContext(HeaderRowSelectionContext); + const headerRowSelectionChangeContext = react.useContext(HeaderRowSelectionChangeContext); + if (headerRowSelectionContext === undefined || headerRowSelectionChangeContext === undefined) { + throw new Error('useHeaderRowSelection must be used within DataGrid cells'); + } + return { + isIndeterminate: headerRowSelectionContext.isIndeterminate, + isRowSelected: headerRowSelectionContext.isRowSelected, + onRowSelectionChange: headerRowSelectionChangeContext + }; } -const SELECT_COLUMN_KEY = 'select-row'; +const SELECT_COLUMN_KEY = 'rdg-select-column'; function HeaderRenderer(props) { - const [isRowSelected, onRowSelectionChange] = useRowSelection(); + const { + isIndeterminate, + isRowSelected, + onRowSelectionChange + } = useHeaderRowSelection(); return /*#__PURE__*/jsxRuntime.jsx(SelectCellFormatter, { "aria-label": "Select All", tabIndex: props.tabIndex, + indeterminate: isIndeterminate, value: isRowSelected, onChange: checked => { onRowSelectionChange({ - type: 'HEADER', - checked + checked: isIndeterminate ? false : checked }); } }); } function SelectFormatter(props) { - const [isRowSelected, onRowSelectionChange] = useRowSelection(); + const { + isRowSelectionDisabled, + isRowSelected, + onRowSelectionChange + } = useRowSelection(); return /*#__PURE__*/jsxRuntime.jsx(SelectCellFormatter, { "aria-label": "Select", tabIndex: props.tabIndex, + disabled: isRowSelectionDisabled, value: isRowSelected, onChange: (checked, isShiftClick) => { onRowSelectionChange({ - type: 'ROW', row: props.row, checked, isShiftClick @@ -482,14 +501,16 @@ function SelectFormatter(props) { }); } function SelectGroupFormatter(props) { - const [isRowSelected, onRowSelectionChange] = useRowSelection(); + const { + isRowSelected, + onRowSelectionChange + } = useRowSelection(); return /*#__PURE__*/jsxRuntime.jsx(SelectCellFormatter, { "aria-label": "Select Group", tabIndex: props.tabIndex, value: isRowSelected, onChange: checked => { onRowSelectionChange({ - type: 'ROW', row: props.row, checked, isShiftClick: false @@ -802,7 +823,7 @@ function useColumnWidths(columns, viewportColumns, templateColumns, gridRef, gri } function measureColumnWidth(gridRef, key) { const selector = `[data-measuring-cell-key="${CSS.escape(key)}"]`; - const measuringCell = gridRef.current.querySelector(selector); + const measuringCell = gridRef.current?.querySelector(selector); return measuringCell?.getBoundingClientRect().width; } @@ -1035,9 +1056,9 @@ function useViewportRows({ }; } -const cellCopied = "c6ra8a37-0-0-beta-44"; +const cellCopied = "c6ra8a37-0-0-beta-47"; const cellCopiedClassname = `rdg-cell-copied ${cellCopied}`; -const cellDraggedOver = "cq910m07-0-0-beta-44"; +const cellDraggedOver = "cq910m07-0-0-beta-47"; const cellDraggedOverClassname = `rdg-cell-dragged-over ${cellDraggedOver}`; function Cell({ column, @@ -1135,16 +1156,15 @@ function Cell({ }) }); } -const CellComponent = /*#__PURE__*/react.memo( /*#__PURE__*/react.forwardRef(Cell)); -const CellComponent$1 = CellComponent; +const CellComponent = /*#__PURE__*/react.memo(/*#__PURE__*/react.forwardRef(Cell)); function defaultRenderCell(key, props) { return /*#__PURE__*/jsxRuntime.jsx(CellComponent, { ...props }, key); } -const cellDragHandle = "c1w9bbhr7-0-0-beta-44"; -const cellDragHandleFrozenClassname = "c1creorc7-0-0-beta-44"; +const cellDragHandle = "c1w9bbhr7-0-0-beta-47"; +const cellDragHandleFrozenClassname = "c1creorc7-0-0-beta-47"; const cellDragHandleClassname = `rdg-cell-drag-handle ${cellDragHandle}`; function DragHandle({ gridRowStart, @@ -1249,7 +1269,7 @@ function DragHandle({ }); } -const cellEditing = "cis5rrm7-0-0-beta-44"; +const cellEditing = "cis5rrm7-0-0-beta-47"; function EditCell({ column, colSpan, @@ -1260,7 +1280,7 @@ function EditCell({ onKeyDown, navigate }) { - const frameRequestRef = react.useRef(); + const frameRequestRef = react.useRef(undefined); const commitOnOutsideClick = column.editorOptions?.commitOnOutsideClick !== false; const commitOnOutsideMouseDown = useLatestFunc(() => { onClose(true, false); @@ -1333,6 +1353,7 @@ function EditCell({ children: [column.renderEditCell({ column, row, + rowIdx, onRowChange: onEditorRowChange, onClose }), column.editorOptions?.displayCellContent && column.renderCell({ @@ -1387,8 +1408,8 @@ function GroupedColumnHeaderCell({ }); } -const headerSortCellClassname = "h44jtk67-0-0-beta-44"; -const headerSortName = "hcgkhxz7-0-0-beta-44"; +const headerSortCellClassname = "h44jtk67-0-0-beta-47"; +const headerSortName = "hcgkhxz7-0-0-beta-47"; const headerSortNameClassname = `rdg-header-sort-name ${headerSortName}`; function renderHeaderCell({ column, @@ -1422,14 +1443,14 @@ function SortableHeaderCell({ }); } -const cellSortableClassname = "c6l2wv17-0-0-beta-44"; -const cellResizable = "c1kqdw7y7-0-0-beta-44"; +const cellSortableClassname = "c6l2wv17-0-0-beta-47"; +const cellResizable = "c1kqdw7y7-0-0-beta-47"; const cellResizableClassname = `rdg-cell-resizable ${cellResizable}`; -const resizeHandleClassname = "r1y6ywlx7-0-0-beta-44"; +const resizeHandleClassname = "r1y6ywlx7-0-0-beta-47"; const cellDraggableClassname = 'rdg-cell-draggable'; -const cellDragging = "c1bezg5o7-0-0-beta-44"; +const cellDragging = "c1bezg5o7-0-0-beta-47"; const cellDraggingClassname = `rdg-cell-dragging ${cellDragging}`; -const cellOver = "c1vc96037-0-0-beta-44"; +const cellOver = "c1vc96037-0-0-beta-47"; const cellOverClassname = `rdg-cell-drag-over ${cellOver}`; function HeaderCell({ column, @@ -1481,22 +1502,34 @@ function HeaderCell({ left } = headerCell.getBoundingClientRect(); const offset = isRtl ? event.clientX - left : right - event.clientX; + let hasDoubleClicked = false; function onPointerMove(event) { const { + width, right, left } = headerCell.getBoundingClientRect(); - const width = isRtl ? right + offset - event.clientX : event.clientX + offset - left; - if (width > 0) { - onColumnResize(column, clampColumnWidth(width, column)); + let newWidth = isRtl ? right + offset - event.clientX : event.clientX + offset - left; + newWidth = clampColumnWidth(newWidth, column); + if (width > 0 && newWidth !== width) { + onColumnResize(column, newWidth); } } - function onLostPointerCapture() { + function onDoubleClick() { + hasDoubleClicked = true; + onColumnResize(column, 'max-content'); + } + function onLostPointerCapture(event) { + if (!hasDoubleClicked) { + onPointerMove(event); + } currentTarget.removeEventListener('pointermove', onPointerMove); + currentTarget.removeEventListener('dblclick', onDoubleClick); currentTarget.removeEventListener('lostpointercapture', onLostPointerCapture); } currentTarget.setPointerCapture(pointerId); currentTarget.addEventListener('pointermove', onPointerMove); + currentTarget.addEventListener('dblclick', onDoubleClick); currentTarget.addEventListener('lostpointercapture', onLostPointerCapture); } function onSort(ctrlClick) { @@ -1540,9 +1573,6 @@ function HeaderCell({ onSort(event.ctrlKey || event.metaKey); } } - function onDoubleClick() { - onColumnResize(column, 'max-content'); - } function handleFocus(event) { onFocus?.(event); if (shouldFocusGrid) { @@ -1572,8 +1602,8 @@ function HeaderCell({ } function onDrop(event) { setIsOver(false); - if (event.dataTransfer.types.includes(dragDropKey)) { - const sourceKey = event.dataTransfer.getData(dragDropKey); + if (event.dataTransfer.types.includes(dragDropKey.toLowerCase())) { + const sourceKey = event.dataTransfer.getData(dragDropKey.toLowerCase()); if (sourceKey !== column.key) { event.preventDefault(); onColumnsReorder?.(sourceKey, column.key); @@ -1627,7 +1657,6 @@ function HeaderCell({ }), resizable && /*#__PURE__*/jsxRuntime.jsx("div", { className: resizeHandleClassname, onClick: stopPropagation, - onDoubleClick: onDoubleClick, onPointerDown: onPointerDown })] }); @@ -1637,15 +1666,15 @@ function isEventPertinent(event) { return !event.currentTarget.contains(relatedTarget); } -const row = "r1upfr807-0-0-beta-44"; +const row = "r1upfr807-0-0-beta-47"; const rowClassname = `rdg-row ${row}`; -const rowSelected = "r190mhd37-0-0-beta-44"; +const rowSelected = "r190mhd37-0-0-beta-47"; const rowSelectedClassname = 'rdg-row-selected'; -const rowSelectedWithFrozenCell = "r139qu9m7-0-0-beta-44"; +const rowSelectedWithFrozenCell = "r139qu9m7-0-0-beta-47"; const topSummaryRowClassname = 'rdg-top-summary-row'; const bottomSummaryRowClassname = 'rdg-bottom-summary-row'; -const headerRow = "h10tskcx7-0-0-beta-44"; +const headerRow = "h10tskcx7-0-0-beta-47"; const headerRowClassname = `rdg-header-row ${headerRow}`; function HeaderRow({ rowIdx, @@ -1670,7 +1699,7 @@ function HeaderRow({ if (colSpan !== undefined) { index += colSpan - 1; } - cells.push( /*#__PURE__*/jsxRuntime.jsx(HeaderCell, { + cells.push(/*#__PURE__*/jsxRuntime.jsx(HeaderCell, { column: column, colSpan: colSpan, rowIdx: rowIdx, @@ -1717,7 +1746,7 @@ function GroupedColumnHeaderRow({ const { idx } = parent; - cells.push( /*#__PURE__*/jsxRuntime.jsx(GroupedColumnHeaderCell, { + cells.push(/*#__PURE__*/jsxRuntime.jsx(GroupedColumnHeaderCell, { column: parent, rowIdx: rowIdx, isCellSelected: selectedCellIdx === idx, @@ -1738,8 +1767,8 @@ function Row({ className, rowIdx, gridRowStart, - height, selectedCellIdx, + isRowSelectionDisabled, isRowSelected, copiedCellIdx, draggedOverCellIdx, @@ -1799,21 +1828,24 @@ function Row({ })); } } + const selectionValue = react.useMemo(() => ({ + isRowSelected, + isRowSelectionDisabled + }), [isRowSelectionDisabled, isRowSelected]); return /*#__PURE__*/jsxRuntime.jsx(RowSelectionProvider, { - value: isRowSelected, + value: selectionValue, children: /*#__PURE__*/jsxRuntime.jsx("div", { role: "row", ref: ref, className: className, onMouseEnter: handleDragEnter, - style: getRowStyle(gridRowStart, height), + style: getRowStyle(gridRowStart), ...props, children: cells }) }); } -const RowComponent = /*#__PURE__*/react.memo( /*#__PURE__*/react.forwardRef(Row)); -const RowComponent$1 = RowComponent; +const RowComponent = /*#__PURE__*/react.memo(/*#__PURE__*/react.forwardRef(Row)); function defaultRenderRow(key, props) { return /*#__PURE__*/jsxRuntime.jsx(RowComponent, { ...props @@ -1854,7 +1886,7 @@ function ScrollToCell({ }); } -const arrow = "a3ejtar7-0-0-beta-44"; +const arrow = "a3ejtar7-0-0-beta-47"; const arrowClassname = `rdg-sort-arrow ${arrow}`; function renderSortStatus({ sortDirection, @@ -1889,14 +1921,14 @@ function renderSortPriority({ return priority; } -const root = "rnvodz57-0-0-beta-44"; +const root = "rnvodz57-0-0-beta-47"; const rootClassname = `rdg ${root}`; -const viewportDragging = "vlqv91k7-0-0-beta-44"; +const viewportDragging = "vlqv91k7-0-0-beta-47"; const viewportDraggingClassname = `rdg-viewport-dragging ${viewportDragging}`; -const focusSinkClassname = "f1lsfrzw7-0-0-beta-44"; -const focusSinkHeaderAndSummaryClassname = "f1cte0lg7-0-0-beta-44"; +const focusSinkClassname = "f1lsfrzw7-0-0-beta-47"; +const focusSinkHeaderAndSummaryClassname = "f1cte0lg7-0-0-beta-47"; -const summaryCellClassname = "s8wc6fl7-0-0-beta-44"; +const summaryCellClassname = "s8wc6fl7-0-0-beta-47"; function SummaryCell({ column, colSpan, @@ -1939,8 +1971,8 @@ function SummaryCell({ } const SummaryCell$1 = /*#__PURE__*/react.memo(SummaryCell); -const summaryRow = "skuhp557-0-0-beta-44"; -const topSummaryRow = "tf8l5ub7-0-0-beta-44"; +const summaryRow = "skuhp557-0-0-beta-47"; +const topSummaryRow = "tf8l5ub7-0-0-beta-47"; const summaryRowClassname = `rdg-summary-row ${summaryRow}`; function SummaryRow({ rowIdx, @@ -1966,7 +1998,7 @@ function SummaryRow({ index += colSpan - 1; } const isCellSelected = selectedCellIdx === column.idx; - cells.push( /*#__PURE__*/jsxRuntime.jsx(SummaryCell$1, { + cells.push(/*#__PURE__*/jsxRuntime.jsx(SummaryCell$1, { column: column, colSpan: colSpan, row: row, @@ -2001,6 +2033,7 @@ function DataGrid(props, ref) { headerRowHeight: rawHeaderRowHeight, summaryRowHeight: rawSummaryRowHeight, selectedRows, + isRowSelectionDisabled, onSelectedRowsChange, sortColumns, onSortColumnsChange, @@ -2103,11 +2136,23 @@ function DataGrid(props, ref) { renderSortStatus: renderSortStatus$1, renderCell }), [renderCheckbox$1, renderSortStatus$1, renderCell]); - const allRowsSelected = react.useMemo(() => { - const { - length - } = rows; - return length !== 0 && selectedRows != null && rowKeyGetter != null && selectedRows.size >= length && rows.every(row => selectedRows.has(rowKeyGetter(row))); + const headerSelectionValue = react.useMemo(() => { + let hasSelectedRow = false; + let hasUnselectedRow = false; + if (rowKeyGetter != null && selectedRows != null && selectedRows.size > 0) { + for (const row of rows) { + if (selectedRows.has(rowKeyGetter(row))) { + hasSelectedRow = true; + } else { + hasUnselectedRow = true; + } + if (hasSelectedRow && hasUnselectedRow) break; + } + } + return { + isRowSelected: hasSelectedRow && !hasUnselectedRow, + isIndeterminate: hasSelectedRow && hasUnselectedRow + }; }, [rows, selectedRows, rowKeyGetter]); const { rowOverscanStartIdx, @@ -2151,6 +2196,7 @@ function DataGrid(props, ref) { const onCellClickLatest = useLatestFunc(onCellClick); const onCellDoubleClickLatest = useLatestFunc(onCellDoubleClick); const onCellContextMenuLatest = useLatestFunc(onCellContextMenu); + const selectHeaderRowLatest = useLatestFunc(selectHeaderRow); const selectRowLatest = useLatestFunc(selectRow); const handleFormatterRowChangeLatest = useLatestFunc(updateRow); const selectCellLatest = useLatestFunc(selectCell); @@ -2203,44 +2249,51 @@ function DataGrid(props, ref) { setOverRowIdx(rowIdx); latestDraggedOverRowIdx.current = rowIdx; }, []); - function selectRow(args) { + function selectHeaderRow(args) { if (!onSelectedRowsChange) return; assertIsValidKeyGetter(rowKeyGetter); - if (args.type === 'HEADER') { - const newSelectedRows = new Set(selectedRows); - for (const row of rows) { - const rowKey = rowKeyGetter(row); - if (args.checked) { - newSelectedRows.add(rowKey); - } else { - newSelectedRows.delete(rowKey); - } + const newSelectedRows = new Set(selectedRows); + for (const row of rows) { + if (isRowSelectionDisabled?.(row) === true) continue; + const rowKey = rowKeyGetter(row); + if (args.checked) { + newSelectedRows.add(rowKey); + } else { + newSelectedRows.delete(rowKey); } - onSelectedRowsChange(newSelectedRows); - return; } + onSelectedRowsChange(newSelectedRows); + } + function selectRow(args) { + if (!onSelectedRowsChange) return; + assertIsValidKeyGetter(rowKeyGetter); const { row, checked, isShiftClick } = args; + if (isRowSelectionDisabled?.(row) === true) return; const newSelectedRows = new Set(selectedRows); const rowKey = rowKeyGetter(row); + const previousRowIdx = lastSelectedRowIdx.current; + const rowIdx = rows.indexOf(row); + lastSelectedRowIdx.current = rowIdx; if (checked) { newSelectedRows.add(rowKey); - const previousRowIdx = lastSelectedRowIdx.current; - const rowIdx = rows.indexOf(row); - lastSelectedRowIdx.current = rowIdx; - if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { - const step = sign(rowIdx - previousRowIdx); - for (let i = previousRowIdx + step; i !== rowIdx; i += step) { - const row = rows[i]; + } else { + newSelectedRows.delete(rowKey); + } + if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx && previousRowIdx < rows.length) { + const step = sign(rowIdx - previousRowIdx); + for (let i = previousRowIdx + step; i !== rowIdx; i += step) { + const row = rows[i]; + if (isRowSelectionDisabled?.(row) === true) continue; + if (checked) { newSelectedRows.add(rowKeyGetter(row)); + } else { + newSelectedRows.delete(rowKeyGetter(row)); } } - } else { - newSelectedRows.delete(rowKey); - lastSelectedRowIdx.current = -1; } onSelectedRowsChange(newSelectedRows); } @@ -2373,7 +2426,6 @@ function DataGrid(props, ref) { assertIsValidKeyGetter(rowKeyGetter); const rowKey = rowKeyGetter(row); selectRow({ - type: 'ROW', row, checked: !selectedRows.has(rowKey), isShiftClick: false @@ -2705,13 +2757,13 @@ function DataGrid(props, ref) { rowIdx, row, viewportColumns: rowColumns, + isRowSelectionDisabled: isRowSelectionDisabled?.(row) ?? false, isRowSelected, onCellClick: onCellClickLatest, onCellDoubleClick: onCellDoubleClickLatest, onCellContextMenu: onCellContextMenuLatest, rowClass, gridRowStart, - height: getRowHeight(rowIdx), copiedCellIdx: copiedCell !== null && copiedCell.row === row ? columns.findIndex(c => c.key === copiedCell.columnKey) : undefined, selectedCellIdx: selectedRowIdx === rowIdx ? selectedIdx : undefined, draggedOverCellIdx: getDraggedOverCellIdx(rowIdx), @@ -2759,9 +2811,7 @@ function DataGrid(props, ref) { gridTemplateColumns, gridTemplateRows: templateRows, '--rdg-header-row-height': `${headerRowHeight}px`, - '--rdg-summary-row-height': `${summaryRowHeight}px`, '--rdg-scroll-height': `${scrollHeight}px`, - '--rdg-sign': isRtl ? -1 : 1, ...layoutCssVars }, dir: direction, @@ -2769,12 +2819,12 @@ function DataGrid(props, ref) { onScroll: handleScroll, onKeyDown: handleKeyDown, "data-testid": testId, - children: [/*#__PURE__*/jsxRuntime.jsx(DataGridDefaultRenderersProvider, { + children: [/*#__PURE__*/jsxRuntime.jsxs(DataGridDefaultRenderersProvider, { value: defaultGridComponents, - children: /*#__PURE__*/jsxRuntime.jsxs(RowSelectionChangeProvider, { - value: selectRowLatest, - children: [/*#__PURE__*/jsxRuntime.jsxs(RowSelectionProvider, { - value: allRowsSelected, + children: [/*#__PURE__*/jsxRuntime.jsx(HeaderRowSelectionChangeProvider, { + value: selectHeaderRowLatest, + children: /*#__PURE__*/jsxRuntime.jsxs(HeaderRowSelectionProvider, { + value: headerSelectionValue, children: [Array.from({ length: groupedColumnHeaderRowsCount }, (_, index) => /*#__PURE__*/jsxRuntime.jsx(GroupedColumnHeaderRow$1, { @@ -2796,47 +2846,50 @@ function DataGrid(props, ref) { shouldFocusGrid: !selectedCellIsWithinSelectionBounds, direction: direction })] - }), rows.length === 0 && noRowsFallback ? noRowsFallback : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, { - children: [topSummaryRows?.map((row, rowIdx) => { - const gridRowStart = headerRowsCount + 1 + rowIdx; - const summaryRowIdx = mainHeaderRowIdx + 1 + rowIdx; - const isSummaryRowSelected = selectedPosition.rowIdx === summaryRowIdx; - const top = headerRowsHeight + summaryRowHeight * rowIdx; - return /*#__PURE__*/jsxRuntime.jsx(SummaryRow$1, { - "aria-rowindex": gridRowStart, - rowIdx: summaryRowIdx, - gridRowStart: gridRowStart, - row: row, - top: top, - bottom: undefined, - viewportColumns: getRowViewportColumns(summaryRowIdx), - lastFrozenColumnIndex: lastFrozenColumnIndex, - selectedCellIdx: isSummaryRowSelected ? selectedPosition.idx : undefined, - isTop: true, - selectCell: selectCellLatest - }, rowIdx); - }), getViewportRows(), bottomSummaryRows?.map((row, rowIdx) => { - const gridRowStart = headerAndTopSummaryRowsCount + rows.length + rowIdx + 1; - const summaryRowIdx = rows.length + rowIdx; - const isSummaryRowSelected = selectedPosition.rowIdx === summaryRowIdx; - const top = clientHeight > totalRowHeight ? gridHeight - summaryRowHeight * (bottomSummaryRows.length - rowIdx) : undefined; - const bottom = top === undefined ? summaryRowHeight * (bottomSummaryRows.length - 1 - rowIdx) : undefined; - return /*#__PURE__*/jsxRuntime.jsx(SummaryRow$1, { - "aria-rowindex": ariaRowCount - bottomSummaryRowsCount + rowIdx + 1, - rowIdx: summaryRowIdx, - gridRowStart: gridRowStart, - row: row, - top: top, - bottom: bottom, - viewportColumns: getRowViewportColumns(summaryRowIdx), - lastFrozenColumnIndex: lastFrozenColumnIndex, - selectedCellIdx: isSummaryRowSelected ? selectedPosition.idx : undefined, - isTop: false, - selectCell: selectCellLatest - }, rowIdx); - })] + }) + }), rows.length === 0 && noRowsFallback ? noRowsFallback : /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, { + children: [topSummaryRows?.map((row, rowIdx) => { + const gridRowStart = headerRowsCount + 1 + rowIdx; + const summaryRowIdx = mainHeaderRowIdx + 1 + rowIdx; + const isSummaryRowSelected = selectedPosition.rowIdx === summaryRowIdx; + const top = headerRowsHeight + summaryRowHeight * rowIdx; + return /*#__PURE__*/jsxRuntime.jsx(SummaryRow$1, { + "aria-rowindex": gridRowStart, + rowIdx: summaryRowIdx, + gridRowStart: gridRowStart, + row: row, + top: top, + bottom: undefined, + viewportColumns: getRowViewportColumns(summaryRowIdx), + lastFrozenColumnIndex: lastFrozenColumnIndex, + selectedCellIdx: isSummaryRowSelected ? selectedPosition.idx : undefined, + isTop: true, + selectCell: selectCellLatest + }, rowIdx); + }), /*#__PURE__*/jsxRuntime.jsx(RowSelectionChangeProvider, { + value: selectRowLatest, + children: getViewportRows() + }), bottomSummaryRows?.map((row, rowIdx) => { + const gridRowStart = headerAndTopSummaryRowsCount + rows.length + rowIdx + 1; + const summaryRowIdx = rows.length + rowIdx; + const isSummaryRowSelected = selectedPosition.rowIdx === summaryRowIdx; + const top = clientHeight > totalRowHeight ? gridHeight - summaryRowHeight * (bottomSummaryRows.length - rowIdx) : undefined; + const bottom = top === undefined ? summaryRowHeight * (bottomSummaryRows.length - 1 - rowIdx) : undefined; + return /*#__PURE__*/jsxRuntime.jsx(SummaryRow$1, { + "aria-rowindex": ariaRowCount - bottomSummaryRowsCount + rowIdx + 1, + rowIdx: summaryRowIdx, + gridRowStart: gridRowStart, + row: row, + top: top, + bottom: bottom, + viewportColumns: getRowViewportColumns(summaryRowIdx), + lastFrozenColumnIndex: lastFrozenColumnIndex, + selectedCellIdx: isSummaryRowSelected ? selectedPosition.idx : undefined, + isTop: false, + selectCell: selectCellLatest + }, rowIdx); })] - }) + })] }), renderDragHandle(), renderMeasuringCells(viewportColumns), isTreeGrid && /*#__PURE__*/jsxRuntime.jsx("div", { ref: focusSinkRef, tabIndex: isGroupRowFocused ? 0 : -1, @@ -2905,7 +2958,7 @@ function GroupCell({ } const GroupCell$1 = /*#__PURE__*/react.memo(GroupCell); -const groupRow = "g1yxluv37-0-0-beta-44"; +const groupRow = "g1yxluv37-0-0-beta-47"; const groupRowClassname = `rdg-group-row ${groupRow}`; function GroupedRow({ className, @@ -2916,9 +2969,9 @@ function GroupedRow({ isRowSelected, selectCell, gridRowStart, - height, groupBy, toggleGroup, + isRowSelectionDisabled, ...props }) { const idx = viewportColumns[0].key === SELECT_COLUMN_KEY ? row.level + 1 : row.level; @@ -2928,8 +2981,12 @@ function GroupedRow({ idx: -1 }); } + const selectionValue = react.useMemo(() => ({ + isRowSelectionDisabled: false, + isRowSelected + }), [isRowSelected]); return /*#__PURE__*/jsxRuntime.jsx(RowSelectionProvider, { - value: isRowSelected, + value: selectionValue, children: /*#__PURE__*/jsxRuntime.jsx("div", { role: "row", "aria-level": row.level + 1, @@ -2938,7 +2995,7 @@ function GroupedRow({ "aria-expanded": row.isExpanded, className: clsx(rowClassname, groupRowClassname, `rdg-row-${rowIdx % 2 === 0 ? 'even' : 'odd'}`, className, selectedCellIdx === -1 && rowSelectedClassname), onClick: handleSelectGroup, - style: getRowStyle(gridRowStart, height), + style: getRowStyle(gridRowStart), ...props, children: viewportColumns.map(column => /*#__PURE__*/jsxRuntime.jsx(GroupCell$1, { id: row.id, @@ -3295,7 +3352,7 @@ function isReadonlyArray(arr) { } const TreeDataGrid$1 = /*#__PURE__*/react.forwardRef(TreeDataGrid); -const textEditorInternalClassname = "t7vyx3i7-0-0-beta-44"; +const textEditorInternalClassname = "t7vyx3i7-0-0-beta-47"; const textEditorClassname = `rdg-text-editor ${textEditorInternalClassname}`; function autoFocusAndSelect(input) { input?.focus(); @@ -3319,9 +3376,9 @@ function textEditor({ }); } -exports.Cell = CellComponent$1; +exports.Cell = CellComponent; exports.DataGridDefaultRenderersProvider = DataGridDefaultRenderersProvider; -exports.Row = RowComponent$1; +exports.Row = RowComponent; exports.SELECT_COLUMN_KEY = SELECT_COLUMN_KEY; exports.SelectCellFormatter = SelectCellFormatter; exports.SelectColumn = SelectColumn; @@ -3335,5 +3392,6 @@ exports.renderSortPriority = renderSortPriority; exports.renderToggleGroup = renderToggleGroup; exports.renderValue = renderValue; exports.textEditor = textEditor; +exports.useHeaderRowSelection = useHeaderRowSelection; exports.useRowSelection = useRowSelection; //# sourceMappingURL=bundle.cjs.map diff --git a/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs.map b/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs.map index a0731d41f3..4c948f9921 100644 --- a/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs.map +++ b/webapp/packages/plugin-react-data-grid/react-data-grid-dist/lib/bundle.cjs.map @@ -1 +1 @@ -{"version":3,"file":"bundle.cjs","sources":["../src/utils/colSpanUtils.ts","../src/utils/domUtils.ts","../src/utils/eventUtils.ts","../src/utils/keyboardUtils.ts","../src/utils/renderMeasuringCells.tsx","../src/utils/selectedCellUtils.ts","../src/style/cell.ts","../src/utils/styleUtils.ts","../src/utils/index.ts","../src/cellRenderers/renderCheckbox.tsx","../src/cellRenderers/renderToggleGroup.tsx","../src/cellRenderers/renderValue.tsx","../src/DataGridDefaultRenderersProvider.ts","../src/cellRenderers/SelectCellFormatter.tsx","../src/hooks/useRowSelection.ts","../src/Columns.tsx","../src/hooks/useCalculatedColumns.ts","../src/hooks/useLayoutEffect.ts","../src/hooks/useColumnWidths.ts","../src/hooks/useGridDimensions.ts","../src/hooks/useLatestFunc.ts","../src/hooks/useRovingTabIndex.ts","../src/hooks/useViewportColumns.ts","../src/hooks/useViewportRows.ts","../src/Cell.tsx","../src/DragHandle.tsx","../src/EditCell.tsx","../src/GroupedColumnHeaderCell.tsx","../src/renderHeaderCell.tsx","../src/HeaderCell.tsx","../src/style/row.ts","../src/HeaderRow.tsx","../src/GroupedColumnHeaderRow.tsx","../src/Row.tsx","../src/ScrollToCell.tsx","../src/sortStatus.tsx","../src/style/core.ts","../src/SummaryCell.tsx","../src/SummaryRow.tsx","../src/DataGrid.tsx","../src/GroupCell.tsx","../src/GroupRow.tsx","../src/TreeDataGrid.tsx","../src/editors/textEditor.tsx"],"sourcesContent":["import type { CalculatedColumn, ColSpanArgs } from '../types';\n\nexport function getColSpan(\n column: CalculatedColumn,\n lastFrozenColumnIndex: number,\n args: ColSpanArgs\n): number | undefined {\n const colSpan = typeof column.colSpan === 'function' ? column.colSpan(args) : 1;\n if (\n Number.isInteger(colSpan) &&\n colSpan! > 1 &&\n // ignore colSpan if it spans over both frozen and regular columns\n (!column.frozen || column.idx + colSpan! - 1 <= lastFrozenColumnIndex)\n ) {\n return colSpan!;\n }\n return undefined;\n}\n","import type { Maybe } from '../types';\n\nexport function stopPropagation(event: React.SyntheticEvent) {\n event.stopPropagation();\n}\n\nexport function scrollIntoView(element: Maybe) {\n element?.scrollIntoView({ inline: 'nearest', block: 'nearest' });\n}\n","import type { CellEvent } from '../types';\n\nexport function createCellEvent>(\n event: E\n): CellEvent {\n let defaultPrevented = false;\n const cellEvent = {\n ...event,\n preventGridDefault() {\n defaultPrevented = true;\n },\n isGridDefaultPrevented() {\n return defaultPrevented;\n }\n };\n\n Object.setPrototypeOf(cellEvent, Object.getPrototypeOf(event));\n\n return cellEvent;\n}\n","// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values\nconst nonInputKeys = new Set([\n // Special keys\n 'Unidentified',\n // Modifier keys\n 'Alt',\n 'AltGraph',\n 'CapsLock',\n 'Control',\n 'Fn',\n 'FnLock',\n 'Meta',\n 'NumLock',\n 'ScrollLock',\n 'Shift',\n // Whitespace keys\n 'Tab',\n // Navigation keys\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'End',\n 'Home',\n 'PageDown',\n 'PageUp',\n // Editing\n 'Insert',\n // UI keys\n 'ContextMenu',\n 'Escape',\n 'Pause',\n 'Play',\n // Device keys\n 'PrintScreen',\n // Function keys\n 'F1',\n // 'F2', /!\\ specifically allowed, do not edit\n 'F3',\n 'F4',\n 'F5',\n 'F6',\n 'F7',\n 'F8',\n 'F9',\n 'F10',\n 'F11',\n 'F12'\n]);\n\nexport function isCtrlKeyHeldDown(e: React.KeyboardEvent): boolean {\n return (e.ctrlKey || e.metaKey) && e.key !== 'Control';\n}\n\nexport function isDefaultCellInput(event: React.KeyboardEvent): boolean {\n const vKey = 86;\n if (isCtrlKeyHeldDown(event) && event.keyCode !== vKey) return false;\n return !nonInputKeys.has(event.key);\n}\n\n/**\n * By default, the following navigation keys are enabled while an editor is open, under specific conditions:\n * - Tab:\n * - The editor must be an , a