dsm: routes and pagination

This commit is contained in:
Michele Artini 2022-12-16 11:39:32 +01:00
parent 209ed2166d
commit 56cf7ffcef
7 changed files with 260 additions and 251 deletions

View File

@ -1,6 +1,8 @@
package eu.dnetlib.is;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@ -16,6 +18,7 @@ import eu.dnetlib.data.is.resource.model.ResourceType;
import eu.dnetlib.data.is.resource.repository.ResourceTypeRepository;
import eu.dnetlib.data.is.vocabulary.model.Vocabulary;
import eu.dnetlib.data.is.vocabulary.repository.VocabularyRepository;
import eu.dnetlib.is.info.KeyValue;
import eu.dnetlib.is.wfs.WfHistoryAjaxController;
import eu.dnetlib.openaire.dsm.utils.DsmBrowsableFields;
@ -34,15 +37,12 @@ public class MainController {
@GetMapping("/main")
public void mainPage() {}
@GetMapping("/searchDatasources")
@GetMapping("/dsm")
public void searchDsApi(final ModelMap map) {
map.addAttribute("browsableFields", DsmBrowsableFields.values());
}
@GetMapping("/resultsDatasources")
public void resultsDsApi(@RequestParam(required = false, defaultValue = "") final String field, @RequestParam final String value, final ModelMap map) {
map.addAttribute("field", field);
map.addAttribute("value", value);
map.addAttribute("pageSize", 100);
map.addAttribute("browsableFields", Arrays.stream(DsmBrowsableFields.values())
.map(f -> new KeyValue(f.name(), f.desc))
.collect(Collectors.toList()));
}
@GetMapping("/resources")

View File

@ -0,0 +1,79 @@
<div class="container-fluid">
<div class="row mt-5">
<div class="col">
<p class="text-muted">
<span></span><b>Number of results:</b> {{nResults}}<br />
<b>Page:</b> <span ng-if="nPages > 0">{{currPage + 1}} / {{nPages}}</span><span ng-if="nPages == 0">- / -</span>
</p>
<nav ng-show="nPages > 0">
<ul class="pagination small">
<li class="page-item" ng-class="{'disabled' : currPage <= 0}">
<a class="page-link" href="javascript:void(0)" ng-click="gotoPage(currPage - 1)">&laquo; Previous</a>
</li>
<li class="page-item" ng-class="{'disabled': currPage + 1 >= nPages}">
<a class="page-link" href="javascript:void(0)" ng-click="gotoPage(currPage + 1)">Next &raquo;</a>
</li>
</ul>
</nav>
<p ng-show="results.length > 0">
<input type="text" class="form-control form-control-sm" ng-model="apiFilter" placeholder="Filter in current page..."/>
</p>
<div class="card mb-4 small" ng-repeat="r in results|filter:apiFilter">
<div class="card-body">
<h5 class="card-title" title="{{r.id}}">{{r.name}}
<span style="font-size: 0.6em" ng-if="r.otherName && r.name != r.otherName"><br />{{r.otherName}}</span>
</h5>
<table class="table table-sm">
<tr>
<th style="width: 20em;">Id</th>
<td>{{r.id}}</td>
</tr><tr>
<th>Type</th>
<td>{{r.type}}</td>
</tr><tr>
<th>Collected From</th>
<td>{{r.collectedFrom}}</td>
</tr><tr ng-if="r.websiteUrl">
<th>URL</th>
<td><a href="{{r.websiteUrl}}" target="_blank">{{r.websiteUrl}}</a></td>
</tr><tr>
<th>Namespace Prefix</th>
<td>{{r.nsprefix}}</td>
</tr>
<tr ng-if="r.organizations">
<th>Organization(s)</th>
<td>
<span ng-repeat="o in r.organizations">
{{o.name}}
<img src="common/images/flags/{{o.country}}.gif" title="{{o.country}}" alt="" ng-if="o.country"/>
<br />
</span>
</td>
</tr><tr>
<th>APIs</th>
<td>
<div ng-repeat="a in r.apis" ng-if="a.id">
<span class="monospaced">{{a.id}}</span>
<span class="badge badge-primary" title="protocol">{{a.protocol}}</span>
<span class="badge badge-info" title="compliance">{{a.compliance}}</span>
<span class="badge badge-success" ng-if="a.active">active</span><span class="badge badge-danger" ng-if="!a.active">not active</span>
<span ng-if="a.aggrDate"><br/><b>Last aggregation:</b> {{a.aggrDate}} <b>(total: {{a.aggrTotal}})</b></span>
</div>
</td>
</tr><tr ng-if="r.consenttermsofuse">
<th>Consent Terms of Use</th>
<td><span class="badge badge-success">YES</span></td>
</tr><tr ng-if="r.fulltextdownload">
<th>Fulltext Download</th>
<td><span class="badge badge-success">YES</span></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,70 @@
<div class="container-fluid">
<div class="row mt-5">
<div class="offset-md-3 col-md-6 offset-lg-4 col-lg-4">
<form>
<div class="input-group">
<input type="text" class="form-control" ng-model="textApiSearch" placeholder="Search..."/>
<span class="input-group-append">
<button type="submit" class="btn btn-primary" ng-click="search('', textApiSearch)">Search</button>
</span>
</div>
</form>
</div>
</div>
<div class="row mt-5">
<div class="offset-md-3 col-md-6 offset-lg-4 col-lg-4">
<p>
<b>Or browse using:</b>
<ul>
<li ng-repeat="f in browsableFields">
<a href="javascript:void(0)" data-toggle="modal" data-target="#showBrowseData" ng-click="browseField(f.k, f.v)">{{f.v}}</a>
</li>
</ul>
</p>
</div>
</div>
</div>
<div id="showBrowseData" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">{{browseFieldName}}</h4>
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body small">
<input type="text" class="form-control input-sm" ng-model="filterBrowseData" placeholder="Filter..." />
<table class="table table-sm table-striped mt-4" style="table-layout: fixed;">
<thead>
<tr>
<th>
<a href="javascript:void(0)" ng-click="sortType = 'name'; sortReverse = !sortReverse">
Name
<i class="fa fa-sort-up" ng-show="sortType == 'name' && sortReverse" ></i>
<i class="fa fa-sort-down" ng-show="sortType == 'name' && !sortReverse"></i>
</a>
</th>
<th class="text-right">
<a href="javascript:void(0)" ng-click="sortType = 'total'; sortReverse = !sortReverse">
# datasources
<i class="fa fa-sort-up" ng-show="sortType == 'total' && sortReverse" ></i>
<i class="fa fa-sort-down" ng-show="sortType == 'total' && !sortReverse"></i>
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in browseData | orderBy:sortType:sortReverse | filter:filterBrowseData">
<th><a href="javascript:void(0)" ng-click="search(browseFieldId, row.term)">{{row.name}}</a></td>
<td class="text-right">{{row.total}}</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head th:replace="fragments/mainParts.html :: htmlHeader('Search Datasources')"></head>
<body ng-app="dsmApp" ng-controller="dsmSearchController">
<nav th:replace="fragments/mainParts.html :: mainMenu('Search Datasources')"></nav>
<div ng-view></div>
</body>
<th:block th:replace="fragments/mainParts.html :: scripts"></th:block>
<script th:inline="javascript">
/*<![CDATA[*/
function browsableFields() { return /*[[${browsableFields}]]*/ ''; }
function pageSize() { return /*[[${pageSize}]]*/ ''; }
/*]]>*/
</script>
<script>
var app = angular.module('dsmApp', ['ngRoute']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/search', { templateUrl: 'dsm/search.html', controller: 'dsmSearchController' })
.when('/results/:page/:size', { templateUrl: 'dsm/results.html', controller: 'dsmResultsController' })
.when('/results/:field/:page/:size', { templateUrl: 'dsm/results.html', controller: 'dsmResultsController' })
.otherwise({ redirectTo: '/search' });
}
]);
app.controller('dsmSearchController', function($scope, $http, $location) {
$scope.browseFieldId = "";
$scope.browseFieldName = "";
$scope.browseData = [];
$scope.browsableFields = browsableFields();
$scope.browseField = function(id, label) {
$scope.browseFieldId = id;
$scope.browseFieldName = name;
$scope.browseData = [];
$http.get('./ajax/dsm/browse/' + encodeURIComponent(id) + '?' + $.now()).then(function successCallback(res) {
$scope.browseData = res.data;
}, function errorCallback(res) {
alert('ERROR: ' + res.data.message);
});
}
$scope.search = function(field, value) {
var path = "/results/";
if (field) { path += encodeURIComponent(field); }
path += '/0/' + pageSize();
$location.path(path).search('value', value);
}
});
app.controller('dsmResultsController', function($scope, $http, $location, $routeParams) {
$scope.field = $routeParams.field;
$scope.value = $routeParams.value;
$scope.pageSize = $routeParams.size;
$scope.currPage = $routeParams.page;
$scope.nResults = 0;
$scope.results = [];
$scope.nPages = 0;
var url = './ajax/dsm/';
if ($scope.field) { url += 'searchByField/' + encodeURIComponent($scope.field); }
else { url += 'search' }
url += '/' + $scope.currPage + '/' + $scope.pageSize;
url += '?value=' + encodeURIComponent($scope.value) + '&' + $.now();
$http.get(url).then(function successCallback(res) {
$scope.results = res.data.content;
$scope.nResults = res.data.totalElements;
$scope.currPage = res.data.number;
$scope.nPages = res.data.totalPages;
}, function errorCallback(res) {
alert('ERROR: ' + res.data.message);
});
$scope.gotoPage = function(page) {
$scope.results = [];
var path = "/results/";
if ($scope.field) { path += encodeURIComponent($scope.field); }
path += '/' + page + '/' + $scope.pageSize;
$location.path(path).search('value', $scope.value);
}
});
</script>
</html>

