import { computed , makeObservable , observable } from 'mobx' ; import type { IFormStateInfo } from '@cloudbeaver/core-blocks' ; import { DatabaseConnection , EConnectionFeature , IConnectionsResource } from '@cloudbeaver/core-connections' ; import { Executor , IExecutionContextProvider , IExecutor } from '@cloudbeaver/core-executor' ; import { ConnectionConfig , ResourceKey , ResourceKeyUtils } from '@cloudbeaver/core-sdk' ; import { MetadataMap } from '@cloudbeaver/core-utils' ; import { connectionFormConfigureContext } from './connectionFormConfigureContext' ; import type { ConnectionFormService } from './ConnectionFormService' ; import { connectionFormStateContext } from './Contexts/connectionFormStateContext' ; import type { IConnectionFormState , ConnectionFormMode , ConnectionFormType , IConnectionFormSubmitData } from './IConnectionFormProps' ; export class ConnectionFormState implements IConnectionFormState { mode : ConnectionFormMode ; type : ConnectionFormType ; config : ConnectionConfig ; partsState : MetadataMap < string , any > ; statusMessage : string | null ; configured : boolean ; initError : Error | null ; get loading ( ) : boolean { return this . loadConnectionTask . executing || this . submittingTask . executing ; } get disabled ( ) : boolean { return this . loading || ! ! this . stateInfo ?. disabled || this . loadConnectionTask . executing ; } get availableDrivers ( ) : string [ ] { if ( this . _availableDrivers . length === 0 && this . config . driverId ) { return [ this . config . driverId ] ; } return this . _availableDrivers ; } get info ( ) : DatabaseConnection | undefined { if ( ! this . config . connectionId ) { return undefined ; } return this . resource . get ( this . config . connectionId ) ; } get readonly ( ) : boolean { if ( this . stateInfo ?. readonly ) { return true ; } if ( this . type === 'admin' || this . mode === 'create' ) { return false ; } if ( ! this . info ?. features . includes ( EConnectionFeature . manageable ) ) { return true ; } return false ; } readonly resource : IConnectionsResource ; readonly service : ConnectionFormService ; readonly submittingTask : IExecutor < IConnectionFormSubmitData > ; private stateInfo : IFormStateInfo | null ; private readonly loadConnectionTask : IExecutor < IConnectionFormState > ; private readonly formStateTask : IExecutor < IConnectionFormState > ; private _availableDrivers : string [ ] ; constructor ( service , resource ) { this . initError = null ; makeObservable < IConnectionFormState , '_availableDrivers' | 'stateInfo' > ( this , { mode : observable , type : observable , config : observable , availableDrivers : computed , _availableDrivers : observable , info : computed , statusMessage : observable , configured : observable , readonly : computed , stateInfo : observable , initError : observable . ref , } ) ; this . resource = resource ; this . config = { } ; this . _availableDrivers = [ ] ; this . stateInfo = null ; this . partsState = new MetadataMap ( ) ; this . service = service ; this . formStateTask = new Executor < IConnectionFormState > ( this , ( ) => true ) ; this . loadConnectionTask = new Executor < IConnectionFormState > ( this , ( ) => true ) ; this . submittingTask = new Executor ( ) ; this . statusMessage = null ; this . configured = false ; this . mode = 'create' ; this . type = 'public' ; this . syncInfo = this . syncInfo . bind ( this ) ; this . test = this . test . bind ( this ) ; this . save = this . save . bind ( this ) ; this . checkFormState = this . checkFormState . bind ( this ) ; this . loadInfo = this . loadInfo . bind ( this ) ; this . updateFormState = this . updateFormState . bind ( this ) ; this . formStateTask . addCollection ( service . formStateTask ) . addPostHandler ( this . updateFormState ) ; this . resource . onItemAdd . addHandler ( this . syncInfo ) ; this . loadConnectionTask . before ( service . configureTask ) . addPostHandler ( this . loadInfo ) . next ( service . fillConfigTask , ( state , contexts ) => { const configuration = contexts . getContext ( connectionFormConfigureContext ) ; return { state , updated : state . info !== configuration . info || state . config . driverId !== configuration . driverId || ! this . configured , } ; } ) . next ( this . formStateTask ) ; } async loadConnectionInfo ( ) { try { await this . loadConnectionTask . execute ( this ) ; this . initError = null ; return this . info ; } catch ( exception ) { this . initError = exception ; throw exception ; } } async load ( ) { await this . loadConnectionInfo ( ) ; } reset ( ) { this . configured = false ; this . partsState . clear ( ) ; } setPartsState ( state ) { this . partsState = state ; return this ; } setOptions ( mode , type ) { this . mode = mode ; this . type = type ; return this ; } setConfig ( config ) { this . config = config ; this . reset ( ) ; return this ; } setAvailableDrivers ( drivers ) { this . _availableDrivers = drivers ; this . reset ( ) ; return this ; } async save ( ) { await this . submittingTask . executeScope ( { state : this , submitType : 'submit' , } , this . service . formSubmittingTask ) ; } async test ( ) { await this . submittingTask . executeScope ( { state : this , submitType : 'test' , } , this . service . formSubmittingTask ) ; } async checkFormState ( ) { await this . loadConnectionInfo ( ) ; return this . stateInfo ; } dispose ( ) { this . resource . onItemAdd . removeHandler ( this . syncInfo ) ; } private updateFormState ( data , contexts ) { const context = contexts . getContext ( connectionFormStateContext ) ; if ( this . mode === 'create' ) { context . markEdited ( ) ; } this . statusMessage = context . statusMessage ; if ( this . statusMessage === null && this . mode === 'edit' ) { if ( ! this . info ?. features . includes ( EConnectionFeature . manageable ) ) { this . statusMessage = 'connections_connection_edit_not_own_deny' ; } } this . stateInfo = context ; this . configured = true ; } private syncInfo ( key ) { if ( ! ResourceKeyUtils . includes ( key , this . config . connectionId ) ) { return ; } this . loadConnectionInfo ( ) ; } private async loadInfo ( data , contexts ) { if ( ! data . config . connectionId ) { return ; } const configuration = contexts . getContext ( connectionFormConfigureContext ) ; if ( ! this . resource . has ( data . config . connectionId ) ) { return ; } await this . resource . load ( data . config . connectionId , configuration . connectionIncludes ) ; } }