Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort Nodes: tool to sort JCR nodes by node name or title #2537

Closed

Conversation

YegorKozlov
Copy link
Contributor

@YegorKozlov YegorKozlov commented Feb 28, 2021

Sometimes it is useful to re-order nodes in the repository by node name or title so that:

  1. Nodes are sorted in all views in AEM TouchUI. Only the List View of the 'collectionpage' container in AEM supports sorting, other views like Card and Column print items in the default order which is by jcr:created. This makes it difficult to browse pages or tags with large number of children.
  2. Node iterators in Java return sorted data.
  3. User can choose whether to sort by node name or jcr:title

The patch extends the Sling POST Servlet with the acs-commons:sortNodes operation and and a simple GUI to execute it:

sort children of /content/someFolder by node name, case-insensitive (defaults)

curl -F":operation=acs-commons:sortNodes" http://localhost:4502/content/someFolder

sort children of /content/someFolder by jcr:title, case-sensitive

curl -F":operation=acs-commons:sortNodes" \
-F":sorterName=byTitle" \
-F":caseSensitive=true" \
http://localhost:4502/content/someFolder

AEM GUI

In AEM, navigate to the Tools > ACS AEM Commons > Sort JCR Nodes

In the path field, enter the the target path to sort. You can choose whether to sort by node name (default) or by jcr:title and whether sort should be case-sensitive.

image

Request Parameters

:sorterName

To select the actual sorter to execute, the :sorterName request parameter is used. Out of the box, the SortNodesOperation supports the following sorters:

Sorter Description
byName Sort nodes by node name (default)
byTitle Sort nodes by jcr:title. The code will use the value of the jcr:title property of the underlying node or of it's jcr:content child node if it exists or default to node name of jcr:title was not found

:caseSensitive

Optional boolean parameter to control whether sort should be case sensitive (default: false), e.g.

+  /content/someFolder
     -  a           
     -  A           
     -  b           
     -  B           

You can turn it off by setting the -F":caseSensitive=true" request parameter and the order will change to

+  /content/someFolder
     -  A           
     -  B           
     -  a           
     -  b           

:nonHierarchyFirst

Optional boolean parameter to control whether sort should move non-hierarchy nodes to the top (default: true)

The default value is true which means jcr:content, rep:policy and such will be sorted first followed by other, hierarchy nodes like cq:Page, e.g.

+  /content/someFolder
     -  jcr:content // non-hierarchy
     -  rep:policy  // non-hierarchy
     -  a           // cq:Page
     -  b           // cq:Page
     -  c           // cq:Page
     -  p           // cq:Page

You can turn it off by setting the -F":nonHierarchyFirst=false" parameter
which will switch the mode to sort nodes regardless if they are nt:hierarchyNode or not

+  /content/someFolder
     -  a           // cq:Page
     -  b           // cq:Page
     -  c           // cq:Page
     -  jcr:content // non-hierarchy
     -  p           // cq:Page
     -  rep:policy  // non-hierarchy

Extending SortNodesOperation

OSGi services of the com.adobe.acs.commons.sorter.NodeSorter type can be used to implement new node sorters. For example, to register a sorter by sling:resourceType deploy the service below:

import com.adobe.acs.commons.sorter.NodeSorter;
import org.apache.jackrabbit.commons.JcrUtils;
import org.osgi.service.component.annotations.Component;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.servlet.http.HttpServletRequest;
import java.util.Comparator;


@Component
public class ResourceTypeSorter implements NodeSorter {

    /**
     * A unique name which will be used to find the actual sorter by the
     * <code>:sorterName</code> request parameter
     */
    @Override
    public String getName() {
        return "resourceType";
    }

    /**
     * The label that will appear in the 'Select Sorter' drop-down in UI
     */
    @Override
    public String getLabel() {
        return "By resource type";
    }

    /**
     * Create a comparator to sort nodes.
     * Implementations can read additional parameters from request, e.g.
      * whether search should be case-sensitive, ascending/descending, etc.
    */
    @Override
    public Comparator<Node> createComparator(HttpServletRequest request) {

        return (n1, n2) -> {
            try {
                String val1 = JcrUtils.getStringProperty(n1, "jcr:content/sling:resourceType", "");
                String val2 = JcrUtils.getStringProperty(n2, "jcr:content/sling:resourceType", "");
                return val1.compareTo(val2);
            } catch (RepositoryException e) {
                return 0;
            }
        };
    }

}

Once the ResourceTypeSorter service is deployed you should be able to select the new sorter in the UI:

image

or pass it as -F":sorterName=resourceType" request parameter to curl:

