Skip to content

Commit

Permalink
[FORMS-8058] implement review component
Browse files Browse the repository at this point in the history
add css for now
  • Loading branch information
Amit Kumar committed Oct 29, 2024
1 parent 5092694 commit 5ef355c
Show file tree
Hide file tree
Showing 36 changed files with 2,630 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,10 @@ private FormConstants() {
public static final String REQ_ATTR_REFERENCED_PATH = "referencedPage";

public static final String PROP_FRAGMENT_PATH = "fragmentPath";

/** The resource type for review v1 */
public static final String RT_FD_FORM_REVIEW_V1 = RT_FD_FORM_PREFIX + "review/v1/review";

/* The resource type for the pre-selected the linked panel */
public final static String RT_FD_FORM_REVIEW_DATASOURCE_V1 = RT_FD_FORM_PREFIX + "review/v1/datasource";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 2023 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.v1.form;

import java.util.Arrays;
import java.util.Map;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import com.adobe.cq.forms.core.components.internal.form.FormConstants;
import com.adobe.cq.forms.core.components.models.form.Review;
import com.adobe.cq.forms.core.components.util.AbstractBaseImpl;
import com.fasterxml.jackson.annotation.JsonIgnore;

@Model(
adaptables = { SlingHttpServletRequest.class, Resource.class },
adapters = { Review.class,
ComponentExporter.class },
resourceType = { FormConstants.RT_FD_FORM_REVIEW_V1 })
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ReviewImpl extends AbstractBaseImpl implements Review {

private static final String LINKED_PANEL_PROPERTY = "fd:linkedPanels";
private static final String EDIT_ACTION_PROPERTY = "fd:editAction";

@JsonIgnore
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = "linkedPanels")
@Nullable
private String[] linkedPanels;

public String[] getLinkedPanels() {
return linkedPanels != null ? Arrays.copyOf(linkedPanels, linkedPanels.length) : new String[] {};
}

@JsonIgnore
@ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL, name = "editAction")
@Nullable
private String editAction;

public String getEditAction() {
return editAction;
}

