diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/ReservedProperties.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/ReservedProperties.java index 80db2c2157..e32da39217 100644 --- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/ReservedProperties.java +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/ReservedProperties.java @@ -158,6 +158,10 @@ private ReservedProperties() { public static final String PN_EXCLUDE_FROM_DOR = "excludeFromDor"; public static final String PN_MANDATORY = "mandatory"; public static final String PN_HTML_ELEMENT_TYPE_V2 = "fd:htmlelementType"; + public static final String FD_AUTO_SAVE_PROPERTY_WRAPPER = "fd:autoSave"; + public static final String FD_ENABLE_AUTO_SAVE = "fd:enableAutoSave"; + public static final String FD_AUTO_SAVE_STRATEGY_TYPE = "fd:autoSaveStrategyType"; + public static final String FD_AUTO_SAVE_INTERVAL = "fd:autoSaveInterval"; private static final Set reservedProperties = aggregateReservedProperties(); private static Set aggregateReservedProperties() { diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/AutoSaveConfigurationImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/AutoSaveConfigurationImpl.java new file mode 100644 index 0000000000..5f97e8e022 --- /dev/null +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/AutoSaveConfigurationImpl.java @@ -0,0 +1,79 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Copyright 2024 Adobe + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package com.adobe.cq.forms.core.components.internal.models.v2.form; + +import javax.annotation.PostConstruct; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Default; +import org.apache.sling.models.annotations.Exporter; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; + +import com.adobe.cq.export.json.ExporterConstants; +import com.adobe.cq.forms.core.components.internal.form.ReservedProperties; +import com.adobe.cq.forms.core.components.models.form.AutoSaveConfiguration; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@Model( + adaptables = { SlingHttpServletRequest.class, Resource.class }, + adapters = AutoSaveConfiguration.class) +@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) +public class AutoSaveConfigurationImpl implements AutoSaveConfiguration { + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.FD_ENABLE_AUTO_SAVE) + @Default(booleanValues = false) + @JsonProperty(ReservedProperties.FD_ENABLE_AUTO_SAVE) + private boolean enableAutoSave; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.FD_AUTO_SAVE_STRATEGY_TYPE) + @JsonIgnore + private String autoSaveStrategyJcr; + + @JsonProperty(ReservedProperties.FD_AUTO_SAVE_STRATEGY_TYPE) + private AutoSaveStrategyType autoSaveStrategyType; + + @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = ReservedProperties.FD_AUTO_SAVE_INTERVAL) + @JsonProperty(ReservedProperties.FD_AUTO_SAVE_INTERVAL) + private Integer autoSaveInterval; + + @Override + public boolean isEnableAutoSave() { + return enableAutoSave; + } + + @Override + @JsonInclude(JsonInclude.Include.NON_NULL) + public AutoSaveStrategyType getAutoSaveStrategyType() { + return autoSaveStrategyType; + } + + @Override + @JsonInclude(JsonInclude.Include.NON_NULL) + public Integer getAutoSaveInterval() { + return autoSaveInterval; + } + + @PostConstruct + protected void initAutoSaveConfiguration() { + autoSaveStrategyType = AutoSaveStrategyType.fromString(autoSaveStrategyJcr); + } + +} diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImpl.java index af40e4d3a3..ed89546728 100644 --- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImpl.java +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v2/form/FormContainerImpl.java @@ -28,6 +28,7 @@ import org.apache.sling.models.annotations.Exporter; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; +import org.apache.sling.models.annotations.injectorspecific.Self; import org.apache.sling.models.annotations.injectorspecific.SlingObject; import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; import org.jetbrains.annotations.NotNull; @@ -46,6 +47,7 @@ import com.adobe.cq.forms.core.components.internal.form.FormConstants; import com.adobe.cq.forms.core.components.internal.form.ReservedProperties; import com.adobe.cq.forms.core.components.internal.models.v1.form.FormMetaDataImpl; +import com.adobe.cq.forms.core.components.models.form.AutoSaveConfiguration; import com.adobe.cq.forms.core.components.models.form.Container; import com.adobe.cq.forms.core.components.models.form.FormClientLibManager; import com.adobe.cq.forms.core.components.models.form.FormContainer; @@ -119,6 +121,9 @@ public class FormContainerImpl extends AbstractContainerImpl implements FormCont @Default(values = DEFAULT_FORMS_SPEC_VERSION) private String specVersion; + @Self(injectionStrategy = InjectionStrategy.OPTIONAL) + private AutoSaveConfiguration autoSaveConfig; + @PostConstruct protected void initFormContainerModel() { if (request != null) { @@ -314,6 +319,7 @@ public String getLanguageDirection() { } properties.put(FD_ROLE_ATTRIBUTE, getRoleAttribute()); properties.put(FD_FORM_DATA_ENABLED, formDataEnabled); + properties.put(ReservedProperties.FD_AUTO_SAVE_PROPERTY_WRAPPER, this.autoSaveConfig); return properties; } diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/AutoSaveConfiguration.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/AutoSaveConfiguration.java new file mode 100644 index 0000000000..8671eb3ca7 --- /dev/null +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/AutoSaveConfiguration.java @@ -0,0 +1,79 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Copyright 2024 Adobe + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package com.adobe.cq.forms.core.components.models.form; + +import org.apache.commons.lang3.StringUtils; +import org.osgi.annotation.versioning.ProviderType; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines the auto save configuration {@code AutoSaveConfiguration} + * + * @since com.adobe.cq.forms.core.components.models.form 5.5.4 + */ +@ProviderType +public interface AutoSaveConfiguration { + + enum AutoSaveStrategyType { + TIME("time"); + + private String strategyType; + + AutoSaveStrategyType(String strategyType) { + this.strategyType = strategyType; + } + + public String getStrategyType() { + return strategyType; + } + + /** + * Given a {@link String} strategyType, this method returns the enum's value that corresponds to the provided string + * representation + * + * @param strategyType the string representation for which an enum value should be returned + * @return the corresponding enum value, if one was found + * @since com.adobe.cq.forms.core.components.models.form 5.5.4 + */ + public static AutoSaveStrategyType fromString(String strategyType) { + for (AutoSaveStrategyType type : AutoSaveStrategyType.values()) { + if (StringUtils.equals(strategyType, type.strategyType)) { + return type; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return getStrategyType(); + } + } + + default boolean isEnableAutoSave() { + return false; + } + + default AutoSaveStrategyType getAutoSaveStrategyType() { + return AutoSaveStrategyType.TIME; + } + + default Integer getAutoSaveInterval() { + return 0; + } +} diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java index d48bd538f7..3d71430765 100644 --- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java +++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/package-info.java @@ -35,7 +35,7 @@ *

*/ -@Version("5.5.3") // aligning this with release/650 since af2-rest-api is compiled with 5.2.0 in release/650 +@Version("5.5.4") // aligning this with release/650 since af2-rest-api is compiled with 5.2.0 in release/650 package com.adobe.cq.forms.core.components.models.form; import org.osgi.annotation.versioning.Version; diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/AutoSaveConfigurationTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/AutoSaveConfigurationTest.java new file mode 100644 index 0000000000..71037f4131 --- /dev/null +++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v2/form/AutoSaveConfigurationTest.java @@ -0,0 +1,72 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Copyright 2024 Adobe + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package com.adobe.cq.forms.core.components.internal.models.v2.form; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import com.adobe.cq.forms.core.components.models.form.AutoSaveConfiguration; +import com.adobe.cq.forms.core.context.FormsCoreComponentTestContext; +import io.wcm.testing.mock.aem.junit5.AemContext; +import io.wcm.testing.mock.aem.junit5.AemContextExtension; + +import static org.junit.Assert.assertEquals; + +@ExtendWith(AemContextExtension.class) +public class AutoSaveConfigurationTest { + + private static final String BASE = "/form/formcontainer"; + private static final String TEST_CONTENT = BASE + "/test-content-auto-save.json"; + private static final String GUIDE_CONTAINER_ROOT = "/content/forms/af/testform/jcr:content/guideContainer"; + + private final AemContext context = FormsCoreComponentTestContext.newAemContext(); + + @BeforeEach + void setUp() { + context.load().json(TEST_CONTENT, GUIDE_CONTAINER_ROOT); + context.request().setResource(context.currentResource(GUIDE_CONTAINER_ROOT)); + } + + @Test + void testAutoSaveConfigurationForDefaultImplementation() { + final AutoSaveConfiguration autoSaveConfiguration = new AutoSaveConfiguration() { + + }; + assertEquals(false, autoSaveConfiguration.isEnableAutoSave()); + assertEquals(AutoSaveConfiguration.AutoSaveStrategyType.TIME, autoSaveConfiguration.getAutoSaveStrategyType()); + assertEquals((Integer) 0, autoSaveConfiguration.getAutoSaveInterval()); + } + + @Test + void testAutoSaveConfigurationForResourceAdaptation() { + + final AutoSaveConfiguration autoSaveConfiguration = context.currentResource(GUIDE_CONTAINER_ROOT).adaptTo( + AutoSaveConfiguration.class); + assertEquals(true, autoSaveConfiguration.isEnableAutoSave()); + assertEquals(AutoSaveConfiguration.AutoSaveStrategyType.TIME, autoSaveConfiguration.getAutoSaveStrategyType()); + assertEquals((Integer) 2, autoSaveConfiguration.getAutoSaveInterval()); + } + + @Test + void testAutoSaveConfigurationForRequestAdaptation() { + final AutoSaveConfiguration autoSaveConfiguration = context.request().adaptTo(AutoSaveConfiguration.class); + assertEquals(true, autoSaveConfiguration.isEnableAutoSave()); + assertEquals(AutoSaveConfiguration.AutoSaveStrategyType.TIME, autoSaveConfiguration.getAutoSaveStrategyType()); + assertEquals((Integer) 2, autoSaveConfiguration.getAutoSaveInterval()); + } + +} diff --git a/bundles/af-core/src/test/resources/form/formcontainer/exporter-formcontainerv2.json b/bundles/af-core/src/test/resources/form/formcontainer/exporter-formcontainerv2.json index d27184ca07..2a9db08623 100644 --- a/bundles/af-core/src/test/resources/form/formcontainer/exporter-formcontainerv2.json +++ b/bundles/af-core/src/test/resources/form/formcontainer/exporter-formcontainerv2.json @@ -8,6 +8,9 @@ "dorType": "generate", "dorTemplateRef": "xyz" }, + "fd:autoSave": { + "fd:enableAutoSave":false + }, "fd:path": "/content/forms/af/demo/jcr:content/formcontainerv2", "fd:schemaType": "BASIC", "fd:formDataEnabled": true, diff --git a/bundles/af-core/src/test/resources/form/formcontainer/test-content-auto-save.json b/bundles/af-core/src/test/resources/form/formcontainer/test-content-auto-save.json new file mode 100644 index 0000000000..6117603567 --- /dev/null +++ b/bundles/af-core/src/test/resources/form/formcontainer/test-content-auto-save.json @@ -0,0 +1,11 @@ +{ + "jcr:primaryType": "nt:unstructured", + "sling:resourceType" : "core/fd/components/form/container/v2/container", + "thankyouPage": "/a/b/c", + "thankyouMessage": "message", + "fieldType" : "form", + "prefillService" : "abc", + "fd:enableAutoSave": "true", + "fd:autoSaveInterval": "2", + "fd:autoSaveStrategyType": "time" +} diff --git a/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.granite.toggle.impl.dev.DynamicToggleProviderImpl.cfg.json b/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.granite.toggle.impl.dev.DynamicToggleProviderImpl.cfg.json index 86d79314d0..5b455dbc34 100644 --- a/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.granite.toggle.impl.dev.DynamicToggleProviderImpl.cfg.json +++ b/it/config/src/main/content/jcr_root/apps/system/config/com.adobe.granite.toggle.impl.dev.DynamicToggleProviderImpl.cfg.json @@ -18,6 +18,7 @@ "FT_FORMS-13209", "FT_FORMS-11581", "FT_FORMS-14545", - "FT_SITES-19631" + "FT_SITES-19631", + "FT_FORMS-14255" ] } diff --git a/it/content/src/main/content/META-INF/vault/filter.xml b/it/content/src/main/content/META-INF/vault/filter.xml index 6610ec450a..5ae72b9afa 100644 --- a/it/content/src/main/content/META-INF/vault/filter.xml +++ b/it/content/src/main/content/META-INF/vault/filter.xml @@ -6,6 +6,7 @@ + diff --git a/it/content/src/main/content/jcr_root/conf/global/settings/forms/.content.xml b/it/content/src/main/content/jcr_root/conf/global/settings/forms/.content.xml new file mode 100644 index 0000000000..a0ac99e384 --- /dev/null +++ b/it/content/src/main/content/jcr_root/conf/global/settings/forms/.content.xml @@ -0,0 +1,3 @@ + + diff --git a/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/.content.xml b/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/.content.xml new file mode 100644 index 0000000000..a0ac99e384 --- /dev/null +++ b/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/.content.xml @@ -0,0 +1,3 @@ + + diff --git a/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/portal/.content.xml b/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/portal/.content.xml new file mode 100644 index 0000000000..a0ac99e384 --- /dev/null +++ b/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/portal/.content.xml @@ -0,0 +1,3 @@ + + diff --git a/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/portal/portal/.content.xml b/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/portal/portal/.content.xml new file mode 100644 index 0000000000..3a6dde7cd0 --- /dev/null +++ b/it/content/src/main/content/jcr_root/conf/global/settings/forms/usc/portal/portal/.content.xml @@ -0,0 +1,10 @@ + + + + diff --git a/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/autosave/.content.xml b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/autosave/.content.xml new file mode 100644 index 0000000000..74aeef758a --- /dev/null +++ b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/autosave/.content.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/autosave/.content.xml b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/autosave/.content.xml new file mode 100644 index 0000000000..e4b53a79e9 --- /dev/null +++ b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/autosave/.content.xml @@ -0,0 +1,61 @@ + + + + + + + + + + diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v1/container/clientlibs/editor/js/editDialog.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v1/container/clientlibs/editor/js/editDialog.js index c1049dd3ef..58bca1b835 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v1/container/clientlibs/editor/js/editDialog.js +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v1/container/clientlibs/editor/js/editDialog.js @@ -41,6 +41,8 @@ REST_ENDPOINT = ".rest", FDM = ".fdm", EMAIL = ".email", + ENABLE_AUTO_SAVE = "[name='./fd:enableAutoSave']", + AUTO_SAVE_STRATEGY_CONTAINER = ".cmp-adaptiveform-container__autoSaveStrategyContainer", Utils = window.CQ.FormsCoreComponents.Utils.v1; @@ -419,6 +421,31 @@ } } + function showHideAutoSave(dialog) { + var enableAutoSave = dialog.find(ENABLE_AUTO_SAVE); + if (enableAutoSave[0]) { + var autoSaveStrategyContainer = dialog.find(AUTO_SAVE_STRATEGY_CONTAINER); + if (autoSaveStrategyContainer) { + if (enableAutoSave[0].checked) { + autoSaveStrategyContainer.show(); + } else { + autoSaveStrategyContainer.hide(); + } + } + } + } + + function registerAutoSaveDialogAction(dialog) { + var $subDialogContent = dialog.find(SUB_DIALOG_CONTENT); + $subDialogContent.on('foundation-contentloaded', function() { + showHideAutoSave(dialog); + }); + showHideAutoSave(dialog); + $(document).on('change', ENABLE_AUTO_SAVE, function () { + showHideAutoSave(dialog); + }); + } + $(window).adaptTo("foundation-registry").register("foundation.validation.validator", { selector : "[data-validation~='datamodel.config']", validate : function (el) { @@ -430,7 +457,7 @@ }); Utils.initializeEditDialog(EDIT_DIALOG_FORM)(handleAsyncSubmissionAndThankYouOption, handleSubmitAction, - registerSubmitActionSubDialogClientLibs, registerRestEndPointDialogClientlibs, registerFDMDialogClientlibs, registerEmailDialogClientlibs, initialiseDataModel); + registerSubmitActionSubDialogClientLibs, registerRestEndPointDialogClientlibs, registerFDMDialogClientlibs, registerEmailDialogClientlibs, initialiseDataModel, registerAutoSaveDialogAction); Utils.initializeEditDialog(EDIT_DIALOG_FRAGMENT)(initialiseDataModel); diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml index a7b43d2dad..119e49ce73 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml @@ -177,6 +177,12 @@ + { + formModel.dispatch(new FormView.Actions.Save({ + 'action': saveEndPoint + })); + }, parseInt(autoSaveInterval) * 1000); + } + } } } diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fragmentcontainer/v1/fragmentcontainer/_cq_dialog/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fragmentcontainer/v1/fragmentcontainer/_cq_dialog/.content.xml index 0653eb0e64..25a29e6942 100644 --- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fragmentcontainer/v1/fragmentcontainer/_cq_dialog/.content.xml +++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/fragmentcontainer/v1/fragmentcontainer/_cq_dialog/.content.xml @@ -64,6 +64,9 @@ jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/include" path="core/fd/components/form/container/v2/container/cq:dialog/content/items/tabs/items/dataModel"/> + diff --git a/ui.frontend/src/index.js b/ui.frontend/src/index.js index f9bc61b0f8..6d625af2bf 100644 --- a/ui.frontend/src/index.js +++ b/ui.frontend/src/index.js @@ -15,7 +15,7 @@ ******************************************************************************/ import Utils from "./utils.js"; import LanguageUtils from "./LanguageUtils.js"; -import {createFormInstance, FileObject, extractFileInfo, Click, Change, Submit, Blur, AddItem, RemoveItem, CustomEvent, UIChange} from "@aemforms/af-core"; +import {createFormInstance, FileObject, extractFileInfo, Click, Change, Submit, Save, Blur, AddItem, RemoveItem, CustomEvent, UIChange} from "@aemforms/af-core"; import {FormField, FormContainer, FormFieldBase, FormPanel, FormTabs, FormFileInput, FormOptionFieldBase, FormCheckBox, FormFileInputWidgetBase, FormFileInputWidget} from "./view/index.js"; import {Constants} from "./constants.js"; import GuideBridge from "./GuideBridge.js"; @@ -46,9 +46,10 @@ window.guideBridge = new GuideBridge(); * @property {string} Blur - The action for a blur event. * @property {string} AddItem - The action for adding an item. * @property {string} RemoveItem - The action for removing an item. + * @property {string} Save - The action for save event. */ const Actions = { - Click, Change, Submit, Blur, AddItem, RemoveItem, UIChange, CustomEvent + Click, Change, Submit, Blur, AddItem, RemoveItem, UIChange, Save, CustomEvent } /** diff --git a/ui.tests/test-module/specs/autosave/autosave.runtime.spec.js b/ui.tests/test-module/specs/autosave/autosave.runtime.spec.js new file mode 100644 index 0000000000..9c9c1e3d17 --- /dev/null +++ b/ui.tests/test-module/specs/autosave/autosave.runtime.spec.js @@ -0,0 +1,36 @@ +describe("Auto save handler runtime", () => { + + let toggle_array = []; + + before(() => { + cy.fetchFeatureToggles().then((response) => { + if (response.status === 200) { + toggle_array = response.body.enabled; + } + }); + }); + + const autoSaveRunTime = "content/forms/af/core-components-it/samples/autosave.html" + + it("should save formData after every 3 seconds", () => { + if (cy.af.isLatestAddon() && toggle_array.includes('FT_FORMS-14255')) { + + const saveApiResponse = { + 'draftId': 'ABC' + }; + // Rule when button is clicked then save call should trigger + cy.intercept('POST' , '**/adobe/forms/af/save/*', saveApiResponse).as('afSave'); + + cy.previewForm(autoSaveRunTime); + + cy.wait('@afSave').then(({request, response}) => { + // Check the request payload + expect(request.body).to.be.not.null; + + expect(response.statusCode).to.equal(200); + expect(response.body).to.be.not.null; + expect(response.body.draftId).to.equal('ABC'); + }); + } + }) +}) diff --git a/ui.tests/test-module/specs/formcontainer.spec.js b/ui.tests/test-module/specs/formcontainer.spec.js index b32695b8d5..803df179b2 100644 --- a/ui.tests/test-module/specs/formcontainer.spec.js +++ b/ui.tests/test-module/specs/formcontainer.spec.js @@ -65,6 +65,19 @@ describe('Page/Form Authoring', function () { cy.get("[name='./title'").should("have.value", "Adaptive Form V2 (IT)"); } + const checkAutoSaveTab = function(formContainerEditPathSelector) { + cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + formContainerEditPathSelector); + cy.invokeEditableAction("[data-action='CONFIGURE']"); + // Open auto save tab + cy.get('.cmp-adaptiveform-container'+'__editdialog').contains('Auto-save').click({force:true}); + cy.get("coral-checkbox[name='./fd:enableAutoSave']").should("exist"); + cy.get("coral-checkbox[name='./fd:enableAutoSave']").click({force:true}); + cy.get("coral-select[name='./fd:autoSaveStrategyType']").should("exist"); + cy.get("coral-numberinput[name='./fd:autoSaveInterval']").should("exist"); + } + + + const checkAndSaveSubmitAction = function(formContainerEditPathSelector) { // click configure action on adaptive form container component cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + formContainerEditPathSelector); @@ -195,7 +208,14 @@ describe('Page/Form Authoring', function () { it ('check title in edit dialog', {retries: 3}, function() { checkTitleInEditDialog(formContainerEditPathSelector); cy.get('.cq-dialog-cancel').click(); - }) + }); + + it('open edit dialog, verify auto save tab in container edit dialog box', {retries: 3},function () { + if (cy.af.isLatestAddon() && toggle_array.includes("FT_FORMS-14255")) { + checkAutoSaveTab(formContainerEditPathSelector); + } + }); + }); // commenting once we support adaptive form container in sites editor, uncomment this test