View File

@ -31,7 +31,7 @@
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown">Datasources</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="./searchDatasources">Search</a>
<a class="dropdown-item" href="./dsm">Search</a>
</div>
</li>
<li class="nav-item dropdown">
@ -84,6 +84,7 @@
<script src="common/js/popper.min.js"></script>
<script src="common/js/bootstrap.min.js"></script>
<script src="common/js/angular.min.js"></script>
<script src="common/js/angular-route.min.js"></script>
</th:block>
</html>

View File

@ -1,124 +0,0 @@
<!DOCTYPE html>
<html>
<head th:replace="fragments/mainParts.html :: htmlHeader('Datasources')"></head>
<script th:inline="javascript">
/*<![CDATA[*/
function getField() { return /*[[${field}]]*/ ''; }
function getValue() { return /*[[${value}]]*/ ''; }
/*]]>*/
</script>
<body ng-app="dsmResultsApp" ng-controller="dsmResultsController">
<nav th:replace="fragments/mainParts.html :: mainMenu('Datasources')"></nav>
<div class="container-fluid">
<div class="row mt-5">
<div class="col">
<p class="text-muted">
<b>Number of results:</b> {{nResults}}<br />
<b>Page:</b> {{currPage}} / {{nPages}}
</p>
<p ng-show="results.length > 0">
<input type="text" class="form-control form-control-sm" ng-model="apiFilter" placeholder="Filter in current page..."/>
</p>
<div class="card mb-4 small" ng-repeat="r in results|filter:apiFilter">
<div class="card-body">
<h5 class="card-title" title="{{r.id}}">{{r.name}}
<span style="font-size: 0.6em" ng-if="r.otherName && r.name != r.otherName"><br />{{r.otherName}}</span>
</h5>
<table class="table table-sm">
<tr>
<th style="width: 20em;">Id</th>
<td>{{r.id}}</td>
</tr><tr>
<th>Type</th>
<td>{{r.type}}</td>
</tr><tr>
<th>Collected From</th>
<td>{{r.collectedFrom}}</td>
</tr><tr ng-if="r.websiteUrl">
<th>URL</th>
<td><a href="{{r.websiteUrl}}" target="_blank">{{r.websiteUrl}}</a></td>
</tr><tr>
<th>Namespace Prefix</th>
<td>{{r.nsprefix}}</td>
</tr>
<tr ng-if="r.organizations">
<th>Organization(s)</th>
<td>
<span ng-repeat="o in r.organizations">
{{o.name}}
<img src="common/images/flags/{{o.country}}.gif" title="{{o.country}}" alt="" ng-if="o.country"/>
<br />
</span>
</td>
</tr><tr>
<th>APIs</th>
<td>
<div ng-repeat="a in r.apis" ng-if="a.id">
<span class="monospaced">{{a.id}}</span>
<span class="badge badge-primary" title="protocol">{{a.protocol}}</span>
<span class="badge badge-info" title="compliance">{{a.compliance}}</span>
<span class="badge badge-success" ng-if="a.active">active</span><span class="badge badge-danger" ng-if="!a.active">not active</span>
<span ng-if="a.aggrDate"><br/><b>Last aggregation:</b> {{a.aggrDate}} <b>(total: {{a.aggrTotal}})</b></span>
</div>
</td>
</tr><tr ng-if="r.consenttermsofuse">
<th>Consent Terms of Use</th>
<td><span class="badge badge-success">YES</span></td>
</tr><tr ng-if="r.fulltextdownload">
<th>Fulltext Download</th>
<td><span class="badge badge-success">YES</span></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</body>
<th:block th:replace="fragments/mainParts.html :: scripts"></th:block>
<script>
var app = angular.module('dsmResultsApp', []);
app.controller('dsmResultsController', function($scope, $http) {
$scope.field = getField();
$scope.value = getValue();
$scope.results = [];
$scope.nResults = 0;
$scope.currPage = 0;
$scope.nPages = 1;
$scope.pageSize = 100;
$scope.loadPage = function(page) {
var url = './ajax/dsm/';
if ($scope.field) { url += 'searchByField/' + encodeURIComponent($scope.field); }
else { url += 'search' }
url += '/' + (page - 1) + '/' + $scope.pageSize;
url += '?value=' + encodeURIComponent($scope.value) + '&' + $.now();
$http.get(url).then(function successCallback(res) {
$scope.results = res.data.content;
$scope.nResults = res.data.totalElements;
$scope.currPage = res.data.number + 1;
$scope.nPages = res.data.totalPages;
}, function errorCallback(res) {
alert('ERROR: ' + res.data.message);
});
}
$scope.loadPage(1);
});
</script>
</html>