@Override
public @NotNull Map<String, Object> getProperties() {
Map<String, Object> customProperties = super.getProperties();
customProperties.put(LINKED_PANEL_PROPERTY, getLinkedPanels());
customProperties.put(EDIT_ACTION_PROPERTY, getEditAction());
return customProperties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 2023 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.servlets;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Servlet;

import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.SyntheticResource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.jetbrains.annotations.NotNull;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.forms.core.components.internal.form.FormConstants;
import com.adobe.cq.forms.core.components.models.form.Base;
import com.adobe.cq.forms.core.components.models.form.Container;
import com.adobe.cq.forms.core.components.models.form.FormComponent;
import com.adobe.cq.forms.core.components.models.form.FormContainer;
import com.adobe.cq.forms.core.components.models.form.Label;
import com.adobe.cq.forms.core.components.util.ComponentUtils;
import com.adobe.granite.ui.components.ExpressionResolver;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;

@Component(
service = { Servlet.class },
property = {
"sling.servlet.resourceTypes=" + FormConstants.RT_FD_FORM_REVIEW_DATASOURCE_V1,
"sling.servlet.methods=GET",
"sling.servlet.extensions=html"
})
public class ReviewDataSourceServlet extends AbstractDataSourceServlet {

/**
* Defines the form meta data type. Possible values: {@code submitAction},
* {@code prefillServiceProvider}
*
* @todo: Add other metadata types here like fragment, actions etc
*/
@Reference
private transient ExpressionResolver expressionResolver;

private static final Logger LOGGER = LoggerFactory.getLogger(ReviewDataSourceServlet.class);

@NotNull
@Override
protected ExpressionResolver getExpressionResolver() {
return expressionResolver;
}

@Override
protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response) {

ResourceResolver resourceResolver = request.getResourceResolver();
String componentInstancePath = request.getRequestPathInfo().getSuffix();
List<Resource> resources = new ArrayList<>();
if (resourceResolver != null) {
Resource componentInstance = resourceResolver.getResource(componentInstancePath);
Resource formInstance = ComponentUtils.getFormContainer(componentInstance);
FormContainer formContainer = formInstance.adaptTo(FormContainer.class);
List<Base> panels = (List<Base>) getPanels(formContainer);
for (Base panel : panels) {
String name = panel != null ? panel.getName() : "";
String title = "";
if (panel != null) {
Label label = panel.getLabel();
if (label != null) {
String value = label.getValue();
if (value != null) {
title = value;
}
}
}
if (name != null && title != null) {
resources.add(getResourceForDropdownDisplay(resourceResolver, title, name));
} else {
LOGGER.warn("[AF] name or title is null");
}
}
}
SimpleDataSource actionTypeDataSource = new SimpleDataSource(resources.iterator());
request.setAttribute(DataSource.class.getName(), actionTypeDataSource);
}

private List<? extends ComponentExporter> getPanels(FormComponent formContainer) {
if (formContainer instanceof FormContainer) {
while (formContainer instanceof Container && ((Container) formContainer).getItems().size() == 1) {
formContainer = (FormComponent) ((Container) formContainer).getItems().get(0);
}
if (formContainer instanceof Container) {
return ((Container) formContainer).getItems();
}
}
return new ArrayList<>();
}

private SyntheticResource getResourceForDropdownDisplay(ResourceResolver resourceResolver, String displayValue,
String dataValue) {
Map<String, Object> dropdownMap = new HashMap<>();
dropdownMap.put("text", displayValue);
dropdownMap.put("value", dataValue);
ValueMap dropdownEntryVm = new ValueMapDecorator(dropdownMap);
return new ValueMapResource(resourceResolver, "", JcrConstants.NT_UNSTRUCTURED, dropdownEntryVm);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright 2023 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.osgi.annotation.versioning.ConsumerType;

/**
* Defines the {@code Review} Sling Model used for the {@code /apps/core/fd/components/form/review} component.
*
* @since com.adobe.cq.forms.core.components.models 2.1.0
*/
@ConsumerType
public interface Review extends Base {
default String[] getLinkedPanels() {
return new String[] {};
}

default String getEditAction() {
return "";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ 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.v1.form;

import java.io.IOException;
import java.util.Map;

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.Utils;
import com.adobe.cq.forms.core.components.models.form.Review;
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.jupiter.api.Assertions.*;

@ExtendWith(AemContextExtension.class)
public class ReviewImplTest {

private final AemContext context = FormsCoreComponentTestContext.newAemContext();
private static final String TEST_BASE = "/form/review";
private static final String APPS_ROOT = "/apps";
private static final String PATH_REVIEW = "/apps/formcontainer/wizard/panel2/review";

@BeforeEach
void setUp() throws Exception {
context.load().json(TEST_BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, APPS_ROOT);
}

@Test
void testGetEditAction() {
Review review = Utils.getComponentUnderTest(PATH_REVIEW, ReviewImpl.class, context);
assertEquals("field", review.getEditAction());
}

@Test
public void testGetLinkedPanelsWithNonNullArray() throws IOException {
Review review = Utils.getComponentUnderTest(PATH_REVIEW, ReviewImpl.class, context);
String[] linkedPanels = review.getLinkedPanels();
String[] expectedLinkedPanels = context.resourceResolver().getResource(PATH_REVIEW).getValueMap().get("linkedPanels",
String[].class);
assertNotNull(expectedLinkedPanels);
assertArrayEquals(expectedLinkedPanels, linkedPanels);
}

@Test
public void testGetLinkedPanelsWithNullArray() {
Review review = new ReviewImpl();
String[] linkedPanels = review.getLinkedPanels();
assertNotNull(linkedPanels);
assertEquals(0, linkedPanels.length);
}

@Test
void testGetProperties() {
Review review = Utils.getComponentUnderTest(PATH_REVIEW, ReviewImpl.class, context);
Map<String, Object> properties = review.getProperties();
assertEquals("/apps/formcontainer/wizard/panel2/review", properties.get("fd:path"));
assertEquals("field", properties.get("editAction"));

}

}
Loading

0 comments on commit 5ef355c

Please sign in to comment.