From be9dcf62bc71ffc5106b356fc25c75e7f1130e22 Mon Sep 17 00:00:00 2001 From: Wroud Date: Sun, 1 Nov 2020 16:38:02 +0300 Subject: [PATCH] refactor(core-connections): CB-449 move connection create methods to tabs container --- .../packages/core-bootstrap/src/manifest.ts | 9 +- .../Connections/ConnectionsAdministration.tsx | 13 +- .../ConnectionsAdministrationController.ts | 9 +- .../ConnectionsAdministrationService.ts | 14 +- .../CreateConnection/CreateConnection.tsx | 94 ++++---------- .../CreateConnectionBaseBootstrap.ts | 51 ++++++++ .../CreateConnectionController.tsx | 103 --------------- .../CreateConnectionMethod.tsx | 32 ----- .../Manual/ConnectionManualService.tsx | 51 ++++++++ .../{ => Manual}/CustomConnection.tsx | 23 +--- .../CreateConnection/{ => Manual}/Driver.tsx | 2 +- .../{ => Manual}/DriverList.tsx | 2 +- .../Search/ConnectionSearchService.tsx | 96 ++++++++++++++ .../{ => Search}/Database.tsx | 2 +- .../{ => Search}/DatabaseList.tsx | 1 + .../Search/SearchDatabase.tsx | 29 +++++ .../CreateConnection/SearchDatabase.tsx | 45 ------- .../Connections/CreateConnectionService.ts | 122 +++++++++++++++--- webapp/packages/core-connections/src/index.ts | 3 + 19 files changed, 396 insertions(+), 305 deletions(-) create mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts delete mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionController.tsx delete mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionMethod.tsx create mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.tsx rename webapp/packages/core-connections/src/Administration/Connections/CreateConnection/{ => Manual}/CustomConnection.tsx (65%) rename webapp/packages/core-connections/src/Administration/Connections/CreateConnection/{ => Manual}/Driver.tsx (95%) rename webapp/packages/core-connections/src/Administration/Connections/CreateConnection/{ => Manual}/DriverList.tsx (95%) create mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/ConnectionSearchService.tsx rename webapp/packages/core-connections/src/Administration/Connections/CreateConnection/{ => Search}/Database.tsx (97%) rename webapp/packages/core-connections/src/Administration/Connections/CreateConnection/{ => Search}/DatabaseList.tsx (99%) create mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/SearchDatabase.tsx delete mode 100644 webapp/packages/core-connections/src/Administration/Connections/CreateConnection/SearchDatabase.tsx diff --git a/webapp/packages/core-bootstrap/src/manifest.ts b/webapp/packages/core-bootstrap/src/manifest.ts index 7ef00e666a..44851e2f8e 100644 --- a/webapp/packages/core-bootstrap/src/manifest.ts +++ b/webapp/packages/core-bootstrap/src/manifest.ts @@ -58,7 +58,11 @@ import { ConnectionsResource, ConnectionsLocaleService, DriverPropertiesService, - ConnectionsAdministrationNavService, CreateConnectionService + ConnectionsAdministrationNavService, + CreateConnectionService, + ConnectionManualService, + ConnectionSearchService, + CreateConnectionBaseBootstrap } from '@cloudbeaver/core-connections'; import { PluginManifest } from '@cloudbeaver/core-di'; import { CommonDialogService, ContextMenuService } from '@cloudbeaver/core-dialogs'; @@ -146,6 +150,9 @@ export const coreManifest: PluginManifest = { DatabaseAuthModelsResource, ConnectionAuthService, ConnectionsAdministrationNavService, + ConnectionManualService, + ConnectionSearchService, + CreateConnectionBaseBootstrap, CreateConnectionService, ConnectionsAdministrationService, ConnectionsResource, diff --git a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministration.tsx b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministration.tsx index 05fa826846..0d96250d0a 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministration.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministration.tsx @@ -11,13 +11,14 @@ import styled, { css, use } from 'reshadow'; import { AdministrationTools, AdministrationItemContentProps, ADMINISTRATION_TOOLS_STYLES } from '@cloudbeaver/core-administration'; import { Loader, IconButton } from '@cloudbeaver/core-blocks'; -import { useController } from '@cloudbeaver/core-di'; +import { useController, useService } from '@cloudbeaver/core-di'; import { Translate } from '@cloudbeaver/core-localization'; import { useStyles, composes } from '@cloudbeaver/core-theming'; import { ConnectionsAdministrationController } from './ConnectionsAdministrationController'; import { ConnectionsTable } from './ConnectionsTable/ConnectionsTable'; import { CreateConnection } from './CreateConnection/CreateConnection'; +import { CreateConnectionService } from './CreateConnectionService'; const styles = composes( css` @@ -70,6 +71,7 @@ export const ConnectionsAdministration: React.FC param, configurationWizard, }) { + const service = useService(CreateConnectionService); const controller = useController(ConnectionsAdministrationController); return styled(useStyles(styles, ADMINISTRATION_TOOLS_STYLES))( @@ -82,17 +84,12 @@ export const ConnectionsAdministration: React.FC )} - + {sub && ( - + )} this.connectionsAdministrationNavService.navToCreate(method); - cancelCreate = (): void => this.connectionsAdministrationNavService.navToRoot(); - - create = (): void => this.connectionsAdministrationNavService.navToCreate('driver'); - update = async (): Promise => { try { await this.connectionsResource.refresh('all'); diff --git a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts index b48594d38e..0e48ee0f38 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts +++ b/webapp/packages/core-connections/src/Administration/Connections/ConnectionsAdministrationService.ts @@ -36,13 +36,14 @@ export class ConnectionsAdministrationService extends Bootstrap { type: AdministrationItemType.Default, order: 2, configurationWizardOptions: { - defaultRoute: { sub: 'create', param: 'search-database' }, + defaultRoute: { sub: 'create' }, description: 'connections_administration_configuration_wizard_step_description', }, sub: [ { name: 'create', onActivate: this.activateCreateMethod.bind(this), + onDeActivate: this.deactivateCreateMethod.bind(this), }, ], getContentComponent: () => ConnectionsAdministration, @@ -63,12 +64,19 @@ export class ConnectionsAdministrationService extends Bootstrap { private async activateCreateMethod(param: string | null) { if (!param) { + this.createConnectionService.setCreateMethod(); return; } - const method = this.createConnectionService.methods.get(param); + const method = this.createConnectionService.tabsContainer.tabInfoMap.get(param); if (method) { - method.onOpen?.(); + method.onOpen?.(method.key); + } + } + + private async deactivateCreateMethod(param: string | null, configuration: boolean, outside: boolean) { + if (outside) { + this.createConnectionService.close(); } } diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnection.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnection.tsx index d7ea103255..4d1b2b2612 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnection.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnection.tsx @@ -7,23 +7,18 @@ */ import { observer } from 'mobx-react'; -import { useEffect, useCallback } from 'react'; import styled, { css } from 'reshadow'; import { - TabsState, TabList, Tab, TabTitle, IconButton, Loader, StaticImage, Icon, BORDER_TAB_STYLES + TabsState, TabList, IconButton, Loader, StaticImage, Icon, BORDER_TAB_STYLES, TabPanelList } from '@cloudbeaver/core-blocks'; -import { useController, useService } from '@cloudbeaver/core-di'; +import { useService } from '@cloudbeaver/core-di'; import { useTranslate } from '@cloudbeaver/core-localization'; import { useStyles, composes } from '@cloudbeaver/core-theming'; import { ConnectionForm } from '../ConnectionForm/ConnectionForm'; import { IConnectionFormModel } from '../ConnectionForm/IConnectionFormModel'; import { CreateConnectionService } from '../CreateConnectionService'; -import { CreateConnectionController } from './CreateConnectionController'; -import { CreateConnectionMethod } from './CreateConnectionMethod'; -import { CustomConnection } from './CustomConnection'; -import { SearchDatabase } from './SearchDatabase'; const styles = composes( css` @@ -64,7 +59,8 @@ const styles = composes( overflow: auto; } - CustomConnection, SearchDatabase { + TabPanel, CustomConnection, SearchDatabase { + flex-direction: column; height: 100%; overflow: auto; } @@ -115,52 +111,33 @@ const styles = composes( ); interface Props { - method: string; + method: string | null | undefined; configurationWizard: boolean; - onChange: (method: string) => void; - onCancel: () => void; } export const CreateConnection = observer(function CreateConnection({ method, configurationWizard, - onChange, - onCancel, }: Props) { const style = useStyles(styles); const service = useService(CreateConnectionService); - const controller = useController(CreateConnectionController); const translate = useTranslate(); - useEffect(() => { - if (configurationWizard) { - controller.search(); - } - }, [configurationWizard, controller]); - - const handleConnectionCancel = useCallback(() => { - if (method === 'driver') { - onCancel(); - } else { - controller.back(); - } - }, [controller, method, onCancel]); - - if (controller.connection) { + if (service.connection) { return styled(style)( - - {controller.driver?.icon && } - {controller.driver?.name ?? translate('connections_administration_connection_create')} + + {service.driver?.icon && } + {service.driver?.name ?? translate('connections_administration_connection_create')} - + @@ -170,42 +147,25 @@ export const CreateConnection = observer(function CreateConnection({ return styled(style, BORDER_TAB_STYLES)( - + {translate('connections_administration_connection_create')} - + - - - {translate('connections_connection_create_custom')} - - - {translate('connections_connection_create_search_database')} - - {service.methodList.map(method => ( - - {translate(method.title)} - - ))} - + + + + {service.disabled && } + + - - {method === 'driver' && } - {method === 'search-database' && ( - - )} - - {controller.isProcessing && } - - ); }); diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts new file mode 100644 index 0000000000..eebbae29ab --- /dev/null +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap.ts @@ -0,0 +1,51 @@ +/* + * 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 { injectable, Bootstrap } from '@cloudbeaver/core-di'; + +import { CreateConnectionService } from '../CreateConnectionService'; +import { ConnectionManualService } from './Manual/ConnectionManualService'; +import { CustomConnection } from './Manual/CustomConnection'; +import { ConnectionSearchService } from './Search/ConnectionSearchService'; +import { SearchDatabase } from './Search/SearchDatabase'; + +@injectable() +export class CreateConnectionBaseBootstrap extends Bootstrap { + constructor( + private readonly createConnectionService: CreateConnectionService, + private readonly connectionManualService: ConnectionManualService, + private readonly connectionSearchService: ConnectionSearchService + ) { + super(); + } + + register(): void | Promise { + this.createConnectionService.tabsContainer.add({ + key: 'manual', + name: 'connections_connection_create_custom', + order: 1, + panel: () => CustomConnection, + onOpen: () => this.connectionManualService.load(), + }); + this.createConnectionService.tabsContainer.add({ + key: 'search', + name: 'connections_connection_create_search_database', + order: 2, + panel: () => SearchDatabase, + onOpen: () => this.connectionSearchService.load(), + options: { + configurationWizard: { + activationPriority: 2, + }, + close: () => this.connectionSearchService.close(), + }, + }); + } + + load(): void | Promise { } +} diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionController.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionController.tsx deleted file mode 100644 index 5e472c77fe..0000000000 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionController.tsx +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 { observable, computed } from 'mobx'; - -import { injectable } from '@cloudbeaver/core-di'; -import { NotificationService } from '@cloudbeaver/core-events'; -import { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; -import { uuid } from '@cloudbeaver/core-utils'; - -import { DBDriverResource } from '../../../DBDriverResource'; -import { AdminConnection, ConnectionsResource } from '../../ConnectionsResource'; - -@injectable() -export class CreateConnectionController { - @observable hosts = 'localhost'; - @observable isProcessing = false; - @observable databases: AdminConnectionSearchInfo[]; - @observable connection: AdminConnection | null; - @observable availableDrivers: string[]; - @observable credentials: Record; - @observable grantedSubjects = []; - - @computed get driver() { - if (!this.connection?.driverId) { - return; - } - - return this.dbDriverResource.get(this.connection.driverId); - } - - constructor( - private notificationService: NotificationService, - private connectionsResource: ConnectionsResource, - private dbDriverResource: DBDriverResource - ) { - this.credentials = {}; - this.databases = []; - this.availableDrivers = []; - this.connection = null; - } - - search = async () => { - if (this.isProcessing || !this.hosts || !this.hosts.trim()) { - return; - } - - this.isProcessing = true; - - try { - const hosts = this.hosts - .trim() - .replace(/[\s,|+-]+/gm, ' ') - .split(/[\s,|+-]/); - - this.databases = await this.connectionsResource.searchDatabases(hosts); - } catch (exception) { - this.notificationService.logException(exception, 'Databases search failed'); - } finally { - this.isProcessing = false; - } - }; - - onSearchChange = (hosts: string) => { - this.hosts = hosts; - }; - - onDriverSelect = (driverId: string) => { - this.connection = { - id: uuid(), - driverId, - template: false, - saveCredentials: false, - authProperties: [], - properties: {}, - } as Partial as any; - this.availableDrivers = [driverId]; - }; - - onDatabaseSelect = (database: AdminConnectionSearchInfo) => { - this.connection = { - id: uuid(), - driverId: database.defaultDriver, - template: false, - saveCredentials: false, - host: database.host, - port: `${database.port}`, - authProperties: [], - properties: {}, - } as Partial as any; - this.availableDrivers = database.possibleDrivers; - }; - - back = (): void => { - this.connection = null; - this.availableDrivers = []; - }; -} diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionMethod.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionMethod.tsx deleted file mode 100644 index 56921969a0..0000000000 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CreateConnectionMethod.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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'; - -import { useService } from '@cloudbeaver/core-di'; - -import { CreateConnectionService } from '../CreateConnectionService'; - -interface Props { - methodId: string; -} - -export const CreateConnectionMethod: React.FC = observer(function CreateConnectionMethod({ - methodId, -}) { - const service = useService(CreateConnectionService); - - const method = service.methods.get(methodId); - if (!method) { - return null; - } - - const Panel = method.panel(); - - return ; -}); diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.tsx new file mode 100644 index 0000000000..c4bd69a765 --- /dev/null +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.tsx @@ -0,0 +1,51 @@ +/* + * 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 { injectable } from '@cloudbeaver/core-di'; +import { uuid } from '@cloudbeaver/core-utils'; + +import { DBDriverResource } from '../../../../DBDriverResource'; +import { AdminConnection } from '../../../ConnectionsResource'; +import { CreateConnectionService } from '../../CreateConnectionService'; + +@injectable() +export class ConnectionManualService { + get disabled(): boolean { + return this.createConnectionService.disabled; + } + + set disabled(value: boolean) { + this.createConnectionService.disabled = value; + } + + constructor( + private dbDriverResource: DBDriverResource, + private createConnectionService: CreateConnectionService + ) { + this.select = this.select.bind(this); + this.load = this.load.bind(this); + } + + select(driverId: string): void { + this.createConnectionService.setConnectionTemplate( + { + id: uuid(), + driverId, + template: false, + saveCredentials: false, + authProperties: [], + properties: {}, + } as Partial as any, + [driverId] + ); + } + + async load(): Promise { + await this.dbDriverResource.loadAll(); + } +} diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CustomConnection.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx similarity index 65% rename from webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CustomConnection.tsx rename to webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx index ba4916b37f..c13b9a47fb 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/CustomConnection.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/CustomConnection.tsx @@ -8,28 +8,19 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; -import { useMemo, useEffect } from 'react'; +import { useMemo } from 'react'; import { Loader } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; -import { DBDriverResource } from '../../../DBDriverResource'; +import { DBDriverResource } from '../../../../DBDriverResource'; +import { ConnectionManualService } from './ConnectionManualService'; import { DriverList } from './DriverList'; -interface Props { - className?: string; - onSelect: (driverId: string) => void; -} - -export const CustomConnection = observer(function CustomConnection({ - className, - onSelect, -}: Props) { +export const CustomConnection = observer(function CustomConnection() { + const service = useService(ConnectionManualService); const dbDriverResource = useService(DBDriverResource); - useEffect(() => { - dbDriverResource.loadAll(); - }, []); const loading = dbDriverResource.isLoading(); const drivers = useMemo(() => computed(() => ( Array.from(dbDriverResource.data.values()) @@ -37,8 +28,8 @@ export const CustomConnection = observer(function CustomConnection({ )), [dbDriverResource.data]); if (loading) { - return ; + return ; } - return ; + return ; }); diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Driver.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/Driver.tsx similarity index 95% rename from webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Driver.tsx rename to webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/Driver.tsx index 513602f6aa..104e220f1a 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Driver.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/Driver.tsx @@ -14,7 +14,7 @@ import { ListItem, ListItemIcon, StaticImage, ListItemName, ListItemDescription } from '@cloudbeaver/core-blocks'; -import { DBDriver } from '../../../DBDriverResource'; +import { DBDriver } from '../../../../DBDriverResource'; const styles = css` StaticImage { diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/DriverList.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx similarity index 95% rename from webapp/packages/core-connections/src/Administration/Connections/CreateConnection/DriverList.tsx rename to webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx index 5811b5dbf5..e4c5a43390 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/DriverList.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Manual/DriverList.tsx @@ -12,7 +12,7 @@ import { useState, useMemo } from 'react'; import { ItemListSearch, ItemList } from '@cloudbeaver/core-blocks'; import { useTranslate } from '@cloudbeaver/core-localization'; -import { DBDriver } from '../../../DBDriverResource'; +import { DBDriver } from '../../../../DBDriverResource'; import { Driver } from './Driver'; interface Props { diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/ConnectionSearchService.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/ConnectionSearchService.tsx new file mode 100644 index 0000000000..995e7d8f7b --- /dev/null +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/ConnectionSearchService.tsx @@ -0,0 +1,96 @@ +/* + * 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 { observable } from 'mobx'; + +import { AdministrationScreenService } from '@cloudbeaver/core-administration'; +import { injectable } from '@cloudbeaver/core-di'; +import { NotificationService } from '@cloudbeaver/core-events'; +import { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; +import { uuid } from '@cloudbeaver/core-utils'; + +import { AdminConnection, ConnectionsResource } from '../../../ConnectionsResource'; +import { CreateConnectionService } from '../../CreateConnectionService'; + +@injectable() +export class ConnectionSearchService { + @observable hosts = 'localhost'; + @observable databases: AdminConnectionSearchInfo[]; + + get disabled(): boolean { + return this.createConnectionService.disabled; + } + + set disabled(value: boolean) { + this.createConnectionService.disabled = value; + } + + constructor( + private notificationService: NotificationService, + private connectionsResource: ConnectionsResource, + private createConnectionService: CreateConnectionService, + private administrationScreenService: AdministrationScreenService + ) { + this.databases = []; + this.search = this.search.bind(this); + this.change = this.change.bind(this); + this.select = this.select.bind(this); + } + + close(): void { + this.hosts = 'localhost'; + this.databases = []; + } + + async load(): Promise { + if (this.administrationScreenService.isConfigurationMode) { + await this.search(); + } + } + + async search(): Promise { + if (this.disabled || !this.hosts || !this.hosts.trim()) { + return; + } + + this.disabled = true; + + try { + const hosts = this.hosts + .trim() + .replace(/[\s,|+-]+/gm, ' ') + .split(/[\s,|+-]/); + + this.databases = await this.connectionsResource.searchDatabases(hosts); + } catch (exception) { + this.notificationService.logException(exception, 'Databases search failed'); + } finally { + this.disabled = false; + } + } + + change(hosts: string): void { + this.hosts = hosts; + } + + select(database: AdminConnectionSearchInfo): void { + this.createConnectionService.setConnectionTemplate( + { + id: uuid(), + driverId: database.defaultDriver, + template: false, + saveCredentials: false, + host: database.host, + port: `${database.port}`, + authProperties: [], + properties: {}, + } as Partial as any, + database.possibleDrivers + ); + } +} diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Database.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/Database.tsx similarity index 97% rename from webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Database.tsx rename to webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/Database.tsx index b22e0fc15d..9e7a90ef8b 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Database.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/Database.tsx @@ -17,7 +17,7 @@ import { useService } from '@cloudbeaver/core-di'; import { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; import { composes, useStyles } from '@cloudbeaver/core-theming'; -import { DBDriverResource } from '../../../DBDriverResource'; +import { DBDriverResource } from '../../../../DBDriverResource'; const styles = composes( css` diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/DatabaseList.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/DatabaseList.tsx similarity index 99% rename from webapp/packages/core-connections/src/Administration/Connections/CreateConnection/DatabaseList.tsx rename to webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/DatabaseList.tsx index 7d1137005a..30d90b0f85 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/DatabaseList.tsx +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/DatabaseList.tsx @@ -27,6 +27,7 @@ const styles = composes( `, css` SubmittingForm { + flex: 1; display: flex; flex-direction: column; } diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/SearchDatabase.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/SearchDatabase.tsx new file mode 100644 index 0000000000..bd4e3a2857 --- /dev/null +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/Search/SearchDatabase.tsx @@ -0,0 +1,29 @@ +/* + * 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'; + +import { useService } from '@cloudbeaver/core-di'; + +import { ConnectionSearchService } from './ConnectionSearchService'; +import { DatabaseList } from './DatabaseList'; + +export const SearchDatabase: React.FC = observer(function SearchDatabase() { + const service = useService(ConnectionSearchService); + + return ( + + ); +}); diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/SearchDatabase.tsx b/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/SearchDatabase.tsx deleted file mode 100644 index 1db21e6ef6..0000000000 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnection/SearchDatabase.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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'; - -import { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; - -import { DatabaseList } from './DatabaseList'; - -interface Props { - databases: AdminConnectionSearchInfo[]; - hosts: string; - disabled?: boolean; - onSelect: (database: AdminConnectionSearchInfo) => void; - onChange: (hosts: string) => void; - onSearch?: () => Promise; - className?: string; -} - -export const SearchDatabase = observer(function SearchDatabase({ - databases, - hosts, - disabled, - onChange, - onSelect, - onSearch, - className, -}: Props) { - return ( - - ); -}); diff --git a/webapp/packages/core-connections/src/Administration/Connections/CreateConnectionService.ts b/webapp/packages/core-connections/src/Administration/Connections/CreateConnectionService.ts index 4653cb8b7b..238ee02001 100644 --- a/webapp/packages/core-connections/src/Administration/Connections/CreateConnectionService.ts +++ b/webapp/packages/core-connections/src/Administration/Connections/CreateConnectionService.ts @@ -8,33 +8,117 @@ import { computed, observable } from 'mobx'; +import { AdministrationScreenService } from '@cloudbeaver/core-administration'; +import { TabsContainer } from '@cloudbeaver/core-blocks'; import { injectable } from '@cloudbeaver/core-di'; +import { AdminConnectionGrantInfo } from '@cloudbeaver/core-sdk'; -export interface IConnectionCreateMethod { - key: string; - title: string; - panel: () => React.FC; - onOpen?: () => void; +import { DBDriver, DBDriverResource } from '../../DBDriverResource'; +import { AdminConnection } from '../ConnectionsResource'; +import { ConnectionsAdministrationNavService } from './ConnectionsAdministrationNavService'; + +export interface ICreateMethodOptions { + configurationWizard?: { + activationPriority?: number; + }; + close?: () => void; } @injectable() export class CreateConnectionService { - @observable.shallow - readonly methods: Map; + @observable disabled = false; + @observable connection: AdminConnection | null; + @observable availableDrivers: string[]; + @observable credentials: Record; + @observable grantedSubjects: AdminConnectionGrantInfo[]; - @computed get methodList(): IConnectionCreateMethod[] { - return Array.from(this.methods.values()); - } - - constructor() { - this.methods = new Map(); - } - - addMethod(method: IConnectionCreateMethod): void { - if (this.methods.has(method.key)) { - throw new Error('Method with same key already exists'); + @computed get driver(): DBDriver | undefined { + if (!this.connection?.driverId) { + return; } - this.methods.set(method.key, method); + return this.dbDriverResource.get(this.connection.driverId); + } + + readonly tabsContainer: TabsContainer; + + constructor( + private readonly dbDriverResource: DBDriverResource, + private readonly connectionsAdministrationNavService: ConnectionsAdministrationNavService, + private readonly administrationScreenService: AdministrationScreenService + ) { + this.credentials = {}; + this.availableDrivers = []; + this.grantedSubjects = []; + this.connection = null; + this.tabsContainer = new TabsContainer(); + + this.setConnectionTemplate = this.setConnectionTemplate.bind(this); + this.clearConnectionTemplate = this.clearConnectionTemplate.bind(this); + this.setCreateMethod = this.setCreateMethod.bind(this); + this.cancelCreate = this.cancelCreate.bind(this); + this.create = this.create.bind(this); + } + + getDefault(): string | null { + if (this.tabsContainer.tabInfoList.length === 0) { + return null; + } + if (this.administrationScreenService.isConfigurationMode) { + const sorted = this.tabsContainer.tabInfoList.sort((a, b) => { + const aPriority = a.options?.configurationWizard?.activationPriority || Number.MAX_SAFE_INTEGER; + const bPriority = b.options?.configurationWizard?.activationPriority || Number.MAX_SAFE_INTEGER; + + return aPriority - bPriority; + }); + + return sorted[0].key; + } + return this.tabsContainer.tabInfoList[0].key; + } + + setCreateMethod(method?: string): void { + if (!method) { + const id = this.getDefault(); + + if (!id) { + return; + } + method = id; + } + this.connectionsAdministrationNavService.navToCreate(method); + } + + cancelCreate(): void{ + this.clearConnectionTemplate(); + this.connectionsAdministrationNavService.navToRoot(); + } + + create(): void { + const defaultId = this.getDefault(); + if (!defaultId) { + return; + } + + this.connectionsAdministrationNavService.navToCreate(defaultId); + } + + setConnectionTemplate(connection: AdminConnection, drivers: string[]): void { + this.connection = connection; + this.availableDrivers = drivers; + } + + clearConnectionTemplate(): void { + this.connection = null; + this.availableDrivers = []; + this.credentials = {}; + this.grantedSubjects = []; + } + + close(): void { + this.clearConnectionTemplate(); + for (const method of this.tabsContainer.tabInfoList) { + method.options?.close?.(); + } } } diff --git a/webapp/packages/core-connections/src/index.ts b/webapp/packages/core-connections/src/index.ts index 5c4c827465..4b1bdb1e62 100644 --- a/webapp/packages/core-connections/src/index.ts +++ b/webapp/packages/core-connections/src/index.ts @@ -1,6 +1,9 @@ export * from './Administration/Connections/ConnectionsAdministration'; export * from './Administration/Connections/ConnectionsAdministrationNavService'; export * from './Administration/Connections/ConnectionsAdministrationService'; +export * from './Administration/Connections/CreateConnection/Manual/ConnectionManualService'; +export * from './Administration/Connections/CreateConnection/Search/ConnectionSearchService'; +export * from './Administration/Connections/CreateConnection/CreateConnectionBaseBootstrap'; export * from './Administration/Connections/CreateConnectionService'; export * from './Administration/ConnectionsResource';