diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java index e88ea57a..c15c9624 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java @@ -247,7 +247,7 @@ public class DocumentDao { tagCriteriaList.add(String.format("dt%d.DOT_ID_C is not null", index)); index++; } - criteriaList.add(Joiner.on(" OR ").join(tagCriteriaList)); + criteriaList.add("(" + Joiner.on(" OR ").join(tagCriteriaList) + ")"); } if (criteria.getShared() != null && criteria.getShared()) { criteriaList.add("(select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) > 0"); diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java index cfcfcb71..74593c05 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java @@ -499,14 +499,14 @@ public class DocumentResource extends BaseResource { break; case "shared": // New shared state criteria - if (params[1].equals("yes")) { - documentCriteria.setShared(true); - } + documentCriteria.setShared(params[1].equals("yes")); break; case "lang": // New language criteria if (Constants.SUPPORTED_LANGUAGES.contains(params[1])) { documentCriteria.setLanguage(params[1]); + } else { + documentCriteria.setLanguage(UUID.randomUUID().toString()); } break; case "by": @@ -522,9 +522,7 @@ public class DocumentResource extends BaseResource { break; case "workflow": // New shared state criteria - if (params[1].equals("me")) { - documentCriteria.setActiveRoute(true); - } + documentCriteria.setActiveRoute(params[1].equals("me")); break; case "full": // New full content search criteria diff --git a/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js b/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js index 4ec2df83..98d767a3 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js @@ -14,7 +14,6 @@ angular.module('docs').controller('Document', function ($scope, $rootScope, $tim $scope.limit = _.isUndefined(localStorage.documentsPageSize) ? '10' : localStorage.documentsPageSize; $scope.search = $state.params.search ? $state.params.search : ''; $scope.searchOpened = false; - $scope.setSearch = function (search) { $scope.search = search }; $scope.searchDropdownAnchor = angular.element(document.querySelector('.search-dropdown-anchor')); $scope.paginationShown = true; $scope.advsearch = {}; @@ -81,6 +80,8 @@ angular.module('docs').controller('Document', function ($scope, $rootScope, $tim }); } + $scope.extractNavigatedTag(); + // Call API later timeoutPromise = $timeout(function () { $scope.loadDocuments(); @@ -118,22 +119,6 @@ angular.module('docs').controller('Document', function ($scope, $rootScope, $tim $state.go('document.view', { id: id }); }; - // Load tags - $scope.tags = []; - Restangular.one('tag/list').get().then(function (data) { - $scope.tags = data.tags; - }); - - /** - * Find children tags. - * @param parent - */ - $scope.getChildrenTags = function(parent) { - return _.filter($scope.tags, function(tag) { - return tag.parent === parent; - }); - }; - /** * Returns a promise for typeahead user. */ @@ -210,12 +195,18 @@ angular.module('docs').controller('Document', function ($scope, $rootScope, $tim $scope.searchOpened = false; }; + /** + * Clear the search. + */ $scope.clearSearch = function () { $scope.advsearch = {}; $scope.search = ''; $scope.searchOpened = false; }; + /** + * Import an EML file. + */ $scope.importEml = function (file) { // Open the import modal $uibModal.open({ @@ -235,4 +226,97 @@ angular.module('docs').controller('Document', function ($scope, $rootScope, $tim $scope.loadDocuments(); }); }; + + // Tag navigation + $scope.tags = []; + $scope.navigatedFilter = { parent: '' }; + $scope.navigatedTag = undefined; + $scope.navigationEnabled = _.isUndefined(localStorage.navigationEnabled) ? + true : localStorage.navigationEnabled === 'true'; + + Restangular.one('tag/list').get().then(function (data) { + $scope.tags = data.tags; + $scope.extractNavigatedTag(); + }); + + /** + * Comparator for the navigation tag filter. + */ + $scope.navigatedComparator = function (actual, expected) { + if (expected === '') { + return _.isUndefined(actual); + } + return angular.equals(actual, expected); + }; + + /** + * Navigate to a specific tag. + */ + $scope.navigateToTag = function (tag) { + if (tag) { + $scope.search = 'tag:' + tag.name; + } else { + $scope.search = ''; + } + }; + + /** + * Navigate one tag up. + */ + $scope.navigateUp = function () { + if (!$scope.navigatedTag) { + return; + } + $scope.navigateToTag(_.findWhere($scope.tags, { id: $scope.navigatedTag.parent })); + }; + + /** + * Get the current navigation breadcrumb. + */ + $scope.getCurrentNavigation = function () { + if (!$scope.navigatedTag) { + return []; + } + + var nav = []; + nav.push($scope.navigatedTag); + var current = $scope.navigatedTag; + while (current.parent) { + current = _.findWhere($scope.tags, { id: current.parent }); + if (!current) { + break; + } + nav.push(current); + } + return nav.reverse(); + }; + + /** + * Extract the current navigated tag from the search query. + * Called each time the search query changes. + */ + $scope.extractNavigatedTag = function () { + // Find the current tag in the search query + var tagFound = /tag:([^ ]*)/.exec($scope.search); + if (tagFound) { + tagFound = tagFound[1]; + // We search only for exact match + $scope.navigatedTag = _.findWhere($scope.tags, { name: tagFound }); + } else { + $scope.navigatedTag = undefined; + } + if ($scope.navigatedTag) { + $scope.navigatedFilter = {parent: $scope.navigatedTag.id}; + } else { + $scope.navigatedFilter = {parent: ''}; + } + }; + + /** + * Toggle the navigation context. + */ + $scope.navigationToggle = function () { + $scope.navigationEnabled = !$scope.navigationEnabled; + localStorage.navigationEnabled = $scope.navigationEnabled; + }; }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/src/locale/en.json b/docs-web/src/main/webapp/src/locale/en.json index 35369d0d..e6ba5ae4 100644 --- a/docs-web/src/main/webapp/src/locale/en.json +++ b/docs-web/src/main/webapp/src/locale/en.json @@ -39,6 +39,8 @@ "global_quota_warning": "Warning! Global quota almost reached at {{ current | number: 0 }}MB ({{ percent | number: 1 }}%) used on {{ total | number: 0 }}MB" }, "document": { + "navigation_up": "Go up one level", + "toggle_navigation": "Toggle folder navigation", "search_simple": "Simple search", "search_fulltext": "Fulltext search", "search_creator": "Creator", diff --git a/docs-web/src/main/webapp/src/partial/docs/document.html b/docs-web/src/main/webapp/src/partial/docs/document.html index 205ade81..8c4f28f3 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.html @@ -1,16 +1,7 @@ - -
+ +
-
- -
    -
  • {{ 'document.no_tags' | translate }}
  • -
  • -
-
- -
+
+ +
+ +
+ + + +
+ + + + + + +
{{ tag.name }}
+ + diff --git a/docs-web/src/main/webapp/src/partial/docs/document.view.html b/docs-web/src/main/webapp/src/partial/docs/document.view.html index 9f56996b..b309daf5 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.view.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.view.html @@ -14,32 +14,34 @@
-
- -
- +
+ + {{ 'edit' | translate }} +
+ + +