From 5b7ba6c14676a5daa28a1ccdce686e8c93599f64 Mon Sep 17 00:00:00 2001 From: Jens Pelzetter Date: Wed, 27 Jan 2021 21:20:49 +0100 Subject: [PATCH] DocumentFolderBrower view for content sections Former-commit-id: e5187599647952639ed34795af89ef410124a2fa --- .../librecms/ui/ContentSectionController.java | 127 ++++++++++++- .../org/librecms/ui/ContentSectionModel.java | 13 ++ .../ui/DocumentFolderBreadcrumbModel.java | 46 +++++ .../org/librecms/ui/DocumentFolderModel.java | 20 +- .../librecms/ui/DocumentFolderRowModel.java | 10 + .../java/org/librecms/ui/FolderTreeNode.java | 88 +++++++++ .../resources/components/cms/treeNode.xhtml | 66 +++++++ .../contentsection-not-found.xhtml | 2 +- .../ui/content-section/contentsection.xhtml | 6 +- .../document-folder-not-found.xhtml | 27 +++ .../ui/content-section/document-folder.xhtml | 172 +++++++++++++----- .../ui/content-section/testdata.xhtml | 2 +- .../org/librecms/CmsAdminMessages.properties | 10 +- .../librecms/CmsAdminMessages_de.properties | 10 +- .../main/scss/content-sections/_custom.scss | 2 +- 15 files changed, 530 insertions(+), 71 deletions(-) create mode 100644 ccm-cms/src/main/java/org/librecms/ui/DocumentFolderBreadcrumbModel.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/FolderTreeNode.java create mode 100644 ccm-cms/src/main/resources/META-INF/resources/components/cms/treeNode.xhtml create mode 100644 ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/document-folder-not-found.xhtml diff --git a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionController.java b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionController.java index 3fce2b44b..3c6e73891 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionController.java @@ -9,7 +9,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.libreccm.api.Identifier; import org.libreccm.api.IdentifierParser; -import org.libreccm.core.CcmObject; import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.PermissionChecker; @@ -26,12 +25,15 @@ import org.librecms.contentsection.DocumentFolderEntry; import org.librecms.contentsection.Folder; import org.librecms.contentsection.FolderManager; import org.librecms.contentsection.FolderRepository; +import org.librecms.contentsection.FolderType; import org.librecms.contentsection.privileges.ItemPrivileges; import org.librecms.contenttypes.Article; import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; @@ -111,11 +113,13 @@ public class ContentSectionController { private PermissionChecker permissionChecker; @GET - @Path("/document-folders") + @Path("/document-folders{folderPath:(/.+)?}") @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public String listItems( @PathParam("sectionIdentifier") final String sectionIdentifier, + @PathParam("folderPath") final String folderPath, + @QueryParam("filterTerm") @DefaultValue("") final String filterTerm, @QueryParam("firstResult") @DefaultValue("0") final int firstResult, @QueryParam("maxResults") @DefaultValue("20") final int maxResults ) { @@ -155,22 +159,60 @@ public class ContentSectionController { System.currentTimeMillis() - permissionCheckStart ); + final Folder folder; + if (folderPath.isBlank()) { + folder = section.getRootDocumentsFolder(); + documentFolderModel.setBreadcrumbs(Collections.emptyList()); + } else { + final Optional folderResult = folderRepo + .findByPath(section, + folderPath, + FolderType.DOCUMENTS_FOLDER + ); + if (folderResult.isPresent()) { + folder = folderResult.get(); + final List breadcrumbs + = new ArrayList<>(); + final List tokens = Arrays + .stream(folderPath.split("/")) + .filter(token -> !token.isEmpty()) + .collect(Collectors.toList()); + for (final String token : tokens) { + final String path = breadcrumbs + .stream() + .map(DocumentFolderBreadcrumbModel::getPathToken) + .collect(Collectors.joining("/")); + final DocumentFolderBreadcrumbModel breadcrumb + = new DocumentFolderBreadcrumbModel(); + breadcrumb.setPath(path); + breadcrumb.setPathToken(token); + breadcrumbs.add(breadcrumb); + } + breadcrumbs + .get(breadcrumbs.size() - 1) + .setCurrentFolder(true); + documentFolderModel.setBreadcrumbs(breadcrumbs); + } else { + models.put("contentSection", section.getLabel()); + models.put("folderPath", folderPath); + return "org/librecms/ui/content-section/document-folder-not-found.xhtml"; + } + } + final long objectsStart = System.currentTimeMillis(); final List folderEntries = folderRepo .getDocumentFolderEntries( - section.getRootDocumentsFolder(), + folder, firstResult, maxResults, - "" + filterTerm ); LOGGER.info( "Retrieved objects in {} ms", System.currentTimeMillis() - objectsStart ); documentFolderModel.setCount( - folderRepo.countDocumentFolderEntries( - section.getRootDocumentsFolder(), "" - ) + folderRepo.countDocumentFolderEntries(folder, filterTerm) ); documentFolderModel.setFirstResult(firstResult); documentFolderModel.setMaxResults(maxResults); @@ -179,6 +221,8 @@ public class ContentSectionController { System.currentTimeMillis() - objectsStart ); + contentSectionModel.setFolders(buildFolderTree(section, folder)); + final long rowsStart = System.currentTimeMillis(); documentFolderModel.setRows( folderEntries @@ -186,8 +230,10 @@ public class ContentSectionController { .map(entry -> buildRowModel(section, entry)) .collect(Collectors.toList()) ); - LOGGER.info("Build rows in {} ms.", System.currentTimeMillis() - - rowsStart); + LOGGER.info( + "Build rows in {} ms.", + System.currentTimeMillis() - rowsStart + ); return "org/librecms/ui/content-section/document-folder.xhtml"; } else { @@ -294,6 +340,60 @@ public class ContentSectionController { } } + private List buildFolderTree( + final ContentSection section, final Folder currentFolder + ) { + final Folder root = section.getRootDocumentsFolder(); + final String currentFolderPath = folderManager + .getFolderPath(currentFolder) + .substring( + folderManager + .getFolderPath(section.getRootDocumentsFolder()) + .length() - 1 + ); + + return root + .getSubFolders() + .stream() + .sorted() + .map(folder -> buildFolderTreeNode(section, currentFolderPath, + folder)) + .collect(Collectors.toList()); + } + + private FolderTreeNode buildFolderTreeNode( + final ContentSection section, + final String currentFolderPath, + final Folder folder + ) { + final String folderPath = folderManager + .getFolderPath(folder) + .substring( + folderManager + .getFolderPath(section.getRootDocumentsFolder()) + .length() - 1 + ); + + final FolderTreeNode node = new FolderTreeNode(); + node.setFolderId(folder.getObjectId()); + node.setUuid(folder.getUuid()); + node.setName(folder.getName()); + node.setOpen(currentFolderPath.startsWith(folderPath)); + node.setSelected(currentFolderPath.equals(folderPath)); + node.setSubFolders( + folder + .getSubFolders() + .stream() + .sorted() + .map(subFolder -> buildFolderTreeNode(section, + currentFolderPath, + subFolder)) + .collect(Collectors.toList()) + ); + + return node; + } + private DocumentFolderRowModel buildRowModel( final ContentSection section, final DocumentFolderEntry entry ) { @@ -312,6 +412,15 @@ public class ContentSectionController { == FolderManager.FolderIsDeletable.YES ); row.setFolder(true); + row.setFolderPath( + folderManager + .getFolderPath(folder) + .substring( + folderManager + .getFolderPath(section.getRootDocumentsFolder()) + .length() + ) + ); row.setLanguages(Collections.emptySortedSet()); row.setLastEditPublished(false); row.setLastEdited(""); diff --git a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionModel.java b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionModel.java index b901c04ad..5a85bc951 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionModel.java +++ b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionModel.java @@ -7,6 +7,9 @@ package org.librecms.ui; import org.librecms.contentsection.ContentSection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.Optional; @@ -23,6 +26,8 @@ public class ContentSectionModel { private ContentSection section; + private List folders; + protected void setSection(final ContentSection section) { this.section = Objects.requireNonNull( section, "Parameter section can't be null" @@ -36,4 +41,12 @@ public class ContentSectionModel { .orElse(""); } + public List getFolders() { + return Collections.unmodifiableList(folders); + } + + protected void setFolders(final List folders) { + this.folders = new ArrayList<>(folders); + } + } diff --git a/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderBreadcrumbModel.java b/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderBreadcrumbModel.java new file mode 100644 index 000000000..15be9ecb0 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderBreadcrumbModel.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui; + +/** + * + * @author Jens Pelzetter + */ +public class DocumentFolderBreadcrumbModel { + + private String pathToken; + + private String path; + + private boolean currentFolder; + + public String getPathToken() { + return pathToken; + } + + public void setPathToken(final String pathToken) { + this.pathToken = pathToken; + } + + public String getPath() { + return path; + } + + public void setPath(final String path) { + this.path = path; + } + + public boolean isCurrentFolder() { + return currentFolder; + } + + public void setCurrentFolder(final boolean currentFolder) { + this.currentFolder = currentFolder; + } + + + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderModel.java b/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderModel.java index f83431df5..1ac295a7c 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderModel.java +++ b/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderModel.java @@ -29,6 +29,8 @@ public class DocumentFolderModel { private List rows; + private List breadcrumbs; + public long getCount() { return count; } @@ -41,6 +43,7 @@ public class DocumentFolderModel { return firstResult; } + protected void setFirstResult(final int firstResult) { this.firstResult = firstResult; } @@ -52,13 +55,13 @@ public class DocumentFolderModel { protected void setMaxResults(final int maxResults) { this.maxResults = maxResults; } - + public long getNumberOfPages() { return (long) Math.ceil((double) count / maxResults); } - + public long getCurrentPage() { - return (long) Math.ceil((double) firstResult / maxResults ) + 1; + return (long) Math.ceil((double) firstResult / maxResults) + 1; } public List getRows() { @@ -68,5 +71,16 @@ public class DocumentFolderModel { protected void setRows(final List rows) { this.rows = new ArrayList<>(rows); } + + + public List getBreadcrumbs() { + return Collections.unmodifiableList(breadcrumbs); + } + + public void setBreadcrumbs( + final List breadcrumbs + ) { + this.breadcrumbs = new ArrayList<>(breadcrumbs); + } } diff --git a/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderRowModel.java b/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderRowModel.java index e3afc3b2b..3baba5db3 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderRowModel.java +++ b/ccm-cms/src/main/java/org/librecms/ui/DocumentFolderRowModel.java @@ -19,6 +19,8 @@ public class DocumentFolderRowModel { private boolean deletable; private boolean folder; + + private String folderPath; private SortedSet languages; @@ -53,6 +55,14 @@ public class DocumentFolderRowModel { public boolean isFolder() { return folder; } + + public String getFolderPath() { + return folderPath; + } + + protected void setFolderPath(final String folderPath) { + this.folderPath = folderPath; + } protected void setFolder(final boolean folder) { this.folder = folder; diff --git a/ccm-cms/src/main/java/org/librecms/ui/FolderTreeNode.java b/ccm-cms/src/main/java/org/librecms/ui/FolderTreeNode.java new file mode 100644 index 000000000..0c3c23df1 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/FolderTreeNode.java @@ -0,0 +1,88 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui; + +import java.util.List; + +/** + * + * @author Jens Pelzetter + */ +public class FolderTreeNode { + + private long folderId; + + private String uuid; + + private String name; + + private String path; + + private List subFolders; + + private boolean open; + + private boolean selected; + + public long getFolderId() { + return folderId; + } + + public void setFolderId(final long folderId) { + this.folderId = folderId; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(final String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(final String path) { + this.path = path; + } + + public List getSubFolders() { + return subFolders; + } + + public void setSubFolders(final List subFolders) { + this.subFolders = subFolders; + } + + public boolean isOpen() { + return open; + } + + public void setOpen(final boolean open) { + this.open = open; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(final boolean selected) { + this.selected = selected; + } + + + +} diff --git a/ccm-cms/src/main/resources/META-INF/resources/components/cms/treeNode.xhtml b/ccm-cms/src/main/resources/META-INF/resources/components/cms/treeNode.xhtml new file mode 100644 index 000000000..1f1b9a1ce --- /dev/null +++ b/ccm-cms/src/main/resources/META-INF/resources/components/cms/treeNode.xhtml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + +
  • +
    + + #{cc.attrs.name} +
    +
      + + + +
    +
  • +
    + +
  • + #{cc.attrs.name} +
  • +
    +
    +
    + diff --git a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/contentsection-not-found.xhtml b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/contentsection-not-found.xhtml index 566a36934..411536a8d 100644 --- a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/contentsection-not-found.xhtml +++ b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/contentsection-not-found.xhtml @@ -7,7 +7,7 @@ - + + + + +
    +
    + #{CmsAdminMessages.getMessage("contentsections.documentfolder.not_found", [contentSection, folderPath])} +
    +
    +
    + +
    + + diff --git a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/document-folder.xhtml b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/document-folder.xhtml index ddac3bd39..30d4814b4 100644 --- a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/document-folder.xhtml +++ b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/content-section/document-folder.xhtml @@ -2,73 +2,138 @@ - + - + + + + + + + + + + + + + + + + + + +

    #{CmsAdminMessages.getMessage("contentsection.documentfolder.heading", [ContentSectionModel.sectionName])}

    -
    -