diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26126_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26126_spec.ts new file mode 100644 index 0000000000..4b5ba6c883 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug26126_spec.ts @@ -0,0 +1,26 @@ +import { + dataSources, + entityExplorer, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Bug 26126: Fix DS button disability", function () { + it("ensures save button is correctly updated when DS required fields change", function () { + dataSources.NavigateToDSCreateNew(); + dataSources.CreatePlugIn("S3"); + dataSources.FillS3DSForm(); + dataSources.AssertSaveDSButtonDisability(false); + dataSources.ValidateNSelectDropdown( + "S3 service provider", + "Amazon S3", + "Upcloud", + ); + dataSources.AssertSaveDSButtonDisability(true); + dataSources.ValidateNSelectDropdown( + "S3 service provider", + "Upcloud", + "Amazon S3", + ); + + dataSources.AssertSaveDSButtonDisability(false); + }); +}); diff --git a/app/client/cypress/support/Pages/DataSources.ts b/app/client/cypress/support/Pages/DataSources.ts index ab3501aefb..fc486f0b48 100644 --- a/app/client/cypress/support/Pages/DataSources.ts +++ b/app/client/cypress/support/Pages/DataSources.ts @@ -800,11 +800,10 @@ export class DataSources { } else { this.assertHelper.AssertNetworkStatus("@updateDatasource", 200); } + } - // cy.wait("@saveDatasource") - // .then((xhr) => { - // cy.log(JSON.stringify(xhr.response!.body)); - // }).should("have.nested.property", "response.body.responseMeta.status", 200); + public AssertSaveDSButtonDisability(isDisabled = true) { + this.agHelper.AssertElementEnabledDisabled(this._saveDs, 0, isDisabled); } public AuthAPISaveAndAuthorize() { diff --git a/app/client/src/pages/Editor/DataSourceEditor/index.tsx b/app/client/src/pages/Editor/DataSourceEditor/index.tsx index 2ae1bd43a9..2e0f9efb04 100644 --- a/app/client/src/pages/Editor/DataSourceEditor/index.tsx +++ b/app/client/src/pages/Editor/DataSourceEditor/index.tsx @@ -79,6 +79,7 @@ import { getConfigInitialValues, getIsFormDirty, getTrimmedData, + isHidden, normalizeValues, validate, } from "components/formControls/utils"; @@ -92,8 +93,13 @@ import DSDataFilter from "@appsmith/components/DSDataFilter"; import { DEFAULT_ENV_ID } from "@appsmith/api/ApiUtils"; import { isStorageEnvironmentCreated } from "@appsmith/utils/Environments"; import type { CalloutKind } from "design-system"; +import type { FeatureFlags } from "@appsmith/entities/FeatureFlag"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; -import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors"; + +import { + selectFeatureFlagCheck, + selectFeatureFlags, +} from "@appsmith/selectors/featureFlagsSelectors"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { DATASOURCES_ALLOWED_FOR_PREVIEW_MODE } from "constants/QueryEditorConstants"; import { setCurrentEditingEnvironmentID } from "@appsmith/actions/environmentAction"; @@ -133,6 +139,7 @@ interface ReduxStateProps { defaultKeyValueArrayConfig: Array; initialValue: Datasource | ApiDatasourceForm | undefined; showDebugger: boolean; + featureFlags?: FeatureFlags; isEnabledForDSViewModeSchema: boolean; isPluginAllowedToPreviewData: boolean; } @@ -387,9 +394,72 @@ class DatasourceEditorRouter extends React.Component { const requiredFields = this.state.requiredFields; configDetails[configProperty] = controlType; if (isRequired) requiredFields[configProperty] = config; - this.setState({ - configDetails, - requiredFields, + + // if the required fields being rendered has been hidden, then remove them. + if (this.hasRequiredFieldsChanged()) { + // derive new states + const newConfigDetails = { ...configDetails }; + const newRequiredFields = { ...requiredFields }; + + Object.keys(requiredFields).forEach((field) => { + const currentConfig = requiredFields[field]; + + if ( + !!field && + this.props.formData && + this.props.pluginDatasourceForm !== + DatasourceComponentTypes.RestAPIDatasourceForm && + isHidden( + (this.props.formData as Datasource).datasourceStorages[ + this.getEnvironmentId() + ], + currentConfig.hidden, + this.props?.featureFlags, + false, + ) + ) { + // delete those fields. + delete newConfigDetails[field]; + delete newRequiredFields[field]; + } + }); + + this.setState({ + configDetails: newConfigDetails, + requiredFields: newRequiredFields, + }); + } else { + this.setState({ + configDetails, + requiredFields, + }); + } + }; + + // this method checks if any of the current required fields has been hidden/not rendered. + // + hasRequiredFieldsChanged = () => { + return Object.keys(this.state.requiredFields).some((field) => { + const currentConfig = this.state.requiredFields[field]; + + if ( + !!field && + this.props.formData && + this.props.pluginDatasourceForm !== + DatasourceComponentTypes.RestAPIDatasourceForm && + isHidden( + (this.props.formData as Datasource).datasourceStorages[ + this.getEnvironmentId() + ], + currentConfig.hidden, + this.props?.featureFlags, + false, + ) + ) { + return true; + } else { + return false; + } }); }; @@ -999,6 +1069,8 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => { pluginId, ); + const featureFlags = selectFeatureFlags(state); + // A/B feature flag for datasource view mode preview data. const isEnabledForDSViewModeSchema = selectFeatureFlagCheck( state, @@ -1016,6 +1088,7 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => { datasourceButtonConfiguration, datasourceId, pluginImage: getPluginImages(state)[pluginId], + featureFlags, formData, formName, isInsideReconnectModal: props.isInsideReconnectModal ?? false,