diff --git a/webapp/packages/core-connections/src/ConnectionInfoResource.ts b/webapp/packages/core-connections/src/ConnectionInfoResource.ts index 390ccf6bb3..e65e306170 100644 --- a/webapp/packages/core-connections/src/ConnectionInfoResource.ts +++ b/webapp/packages/core-connections/src/ConnectionInfoResource.ts @@ -1,10 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 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 { action, makeObservable, observable, runInAction, toJS } from 'mobx'; import { AppAuthService, UserInfoResource } from '@cloudbeaver/core-authentication'; @@ -269,13 +270,6 @@ export class ConnectionInfoResource extends CachedMapResource): boolean; isConnecting(key: ResourceKey): boolean; diff --git a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts index 84a1b67358..54c7c8463f 100644 --- a/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts +++ b/webapp/packages/plugin-connection-search/src/Search/ConnectionSearchService.ts @@ -1,11 +1,12 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 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 { makeObservable, observable } from 'mobx'; + +import { makeObservable, observable, runInAction } from 'mobx'; import { ConfirmationDialog } from '@cloudbeaver/core-blocks'; import { ConnectionInfoResource, ConnectionsManagerService, createConnectionParam } from '@cloudbeaver/core-connections'; @@ -15,7 +16,7 @@ import { NotificationService } from '@cloudbeaver/core-events'; import { ExecutorInterrupter, type IExecutorHandler } from '@cloudbeaver/core-executor'; import type { AdminConnectionSearchInfo } from '@cloudbeaver/core-sdk'; import { OptionsPanelService } from '@cloudbeaver/core-ui'; -import { ConnectionFormService, ConnectionFormState } from '@cloudbeaver/plugin-connections'; +import { ConnectionFormService, ConnectionFormState, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections'; import { SearchDatabase } from './SearchDatabase.js'; @@ -102,13 +103,17 @@ export class ConnectionSearchService { this.close(); }; + get optionsPart() { + return this.formState ? getConnectionFormOptionsPart(this.formState) : null; + } + private async showUnsavedChangesDialog(): Promise { if ( !this.formState || !this.optionsPanelService.isOpen(formGetter) || - (this.formState.state.config.connectionId && + (this.optionsPart?.state.connectionId && this.formState.state.projectId !== null && - !this.connectionInfoResource.has(createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId))) + !this.connectionInfoResource.has(createConnectionParam(this.formState.state.projectId, this.optionsPart.state.connectionId))) ) { return true; } @@ -148,18 +153,19 @@ export class ConnectionSearchService { if (!this.formState) { this.formState = new ConnectionFormState(this.serviceProvider, this.connectionFormService, { - config: { - ...this.connectionInfoResource.getEmptyConfig(), - host: database.host, - port: String(database.port), - driverId: database.defaultDriver, - }, submitType: null, projectId: projects[0]!.id, availableDrivers: database.possibleDrivers, type: 'public', requiredNetworkHandlersIds: [], }); + + runInAction(() => { + this.optionsPart!.state.host = database.host; + this.optionsPart!.state.port = String(database.port); + this.optionsPart!.state.driverId = database.defaultDriver; + }); + this.formState.disposeTask.addHandler(this.goBack.bind(this)); } } diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx index 173385be73..25e0fe02f7 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/ConnectionsTable/ConnectionEdit.tsx @@ -1,15 +1,16 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + import { observer } from 'mobx-react-lite'; import { Loader, s, useS } from '@cloudbeaver/core-blocks'; import { type IConnectionInfoParams } from '@cloudbeaver/core-connections'; -import { ConnectionFormLoader, useConnectionFormState } from '@cloudbeaver/plugin-connections'; +import { ConnectionFormLoader, getConnectionFormOptionsPart, useConnectionFormState } from '@cloudbeaver/plugin-connections'; import styles from './ConnectionEdit.module.css'; import { FormMode } from '@cloudbeaver/core-ui'; @@ -22,9 +23,10 @@ interface Props { export const ConnectionEdit = observer(function ConnectionEditNew({ item }) { const data = useConnectionFormState(item, state => { state.setMode(FormMode.Edit); + const optionsPart = getConnectionFormOptionsPart(state); runInAction(() => { - state.state.config.connectionId = item.connectionId; + optionsPart.state.connectionId = item.connectionId; state.state.projectId = item.projectId; state.state.type = 'admin'; }); diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx index 8f5e41b2ec..acaacd7071 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/CreateConnection.tsx @@ -1,10 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + import { observer } from 'mobx-react-lite'; import { @@ -25,7 +26,7 @@ import { import { DBDriverResource } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { TabListStyles, TabPanelList, TabPanelStyles, TabsState, TabStyles } from '@cloudbeaver/core-ui'; -import { ConnectionFormLoader } from '@cloudbeaver/plugin-connections'; +import { ConnectionFormLoader, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections'; import { CreateConnectionService } from '../CreateConnectionService.js'; import styles from './shared/CreateConnection.module.css'; @@ -48,7 +49,8 @@ export const CreateConnection = observer(function CreateConnection({ meth const style = useS(styles); const createConnectionService = useService(CreateConnectionService); const translate = useTranslate(); - const driver = useResource(CreateConnection, DBDriverResource, createConnectionService.data?.state.config.driverId || null); + const optionsPart = createConnectionService.data ? getConnectionFormOptionsPart(createConnectionService.data) : null; + const driver = useResource(CreateConnection, DBDriverResource, optionsPart?.state.driverId || null); if (createConnectionService.data) { return ( diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts index 8b51edd2f6..9d9af6f50c 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnection/Manual/ConnectionManualService.ts @@ -1,11 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 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 { ConnectionInfoResource } from '@cloudbeaver/core-connections'; + import { injectable } from '@cloudbeaver/core-di'; import { CreateConnectionService } from '../../CreateConnectionService.js'; @@ -20,7 +20,7 @@ export class ConnectionManualService { this.createConnectionService.disabled = value; } - constructor(private readonly connectionInfoResource: ConnectionInfoResource, private readonly createConnectionService: CreateConnectionService) { + constructor(private readonly createConnectionService: CreateConnectionService) { this.select = this.select.bind(this); } @@ -28,7 +28,6 @@ export class ConnectionManualService { this.createConnectionService.setConnectionTemplate( projectId, { - ...this.connectionInfoResource.getEmptyConfig(), template: true, driverId, }, diff --git a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts index 2b4d637c68..a40e299830 100644 --- a/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts +++ b/webapp/packages/plugin-connections-administration/src/Administration/Connections/CreateConnectionService.ts @@ -5,13 +5,13 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { action, makeObservable, observable } from 'mobx'; +import { action, makeObservable, observable, runInAction } from 'mobx'; import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { injectable, IServiceProvider } from '@cloudbeaver/core-di'; import type { ConnectionConfig } from '@cloudbeaver/core-sdk'; import { TabsContainer } from '@cloudbeaver/core-ui'; -import { ConnectionFormService, ConnectionFormState } from '@cloudbeaver/plugin-connections'; +import { ConnectionFormService, ConnectionFormState, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections'; import { ConnectionsAdministrationNavService } from './ConnectionsAdministrationNavService.js'; @@ -104,16 +104,26 @@ export class CreateConnectionService { this.activateMethod(defaultId); } + get optionsPart() { + return this.data ? getConnectionFormOptionsPart(this.data) : null; + } + setConnectionTemplate(projectId: string, config: ConnectionConfig, availableDrivers: string[]): void { this.data?.dispose(); this.data = new ConnectionFormState(this.serviceProvider, this.connectionFormService, { projectId, availableDrivers, - config, submitType: null, type: 'admin', requiredNetworkHandlersIds: [], }); + + runInAction(() => { + this.optionsPart!.state = { + ...this.optionsPart!.state, + ...config, + }; + }); this.data.disposeTask.addHandler(this.cancelCreate.bind(this)); } diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx index 3ea1511c05..f910a4535f 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccess.tsx @@ -5,6 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useMemo, useState } from 'react'; @@ -29,11 +30,10 @@ import type { TLocalizationToken } from '@cloudbeaver/core-localization'; import { CachedMapAllKey, CachedResourceOffsetPageListKey } from '@cloudbeaver/core-resource'; import { FormMode, type TabContainerPanelComponent, useTab } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '@cloudbeaver/plugin-connections'; - +import { getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections'; import styles from './ConnectionAccess.module.css'; import { ConnectionAccessGrantedList } from './ConnectionAccessGrantedList.js'; import { ConnectionAccessList } from './ConnectionAccessList.js'; -import { useService } from '@cloudbeaver/core-di'; import { getConnectionFormAccessPart } from './getConnectionFormAccessPart.js'; export const ConnectionAccess: TabContainerPanelComponent = observer(function ConnectionAccess({ tabId, formState }) { @@ -74,14 +74,12 @@ export const ConnectionAccess: TabContainerPanelComponent [accessPart.state, teams.resource], ); - if (!selected) { - return null; - } - - const connectionInfoService = useService(ConnectionInfoResource); - const originInfoService = useService(ConnectionInfoOriginResource); - const connectionInfo = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); - const originInfo = originInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); + const optionsPart = getConnectionFormOptionsPart(formState); + const key = createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!); + const connectionInfoResource = useResource(ConnectionAccess, ConnectionInfoResource, key); + const originInfoResource = useResource(ConnectionAccess, ConnectionInfoOriginResource, key); + const connectionInfo = connectionInfoResource.data; + const originInfo = originInfoResource.data; const loading = users.isLoading() || teams.isLoading() || accessPart.isLoading(); const cloud = connectionInfo && originInfo?.origin ? isCloudConnection(originInfo.origin) : false; const disabled = loading || !accessPart.isLoaded() || formState.isDisabled || cloud; @@ -93,6 +91,10 @@ export const ConnectionAccess: TabContainerPanelComponent info = 'cloud_connections_access_placeholder'; } + if (!selected) { + return null; + } + return ( {() => ( diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts index 26c9bb055b..22f831c8d0 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionAccessTabService.ts @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -11,7 +11,7 @@ import { AdministrationScreenService } from '@cloudbeaver/core-administration'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { isGlobalProject, ProjectInfoResource } from '@cloudbeaver/core-projects'; import { EAdminPermission, PermissionsService } from '@cloudbeaver/core-root'; -import { ConnectionFormService } from '@cloudbeaver/plugin-connections'; +import { ConnectionFormService, getConnectionFormOptionsPart } from '@cloudbeaver/plugin-connections'; import { getConnectionFormAccessPart } from './getConnectionFormAccessPart.js'; const ConnectionAccess = React.lazy(async () => { @@ -41,7 +41,11 @@ export class ConnectionAccessTabService extends Bootstrap { order: 4, stateGetter: context => () => getConnectionFormAccessPart(context.formState), isHidden: (_, context) => !context || !this.isAccessTabActive(context.formState.state.projectId), - isDisabled: (tabId, props) => !props?.formState.state.config.driverId || this.administrationScreenService.isConfigurationMode, + isDisabled: (tabId, props) => { + const optionsPart = props?.formState ? getConnectionFormOptionsPart(props.formState) : null; + + return !optionsPart?.state.driverId || this.administrationScreenService.isConfigurationMode; + }, panel: () => ConnectionAccess, }); } diff --git a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionFormAccessPart.ts b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionFormAccessPart.ts index 0068c3efc9..e83e9fb671 100644 --- a/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionFormAccessPart.ts +++ b/webapp/packages/plugin-connections-administration/src/ConnectionForm/ConnectionAccess/ConnectionFormAccessPart.ts @@ -9,7 +9,7 @@ import { FormPart, formStatusContext, type IFormState } from '@cloudbeaver/core- import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { createConnectionParam, type ConnectionInfoResource } from '@cloudbeaver/core-connections'; import { action, makeObservable } from 'mobx'; -import type { IConnectionFormState } from '@cloudbeaver/plugin-connections'; +import { getConnectionFormOptionsPart, type IConnectionFormState } from '@cloudbeaver/plugin-connections'; import { getSubjectDifferences } from '@cloudbeaver/core-utils'; function getDefaultState(): string[] { @@ -29,21 +29,9 @@ export class ConnectionFormAccessPart extends FormPart { - const connectionId = this.formState.state.config.connectionId; + const optionsPart = getConnectionFormOptionsPart(this.formState); + const connectionId = optionsPart.state.connectionId; const projectId = this.formState.state.projectId; if (!connectionId || !projectId) { @@ -62,7 +50,8 @@ export class ConnectionFormAccessPart extends FormPart>, ): Promise { const status = contexts.getContext(formStatusContext); - const connectionId = this.formState.state.config.connectionId; + const optionsPart = getConnectionFormOptionsPart(this.formState); + const connectionId = optionsPart.state.connectionId; if (this.formState.state.submitType === 'test' || !data.state.projectId || !status.saved || !connectionId || !this.loaded) { return; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx index 392725606e..01c1eae82c 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionForm.tsx @@ -19,6 +19,7 @@ import type { ConnectionFormState } from './ConnectionFormState.js'; import { getFirstException } from '@cloudbeaver/core-utils'; import { ConnectionFormService } from './ConnectionFormService.js'; import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections'; +import { getConnectionFormOptionsPart } from './Options/getConnectionFormOptionsPart.js'; export interface ConnectionFormProps { formState: ConnectionFormState; @@ -41,7 +42,8 @@ export const ConnectionForm = observer(function ConnectionF const initialMode = formState.mode; const saved = await formState.save(); - const info = connectionInfoResource.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); + const optionsPart = getConnectionFormOptionsPart(formState); + const info = connectionInfoResource.get(createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!)); if (saved) { if (formState.state.submitType === 'submit') { @@ -75,9 +77,10 @@ export const ConnectionForm = observer(function ConnectionF function save(data, contexts) { const validation = contexts.getContext(formValidationContext); const state = contexts.getContext(formStatusContext); + const optionsPart = getConnectionFormOptionsPart(data); if (validation.valid && state.saved && data.state.submitType === 'submit') { - props.onSave(data.state.config); + props.onSave(optionsPart.state); } }, ], diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx index 37070c6d04..8bbd51ac4d 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormBaseActions.tsx @@ -1,10 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + import { observer } from 'mobx-react-lite'; import { useContext } from 'react'; @@ -16,7 +17,7 @@ import { ServerConfigResource } from '@cloudbeaver/core-root'; import { ConnectionFormActionsContext } from './ConnectFormActionsContext.js'; import type { IConnectionFormProps } from './IConnectionFormState.js'; import { useService } from '@cloudbeaver/core-di'; - +import { getConnectionFormOptionsPart } from './Options/getConnectionFormOptionsPart.js'; export const ConnectionFormBaseActions: PlaceholderComponent = observer(function ConnectionFormBaseActions({ formState }) { const actions = useContext(ConnectionFormActionsContext); @@ -25,24 +26,25 @@ export const ConnectionFormBaseActions: PlaceholderComponent formState.state.config.authModelId || info?.authModel || driver?.defaultAuthModel || null), + getComputed(() => optionsPart.state.authModelId || info?.authModel || driver?.defaultAuthModel || null), ); const authentication = useAuthenticationAction({ providerId: authModel?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID, }); const authorized = authentication.providerId === AUTH_PROVIDER_LOCAL_ID || authentication.authorized; - const disableTest = serverConfigResource.data?.distributed && !!formState.state.config.sharedCredentials; + const disableTest = serverConfigResource.data?.distributed && !!optionsPart.state.sharedCredentials; return ( <> diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts index e4ff93a48e..011448ae8b 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/ConnectionFormState.ts @@ -10,52 +10,45 @@ import { FormState } from '@cloudbeaver/core-ui'; import { ConnectionFormService } from './ConnectionFormService.js'; import type { IConnectionFormState } from './IConnectionFormState.js'; -import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects'; -import { ConnectionInfoResource, createConnectionParam, type IConnectionInfoParams } from '@cloudbeaver/core-connections'; -import type { ResourceKeySimple } from '@cloudbeaver/core-resource'; export class ConnectionFormState extends FormState { - constructor( - private readonly serviceProvider: IServiceProvider, - service: ConnectionFormService, - config: IConnectionFormState, - ) { + constructor(serviceProvider: IServiceProvider, service: ConnectionFormService, config: IConnectionFormState) { super(serviceProvider, service, config); - const projectInfoResource = serviceProvider.getService(ProjectInfoResource); - const projectsService = serviceProvider.getService(ProjectsService); - const resource = serviceProvider.getService(ConnectionInfoResource); + // const projectInfoResource = serviceProvider.getService(ProjectInfoResource); + // const projectsService = serviceProvider.getService(ProjectsService); + // const resource = serviceProvider.getService(ConnectionInfoResource); - resource.onItemUpdate.removeHandler(this.syncInfo.bind(this)); - projectInfoResource.onDataUpdate.removeHandler(this.syncProject.bind(this)); - projectsService.onActiveProjectChange.removeHandler(this.syncProject.bind(this)); + // resource.onItemUpdate.removeHandler(this.syncInfo.bind(this)); + // projectInfoResource.onDataUpdate.removeHandler(this.syncProject.bind(this)); + // projectsService.onActiveProjectChange.removeHandler(this.syncProject.bind(this)); } - private async syncInfo(key: ResourceKeySimple) { - const resource = this.serviceProvider.getService(ConnectionInfoResource); + // private async syncInfo(key: ResourceKeySimple) { + // const resource = this.serviceProvider.getService(ConnectionInfoResource); - if ( - !this.state.config.connectionId || - this.state.projectId === null || - !resource.isIntersect(key, createConnectionParam(this.state.projectId, this.state.config.connectionId)) - ) { - return; - } + // if ( + // !this.state.config.connectionId || + // this.state.projectId === null || + // !resource.isIntersect(key, createConnectionParam(this.state.projectId, this.state.config.connectionId)) + // ) { + // return; + // } - await this.reload(); - } + // await this.reload(); + // } - private async syncProject() { - if (!this.state.projectId) { - return; - } + // private async syncProject() { + // if (!this.state.projectId) { + // return; + // } - const projectInfoResource = this.serviceProvider.getService(ProjectInfoResource); - const projectsService = this.serviceProvider.getService(ProjectsService); + // const projectInfoResource = this.serviceProvider.getService(ProjectInfoResource); + // const projectsService = this.serviceProvider.getService(ProjectsService); - const project = projectInfoResource.get(this.state.projectId); - if (!project?.canEditDataSources || !projectsService.activeProjects.includes(project)) { - await this.dispose(); - } - } + // const project = projectInfoResource.get(this.state.projectId); + // if (!project?.canEditDataSources || !projectsService.activeProjects.includes(project)) { + // await this.dispose(); + // } + // } } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts index 7dc87f7a44..2693421d14 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts @@ -1,15 +1,15 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 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 { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { DriverPropertiesLoader } from './DriverPropertiesLoader.js'; import { ConnectionFormService } from '../ConnectionFormService.js'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; @injectable() export class ConnectionDriverPropertiesTabService extends Bootstrap { @@ -25,9 +25,12 @@ export class ConnectionDriverPropertiesTabService extends Bootstrap { order: 2, panel: () => DriverPropertiesLoader, isDisabled: (tabId, props) => { - if (props?.formState.state.config.driverId) { - return !props.formState.state.config.driverId; + const optionsPart = props?.formState ? getConnectionFormOptionsPart(props.formState) : null; + + if (optionsPart?.state.driverId) { + return false; } + return true; }, }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionFormDriverPropertiesPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionFormDriverPropertiesPart.ts index b66cf0719c..c774977462 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionFormDriverPropertiesPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/ConnectionFormDriverPropertiesPart.ts @@ -10,6 +10,8 @@ import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections'; import type { IConnectionFormState } from '../IConnectionFormState.js'; import type { IConnectionProperties } from '../Options/IConnectionConfig.js'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; +import { runInAction } from 'mobx'; function getDefaultState(): IConnectionProperties { return {}; @@ -23,19 +25,17 @@ export class ConnectionFormDriverPropertiesPart extends FormPart { - if (!this.formState.state.config.connectionId || !this.formState.state.projectId) { + if (!this.optionsPart.state.connectionId || !this.formState.state.projectId) { this.setInitialState(getDefaultState()); return; } - const connection = this.connectionInfoResource.get( - createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId), - ); + const connection = this.connectionInfoResource.get(createConnectionParam(this.formState.state.projectId, this.optionsPart.state.connectionId!)); if (connection?.properties) { this.setInitialState({ ...connection.properties }); @@ -59,5 +59,14 @@ export class ConnectionFormDriverPropertiesPart extends FormPart { + optionsPart.state.properties = { + ...optionsPart.state.properties, + ...this.state, + }; + }); } } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx index fa3ce81b73..8aaf76ec0e 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/DriverProperties/DriverProperties.tsx @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -17,12 +17,13 @@ import { uuid } from '@cloudbeaver/core-utils'; import styles from './DriverProperties.module.css'; import { getConnectionFormDriverPropertiesPart } from './getConnectionFormDriverPropertiesPart.js'; import type { IConnectionFormProps } from '../IConnectionFormState.js'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; export const DriverProperties: TabContainerPanelComponent = observer(function DriverProperties({ tabId, formState }) { const { selected } = useTab(tabId); const style = useS(styles); const driverPropertiesPart = getConnectionFormDriverPropertiesPart(formState); - + const optionsPart = getConnectionFormOptionsPart(formState); const [state] = useState(() => { const propertiesList: IProperty[] = observable([]); @@ -44,7 +45,7 @@ export const DriverProperties: TabContainerPanelComponent }); const driver = useResource(DriverProperties, DBDriverResource, { - key: (selected && formState.state.config.driverId) || null, + key: (selected && optionsPart.state.driverId) || null, includes: ['includeDriverProperties'] as const, }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormState.ts index 154afcc34c..d186b48647 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/IConnectionFormState.ts @@ -7,13 +7,11 @@ */ import { schema } from '@cloudbeaver/core-utils'; -import { CONNECTION_CONFIG_SCHEMA } from './Options/IConnectionConfig.js'; import type { IFormProps } from '@cloudbeaver/core-ui'; export const CONNECTION_FORM_STATE_SCHEMA = schema .object({ projectId: schema.string(), - config: CONNECTION_CONFIG_SCHEMA, submitType: schema.enum(['submit', 'test']).nullable(), availableDrivers: schema.array(schema.string()), requiredNetworkHandlersIds: schema.array(schema.string()), diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOpitonsPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOpitonsPart.ts index b3ecbc92a5..7a7a37a4ca 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOpitonsPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/ConnectionFormOpitonsPart.ts @@ -6,7 +6,13 @@ * you may not use this file except in compliance with the License. */ import { FormMode, FormPart, formStateContext, formValidationContext, type IFormState } from '@cloudbeaver/core-ui'; -import { DriverConfigurationType, type ConnectionConfig, type ObjectPropertyInfo, type TestConnectionMutation } from '@cloudbeaver/core-sdk'; +import { + DriverConfigurationType, + type ConnectionConfig, + type DatabaseAuthModel, + type ObjectPropertyInfo, + type TestConnectionMutation, +} from '@cloudbeaver/core-sdk'; import { ExecutorInterrupter, type IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { ConnectionInfoProjectKey, @@ -16,6 +22,7 @@ import { DBDriverResource, isJDBCConnection, type DatabaseConnection, + type DBDriver, } from '@cloudbeaver/core-connections'; import type { ProjectInfoResource } from '@cloudbeaver/core-projects'; import { AUTH_PROVIDER_LOCAL_ID, AuthProvidersResource, UserInfoResource } from '@cloudbeaver/core-authentication'; @@ -40,6 +47,7 @@ const defaultStateGetter = () => configurationType: DriverConfigurationType.Manual, keepAliveInterval: 0, credentials: {}, + template: false, mainPropertyValues: {}, networkHandlersConfig: [], saveCredentials: false, @@ -66,19 +74,15 @@ export class ConnectionFormOptionsPart extends FormPart, contexts: IExecutionContextProvider>) { const stateContext = contexts.getContext(formStateContext); - const info = this.connectionInfoResource.get(createConnectionParam(data.state.projectId, data.state.config.connectionId!)); + const info = this.connectionInfoResource.get(createConnectionParam(data.state.projectId, this.state.connectionId!)); - if (!this.formState.state.config.driverId || !this.formState.state.projectId) { + if (!this.state.driverId || !this.formState.state.projectId) { return; } - const driver = await this.dbDriverResource.load(this.formState.state.config.driverId, ['includeProviderProperties', 'includeMainProperties']); + const driver = await this.dbDriverResource.load(this.state.driverId, ['includeProviderProperties', 'includeMainProperties']); const [authModel] = await Promise.all([this.databaseAuthModelsResource.load(driver.defaultAuthModel), this.userInfoResource.load()]); const providerId = authModel.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; @@ -93,22 +97,19 @@ export class ConnectionFormOptionsPart extends FormPart, contexts: IExecutionContextProvider>) { - if ( - this.formState.state.submitType !== 'test' || - (!this.formState.state.config.authModelId && !this.formState.state.requiredNetworkHandlersIds.length) - ) { + if (this.formState.state.submitType !== 'test' || (!this.state.authModelId && !this.formState.state.requiredNetworkHandlersIds.length)) { return; } runInAction(() => { - if (this.formState.state.config.authModelId) { + if (this.state.authModelId) { this.state.credentials = observable(this.state.credentials!); } }); const result = await this.commonDialogService.open(ConnectionAuthenticationDialogLoader, { config: this.state, - authModelId: this.formState.state.config.authModelId ?? null, + authModelId: this.state.authModelId ?? null, networkHandlers: this.formState.state.requiredNetworkHandlersIds, projectId: data.state.projectId, }); @@ -120,30 +121,28 @@ export class ConnectionFormOptionsPart extends FormPart { if (this.formState.mode === 'create') { - await this.setDefaults(); + const defaults = await this.getDefaults(); + this.setInitialState({ - ...defaultStateGetter(), - ...this.formState.state.config, + ...defaults, + ...this.state, }); return; } - if (!this.formState.state.config.connectionId || !this.formState.state.projectId) { + if (!this.state.connectionId || !this.formState.state.projectId) { console.error('Connection id and project id should be defined'); return; } - const info = await this.connectionInfoResource.load( - createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId), - [ - 'includeAuthProperties', - 'includeCredentialsSaved', - 'customIncludeOptions', - 'includeProperties', - 'includeProviderProperties', - 'includeNetworkHandlersConfig', - ], - ); + const info = await this.connectionInfoResource.load(createConnectionParam(this.formState.state.projectId, this.state.connectionId), [ + 'includeAuthProperties', + 'includeCredentialsSaved', + 'customIncludeOptions', + 'includeProperties', + 'includeProviderProperties', + 'includeNetworkHandlersConfig', + ]); const config: ConnectionConfig = defaultStateGetter(); @@ -188,55 +187,97 @@ export class ConnectionFormOptionsPart extends FormPart { + const info = this.connectionInfoResource.get(createConnectionParam(this.formState.state.projectId, this.state.connectionId!)); + if (isJDBCConnection(driver, info)) { + this.state.name = this.state.url || ''; + return; + } + + if (!driver) { + this.state.name = 'New connection'; + return; + } + + const name = getConnectionName(driver.name || '', this.state.host, this.state.port, driver.defaultPort); + + this.state.name = name; + }); + } + + setAuthModel(model: DatabaseAuthModel) { + this.state.credentials = {}; + const info = this.connectionInfoResource.get(createConnectionParam(this.formState.state.projectId, this.state.connectionId!)); + + if (model.id === info?.authModel) { + if (info.authProperties) { + for (const property of info.authProperties) { + if (!property.features.includes('password')) { + this.state.credentials[property.id!] = property.value; + } + } + } } - const driver = await this.dbDriverResource.load(this.formState.state.config.driverId, ['includeProviderProperties']); + this.state.authModelId = model.id; + } - this.formState.state.config.authModelId = driver?.defaultAuthModel; - this.formState.state.config.configurationType = getDefaultConfigurationType(driver); + private async getDefaults() { + const config = defaultStateGetter(); - if (!this.formState.state.config.host) { - this.formState.state.config.host = driver?.defaultServer || 'localhost'; + if (!this.state.driverId) { + config.name = 'New connection'; + return config; } - if (!this.formState.state.config.port) { - this.formState.state.config.port = driver?.defaultPort; + const driver = await this.dbDriverResource.load(this.state.driverId, ['includeProviderProperties']); + + config.authModelId = driver?.defaultAuthModel; + config.configurationType = getDefaultConfigurationType(driver); + + if (!this.state.host) { + config.host = driver?.defaultServer || 'localhost'; } - this.formState.state.config.databaseName = driver?.defaultDatabase; - this.formState.state.config.url = driver?.sampleURL; + if (!this.state.port) { + config.port = driver?.defaultPort; + } + + config.databaseName = driver?.defaultDatabase; + config.url = driver?.sampleURL; if (isJDBCConnection(driver)) { - this.formState.state.config.name = this.formState.state.config.url; + config.name = config.url; } else { - this.formState.state.config.name = getConnectionName( - driver.name || '', - this.formState.state.config.host, - this.formState.state.config.port, - driver.defaultPort, - ); + config.name = getConnectionName(driver.name || '', config.host, config.port, driver.defaultPort); } + + return config; } protected override async format( data: IFormState, contexts: IExecutionContextProvider>, ): Promise { - if (!this.formState.state.config.driverId || !this.formState.state.projectId) { + if (!this.state.driverId || !this.formState.state.projectId) { return; } - const driver = await this.dbDriverResource.load(this.formState.state.config.driverId, ['includeProviderProperties', 'includeMainProperties']); + const driver = await this.dbDriverResource.load(this.state.driverId, ['includeProviderProperties', 'includeMainProperties']); if (this.formState.mode === 'edit') { - this.state.connectionId = this.formState.state.config.connectionId; + this.state.connectionId = this.state.connectionId; } this.formState.state.requiredNetworkHandlersIds = observable([]); @@ -278,21 +319,15 @@ export class ConnectionFormOptionsPart extends FormPart 0) { @@ -388,13 +423,10 @@ export class ConnectionFormOptionsPart extends FormPart; export type IConnectionProperties = schema.infer; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx index 6a607da07f..a103f0c9aa 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/Options/Options.tsx @@ -60,9 +60,9 @@ import { AdvancedPropertiesForm } from './AdvancedPropertiesForm.js'; import styles from './Options.module.css'; import { ParametersForm } from './ParametersForm.js'; import { ProviderPropertiesForm } from './ProviderPropertiesForm.js'; -import { useOptions } from './useOptions.js'; import { getConnectionFormOptionsPart } from './getConnectionFormOptionsPart.js'; import type { IConnectionFormProps } from '../IConnectionFormState.js'; +import { runInAction } from 'mobx'; const PROFILE_AUTH_MODEL_ID = 'profile'; @@ -97,39 +97,32 @@ export const Options: TabContainerPanelComponent = observe const isSharedProject = projectInfoResource.isProjectShared(formState.state.projectId); const connectionInfoService = useService(ConnectionInfoResource); const connectionInfoOriginResource = useService(ConnectionInfoOriginResource); - const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); - const originInfo = connectionInfoOriginResource.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); const optionsPart = getConnectionFormOptionsPart(formState); - const config = optionsPart.state; + const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!)); + const key = createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!); + const originInfo = key ? connectionInfoOriginResource.get(key) : null; //@TODO it's here until the profile implementation in the CloudBeaver const readonly = formState.isDisabled || info?.authModel === PROFILE_AUTH_MODEL_ID; useFormValidator(formState.validationTask, formRef.current); - const optionsHook = useOptions(formState, optionsPart.state); const { credentialsSavingEnabled } = useAdministrationSettings(); - const driverMap = useResource( - Options, - DBDriverResource, - { key: formState.state.config.driverId || config.driverId || null, includes: ['includeProviderProperties', 'includeMainProperties'] as const }, - { - onData: data => { - optionsHook.setDefaults(data); - }, - }, - ); + const driverMap = useResource(Options, DBDriverResource, { + key: optionsPart.state.driverId || null, + includes: ['includeProviderProperties', 'includeMainProperties'] as const, + }); const driver = driverMap.data; const configurationTypes = driverConfiguration.filter(configuration => driver && configuration.isVisible(driver)); function handleFormChange(value?: unknown, name?: string) { - if (name !== 'name' && optionsHook.isNameAutoFill()) { - optionsHook.updateNameTemplate(driver); + if (name !== 'name' && optionsPart.isNameAutoFill()) { + optionsPart.updateNameTemplate(driver); } - if (config.template) { - config.folder = undefined; + if (optionsPart.state.template) { + optionsPart.state.folder = undefined; } } @@ -138,9 +131,9 @@ export const Options: TabContainerPanelComponent = observe const authModelLoader = useResource( Options, DatabaseAuthModelsResource, - getComputed(() => config.authModelId || info?.authModel || driver?.defaultAuthModel || null), + getComputed(() => optionsPart.state.authModelId || info?.authModel || driver?.defaultAuthModel || null), { - onData: optionsHook.setAuthModel, + onData: optionsPart.setAuthModel.bind(optionsPart), }, ); @@ -157,7 +150,7 @@ export const Options: TabContainerPanelComponent = observe return; } - await optionsHook.setAuthModel(model); + optionsPart.setAuthModel(model); } const authentication = useAuthenticationAction({ @@ -181,11 +174,11 @@ export const Options: TabContainerPanelComponent = observe let properties = authModel?.properties; - if (info?.authProperties && info.authProperties.length > 0 && config.authModelId === info.authModel) { + if (info?.authProperties && info.authProperties.length > 0 && optionsPart.state.authModelId === info.authModel) { properties = info.authProperties; } - const sharedCredentials = config.sharedCredentials && serverConfigResource.data?.distributed; + const sharedCredentials = optionsPart.state.sharedCredentials && serverConfigResource.data?.distributed; function openCredentialsTab(event: React.MouseEvent) { event.preventDefault(); @@ -197,7 +190,10 @@ export const Options: TabContainerPanelComponent = observe return; } - formState.state.config.driverId = driverId; + runInAction(() => { + optionsPart.state.driverId = driverId; + }); + await formState.reload(); } @@ -218,7 +214,7 @@ export const Options: TabContainerPanelComponent = observe driver.id} @@ -237,7 +233,7 @@ export const Options: TabContainerPanelComponent = observe {configurationTypes.length > 1 && ( - + {configurationTypes.map(conf => ( = observe )} - {config.configurationType === DriverConfigurationType.Url && ( + {optionsPart.state.configurationType === DriverConfigurationType.Url && ( {translate('plugin_connections_connection_form_part_main_url_jdbc')} )} - {config.configurationType === DriverConfigurationType.Manual && + {optionsPart.state.configurationType === DriverConfigurationType.Manual && (driver?.useCustomPage ? ( ) : ( = observe - + {translate('connections_connection_name')} - {!config.template && ( + {!optionsPart.state.template && ( = observe onChange={setProject} /> )} - {!config.template && ( + {!optionsPart.state.template && ( = observe )} - @@ -328,10 +324,10 @@ export const Options: TabContainerPanelComponent = observe {translate('connections_connection_edit_authentication')} {serverConfigResource.resource.distributed && isSharedProject && ( @@ -339,7 +335,7 @@ export const Options: TabContainerPanelComponent = observe )} = observe <> {properties && ( = observe )} - {!sharedCredentials && authModel && credentialsSavingEnabled && !config.template && ( + {!sharedCredentials && authModel && credentialsSavingEnabled && !optionsPart.state.template && ( = observe )} {driver?.providerProperties && ( - + )} - + diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts b/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts deleted file mode 100644 index b9842fc2ed..0000000000 --- a/webapp/packages/plugin-connections/src/ConnectionForm/Options/useOptions.ts +++ /dev/null @@ -1,133 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { runInAction } from 'mobx'; - -import { useObjectRef } from '@cloudbeaver/core-blocks'; -import { ConnectionInfoResource, createConnectionParam, type DBDriver, DBDriverResource, isJDBCConnection } from '@cloudbeaver/core-connections'; -import { useService } from '@cloudbeaver/core-di'; -import type { ConnectionConfig, DatabaseAuthModel } from '@cloudbeaver/core-sdk'; -import { getConnectionName } from './getConnectionName.js'; -import { getDefaultConfigurationType } from './getDefaultConfigurationType.js'; -import type { IFormState } from '@cloudbeaver/core-ui'; -import type { IConnectionFormState } from '../IConnectionFormState.js'; - -export function useOptions(formState: IFormState, config: ConnectionConfig) { - const mode = formState.mode; - const connectionInfoService = useService(ConnectionInfoResource); - const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); - - const dbDriverResource = useService(DBDriverResource); - const refObject = useObjectRef( - () => ({ - prevName: null as string | null, - prevDriverId: null as string | null, - }), - { - config, - info, - mode, - formState, - }, - ); - - return useObjectRef({ - updateNameTemplate(driver: DBDriver | undefined) { - runInAction(() => { - const { config, info } = refObject; - - if (isJDBCConnection(driver, info)) { - refObject.prevName = config.url || ''; - config.name = config.url || ''; - return; - } - - if (!driver) { - config.name = 'New connection'; - return; - } - - const name = getConnectionName(driver.name || '', config.host, config.port, driver.defaultPort); - - refObject.prevName = name; - config.name = name; - }); - }, - setDefaults(driver: DBDriver | undefined) { - runInAction(() => { - const { config, info, prevDriverId } = refObject; - - if (info || driver?.id !== config.driverId) { - return; - } - - let prevDriver: DBDriver | undefined; - - if (prevDriverId) { - prevDriver = dbDriverResource.get(prevDriverId); - } - - refObject.prevDriverId = driver?.id || null; - - if (!config.configurationType || !driver?.configurationTypes.includes(config.configurationType)) { - config.configurationType = getDefaultConfigurationType(driver); - } - - if ((!prevDriver && config.host === undefined) || config.host === prevDriver?.defaultServer) { - config.host = driver?.defaultServer || 'localhost'; - } - - if ((!prevDriver && config.port === undefined) || config.port === prevDriver?.defaultPort) { - config.port = driver?.defaultPort; - } - - if ((!prevDriver && config.databaseName === undefined) || config.databaseName === prevDriver?.defaultDatabase) { - config.databaseName = driver?.defaultDatabase; - } - - if ((!prevDriver && config.url === undefined) || config.url === prevDriver?.sampleURL) { - config.url = driver?.sampleURL; - } - - if (this.isNameAutoFill()) { - this.updateNameTemplate(driver); - } - - if (driver?.id !== prevDriver?.id) { - config.credentials = {}; - config.providerProperties = {}; - config.authModelId = driver?.defaultAuthModel; - } - }); - }, - async setAuthModel(model: DatabaseAuthModel) { - const { config, info, formState } = refObject; - - config.credentials = {}; - - if (model.id === info?.authModel) { - if (info.authProperties) { - for (const property of info.authProperties) { - if (!property.features.includes('password')) { - config.credentials[property.id!] = property.value; - } - } - } - } - - await formState.reload(); - }, - - isNameAutoFill() { - const { prevName, config, mode } = refObject; - - const isAutoFill = config.name === prevName || prevName === null; - - return isAutoFill && mode === 'create'; - }, - }); -} diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx index e1160fcce1..4c71f6c734 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormAuthenticationAction.tsx @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -13,18 +13,20 @@ import { ConnectionInfoResource, createConnectionParam, DatabaseAuthModelsResour import type { IConnectionFormProps } from '../IConnectionFormState.js'; import { useService } from '@cloudbeaver/core-di'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; export const AuthenticationButton: PlaceholderComponent = observer(function ConnectionFormAuthenticationAction({ formState }) { const translate = useTranslate(); - const driverMap = useResource(ConnectionFormAuthenticationAction, DBDriverResource, formState.state.config.driverId || null); + const optionsPart = getConnectionFormOptionsPart(formState); + const driverMap = useResource(ConnectionFormAuthenticationAction, DBDriverResource, optionsPart.state.driverId || null); const connectionInfoService = useService(ConnectionInfoResource); - const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); + const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!)); const driver = driverMap.data; const { data: authModel } = useResource( ConnectionFormAuthenticationAction, DatabaseAuthModelsResource, - getComputed(() => formState.state.config.authModelId || info?.authModel || driver?.defaultAuthModel || null), + getComputed(() => optionsPart.state.authModelId || info?.authModel || driver?.defaultAuthModel || null), ); const authentication = useAuthenticationAction({ @@ -46,15 +48,16 @@ export const AuthenticationButton: PlaceholderComponent = export const ConnectionFormAuthenticationAction: PlaceholderComponent = observer(function ConnectionFormAuthenticationAction({ formState, }) { - const driverMap = useResource(ConnectionFormAuthenticationAction, DBDriverResource, formState.state.config.driverId || null); + const optionsPart = getConnectionFormOptionsPart(formState); + const driverMap = useResource(ConnectionFormAuthenticationAction, DBDriverResource, optionsPart.state.driverId || null); const connectionInfoService = useService(ConnectionInfoResource); - const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); + const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!)); const driver = driverMap.data; const { data: authModel } = useResource( ConnectionFormAuthenticationAction, DatabaseAuthModelsResource, - getComputed(() => formState.state.config.authModelId || info?.authModel || driver?.defaultAuthModel || null), + getComputed(() => optionsPart.state.authModelId || info?.authModel || driver?.defaultAuthModel || null), ); if (!authModel?.requiredAuth && !info?.requiredAuth) { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormOriginInfoFormPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormOriginInfoFormPart.ts index 142cda6dd0..6920f4cefb 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormOriginInfoFormPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/ConnectionFormOriginInfoFormPart.ts @@ -42,22 +42,23 @@ export class ConnectionFormOriginInfoFormPart extends FormPart { @@ -101,12 +85,12 @@ export class ConnectionFormOriginInfoFormPart extends FormPart import('./ConnectionFormAuthenticationAction.js').then(m => m.ConnectionFormAuthenticationAction), ); @@ -38,7 +38,8 @@ export class ConnectionOriginInfoTabService extends Bootstrap { getLoader: () => getCachedMapResourceLoaderState(this.connectionInfoOriginResource, () => CachedMapAllKey), isHidden: (tabId, props) => { const projectId = props?.formState.state.projectId; - const connectionId = props?.formState.state.config.connectionId; + const optionsPart = props?.formState ? getConnectionFormOptionsPart(props.formState) : null; + const connectionId = optionsPart?.state.connectionId; if (!projectId || !connectionId) { return true; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index 93b07d3a35..0cdb3f5272 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -1,11 +1,10 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ - import { observer } from 'mobx-react-lite'; import { AuthProvidersResource } from '@cloudbeaver/core-authentication'; @@ -30,6 +29,7 @@ import styles from './OriginInfo.module.css'; import type { IConnectionFormProps } from '../IConnectionFormState.js'; import { useService } from '@cloudbeaver/core-di'; import { getConnectionFormOriginInfoFormPart } from './getConnectionFormOriginInfoFormPart.js'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ tabId, formState }) { const tab = useTab(tabId); @@ -37,7 +37,8 @@ export const OriginInfo: TabContainerPanelComponent = obse const originInfoPart = getConnectionFormOriginInfoFormPart(formState); const style = useS(styles); const connectionInfoService = useService(ConnectionInfoResource); - const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); + const optionsPart = getConnectionFormOptionsPart(formState); + const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!)); const providerLoader = useResource(OriginInfo, AuthProvidersResource, originInfoPart.providerId); const connectionId = tab.selected && info ? createConnectionParam(info.projectId, info.id) : null; const isAuthenticated = getComputed(() => originInfoPart.isAuthenticated); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx index dbc6fe5fcd..467b5483d1 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfoTab.tsx @@ -12,12 +12,13 @@ import { Tab, type TabContainerTabComponent, TabTitle } from '@cloudbeaver/core- import type { IConnectionFormProps } from '../IConnectionFormState.js'; import { ConnectionInfoOriginResource, createConnectionParam } from '@cloudbeaver/core-connections'; - +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; export const OriginInfoTab: TabContainerTabComponent = observer(function OriginInfoTab({ formState, ...rest }) { + const optionsPart = getConnectionFormOptionsPart(formState); const connectionInfoOriginResource = useResource( OriginInfoTab, ConnectionInfoOriginResource, - createConnectionParam(formState.state.projectId, formState.state.config.connectionId!), + createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!), ); return ( diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionFormSSHPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionFormSSHPart.ts index 37e022cf22..f7a9ee8f1d 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionFormSSHPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionFormSSHPart.ts @@ -42,18 +42,18 @@ export class ConnectionFormSSHPart extends FormPart { - if (!this.formState.state.config.connectionId || !this.formState.state.projectId) { + if (!this.optionsPart.state.connectionId || !this.formState.state.projectId) { this.setInitialState(getDefaultState()); return; } const connection = await this.connectionInfoResource.load( - createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId), + createConnectionParam(this.formState.state.projectId, this.optionsPart.state.connectionId!), ); this.setInitialState(connection?.networkHandlersConfig?.find(h => h.id === SSH_TUNNEL_ID) ?? getDefaultState()); @@ -68,8 +68,8 @@ export class ConnectionFormSSHPart extends FormPart, contexts: IExecutionContextProvider>, ): void | Promise { - const urlType = this.formState.state.config.configurationType === DriverConfigurationType.Url; const optionsPart = getConnectionFormOptionsPart(this.formState); + const urlType = optionsPart.state.configurationType === DriverConfigurationType.Url; if (urlType) { return; diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts index 6ecc8c477f..a975bd6c2f 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/ConnectionSSHTabService.ts @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -40,9 +40,10 @@ export class ConnectionSSHTabService extends Bootstrap { tab: () => SSHTab, panel: () => SSHPanel, isHidden: (tabId, props) => { - if (props?.formState.state.config.driverId) { - const driver = this.dbDriverResource.get(props?.formState.state.config.driverId); - const optionsPart = getConnectionFormOptionsPart(props.formState); + const optionsPart = props?.formState ? getConnectionFormOptionsPart(props.formState) : null; + + if (optionsPart?.state.driverId) { + const driver = this.dbDriverResource.get(optionsPart.state.driverId); const urlType = optionsPart.state.configurationType === DriverConfigurationType.Url; return urlType || !driver?.applicableNetworkHandlers.includes(SSH_TUNNEL_ID); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionFormSSLPart.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionFormSSLPart.ts index 223e3ff002..eb28582686 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionFormSSLPart.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionFormSSLPart.ts @@ -44,25 +44,18 @@ export class ConnectionFormSSLPart extends FormPart { - if (!this.formState.state.config.driverId) { + if (!this.optionsPart.state.driverId) { this.setInitialState(getDefaultState()); return; } - const optionsPart = getConnectionFormOptionsPart(this.formState); const [driver, handlers] = await Promise.all([ - this.dbDriverResource.load(this.formState.state.config.driverId), + this.dbDriverResource.load(this.optionsPart.state.driverId), this.networkHandlerResource.load(CachedMapAllKey), ]); const handler = getSSLDriverHandler(handlers, driver?.applicableNetworkHandlers ?? []); @@ -72,10 +65,10 @@ export class ConnectionFormSSLPart extends FormPart h.id === handler.id); - if (!optionsPart.state.networkHandlersConfig?.some(state => state.id === handler.id)) { + if (!this.optionsPart.state.networkHandlersConfig?.some(state => state.id === handler.id)) { const config: NetworkHandlerConfigInput = initialConfig ? toJS(initialConfig) : getSSLDefaultConfig(handler.id); if (config.secureProperties) { @@ -93,11 +86,12 @@ export class ConnectionFormSSLPart extends FormPart, contexts: IExecutionContextProvider>, ): Promise { - if (!this.formState.state.config.driverId) { + const optionsPart = getConnectionFormOptionsPart(this.formState); + + if (!optionsPart.state.driverId) { return; } - const optionsPart = getConnectionFormOptionsPart(this.formState); const handlers = await this.networkHandlerResource.load(CachedMapAllKey); const descriptor = handlers.find(h => h.id === this.state?.id); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionSSLTabService.ts b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionSSLTabService.ts index 98aa3bd4ec..176e3f544a 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionSSLTabService.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/ConnectionSSLTabService.ts @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -9,7 +9,7 @@ import React from 'react'; import { DBDriverResource, NetworkHandlerResource } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; - +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; import { getSSLDriverHandler } from './getSSLDriverHandler.js'; import { ConnectionFormService } from '../ConnectionFormService.js'; @@ -39,8 +39,10 @@ export class ConnectionSSLTabService extends Bootstrap { tab: () => SSLTab, panel: () => SSLPanel, isHidden: (_, props) => { - if (props?.formState.state.config.driverId) { - const driver = this.dbDriverResource.get(props?.formState.state.config.driverId); + const optionsPart = props?.formState ? getConnectionFormOptionsPart(props.formState) : null; + + if (optionsPart?.state.driverId) { + const driver = this.dbDriverResource.get(optionsPart.state.driverId); const handler = getSSLDriverHandler(this.networkHandlerResource.values, driver?.applicableNetworkHandlers ?? []); return !handler; } diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx index 0be623dca8..89d158f31f 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSL.tsx @@ -1,10 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + import { observer } from 'mobx-react-lite'; import React from 'react'; @@ -53,12 +54,12 @@ export const SSL: TabContainerPanelComponent = observer(function SSL({ fo const disabled = formState.isDisabled; const enabled = handlerState.enabled || false; const connectionInfoService = useService(ConnectionInfoResource); - const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, formState.state.config.connectionId!)); + const optionsPart = getConnectionFormOptionsPart(formState); + const info = connectionInfoService.get(createConnectionParam(formState.state.projectId, optionsPart.state.connectionId!)); const initialHandler = info?.networkHandlersConfig?.find(h => h.id === handler.id); const autofillToken = isSafari ? 'section-connection-authentication-ssl section-ssl' : 'new-password'; const projectInfoResource = useService(ProjectInfoResource); const isSharedProject = projectInfoResource.isProjectShared(formState.state.projectId); - const optionsPart = getConnectionFormOptionsPart(formState); useAutoLoad(SSL, optionsPart); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLPanel.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLPanel.tsx index 62d97eb2a9..7ef6594963 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLPanel.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLPanel.tsx @@ -16,10 +16,12 @@ import { getSSLDriverHandler } from './getSSLDriverHandler.js'; import { SSL } from './SSL.js'; import { getConnectionFormSSLPart } from './getConnectionFormSSLPart.js'; import type { IConnectionFormProps } from '../IConnectionFormState.js'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; export const SSLPanel: TabContainerTabComponent = observer(function SSLPanel(props) { const networkHandlerResource = useResource(SSLPanel, NetworkHandlerResource, CachedMapAllKey); - const dbDriverResource = useResource(SSLPanel, DBDriverResource, props.formState.state.config.driverId ?? null); + const optionsPart = getConnectionFormOptionsPart(props.formState); + const dbDriverResource = useResource(SSLPanel, DBDriverResource, optionsPart.state.driverId ?? null); const handler = getSSLDriverHandler(networkHandlerResource.resource.values, dbDriverResource.data?.applicableNetworkHandlers ?? []); const sslPart = getConnectionFormSSLPart(props.formState); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLTab.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLTab.tsx index bda4118aea..80cde4d36f 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLTab.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSL/SSLTab.tsx @@ -1,10 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + import { observer } from 'mobx-react-lite'; import { Translate, useResource } from '@cloudbeaver/core-blocks'; @@ -14,10 +15,12 @@ import { Tab, type TabContainerTabComponent, TabTitle } from '@cloudbeaver/core- import { getSSLDriverHandler } from './getSSLDriverHandler.js'; import type { IConnectionFormProps } from '../IConnectionFormState.js'; +import { getConnectionFormOptionsPart } from '../Options/getConnectionFormOptionsPart.js'; export const SSLTab: TabContainerTabComponent = observer(function SSLTab(props) { const networkHandlerResource = useResource(SSLTab, NetworkHandlerResource, CachedMapAllKey); - const dbDriverResource = useResource(SSLTab, DBDriverResource, props.formState.state.config.driverId ?? null); + const optionsPart = getConnectionFormOptionsPart(props.formState); + const dbDriverResource = useResource(SSLTab, DBDriverResource, optionsPart.state.driverId ?? null); const handler = getSSLDriverHandler(networkHandlerResource.resource.values, dbDriverResource.data?.applicableNetworkHandlers ?? []); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts index cb9d53fdf6..117a42b1e9 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts +++ b/webapp/packages/plugin-connections/src/ConnectionForm/useConnectionFormState.ts @@ -11,10 +11,11 @@ import { ConnectionFormState } from './ConnectionFormState.js'; import { ConnectionFormService } from './ConnectionFormService.js'; import type { IConnectionFormState } from './IConnectionFormState.js'; import type { IConnectionInfoParams } from '@cloudbeaver/core-connections'; +import { getConnectionFormOptionsPart } from './Options/getConnectionFormOptionsPart.js'; +import { runInAction } from 'mobx'; const EMPTY_CONNECTION_INFO_PARAMS: IConnectionFormState = { projectId: '', - config: {}, submitType: 'submit', availableDrivers: [], type: 'admin', @@ -25,17 +26,21 @@ export function useConnectionFormState(params: IConnectionInfoParams, configure? const serviceProvider = useService(IServiceProvider); const service = useService(ConnectionFormService); const ref = useRef(null); + let optionsPart = ref.current ? getConnectionFormOptionsPart(ref.current) : null; - if (ref.current?.state.config.connectionId !== params.connectionId || ref.current?.state.projectId !== params.projectId) { + if (optionsPart?.state.connectionId !== params.connectionId || ref.current?.state.projectId !== params.projectId) { ref.current?.dispose(); ref.current = new ConnectionFormState(serviceProvider, service, { ...EMPTY_CONNECTION_INFO_PARAMS, projectId: params.projectId, - config: { - ...EMPTY_CONNECTION_INFO_PARAMS.config, - connectionId: params.connectionId, - }, }); + + optionsPart = getConnectionFormOptionsPart(ref.current); + + runInAction(() => { + optionsPart!.state.connectionId = params.connectionId; + }); + configure?.(ref.current); } diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts index 0563cd1833..a891c130b1 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionFormService.ts @@ -1,11 +1,12 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2025 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 { action, makeObservable, observable } from 'mobx'; + +import { action, makeObservable, observable, runInAction } from 'mobx'; import { UserInfoResource } from '@cloudbeaver/core-authentication'; import { ConfirmationDialog, importLazyComponent } from '@cloudbeaver/core-blocks'; @@ -21,6 +22,7 @@ import { AuthenticationService } from '@cloudbeaver/plugin-authentication'; import { ConnectionFormState } from '../ConnectionForm/ConnectionFormState.js'; import { ConnectionFormService } from '../ConnectionForm/ConnectionFormService.js'; +import { getConnectionFormOptionsPart } from '../ConnectionForm/Options/getConnectionFormOptionsPart.js'; const PublicConnectionForm = importLazyComponent(() => import('./PublicConnectionForm.js').then(m => m.PublicConnectionForm)); @@ -74,11 +76,18 @@ export class PublicConnectionFormService { this.formState = new ConnectionFormState(this.serviceProvider, this.connectionFormService, { projectId, availableDrivers: availableDrivers ?? [], - config, submitType: 'submit', type: 'public', requiredNetworkHandlersIds: [], }); + + runInAction(() => { + this.optionsPart!.state = { + ...this.optionsPart!.state, + ...config, + }; + }); + this.formState.disposeTask.addHandler(this.close.bind(this, true)); } @@ -114,9 +123,11 @@ export class PublicConnectionFormService { } async save(): Promise { + const optionsPart = this.formState ? getConnectionFormOptionsPart(this.formState) : null; + const key = - this.formState && this.formState.state.config.connectionId && this.formState.state.projectId !== null - ? createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId) + this.formState && optionsPart?.state.connectionId && this.formState.state.projectId !== null + ? createConnectionParam(this.formState.state.projectId, optionsPart.state.connectionId) : null; await this.close(true); @@ -126,24 +137,26 @@ export class PublicConnectionFormService { } } + get optionsPart() { + return this.formState ? getConnectionFormOptionsPart(this.formState) : null; + } + private readonly closeRemoved: IExecutorHandler> = (data, contexts) => { - if (!this.formState || !this.formState.state.config.connectionId || this.formState.state.projectId === null) { + if (!this.formState || !this.optionsPart?.state.connectionId || this.formState.state.projectId === null) { return; } - if (!this.connectionInfoResource.has(createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId))) { + if (!this.connectionInfoResource.has(createConnectionParam(this.formState.state.projectId, this.optionsPart.state.connectionId!))) { this.close(true); } }; private readonly closeDeleted: IExecutorHandler> = (data, contexts) => { - if (!this.formState || !this.formState.state.config.connectionId || this.formState.state.projectId === null) { + if (!this.formState || !this.optionsPart?.state.connectionId || this.formState.state.projectId === null) { return; } - if ( - this.connectionInfoResource.isIntersect(data, createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId)) - ) { + if (this.connectionInfoResource.isIntersect(data, createConnectionParam(this.formState.state.projectId, this.optionsPart.state.connectionId!))) { this.close(true); } }; @@ -157,12 +170,14 @@ export class PublicConnectionFormService { }; private async showUnsavedChangesDialog(): Promise { + const optionsPart = this.formState ? getConnectionFormOptionsPart(this.formState) : null; + if ( !this.formState || !this.optionsPanelService.isOpen(formGetter) || - (this.formState.state.config.connectionId && + (optionsPart?.state.connectionId && this.formState.state.projectId !== null && - !this.connectionInfoResource.has(createConnectionParam(this.formState.state.projectId, this.formState.state.config.connectionId))) + !this.connectionInfoResource.has(createConnectionParam(this.formState.state.projectId, optionsPart.state.connectionId))) ) { return true; }