diff --git a/doc/release-notes/9204-group-by-file-ordering.md b/doc/release-notes/9204-group-by-file-ordering.md new file mode 100644 index 00000000000..97f6b0750fb --- /dev/null +++ b/doc/release-notes/9204-group-by-file-ordering.md @@ -0,0 +1,9 @@ +### Support for Grouping Dataset Files by Folder and Category Tag + +Dataverse now supports grouping dataset files by folder and/or optionally by Tag/Category. The default for whether to order by folder can be changed via :OrderByFolder. Ordering by category must be enabled by an administrator via the :CategoryOrder parameter which is used to specify which tags appear first (e.g. to put Documentation files before Data or Code files, etc.) These Group-By options work with the existing sort options, i.e. sorting alphabetically means that files within each folder or tag group will be sorted alphabetically. :AllowUsersToManageOrdering can be set to true to allow users to turn folder ordering and category ordering (if enabled) on or off in the current dataset view. + +### New Setting + +:CategoryOrder - a comma separated list of Category/Tag names defining the order in which files with those tags should be displayed. The setting can include custom tag names along with the pre-defined defaults ( Documentation, Data, and Code, which can be overridden by the ::FileCategories setting.) +:OrderByFolder - defaults to true - whether to group files in the same folder together +:AllowUserManagementOfOrder - default false - allow users to toggle ordering on/off in the dataset display \ No newline at end of file diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 9828d5bb6e4..a80c93d076a 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -3710,6 +3710,8 @@ For example: When set to ``true``, this setting allows a superuser to publish and/or update Dataverse collections and datasets bypassing the external validation checks (specified by the settings above). In an event where an external script is reporting validation failures that appear to be in error, this option gives an admin with superuser privileges a quick way to publish the dataset or update a collection for the user. +.. _:FileCategories: + :FileCategories +++++++++++++++ @@ -3811,4 +3813,21 @@ To use the current GDCC version directly: ``curl -X PUT -d 'https://gdcc.github.io/dvwebloader/src/dvwebloader.html' http://localhost:8080/api/admin/settings/:WebloaderUrl`` +:CategoryOrder +++++++++++++++ + +A comma separated list of Category/Tag names defining the order in which files with those tags should be displayed. +The setting can include custom tag names along with the pre-defined tags(Documentation, Data, and Code are the defaults but the :ref:`:FileCategories` setting can be used to use a different set of tags). +The default is category ordering disabled. + +:OrderByFolder +++++++++++++++ + +A true(default)/false option determining whether datafiles listed on the dataset page should be grouped by folder. + +:AllowUserManagementOfOrder ++++++++++++++++++++++++++++ + +A true/false (default) option determining whether the dataset datafile table display includes checkboxes enabling users to turn folder ordering and/or category ordering (if an order is defined by :CategoryOrder) on and off dynamically. + .. _supported MicroProfile Config API source: https://docs.payara.fish/community/docs/Technical%20Documentation/MicroProfile/Config/Overview.html diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index dc8e2e3c2fb..54c92dba999 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -48,6 +48,7 @@ import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.ArchiverUtil; import edu.harvard.iq.dataverse.util.BundleUtil; +import edu.harvard.iq.dataverse.util.DataFileComparator; import edu.harvard.iq.dataverse.util.FileSortFieldAndOrder; import edu.harvard.iq.dataverse.util.FileUtil; import edu.harvard.iq.dataverse.util.JsfHelper; @@ -505,6 +506,16 @@ public void setRemoveUnusedTags(boolean removeUnusedTags) { private String fileSortField; private String fileSortOrder; + private boolean tagPresort = true; + private boolean folderPresort = true; + // Due to what may be a bug in PrimeFaces, the call to select a new page of + // files appears to reset the two presort booleans to false. The following + // values are a flag and duplicate booleans to remember what the new values were + // so that they can be set only in real checkbox changes. Further comments where + // these are used. + boolean isPageFlip = false; + private boolean newTagPresort = true; + private boolean newFolderPresort = true; public List> getCartList() { if (session.getUser() instanceof AuthenticatedUser) { @@ -673,64 +684,43 @@ private List selectFileMetadatasForDisplay() { // We run the search even if no search term and/or facets are // specified - to generate the facet labels list: searchResultsIdSet = getFileIdsInVersionFromSolr(workingVersion.getId(), this.fileLabelSearchTerm); - // But, if no search terms were specified, we can immediately return the full + // But, if no search terms were specified, we return the full // list of the files in the version: if (StringUtil.isEmpty(fileLabelSearchTerm) && StringUtil.isEmpty(fileTypeFacet) && StringUtil.isEmpty(fileAccessFacet) && StringUtil.isEmpty(fileTagsFacet)) { - if ((StringUtil.isEmpty(fileSortField) || fileSortField.equals("name")) && StringUtil.isEmpty(fileSortOrder)) { - return workingVersion.getFileMetadatasSorted(); - } else { - searchResultsIdSet = null; - } + // Since the search results should include the full set of fmds if all the + // terms/facets are empty, setting them to null should just be + // an optimization for the loop below + searchResultsIdSet = null; } - } else { // No, this is not an indexed version. // If the search term was specified, we'll run a search in the db; // if not - return the full list of files in the version. // (no facets without solr!) - if (StringUtil.isEmpty(this.fileLabelSearchTerm)) { - if ((StringUtil.isEmpty(fileSortField) || fileSortField.equals("name")) && StringUtil.isEmpty(fileSortOrder)) { - return workingVersion.getFileMetadatasSorted(); - } - } else { + if (!StringUtil.isEmpty(this.fileLabelSearchTerm)) { searchResultsIdSet = getFileIdsInVersionFromDb(workingVersion.getId(), this.fileLabelSearchTerm); } } List retList = new ArrayList<>(); - for (FileMetadata fileMetadata : workingVersion.getFileMetadatasSorted()) { + for (FileMetadata fileMetadata : workingVersion.getFileMetadatas()) { if (searchResultsIdSet == null || searchResultsIdSet.contains(fileMetadata.getDataFile().getId())) { retList.add(fileMetadata); } } - - if ((StringUtil.isEmpty(fileSortOrder) && !("name".equals(fileSortField))) - || ("desc".equals(fileSortOrder) || !("name".equals(fileSortField)))) { - sortFileMetadatas(retList); - - } - + sortFileMetadatas(retList); return retList; } private void sortFileMetadatas(List fileList) { - if ("name".equals(fileSortField) && "desc".equals(fileSortOrder)) { - Collections.sort(fileList, compareByLabelZtoA); - } else if ("date".equals(fileSortField)) { - if ("desc".equals(fileSortOrder)) { - Collections.sort(fileList, compareByOldest); - } else { - Collections.sort(fileList, compareByNewest); - } - } else if ("type".equals(fileSortField)) { - Collections.sort(fileList, compareByType); - } else if ("size".equals(fileSortField)) { - Collections.sort(fileList, compareBySize); - } + + DataFileComparator dfc = new DataFileComparator(); + Comparator comp = dfc.compareBy(folderPresort, tagPresort, fileSortField, !"desc".equals(fileSortOrder)); + Collections.sort(fileList, comp); } private Boolean isIndexedVersion = null; @@ -1863,7 +1853,12 @@ private String init(boolean initFull) { String nonNullDefaultIfKeyNotFound = ""; protocol = settingsWrapper.getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); authority = settingsWrapper.getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - if (this.getId() != null || versionId != null || persistentId != null) { // view mode for a dataset + String sortOrder = getSortOrder(); + if(sortOrder != null) { + FileMetadata.setCategorySortOrder(sortOrder); + } + + if (dataset.getId() != null || versionId != null || persistentId != null) { // view mode for a dataset DatasetVersionServiceBean.RetrieveDatasetVersionResponse retrieveDatasetVersionResponse = null; @@ -2245,6 +2240,19 @@ private void displayLockInfo(Dataset dataset) { } + public String getSortOrder() { + return settingsWrapper.getValueForKey(SettingsServiceBean.Key.CategoryOrder, null); + } + + public boolean orderByFolder() { + return settingsWrapper.isTrueForKey(SettingsServiceBean.Key.OrderByFolder, true); + } + + public boolean allowUserManagementOfOrder() { + return settingsWrapper.isTrueForKey(SettingsServiceBean.Key.AllowUserManagementOfOrder, false); + } + + private Boolean fileTreeViewRequired = null; public boolean isFileTreeViewRequired() { @@ -2267,6 +2275,7 @@ public String getFileDisplayMode() { } public void setFileDisplayMode(String fileDisplayMode) { + isPageFlip = true; if ("Table".equals(fileDisplayMode)) { this.fileDisplayMode = FileDisplayStyle.TABLE; } else { @@ -2278,13 +2287,6 @@ public boolean isFileDisplayTable() { return fileDisplayMode == FileDisplayStyle.TABLE; } - public void toggleFileDisplayMode() { - if (fileDisplayMode == FileDisplayStyle.TABLE) { - fileDisplayMode = FileDisplayStyle.TREE; - } else { - fileDisplayMode = FileDisplayStyle.TABLE; - } - } public boolean isFileDisplayTree() { return fileDisplayMode == FileDisplayStyle.TREE; } @@ -2804,6 +2806,24 @@ public void refresh(ActionEvent e) { refresh(); } + + public void sort() { + // This is called as the presort checkboxes' listener when the user is actually + // clicking in the checkbox. It does appear to happen after the setTagPresort + // and setFolderPresort calls. + // So -we know this isn't a pageflip and at this point can update to use the new + // values. + isPageFlip = false; + if (!newTagPresort == tagPresort) { + tagPresort = newTagPresort; + } + if (!newFolderPresort == folderPresort) { + folderPresort = newFolderPresort; + } + sortFileMetadatas(fileMetadatasSearch); + JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("file.results.presort.change.success")); + } + public String refresh() { logger.fine("refreshing"); @@ -5558,6 +5578,10 @@ public void clearSelection() { } public void fileListingPaginatorListener(PageEvent event) { + // Changing to a new page of files - set this so we can ignore changes to the + // presort checkboxes. (This gets called before the set calls for the presorts + // get called.) + isPageFlip=true; setFilePaginatorPage(event.getPage()); } @@ -5674,52 +5698,34 @@ public boolean isSomeVersionArchived() { return someVersionArchived; } - private static Date getFileDateToCompare(FileMetadata fileMetadata) { - DataFile datafile = fileMetadata.getDataFile(); - - if (datafile.isReleased()) { - return datafile.getPublicationDate(); + public boolean isTagPresort() { + return this.tagPresort; } - return datafile.getCreateDate(); - } - - private static final Comparator compareByLabelZtoA = new Comparator() { - @Override - public int compare(FileMetadata o1, FileMetadata o2) { - return o2.getLabel().toUpperCase().compareTo(o1.getLabel().toUpperCase()); - } - }; - - private static final Comparator compareByNewest = new Comparator() { - @Override - public int compare(FileMetadata o1, FileMetadata o2) { - return getFileDateToCompare(o2).compareTo(getFileDateToCompare(o1)); + public void setTagPresort(boolean tagPresort) { + // Record the new value + newTagPresort = tagPresort && (null != getSortOrder()); + // If this is not a page flip, it should be a real change to the presort + // boolean that we should use. + if (!isPageFlip) { + this.tagPresort = tagPresort && (null != getSortOrder()); + } } - }; - private static final Comparator compareByOldest = new Comparator() { - @Override - public int compare(FileMetadata o1, FileMetadata o2) { - return getFileDateToCompare(o1).compareTo(getFileDateToCompare(o2)); + public boolean isFolderPresort() { + return this.folderPresort; } - }; - private static final Comparator compareBySize = new Comparator() { - @Override - public int compare(FileMetadata o1, FileMetadata o2) { - return (new Long(o1.getDataFile().getFilesize())).compareTo(new Long(o2.getDataFile().getFilesize())); + public void setFolderPresort(boolean folderPresort) { + //Record the new value + newFolderPresort = folderPresort && orderByFolder(); + // If this is not a page flip, it should be a real change to the presort + // boolean that we should use. + if (!isPageFlip) { + this.folderPresort = folderPresort && orderByFolder(); + } } - }; - private static final Comparator compareByType = new Comparator() { - @Override - public int compare(FileMetadata o1, FileMetadata o2) { - String type1 = StringUtil.isEmpty(o1.getDataFile().getFriendlyType()) ? "" : o1.getDataFile().getContentType(); - String type2 = StringUtil.isEmpty(o2.getDataFile().getFriendlyType()) ? "" : o2.getDataFile().getContentType(); - return type1.compareTo(type2); - } - }; public void explore(ExternalTool externalTool) { ApiToken apiToken = null; diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java b/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java index a043d110473..e04eab666a4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java @@ -3,6 +3,7 @@ import edu.harvard.iq.dataverse.util.MarkupChecker; import edu.harvard.iq.dataverse.util.PersonOrOrgUtil; import edu.harvard.iq.dataverse.util.BundleUtil; +import edu.harvard.iq.dataverse.util.DataFileComparator; import edu.harvard.iq.dataverse.DatasetFieldType.FieldType; import edu.harvard.iq.dataverse.branding.BrandingUtil; import edu.harvard.iq.dataverse.dataset.DatasetUtil; @@ -242,14 +243,34 @@ public List getFileMetadatas() { } public List getFileMetadatasSorted() { - Collections.sort(fileMetadatas, FileMetadata.compareByLabel); + + /* + * fileMetadatas can sometimes be an + * org.eclipse.persistence.indirection.IndirectList When that happens, the + * comparator in the Collections.sort below is not called, possibly due to + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=446236 which is Java 1.8+ + * specific Converting to an ArrayList solves the problem, but the longer term + * solution may be in avoiding the IndirectList or moving to a new version of + * the jar it is in. + */ + if(!(fileMetadatas instanceof ArrayList)) { + List newFMDs = new ArrayList(); + for(FileMetadata fmd: fileMetadatas) { + newFMDs.add(fmd); + } + setFileMetadatas(newFMDs); + } + + DataFileComparator dfc = new DataFileComparator(); + Collections.sort(fileMetadatas, dfc.compareBy(true, null!=FileMetadata.getCategorySortOrder(), "name", true)); return fileMetadatas; } public List getFileMetadatasSortedByLabelAndFolder() { ArrayList fileMetadatasCopy = new ArrayList<>(); fileMetadatasCopy.addAll(fileMetadatas); - Collections.sort(fileMetadatasCopy, FileMetadata.compareByLabelAndFolder); + DataFileComparator dfc = new DataFileComparator(); + Collections.sort(fileMetadatasCopy, dfc.compareBy(true, null!=FileMetadata.getCategorySortOrder(), "name", true)); return fileMetadatasCopy; } diff --git a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java index fc31d0867ed..01131bdca01 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java +++ b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java @@ -13,10 +13,13 @@ import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.json.Json; @@ -203,6 +206,25 @@ public void setVarGroups(List varGroups) { private List fileCategories; public List getCategories() { + if (fileCategories != null) { + /* + * fileCategories can sometimes be an + * org.eclipse.persistence.indirection.IndirectList When that happens, the + * comparator in the Collections.sort below is not called, possibly due to + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=446236 which is Java 1.8+ + * specific Converting to an ArrayList solves the problem, but the longer term + * solution may be in avoiding the IndirectList or moving to a new version of + * the jar it is in. + */ + if (!(fileCategories instanceof ArrayList)) { + List newDFCs = new ArrayList(); + for (DataFileCategory fdc : fileCategories) { + newDFCs.add(fdc); + } + setCategories(newDFCs); + } + Collections.sort(fileCategories, FileMetadata.compareByNameWithSortCategories); + } return fileCategories; } @@ -228,7 +250,7 @@ public List getCategoriesByName() { return ret; } - for (DataFileCategory fileCategory : fileCategories) { + for (DataFileCategory fileCategory : getCategories()) { ret.add(fileCategory.getName()); } // fileCategories.stream() @@ -536,7 +558,7 @@ public boolean compareContent(FileMetadata other){ @Override public String toString() { - return "edu.harvard.iq.dvn.core.study.FileMetadata[id=" + id + "]"; + return "edu.harvard.iq.dataverse.FileMetadata[id=" + id + "]"; } public static final Comparator compareByLabel = new Comparator() { @@ -546,28 +568,37 @@ public int compare(FileMetadata o1, FileMetadata o2) { } }; - public static final Comparator compareByLabelAndFolder = new Comparator() { + static Map categoryMap=null; + + public static void setCategorySortOrder(String categories) { + categoryMap=new HashMap(); + long i=1; + for(String cat: categories.split(",\\s*")) { + categoryMap.put(cat.toUpperCase(), i); + i++; + } + } + + public static Map getCategorySortOrder() { + return categoryMap; + } + + + public static final Comparator compareByNameWithSortCategories = new Comparator() { @Override - public int compare(FileMetadata o1, FileMetadata o2) { - String folder1 = o1.getDirectoryLabel() == null ? "" : o1.getDirectoryLabel().toUpperCase(); - String folder2 = o2.getDirectoryLabel() == null ? "" : o2.getDirectoryLabel().toUpperCase(); - - - // We want to the files w/ no folders appear *after* all the folders - // on the sorted list: - if ("".equals(folder1) && !"".equals(folder2)) { - return 1; - } - - if ("".equals(folder2) && !"".equals(folder1)) { - return -1; - } - - int comp = folder1.compareTo(folder2); - if (comp != 0) { - return comp; + public int compare(DataFileCategory o1, DataFileCategory o2) { + if (categoryMap != null) { + //If one is in the map and one is not, the former is first, otherwise sort by name + boolean o1InMap = categoryMap.containsKey(o1.getName().toUpperCase()); + boolean o2InMap = categoryMap.containsKey(o2.getName().toUpperCase()); + if(o1InMap && !o2InMap) { + return (-1); + } + if(!o1InMap && o2InMap) { + return 1; + } } - return o1.getLabel().toUpperCase().compareTo(o2.getLabel().toUpperCase()); + return(o1.getName().toUpperCase().compareTo(o2.getName().toUpperCase())); } }; diff --git a/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java index d84e18d5931..0c651d14feb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java @@ -576,8 +576,24 @@ Whether Harvesting (OAI) service is enabled /** * The URL for the DvWebLoader tool (see github.com/gdcc/dvwebloader for details) */ - WebloaderUrl - + WebloaderUrl, + /** + * A comma-separated list of CategoryName in the desired order for files to be + * sorted in the file table display. If not set, files will be sorted + * alphabetically by default. If set, files will be sorted by these categories + * and alphabetically within each category. + */ + CategoryOrder, + /** + * True(default)/false option deciding whether ordering by folder should be applied to the + * dataset listing of datafiles. + */ + OrderByFolder, + /** + * True/false(default) option deciding whether the dataset file table display should include checkboxes + * allowing users to dynamically turn folder and category ordering on/off. + */ + AllowUserManagementOfOrder ; @Override diff --git a/src/main/java/edu/harvard/iq/dataverse/util/DataFileComparator.java b/src/main/java/edu/harvard/iq/dataverse/util/DataFileComparator.java new file mode 100644 index 00000000000..8003fefd635 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/util/DataFileComparator.java @@ -0,0 +1,129 @@ +package edu.harvard.iq.dataverse.util; + + +import java.util.Comparator; +import java.util.Date; +import java.util.Map; +import edu.harvard.iq.dataverse.DataFile; +import edu.harvard.iq.dataverse.DataFileCategory; +import edu.harvard.iq.dataverse.FileMetadata; + +/** + * + * @author qqmyers + */ +public class DataFileComparator implements Comparator { + + boolean byFolder = false; + boolean byCategory = false; + String field = "name"; + boolean ascending = true; + + public Comparator compareBy(boolean byFolder, boolean byCategory, String field, boolean ascending) { + this.byFolder = byFolder; + this.byCategory = byCategory; + if(StringUtil.nonEmpty(field)) { + this.field = field; + } + this.ascending = ascending; + return this; + } + + public boolean getByFolder() { + return this.byFolder; + } + public int getByCategory() { + return FileMetadata.getCategorySortOrder().size(); + } + + public String getField() { + return this.field; + } + + public boolean getAsc() { + return this.ascending; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public int compare(FileMetadata o1, FileMetadata o2) { + if (byFolder) { + // Compare folders first + String folder1 = o1.getDirectoryLabel() == null ? "" : o1.getDirectoryLabel().toUpperCase(); + String folder2 = o2.getDirectoryLabel() == null ? "" : o2.getDirectoryLabel().toUpperCase(); + + if ("".equals(folder1) && !"".equals(folder2)) { + return -1; + } + + if ("".equals(folder2) && !"".equals(folder1)) { + return 1; + } + + int comp = folder1.compareTo(folder2); + if (comp != 0) { + return comp; + } + } + Map categoryMap = FileMetadata.getCategorySortOrder(); + + if (byCategory) { + // Then by category if set + if (categoryMap != null) { + long rank1 = Long.MAX_VALUE; + for (DataFileCategory c : o1.getCategories()) { + Long rank = categoryMap.get(c.getName().toUpperCase()); + if (rank != null) { + if (rank < rank1) { + rank1 = rank; + } + } + } + long rank2 = Long.MAX_VALUE; + for (DataFileCategory c : o2.getCategories()) { + Long rank = categoryMap.get(c.getName().toUpperCase()); + if (rank != null) { + if (rank < rank2) { + rank2 = rank; + } + } + } + if (rank1 != rank2) { + return rank1 < rank2 ? -1 : 1; + } + } + } + + // Folders are equal, no categories or category score is equal, so compare + // labels + Comparable file1 = null; + Comparable file2 = null; + switch (field) { + case "date": + file1 = getFileDateToCompare(o1); + file2 = getFileDateToCompare(o2); + break; + case "type": + file1 = StringUtil.isEmpty(o1.getDataFile().getFriendlyType()) ? "" : o1.getDataFile().getContentType(); + file2 = StringUtil.isEmpty(o2.getDataFile().getFriendlyType()) ? "" : o2.getDataFile().getContentType(); + break; + case "size": + file1 = new Long(o1.getDataFile().getFilesize()); + file2 = new Long(o2.getDataFile().getFilesize()); + break; + default: // "name" or not recognized + file1 = o1.getLabel().toUpperCase(); + file2 = o2.getLabel().toUpperCase(); + + } + return (ascending ? file1.compareTo(file2) : file2.compareTo(file1)); + } + + private Date getFileDateToCompare(FileMetadata fileMetadata) { + DataFile datafile = fileMetadata.getDataFile(); + if (datafile.isReleased()) { + return datafile.getPublicationDate(); + } + return datafile.getCreateDate(); + } +} \ No newline at end of file diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 45807dc7cde..97b4bd22652 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2007,6 +2007,11 @@ file.results.btn.sort.option.newest=Newest file.results.btn.sort.option.oldest=Oldest file.results.btn.sort.option.size=Size file.results.btn.sort.option.type=Type +file.results.presort.tag=Group by Tag +file.results.presort.tag.desc=Datafiles will be grouped by Tag before being sorted. +file.results.presort.folder=Group by Folder +file.results.presort.folder.desc=Datafiles will be grouped by Folder before being sorted. +file.results.presort.change.success=Grouping of Files in File Table updated. file.compute.fileAccessDenied=This file is restricted and you may not compute on it because you have not been granted access. file.configure.Button=Configure diff --git a/src/main/webapp/dataset.xhtml b/src/main/webapp/dataset.xhtml index 25aaf0a317d..4ba6ad0e7e1 100644 --- a/src/main/webapp/dataset.xhtml +++ b/src/main/webapp/dataset.xhtml @@ -103,6 +103,8 @@ + + diff --git a/src/main/webapp/filesFragment.xhtml b/src/main/webapp/filesFragment.xhtml index ca696e67187..0fea8895c89 100644 --- a/src/main/webapp/filesFragment.xhtml +++ b/src/main/webapp/filesFragment.xhtml @@ -134,7 +134,7 @@
-
+
#{bundle['file.results.filter']}
@@ -153,6 +153,8 @@ + + @@ -168,6 +170,8 @@ + + @@ -190,6 +194,8 @@ + + @@ -205,6 +211,8 @@ + + @@ -227,6 +235,8 @@ + + @@ -242,13 +252,26 @@ + +
-
+ + + +
+
+ + + + + + +
diff --git a/src/main/webapp/resources/css/structure.css b/src/main/webapp/resources/css/structure.css index 17b8fb96ac9..6e192d411f1 100644 --- a/src/main/webapp/resources/css/structure.css +++ b/src/main/webapp/resources/css/structure.css @@ -1142,3 +1142,18 @@ span.label-default { background-color: #757575 } .ui-inplace .ui-inputfield { width:60% } +/*File sorting*/ +#datasetForm .file-sort { + max-width: 255px; + float: right; + padding-right:21px; +} + +#datasetForm .file-sort .btn-group { + padding-top: 4px; +} + +#datasetForm .file-group-by { + min-width: 130px; + padding: 0px; +}