From fdde4348a29f80a60579e95d25a73cf0d3a05780 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:33:05 +0100 Subject: [PATCH] CB-3703 save product configuration from ui (#2334) * CB-4560 api for saving product configuration * CB-4560 save product config in te * CB-4560 move update product config to mutations * CB-3703 feat: extend base components * CB-3703 feat: settings editor * CB-3703 chore: review fixes * CB-3703 chore: pr review * CB-3703 feat: update server configuration icon * CB-4560 add events * CB-3703 fix: localization * CB-3703 chore: localization --------- Co-authored-by: Alexey Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com> --- .../io/cloudbeaver/server/CBApplication.java | 92 ++++++---- .../schema/service.admin.graphqls | 5 + .../service/admin/DBWServiceAdmin.java | 6 +- .../service/admin/WebServiceBindingAdmin.java | 3 + .../service/admin/impl/WebServiceAdmin.java | 11 ++ .../public/icons/server-configuration.svg | 1 + .../AdministrationScreenService.ts | 8 +- .../src/AdministrationSettingsService.ts | 13 +- .../core-administration/tsconfig.json | 48 ++--- webapp/packages/core-app/package.json | 5 +- .../core-app/src/CoreSettingsService.ts | 33 ---- webapp/packages/core-app/src/index.ts | 1 - webapp/packages/core-app/src/manifest.ts | 3 +- webapp/packages/core-app/tsconfig.json | 7 +- .../src/AUTH_SETTINGS_GROUP.ts | 19 +- .../src/AuthSettingsService.ts | 35 ++-- .../src/UserDataService.ts | 6 +- .../core-authentication/src/locales/en.ts | 2 +- .../core-authentication/src/locales/it.ts | 2 +- .../core-authentication/src/locales/ru.ts | 2 +- .../core-authentication/src/locales/zh.ts | 2 +- .../core-authentication/tsconfig.json | 60 +++--- .../src/Containers/ILayoutSizeProps.ts | 1 + .../src/Containers/filterLayoutFakeProps.ts | 6 +- .../src/Containers/shared/ElementsSize.m.css | 12 ++ .../src/FormControls/Checkboxes/Checkbox.tsx | 22 +-- .../FormControls/Checkboxes/FieldCheckbox.tsx | 9 +- .../src/FormControls/Checkboxes/Switch.tsx | 7 +- .../core-blocks/src/FormControls/Combobox.tsx | 6 +- .../src/FormControls/InputField.m.css | 1 - .../FormControls/useCustomInputValidation.ts | 59 ++++-- .../src/ToolsPanel/ToolsAction.tsx | 23 ++- webapp/packages/core-blocks/src/locales/en.ts | 1 + webapp/packages/core-blocks/src/locales/it.ts | 1 + webapp/packages/core-blocks/src/locales/ru.ts | 1 + webapp/packages/core-blocks/tsconfig.json | 42 ++--- webapp/packages/core-bootstrap/package.json | 3 + .../packages/core-bootstrap/src/manifest.ts | 6 + webapp/packages/core-bootstrap/tsconfig.json | 23 ++- .../src/CookiesService.ts | 3 - .../core-browser-settings/package.json | 11 +- .../src/BROWSER_COOKIES_SETTINGS_GROUP.ts} | 8 +- .../src/BROWSER_SETTINGS_GROUP.ts} | 7 +- .../src/BrowserSettingsService.test.ts | 37 ++-- .../src/BrowserSettingsService.ts | 56 +++--- .../src/LocaleService.ts | 35 ++++ .../core-browser-settings/src/locales/en.ts | 4 + .../core-browser-settings/src/locales/it.ts | 4 + .../core-browser-settings/src/locales/ru.ts | 4 + .../core-browser-settings/src/locales/zh.ts | 4 + .../core-browser-settings/src/manifest.ts | 3 +- .../core-browser-settings/tsconfig.json | 27 +++ webapp/packages/core-browser/package.json | 1 + .../src/LocalStorageSaveService.ts | 4 +- webapp/packages/core-browser/src/index.ts | 1 + webapp/packages/core-browser/src/manifest.ts | 3 +- .../bin/typescript-resolve-references.js | 1 + .../core-cli/bin/validate-dependencies.js | 37 ++-- .../configs/webpack.product.dev.config.js | 9 + webapp/packages/core-cli/package.json | 1 - .../src/CONNECTIONS_SETTINGS_GROUP.ts | 10 + .../src/ConnectionsSettingsService.ts | 34 +++- webapp/packages/core-connections/src/index.ts | 1 + .../core-connections/src/locales/en.ts | 1 + .../core-connections/src/locales/it.ts | 1 + .../core-connections/src/locales/ru.ts | 1 + .../core-connections/src/locales/zh.ts | 1 + webapp/packages/core-di/package.json | 4 +- webapp/packages/core-events/package.json | 4 + .../src/EventsSettingsService.test.ts | 42 ++++- .../core-events/src/EventsSettingsService.ts | 56 ++++-- .../src/NOTIFICATIONS_SETTINGS_GROUP.ts | 10 + .../core-events/src/NotificationService.ts | 8 +- webapp/packages/core-events/tsconfig.json | 24 ++- .../packages/core-localization/package.json | 14 -- .../core-localization/src/DEFAULT_LOCALE.ts | 10 + .../packages/core-localization/src/ILocale.ts | 12 ++ .../src/LocalizationService.ts | 172 +++++++++--------- .../packages/core-localization/src/index.ts | 1 + .../packages/core-localization/tsconfig.json | 36 ---- .../core-navigation-tree/package.json | 2 +- .../core-navigation-tree/src/LocaleService.ts | 33 ++++ .../src/NAVIGATION_TREE_SETTINGS_GROUP.ts | 10 + .../src/NavTreeSettingsService.test.ts | 51 ++++-- .../src/NavTreeSettingsService.ts | 62 +++++-- .../src/NodesManager/NavTreeResource.ts | 6 +- .../core-navigation-tree/src/index.ts | 1 + .../core-navigation-tree/src/locales/en.ts | 1 + .../core-navigation-tree/src/locales/it.ts | 1 + .../core-navigation-tree/src/locales/ru.ts | 1 + .../core-navigation-tree/src/locales/zh.ts | 1 + .../core-navigation-tree/src/manifest.ts | 11 +- .../core-navigation-tree/tsconfig.json | 62 +++---- webapp/packages/core-plugin/package.json | 4 +- .../packages/core-plugin/src/LocaleService.ts | 33 ++++ .../core-plugin/src/PluginManagerService.ts | 26 ++- .../core-plugin/src/PluginSettings.ts | 58 ++++-- .../src/SettingsManager/ESettingsValueType.ts | 14 ++ .../SettingsManager/ISettingDescription.ts | 35 ++++ .../src/SettingsManager/SettingsGroup.ts | 38 ++++ .../INTERFACE_SETTINGS_GROUP.ts | 10 + .../SettingsGroups/ROOT_SETTINGS_GROUP.ts | 10 + .../SettingsManager/SettingsManagerService.ts | 54 ++++++ .../src/createDeprecatedResolver.ts | 75 ++++++++ webapp/packages/core-plugin/src/index.ts | 7 + webapp/packages/core-plugin/src/locales/en.ts | 4 + webapp/packages/core-plugin/src/locales/it.ts | 4 + webapp/packages/core-plugin/src/locales/ru.ts | 4 + webapp/packages/core-plugin/src/locales/zh.ts | 4 + webapp/packages/core-plugin/src/manifest.ts | 4 +- webapp/packages/core-plugin/tsconfig.json | 6 + webapp/packages/core-product/package.json | 3 +- .../core-product/src/ProductManagerService.ts | 9 +- .../src/ProductSettingsService.ts | 43 ++++- .../core-resource-manager/package.json | 2 + .../src/LocaleService.ts | 33 ++++ .../src/RESOURCE_MANAGER_SETTINGS_GROUP.ts | 10 + .../core-resource-manager/src/index.ts | 1 + .../core-resource-manager/src/locales/en.ts | 1 + .../core-resource-manager/src/locales/it.ts | 1 + .../core-resource-manager/src/locales/ru.ts | 1 + .../core-resource-manager/src/locales/zh.ts | 1 + .../core-resource-manager/src/manifest.ts | 10 +- .../core-resource-manager/tsconfig.json | 6 + .../core-root/src/ServerConfigResource.ts | 7 + .../packages/core-root/src/ServerService.ts | 36 ---- .../src/ServerSettingsResolverService.ts | 19 ++ .../core-root/src/ServerSettingsService.ts | 110 ++++++++++- .../packages/core-root/src/SessionService.ts | 22 --- .../core-root/src/SessionSettingsService.ts | 35 ++-- webapp/packages/core-root/src/index.ts | 3 +- webapp/packages/core-root/src/manifest.ts | 6 +- webapp/packages/core-root/tsconfig.json | 6 +- .../updateProductConfiguration.gql | 3 + .../core-server-localization/.gitignore | 21 +++ .../core-server-localization/package.json | 29 +++ .../src/ServerLocalizationService.ts | 32 ++++ .../core-server-localization/src/index.ts | 1 + .../core-server-localization/src/manifest.ts | 18 ++ .../core-server-localization/tsconfig.json | 31 ++++ .../core-session-localization/.gitignore | 21 +++ .../core-session-localization/package.json | 29 +++ .../src/SessionLocalizationService.ts | 34 ++++ .../core-session-localization/src/index.ts | 1 + .../core-session-localization/src/manifest.ts | 18 ++ .../core-session-localization/tsconfig.json | 31 ++++ .../core-settings-localization/.gitignore | 21 +++ .../core-settings-localization/package.json | 42 +++++ .../src/LocaleService.ts | 35 ++++ .../src/LocalizationSettingsManagerService.ts | 43 +++++ .../src/SettingsLocalizationService.test.ts} | 41 +++-- .../src/SettingsLocalizationService.ts | 57 ++++++ .../core-settings-localization/src/index.ts | 1 + .../src/locales/en.ts | 4 + .../src/locales/it.ts | 4 + .../src/locales/ru.ts | 4 + .../src/locales/zh.ts | 4 + .../src/manifest.ts | 20 ++ .../core-settings-localization/tsconfig.json | 61 +++++++ webapp/packages/core-settings/package.json | 1 - .../src/ISettingsResolverSource.ts | 3 +- .../core-settings/src/ISettingsSource.ts | 2 + .../src/SettingsManagerService.ts | 73 -------- .../src/SettingsResolverService.ts | 17 ++ .../src/SettingsResolverSource.ts | 42 +++-- .../core-settings/src/SettingsScopeType.ts | 9 + .../core-settings/src/SettingsService.ts | 20 +- .../core-settings/src/SettingsSource.ts | 46 ----- webapp/packages/core-settings/src/index.ts | 6 +- webapp/packages/core-settings/src/manifest.ts | 5 +- webapp/packages/core-settings/tsconfig.json | 3 - .../packages/core-task-manager/package.json | 4 +- .../packages/core-task-manager/tsconfig.json | 4 +- webapp/packages/core-theming/package.json | 1 + .../core-theming/src/THEME_SETTINGS_GROUP.ts | 27 --- .../packages/core-theming/src/ThemeService.ts | 20 +- .../src/ThemeSettingsManagementService.ts | 29 +++ .../src/ThemeSettingsService.test.ts | 41 ++--- .../core-theming/src/ThemeSettingsService.ts | 38 ++-- webapp/packages/core-theming/src/index.ts | 1 - .../packages/core-theming/src/locales/en.ts | 5 +- .../packages/core-theming/src/locales/it.ts | 5 +- .../packages/core-theming/src/locales/ru.ts | 5 +- .../packages/core-theming/src/locales/zh.ts | 5 +- webapp/packages/core-theming/src/manifest.ts | 3 +- .../src/styles/_form-controls.scss | 20 +- webapp/packages/core-theming/src/themes.ts | 2 + webapp/packages/core-theming/tsconfig.json | 33 ++-- webapp/packages/core-utils/package.json | 4 +- webapp/packages/core-utils/src/index.ts | 3 + webapp/packages/core-utils/src/schema.ts | 3 + .../core-utils/src/schemaValidationError.ts | 9 + webapp/packages/core-utils/src/setByPath.ts | 27 +++ .../core-version/src/VersionService.ts | 6 +- .../plugin-administration/package.json | 4 +- .../ServerConfigurationDrawerItem.tsx | 2 +- .../plugin-administration/tsconfig.json | 6 +- .../package.json | 4 +- .../packages/plugin-codemirror6/tsconfig.json | 4 +- .../plugin-connection-custom/package.json | 1 + .../src/CustomConnectionSettingsService.ts | 35 ++-- .../plugin-connection-custom/tsconfig.json | 3 + .../plugin-connection-search/package.json | 1 + .../src/ConnectionSearchSettingsService.ts | 35 ++-- .../plugin-connection-search/tsconfig.json | 3 + .../packages/plugin-connections/package.json | 1 - .../src/CONNECTIONS_SETTINGS_GROUP.ts | 25 --- .../src/PluginConnectionsSettingsService.ts | 38 ++-- .../packages/plugin-connections/src/index.ts | 1 - .../packages/plugin-connections/tsconfig.json | 3 - .../packages/plugin-data-export/package.json | 4 +- .../src/DATA_EXPORT_SETTINGS_GROUP.ts | 10 + .../src/DataExportMenuService.ts | 9 +- .../src/DataExportSettingsService.test.ts | 29 +-- .../src/DataExportSettingsService.ts | 46 +++-- .../plugin-data-export/src/locales/en.ts | 1 + .../plugin-data-export/src/locales/it.ts | 1 + .../plugin-data-export/src/locales/ru.ts | 1 + .../plugin-data-export/src/locales/zh.ts | 1 + .../packages/plugin-data-export/tsconfig.json | 100 +++++----- .../plugin-data-spreadsheet-new/package.json | 3 +- .../src/DataGridSettingsService.test.ts | 39 ++-- .../src/DataGridSettingsService.ts | 53 ++++-- .../src/SpreadsheetBootstrap.ts | 9 +- .../src/locales/en.ts | 1 + .../src/locales/it.ts | 1 + .../src/locales/ru.ts | 1 + .../src/locales/zh.ts | 1 + .../plugin-data-spreadsheet-new/tsconfig.json | 93 +++++----- .../packages/plugin-data-viewer/package.json | 9 +- .../src/DATA_EDITOR_SETTINGS_GROUP.ts | 39 +--- .../src/DataViewerService.ts | 4 +- .../src/DataViewerSettingsService.test.ts | 35 ++-- .../src/DataViewerSettingsService.ts | 93 +++++++--- .../src/TableViewer/TableViewer.tsx | 4 +- .../plugin-data-viewer/src/locales/en.ts | 4 +- .../plugin-data-viewer/src/locales/it.ts | 4 +- .../plugin-data-viewer/src/locales/ru.ts | 4 +- .../plugin-data-viewer/src/locales/zh.ts | 4 +- .../packages/plugin-data-viewer/tsconfig.json | 121 ++++++------ .../packages/plugin-ddl-viewer/tsconfig.json | 6 +- .../plugin-devtools/src/DevToolsService.ts | 6 +- webapp/packages/plugin-help/package.json | 2 +- .../plugin-help/src/PluginBootstrap.ts | 6 +- webapp/packages/plugin-help/tsconfig.json | 6 +- .../packages/plugin-log-viewer/package.json | 1 - .../LogViewer/LOG_VIEWER_SETTINGS_GROUP.ts | 10 + .../src/LogViewer/LogViewerBootstrap.ts | 4 +- .../LogViewerSettingsService.test.ts | 43 +++-- .../src/LogViewer/LogViewerSettingsService.ts | 80 ++++++-- .../src/SessionLogsResource.ts | 6 +- .../plugin-log-viewer/src/locales/en.ts | 1 + .../plugin-log-viewer/src/locales/it.ts | 1 + .../plugin-log-viewer/src/locales/ru.ts | 1 + .../plugin-log-viewer/src/locales/zh.ts | 1 + .../packages/plugin-log-viewer/tsconfig.json | 63 +++---- .../NavigationTabs/NavigationTabsService.ts | 12 +- .../plugin-navigation-tree-rm/tsconfig.json | 4 +- .../plugin-navigation-tree/package.json | 1 - .../src/NavigationTreeSettingsService.ts | 33 +++- .../NodesManager/NavNodeContextMenuService.ts | 10 +- .../src/TreeNew/INodeRenderer.ts | 7 + .../src/TreeNew/Node.tsx | 15 +- .../src/TreeNew/NodeControl.tsx | 7 +- .../src/TreeNew/NodeControlLazy.ts | 10 + .../src/TreeNew/NodeLazy.ts | 10 + .../src/TreeNew/Tree.tsx | 11 +- .../src/TreeNew/useTree.ts | 6 + .../src/TreeNew/useTreeData.ts | 4 + .../src/TreeNew/useTreeState.ts | 10 +- .../plugin-navigation-tree/src/index.ts | 5 + .../plugin-navigation-tree/tsconfig.json | 93 +++++----- .../plugin-object-viewer/package.json | 1 - .../ObjectPropertyTableFooterService.ts | 10 +- .../plugin-object-viewer/tsconfig.json | 9 +- .../package.json | 1 + .../ResourceManagerScriptsSettingsService.ts | 33 +++- .../tsconfig.json | 7 +- .../plugin-resource-manager/package.json | 1 + .../ResourceManagerSettingsService.test.ts | 31 ++-- .../src/ResourceManagerSettingsService.ts | 47 +++-- .../plugin-resource-manager/tsconfig.json | 51 +++--- .../plugin-settings-administration/.gitignore | 17 ++ .../package.json | 39 ++++ .../src/LocaleService.ts | 35 ++++ .../src/SettingsAdministration.m.css | 13 ++ .../src/SettingsAdministration.tsx | 66 +++++++ .../SettingsAdministrationPluginBootstrap.ts | 32 ++++ .../src/SettingsDrawerItem.tsx | 29 +++ .../src/index.ts | 4 + .../src/locales/en.ts | 5 + .../src/locales/it.ts | 5 + .../src/locales/ru.ts | 5 + .../src/locales/zh.ts | 5 + .../src/manifest.ts | 16 ++ .../tsconfig.json | 49 +++++ .../plugin-settings-panel/package.json | 10 +- .../SettingsPanel/SETTINGS_GROUP_ID_PREFIX.ts | 9 + .../src/SettingsPanel/Setting.tsx | 108 +++++++++++ .../src/SettingsPanel/Settings.tsx | 63 +++++++ .../src/SettingsPanel/SettingsGroup.tsx | 54 ------ .../SettingsGroups/GroupNodeControl.tsx | 29 +++ .../SettingsGroups/SettingsGroups.tsx | 29 +++ .../SettingsGroups/groupNodeRenderer.tsx | 16 ++ .../src/SettingsPanel/SettingsInfoForm.tsx | 60 ------ .../SettingsPanel/SettingsInfoFormField.tsx | 102 ----------- .../src/SettingsPanel/SettingsLazy.ts | 10 + .../src/SettingsPanel/SettingsList.tsx | 54 ++++++ .../src/SettingsPanel/SettingsPanelForm.m.css | 6 - .../src/SettingsPanel/SettingsPanelForm.tsx | 35 ---- .../src/SettingsPanel/getSettingGroupId.ts | 12 ++ .../getSettingGroupIdFromElementId.ts | 12 ++ .../src/SettingsPanel/querySettingsGroups.ts | 12 ++ .../src/SettingsPanel/useSettings.ts | 56 ++++++ .../src/SettingsPanel/useTreeScrollSync.ts | 62 +++++++ .../src/SettingsPanelPluginBootstrap.ts | 31 +--- .../plugin-settings-panel/src/index.ts | 4 +- .../plugin-settings-panel/src/locales/en.ts | 5 +- .../plugin-settings-panel/src/locales/it.ts | 5 +- .../plugin-settings-panel/src/locales/ru.ts | 5 +- .../plugin-settings-panel/src/locales/zh.ts | 5 +- .../plugin-settings-panel/tsconfig.json | 10 +- .../src/PluginBootstrap.ts | 4 +- .../src/ResourceEditorSettingsService.ts | 18 +- .../src/ResourceSqlDataSourceBootstrap.ts | 6 +- .../tsconfig.json | 12 +- .../plugin-sql-editor-screen/tsconfig.json | 4 +- .../packages/plugin-sql-editor/package.json | 4 +- .../src/SQL_EDITOR_SETTINGS_GROUP.ts | 10 + .../LocalStorageSqlDataSourceBootstrap.ts | 6 +- .../src/SqlEditor/useTools.tsx | 4 +- .../src/SqlEditorSettingsService.test.ts | 31 +++- .../src/SqlEditorSettingsService.ts | 64 +++++-- .../plugin-sql-editor/src/locales/en.ts | 1 + .../plugin-sql-editor/src/locales/it.ts | 1 + .../plugin-sql-editor/src/locales/ru.ts | 1 + .../plugin-sql-editor/src/locales/zh.ts | 1 + .../packages/plugin-sql-editor/tsconfig.json | 126 ++++++------- .../plugin-sql-generator/package.json | 4 +- .../plugin-sql-generator/tsconfig.json | 8 +- .../packages/plugin-task-manager/package.json | 6 +- .../plugin-task-manager/tsconfig.json | 12 +- .../src/TOOLS_PANEL_SETTINGS_GROUP.ts | 10 + .../src/ToolsPanelSettingsService.ts | 32 +++- .../plugin-tools-panel/src/locales/en.ts | 7 +- .../plugin-tools-panel/src/locales/it.ts | 7 +- .../plugin-tools-panel/src/locales/ru.ts | 7 +- .../plugin-tools-panel/src/locales/zh.ts | 7 +- .../plugin-top-app-bar/src/TopNavBar/Logo.tsx | 6 +- .../package.json | 6 +- .../tsconfig.json | 10 +- webapp/packages/product-default/package.json | 1 + webapp/packages/product-default/src/index.ts | 5 +- webapp/packages/product-default/tsconfig.json | 47 ++--- webapp/yarn.lock | 50 ++--- 355 files changed, 4429 insertions(+), 2183 deletions(-) create mode 100644 webapp/packages/core-administration/public/icons/server-configuration.svg delete mode 100644 webapp/packages/core-app/src/CoreSettingsService.ts rename webapp/packages/{core-settings/src/createSettingsGroup.ts => core-browser-settings/src/BROWSER_COOKIES_SETTINGS_GROUP.ts} (50%) rename webapp/packages/{plugin-settings-panel/src/actions/ACTION_OPEN_APP_SETTINGS.ts => core-browser-settings/src/BROWSER_SETTINGS_GROUP.ts} (53%) create mode 100644 webapp/packages/core-browser-settings/src/LocaleService.ts create mode 100644 webapp/packages/core-browser-settings/src/locales/en.ts create mode 100644 webapp/packages/core-browser-settings/src/locales/it.ts create mode 100644 webapp/packages/core-browser-settings/src/locales/ru.ts create mode 100644 webapp/packages/core-browser-settings/src/locales/zh.ts rename webapp/packages/{core-settings => core-browser}/src/LocalStorageSaveService.ts (98%) create mode 100644 webapp/packages/core-connections/src/CONNECTIONS_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-events/src/NOTIFICATIONS_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-localization/src/DEFAULT_LOCALE.ts create mode 100644 webapp/packages/core-localization/src/ILocale.ts create mode 100644 webapp/packages/core-navigation-tree/src/LocaleService.ts create mode 100644 webapp/packages/core-navigation-tree/src/NAVIGATION_TREE_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-navigation-tree/src/locales/en.ts create mode 100644 webapp/packages/core-navigation-tree/src/locales/it.ts create mode 100644 webapp/packages/core-navigation-tree/src/locales/ru.ts create mode 100644 webapp/packages/core-navigation-tree/src/locales/zh.ts create mode 100644 webapp/packages/core-plugin/src/LocaleService.ts create mode 100644 webapp/packages/core-plugin/src/SettingsManager/ESettingsValueType.ts create mode 100644 webapp/packages/core-plugin/src/SettingsManager/ISettingDescription.ts create mode 100644 webapp/packages/core-plugin/src/SettingsManager/SettingsGroup.ts create mode 100644 webapp/packages/core-plugin/src/SettingsManager/SettingsGroups/INTERFACE_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-plugin/src/SettingsManager/SettingsGroups/ROOT_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-plugin/src/SettingsManager/SettingsManagerService.ts create mode 100644 webapp/packages/core-plugin/src/createDeprecatedResolver.ts create mode 100644 webapp/packages/core-plugin/src/locales/en.ts create mode 100644 webapp/packages/core-plugin/src/locales/it.ts create mode 100644 webapp/packages/core-plugin/src/locales/ru.ts create mode 100644 webapp/packages/core-plugin/src/locales/zh.ts create mode 100644 webapp/packages/core-resource-manager/src/LocaleService.ts create mode 100644 webapp/packages/core-resource-manager/src/RESOURCE_MANAGER_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-resource-manager/src/locales/en.ts create mode 100644 webapp/packages/core-resource-manager/src/locales/it.ts create mode 100644 webapp/packages/core-resource-manager/src/locales/ru.ts create mode 100644 webapp/packages/core-resource-manager/src/locales/zh.ts delete mode 100644 webapp/packages/core-root/src/ServerService.ts create mode 100644 webapp/packages/core-root/src/ServerSettingsResolverService.ts delete mode 100644 webapp/packages/core-root/src/SessionService.ts create mode 100644 webapp/packages/core-sdk/src/queries/server-configuration/updateProductConfiguration.gql create mode 100644 webapp/packages/core-server-localization/.gitignore create mode 100644 webapp/packages/core-server-localization/package.json create mode 100644 webapp/packages/core-server-localization/src/ServerLocalizationService.ts create mode 100644 webapp/packages/core-server-localization/src/index.ts create mode 100644 webapp/packages/core-server-localization/src/manifest.ts create mode 100644 webapp/packages/core-server-localization/tsconfig.json create mode 100644 webapp/packages/core-session-localization/.gitignore create mode 100644 webapp/packages/core-session-localization/package.json create mode 100644 webapp/packages/core-session-localization/src/SessionLocalizationService.ts create mode 100644 webapp/packages/core-session-localization/src/index.ts create mode 100644 webapp/packages/core-session-localization/src/manifest.ts create mode 100644 webapp/packages/core-session-localization/tsconfig.json create mode 100644 webapp/packages/core-settings-localization/.gitignore create mode 100644 webapp/packages/core-settings-localization/package.json create mode 100644 webapp/packages/core-settings-localization/src/LocaleService.ts create mode 100644 webapp/packages/core-settings-localization/src/LocalizationSettingsManagerService.ts rename webapp/packages/{core-localization/src/LocalizationService.test.ts => core-settings-localization/src/SettingsLocalizationService.test.ts} (61%) create mode 100644 webapp/packages/core-settings-localization/src/SettingsLocalizationService.ts create mode 100644 webapp/packages/core-settings-localization/src/index.ts create mode 100644 webapp/packages/core-settings-localization/src/locales/en.ts create mode 100644 webapp/packages/core-settings-localization/src/locales/it.ts create mode 100644 webapp/packages/core-settings-localization/src/locales/ru.ts create mode 100644 webapp/packages/core-settings-localization/src/locales/zh.ts create mode 100644 webapp/packages/core-settings-localization/src/manifest.ts create mode 100644 webapp/packages/core-settings-localization/tsconfig.json delete mode 100644 webapp/packages/core-settings/src/SettingsManagerService.ts create mode 100644 webapp/packages/core-settings/src/SettingsResolverService.ts create mode 100644 webapp/packages/core-settings/src/SettingsScopeType.ts delete mode 100644 webapp/packages/core-settings/src/SettingsSource.ts delete mode 100644 webapp/packages/core-theming/src/THEME_SETTINGS_GROUP.ts create mode 100644 webapp/packages/core-theming/src/ThemeSettingsManagementService.ts create mode 100644 webapp/packages/core-utils/src/schema.ts create mode 100644 webapp/packages/core-utils/src/schemaValidationError.ts create mode 100644 webapp/packages/core-utils/src/setByPath.ts delete mode 100644 webapp/packages/plugin-connections/src/CONNECTIONS_SETTINGS_GROUP.ts create mode 100644 webapp/packages/plugin-data-export/src/DATA_EXPORT_SETTINGS_GROUP.ts create mode 100644 webapp/packages/plugin-log-viewer/src/LogViewer/LOG_VIEWER_SETTINGS_GROUP.ts create mode 100644 webapp/packages/plugin-navigation-tree/src/TreeNew/NodeControlLazy.ts create mode 100644 webapp/packages/plugin-navigation-tree/src/TreeNew/NodeLazy.ts create mode 100644 webapp/packages/plugin-settings-administration/.gitignore create mode 100644 webapp/packages/plugin-settings-administration/package.json create mode 100644 webapp/packages/plugin-settings-administration/src/LocaleService.ts create mode 100644 webapp/packages/plugin-settings-administration/src/SettingsAdministration.m.css create mode 100644 webapp/packages/plugin-settings-administration/src/SettingsAdministration.tsx create mode 100644 webapp/packages/plugin-settings-administration/src/SettingsAdministrationPluginBootstrap.ts create mode 100644 webapp/packages/plugin-settings-administration/src/SettingsDrawerItem.tsx create mode 100644 webapp/packages/plugin-settings-administration/src/index.ts create mode 100644 webapp/packages/plugin-settings-administration/src/locales/en.ts create mode 100644 webapp/packages/plugin-settings-administration/src/locales/it.ts create mode 100644 webapp/packages/plugin-settings-administration/src/locales/ru.ts create mode 100644 webapp/packages/plugin-settings-administration/src/locales/zh.ts create mode 100644 webapp/packages/plugin-settings-administration/src/manifest.ts create mode 100644 webapp/packages/plugin-settings-administration/tsconfig.json create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SETTINGS_GROUP_ID_PREFIX.ts create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/Setting.tsx create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/Settings.tsx delete mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroup.tsx create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroups/GroupNodeControl.tsx create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroups/SettingsGroups.tsx create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsGroups/groupNodeRenderer.tsx delete mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsInfoForm.tsx delete mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsInfoFormField.tsx create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsLazy.ts create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsList.tsx delete mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsPanelForm.m.css delete mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/SettingsPanelForm.tsx create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/getSettingGroupId.ts create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/getSettingGroupIdFromElementId.ts create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/querySettingsGroups.ts create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/useSettings.ts create mode 100644 webapp/packages/plugin-settings-panel/src/SettingsPanel/useTreeScrollSync.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SQL_EDITOR_SETTINGS_GROUP.ts create mode 100644 webapp/packages/plugin-tools-panel/src/TOOLS_PANEL_SETTINGS_GROUP.ts diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java index b931441a47..97af6a947c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java @@ -895,11 +895,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut } } - String sessionId = null; - if (credentialsProvider != null && credentialsProvider.getActiveUserCredentials() != null) { - sessionId = credentialsProvider.getActiveUserCredentials().getSmSessionId(); - } - eventController.addEvent(new WSServerConfigurationChangedEvent(sessionId, null)); + sendConfigChangedEvent(credentialsProvider); eventController.setForceSkipEvents(isConfigurationMode()); } @@ -992,11 +988,10 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut sessionExpireTime, appConfig); validateConfiguration(configurationProperties); - writeRuntimeConfig(configurationProperties); + writeRuntimeConfig(getRuntimeAppConfigFile(), configurationProperties); } - private void writeRuntimeConfig(Map configurationProperties) throws DBException { - File runtimeConfigFile = getRuntimeAppConfigFile(); + private void writeRuntimeConfig(File runtimeConfigFile, Map configurationProperties) throws DBException { if (runtimeConfigFile.exists()) { ContentUtils.makeFileBackup(runtimeConfigFile.toPath()); } @@ -1024,33 +1019,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut var serverConfigProperties = new LinkedHashMap(); var originServerConfig = getServerConfigProps(this.originalConfigurationProperties); // get server properties from original configuration file rootConfig.put("server", serverConfigProperties); - if (!CommonUtils.isEmpty(newServerName)) { - copyConfigValue(originServerConfig, - serverConfigProperties, - CBConstants.PARAM_SERVER_NAME, - newServerName); - } - if (!CommonUtils.isEmpty(newServerURL)) { - copyConfigValue( - originServerConfig, serverConfigProperties, CBConstants.PARAM_SERVER_URL, newServerURL); - } - if (sessionExpireTime > 0) { - copyConfigValue( - originServerConfig, - serverConfigProperties, - CBConstants.PARAM_SESSION_EXPIRE_PERIOD, - sessionExpireTime); - } - var databaseConfigProperties = new LinkedHashMap(); - Map oldRuntimeDBConfig = JSONUtils.getObject(originServerConfig, - CBConstants.PARAM_DB_CONFIGURATION); - if (!CommonUtils.isEmpty(databaseConfiguration) && !isDistributed()) { - for (Map.Entry mp : databaseConfiguration.entrySet()) { - copyConfigValue(oldRuntimeDBConfig, databaseConfigProperties, mp.getKey(), mp.getValue()); - } - serverConfigProperties.put(CBConstants.PARAM_DB_CONFIGURATION, databaseConfigProperties); - } - savePasswordPolicyConfig(originServerConfig, serverConfigProperties); + collectServerConfigProperties(newServerName, newServerURL, sessionExpireTime, originServerConfig, serverConfigProperties); } { var appConfigProperties = new LinkedHashMap(); @@ -1160,7 +1129,43 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut return rootConfig; } - private void savePasswordPolicyConfig(Map originServerConfig, LinkedHashMap serverConfigProperties) { + protected void collectServerConfigProperties( + String newServerName, + String newServerURL, + long sessionExpireTime, + Map originServerConfig, + Map serverConfigProperties + ) { + if (!CommonUtils.isEmpty(newServerName)) { + copyConfigValue(originServerConfig, + serverConfigProperties, + CBConstants.PARAM_SERVER_NAME, + newServerName); + } + if (!CommonUtils.isEmpty(newServerURL)) { + copyConfigValue( + originServerConfig, serverConfigProperties, CBConstants.PARAM_SERVER_URL, newServerURL); + } + if (sessionExpireTime > 0) { + copyConfigValue( + originServerConfig, + serverConfigProperties, + CBConstants.PARAM_SESSION_EXPIRE_PERIOD, + sessionExpireTime); + } + var databaseConfigProperties = new LinkedHashMap(); + Map oldRuntimeDBConfig = JSONUtils.getObject(originServerConfig, + CBConstants.PARAM_DB_CONFIGURATION); + if (!CommonUtils.isEmpty(databaseConfiguration) && !isDistributed()) { + for (Map.Entry mp : databaseConfiguration.entrySet()) { + copyConfigValue(oldRuntimeDBConfig, databaseConfigProperties, mp.getKey(), mp.getValue()); + } + serverConfigProperties.put(CBConstants.PARAM_DB_CONFIGURATION, databaseConfigProperties); + } + savePasswordPolicyConfig(originServerConfig, serverConfigProperties); + } + + private void savePasswordPolicyConfig(Map originServerConfig, Map serverConfigProperties) { // save password policy configuration var passwordPolicyProperties = new LinkedHashMap(); @@ -1297,4 +1302,19 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut public Class getPlatformUIClass() { return CBPlatformUI.class; } + + public void saveProductConfiguration(SMCredentialsProvider credentialsProvider, Map productConfiguration) throws DBException { + Map mergedConfig = WebAppUtils.mergeConfigurations(this.productConfiguration, productConfiguration); + writeRuntimeConfig(getRuntimeProductConfigFilePath().toFile(), mergedConfig); + this.productConfiguration.putAll(mergedConfig); + sendConfigChangedEvent(credentialsProvider); + } + + protected void sendConfigChangedEvent(SMCredentialsProvider credentialsProvider) { + String sessionId = null; + if (credentialsProvider != null && credentialsProvider.getActiveUserCredentials() != null) { + sessionId = credentialsProvider.getActiveUserCredentials().getSmSessionId(); + } + eventController.addEvent(new WSServerConfigurationChangedEvent(sessionId, null)); + } } diff --git a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls index fa77fb0dd7..586a0e8f96 100644 --- a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls +++ b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls @@ -206,3 +206,8 @@ extend type Query { setDefaultNavigatorSettings( settings: NavigatorSettingsInput!): Boolean! } + +extend type Mutation { + # Updates product configuration + adminUpdateProductConfiguration(configuration: Object!): Boolean! @since(version: "23.3.4") +} diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java index 1f8a328648..19271b41f5 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java @@ -138,6 +138,9 @@ public interface DBWServiceAdmin extends DBWService { @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) boolean setDefaultNavigatorSettings(WebSession webSession, DBNBrowseSettings settings) throws DBWebException; + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) + boolean updateProductConfiguration(WebSession webSession, Map productConfiguration) throws DBWebException; + //////////////////////////////////////////////////////////////////// // Permissions @@ -179,6 +182,7 @@ public interface DBWServiceAdmin extends DBWService { DBWebException; //////////////////////////////////////////////////////////////////// + // User meta parameters @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) @@ -187,11 +191,11 @@ public interface DBWServiceAdmin extends DBWService { @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean deleteUserMetaParameter(WebSession webSession, String id) throws DBWebException; - @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean setUserMetaParameterValues(WebSession webSession, String userId, Map parameters) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean setTeamMetaParameterValues(WebSession webSession, String teamId, Map parameters) throws DBWebException; + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) Boolean enableUser(WebSession webSession, String userId, Boolean enabled) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java index 80bfcbb362..9bbc7895ad 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/WebServiceBindingAdmin.java @@ -185,6 +185,9 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase getService(env).setDefaultNavigatorSettings(getWebSession(env), WebServiceUtils.parseNavigatorSettings(env.getArgument("settings")))) ; + model.getMutationType() + .dataFetcher("adminUpdateProductConfiguration", + env -> getService(env).updateProductConfiguration(getWebSession(env), env.getArgument("configuration"))); } @Override diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java index 64c1209826..748734679f 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java @@ -609,6 +609,17 @@ public class WebServiceAdmin implements DBWServiceAdmin { return true; } + + @Override + public boolean updateProductConfiguration(WebSession webSession, Map productConfiguration) throws DBWebException { + try { + CBApplication.getInstance().saveProductConfiguration(webSession, productConfiguration); + return true; + } catch (DBException e) { + throw new DBWebException("Error updating product configuration", e); + } + } + //////////////////////////////////////////////////////////////////// // Access management diff --git a/webapp/packages/core-administration/public/icons/server-configuration.svg b/webapp/packages/core-administration/public/icons/server-configuration.svg new file mode 100644 index 0000000000..b48a05351a --- /dev/null +++ b/webapp/packages/core-administration/public/icons/server-configuration.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts index 1948153ade..5260f4e949 100644 --- a/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts +++ b/webapp/packages/core-administration/src/AdministrationScreen/AdministrationScreenService.ts @@ -12,7 +12,7 @@ import { NotificationService } from '@cloudbeaver/core-events'; import { Executor, IExecutor } from '@cloudbeaver/core-executor'; import { EAdminPermission, PermissionsService, ServerConfigResource, SessionPermissionsResource } from '@cloudbeaver/core-root'; import { RouterState, ScreenService } from '@cloudbeaver/core-routing'; -import { LocalStorageSaveService } from '@cloudbeaver/core-settings'; +import { SettingsService } from '@cloudbeaver/core-settings'; import { GlobalConstants } from '@cloudbeaver/core-utils'; import { AdministrationItemService } from '../AdministrationItem/AdministrationItemService'; @@ -69,7 +69,7 @@ export class AdministrationScreenService { private readonly permissionsService: PermissionsService, private readonly screenService: ScreenService, private readonly administrationItemService: AdministrationItemService, - private readonly autoSaveService: LocalStorageSaveService, + private readonly settingsService: SettingsService, private readonly serverConfigResource: ServerConfigResource, private readonly notificationService: NotificationService, ) { @@ -84,8 +84,8 @@ export class AdministrationScreenService { activeScreen: computed, }); - this.autoSaveService.withAutoSave(ADMINISTRATION_ITEMS_STATE, this.itemState, () => new Map()); - this.autoSaveService.withAutoSave(ADMINISTRATION_INFO, this.info, getDefaultAdministrationScreenInfo); + this.settingsService.registerSettings(ADMINISTRATION_ITEMS_STATE, this.itemState, () => new Map()); + this.settingsService.registerSettings(ADMINISTRATION_INFO, this.info, getDefaultAdministrationScreenInfo); this.permissionsResource.onDataUpdate.addPostHandler(() => { this.checkPermissions(this.screenService.routerService.state); }); diff --git a/webapp/packages/core-administration/src/AdministrationSettingsService.ts b/webapp/packages/core-administration/src/AdministrationSettingsService.ts index c6b79f8c9d..6e5188c465 100644 --- a/webapp/packages/core-administration/src/AdministrationSettingsService.ts +++ b/webapp/packages/core-administration/src/AdministrationSettingsService.ts @@ -7,19 +7,20 @@ */ import { injectable } from '@cloudbeaver/core-di'; import { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; +import { schema } from '@cloudbeaver/core-utils'; -const defaultSettings = { - baseFeatures: [] as string[], -}; +const settingsSchema = schema.object({ + baseFeatures: schema.array(schema.string()).default([]), +}); -export type AdministrationSettings = typeof defaultSettings; +export type AdministrationSettings = schema.infer; @injectable() export class AdministrationSettingsService { - readonly settings: PluginSettings; + readonly settings: PluginSettings; constructor(private readonly pluginManagerService: PluginManagerService) { - this.settings = this.pluginManagerService.createSettings('administration', 'core', defaultSettings); + this.settings = this.pluginManagerService.createSettings('administration', 'core', settingsSchema); } isBase(feature: string): boolean { diff --git a/webapp/packages/core-administration/tsconfig.json b/webapp/packages/core-administration/tsconfig.json index 1587831354..b71c4bdc46 100644 --- a/webapp/packages/core-administration/tsconfig.json +++ b/webapp/packages/core-administration/tsconfig.json @@ -6,6 +6,9 @@ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" }, "references": [ + { + "path": "../core-browser/tsconfig.json" + }, { "path": "../core-data-context/tsconfig.json" }, @@ -15,27 +18,48 @@ { "path": "../core-events/tsconfig.json" }, + { + "path": "../core-events/tsconfig.json" + }, { "path": "../core-executor/tsconfig.json" }, { "path": "../core-localization/tsconfig.json" }, + { + "path": "../core-localization/tsconfig.json" + }, { "path": "../core-plugin/tsconfig.json" }, + { + "path": "../core-plugin/tsconfig.json" + }, + { + "path": "../core-product/tsconfig.json" + }, { "path": "../core-resource/tsconfig.json" }, { "path": "../core-root/tsconfig.json" }, + { + "path": "../core-root/tsconfig.json" + }, { "path": "../core-routing/tsconfig.json" }, { "path": "../core-sdk/tsconfig.json" }, + { + "path": "../core-sdk/tsconfig.json" + }, + { + "path": "../core-settings/tsconfig.json" + }, { "path": "../core-settings/tsconfig.json" }, @@ -45,30 +69,6 @@ { "path": "../core-utils/tsconfig.json" }, - { - "path": "../core-browser/tsconfig.json" - }, - { - "path": "../core-events/tsconfig.json" - }, - { - "path": "../core-localization/tsconfig.json" - }, - { - "path": "../core-plugin/tsconfig.json" - }, - { - "path": "../core-product/tsconfig.json" - }, - { - "path": "../core-root/tsconfig.json" - }, - { - "path": "../core-sdk/tsconfig.json" - }, - { - "path": "../core-settings/tsconfig.json" - }, { "path": "../tests-runner/tsconfig.json" } diff --git a/webapp/packages/core-app/package.json b/webapp/packages/core-app/package.json index 8ff5cf9c37..cd38d98b18 100644 --- a/webapp/packages/core-app/package.json +++ b/webapp/packages/core-app/package.json @@ -22,17 +22,16 @@ "@cloudbeaver/core-executor": "~0.1.0", "@cloudbeaver/core-localization": "~0.1.0", "@cloudbeaver/core-notifications": "~0.1.0", - "@cloudbeaver/core-plugin": "~0.1.0", "@cloudbeaver/core-projects": "~0.1.0", "@cloudbeaver/core-resource": "~0.1.0", "@cloudbeaver/core-root": "~0.1.0", "@cloudbeaver/core-routing": "~0.1.0", "@cloudbeaver/core-theming": "~0.1.0", "@cloudbeaver/core-ui": "~0.1.0", + "@cloudbeaver/core-utils": "~0.1.0", "@cloudbeaver/core-version": "~0.1.0", "mobx-react-lite": "^4.0.5", - "react": "^18.2.0", - "@cloudbeaver/core-utils": "~0.1.0" + "react": "^18.2.0" }, "peerDependencies": {}, "devDependencies": { diff --git a/webapp/packages/core-app/src/CoreSettingsService.ts b/webapp/packages/core-app/src/CoreSettingsService.ts deleted file mode 100644 index 8b18449b54..0000000000 --- a/webapp/packages/core-app/src/CoreSettingsService.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { injectable } from '@cloudbeaver/core-di'; -import { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; - -const defaultSettings = { - 'app.logViewer.refreshTimeout': 3000, - 'app.logViewer.maxLogRecords': 1000, - 'app.logViewer.logBatchSize': 2000, - 'app.logViewer.maxFailedRequests': 3, - 'app.navigationTree.childrenLimit': 100, - 'app.metadata.editing': true, - 'app.metadata.deleting': true, -}; - -export type CoreSettings = typeof defaultSettings; - -/** - * @deprecated use plugin-log-viewer, core-navigation-tree settings instead - */ -@injectable() -export class CoreSettingsService { - readonly settings: PluginSettings; - - constructor(private readonly pluginManagerService: PluginManagerService) { - this.settings = this.pluginManagerService.getDeprecatedPluginSettings('core', defaultSettings); - } -} diff --git a/webapp/packages/core-app/src/index.ts b/webapp/packages/core-app/src/index.ts index bb15f72a3a..51841f691c 100644 --- a/webapp/packages/core-app/src/index.ts +++ b/webapp/packages/core-app/src/index.ts @@ -1,5 +1,4 @@ // Services -export * from './CoreSettingsService'; export * from './AppScreen/AppScreenService'; export * from './AppScreen/AppScreenBootstrap'; diff --git a/webapp/packages/core-app/src/manifest.ts b/webapp/packages/core-app/src/manifest.ts index d00b384719..0042da0973 100644 --- a/webapp/packages/core-app/src/manifest.ts +++ b/webapp/packages/core-app/src/manifest.ts @@ -10,12 +10,11 @@ import type { PluginManifest } from '@cloudbeaver/core-di'; import { AppLocaleService } from './AppLocaleService'; import { AppScreenBootstrap } from './AppScreen/AppScreenBootstrap'; import { AppScreenService } from './AppScreen/AppScreenService'; -import { CoreSettingsService } from './CoreSettingsService'; export const coreAppManifest: PluginManifest = { info: { name: 'Core App', }, - providers: [AppScreenService, AppScreenBootstrap, CoreSettingsService, AppLocaleService], + providers: [AppScreenService, AppScreenBootstrap, AppLocaleService], }; diff --git a/webapp/packages/core-app/tsconfig.json b/webapp/packages/core-app/tsconfig.json index 58c432283c..a8bdc73634 100644 --- a/webapp/packages/core-app/tsconfig.json +++ b/webapp/packages/core-app/tsconfig.json @@ -21,9 +21,6 @@ { "path": "../core-notifications/tsconfig.json" }, - { - "path": "../core-plugin/tsconfig.json" - }, { "path": "../core-projects/tsconfig.json" }, @@ -43,10 +40,10 @@ "path": "../core-ui/tsconfig.json" }, { - "path": "../core-version/tsconfig.json" + "path": "../core-utils/tsconfig.json" }, { - "path": "../core-utils/tsconfig.json" + "path": "../core-version/tsconfig.json" } ], "include": [ diff --git a/webapp/packages/core-authentication/src/AUTH_SETTINGS_GROUP.ts b/webapp/packages/core-authentication/src/AUTH_SETTINGS_GROUP.ts index 7ea10189d1..bc35d8aa03 100644 --- a/webapp/packages/core-authentication/src/AUTH_SETTINGS_GROUP.ts +++ b/webapp/packages/core-authentication/src/AUTH_SETTINGS_GROUP.ts @@ -5,21 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { createSettingsGroup, SettingsData } from '@cloudbeaver/core-settings'; +import { ROOT_SETTINGS_GROUP } from '@cloudbeaver/core-plugin'; -export const AUTH_SETTINGS_GROUP = createSettingsGroup('settings_authentication'); - -export const settings: SettingsData = { - scopeType: 'core', - scope: 'authentication', - settingsData: [ - // TODO: it's administrator settings - // { - // key: 'disableAnonymousAccess', - // type: FormFieldType.Checkbox, - // name: 'settings_authentication_disable_anonymous_access_name', - // description: 'settings_authentication_disable_anonymous_access_description', - // groupId: AUTH_SETTINGS_GROUP.id, - // }, - ], -}; +export const AUTH_SETTINGS_GROUP = ROOT_SETTINGS_GROUP.createSubGroup('core_authentication_auth_settings_group'); diff --git a/webapp/packages/core-authentication/src/AuthSettingsService.ts b/webapp/packages/core-authentication/src/AuthSettingsService.ts index c0c7b6b1f6..5b819b2751 100644 --- a/webapp/packages/core-authentication/src/AuthSettingsService.ts +++ b/webapp/packages/core-authentication/src/AuthSettingsService.ts @@ -6,25 +6,34 @@ * you may not use this file except in compliance with the License. */ import { injectable } from '@cloudbeaver/core-di'; -import { PluginManagerService, PluginSettings } from '@cloudbeaver/core-plugin'; -import { SettingsManagerService } from '@cloudbeaver/core-settings'; +import { PluginManagerService, PluginSettings, SettingsManagerService } from '@cloudbeaver/core-plugin'; +import { schema } from '@cloudbeaver/core-utils'; -import { AUTH_SETTINGS_GROUP, settings } from './AUTH_SETTINGS_GROUP'; +const settingsSchema = schema.object({ + disableAnonymousAccess: schema.coerce.boolean().default(false), +}); -const defaultSettings = { - disableAnonymousAccess: false, -}; - -export type AuthSettings = typeof defaultSettings; +export type AuthSettings = schema.infer; @injectable() export class AuthSettingsService { - readonly settings: PluginSettings; + readonly settings: PluginSettings; - constructor(private readonly pluginManagerService: PluginManagerService, settingsManagerService: SettingsManagerService) { - this.settings = this.pluginManagerService.createSettings('authentication', 'core', defaultSettings); + constructor(private readonly pluginManagerService: PluginManagerService, private readonly settingsManagerService: SettingsManagerService) { + this.settings = this.pluginManagerService.createSettings('authentication', 'core', settingsSchema); - settingsManagerService.addGroup(AUTH_SETTINGS_GROUP); - settingsManagerService.addSettings(settings.scopeType, settings.scope, settings.settingsData); + this.registerSettings(); + } + + private registerSettings() { + this.settingsManagerService.registerSettings(this.settings, () => [ + // { + // key: 'disableAnonymousAccess', + // type: ESettingsValueType.Checkbox, + // name: 'settings_authentication_disable_anonymous_access_name', + // description: 'settings_authentication_disable_anonymous_access_description', + // group: AUTH_SETTINGS_GROUP, + // }, + ]); } } diff --git a/webapp/packages/core-authentication/src/UserDataService.ts b/webapp/packages/core-authentication/src/UserDataService.ts index c5bdaea98e..317336e35d 100644 --- a/webapp/packages/core-authentication/src/UserDataService.ts +++ b/webapp/packages/core-authentication/src/UserDataService.ts @@ -8,7 +8,7 @@ import { makeObservable, observable } from 'mobx'; import { injectable } from '@cloudbeaver/core-di'; -import { LocalStorageSaveService } from '@cloudbeaver/core-settings'; +import { SettingsService } from '@cloudbeaver/core-settings'; import { TempMap } from '@cloudbeaver/core-utils'; import { UserInfoResource } from './UserInfoResource'; @@ -18,7 +18,7 @@ export class UserDataService { private readonly userData: Map>; private readonly tempData: TempMap>; - constructor(private readonly userInfoResource: UserInfoResource, private readonly autoSaveService: LocalStorageSaveService) { + constructor(private readonly userInfoResource: UserInfoResource, private readonly settingsService: SettingsService) { this.userData = new Map(); makeObservable(this, { @@ -27,7 +27,7 @@ export class UserDataService { this.tempData = new TempMap(this.userData); - this.autoSaveService.withAutoSave('user_data', this.userData, () => new Map()); + this.settingsService.registerSettings('user_data', this.userData, () => new Map()); } getUserData>(key: string, defaultValue: () => T, validate?: (data: T) => boolean): T { diff --git a/webapp/packages/core-authentication/src/locales/en.ts b/webapp/packages/core-authentication/src/locales/en.ts index 4554669df2..859671e833 100644 --- a/webapp/packages/core-authentication/src/locales/en.ts +++ b/webapp/packages/core-authentication/src/locales/en.ts @@ -1,5 +1,5 @@ export default [ - ['settings_authentication', 'Authentication'], + ['core_authentication_auth_settings_group', 'Authentication'], ['settings_authentication_disable_anonymous_access_name', 'Disable anonymous access'], ['settings_authentication_disable_anonymous_access_description', 'Disable anonymous access function'], diff --git a/webapp/packages/core-authentication/src/locales/it.ts b/webapp/packages/core-authentication/src/locales/it.ts index 4554669df2..859671e833 100644 --- a/webapp/packages/core-authentication/src/locales/it.ts +++ b/webapp/packages/core-authentication/src/locales/it.ts @@ -1,5 +1,5 @@ export default [ - ['settings_authentication', 'Authentication'], + ['core_authentication_auth_settings_group', 'Authentication'], ['settings_authentication_disable_anonymous_access_name', 'Disable anonymous access'], ['settings_authentication_disable_anonymous_access_description', 'Disable anonymous access function'], diff --git a/webapp/packages/core-authentication/src/locales/ru.ts b/webapp/packages/core-authentication/src/locales/ru.ts index 51fffc3dbd..31219f8af2 100644 --- a/webapp/packages/core-authentication/src/locales/ru.ts +++ b/webapp/packages/core-authentication/src/locales/ru.ts @@ -1,5 +1,5 @@ export default [ - ['settings_authentication', 'Аутентификация'], + ['core_authentication_auth_settings_group', 'Аутентификация'], ['settings_authentication_disable_anonymous_access_name', 'Отключить анонимный доступ'], ['settings_authentication_disable_anonymous_access_description', 'Отключить функцию анонимного доступа'], diff --git a/webapp/packages/core-authentication/src/locales/zh.ts b/webapp/packages/core-authentication/src/locales/zh.ts index 4554669df2..859671e833 100644 --- a/webapp/packages/core-authentication/src/locales/zh.ts +++ b/webapp/packages/core-authentication/src/locales/zh.ts @@ -1,5 +1,5 @@ export default [ - ['settings_authentication', 'Authentication'], + ['core_authentication_auth_settings_group', 'Authentication'], ['settings_authentication_disable_anonymous_access_name', 'Disable anonymous access'], ['settings_authentication_disable_anonymous_access_description', 'Disable anonymous access function'], diff --git a/webapp/packages/core-authentication/tsconfig.json b/webapp/packages/core-authentication/tsconfig.json index 22b6f52556..5b1b6352b5 100644 --- a/webapp/packages/core-authentication/tsconfig.json +++ b/webapp/packages/core-authentication/tsconfig.json @@ -11,72 +11,72 @@ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" }, "references": [ + { + "path": "../core-browser/tsconfig.json" + }, { "path": "../core-data-context/tsconfig.json" }, { "path": "../core-di/tsconfig.json" }, + { + "path": "../core-events/tsconfig.json" + }, { "path": "../core-executor/tsconfig.json" }, { "path": "../core-localization/tsconfig.json" }, - { - "path": "../core-plugin/tsconfig.json" - }, - { - "path": "../core-resource/tsconfig.json" - }, - { - "path": "../core-root/tsconfig.json" - }, - { - "path": "../core-routing/tsconfig.json" - }, - { - "path": "../core-sdk/tsconfig.json" - }, - { - "path": "../core-settings/tsconfig.json" - }, - { - "path": "../core-theming/tsconfig.json" - }, - { - "path": "../core-utils/tsconfig.json" - }, - { - "path": "../core-browser/tsconfig.json" - }, - { - "path": "../core-events/tsconfig.json" - }, { "path": "../core-localization/tsconfig.json" }, { "path": "../core-plugin/tsconfig.json" }, + { + "path": "../core-plugin/tsconfig.json" + }, { "path": "../core-product/tsconfig.json" }, + { + "path": "../core-resource/tsconfig.json" + }, { "path": "../core-root/tsconfig.json" }, + { + "path": "../core-root/tsconfig.json" + }, + { + "path": "../core-routing/tsconfig.json" + }, { "path": "../core-routing/tsconfig.json" }, { "path": "../core-sdk/tsconfig.json" }, + { + "path": "../core-sdk/tsconfig.json" + }, + { + "path": "../core-settings/tsconfig.json" + }, { "path": "../core-settings/tsconfig.json" }, { "path": "../core-theming/tsconfig.json" }, + { + "path": "../core-theming/tsconfig.json" + }, + { + "path": "../core-utils/tsconfig.json" + }, { "path": "../tests-runner/tsconfig.json" } diff --git a/webapp/packages/core-blocks/src/Containers/ILayoutSizeProps.ts b/webapp/packages/core-blocks/src/Containers/ILayoutSizeProps.ts index ea039ca292..e5abb40b44 100644 --- a/webapp/packages/core-blocks/src/Containers/ILayoutSizeProps.ts +++ b/webapp/packages/core-blocks/src/Containers/ILayoutSizeProps.ts @@ -17,4 +17,5 @@ export interface ILayoutSizeProps { fill?: boolean; noGrow?: boolean; zeroBasis?: boolean; + groupGap?: boolean; } diff --git a/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts b/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts index 5499f4e0f6..e3ec1696dd 100644 --- a/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts +++ b/webapp/packages/core-blocks/src/Containers/filterLayoutFakeProps.ts @@ -8,12 +8,12 @@ import type { ILayoutSizeProps } from './ILayoutSizeProps'; export function filterLayoutFakeProps(props: T): Omit { - const { noWrap, keepSize, tiny, small, medium, large, maximum, fill, noGrow, zeroBasis, ...rest } = props; + const { noWrap, keepSize, tiny, small, medium, large, maximum, fill, noGrow, zeroBasis, groupGap, ...rest } = props; return rest; } export function getLayoutProps(props: T): ILayoutSizeProps { - const { noWrap, keepSize, tiny, small, medium, large, maximum, fill, noGrow, zeroBasis } = props; - return { noWrap, keepSize, tiny, small, medium, large, maximum, fill, noGrow, zeroBasis }; + const { noWrap, keepSize, tiny, small, medium, large, maximum, fill, noGrow, zeroBasis, groupGap } = props; + return { noWrap, keepSize, tiny, small, medium, large, maximum, fill, noGrow, zeroBasis, groupGap }; } diff --git a/webapp/packages/core-blocks/src/Containers/shared/ElementsSize.m.css b/webapp/packages/core-blocks/src/Containers/shared/ElementsSize.m.css index b38da5b528..3bac01df4c 100644 --- a/webapp/packages/core-blocks/src/Containers/shared/ElementsSize.m.css +++ b/webapp/packages/core-blocks/src/Containers/shared/ElementsSize.m.css @@ -75,3 +75,15 @@ .container > .zeroBasis { flex-basis: 0%; } + +.container.gap > .groupGap + .groupGap { + margin-top: -12px; +} + +.container.gap.compact > .groupGap + .groupGap { + margin-top: -8px; +} + +.container.gap.dense > .groupGap + .groupGap { + margin-top: -4px; +} diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx index d963f59594..a691e52199 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Checkbox.tsx @@ -9,8 +9,6 @@ import { observer } from 'mobx-react-lite'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; -import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps'; -import type { ILayoutSizeProps } from '../../Containers/ILayoutSizeProps'; import { isControlPresented } from '../isControlPresented'; import { CheckboxMarkup, CheckboxMod } from './CheckboxMarkup'; import { CheckboxOnChangeEvent, useCheckboxState } from './useCheckboxState'; @@ -27,13 +25,12 @@ export interface CheckboxBaseProps { export type CheckboxInputProps = Omit< React.InputHTMLAttributes, 'onChange' | 'type' | 'value' | 'defaultValue' | 'checked' | 'defaultChecked' | 'style' -> & - ILayoutSizeProps & { - value?: string; - defaultValue?: string; - defaultChecked?: boolean; - label?: string; - }; +> & { + value?: string; + defaultValue?: string; + defaultChecked?: boolean; + label?: string; +}; export interface ICheckboxControlledProps extends CheckboxInputProps { state?: never; @@ -50,9 +47,9 @@ export interface ICheckboxObjectProps extends CheckboxInput name: TKey; } -export interface CheckboxType { - (props: CheckboxBaseProps & ICheckboxControlledProps): React.ReactElement | null; - (props: CheckboxBaseProps & ICheckboxObjectProps): React.ReactElement | null; +export interface CheckboxType

> { + (props: CheckboxBaseProps & ICheckboxControlledProps & P): React.ReactElement | null; + (props: CheckboxBaseProps & ICheckboxObjectProps & P): React.ReactElement | null; } export const Checkbox: CheckboxType = observer(function Checkbox({ @@ -72,7 +69,6 @@ export const Checkbox: CheckboxType = observer(function Checkbox({ onChange, ...rest }: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { - rest = filterLayoutFakeProps(rest); const checkboxState = useCheckboxState({ value, defaultValue, diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx index 51ee9cda01..24f64a2d30 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx @@ -8,6 +8,7 @@ import { observer } from 'mobx-react-lite'; import { filterLayoutFakeProps, getLayoutProps } from '../../Containers/filterLayoutFakeProps'; +import type { ILayoutSizeProps } from '../../Containers/ILayoutSizeProps'; import { s } from '../../s'; import { useS } from '../../useS'; import { Field } from '../Field'; @@ -16,13 +17,13 @@ import { isControlPresented } from '../isControlPresented'; import { Checkbox, CheckboxBaseProps, CheckboxType, ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox'; import fieldCheckboxStyles from './FieldCheckbox.m.css'; -export const FieldCheckbox: CheckboxType = observer(function FieldCheckbox({ +export const FieldCheckbox: CheckboxType = observer(function FieldCheckbox({ children, className, ...rest -}: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { +}: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps) & ILayoutSizeProps) { const layoutProps = getLayoutProps(rest); - const checkboxProps = filterLayoutFakeProps(rest); + const checkboxProps = filterLayoutFakeProps(rest) as CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps); const styles = useS(fieldCheckboxStyles); if (checkboxProps.autoHide && !isControlPresented(checkboxProps.name, checkboxProps.state)) { @@ -31,7 +32,7 @@ export const FieldCheckbox: CheckboxType = observer(function FieldCheckbox({ return ( - + {children && ( {children} diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx index ae8d39784a..996f91fb6f 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx @@ -8,6 +8,7 @@ import { observer } from 'mobx-react-lite'; import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps'; +import type { ILayoutSizeProps } from '../../Containers/ILayoutSizeProps'; import { s } from '../../s'; import { useS } from '../../useS'; import { Field } from '../Field'; @@ -32,8 +33,8 @@ interface IBaseProps { } interface SwitchType { - (props: IBaseProps & ICheckboxControlledProps): React.ReactElement | null; - (props: IBaseProps & ICheckboxObjectProps): React.ReactElement | null; + (props: IBaseProps & ICheckboxControlledProps & ILayoutSizeProps): React.ReactElement | null; + (props: IBaseProps & ICheckboxObjectProps & ILayoutSizeProps): React.ReactElement | null; } export const Switch: SwitchType = observer(function Switch({ @@ -53,7 +54,7 @@ export const Switch: SwitchType = observer(function Switch({ disabled, onChange, ...rest -}: IBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { +}: IBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps) & ILayoutSizeProps) { const checkboxState = useCheckboxState({ value, defaultValue, diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx index 9af5dbc436..eccce874b8 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx @@ -62,7 +62,9 @@ interface ComboboxType { (props: ObjectProps): JSX.Element; } -{/* TODO rewrite whole component to select attribute instead of input type text so it has an okay form validation */} +{ + /* TODO rewrite whole component to select attribute instead of input type text so it has an okay form validation */ +} export const Combobox: ComboboxType = observer(function Combobox({ value: controlledValue, defaultValue, @@ -264,7 +266,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ )}

- + {(icon || loading) && (
{loading ? ( diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.m.css b/webapp/packages/core-blocks/src/FormControls/InputField.m.css index 4baf35784c..5d7975f5e2 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.m.css +++ b/webapp/packages/core-blocks/src/FormControls/InputField.m.css @@ -48,4 +48,3 @@ .input { font-size: 12px; } - diff --git a/webapp/packages/core-blocks/src/FormControls/useCustomInputValidation.ts b/webapp/packages/core-blocks/src/FormControls/useCustomInputValidation.ts index d8d5452faa..9ee884992f 100644 --- a/webapp/packages/core-blocks/src/FormControls/useCustomInputValidation.ts +++ b/webapp/packages/core-blocks/src/FormControls/useCustomInputValidation.ts @@ -9,12 +9,38 @@ import { useContext, useEffect, useRef } from 'react'; import { ExecutorInterrupter } from '@cloudbeaver/core-executor'; +import { useTranslate } from '../localization/useTranslate'; import { useExecutor } from '../useExecutor'; import { FormContext } from './FormContext'; export function useCustomInputValidation(validation: (value: T) => string | null): React.RefObject { const context = useContext(FormContext); const inputRef = useRef(null); + const translate = useTranslate(); + + function validate(element: HTMLInputElement): boolean { + let value: T = undefined as unknown as T; + + if (element instanceof HTMLInputElement) { + value = element.value as unknown as T; + } + + const valid = element.validity.valid; + const result = validation(value); + + try { + if (typeof result === 'string') { + element.setCustomValidity(result || translate('core_blocks_custom_input_validation_error')); + return false; + } + element.setCustomValidity(''); + return true; + } finally { + if (valid !== element.validity.valid) { + element.reportValidity(); + } + } + } useExecutor({ executor: context?.onValidate, @@ -24,19 +50,8 @@ export function useCustomInputValidation(validation: (value: T) => str return; } - let value: T = undefined as unknown as T; - - if (inputRef.current instanceof HTMLInputElement) { - value = inputRef.current.value as unknown as T; - } - - const result = validation(value); - - if (typeof result === 'string') { - inputRef.current.setCustomValidity(result); + if (!validate(inputRef.current)) { ExecutorInterrupter.interrupt(context); - } else { - inputRef.current?.setCustomValidity(''); } }, ], @@ -48,14 +63,26 @@ export function useCustomInputValidation(validation: (value: T) => str return; } - function resetValidationMessage() { - element?.setCustomValidity(''); + function handleInput(event: Event) { + const target = event.target as HTMLInputElement; + if (target.validity.valid === false) { + validate(target); + } } - element.addEventListener('input', resetValidationMessage); + function handleBlur(event: Event) { + const target = event.target as HTMLInputElement; + if (target.validity.valid === true) { + validate(target); + } + } + + element.addEventListener('input', handleInput); + element.addEventListener('blur', handleBlur); return () => { - element?.removeEventListener('input', resetValidationMessage); + element?.removeEventListener('input', handleInput); + element?.removeEventListener('blur', handleBlur); }; }); diff --git a/webapp/packages/core-blocks/src/ToolsPanel/ToolsAction.tsx b/webapp/packages/core-blocks/src/ToolsPanel/ToolsAction.tsx index 9a26ce3a7d..325e2a659b 100644 --- a/webapp/packages/core-blocks/src/ToolsPanel/ToolsAction.tsx +++ b/webapp/packages/core-blocks/src/ToolsPanel/ToolsAction.tsx @@ -5,26 +5,41 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { ButtonHTMLAttributes } from 'react'; +import { type ButtonHTMLAttributes, useState } from 'react'; import { IconOrImage } from '../IconOrImage'; import { Loader } from '../Loader/Loader'; import { s } from '../s'; import { useS } from '../useS'; +import { useStateDelay } from '../useStateDelay'; import style from './ToolsAction.m.css'; -interface Props extends ButtonHTMLAttributes { +interface Props extends Omit, 'onClick'> { icon?: string; viewBox?: string; loading?: boolean; className?: string; + onClick?: (event: React.MouseEvent) => Promise | any; } -export const ToolsAction: React.FC = function ToolsAction({ icon, viewBox, loading, children, className, ...rest }) { +export const ToolsAction: React.FC = function ToolsAction({ icon, viewBox, disabled, loading, children, className, onClick, ...rest }) { const styles = useS(style); + const [loadingState, setLoadingState] = useState(false); + + async function handleClick(event: React.MouseEvent) { + try { + setLoadingState(true); + await onClick?.(event); + } finally { + setLoadingState(false); + } + } + + loading = useStateDelay(loading || loadingState, 300); + disabled = disabled || loadingState; return ( -