From fbccdf754c0e525d243bf005569c2f7416de5bda Mon Sep 17 00:00:00 2001 From: Wroud Date: Wed, 21 Apr 2021 17:48:45 +0300 Subject: [PATCH] fix: CB-780 connection form close confirmation --- .../ConnectionDriverPropertiesTabService.ts | 18 +++++-- .../Options/ConnectionOptionsTabService.ts | 29 ++++++----- webapp/packages/core-sdk/src/index.ts | 1 + .../src/isObjectPropertyInfoStateEqual.ts | 49 +++++++++++++++++++ webapp/packages/core-utils/src/index.ts | 1 + .../packages/core-utils/src/isValuesEqual.ts | 15 ++++++ .../PublicConnectionForm.tsx | 2 +- 7 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 webapp/packages/core-sdk/src/isObjectPropertyInfoStateEqual.ts create mode 100644 webapp/packages/core-utils/src/isValuesEqual.ts diff --git a/webapp/packages/core-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts b/webapp/packages/core-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts index 498e71de44..a52670b2d6 100644 --- a/webapp/packages/core-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts +++ b/webapp/packages/core-connections/src/ConnectionForm/DriverProperties/ConnectionDriverPropertiesTabService.ts @@ -8,8 +8,9 @@ import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import { isPropertiesEqual } from '@cloudbeaver/core-utils'; +import { isObjectPropertyInfoStateEqual } from '@cloudbeaver/core-sdk'; +import { DBDriverResource } from '../../DBDriverResource'; import { connectionConfigContext } from '../connectionConfigContext'; import { IConnectionFormSubmitData, ConnectionFormService, IConnectionFormState } from '../ConnectionFormService'; import { connectionFormStateContext } from '../connectionFormStateContext'; @@ -18,7 +19,8 @@ import { DriverProperties } from './DriverProperties'; @injectable() export class ConnectionDriverPropertiesTabService extends Bootstrap { constructor( - private readonly connectionFormService: ConnectionFormService + private readonly connectionFormService: ConnectionFormService, + private readonly dbDriverResource: DBDriverResource, ) { super(); } @@ -54,15 +56,21 @@ export class ConnectionDriverPropertiesTabService extends Bootstrap { ) { const config = contexts.getContext(connectionConfigContext); - config.properties = state.config.properties; + config.properties = { ...state.config.properties }; } - private formState( + private async formState( data: IConnectionFormState, contexts: IExecutionContextProvider ) { + if (!data.info || !data.config.driverId) { + return; + } + const config = contexts.getContext(connectionConfigContext); - if (!isPropertiesEqual(config.properties, data.info?.properties)) { + const driver = await this.dbDriverResource.load(data.config.driverId, ['includeDriverProperties']); + + if (!isObjectPropertyInfoStateEqual(driver.driverProperties, config.properties, data.info.properties)) { const stateContext = contexts.getContext(connectionFormStateContext); stateContext.markEdited(); diff --git a/webapp/packages/core-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts b/webapp/packages/core-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts index 1e85ee3f06..0ecdcf3975 100644 --- a/webapp/packages/core-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts +++ b/webapp/packages/core-connections/src/ConnectionForm/Options/ConnectionOptionsTabService.ts @@ -8,8 +8,8 @@ import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; -import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; -import { isPropertiesEqual } from '@cloudbeaver/core-utils'; +import { isObjectPropertyInfoStateEqual, ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; +import { isValuesEqual } from '@cloudbeaver/core-utils'; import { ConnectionsResource, DatabaseConnection } from '../../Administration/ConnectionsResource'; import { ConnectionInfoResource } from '../../ConnectionInfoResource'; @@ -208,22 +208,27 @@ export class ConnectionOptionsTabService extends Bootstrap { const config = contexts.getContext(connectionConfigContext); const stateContext = contexts.getContext(connectionFormStateContext); + const driver = await this.dbDriverResource.load(data.config.driverId!, ['includeProviderProperties']); if ( - config.name !== data.info.name - || config.description !== data.info.description - || config.template !== data.info.template - || config.driverId !== data.info.driverId - || (config.url !== undefined && config.url !== data.info.url) - || (config.host !== undefined && config.host !== data.info.host) - || (config.port !== undefined && config.port !== data.info.port) - || (config.databaseName !== undefined && config.databaseName !== data.info.databaseName) + !isValuesEqual(config.name, data.info.name, '') + || !isValuesEqual(config.description, data.info.description, '') + || !isValuesEqual(config.template, data.info.template, true) + || !isValuesEqual(config.driverId, data.info.driverId, '') + || (config.url !== undefined && !isValuesEqual(config.url, data.info.url, '')) + || (config.host !== undefined && !isValuesEqual(config.host, data.info.host, '')) + || (config.port !== undefined && !isValuesEqual(config.port, data.info.port, '')) + || (config.databaseName !== undefined && !isValuesEqual(config.databaseName, data.info.databaseName, '')) || config.credentials !== undefined - || (config.authModelId !== undefined && config.authModelId !== data.info.authModel) + || (config.authModelId !== undefined && !isValuesEqual(config.authModelId, data.info.authModel, '')) || (config.saveCredentials !== undefined && config.saveCredentials !== data.info.saveCredentials) || ( config.providerProperties !== undefined - && !isPropertiesEqual(config.providerProperties, data.info.providerProperties) + && !isObjectPropertyInfoStateEqual( + driver.providerProperties, + config.providerProperties, + data.info.providerProperties + ) ) ) { stateContext.markEdited(); diff --git a/webapp/packages/core-sdk/src/index.ts b/webapp/packages/core-sdk/src/index.ts index 7434aaf753..e688a029a3 100644 --- a/webapp/packages/core-sdk/src/index.ts +++ b/webapp/packages/core-sdk/src/index.ts @@ -11,5 +11,6 @@ export * from './getErrorDetails'; export * from './GQLError'; export * from './GQLErrorCatcher'; export * from './GraphQLService'; +export * from './isObjectPropertyInfoStateEqual'; export * from './sdk'; export * from './ServerInternalError'; diff --git a/webapp/packages/core-sdk/src/isObjectPropertyInfoStateEqual.ts b/webapp/packages/core-sdk/src/isObjectPropertyInfoStateEqual.ts new file mode 100644 index 0000000000..d2b1e1ee5d --- /dev/null +++ b/webapp/packages/core-sdk/src/isObjectPropertyInfoStateEqual.ts @@ -0,0 +1,49 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 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 { isValuesEqual } from '@cloudbeaver/core-utils'; + +import type { ObjectPropertyInfo } from './sdk'; + +type RequiredObjectPropertyInfoFields = Pick; + +export function isObjectPropertyInfoStateEqual( + properties: RequiredObjectPropertyInfoFields[], + first: T, + second: T +): boolean { + if ( + first === null + || second === null + || typeof first !== 'object' + || typeof second !== 'object' + ) { + return false; + } + + const customKeys = [...Object.keys(first), ...Object.keys(second)] + .filter(key => !properties.some(property => key === property.id)); + + for (const property of properties) { + if (!property.id) { + continue; + } + + if (!isValuesEqual(first[property.id as keyof T], second[property.id as keyof T], property.defaultValue)) { + return false; + } + } + + for (const key of customKeys) { + if (first[key as keyof T] !== second[key as keyof T]) { + return false; + } + } + + return true; +} diff --git a/webapp/packages/core-utils/src/index.ts b/webapp/packages/core-utils/src/index.ts index 615199d4a5..ae34073384 100644 --- a/webapp/packages/core-utils/src/index.ts +++ b/webapp/packages/core-utils/src/index.ts @@ -7,6 +7,7 @@ export * from './uuid_'; export * from './generateFileName'; export * from './isArraysEqual'; export * from './isPropertiesEqual'; +export * from './isValuesEqual'; export * from './md5'; export * from './TextTools'; export * from './copyToClipboard'; diff --git a/webapp/packages/core-utils/src/isValuesEqual.ts b/webapp/packages/core-utils/src/isValuesEqual.ts new file mode 100644 index 0000000000..25588eae33 --- /dev/null +++ b/webapp/packages/core-utils/src/isValuesEqual.ts @@ -0,0 +1,15 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ + +export function isValuesEqual( + first: T | null | undefined, + second: T | null | undefined, + defaultValue?: T +): boolean { + return (first ?? defaultValue) === (second ?? defaultValue); +} diff --git a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx index 71be28b1df..3ecc8160bb 100644 --- a/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx +++ b/webapp/packages/plugin-connections/src/PublicConnectionForm/PublicConnectionForm.tsx @@ -59,7 +59,7 @@ const PublicConnectionFormRenderer: React.FC = observer(function PublicCo export const PublicConnectionForm: React.FC = observer(function PublicConnectionForm() { const service = useService(PublicConnectionFormService); - const close = useCallback(() => service.close(), []); + const close = useCallback(() => service.close(true), []); const save = useCallback(() => service.close(true), []); return styled(styles)(