View File

@ -1,118 +0,0 @@
<!DOCTYPE html>
<html>
<head th:replace="fragments/mainParts.html :: htmlHeader('Search Datasources')"></head>
<body ng-app="dsmSearchApp" ng-controller="dsmSearchController">
<nav th:replace="fragments/mainParts.html :: mainMenu('Search Datasources')"></nav>
<div class="container-fluid">
<div class="row mt-5">
<div class="offset-md-3 col-md-6 offset-lg-4 col-lg-4">
<form>
<div class="input-group">
<input type="text" class="form-control" ng-model="textApiSearch" placeholder="Search..."/>
<span class="input-group-append">
<button type="submit" class="btn btn-primary" ng-click="search('', textApiSearch)">Search</button>
</span>
</div>
</form>
</div>
</div>
<div class="row mt-5">
<div class="offset-md-3 col-md-6 offset-lg-4 col-lg-4">
<p>
<b>Or browse using:</b>
<ul>
<li th:each="f: ${browsableFields}">
<a href="javascript:void(0)"
data-toggle="modal" data-target="#showBrowseData"
th:attr="ng-click='browseField(\''+ ${f} + '\',\'' + ${f.desc} + '\')'"
th:text="${f.desc}"></a>
</li>
</ul>
</p>
</div>
</div>
</div>
<div id="showBrowseData" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">{{browseFieldName}}</h4>
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body small">
<input type="text" class="form-control input-sm" ng-model="filterBrowseData" placeholder="Filter..." />
<table class="table table-sm table-striped mt-4" style="table-layout: fixed;">
<thead>
<tr>
<th>
<a href="javascript:void(0)" ng-click="sortType = 'name'; sortReverse = !sortReverse">
Name
<i class="fa fa-sort-up" ng-show="sortType == 'name' && sortReverse" ></i>
<i class="fa fa-sort-down" ng-show="sortType == 'name' && !sortReverse"></i>
</a>
</th>
<th class="text-right">
<a href="javascript:void(0)" ng-click="sortType = 'total'; sortReverse = !sortReverse">
# datasources
<i class="fa fa-sort-up" ng-show="sortType == 'total' && sortReverse" ></i>
<i class="fa fa-sort-down" ng-show="sortType == 'total' && !sortReverse"></i>
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in browseData | orderBy:sortType:sortReverse | filter:filterBrowseData">
<th><a href="javascript:void(0)" ng-click="search(browseFieldId, row.term)">{{row.name}}</a></td>
<td class="text-right">{{row.total}}</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
<th:block th:replace="fragments/mainParts.html :: scripts"></th:block>
<script>
var app = angular.module('dsmSearchApp', []);
app.controller('dsmSearchController', function($scope, $http) {
$scope.browseFieldId = "";
$scope.browseFieldName = "";
$scope.browseData = [];
$scope.browseField = function(id, label) {
$scope.browseFieldId = id;
$scope.browseFieldName = name;
$scope.browseData = [];
$http.get('./ajax/dsm/browse/' + encodeURIComponent(id) + '?' + $.now()).then(function successCallback(res) {
$scope.browseData = res.data;
}, function errorCallback(res) {
alert('ERROR: ' + res.data.message);
});
}
$scope.search = function(field, value) {
var url = "resultsDatasources?"
if (field) { url += "field=" + encodeURIComponent(field) + "&" }
url += "value=" + encodeURIComponent(value)
location.href = url;
}
});
</script>
</html>