diff --git a/webapp/packages/core-app/src/NavigationTree/NavigationTreeContextMenuService.ts b/webapp/packages/core-app/src/NavigationTree/NavigationTreeContextMenuService.ts index 66581e0ac1..c69ed9c379 100644 --- a/webapp/packages/core-app/src/NavigationTree/NavigationTreeContextMenuService.ts +++ b/webapp/packages/core-app/src/NavigationTree/NavigationTreeContextMenuService.ts @@ -6,26 +6,34 @@ * you may not use this file except in compliance with the License. */ +import { ConnectionViewService, CONNECTION_NAVIGATOR_VIEW_SETTINGS } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { ContextMenuService, IMenuPanel } from '@cloudbeaver/core-dialogs'; import type { NavNode } from '../shared/NodesManager/EntityTypes'; +import { EObjectFeature } from '../shared/NodesManager/EObjectFeature'; import { NavNodeManagerService } from '../shared/NodesManager/NavNodeManagerService'; @injectable() export class NavigationTreeContextMenuService { static nodeContextType = 'NodeWithParent'; + private static nodeViewMenuItemToken = 'nodeView'; private static menuToken = 'navTreeMenu'; constructor( private contextMenuService: ContextMenuService, - private navNodeManagerService: NavNodeManagerService + private navNodeManagerService: NavNodeManagerService, + private connectionViewService: ConnectionViewService ) { } getMenuToken() { return NavigationTreeContextMenuService.menuToken; } + getNodeViewMenuItemToken() { + return NavigationTreeContextMenuService.nodeViewMenuItemToken; + } + constructMenuWithContext(node: NavNode): IMenuPanel { return this.contextMenuService.createContextMenu({ menuId: this.getMenuToken(), @@ -35,6 +43,52 @@ export class NavigationTreeContextMenuService { }); } + registerNodeViewMenuItem() { + this.contextMenuService.addMenuItem( + this.contextMenuService.getRootMenuToken(), + { + id: this.getNodeViewMenuItemToken(), + isPresent(context) { + return context.contextType === NavigationTreeContextMenuService.nodeContextType + && context.data.objectFeatures.includes(EObjectFeature.dataSource); + }, + order: 2, + title: 'app_navigationTree_connection_view', + isPanel: true, + } + ); + this.contextMenuService.addMenuItem( + this.getNodeViewMenuItemToken(), + { + id: 'simple', + isPresent(context) { + return context.contextType === NavigationTreeContextMenuService.nodeContextType + && context.data.objectFeatures.includes(EObjectFeature.dataSource); + }, + onClick: context => { + const node = context.data; + this.connectionViewService.changeConnectionView(node.id, CONNECTION_NAVIGATOR_VIEW_SETTINGS.simple); + }, + title: 'app_navigationTree_connection_view_simple_option', + } + ); + this.contextMenuService.addMenuItem( + this.getNodeViewMenuItemToken(), + { + id: 'advanced', + isPresent(context) { + return context.contextType === NavigationTreeContextMenuService.nodeContextType + && context.data.objectFeatures.includes(EObjectFeature.dataSource); + }, + title: 'app_navigationTree_connection_view_advanced_option', + onClick: context => { + const node = context.data; + this.connectionViewService.changeConnectionView(node.id, CONNECTION_NAVIGATOR_VIEW_SETTINGS.advanced); + }, + } + ); + } + registerMenuItems() { this.contextMenuService.addMenuItem( this.contextMenuService.getRootMenuToken(), @@ -67,5 +121,7 @@ export class NavigationTreeContextMenuService { }, } ); + + this.registerNodeViewMenuItem(); } } diff --git a/webapp/packages/core-app/src/index.ts b/webapp/packages/core-app/src/index.ts index a214a2c96b..c37ebffda6 100644 --- a/webapp/packages/core-app/src/index.ts +++ b/webapp/packages/core-app/src/index.ts @@ -22,6 +22,7 @@ export * from './shared/NavigationTabs/TabNavigationContext'; export * from './shared/ToolsPanel/LogViewTab/LogViewerMenuService'; export * from './shared/ToolsPanel/LogViewTab/LogViewerService'; export * from './shared/SessionExpireDialog/SessionExpiredDialogService'; +export * from './shared/NodesManager/NavNodeManagerService'; export * from './NavigationTree/ElementsTree'; export * from './NavigationTree/TreeContext'; export * from './NavigationTree/NavigationTreeService'; diff --git a/webapp/packages/core-app/src/locales/en.ts b/webapp/packages/core-app/src/locales/en.ts index b686ef09fe..7e3a3432a4 100644 --- a/webapp/packages/core-app/src/locales/en.ts +++ b/webapp/packages/core-app/src/locales/en.ts @@ -10,6 +10,9 @@ export default [ ['app_shared_settingsMenu_lang', 'Language'], ['app_topnavbar_connection_schema_manager_not_selected', '-- not selected --'], ['app_navigationTree_openNodeTab', 'Open'], + ['app_navigationTree_connection_view', 'Connection view'], + ['app_navigationTree_connection_view_simple_option', 'Simple'], + ['app_navigationTree_connection_view_advanced_option', 'Advanced'], ['app_navigationTree_refreshNode', 'Refresh'], ['app_navigationTree_context_disconnect', 'Disconnect'], ['app_shared_inlineEditor_dialog_title', 'Edit mode'], diff --git a/webapp/packages/core-app/src/locales/ru.ts b/webapp/packages/core-app/src/locales/ru.ts index bdc6cf4c55..62d40a3b8c 100644 --- a/webapp/packages/core-app/src/locales/ru.ts +++ b/webapp/packages/core-app/src/locales/ru.ts @@ -13,6 +13,9 @@ export default [ 'Нет открытых объектов для отображения. Дважды нажмите на элемент в дереве навигации, чтобы открыть его.', ], ['app_navigationTree_openNodeTab', 'Открыть'], + ['app_navigationTree_connection_view', 'Отображение'], + ['app_navigationTree_connection_view_simple_option', 'Упрощенное'], + ['app_navigationTree_connection_view_advanced_option', 'Продвинутое'], ['app_navigationTree_refreshNode', 'Обновить'], ['app_navigationTree_context_disconnect', 'Отключить'], ['app_shared_inlineEditor_dialog_title', 'Редактирование'], diff --git a/webapp/packages/core-bootstrap/src/manifest.ts b/webapp/packages/core-bootstrap/src/manifest.ts index ada62a8a0a..e9a51501e6 100644 --- a/webapp/packages/core-bootstrap/src/manifest.ts +++ b/webapp/packages/core-bootstrap/src/manifest.ts @@ -55,6 +55,7 @@ import { DBDriverResource, DatabaseAuthModelsResource, ConnectionAuthService, + ConnectionViewService, ConnectionsAdministrationService, ConnectionsResource, ConnectionsLocaleService, @@ -156,6 +157,7 @@ export const coreManifest: PluginManifest = { NavigationTabsService, DatabaseAuthModelsResource, ConnectionAuthService, + ConnectionViewService, ConnectionsAdministrationNavService, ConnectionManualService, ConnectionSearchService, diff --git a/webapp/packages/core-connections/src/ConnectionNavigatorViewSettings.ts b/webapp/packages/core-connections/src/ConnectionNavigatorViewSettings.ts new file mode 100644 index 0000000000..e9adfe6311 --- /dev/null +++ b/webapp/packages/core-connections/src/ConnectionNavigatorViewSettings.ts @@ -0,0 +1,36 @@ +/* + * cloudbeaver - Cloud Database Manager + * Copyright (C) 2020 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +import type { NavigatorSettingsInput } from '@cloudbeaver/core-sdk'; + +type NavigatorView = 'simple' | 'advanced'; + +export const CONNECTION_NAVIGATOR_VIEW_SETTINGS: Record = { + simple: { + showOnlyEntities: true, + hideFolders: true, + hideVirtualModel: true, + hideSchemas: false, + mergeEntities: false, + showSystemObjects: false, + showUtilityObjects: false, + }, + advanced: { + showOnlyEntities: false, + hideFolders: false, + hideVirtualModel: false, + hideSchemas: false, + mergeEntities: false, + showSystemObjects: false, + showUtilityObjects: false, + }, +}; + +export function isSimpleNavigatorView(settings: NavigatorSettingsInput): boolean { + return settings.hideVirtualModel && settings.showOnlyEntities && settings.hideFolders; +} diff --git a/webapp/packages/core-connections/src/ConnectionViewService.ts b/webapp/packages/core-connections/src/ConnectionViewService.ts new file mode 100644 index 0000000000..16b19b822d --- /dev/null +++ b/webapp/packages/core-connections/src/ConnectionViewService.ts @@ -0,0 +1,36 @@ +/* + * cloudbeaver - Cloud Database Manager + * Copyright (C) 2020 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 { NavNodeManagerService, NodeManagerUtils } from '@cloudbeaver/core-app'; +import { injectable } from '@cloudbeaver/core-di'; +import { NotificationService } from '@cloudbeaver/core-events'; +import { GraphQLService, NavigatorSettingsInput } from '@cloudbeaver/core-sdk'; + +@injectable() +export class ConnectionViewService { + constructor( + private graphQLService: GraphQLService, + private navNodeManagerService: NavNodeManagerService, + private notificationService: NotificationService + ) { } + + async changeConnectionView(nodeId: string, settings: NavigatorSettingsInput): Promise { + const connectionId = NodeManagerUtils.connectionNodeIdToConnectionId(nodeId); + + try { + await this.graphQLService.sdk.setConnectionNavigatorSettings({ + id: connectionId, + settings, + }); + + await this.navNodeManagerService.refreshTree(nodeId); + } catch (exception) { + this.notificationService.logException(exception); + } + } +} diff --git a/webapp/packages/core-connections/src/index.ts b/webapp/packages/core-connections/src/index.ts index f808357054..f083201079 100644 --- a/webapp/packages/core-connections/src/index.ts +++ b/webapp/packages/core-connections/src/index.ts @@ -14,6 +14,7 @@ export * from './extensions/IConnectionSetter'; export * from './ConnectionsManagerService'; export * from './ConnectionInfoResource'; export * from './ConnectionAuthService'; +export * from './ConnectionViewService'; export * from './DriverPropertiesService'; export * from './EConnectionFeature'; export * from './ContainerResource'; @@ -23,3 +24,4 @@ export * from './DBDriverResource'; export * from './useConnectionInfo'; export * from './useDBDriver'; export * from './getUniqueConnectionName'; +export * from './ConnectionNavigatorViewSettings'; diff --git a/webapp/packages/core-dialogs/src/Menu/MenuPanel/MenuTrigger.tsx b/webapp/packages/core-dialogs/src/Menu/MenuPanel/MenuTrigger.tsx index ca74b68a88..7eb8a58456 100644 --- a/webapp/packages/core-dialogs/src/Menu/MenuPanel/MenuTrigger.tsx +++ b/webapp/packages/core-dialogs/src/Menu/MenuPanel/MenuTrigger.tsx @@ -71,7 +71,7 @@ const MenuPanel = observer(function MenuPanel({ } return styled(styles)( - + {panel.menuItems.map(item => ( ))} diff --git a/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql b/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql new file mode 100644 index 0000000000..cf675339c1 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/connections/setConnectionNavigatorSettings.gql @@ -0,0 +1,3 @@ +mutation setConnectionNavigatorSettings($id: ID!, $settings: NavigatorSettingsInput!) { + setConnectionNavigatorSettings(id: $id, settings: $settings) +} diff --git a/webapp/packages/core-sdk/src/sdk.ts b/webapp/packages/core-sdk/src/sdk.ts index 4069f1043c..87191a29ee 100644 --- a/webapp/packages/core-sdk/src/sdk.ts +++ b/webapp/packages/core-sdk/src/sdk.ts @@ -1134,6 +1134,13 @@ export type RefreshSessionConnectionsMutationVariables = Exact<{ [key: string]: export type RefreshSessionConnectionsMutation = Pick; +export type SetConnectionNavigatorSettingsMutationVariables = Exact<{ + id: Scalars['ID']; + settings: NavigatorSettingsInput; +}>; + +export type SetConnectionNavigatorSettingsMutation = Pick; + export type GetTemplateConnectionsQueryVariables = Exact<{ [key: string]: never }>; export interface GetTemplateConnectionsQuery { connections: Array> } @@ -1937,6 +1944,11 @@ export const RefreshSessionConnectionsDocument = ` refreshSessionConnections } `; +export const SetConnectionNavigatorSettingsDocument = ` + mutation setConnectionNavigatorSettings($id: ID!, $settings: NavigatorSettingsInput!) { + setConnectionNavigatorSettings(id: $id, settings: $settings) +} + `; export const GetTemplateConnectionsDocument = ` query getTemplateConnections { connections: templateConnections { @@ -2517,6 +2529,9 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = refreshSessionConnections(variables?: RefreshSessionConnectionsMutationVariables): Promise { return withWrapper(() => client.request(RefreshSessionConnectionsDocument, variables)); }, + setConnectionNavigatorSettings(variables: SetConnectionNavigatorSettingsMutationVariables): Promise { + return withWrapper(() => client.request(SetConnectionNavigatorSettingsDocument, variables)); + }, getTemplateConnections(variables?: GetTemplateConnectionsQueryVariables): Promise { return withWrapper(() => client.request(GetTemplateConnectionsDocument, variables)); }, diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationNavigatorViewForm.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationNavigatorViewForm.tsx new file mode 100644 index 0000000000..1173bffdf5 --- /dev/null +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationNavigatorViewForm.tsx @@ -0,0 +1,53 @@ +/* + * cloudbeaver - Cloud Database Manager + * Copyright (C) 2020 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 { observer } from 'mobx-react-lite'; +import React, { useCallback } from 'react'; + +import { FormGroup, Switch } from '@cloudbeaver/core-blocks'; +import { isSimpleNavigatorView, CONNECTION_NAVIGATOR_VIEW_SETTINGS } from '@cloudbeaver/core-connections'; +import { useTranslate } from '@cloudbeaver/core-localization'; + +import type { IServerConfigurationPageState } from '../IServerConfigurationPageState'; + +interface Props { + configs: IServerConfigurationPageState; +} + +export const ServerConfigurationNavigatorViewForm: React.FC = observer(function ServerConfigurationNavigatorViewForm({ + configs, +}) { + const translate = useTranslate(); + + const isSimpleView = isSimpleNavigatorView(configs.navigatorConfig); + + const onNavigatorViewChangeHandler = useCallback((value: boolean) => { + if (value) { + configs.navigatorConfig = { ...CONNECTION_NAVIGATOR_VIEW_SETTINGS.simple }; + } else { + configs.navigatorConfig = { ...CONNECTION_NAVIGATOR_VIEW_SETTINGS.advanced }; + } + }, [configs]); + + return ( + <> + + + {translate('administration_configuration_wizard_configuration_navigation_tree_view')} + + + + ); +}); diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/IServerConfigurationPageState.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/IServerConfigurationPageState.ts index 5bbc141ebd..02cb5c93a1 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/IServerConfigurationPageState.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/IServerConfigurationPageState.ts @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ -import { NavigatorSettingsInput, ServerConfigInput } from '@cloudbeaver/core-sdk'; +import type { NavigatorSettingsInput, ServerConfigInput } from '@cloudbeaver/core-sdk'; export interface IServerConfigurationPageState { serverConfig: ServerConfigInput; diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx index eeff4d82c9..bc18f79f18 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationPage.tsx @@ -19,6 +19,7 @@ import { useStyles, composes } from '@cloudbeaver/core-theming'; import { ServerConfigurationAdminForm } from './Form/ServerConfigurationAdminForm'; import { ServerConfigurationConfigurationForm } from './Form/ServerConfigurationConfigurationForm'; import { ServerConfigurationInfoForm } from './Form/ServerConfigurationInfoForm'; +import { ServerConfigurationNavigatorViewForm } from './Form/ServerConfigurationNavigatorViewForm'; import { ServerConfigurationPageController } from './ServerConfigurationPageController'; import { ServerConfigurationService } from './ServerConfigurationService'; @@ -111,6 +112,7 @@ export const ServerConfigurationPage = observer(function ServerConfigurationPage + diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts index 01a5233951..481a5759f1 100644 --- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts +++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationService.ts @@ -10,6 +10,7 @@ import { observable, makeObservable } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { UsersResource } from '@cloudbeaver/core-authentication'; +import { CONNECTION_NAVIGATOR_VIEW_SETTINGS } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { IExecutor, Executor } from '@cloudbeaver/core-executor'; @@ -130,8 +131,8 @@ export class ServerConfigurationService { } if (this.administrationScreenService.isConfigurationMode) { if (!this.state.serverConfig.adminName - || this.state.serverConfig.adminName.length < 6 - || !this.state.serverConfig.adminPassword + || this.state.serverConfig.adminName.length < 6 + || !this.state.serverConfig.adminPassword ) { return false; } @@ -151,15 +152,8 @@ export class ServerConfigurationService { customConnectionsEnabled: true, sessionExpireTime: 30, }, - navigatorConfig: { - hideFolders: false, - hideSchemas: false, - hideVirtualModel: false, - mergeEntities: false, - showOnlyEntities: false, - showSystemObjects: false, - showUtilityObjects: false, - }, + navigatorConfig: CONNECTION_NAVIGATOR_VIEW_SETTINGS.advanced, + }; } @@ -171,15 +165,7 @@ export class ServerConfigurationService { customConnectionsEnabled: config.supportsCustomConnections, sessionExpireTime: (config.sessionExpireTime ?? 1800000) / 1000 / 60, }, - navigatorConfig: { - hideFolders: false, - hideSchemas: false, - hideVirtualModel: false, - mergeEntities: false, - showOnlyEntities: false, - showSystemObjects: false, - showUtilityObjects: false, - }, + navigatorConfig: config.defaultNavigatorSettings, }; } } diff --git a/webapp/packages/plugin-administration/src/index.ts b/webapp/packages/plugin-administration/src/index.ts index 217e1aa3f6..316c280185 100644 --- a/webapp/packages/plugin-administration/src/index.ts +++ b/webapp/packages/plugin-administration/src/index.ts @@ -5,3 +5,4 @@ export default manifest; export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationAdminForm'; export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationConfigurationForm'; export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm'; +export * from './ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationNavigatorViewForm'; diff --git a/webapp/packages/plugin-administration/src/locales/en.ts b/webapp/packages/plugin-administration/src/locales/en.ts index 389dd2acf7..f6ee593665 100644 --- a/webapp/packages/plugin-administration/src/locales/en.ts +++ b/webapp/packages/plugin-administration/src/locales/en.ts @@ -22,6 +22,8 @@ export default [ ['administration_configuration_wizard_configuration_authentication', 'Enable users authentication'], ['administration_configuration_wizard_configuration_authentication_description', 'Allows users to authenticate. Otherwise only anonymous access is enabled'], ['administration_configuration_wizard_configuration_custom_connections', 'Enable custom connections'], + ['administration_configuration_wizard_configuration_navigation_tree_view', 'Enable navigation tree simple view'], + ['administration_configuration_wizard_configuration_navigation_tree_view_description', "By default, all user's new connections will contain only basic information in navigation tree"], ['administration_configuration_wizard_configuration_custom_connections_description', 'Allows users to create custom connections. Otherwise, all new connections can be created from the administration part only'], ['administration_configuration_wizard_configuration_navigator', 'Navigator'], ['administration_configuration_wizard_configuration_navigator_hide_folders', 'Hide Folders'], diff --git a/webapp/packages/plugin-administration/src/locales/ru.ts b/webapp/packages/plugin-administration/src/locales/ru.ts index 34b5c3c1ba..ea977a6a97 100644 --- a/webapp/packages/plugin-administration/src/locales/ru.ts +++ b/webapp/packages/plugin-administration/src/locales/ru.ts @@ -2,6 +2,8 @@ export default [ ['administration_configuration_wizard_configuration', 'Настройки сервера'], ['administration_configuration_wizard_configuration_server_session_lifetime', 'Время сессии'], ['administration_configuration_wizard_configuration_custom_connections', 'Разрешить пользовательские подключения'], + ['administration_configuration_wizard_configuration_navigation_tree_view', 'Отображать упрощенную версию дерева навигации'], + ['administration_configuration_wizard_configuration_navigation_tree_view_description', 'Все новые подключения, созданные пользователем, будут иметь только базовую информацию в дереве навигации'], ['administration_configuration_wizard_configuration_custom_connections_description', 'Позволяет пользователям создавать собственные подключения. Иначе, любые подключения могут быть добавлены только со страницы администрирования'], ['administration_server_configuration_save_confirmation_title', 'Изменение настроек сервера'], ['administration_server_configuration_save_confirmation_message', 'Вы собираетесь изменить критичные настройки, приложение будет перезагружено.'],