diff --git a/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts b/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts index 9ffbf15a6c..639ff8ca76 100644 --- a/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts +++ b/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts @@ -15,6 +15,7 @@ import { IExtension } from '@cloudbeaver/core-extensions'; import { NavigationTreeService } from '../../NavigationTree/NavigationTreeService'; import { ConnectionsManagerService } from '../../shared/ConnectionsManager/ConnectionsManagerService'; import { ObjectContainer } from '../../shared/ConnectionsManager/ContainerResource'; +import { DBDriverResource } from '../../shared/ConnectionsManager/DBDriverResource'; import { isConnectionProvider, IConnectionProvider } from '../../shared/ConnectionsManager/extensions/IConnectionProvider'; import { isConnectionSetter, IConnectionSetter } from '../../shared/ConnectionsManager/extensions/IConnectionSetter'; import { ITab } from '../../shared/NavigationTabs/ITab'; @@ -117,6 +118,7 @@ export class ConnectionSchemaManagerService { constructor( private navigationTabsService: NavigationTabsService, private connectionsManagerService: ConnectionsManagerService, + private dbDriverResource: DBDriverResource, private notificationService: NotificationService, private navigationTreeService: NavigationTreeService, private navNodeExtensionsService: NavNodeExtensionsService, @@ -185,7 +187,7 @@ export class ConnectionSchemaManagerService { } try { - await this.connectionsManagerService.dbDrivers.load(''); + await this.dbDriverResource.loadAll(); } catch (exception) { this.notificationService.logException(exception, 'Can\'t load database drivers', true); } diff --git a/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts b/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts index cb756eef15..ec11e529c5 100644 --- a/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts +++ b/webapp/packages/core-app/src/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts @@ -13,6 +13,7 @@ import { ComputedMenuItemModel, ComputedMenuPanelModel, IMenuItem } from '@cloud import { Connection } from '../../../shared/ConnectionsManager/ConnectionInfoResource'; import { ConnectionsManagerService } from '../../../shared/ConnectionsManager/ConnectionsManagerService'; +import { DBDriverResource } from '../../../shared/ConnectionsManager/DBDriverResource'; import { EObjectFeature } from '../../../shared/NodesManager/EObjectFeature'; import { NodeManagerUtils } from '../../../shared/NodesManager/NodeManagerUtils'; import { ConnectionSchemaManagerService } from '../ConnectionSchemaManagerService'; @@ -37,7 +38,7 @@ export class ConnectionSelectorController { if (!this.currentConnection) { return; } - const driverIcon = this.connectionsManagerService.dbDrivers.data.get(this.currentConnection.driverId)?.icon; + const driverIcon = this.dbDriverResource.get(this.currentConnection.driverId)?.icon; return driverIcon; } @@ -75,6 +76,7 @@ export class ConnectionSelectorController { constructor( private connectionSelectorService: ConnectionSchemaManagerService, private connectionsManagerService: ConnectionsManagerService, + private dbDriverResource: DBDriverResource, ) { this.connectionMenu = new ComputedMenuItemModel({ diff --git a/webapp/packages/core-app/src/index.ts b/webapp/packages/core-app/src/index.ts index fab682264d..66f7eb8ef8 100644 --- a/webapp/packages/core-app/src/index.ts +++ b/webapp/packages/core-app/src/index.ts @@ -30,6 +30,7 @@ export * from './shared/NodesManager/NodeManagerUtils'; export * from './shared/Navigation/NavigationService'; export * from './shared/NavigationTabs/NavigationTabsService'; export * from './shared/NavigationTabs/TabNavigationContext'; +export * from './shared/ObjectPropertyInfoForm/ObjectPropertyInfoForm'; export * from './shared/ToolsPanel/LogViewTab/LogViewerMenuService'; export * from './shared/ToolsPanel/LogViewTab/LogViewerService'; export * from './NavigationTree/NavigationTreeService'; diff --git a/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionAuthService.ts b/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionAuthService.ts index 27740e4caf..93752ad496 100644 --- a/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionAuthService.ts +++ b/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionAuthService.ts @@ -26,11 +26,11 @@ export class ConnectionAuthService { if (!connection?.connected) { connection = await this.connectionInfoResource.refresh(connectionId); } else { - return; + return connection; } if (connection.connected) { - return; + return connection; } if (connection.authNeeded) { @@ -38,5 +38,7 @@ export class ConnectionAuthService { } else { await this.connectionInfoResource.init(connectionId); } + + return this.connectionInfoResource.get(connectionId)!; } } diff --git a/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionsManagerService.ts b/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionsManagerService.ts index d7733516e3..a78f2e05a3 100644 --- a/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionsManagerService.ts +++ b/webapp/packages/core-app/src/shared/ConnectionsManager/ConnectionsManagerService.ts @@ -19,7 +19,6 @@ import { NavNodeManagerService } from '../NodesManager/NavNodeManagerService'; import { NodeManagerUtils } from '../NodesManager/NodeManagerUtils'; import { ConnectionInfoResource, Connection } from './ConnectionInfoResource'; import { ContainerResource, ObjectContainer } from './ContainerResource'; -import { DBDriverResource, DBDriver } from './DBDriverResource'; import { EConnectionFeature } from './EConnectionFeature'; export type DBSource = Pick @@ -37,7 +36,6 @@ export class ConnectionsManagerService { private graphQLService: GraphQLService, readonly connectionInfo: ConnectionInfoResource, readonly connectionObjectContainers: ContainerResource, - readonly dbDrivers: DBDriverResource, private navNodeManagerService: NavNodeManagerService, private sessionResource: SessionResource, private notificationService: NotificationService @@ -45,10 +43,6 @@ export class ConnectionsManagerService { this.sessionResource.onDataUpdate.subscribe(this.restoreConnections.bind(this)); } - getDBDrivers(): Map { - return this.dbDrivers.data; - } - async loadConnectionInfoAsync(connectionId: string): Promise { return this.connectionInfo.load(connectionId); } @@ -57,11 +51,6 @@ export class ConnectionsManagerService { return this.connectionInfo.refresh(connectionId); } - async loadDriversAsync(): Promise> { - await this.dbDrivers.load(''); - return this.dbDrivers.data; - } - async addOpenedConnection(connection: Connection) { this.connectionInfo.set(connection.id, connection); this.onOpenConnection.next(connection); diff --git a/webapp/packages/core-app/src/shared/ConnectionsManager/DBDriverResource.ts b/webapp/packages/core-app/src/shared/ConnectionsManager/DBDriverResource.ts index 5460eaf9ba..32c7d67a53 100644 --- a/webapp/packages/core-app/src/shared/ConnectionsManager/DBDriverResource.ts +++ b/webapp/packages/core-app/src/shared/ConnectionsManager/DBDriverResource.ts @@ -6,8 +6,6 @@ * you may not use this file except in compliance with the License. */ -import { observable } from 'mobx'; - import { injectable } from '@cloudbeaver/core-di'; import { GraphQLService, @@ -26,20 +24,22 @@ export type DBDriver = Pick< | 'embedded' | 'anonymousAccess' | 'promotedScore' + | 'defaultAuthModel' > @injectable() export class DBDriverResource extends CachedMapResource { - @observable private loaded = false; + constructor(private graphQLService: GraphQLService) { super(new Map()); } - isLoaded() { - return this.loaded; + async loadAll() { + await this.load('all'); + return this.data; } - protected async loader(param: string): Promise> { + protected async loader(key: string): Promise> { const { driverList } = await this.graphQLService.gql.driverList(); this.data.clear(); @@ -47,7 +47,8 @@ export class DBDriverResource extends CachedMapResource { for (const driver of driverList) { this.data.set(driver.id, driver); } - this.loaded = true; + this.data.set('all', {} as any); + this.markUpdated(key); return this.data; } } diff --git a/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/DatabaseAuthDialog.tsx b/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/DatabaseAuthDialog.tsx index 10c8dfe608..bae6576b3d 100644 --- a/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/DatabaseAuthDialog.tsx +++ b/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/DatabaseAuthDialog.tsx @@ -15,8 +15,8 @@ import { CommonDialogWrapper, DialogComponentProps } from '@cloudbeaver/core-dia import { useTranslate } from '@cloudbeaver/core-localization'; import { composes, useStyles } from '@cloudbeaver/core-theming'; +import { ObjectPropertyInfoForm } from '../../ObjectPropertyInfoForm/ObjectPropertyInfoForm'; import { useConnectionInfo } from '../useConnectionInfo'; -import { AuthForm } from './AuthForm'; import { DBAuthDialogController } from './DBAuthDialogController'; import { DBAuthDialogFooter } from './DBAuthDialogFooter'; @@ -40,14 +40,14 @@ const styles = composes( margin-top: 20px; margin-bottom: 20px; } - SubmittingForm, AuthForm { + SubmittingForm { flex: 1; display: flex; flex-direction: column; } - AuthForm { - flex-direction: column; - padding: 18px 24px; + ObjectPropertyInfoForm { + align-items: center; + justify-content: center; } ErrorMessage { position: sticky; @@ -87,10 +87,10 @@ export const DatabaseAuthDialog = observer(function DatabaseAuthDialog({ ? : ( - )} diff --git a/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/AuthForm.tsx b/webapp/packages/core-app/src/shared/ObjectPropertyInfoForm/ObjectPropertyInfoForm.tsx similarity index 76% rename from webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/AuthForm.tsx rename to webapp/packages/core-app/src/shared/ObjectPropertyInfoForm/ObjectPropertyInfoForm.tsx index b587003382..863fea332c 100644 --- a/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/AuthForm.tsx +++ b/webapp/packages/core-app/src/shared/ObjectPropertyInfoForm/ObjectPropertyInfoForm.tsx @@ -17,42 +17,44 @@ import { useStyles } from '@cloudbeaver/core-theming'; import { formStyles } from './formStyles'; type Props = { - authProperties: ObjectPropertyInfo[] | undefined; + properties: ObjectPropertyInfo[] | undefined; credentials: any; - authenticate: boolean; + processing: boolean; + className?: string; } -export const AuthForm = observer(function AuthForm({ - authProperties, +export const ObjectPropertyInfoForm = observer(function ObjectPropertyInfoForm({ + properties, credentials, - authenticate, + processing, + className, }: Props) { const handleChange = useCallback((key: string, value: string) => { credentials[key] = value; }, [credentials]); - if (!authProperties || authProperties.length === 0) { + if (!properties || properties.length === 0) { return styled(useStyles(formStyles))(
Properties empty
); } return styled(useStyles(formStyles))( - - {authProperties.map(property => ( + + {properties.map(property => ( handleChange(property.id!, value)} - disabled={authenticate} + disabled={processing} mod='surface' > {property.displayName} ))} - + ); }); diff --git a/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/formStyles.ts b/webapp/packages/core-app/src/shared/ObjectPropertyInfoForm/formStyles.ts similarity index 87% rename from webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/formStyles.ts rename to webapp/packages/core-app/src/shared/ObjectPropertyInfoForm/formStyles.ts index 73ab3fa8bc..b79de1391f 100644 --- a/webapp/packages/core-app/src/shared/ConnectionsManager/DatabaseAuthDialog/formStyles.ts +++ b/webapp/packages/core-app/src/shared/ObjectPropertyInfoForm/formStyles.ts @@ -9,13 +9,11 @@ import { css } from 'reshadow'; export const formStyles = css` - login-form { + form-body { flex: 1; box-sizing: border-box; display: flex; flex-direction: column; - align-items: center; - justify-content: center; } group { box-sizing: border-box; diff --git a/webapp/packages/core-events/src/NotificationService.ts b/webapp/packages/core-events/src/NotificationService.ts index 75974ffcb7..cf73942a60 100644 --- a/webapp/packages/core-events/src/NotificationService.ts +++ b/webapp/packages/core-events/src/NotificationService.ts @@ -67,11 +67,12 @@ export class NotificationService { this.notify(notification, ENotificationType.Error); } - logException(exception: Error, message?: string, silent?: boolean) { + logException(exception: Error | GQLError, message?: string, silent?: boolean) { + const exceptionMessage = hasDetails(exception) ? exception.errorText : exception.message || exception.name; if (!silent) { this.logError({ - title: message || exception.message || exception.name, - details: this.hasDetails(exception) ? exception : undefined, + title: message || exceptionMessage, + details: hasDetails(exception) ? exception : undefined, isSilent: silent, }); } @@ -88,8 +89,8 @@ export class NotificationService { showDetails(id: number): void { // TODO: emit event or something } +} - private hasDetails(error: Error) { - return error instanceof GQLError || error instanceof ServerInternalError; - } +function hasDetails(error: Error): error is GQLError | ServerInternalError { + return error instanceof GQLError || error instanceof ServerInternalError; } diff --git a/webapp/packages/core-sdk/src/queries/connections/dataSourceList.gql b/webapp/packages/core-sdk/src/queries/connections/dataSourceList.gql deleted file mode 100644 index 6ee8944c4f..0000000000 --- a/webapp/packages/core-sdk/src/queries/connections/dataSourceList.gql +++ /dev/null @@ -1,8 +0,0 @@ -query dataSourceList { - dataSourceList { - id - name - driverId - description - } -} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/queries/connections/openConnection.gql b/webapp/packages/core-sdk/src/queries/connections/openConnection.gql index b0146e3d23..d01deb3041 100644 --- a/webapp/packages/core-sdk/src/queries/connections/openConnection.gql +++ b/webapp/packages/core-sdk/src/queries/connections/openConnection.gql @@ -1,5 +1,5 @@ mutation openConnection($config: ConnectionConfig!) { - openConnection(config: $config) { + connection: openConnection(config: $config) { id name driverId diff --git a/webapp/packages/core-sdk/src/queries/connections/templateDataSourceList.gql b/webapp/packages/core-sdk/src/queries/connections/templateDataSourceList.gql new file mode 100644 index 0000000000..4a4fad36e8 --- /dev/null +++ b/webapp/packages/core-sdk/src/queries/connections/templateDataSourceList.gql @@ -0,0 +1,8 @@ +query templateDataSourceList { + sources: templateDataSources { + id + name + driverId + description + } +} \ No newline at end of file diff --git a/webapp/packages/core-sdk/src/sdk.ts b/webapp/packages/core-sdk/src/sdk.ts index ec1a3389ce..41fcdf5c89 100644 --- a/webapp/packages/core-sdk/src/sdk.ts +++ b/webapp/packages/core-sdk/src/sdk.ts @@ -814,10 +814,6 @@ export type CreateConnectionMutationVariables = Exact<{ export type CreateConnectionMutation = { createConnection: Pick }; -export type DataSourceListQueryVariables = Exact<{ [key: string]: never }>; - -export type DataSourceListQuery = { dataSourceList: Array> }; - export type DeleteConnectionMutationVariables = Exact<{ id: Scalars['ID']; }>; @@ -861,7 +857,11 @@ export type OpenConnectionMutationVariables = Exact<{ config: ConnectionConfig; }>; -export type OpenConnectionMutation = { openConnection: Pick }; +export type OpenConnectionMutation = { connection: Pick }; + +export type TemplateDataSourceListQueryVariables = Exact<{ [key: string]: never }>; + +export type TemplateDataSourceListQuery = { sources: Array> }; export type TestConnectionMutationVariables = Exact<{ config: ConnectionConfig; @@ -1333,16 +1333,6 @@ export const CreateConnectionDocument = ` } } `; -export const DataSourceListDocument = ` - query dataSourceList { - dataSourceList { - id - name - driverId - description - } -} - `; export const DeleteConnectionDocument = ` mutation deleteConnection($id: ID!) { deleteConnection(id: $id) @@ -1425,7 +1415,7 @@ export const InitConnectionDocument = ` `; export const OpenConnectionDocument = ` mutation openConnection($config: ConnectionConfig!) { - openConnection(config: $config) { + connection: openConnection(config: $config) { id name driverId @@ -1436,6 +1426,16 @@ export const OpenConnectionDocument = ` } } `; +export const TemplateDataSourceListDocument = ` + query templateDataSourceList { + sources: templateDataSources { + id + name + driverId + description + } +} + `; export const TestConnectionDocument = ` mutation testConnection($config: ConnectionConfig!) { testConnection(config: $config) { @@ -2002,9 +2002,6 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = createConnection(variables: CreateConnectionMutationVariables): Promise { return withWrapper(() => client.request(CreateConnectionDocument, variables)); }, - dataSourceList(variables?: DataSourceListQueryVariables): Promise { - return withWrapper(() => client.request(DataSourceListDocument, variables)); - }, deleteConnection(variables: DeleteConnectionMutationVariables): Promise { return withWrapper(() => client.request(DeleteConnectionDocument, variables)); }, @@ -2026,6 +2023,9 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = openConnection(variables: OpenConnectionMutationVariables): Promise { return withWrapper(() => client.request(OpenConnectionDocument, variables)); }, + templateDataSourceList(variables?: TemplateDataSourceListQueryVariables): Promise { + return withWrapper(() => client.request(TemplateDataSourceListDocument, variables)); + }, testConnection(variables: TestConnectionMutationVariables): Promise { return withWrapper(() => client.request(TestConnectionDocument, variables)); }, diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/ConnectionForm.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/ConnectionForm.tsx index 5f18b7ab0a..79a24bd030 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/ConnectionForm.tsx +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/ConnectionForm.tsx @@ -9,13 +9,12 @@ import { observer } from 'mobx-react'; import styled from 'reshadow'; -import { DBDriver } from '@cloudbeaver/core-app'; +import { DBDriver, ObjectPropertyInfoForm } from '@cloudbeaver/core-app'; import { Radio, InputField } from '@cloudbeaver/core-blocks'; import { useTranslate } from '@cloudbeaver/core-localization'; import { useStyles } from '@cloudbeaver/core-theming'; import { ConnectionType } from '../ConnectionFormDialogController'; -import { CredentialsForm } from './CredentialsForm'; import { formStyles } from './formStyles'; import { IFormController } from './IFormController'; import { ParametersForm } from './ParametersForm'; @@ -73,7 +72,16 @@ export const ConnectionForm = observer(function ConnectionForm({ )} - {!driver?.anonymousAccess && } + {controller.authModel && ( + <> +
+ + + )} ); }); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/CredentialsForm.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/CredentialsForm.tsx deleted file mode 100644 index eed26d515c..0000000000 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/CredentialsForm.tsx +++ /dev/null @@ -1,55 +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 styled from 'reshadow'; - -import { InputField } from '@cloudbeaver/core-blocks'; -import { useTranslate } from '@cloudbeaver/core-localization'; -import { useStyles } from '@cloudbeaver/core-theming'; - -import { formStyles } from './formStyles'; -import { IFormController } from './IFormController'; - -type CredentialsFormProps = { - controller: IFormController; -} - -export const CredentialsForm = observer(function CredentialsForm({ - controller, -}: CredentialsFormProps) { - const translate = useTranslate(); - - return styled(useStyles(formStyles))( - <> -
- - controller.onChange('userName', value)} - disabled={controller.isConnecting} - mod='surface' - > - {translate('customConnection_userName')} - - controller.onChange('userPassword', value)} - disabled={controller.isConnecting} - mod='surface' - > - {translate('customConnection_Password')} - - - - ); -}); diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/IFormController.ts b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/IFormController.ts index f2648ae5c5..35a4aafe1c 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/IFormController.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/IFormController.ts @@ -6,11 +6,12 @@ * you may not use this file except in compliance with the License. */ -import { ConnectionConfig } from '@cloudbeaver/core-sdk'; +import { ConnectionConfig, DatabaseAuthModel } from '@cloudbeaver/core-sdk'; import { ConnectionType } from '../ConnectionFormDialogController'; export interface IFormController { + authModel?: DatabaseAuthModel; config: ConnectionConfig; connectionType: ConnectionType; isConnecting: boolean; diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/formStyles.ts b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/formStyles.ts index 001af5123b..1f00a55a7c 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/formStyles.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionForm/formStyles.ts @@ -10,6 +10,8 @@ import { css } from 'reshadow'; export const formStyles = css` connection-form { + flex: 1; + display: flex; flex-direction: column; padding: 18px 24px; } diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionFormDialog.tsx b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionFormDialog.tsx index ff37d26be5..e0e9296562 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionFormDialog.tsx +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/ConnectionFormDialog/ConnectionFormDialog.tsx @@ -12,7 +12,7 @@ import styled, { css } from 'reshadow'; import { DBDriver } from '@cloudbeaver/core-app'; import { - SubmittingForm, ErrorMessage, TabsState, TabList, Tab, TabTitle, TabPanel + SubmittingForm, ErrorMessage, TabsState, TabList, Tab, TabTitle, TabPanel, Loader } from '@cloudbeaver/core-blocks'; import { useController } from '@cloudbeaver/core-di'; import { CommonDialogWrapper } from '@cloudbeaver/core-dialogs'; @@ -43,9 +43,6 @@ const styles = composes( max-height: 500px; min-height: 500px; } - SubmittingForm { - overflow: auto; - } SubmittingForm, BaseTabPanel { flex: 1; display: flex; @@ -117,18 +114,23 @@ export const ConnectionFormDialog = observer(function ConnectionFormDialog({ )} onReject={onClose} > - - - - - - - - + {controller.isLoading + ? + : ( + + + + + + + + + ) + } {controller.error.responseMessage && ( void + private onClose!: () => void; private isDistructed = false; - constructor(private customConnectionService: CustomConnectionService, + constructor( + private customConnectionService: CustomConnectionService, private notificationService: NotificationService, - private commonDialogService: CommonDialogService) { } + private commonDialogService: CommonDialogService, + private dbAuthModelsResource: DatabaseAuthModelsResource + ) { } init(driver: DBDriver, onClose: () => void) { this.driver = driver; this.onClose = onClose; + this.loadDatabaseAuthModel(); this.setDriverDefaults(); } @@ -117,9 +122,9 @@ implements IInitializableController, IDestructibleController { config.name = this.urlToConnectionName(this.config.name, this.config.url); config.url = this.config.url; } - if (!this.driver?.anonymousAccess) { - config.userName = this.config.userName; - config.userPassword = this.config.userPassword; + if (this.authModel) { + config.authModelId = this.config.authModelId; + config.credentials = this.config.credentials; } if (Object.keys(this.config.properties).length > 0) { config.properties = this.config.properties; @@ -136,9 +141,9 @@ implements IInitializableController, IDestructibleController { this.config.port = this.driver?.defaultPort || ''; this.config.databaseName = ''; this.config.url = this.driver?.sampleURL || ''; - this.config.userName = ''; - this.config.userPassword = ''; this.config.properties = {}; + this.config.authModelId = this.driver.defaultAuthModel; + this.config.credentials = {}; } /** @@ -170,4 +175,17 @@ implements IInitializableController, IDestructibleController { this.notificationService.logException(exception, message); } } + + private async loadDatabaseAuthModel() { + if (!this.driver.defaultAuthModel) { + return; + } + try { + this.authModel = await this.dbAuthModelsResource.load(this.driver.defaultAuthModel); + } catch (exception) { + this.notificationService.logException(exception, 'Can\'t load driver auth model'); + } finally { + this.isLoading = false; + } + } } diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts b/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts index f6fa6410d0..1c6d0dd3d9 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnection/CustomConnectionController.ts @@ -8,7 +8,7 @@ import { observable, computed } from 'mobx'; -import { DBDriver, ConnectionsManagerService } from '@cloudbeaver/core-app'; +import { DBDriver, DBDriverResource } from '@cloudbeaver/core-app'; import { injectable, IInitializableController } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -26,16 +26,14 @@ export class CustomConnectionController implements IInitializableController { @computed get drivers(): DBDriver[] { return Array - .from( - this.connectionsManagerService - .getDBDrivers() - .values() - ) + .from(this.dbDriverResource.data.values()) .sort((a, b) => this.sortDrivers(a, b)); } - constructor(private connectionsManagerService: ConnectionsManagerService, - private notificationService: NotificationService) { } + constructor( + private dbDriverResource: DBDriverResource, + private notificationService: NotificationService + ) { } init() { this.loadDBDrivers(); @@ -46,16 +44,14 @@ export class CustomConnectionController implements IInitializableController { } onDriverSelect = (driverId: string) => { - this.driver = this.connectionsManagerService - .getDBDrivers() - .get(driverId)!; + this.driver = this.dbDriverResource.get(driverId)!; this.step = ConnectionStep.Connection; } private async loadDBDrivers() { try { - await this.connectionsManagerService.loadDriversAsync(); + await this.dbDriverResource.loadAll(); } catch (exception) { this.notificationService.logException(exception, 'Can\'t load database drivers'); } finally { diff --git a/webapp/packages/plugin-connection-custom/src/CustomConnectionService.ts b/webapp/packages/plugin-connection-custom/src/CustomConnectionService.ts index 43e797f6a8..4b814d83aa 100644 --- a/webapp/packages/plugin-connection-custom/src/CustomConnectionService.ts +++ b/webapp/packages/plugin-connection-custom/src/CustomConnectionService.ts @@ -13,8 +13,10 @@ import { ConnectionConfig, GraphQLService, ObjectPropertyInfo } from '@cloudbeav @injectable() export class CustomConnectionService { - constructor(private graphQLService: GraphQLService, - private connectionsManagerService: ConnectionsManagerService) { + constructor( + private graphQLService: GraphQLService, + private connectionsManagerService: ConnectionsManagerService, + ) { } async loadDriverProperties(driverId: string): Promise { diff --git a/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionPluginBootstrap.ts b/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionPluginBootstrap.ts index 936dd861ec..3f9fc9cd97 100644 --- a/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionPluginBootstrap.ts +++ b/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionPluginBootstrap.ts @@ -10,10 +10,10 @@ import { MainMenuService, ConnectionDialogsService } from '@cloudbeaver/core-app import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; -import { PermissionsService, EPermission, SessionResource } from '@cloudbeaver/core-root'; +import { PermissionsService, EPermission } from '@cloudbeaver/core-root'; -import { BasicConnectionService } from './BasicConnectionService'; import { ConnectionDialog } from './ConnectionDialog/ConnectionDialog'; +import { TemplateDataSourceListResource } from './DataSourcesResource'; @injectable() export class BasicConnectionPluginBootstrap { @@ -21,17 +21,15 @@ export class BasicConnectionPluginBootstrap { constructor( private connectionDialogsService: ConnectionDialogsService, private mainMenuService: MainMenuService, - private basicConnectionService: BasicConnectionService, + private templateDataSourceListResource: TemplateDataSourceListResource, private commonDialogService: CommonDialogService, private notificationService: NotificationService, - private permissionsService: PermissionsService, - private sessionResource: SessionResource + private permissionsService: PermissionsService ) { } bootstrap() { this.loadDbSources(); - this.sessionResource.onDataUpdate.subscribe(this.loadDbSources.bind(this)); this.mainMenuService.registerMenuItem( this.connectionDialogsService.newConnectionMenuToken, { @@ -40,20 +38,21 @@ export class BasicConnectionPluginBootstrap { title: 'basicConnection_main_menu_item', onClick: () => this.openConnectionsDialog(), isHidden: () => !this.permissionsService.has(EPermission.public), - isDisabled: () => !this.basicConnectionService.dbSources.data.length, + isDisabled: () => !this.templateDataSourceListResource.data.length, } ); } private async openConnectionsDialog() { + this.loadDbSources(); await this.commonDialogService.open(ConnectionDialog, null); } private async loadDbSources() { try { - await this.basicConnectionService.dbSources.refresh(null); + await this.templateDataSourceListResource.loadAll(); } catch (error) { - this.notificationService.logException(error, 'DBSources loading failed'); + this.notificationService.logException(error, 'Template Data Sources loading failed'); } } } diff --git a/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionService.ts b/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionService.ts index c6cdb7eb21..e860b7051f 100644 --- a/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionService.ts +++ b/webapp/packages/plugin-connection-preconfigured/src/BasicConnectionService.ts @@ -6,34 +6,22 @@ * you may not use this file except in compliance with the License. */ -import { - Connection, DBSource, ConnectionsManagerService -} from '@cloudbeaver/core-app'; +import { Connection, ConnectionsManagerService } from '@cloudbeaver/core-app'; import { injectable } from '@cloudbeaver/core-di'; -import { PermissionsService } from '@cloudbeaver/core-root'; import { ConnectionConfig, GraphQLService } from '@cloudbeaver/core-sdk'; -import { DataSourcesResource } from './DataSourcesResource'; - @injectable() export class BasicConnectionService { constructor( private graphQLService: GraphQLService, - private connectionsManagerService: ConnectionsManagerService, - private permissionsService: PermissionsService, - readonly dbSources: DataSourcesResource + private connectionsManagerService: ConnectionsManagerService ) { - this.permissionsService.onUpdate.subscribe(() => this.dbSources.refresh(null)); - } - - public getDBSources(): DBSource[] { - return this.dbSources.data; } async openConnectionAsync(config: ConnectionConfig): Promise { - const response = await this.graphQLService.gql.openConnection({ config }); - this.connectionsManagerService.addOpenedConnection(response.openConnection); - return response.openConnection; + const { connection } = await this.graphQLService.gql.openConnection({ config }); + this.connectionsManagerService.addOpenedConnection(connection); + return connection; } } diff --git a/webapp/packages/plugin-connection-preconfigured/src/ConnectionDialog/ConnectionController.ts b/webapp/packages/plugin-connection-preconfigured/src/ConnectionDialog/ConnectionController.ts index f76a4ad129..8bfd3456ce 100644 --- a/webapp/packages/plugin-connection-preconfigured/src/ConnectionDialog/ConnectionController.ts +++ b/webapp/packages/plugin-connection-preconfigured/src/ConnectionDialog/ConnectionController.ts @@ -8,15 +8,14 @@ import { observable, action } from 'mobx'; -import { - ConnectionsManagerService, DBSource, ErrorDetailsDialog, -} from '@cloudbeaver/core-app'; +import { DBDriverResource, DBSource, ErrorDetailsDialog } from '@cloudbeaver/core-app'; import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { ConnectionConfig, GQLError } from '@cloudbeaver/core-sdk'; import { BasicConnectionService } from '../BasicConnectionService'; +import { TemplateDataSourceListResource } from '../DataSourcesResource'; export enum ConnectionStep { DBSource, @@ -50,11 +49,11 @@ implements IInitializableController, IDestructibleController, IConnectionControl private isDistructed = false; get dbSources() { - return this.basicConnectionService.getDBSources(); + return this.templateDataSourceListResource.data; } get dbDrivers() { - return this.connectionsManagerService.getDBDrivers(); + return this.dbDriverResource.data; } get dbDriver() { @@ -64,10 +63,13 @@ implements IInitializableController, IDestructibleController, IConnectionControl return this.dbDrivers.get(this.dbSource.driverId); } - constructor(private connectionsManagerService: ConnectionsManagerService, + constructor( + private dbDriverResource: DBDriverResource, + private templateDataSourceListResource: TemplateDataSourceListResource, private basicConnectionService: BasicConnectionService, private notificationService: NotificationService, - private commonDialogService: CommonDialogService) { } + private commonDialogService: CommonDialogService + ) { } init(onClose: () => void) { this.onClose = onClose; @@ -153,8 +155,8 @@ implements IInitializableController, IDestructibleController, IConnectionControl private async loadDBSources() { try { - await this.basicConnectionService.dbSources.load(null); - await this.connectionsManagerService.loadDriversAsync(); + await this.templateDataSourceListResource.loadAll(); + await this.dbDriverResource.loadAll(); } catch (exception) { this.notificationService.logException(exception, 'Can\'t load database sources'); } finally { diff --git a/webapp/packages/plugin-connection-preconfigured/src/DataSourcesResource.ts b/webapp/packages/plugin-connection-preconfigured/src/DataSourcesResource.ts index 7a0a538d14..337ab28d45 100644 --- a/webapp/packages/plugin-connection-preconfigured/src/DataSourcesResource.ts +++ b/webapp/packages/plugin-connection-preconfigured/src/DataSourcesResource.ts @@ -12,25 +12,36 @@ import { EPermission, PermissionsService } from '@cloudbeaver/core-root'; import { GraphQLService, CachedDataResource } from '@cloudbeaver/core-sdk'; @injectable() -export class DataSourcesResource extends CachedDataResource { +export class TemplateDataSourceListResource extends CachedDataResource { constructor( private graphQLService: GraphQLService, private permissionsService: PermissionsService ) { super([]); + this.permissionsService.onUpdate.subscribe(() => this.markOutdated(null)); } isLoaded() { return !!this.data.length; } + async loadAll() { + await this.load(null); + return this.data; + } + + async refreshAll() { + await this.refresh(null); + return this.data; + } + protected async loader(key: null): Promise { if (!await this.permissionsService.hasAsync(EPermission.public)) { this.markUpdated(key); return []; } - const { dataSourceList } = await this.graphQLService.gql.dataSourceList(); + const { sources } = await this.graphQLService.gql.templateDataSourceList(); this.markUpdated(key); - return dataSourceList; + return sources; } } diff --git a/webapp/packages/plugin-connection-preconfigured/src/manifest.ts b/webapp/packages/plugin-connection-preconfigured/src/manifest.ts index 291cb4d600..b80b7bfd38 100644 --- a/webapp/packages/plugin-connection-preconfigured/src/manifest.ts +++ b/webapp/packages/plugin-connection-preconfigured/src/manifest.ts @@ -10,7 +10,7 @@ import { PluginManifest } from '@cloudbeaver/core-di'; import { BasicConnectionPluginBootstrap } from './BasicConnectionPluginBootstrap'; import { BasicConnectionService } from './BasicConnectionService'; -import { DataSourcesResource } from './DataSourcesResource'; +import { TemplateDataSourceListResource } from './DataSourcesResource'; import { LocaleService } from './LocaleService'; export const basicConnectionPluginManifest: PluginManifest = { @@ -20,7 +20,7 @@ export const basicConnectionPluginManifest: PluginManifest = { providers: [ BasicConnectionService, - DataSourcesResource, + TemplateDataSourceListResource, LocaleService, ], diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorNavigatorService.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorNavigatorService.ts index d0a2e83a72..0834ec6a8f 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorNavigatorService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorNavigatorService.ts @@ -14,6 +14,7 @@ import { NavigationService, IContextProvider, ITabOptions, + ConnectionAuthService, } from '@cloudbeaver/core-app'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -60,7 +61,8 @@ export class SqlEditorNavigatorService { private notificationService: NotificationService, private gql: GraphQLService, private sqlDialectInfoService: SqlDialectInfoService, - private navigationService: NavigationService + private navigationService: NavigationService, + private connectionAuthService: ConnectionAuthService ) { this.navigator = this.navigationService.createNavigator( @@ -164,6 +166,12 @@ export class SqlEditorNavigatorService { connectionId = this.connectionsManagerService.connections[0].id; } + const connection = await this.connectionAuthService.auth(connectionId); + + if (!connection?.connected) { + return null; + } + await this.sqlDialectInfoService.loadSqlDialectInfo(connectionId); const context = await this.createSqlContext(connectionId, catalogId, schemaId); diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorTabService.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorTabService.ts index 6f901e599c..e59140f62b 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorTabService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorTabService.ts @@ -17,6 +17,7 @@ import { objectCatalogProvider, objectCatalogSetter, objectSchemaSetter, + ConnectionAuthService, } from '@cloudbeaver/core-app'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; @@ -34,11 +35,14 @@ import { SqlExecutionState } from './SqlExecutionState'; export class SqlEditorTabService { readonly tabHandler: TabHandler - constructor(private navigationTabsService: NavigationTabsService, - private connectionsManagerService: ConnectionsManagerService, - private notificationService: NotificationService, - private gql: GraphQLService, - private sqlDialectInfoService: SqlDialectInfoService) { + constructor( + private navigationTabsService: NavigationTabsService, + private connectionsManagerService: ConnectionsManagerService, + private notificationService: NotificationService, + private gql: GraphQLService, + private sqlDialectInfoService: SqlDialectInfoService, + private connectionAuthService: ConnectionAuthService + ) { this.tabHandler = this.navigationTabsService .registerTabHandler({ @@ -102,6 +106,13 @@ export class SqlEditorTabService { private async setConnectionId(connectionId: string, tab: ITab) { try { + + const connection = await this.connectionAuthService.auth(connectionId); + + if (!connection?.connected) { + return false; + } + // try to create new context first const context = await this.createSqlContext(connectionId); // when new context created - destroy old one silently