curl -F":operation=acs-commons:sortNodes" -F":sorterName=resourceType" \
   http://localhost:4502/content/we-retail

Documentation is in another PR: Adobe-Consulting-Services/adobe-consulting-services.github.io#205

@YegorKozlov
Copy link
Contributor Author

The Cognitive Complexity warning should be ignored. I'd like to keep that method as it is

@badvision
Copy link
Contributor

All you have to do is take the body of each of the conditional statements and make each its own method.
Arguably, as separate methods these are individually more testable as well. Therefore I think the cognitive complexity warning is justified here.

@shsteimer
Copy link
Contributor

2 notes of unsolicited feedback

  1. "Nodes are sorted in all views in AEM TouchUI. Only the List View of the 'collectionpage' container in AEM supports sorting, other views like Card and Column print items in the default order which is by jcr:created. This makes it difficult to browse pages or tags with large number of children." This is no longer true as of 6.5 SP7 and the January release of cloud service. Not that this invalidates the feature, but just an FYI
  2. I think the UI would be more intuitive if the sort options were a dropdown with options for "by name" and "by title." This is more in line with the general UI paradigms folks are used to for sorting, and also would allow additional sort modes to be added later without littering the screen with additional checkboxes.

@davidjgonzalez
Copy link
Contributor

Understanding this a bigger change, but WDYT about allowing for the sorting to be pluggable, so users could implement their own sorters? We could provide an "OOTB" sorter Title, but someone could create one for last modified, or whatever?

I think the sorting of the hierarchy first could be OOTB and apply to any potential sorter.

In the Conf UI, we could have a dropdown that is driven by a datasource that lists all available sorters in the system.

WDYT, overkill? This is a great feature, i just expect ppl would like to sort on custom attributes as well (or things that are not title).

@davidjgonzalez davidjgonzalez added this to the 4.12.0 milestone Feb 28, 2021
@YegorKozlov
Copy link
Contributor Author

Understanding this a bigger change, but WDYT about allowing for the sorting to be pluggable, so users could implement their own sorters? We could provide an "OOTB" sorter Title, but someone could create one for last modified, or whatever?

It might be a good idea. NodeComparator will be a pluggable service and the POST operation will somehow resolve it from the request. The OOTB implementation will include NodeName and NodeTitle implementations and user can plug in their custom sorters.

@YegorKozlov
Copy link
Contributor Author

  1. "Nodes are sorted in all views in AEM TouchUI. Only the List View of the 'collectionpage' container in AEM supports sorting, other views like Card and Column print items in the default order which is by jcr:created. This makes it difficult to browse pages or tags with large number of children." This is no longer true as of 6.5 SP7 and the January release of cloud service. Not that this invalidates the feature, but just an FYI

Good to know. I still I think my tool will be useful . 6.5 SP7+ might support sorting in collection views, but not in the pathbrowser component which shows items in their repository order.

  1. I think the UI would be more intuitive if the sort options were a dropdown with options for "by name" and "by title." This is more in line with the general UI paradigms folks are used to for sorting, and also would allow additional sort modes to be added later without littering the screen with additional checkboxes.

Agree. A drop-down would be more intuitive.

@YegorKozlov
Copy link
Contributor Author

YegorKozlov commented Mar 6, 2021

I checked-in support for pluggable sorters and updated the UI to select a sorter from a drop-down, see the updated screenshots

@coveralls
Copy link

coveralls commented Mar 7, 2021

Pull Request Test Coverage Report for Build 6322

  • 76 of 98 (77.55%) changed or added relevant lines in 6 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.07%) to 55.699%

Changes Missing Coverage Covered Lines Changed/Added Lines %
bundle/src/main/java/com/adobe/acs/commons/sorter/NodeSorter.java 0 1 0.0%
bundle/src/main/java/com/adobe/acs/commons/sorter/impl/HierarchyNodeComparator.java 4 6 66.67%
bundle/src/main/java/com/adobe/acs/commons/sorter/impl/NodeNameSorter.java 11 14 78.57%
bundle/src/main/java/com/adobe/acs/commons/sorter/SortersPojo.java 0 4 0.0%
bundle/src/main/java/com/adobe/acs/commons/sorter/impl/NodeTitleSorter.java 14 18 77.78%
bundle/src/main/java/com/adobe/acs/commons/sorter/SortNodesOperation.java 47 55 85.45%
Totals Coverage Status
Change from base Build 6314: 0.07%
Covered Lines: 16132
Relevant Lines: 28963

💛 - Coveralls

@davidjgonzalez
Copy link
Contributor

This was merged through #2544 which included a switch from WCMUse to SlingModel for the Sorters util

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants