mirror of
https://github.com/sismics/docs.git
synced 2024-11-25 15:17:57 +01:00
#176: navigation by tag
This commit is contained in:
parent
a0e89103af
commit
77311f42cd
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
});
|
@ -39,6 +39,8 @@
|
||||
"global_quota_warning": "<strong>Warning!</strong> 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",
|
||||
|
@ -1,16 +1,7 @@
|
||||
<script type="text/ng-template" id="tag-tree-item">
|
||||
<span class="btn" ng-style="{ 'background-color': tag.color }"></span>
|
||||
<span class="btn btn-link" ng-click="setSearch('tag:' + tag.name)">
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
<ul class="list-unstyled">
|
||||
<li ng-repeat="tag in getChildrenTags(tag.id)" ng-include="'tag-tree-item'"></li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="well well-3d">
|
||||
<!-- Main new document button -->
|
||||
<div class="text-center mb-19">
|
||||
<div class="btn-group" uib-dropdown>
|
||||
<a href="#/document/add" class="btn btn-primary">
|
||||
@ -25,18 +16,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search (simple and advanced) -->
|
||||
<div class="row search-dropdown-anchor">
|
||||
<div class="col-xs-2 tag-tree-dropdown" uib-dropdown>
|
||||
<button class="btn btn-block btn-default" uib-dropdown-toggle ng-disabled="disabled">
|
||||
{{ 'document.tags' | translate }} <span class="caret"></span>
|
||||
</button>
|
||||
<ul uib-dropdown-menu class="tag-tree">
|
||||
<li ng-if="getChildrenTags().length == 0">{{ 'document.no_tags' | translate }}</li>
|
||||
<li ng-repeat="tag in getChildrenTags()" ng-include="'tag-tree-item'"></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-10 input-group">
|
||||
<div class="col-xs-12 input-group">
|
||||
<input type="search" class="form-control" ng-attr-placeholder="{{ 'document.search' | translate }}" ng-model="search" />
|
||||
<span class="input-group-addon btn" ng-click="openSearch()">
|
||||
<div uib-dropdown
|
||||
@ -145,6 +127,39 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation breadcrumb -->
|
||||
<ol class="breadcrumb breadcrumb-navigation pull-left mt-10">
|
||||
<li><a href ng-click="navigateToTag()"><span class="fas fa-home"></span></a></li>
|
||||
<li ng-repeat="tag in getCurrentNavigation()" ng-class="{ active: tag.id == navigatedTag.id }">
|
||||
<a class="label" ng-style="{ 'background-color': tag.color }" ng-if="tag.id != navigatedTag.id" href ng-click="navigateToTag(tag)">{{ tag.name }}</a>
|
||||
<span class="label" ng-style="{ 'background-color': tag.color }" ng-if="tag.id == navigatedTag.id">{{ tag.name }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="btn-group mt-10 pull-right">
|
||||
<!-- Go up in the navigation -->
|
||||
<button class="btn btn-default" ng-click="navigateUp()"
|
||||
uib-tooltip="{{ 'document.navigation_up' | translate }}"
|
||||
tooltip-append-to-body="true"
|
||||
ng-if="navigatedTag">
|
||||
<span class="fas fa-chevron-up"></span>
|
||||
</button>
|
||||
<button class="btn btn-default" ng-click="navigationToggle()"
|
||||
ng-class="{ active: navigationEnabled }"
|
||||
uib-tooltip="{{ 'document.toggle_navigation' | translate }}"
|
||||
tooltip-append-to-body="true">
|
||||
<span class="far" ng-class="{ 'fa-folder-open': navigationEnabled, 'fa-folder': !navigationEnabled }"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Current folder -->
|
||||
<table class="row table table-hover table-navigation" ng-show="navigationEnabled">
|
||||
<tr ng-repeat="tag in tags | filter: navigatedFilter: navigatedComparator" ng-click="navigateToTag(tag)">
|
||||
<td colspan="2"><span class="fas fa-tags" ng-style="{ color: tag.color }"></span> {{ tag.name }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Document list -->
|
||||
<table class="row table table-hover table-documents">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -14,32 +14,34 @@
|
||||
</div>
|
||||
|
||||
<div ng-show="document">
|
||||
<div class="pull-right">
|
||||
<div class="dropdown" uib-dropdown ng-class="{ 'btn-group': document.writable }">
|
||||
<button class="btn btn-default" uib-dropdown-toggle>
|
||||
<span class="fas fa-cloud-download-alt"></span>
|
||||
{{ 'export' | translate }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a ng-href="../api/file/zip?id={{ document.id }}">
|
||||
<span class="fas fa-download"></span>
|
||||
{{ 'document.view.download_files' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href ng-click="exportPdf()">
|
||||
<span class="fas fa-file-pdf"></span>
|
||||
{{ 'document.view.export_pdf' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button class="btn btn-danger" ng-show="document.writable" ng-click="deleteDocument(document)"><span class="fas fa-trash"></span> {{ 'delete' | translate }}</button>
|
||||
<a href="#/document/edit/{{ document.id }}" ng-show="document.writable" class="btn btn-primary"><span class="fas fa-pencil-alt"></span> {{ 'edit' | translate }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-right btn-group">
|
||||
<button class="btn btn-danger" ng-show="document.writable" ng-click="deleteDocument(document)"><span class="fas fa-trash"></span> {{ 'delete' | translate }}</button>
|
||||
<a href="#/document/edit/{{ document.id }}" ng-show="document.writable" class="btn btn-primary"><span class="fas fa-pencil-alt"></span> {{ 'edit' | translate }}</a>
|
||||
</div>
|
||||
|
||||
<div class="pull-right dropdown" uib-dropdown>
|
||||
<button class="btn btn-default" uib-dropdown-toggle>
|
||||
<span class="fas fa-cloud-download-alt"></span>
|
||||
{{ 'export' | translate }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a ng-href="../api/file/zip?id={{ document.id }}">
|
||||
<span class="fas fa-download"></span>
|
||||
{{ 'document.view.download_files' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href ng-click="exportPdf()">
|
||||
<span class="fas fa-file-pdf"></span>
|
||||
{{ 'document.view.export_pdf' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
{{ document.title }}
|
||||
|
@ -34,6 +34,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation
|
||||
.table-navigation {
|
||||
tr {
|
||||
cursor: pointer;
|
||||
|
||||
td {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-navigation {
|
||||
background: none;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
|
||||
&> li + li:before {
|
||||
content: '/';
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
// Documents list
|
||||
.table-documents {
|
||||
margin-top: 18px !important;
|
||||
|
Loading…
Reference in New Issue
Block a user