AEM 62 - Touch UI Add Custom Columns to Assets Omni Search List View

Goal


Give AEM admin the flexibility to add additional columns in Assets Omni Search List View - http://localhost:4502/assets.html

Thank you ACS Commons for the Generic Lists

For adding custom columns to Assets List View check this post

For adding custom columns to Reports Console check this post

For AEM 65 check this post

Demo | Package Install | Source Code | GitHub


Configure Columns

                http://localhost:4502/etc/experience-aem/omni-search-columns.html



Custom Omni Search Columns



Solution


1) Create the extension nt:folder /apps/eaem-omni-search-dynamic-columns

2) Add the ACS Commons Generic List in nt:folder /apps/eaem-omni-search-dynamic-columns/components/apps/eaem-omni-search-dynamic-columns/templates (available in Package Install if installing the extension)

3) Create OSGI servlet apps.experienceaem.omnisearch.MetadataResultsServlet with the following code, to get the custom column values; eg. http://localhost:4502/bin/eaem/metadataResults.json?paths=/content/dam/geometrixx/shapes/cir_circle.png,/content/dam/geometrixx/shapes/sq_cube.png

package apps.experienceaem.omnisearch;

import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.sling.SlingServlet;
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.ValueMap;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@SlingServlet(paths = "/bin/eaem/metadataResults",
        methods = "GET",
        metatype = true,
        label = "Experience AEM Metadata Results Servlet",
        extensions = "json")
public class MetadataResultsServlet extends SlingAllMethodsServlet{
    private static final Logger log = LoggerFactory.getLogger(MetadataResultsServlet.class);

    private static String OMNI_SEARCH_COL_CONFIG = "/etc/experience-aem/omni-search-columns/jcr:content/list";

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {
        ResourceResolver resourceResolver = request.getResourceResolver();

        try{
            JSONObject jsonResponse = new JSONObject();

            String paths = request.getParameter("paths");

            if(StringUtils.isEmpty(paths)){
                return;
            }else{
                List<String> configList = getOmniSearchConfigValues(resourceResolver.getResource(OMNI_SEARCH_COL_CONFIG));

                Resource resource, propResource;
                String parentPath, propName, propValue;

                JSONObject valueObj;

                for(String path : paths.split(",")){
                    resource = resourceResolver.getResource(path);

                    if(resource == null){
                        continue;
                    }

                    valueObj = new JSONObject();

                    for(String relPath : configList){
                        parentPath = relPath.substring(0, relPath.lastIndexOf("/"));
                        propName = relPath.substring(relPath.lastIndexOf("/") + 1);

                        propResource = resource.getChild(parentPath);

                        if(propResource == null){
                            continue;
                        }

                        propValue = propResource.adaptTo(ValueMap.class).get(propName, "");

                        valueObj.put(relPath, propValue);
                    }

                    jsonResponse.put(path, valueObj);
                }
            }

            jsonResponse.write(response.getWriter());
        }catch(Exception e){
            log.error("Error reading collections", e);
        }

    }

    public List<String> getOmniSearchConfigValues(Resource managedListResource) {
        List<String> configList = new ArrayList<String>();

        try {
            Iterator<Resource> managedList = managedListResource.listChildren();

            while (managedList.hasNext()) {
                Resource r = managedList.next();
                Node resNode = r.adaptTo(Node.class);

                if (!resNode.hasProperty("value")) {
                    continue;
                }

                configList.add(resNode.getProperty("value").getString());
            }

        } catch (RepositoryException re) {
            log.error("Error getting list values", re);
        }

        return configList;
    }
}


3) Create cq:ClientLibraryFolder /apps/eaem-omni-search-dynamic-columns/clientlib with categories dam.gui.admin.util and dependencies underscore

4) Create nt:file /apps/eaem-omni-search-dynamic-columns/clientlib/js.txt with the following content

                  dynamic-columns.js

5) Create nt:file /apps/eaem-omni-search-dynamic-columnss/clientlib/dynamic-columns.js with the following code

