mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
refactor(core-connections): CB-449 move connection create methods to tabs container
This commit is contained in:
@@ -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,
|
||||
|
||||
+5
-8
@@ -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<AdministrationItemContentProps>
|
||||
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<AdministrationItemContentProps>
|
||||
</message-box>
|
||||
)}
|
||||
<AdministrationTools>
|
||||
<IconButton name="add" viewBox="0 0 28 28" onClick={controller.create} />
|
||||
<IconButton name="add" viewBox="0 0 28 28" onClick={service.create} />
|
||||
<IconButton name="trash" viewBox="0 0 28 28" onClick={controller.delete} />
|
||||
<IconButton name="refresh-outline" viewBox="0 0 16 16" onClick={controller.update} />
|
||||
</AdministrationTools>
|
||||
{sub && (
|
||||
<CreateConnection
|
||||
method={param || 'driver'}
|
||||
configurationWizard={configurationWizard}
|
||||
onChange={controller.setCreateMethod}
|
||||
onCancel={controller.cancelCreate}
|
||||
/>
|
||||
<CreateConnection method={param} configurationWizard={configurationWizard} />
|
||||
)}
|
||||
<ConnectionsTable
|
||||
connections={controller.connections}
|
||||
|
||||
+1
-8
@@ -14,7 +14,6 @@ import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { resourceKeyList } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { AdminConnection, ConnectionsResource } from '../ConnectionsResource';
|
||||
import { ConnectionsAdministrationNavService } from './ConnectionsAdministrationNavService';
|
||||
|
||||
@injectable()
|
||||
export class ConnectionsAdministrationController {
|
||||
@@ -48,15 +47,9 @@ export class ConnectionsAdministrationController {
|
||||
constructor(
|
||||
private notificationService: NotificationService,
|
||||
private connectionsResource: ConnectionsResource,
|
||||
private commonDialogService: CommonDialogService,
|
||||
private connectionsAdministrationNavService: ConnectionsAdministrationNavService
|
||||
private commonDialogService: CommonDialogService
|
||||
) { }
|
||||
|
||||
setCreateMethod = (method: string): void => this.connectionsAdministrationNavService.navToCreate(method);
|
||||
cancelCreate = (): void => this.connectionsAdministrationNavService.navToRoot();
|
||||
|
||||
create = (): void => this.connectionsAdministrationNavService.navToCreate('driver');
|
||||
|
||||
update = async (): Promise<void> => {
|
||||
try {
|
||||
await this.connectionsResource.refresh('all');
|
||||
|
||||
+11
-3
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-67
@@ -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)(
|
||||
<connection-create as='div'>
|
||||
<title-bar as='div'>
|
||||
<back-button as='div'><Icon name="angle" viewBox="0 0 15 8" onClick={controller.back} /></back-button>
|
||||
{controller.driver?.icon && <StaticImage icon={controller.driver.icon} />}
|
||||
{controller.driver?.name ?? translate('connections_administration_connection_create')}
|
||||
<back-button as='div'><Icon name="angle" viewBox="0 0 15 8" onClick={service.clearConnectionTemplate} /></back-button>
|
||||
{service.driver?.icon && <StaticImage icon={service.driver.icon} />}
|
||||
{service.driver?.name ?? translate('connections_administration_connection_create')}
|
||||
<fill as="div" />
|
||||
<IconButton name="cross" viewBox="0 0 24 24" onClick={onCancel} />
|
||||
<IconButton name="cross" viewBox="0 0 24 24" onClick={service.cancelCreate} />
|
||||
</title-bar>
|
||||
<connection-create-content as='div'>
|
||||
<ConnectionForm
|
||||
model={controller as IConnectionFormModel}
|
||||
onBack={controller.back}
|
||||
onCancel={handleConnectionCancel}
|
||||
model={service as IConnectionFormModel}
|
||||
onBack={service.clearConnectionTemplate}
|
||||
onCancel={service.clearConnectionTemplate}
|
||||
/>
|
||||
</connection-create-content>
|
||||
<connection-create-footer as='div' />
|
||||
@@ -170,42 +147,25 @@ export const CreateConnection = observer(function CreateConnection({
|
||||
|
||||
return styled(style, BORDER_TAB_STYLES)(
|
||||
<connection-create as='div'>
|
||||
<TabsState currentTabId={method} onChange={onChange}>
|
||||
<TabsState
|
||||
currentTabId={method}
|
||||
container={service.tabsContainer}
|
||||
manual
|
||||
lazy
|
||||
onChange={service.setCreateMethod}
|
||||
>
|
||||
<title-bar as='div'>
|
||||
{translate('connections_administration_connection_create')}
|
||||
<fill as="div" />
|
||||
<IconButton name="cross" viewBox="0 0 16 16" onClick={onCancel} />
|
||||
<IconButton name="cross" viewBox="0 0 16 16" onClick={service.cancelCreate} />
|
||||
</title-bar>
|
||||
<TabList>
|
||||
<Tab tabId='driver'>
|
||||
<TabTitle>{translate('connections_connection_create_custom')}</TabTitle>
|
||||
</Tab>
|
||||
<Tab tabId='search-database'>
|
||||
<TabTitle>{translate('connections_connection_create_search_database')}</TabTitle>
|
||||
</Tab>
|
||||
{service.methodList.map(method => (
|
||||
<Tab key={method.key} tabId={method.key}>
|
||||
<TabTitle>{translate(method.title)}</TabTitle>
|
||||
</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
<TabList style={[style, BORDER_TAB_STYLES]} />
|
||||
<connection-create-content as='div'>
|
||||
<TabPanelList style={[style, BORDER_TAB_STYLES]} />
|
||||
{service.disabled && <Loader overlay />}
|
||||
</connection-create-content>
|
||||
<connection-create-footer as='div' />
|
||||
</TabsState>
|
||||
<connection-create-content as='div'>
|
||||
{method === 'driver' && <CustomConnection onSelect={controller.onDriverSelect} />}
|
||||
{method === 'search-database' && (
|
||||
<SearchDatabase
|
||||
databases={controller.databases}
|
||||
hosts={controller.hosts}
|
||||
disabled={controller.isProcessing}
|
||||
onSelect={controller.onDatabaseSelect}
|
||||
onSearch={controller.search}
|
||||
onChange={controller.onSearchChange}
|
||||
/>
|
||||
)}
|
||||
<CreateConnectionMethod methodId={method} />
|
||||
{controller.isProcessing && <Loader overlay />}
|
||||
</connection-create-content>
|
||||
<connection-create-footer as='div' />
|
||||
</connection-create>
|
||||
);
|
||||
});
|
||||
|
||||
+51
@@ -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<void> {
|
||||
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<void> { }
|
||||
}
|
||||
-103
@@ -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<string, string | number>;
|
||||
@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<AdminConnection> 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<AdminConnection> as any;
|
||||
this.availableDrivers = database.possibleDrivers;
|
||||
};
|
||||
|
||||
back = (): void => {
|
||||
this.connection = null;
|
||||
this.availableDrivers = [];
|
||||
};
|
||||
}
|
||||
-32
@@ -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<Props> = observer(function CreateConnectionMethod({
|
||||
methodId,
|
||||
}) {
|
||||
const service = useService(CreateConnectionService);
|
||||
|
||||
const method = service.methods.get(methodId);
|
||||
if (!method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const Panel = method.panel();
|
||||
|
||||
return <Panel />;
|
||||
});
|
||||
+51
@@ -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<AdminConnection> as any,
|
||||
[driverId]
|
||||
);
|
||||
}
|
||||
|
||||
async load(): Promise<void> {
|
||||
await this.dbDriverResource.loadAll();
|
||||
}
|
||||
}
|
||||
+7
-16
@@ -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 <Loader className={className} />;
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return <DriverList drivers={drivers.get()} className={className} onSelect={onSelect} />;
|
||||
return <DriverList drivers={drivers.get()} onSelect={service.select} />;
|
||||
});
|
||||
+1
-1
@@ -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 {
|
||||
+1
-1
@@ -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 {
|
||||
+96
@@ -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<void> {
|
||||
if (this.administrationScreenService.isConfigurationMode) {
|
||||
await this.search();
|
||||
}
|
||||
}
|
||||
|
||||
async search(): Promise<void> {
|
||||
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<AdminConnection> as any,
|
||||
database.possibleDrivers
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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`
|
||||
+1
@@ -27,6 +27,7 @@ const styles = composes(
|
||||
`,
|
||||
css`
|
||||
SubmittingForm {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
+29
@@ -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 (
|
||||
<DatabaseList
|
||||
databases={service.databases}
|
||||
hosts={service.hosts}
|
||||
disabled={service.disabled}
|
||||
onSelect={service.select}
|
||||
onChange={service.change}
|
||||
onSearch={service.search}
|
||||
/>
|
||||
);
|
||||
});
|
||||
-45
@@ -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<void>;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const SearchDatabase = observer(function SearchDatabase({
|
||||
databases,
|
||||
hosts,
|
||||
disabled,
|
||||
onChange,
|
||||
onSelect,
|
||||
onSearch,
|
||||
className,
|
||||
}: Props) {
|
||||
return (
|
||||
<DatabaseList
|
||||
databases={databases}
|
||||
hosts={hosts}
|
||||
disabled={disabled}
|
||||
className={className}
|
||||
onSelect={onSelect}
|
||||
onChange={onChange}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
);
|
||||
});
|
||||
+103
-19
@@ -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<string, IConnectionCreateMethod>;
|
||||
@observable disabled = false;
|
||||
@observable connection: AdminConnection | null;
|
||||
@observable availableDrivers: string[];
|
||||
@observable credentials: Record<string, string | number>;
|
||||
@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<any, ICreateMethodOptions>;
|
||||
|
||||
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?.();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user