(function ($, $document) {
    var FOUNDATION_CONTENT_LOADED = "foundation-contentloaded",
        ROW_SELECTOR = "tr.foundation-collection-item",
        GRANITE_OMNI_SEARCH_RESULT = "#granite-omnisearch-result",
        COLUMN_LIST = "/etc/experience-aem/omni-search-columns/_jcr_content.list.json",
        COLUMN_CONFIG = {},
        METADATA_MAPPING = "data-metadata-mapping",
        RESULTS_URL = "/bin/eaem/metadataResults.json",
        GRANITE_OMNI_SEARCH_CONTENT = ".granite-omnisearch-content";

    loadColumnsConfiguration();

    $document.on(FOUNDATION_CONTENT_LOADED, GRANITE_OMNI_SEARCH_CONTENT, function(event){
        _.defer(function(){
            handleContentLoad(event);
        });
    });

    function handleContentLoad(event){
        var layout = $(GRANITE_OMNI_SEARCH_RESULT).data("foundationLayout");

        if(!layout || (layout.layoutId !== "list")){
            return;
        }

        addColumnHeaders();

        fillColumnData();
    }

    function fillColumnData(){
        var $fui = $(window).adaptTo("foundation-ui");

        $fui.wait();

        $.ajax({
            type: "POST",
            dataType: "json",
            url: RESULTS_URL,
            data: {
                paths: getPaths().join(",")
            }
        }).done(collectionIterate);

        function collectionIterate(data){
            $(ROW_SELECTOR).each(function(index, item){
                itemHandler(data, $(item) );
            });

            $fui.clearWait();
        }

        function itemHandler(data, $row){
            if(!_.isEmpty($row.find("[" + METADATA_MAPPING + "]"))){
                return;
            }

            var itemPath = $row.data("foundation-collection-item-id"), metaValue;

            _.each(COLUMN_CONFIG, function(colName, colMetaPath){
                metaValue = data[itemPath][colMetaPath] || "";
                $row.append(getListCellHtml(colMetaPath, metaValue));
            });
        }
    }

    function getPaths(){
        var paths = [], $item;

        $(ROW_SELECTOR).each(function(index, item){
            $item = $(item);

            if(!_.isEmpty($item.find("td[" + METADATA_MAPPING + "]"))){
                return;
            }

            paths.push($item.data("foundation-collection-item-id"));
        });

        return paths;
    }

    function addColumnHeaders(){
        if(checkIFHeadersAdded()){
            return;
        }

        var headerHtml,
            $container = $(GRANITE_OMNI_SEARCH_CONTENT),
            $headRow = $container.find("thead > tr");

        _.each(COLUMN_CONFIG, function(headerText, metaRelPath){
            headerHtml = getTableHeader(metaRelPath, headerText);
            $headRow.append(headerHtml);
        });
    }

    function checkIFHeadersAdded(){
        return !_.isEmpty($(GRANITE_OMNI_SEARCH_CONTENT).find("tr").find("[" + METADATA_MAPPING + "]"));
    }

    function getListCellHtml(colMapping, colValue){
        return '<td is="coral-td" class="coral-Table-cell coral-Table-cell--left" alignment="column" '
                    + METADATA_MAPPING + '="' + colMapping + '">' +
                    '<coral-td-label class="coral-Table-cellLabel">'
                        + colValue +
                    '</coral-td-label>' +
                '</td>';
    }

    function getTableHeader(colMapping, colText) {
        return '<th is="coral-th" '
            + METADATA_MAPPING + '="' + colMapping + '">'
            + colText
            + '</th>';
    }

    function loadColumnsConfiguration(){
        $.ajax({
            url: COLUMN_LIST
        }).done(function(data){
            _.each(data, function(item){
                COLUMN_CONFIG[item.value] = item.text;
            })
        });
    }
})(jQuery, jQuery(document));



2 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. Hi Could you please help me on how to customize the omnisearch based on the some custom properties.

    ReplyDelete