menu refactoring
This commit is contained in:
parent
5a76d32f15
commit
aa24a5475d
|
@ -216,13 +216,18 @@ public class OrganizationController {
|
||||||
: organizationSimpleViewRepository.searchForUser(q, authentication.getName(), PageRequest.of(page, size));
|
: organizationSimpleViewRepository.searchForUser(q, authentication.getName(), PageRequest.of(page, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/byCountry/{code}/{page}/{size}")
|
@GetMapping("/byCountry/{status}/{code}/{page}/{size}")
|
||||||
public Page<OrganizationSimpleView> findByCountry(@PathVariable final String code,
|
public Page<OrganizationSimpleView> findByCountry(@PathVariable final String status,
|
||||||
|
@PathVariable final String code,
|
||||||
@PathVariable final int page,
|
@PathVariable final int page,
|
||||||
@PathVariable final int size,
|
@PathVariable final int size,
|
||||||
final Authentication authentication) {
|
final Authentication authentication) {
|
||||||
if (UserInfo.isSuperAdmin(authentication) || userCountryRepository.verifyAuthorizationForCountry(code, authentication.getName())) {
|
if (UserInfo.isSuperAdmin(authentication) || userCountryRepository.verifyAuthorizationForCountry(code, authentication.getName())) {
|
||||||
return organizationSimpleViewRepository.findByCountryOrderByName(code, PageRequest.of(page, size));
|
if (status.equalsIgnoreCase("all")) {
|
||||||
|
return organizationSimpleViewRepository.findByCountryOrderByName(code, PageRequest.of(page, size));
|
||||||
|
} else {
|
||||||
|
return organizationSimpleViewRepository.findByCountryAndStatusOrderByName(code, status, PageRequest.of(page, size));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("User not authorized");
|
throw new RuntimeException("User not authorized");
|
||||||
}
|
}
|
||||||
|
@ -243,14 +248,27 @@ public class OrganizationController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/byType/{type}/{page}/{size}")
|
@GetMapping("/byType/{status}/{type}/{page}/{size}")
|
||||||
public Page<OrganizationSimpleView> findByType(@PathVariable final String type,
|
public Page<OrganizationSimpleView> findByType(@PathVariable final String status,
|
||||||
|
@PathVariable final String type,
|
||||||
@PathVariable final int page,
|
@PathVariable final int page,
|
||||||
@PathVariable final int size,
|
@PathVariable final int size,
|
||||||
final Authentication authentication) {
|
final Authentication authentication) {
|
||||||
return UserInfo.isSuperAdmin(authentication)
|
|
||||||
? organizationSimpleViewRepository.findByTypeOrderByName(type, PageRequest.of(page, size))
|
if (UserInfo.isSuperAdmin(authentication)) {
|
||||||
: organizationSimpleViewRepository.findByTypeForUser(type, authentication.getName(), PageRequest.of(page, size));
|
if (status.equalsIgnoreCase("all")) {
|
||||||
|
return organizationSimpleViewRepository.findByTypeOrderByName(type, PageRequest.of(page, size));
|
||||||
|
} else {
|
||||||
|
return organizationSimpleViewRepository.findByTypeAndStatusOrderByName(type, status, PageRequest.of(page, size));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (status.equalsIgnoreCase("all")) {
|
||||||
|
return organizationSimpleViewRepository.findByTypeForUser(type, authentication.getName(), PageRequest.of(page, size));
|
||||||
|
} else {
|
||||||
|
return organizationSimpleViewRepository.findByTypeAndStatusForUser(type, status, authentication.getName(), PageRequest.of(page, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/browse/countries")
|
@GetMapping("/browse/countries")
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package eu.dnetlib.organizations.model.utils;
|
package eu.dnetlib.organizations.model.utils;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class BrowseEntry implements Serializable {
|
public class BrowseEntry implements Serializable {
|
||||||
|
|
||||||
|
@ -9,17 +11,16 @@ public class BrowseEntry implements Serializable {
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 8854955977257064470L;
|
private static final long serialVersionUID = 8854955977257064470L;
|
||||||
|
|
||||||
private String value;
|
private String code;
|
||||||
private String name;
|
private String name;
|
||||||
private int approved;
|
private Map<String, Integer> values = new LinkedHashMap<>();
|
||||||
private int pending;
|
|
||||||
|
|
||||||
public String getValue() {
|
public String getCode() {
|
||||||
return value;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(final String value) {
|
public void setCode(final String code) {
|
||||||
this.value = value;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -30,20 +31,12 @@ public class BrowseEntry implements Serializable {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApproved() {
|
public Map<String, Integer> getValues() {
|
||||||
return approved;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApproved(final int approved) {
|
public void setValues(final Map<String, Integer> values) {
|
||||||
this.approved = approved;
|
this.values = values;
|
||||||
}
|
|
||||||
|
|
||||||
public int getPending() {
|
|
||||||
return pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPending(final int pending) {
|
|
||||||
this.pending = pending;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.dnetlib.organizations.model.utils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class TempBrowseEntry implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -2233409680550512318L;
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
private String name;
|
||||||
|
private String group;
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(final String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroup() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroup(final String group) {
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCount(final Integer count) {
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,9 +25,16 @@ public interface OrganizationSimpleViewRepository extends ReadOnlyRepository<Org
|
||||||
|
|
||||||
Iterable<OrganizationSimpleView> findByCountryAndStatusOrderByName(String code, String status);
|
Iterable<OrganizationSimpleView> findByCountryAndStatusOrderByName(String code, String status);
|
||||||
|
|
||||||
|
Page<OrganizationSimpleView> findByCountryAndStatusOrderByName(String code, String status, Pageable pageable);
|
||||||
|
|
||||||
Page<OrganizationSimpleView> findByTypeOrderByName(String type, Pageable pageable);
|
Page<OrganizationSimpleView> findByTypeOrderByName(String type, Pageable pageable);
|
||||||
|
|
||||||
|
Page<OrganizationSimpleView> findByTypeAndStatusOrderByName(String type, String status, Pageable pageable);
|
||||||
|
|
||||||
@Query(value = "select o.* from organizations_simple_view o left outer join user_countries uc on (uc.country = o.country) where uc.email = ?2 and o.type = ?1 order by o.name", nativeQuery = true)
|
@Query(value = "select o.* from organizations_simple_view o left outer join user_countries uc on (uc.country = o.country) where uc.email = ?2 and o.type = ?1 order by o.name", nativeQuery = true)
|
||||||
Page<OrganizationSimpleView> findByTypeForUser(String type, String name, Pageable pageable);
|
Page<OrganizationSimpleView> findByTypeForUser(String type, String name, Pageable pageable);
|
||||||
|
|
||||||
|
@Query(value = "select o.* from organizations_simple_view o left outer join user_countries uc on (uc.country = o.country) where o.type = ?1 and o.status = ?2 and uc.email = ?3 order by o.name", nativeQuery = true)
|
||||||
|
Page<OrganizationSimpleView> findByTypeAndStatusForUser(String type, String status, String name, Pageable pageable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import eu.dnetlib.organizations.model.User;
|
||||||
import eu.dnetlib.organizations.model.UserCountry;
|
import eu.dnetlib.organizations.model.UserCountry;
|
||||||
import eu.dnetlib.organizations.model.utils.BrowseEntry;
|
import eu.dnetlib.organizations.model.utils.BrowseEntry;
|
||||||
import eu.dnetlib.organizations.model.utils.OrganizationConflict;
|
import eu.dnetlib.organizations.model.utils.OrganizationConflict;
|
||||||
|
import eu.dnetlib.organizations.model.utils.TempBrowseEntry;
|
||||||
import eu.dnetlib.organizations.model.utils.VocabularyTerm;
|
import eu.dnetlib.organizations.model.utils.VocabularyTerm;
|
||||||
import eu.dnetlib.organizations.model.view.OrganizationView;
|
import eu.dnetlib.organizations.model.view.OrganizationView;
|
||||||
import eu.dnetlib.organizations.model.view.UserView;
|
import eu.dnetlib.organizations.model.view.UserView;
|
||||||
|
@ -280,36 +281,51 @@ public class DatabaseUtils {
|
||||||
// BROWSE BY COUNTRY
|
// BROWSE BY COUNTRY
|
||||||
public List<BrowseEntry> browseCountries() {
|
public List<BrowseEntry> browseCountries() {
|
||||||
final String sql =
|
final String sql =
|
||||||
"select o.country as value, c.name as name, sum(case when status='approved' then 1 else 0 end) as approved, sum(case when status='pending' then 1 else 0 end) as pending from organizations o left outer join countries c on (o.country = c.val) group by o.country, c.name order by approved desc";
|
"select o.country as code, c.name as name, o.status as group, count(o.status) as count from organizations o left outer join countries c on (o.country = c.val) group by o.country, c.name, o.status";
|
||||||
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class));
|
return listBrowseEntries(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BROWSE BY COUNTRY FOR USER
|
// BROWSE BY COUNTRY FOR USER
|
||||||
public List<BrowseEntry> browseCountriesForUser(final String email) {
|
public List<BrowseEntry> browseCountriesForUser(final String email) {
|
||||||
final String sql =
|
final String sql =
|
||||||
"select o.country as value, c.name as name, sum(case when status='approved' then 1 else 0 end) as approved, sum(case when status='pending' then 1 else 0 end) as pending from user_countries uc left outer join organizations o on (uc.country = o.country) left outer join countries c on (o.country = c.val) where uc.email=? group by o.country, c.name order by approved desc";
|
"select o.country as code, c.name as name, o.status as group, count(o.status) as count from user_countries uc left outer join organizations o on (uc.country = o.country) left outer join countries c on (o.country = c.val) where uc.email=? group by o.country, c.name, o.status";
|
||||||
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class), email);
|
return listBrowseEntries(sql, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BROWSE BY ORG TYPE
|
// BROWSE BY ORG TYPE
|
||||||
public List<BrowseEntry> browseTypes() {
|
public List<BrowseEntry> browseTypes() {
|
||||||
final String sql =
|
final String sql =
|
||||||
"select type as value, type as name, sum(case when status='approved' then 1 else 0 end) as approved, sum(case when status='pending' then 1 else 0 end) as pending from organizations group by type order by approved desc";
|
"select type as code, type as name, status as group, count(status) as count from organizations group by type, status";
|
||||||
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class));
|
return listBrowseEntries(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BROWSE BY ORG TYPE FOR USER
|
// BROWSE BY ORG TYPE FOR USER
|
||||||
public List<BrowseEntry> browseTypesForUser(final String email) {
|
public List<BrowseEntry> browseTypesForUser(final String email) {
|
||||||
final String sql = "select o.type as value, o.type as name,"
|
final String sql = "select o.type as code, o.type as name,"
|
||||||
+ "sum(case when status='approved' then 1 else 0 end) as approved, "
|
+ "o.status as group, count(o.status) as count "
|
||||||
+ "sum(case when status='pending' then 1 else 0 end) as pending "
|
|
||||||
+ "from organizations o "
|
+ "from organizations o "
|
||||||
+ "left outer join user_countries uc on (uc.country = o.country) "
|
+ "left outer join user_countries uc on (uc.country = o.country) "
|
||||||
+ "where uc.email=? "
|
+ "where uc.email=? "
|
||||||
+ "group by o.type "
|
+ "group by o.type, o.status";
|
||||||
+ "order by approved desc;";
|
return listBrowseEntries(sql, email);
|
||||||
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BrowseEntry.class), email);
|
}
|
||||||
|
|
||||||
|
private List<BrowseEntry> listBrowseEntries(final String sql, final Object... params) {
|
||||||
|
final Map<String, BrowseEntry> map = new HashMap<>();
|
||||||
|
|
||||||
|
for (final TempBrowseEntry t : jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TempBrowseEntry.class), params)) {
|
||||||
|
if (StringUtils.isNotBlank(t.getCode())) {
|
||||||
|
if (!map.containsKey(t.getCode())) {
|
||||||
|
final BrowseEntry e = new BrowseEntry();
|
||||||
|
e.setCode(t.getCode());
|
||||||
|
e.setName(t.getName());
|
||||||
|
map.put(t.getCode(), e);
|
||||||
|
}
|
||||||
|
map.get(t.getCode()).getValues().put(t.getGroup(), t.getCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map.values().stream().sorted((o1, o2) -> StringUtils.compare(o1.getName(), o2.getName())).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<OrganizationConflict> listConflictsForId(final String id) {
|
public List<OrganizationConflict> listConflictsForId(final String id) {
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<table class="table table-sm table-hover col-lg-5">
|
|
||||||
<thead class="thead-light">
|
|
||||||
<tr>
|
|
||||||
<th>{{field}}</th>
|
|
||||||
<th class="text-right text-nowrap"># approved</th>
|
|
||||||
<th class="text-right text-nowrap"># pending</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="e in entries">
|
|
||||||
<td><a href="#!{{resultsBasePath}}/0/50/{{e.value}}">{{e.name}}<span ng-if="e.value != e.name"> ({{e.value}})</span></a></td>
|
|
||||||
<td class="text-right">{{e.approved}}</td>
|
|
||||||
<td class="text-right">{{e.pending}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
|
@ -1,42 +0,0 @@
|
||||||
<div>
|
|
||||||
|
|
||||||
<div class="text-muted" ng-if="conflicts.length == 0">No suggestions</div>
|
|
||||||
|
|
||||||
<div class="input-group input-group-sm mb-3" ng-show="conflicts.length > 0">
|
|
||||||
<input type="text" class="form-control" ng-model="conflictFilter" placeholder="Filter...">
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text text-outline-primary">Country:</span>
|
|
||||||
<button class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown">{{country}}</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<small>
|
|
||||||
<a class="dropdown-item" href="#!/suggestions/{{c}}/2"
|
|
||||||
ng-repeat="(c, vals) in info.byCountry"
|
|
||||||
ng-if="vals.nConflicts > 0">
|
|
||||||
{{c}} <span class="badge badge-danger float-right">{{vals.nConflicts}}</span>
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card text-white mb-3" ng-repeat="w in conflicts | filter:conflictFilter" class="mb-2">
|
|
||||||
<div class="card-header bg-primary text-white py-1">Group {{$index+1}}</div>
|
|
||||||
<table class="table table-sm">
|
|
||||||
<tr ng-repeat="o in w">
|
|
||||||
<th style="width:40px" class="text-center">#{{$index+1}}</th>
|
|
||||||
<td><a href="#!/edit/0/{{o.id}}" title="{{o.id}}">{{o.name}}</a></td>
|
|
||||||
<td style="width:250px"><img ng-src="resources/images/flags/{{o.country}}.gif" /> {{o.city || '-'}}, {{o.country}}</td>
|
|
||||||
<td style="width:80px" class="text-right">{{o.type}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="card-footer bg-secondary py-1">
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-sm btn-primary"
|
|
||||||
data-toggle="modal" data-target="#resolveConflictsModal"
|
|
||||||
ng-click="prepareConflictsModal(w)">resolve</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<resolve-conflicts-modal modal-id="resolveConflictsModal" orgs="orgs" selected-orgs="selectedOrgs"></resolve-conflicts-modal>
|
|
|
@ -1,62 +0,0 @@
|
||||||
<div>
|
|
||||||
|
|
||||||
<div class="text-muted" ng-if="duplicates.length == 0">No suggestions</div>
|
|
||||||
|
|
||||||
<div class="input-group input-group-sm mb-3" ng-show="duplicates.length > 0">
|
|
||||||
<input type="text" class="form-control" ng-model="duplicateFilter" placeholder="Filter...">
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text text-outline-primary">Country:</span>
|
|
||||||
<button class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown">{{country}}</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<small>
|
|
||||||
<a class="dropdown-item" href="#!/suggestions/{{c}}/1"
|
|
||||||
ng-repeat="(c, vals) in info.byCountry"
|
|
||||||
ng-if="vals.nDuplicates > 0">
|
|
||||||
{{c}} <span class="badge badge-primary float-right">{{vals.nDuplicates}}</span>
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="table table-sm table-hover" ng-if="duplicates.length > 0">
|
|
||||||
<thead class="thead-light">
|
|
||||||
<tr class="d-flex">
|
|
||||||
<th class="col-8">Organization</th>
|
|
||||||
<th class="col-3">Place</th>
|
|
||||||
<th class="col-1 text-right"># pending duplicates</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="d in duplicates | filter:duplicateFilter" class="d-flex">
|
|
||||||
<td class="col-8">
|
|
||||||
<a href="javascript:void(0)" title="{{d.id}}" ng-click="prepareDuplicatesModal(d)" data-toggle="modal" data-target="#duplicatesModal">{{d.name}}</a>
|
|
||||||
<a href="#!/edit/0/{{d.id}}" title="edit"><i class="fa fa-edit"></i></a>
|
|
||||||
</td>
|
|
||||||
<td class="col-3"><img ng-src="resources/images/flags/{{d.country}}.gif" /> {{d.city || '-'}}, {{d.country}}</td>
|
|
||||||
<td class="col-1 text-right">{{d.numberOfDuplicates}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade" id="duplicatesModal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog modal-xl" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{{currentOrg.name}}</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="text-muted" ng-if="currentDuplicates.length == 0">No duplicates</div>
|
|
||||||
<org-details org="currentOrgDetails" org-title="Registered organization" show="default"></org-details>
|
|
||||||
<org-form-duplicates duplicates="currentDuplicates"></org-form-duplicates>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="saveCurrentDuplicates()" ng-if="currentDuplicates.length > 0">Save changes</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
<div>
|
|
||||||
|
|
||||||
<div class="text-muted" ng-if="orgs.length == 0">No suggestions</div>
|
|
||||||
|
|
||||||
<div class="input-group input-group-sm mb-3" ng-show="orgs.length > 0">
|
|
||||||
<input type="text" class="form-control" ng-model="orgFilter" placeholder="Filter..."/>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text text-outline-primary">Country:</span>
|
|
||||||
<button class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown">{{country}}</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<small>
|
|
||||||
<a class="dropdown-item" href="#!/suggestions/{{c}}/0"
|
|
||||||
ng-repeat="(c, vals) in info.byCountry"
|
|
||||||
ng-if="vals.nPendingOrgs > 0">
|
|
||||||
{{c}} <span class="badge badge-primary float-right">{{vals.nPendingOrgs}}</span>
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="table table-sm table-hover" ng-if="orgs.length > 0">
|
|
||||||
<thead class="thead-light">
|
|
||||||
<tr class="d-flex">
|
|
||||||
<th class="col-6">Organization name</th>
|
|
||||||
<th class="col-4">Place</th>
|
|
||||||
<th class="col-1 text-center">Acronyms</th>
|
|
||||||
<th class="col-1 text-right">Type</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="o in orgs | filter:orgFilter" class="d-flex">
|
|
||||||
<td class="col-6">
|
|
||||||
<a href="#!/edit/0/{{o.id}}" title="{{o.id}}">{{o.name}}</a>
|
|
||||||
</td>
|
|
||||||
<td class="col-4"><img ng-src="resources/images/flags/{{o.country}}.gif" /> {{o.city || '-'}}, {{o.country}}</td>
|
|
||||||
<td class="col-1 text-center">{{o.acronyms.join()}}</td>
|
|
||||||
<td class="col-1 text-right">{{o.type}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<h2>Conflicts</h2>
|
||||||
|
|
||||||
|
<h4 class="text-muted" ng-if="conflicts.length == 0">No suggestions</h4>
|
||||||
|
|
||||||
|
<div class="input-group input-group-sm mb-3" ng-show="conflicts.length > 0">
|
||||||
|
<input type="text" class="form-control" ng-model="conflictFilter" placeholder="Filter...">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text text-outline-primary">Country:</span>
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown">{{country}}</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<small>
|
||||||
|
<a class="dropdown-item" href="#!/conflicts/{{c}}"
|
||||||
|
ng-repeat="(c, vals) in info.data.byCountry"
|
||||||
|
ng-if="vals.nConflicts > 0">
|
||||||
|
{{c}} <span class="badge badge-danger float-right">{{vals.nConflicts}}</span>
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card text-white mb-3" ng-repeat="w in conflicts | filter:conflictFilter" class="mb-2">
|
||||||
|
<div class="card-header bg-primary text-white py-1">Group {{$index+1}}</div>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<tr ng-repeat="o in w">
|
||||||
|
<th style="width:40px" class="text-center">#{{$index+1}}</th>
|
||||||
|
<td><a href="#!/edit/0/{{o.id}}" title="{{o.id}}">{{o.name}}</a></td>
|
||||||
|
<td style="width:250px"><img ng-src="resources/images/flags/{{o.country}}.gif" /> {{o.city || '-'}}, {{o.country}}</td>
|
||||||
|
<td style="width:80px" class="text-right">{{o.type}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div class="card-footer bg-secondary py-1">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-primary"
|
||||||
|
data-toggle="modal" data-target="#resolveConflictsModal"
|
||||||
|
ng-click="prepareConflictsModal(w)">resolve</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<resolve-conflicts-modal modal-id="resolveConflictsModal" orgs="orgs" selected-orgs="selectedOrgs"></resolve-conflicts-modal>
|
|
@ -0,0 +1,60 @@
|
||||||
|
<h2>Duplicates</h2>
|
||||||
|
|
||||||
|
<h4 class="text-muted" ng-if="duplicates.length == 0">No duplicates</h4>
|
||||||
|
|
||||||
|
<div class="input-group input-group-sm mb-3" ng-show="duplicates.length > 0">
|
||||||
|
<input type="text" class="form-control" ng-model="duplicateFilter" placeholder="Filter...">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text text-outline-primary">Country:</span>
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown">{{country}}</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<small>
|
||||||
|
<a class="dropdown-item" href="#!/duplicates/{{c}}"
|
||||||
|
ng-repeat="(c, vals) in info.data.byCountry"
|
||||||
|
ng-if="vals.nDuplicates > 0">
|
||||||
|
{{c}} <span class="badge badge-primary float-right">{{vals.nDuplicates}}</span>
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-sm table-hover" ng-if="duplicates.length > 0">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr class="d-flex">
|
||||||
|
<th class="col-8">Organization</th>
|
||||||
|
<th class="col-3">Place</th>
|
||||||
|
<th class="col-1 text-right"># pending duplicates</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="d in duplicates | filter:duplicateFilter" class="d-flex">
|
||||||
|
<td class="col-8">
|
||||||
|
<a href="javascript:void(0)" title="{{d.id}}" ng-click="prepareDuplicatesModal(d)" data-toggle="modal" data-target="#duplicatesModal">{{d.name}}</a>
|
||||||
|
<a href="#!/edit/0/{{d.id}}" title="edit"><i class="fa fa-edit"></i></a>
|
||||||
|
</td>
|
||||||
|
<td class="col-3"><img ng-src="resources/images/flags/{{d.country}}.gif" /> {{d.city || '-'}}, {{d.country}}</td>
|
||||||
|
<td class="col-1 text-right">{{d.numberOfDuplicates}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="modal fade" id="duplicatesModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog modal-xl" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{{currentOrg.name}}</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="text-muted" ng-if="currentDuplicates.length == 0">No duplicates</div>
|
||||||
|
<org-details org="currentOrgDetails" org-title="Registered organization" show="default"></org-details>
|
||||||
|
<org-form-duplicates duplicates="currentDuplicates"></org-form-duplicates>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="saveCurrentDuplicates()" ng-if="currentDuplicates.length > 0">Save changes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<h2>Pending Organizations</h2>
|
||||||
|
|
||||||
|
<h4 class="text-muted" ng-if="orgs.length == 0">No pending organizations</h4>
|
||||||
|
|
||||||
|
<div class="input-group input-group-sm mb-3" ng-show="orgs.length > 0">
|
||||||
|
<input type="text" class="form-control" ng-model="orgFilter" placeholder="Filter..."/>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text text-outline-primary">Country:</span>
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown">{{country}}</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<small>
|
||||||
|
<a class="dropdown-item" href="#!/pendings/{{c}}"
|
||||||
|
ng-repeat="(c, vals) in info.data.byCountry"
|
||||||
|
ng-if="vals.nPendingOrgs > 0">
|
||||||
|
{{c}} <span class="badge badge-primary float-right">{{vals.nPendingOrgs}}</span>
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-sm table-hover" ng-if="orgs.length > 0">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr class="d-flex">
|
||||||
|
<th class="col-6">Organization name</th>
|
||||||
|
<th class="col-4">Place</th>
|
||||||
|
<th class="col-1 text-center">Acronyms</th>
|
||||||
|
<th class="col-1 text-right">Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="o in orgs | filter:orgFilter" class="d-flex">
|
||||||
|
<td class="col-6">
|
||||||
|
<a href="#!/edit/0/{{o.id}}" title="{{o.id}}">{{o.name}}</a>
|
||||||
|
</td>
|
||||||
|
<td class="col-4"><img ng-src="resources/images/flags/{{o.country}}.gif" /> {{o.city || '-'}}, {{o.country}}</td>
|
||||||
|
<td class="col-1 text-center">{{o.acronyms.join()}}</td>
|
||||||
|
<td class="col-1 text-right">{{o.type}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<h2>{{title}}</h2>
|
||||||
|
|
||||||
|
<h4 class="text-muted" ng-if="entries.length == 0">No entries</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<input type="text" class="form-control col-lg-8 col-xs-12" ng-show="entries.length > 0" ng-model="browseFilter" placeholder="Filter...">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="table table-sm table-bordered table-hover col-lg-8 col-xs-12">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th class="col-6">{{field}}</th>
|
||||||
|
<th class="col-1 text-right text-nowrap"># approved</th>
|
||||||
|
<th class="col-1 text-right text-nowrap"># pending</th>
|
||||||
|
<th class="col-1 text-right text-nowrap"># deleted</th>
|
||||||
|
<th class="col-1 text-right text-nowrap"># duplicated</th>
|
||||||
|
<th class="col-1 text-right text-nowrap"># discarded</th>
|
||||||
|
<th class="col-1 text-right text-nowrap"># hidden</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="e in entries | filter: browseFilter">
|
||||||
|
<th>{{e.name}} <span ng-if="e.code != e.name"> ({{e.code}})</span></th>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="#!{{resultsBasePath}}/0/50/approved/{{e.code}}" ng-if="e.values.approved && e.values.approved > 0">{{e.values.approved}}</a>
|
||||||
|
<span ng-if="!e.values.approved || e.values.approved == 0">-</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="#!{{resultsBasePath}}/0/50/pending/{{e.code}}" ng-if="e.values.pending && e.values.pending > 0">{{e.values.pending}}</a>
|
||||||
|
<span ng-if="!e.values.pending || e.values.pending == 0">-</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="#!{{resultsBasePath}}/0/50/deleted/{{e.code}}" ng-if="e.values.deleted && e.values.deleted > 0">{{e.values.deleted}}</a>
|
||||||
|
<span ng-if="!e.values.deleted || e.values.deleted == 0">-</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="#!{{resultsBasePath}}/0/50/duplicate/{{e.code}}" ng-if="e.values.duplicate && e.values.duplicate > 0">{{e.values.duplicate}}</a>
|
||||||
|
<span ng-if="!e.values.duplicate || e.values.duplicate == 0">-</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="#!{{resultsBasePath}}/0/50/discarded/{{e.code}}" ng-if="e.values.discarded && e.values.discarded > 0">{{e.values.discarded}}</a>
|
||||||
|
<span ng-if="!e.values.discarded || e.values.discarded == 0">-</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="#!{{resultsBasePath}}/0/50/hidden/{{e.code}}" ng-if="e.values.hidden && e.values.hidden > 0">{{e.values.hidden}}</a>
|
||||||
|
<span ng-if="!e.values.hidden || e.values.hidden == 0">-</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -1,23 +0,0 @@
|
||||||
<div class="card">
|
|
||||||
|
|
||||||
<div class="card-header">
|
|
||||||
<ul class="nav nav-tabs card-header-tabs">
|
|
||||||
<li class="nav-item text-nowrap">
|
|
||||||
<a href="#!/suggestions/_/0" class="nav-link" ng-class="{'active': currentTab == 0}">Pending Organizations <span class="badge badge-primary ml-2">{{info.total.nPendingOrgs}}</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item text-nowrap">
|
|
||||||
<a href="#!/suggestions/_/1" class="nav-link" ng-class="{'active': currentTab == 1}">New Duplicates <span class="badge badge-primary ml-2">{{info.total.nDuplicates}}</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item text-nowrap">
|
|
||||||
<a href="#!/suggestions/_/2" class="nav-link" ng-class="{'active': currentTab == 2}">New Conflicts <span class="badge badge-danger ml-2">{{info.total.nConflicts}}</span></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body">
|
|
||||||
<pending-orgs orgs="pendingOrgs" country="{{country}}" info="info" info-method="getInfo()" ng-if="currentTab == 0"></pending-orgs>
|
|
||||||
<all-duplicates duplicates="duplicates" country="{{country}}" info="info" info-method="getInfo()" ng-if="currentTab == 1"></all-duplicates>
|
|
||||||
<all-conflicts conflicts="conflicts" country="{{country}}" info="info" info-method="getInfo()" ng-if="currentTab == 2"></all-conflicts>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
|
@ -17,6 +17,34 @@ orgsModule.service('vocabulariesService', function($http) {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
orgsModule.factory('suggestionInfo', function($http) {
|
||||||
|
var info = { data : {} };
|
||||||
|
|
||||||
|
var getInfo = function() { return info; };
|
||||||
|
|
||||||
|
var updateInfo = function(callback) {
|
||||||
|
$http.get('api/organizations/suggestionsInfo').then(function successCallback(res) {
|
||||||
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
|
info.data = res.data;
|
||||||
|
if (callback) { callback(info); }
|
||||||
|
}, function errorCallback(res) {
|
||||||
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
getInfo: getInfo,
|
||||||
|
updateInfo: updateInfo
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
orgsModule.controller('menuCtrl', function ($scope, suggestionInfo) {
|
||||||
|
$scope.info = suggestionInfo.getInfo();
|
||||||
|
suggestionInfo.updateInfo(null);
|
||||||
|
});
|
||||||
|
|
||||||
orgsModule.directive('selectOrgModal', function($http) {
|
orgsModule.directive('selectOrgModal', function($http) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
|
@ -265,52 +293,6 @@ orgsModule.directive('orgResultsPage', function($http, $location, $route) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
orgsModule.directive('allConflicts', function($http, $location, $route, $q) {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
scope: {
|
|
||||||
'conflicts' : '=',
|
|
||||||
'country' : '@',
|
|
||||||
'info' : '=',
|
|
||||||
'infoMethod' : '&'
|
|
||||||
},
|
|
||||||
templateUrl: 'resources/html/forms/all_conflicts.html',
|
|
||||||
link: function(scope, element, attrs, ctrl) {
|
|
||||||
scope.orgs = [];
|
|
||||||
|
|
||||||
scope.prepareConflictsModal = function(list) {
|
|
||||||
scope.orgs = [];
|
|
||||||
scope.selectedOrgs = [];
|
|
||||||
|
|
||||||
var gets = list.map((o) => $http.get('api/organizations/get?id=' + o.id));
|
|
||||||
|
|
||||||
$q.all(gets).then(function(responses) {
|
|
||||||
scope.orgs = responses.map((resp) => resp.data);
|
|
||||||
angular.forEach(scope.orgs, function(org) { org.show = 'secondary'; });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
orgsModule.directive('pendingOrgs', function($http, $location, $route, $q) {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
scope: {
|
|
||||||
'orgs' : '=',
|
|
||||||
'country' : '@',
|
|
||||||
'info' : '=',
|
|
||||||
'infoMethod' : '&'
|
|
||||||
},
|
|
||||||
templateUrl: 'resources/html/forms/pending_orgs.html',
|
|
||||||
link: function(scope, element, attrs, ctrl) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
orgsModule.directive('orgFormDuplicates', function($http, $location, $route) {
|
orgsModule.directive('orgFormDuplicates', function($http, $location, $route) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
|
@ -354,83 +336,21 @@ orgsModule.directive('orgFormConflicts', function($http, $location, $route, $q)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
orgsModule.directive('allDuplicates', function($http, $location, $route, $timeout) {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
scope: {
|
|
||||||
'duplicates' : '=',
|
|
||||||
'country' : '@',
|
|
||||||
'info' : '=',
|
|
||||||
'infoMethod' : '&'
|
|
||||||
},
|
|
||||||
templateUrl: 'resources/html/forms/all_duplicates.html',
|
|
||||||
link: function(scope, element, attrs, ctrl) {
|
|
||||||
scope.currentOrg = {};
|
|
||||||
scope.currentOrgDetails = {};
|
|
||||||
scope.currentDuplicates = [];
|
|
||||||
|
|
||||||
scope.prepareDuplicatesModal = function(org) {
|
|
||||||
scope.currentOrg = org;
|
|
||||||
scope.currentOrgDetails = {};
|
|
||||||
scope.currentDuplicates = [];
|
|
||||||
|
|
||||||
$http.get('api/organizations/get?id=' + org.id).then(function successCallback(res) {
|
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
|
||||||
scope.currentOrgDetails = res.data;
|
|
||||||
}, function errorCallback(res) {
|
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
|
||||||
});
|
|
||||||
|
|
||||||
$http.get('api/organizations/duplicates?id=' + org.id).then(function successCallback(res) {
|
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
|
||||||
scope.currentDuplicates = res.data;
|
|
||||||
}, function errorCallback(res) {
|
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.saveCurrentDuplicates = function() {
|
|
||||||
$http.defaults.headers.post["Content-Type"] = "application/json;charset=UTF-8";
|
|
||||||
$http.post('api/organizations/duplicates', scope.currentDuplicates).then(function successCallback(res) {
|
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
|
||||||
if (scope.infoMethod) { scope.infoMethod(); }
|
|
||||||
scope.currentOrg.numberOfDuplicates = 0;
|
|
||||||
for (var i=0; i<res.data.length; i++) {
|
|
||||||
if (res.data[i].relType == 'suggested') {
|
|
||||||
scope.currentOrg.numberOfDuplicates++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.currentDuplicates = [];
|
|
||||||
|
|
||||||
$timeout(function() {
|
|
||||||
if (scope.duplicates.length > 1) {
|
|
||||||
$route.reload();
|
|
||||||
} else {
|
|
||||||
$location.url('/suggestions/_/1');
|
|
||||||
}
|
|
||||||
}, 600);
|
|
||||||
|
|
||||||
}, function errorCallback(res) {
|
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
orgsModule.config(function($routeProvider) {
|
orgsModule.config(function($routeProvider) {
|
||||||
$routeProvider
|
$routeProvider
|
||||||
.when('/new', { templateUrl: 'resources/html/new.html', controller: 'newOrgCtrl' })
|
.when('/search', { templateUrl: 'resources/html/pages/search/search.html', controller: 'searchCtrl' })
|
||||||
.when('/search', { templateUrl: 'resources/html/search.html', controller: 'searchCtrl' })
|
.when('/searchResults/:page/:size/:text*', { templateUrl: 'resources/html/pages/search/searchResults.html', controller: 'searchResultsCtrl' })
|
||||||
.when('/searchResults/:page/:size/:text*', { templateUrl: 'resources/html/searchResults.html', controller: 'searchResultsCtrl' })
|
.when('/countries', { templateUrl: 'resources/html/pages/search/browse.html', controller: 'countriesCtrl' })
|
||||||
.when('/countries', { templateUrl: 'resources/html/browse.html', controller: 'countriesCtrl' })
|
.when('/byCountry/:page/:size/:status/:code*', { templateUrl: 'resources/html/pages/search/resultsByCountry.html', controller: 'byCountryCtrl' })
|
||||||
.when('/byCountry/:page/:size/:code*', { templateUrl: 'resources/html/resultsByCountry.html', controller: 'byCountryCtrl' })
|
.when('/types', { templateUrl: 'resources/html/pages/search/browse.html', controller: 'typesCtrl' })
|
||||||
.when('/types', { templateUrl: 'resources/html/browse.html', controller: 'typesCtrl' })
|
.when('/byType/:page/:size/:status/:type*', { templateUrl: 'resources/html/pages/search/resultsByType.html', controller: 'byTypeCtrl' })
|
||||||
.when('/byType/:page/:size/:type*', { templateUrl: 'resources/html/resultsByType.html', controller: 'byTypeCtrl' })
|
.when('/edit/:msg/:id', { templateUrl: 'resources/html/pages/edit/edit.html', controller: 'showEditCtrl' })
|
||||||
.when('/edit/:msg/:id', { templateUrl: 'resources/html/edit.html', controller: 'showEditCtrl' })
|
.when('/new', { templateUrl: 'resources/html/pages/advanced/new.html', controller: 'newOrgCtrl' })
|
||||||
.when('/suggestions/:country/:tab', { templateUrl: 'resources/html/suggestions.html', controller: 'showSuggestionsCtrl' })
|
.when('/pendings/:country', { templateUrl: 'resources/html/pages/advanced/pendingOrgs.html', controller: 'pendingOrgsCtrl' })
|
||||||
.when('/users', { templateUrl: 'resources/html/users.html', controller: 'usersCtrl' })
|
.when('/duplicates/:country', { templateUrl: 'resources/html/pages/advanced/duplicates.html', controller: 'duplicatesCtrl' })
|
||||||
.otherwise({ redirectTo: '/suggestions/_/0' });
|
.when('/conflicts/:country', { templateUrl: 'resources/html/pages/advanced/conflicts.html', controller: 'conflictsCtrl' })
|
||||||
|
.when('/users', { templateUrl: 'resources/html/pages/admin/users.html', controller: 'usersCtrl' })
|
||||||
|
.otherwise({ redirectTo: '/search' });
|
||||||
});
|
});
|
||||||
|
|
||||||
orgsModule.filter('escape', function() {
|
orgsModule.filter('escape', function() {
|
||||||
|
@ -511,6 +431,8 @@ orgsModule.controller('searchResultsCtrl', function ($scope, $http, $routeParams
|
||||||
});
|
});
|
||||||
|
|
||||||
orgsModule.controller('countriesCtrl', function ($scope, $http, $routeParams) {
|
orgsModule.controller('countriesCtrl', function ($scope, $http, $routeParams) {
|
||||||
|
|
||||||
|
$scope.title = 'Countries';
|
||||||
$scope.field = 'Country';
|
$scope.field = 'Country';
|
||||||
$scope.resultsBasePath = '/byCountry'
|
$scope.resultsBasePath = '/byCountry'
|
||||||
$scope.entries = [];
|
$scope.entries = [];
|
||||||
|
@ -528,7 +450,7 @@ orgsModule.controller('byCountryCtrl', function ($scope, $http, $routeParams, $l
|
||||||
$scope.fieldValue = decodeURIComponent($routeParams.code);
|
$scope.fieldValue = decodeURIComponent($routeParams.code);
|
||||||
$scope.orgs = {};
|
$scope.orgs = {};
|
||||||
|
|
||||||
$http.get('api/organizations/byCountry/' + $routeParams.code + '/' + $routeParams.page + '/' + $routeParams.size).then(function successCallback(res) {
|
$http.get('api/organizations/byCountry/' + $routeParams.status + '/' + $routeParams.code + '/' + $routeParams.page + '/' + $routeParams.size).then(function successCallback(res) {
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
$scope.orgs = res.data;
|
$scope.orgs = res.data;
|
||||||
}, function errorCallback(res) {
|
}, function errorCallback(res) {
|
||||||
|
@ -536,16 +458,17 @@ orgsModule.controller('byCountryCtrl', function ($scope, $http, $routeParams, $l
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.prev = function() {
|
$scope.prev = function() {
|
||||||
$location.url('/byCountry/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.fieldValue));
|
$location.url('/byCountry/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/' + $routeParams.status + '/' + encodeURIComponent($scope.fieldValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.next = function() {
|
$scope.next = function() {
|
||||||
$location.url('/byCountry/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.fieldValue));
|
$location.url('/byCountry/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/' + $routeParams.status + '/' + encodeURIComponent($scope.fieldValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
orgsModule.controller('typesCtrl', function ($scope, $http, $routeParams) {
|
orgsModule.controller('typesCtrl', function ($scope, $http, $routeParams) {
|
||||||
|
$scope.title = 'Organization types';
|
||||||
$scope.field = 'Organization type';
|
$scope.field = 'Organization type';
|
||||||
$scope.resultsBasePath = '/byType'
|
$scope.resultsBasePath = '/byType'
|
||||||
$scope.entries = [];
|
$scope.entries = [];
|
||||||
|
@ -565,7 +488,7 @@ orgsModule.controller('byTypeCtrl', function ($scope, $http, $routeParams, $loca
|
||||||
|
|
||||||
$scope.orgs = {};
|
$scope.orgs = {};
|
||||||
|
|
||||||
$http.get('api/organizations/byType/' + $routeParams.type + '/' + $routeParams.page + '/' + $routeParams.size).then(function successCallback(res) {
|
$http.get('api/organizations/byType/' + $routeParams.status + '/' + $routeParams.type + '/' + $routeParams.page + '/' + $routeParams.size).then(function successCallback(res) {
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
$scope.orgs = res.data;
|
$scope.orgs = res.data;
|
||||||
}, function errorCallback(res) {
|
}, function errorCallback(res) {
|
||||||
|
@ -573,11 +496,11 @@ orgsModule.controller('byTypeCtrl', function ($scope, $http, $routeParams, $loca
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.prev = function() {
|
$scope.prev = function() {
|
||||||
$location.url('/byType/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.fieldValue));
|
$location.url('/byType/' + ($scope.orgs.number - 1) + '/' + $scope.orgs.size + '/' + $routeParams.status + '/' + encodeURIComponent($scope.fieldValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.next = function() {
|
$scope.next = function() {
|
||||||
$location.url('/byType/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/' + encodeURIComponent($scope.fieldValue));
|
$location.url('/byType/' + ($scope.orgs.number + 1) + '/' + $scope.orgs.size + '/' + $routeParams.status + '/' + encodeURIComponent($scope.fieldValue));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -612,62 +535,35 @@ orgsModule.controller('showEditCtrl', function ($scope, $http, $routeParams, $ro
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
orgsModule.controller('showSuggestionsCtrl', function ($scope, $http, $routeParams, $location) {
|
orgsModule.controller('pendingOrgsCtrl', function ($scope, $http, $routeParams, $location, suggestionInfo) {
|
||||||
$scope.info = {};
|
$scope.info = suggestionInfo.getInfo();
|
||||||
$scope.pendingOrgs = [];
|
$scope.orgs = [];
|
||||||
$scope.duplicates = [];
|
|
||||||
$scope.conflicts = [];
|
|
||||||
$scope.currentTab = $routeParams.tab;
|
|
||||||
$scope.country = $routeParams.country;
|
$scope.country = $routeParams.country;
|
||||||
|
|
||||||
$scope.getInfo = function() {
|
$scope.getInfo = function() {
|
||||||
$http.get('api/organizations/suggestionsInfo').then(function successCallback(res) {
|
suggestionInfo.updateInfo(function(info) {
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
if ($scope.country == '_') {
|
||||||
$scope.info = res.data;
|
var found = '';
|
||||||
if ($scope.country == '_') {
|
angular.forEach(info.data.byCountry, function(values, c) {
|
||||||
var found = '';
|
if (!found && values.nPendingOrgs > 0) {
|
||||||
|
found = c;
|
||||||
angular.forEach($scope.info.byCountry, function(values, c) {
|
}
|
||||||
if (!found && (($scope.currentTab == 0 && values.nPendingOrgs > 0) || ($scope.currentTab == 1 && values.nDuplicates > 0) || ($scope.currentTab == 2 && values.nConflicts > 0))) {
|
});
|
||||||
found = c;
|
if (found) { $location.url('/pendings/' + found); }
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (found) { $location.url('/suggestions/' + found + '/' + $scope.currentTab); }
|
|
||||||
}
|
|
||||||
}, function errorCallback(res) {
|
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
$scope.refresh = function() {
|
$scope.refresh = function() {
|
||||||
$scope.pendingOrgs = [];
|
$scope.orgs = [];
|
||||||
$scope.duplicates = [];
|
|
||||||
$scope.conflicts = [];
|
|
||||||
|
|
||||||
if ($scope.country != '_') {
|
if ($scope.country != '_') {
|
||||||
if ($scope.currentTab == 0) {
|
$http.get('api/organizations/byCountry/pending/' + $scope.country).then(function successCallback(res) {
|
||||||
$http.get('api/organizations/byCountry/pending/' + $scope.country).then(function successCallback(res) {
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
$scope.orgs = res.data;
|
||||||
$scope.pendingOrgs = res.data;
|
}, function errorCallback(res) {
|
||||||
}, function errorCallback(res) {
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
});
|
||||||
});
|
|
||||||
} else if ($scope.currentTab == 1) {
|
|
||||||
$http.get('api/organizations/duplicates/byCountry/' + $scope.country).then(function successCallback(res) {
|
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
|
||||||
$scope.duplicates = res.data;
|
|
||||||
}, function errorCallback(res) {
|
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
|
||||||
});
|
|
||||||
} else if ($scope.currentTab == 2) {
|
|
||||||
$http.get('api/organizations/conflicts/byCountry/' + $scope.country).then(function successCallback(res) {
|
|
||||||
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
|
||||||
$scope.conflicts = res.data;
|
|
||||||
}, function errorCallback(res) {
|
|
||||||
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
|
||||||
});
|
|
||||||
} else { }
|
|
||||||
}
|
}
|
||||||
$scope.getInfo();
|
$scope.getInfo();
|
||||||
}
|
}
|
||||||
|
@ -675,6 +571,143 @@ orgsModule.controller('showSuggestionsCtrl', function ($scope, $http, $routePara
|
||||||
$scope.refresh();
|
$scope.refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
orgsModule.controller('duplicatesCtrl', function ($scope, $http, $routeParams, $location, $timeout, $route, suggestionInfo) {
|
||||||
|
$scope.info = suggestionInfo.getInfo();
|
||||||
|
$scope.duplicates = [];
|
||||||
|
$scope.country = $routeParams.country;
|
||||||
|
$scope.currentOrg = {};
|
||||||
|
$scope.currentOrgDetails = {};
|
||||||
|
|
||||||
|
$scope.prepareDuplicatesModal = function(org) {
|
||||||
|
$scope.currentOrg = org;
|
||||||
|
$scope.currentOrgDetails = {};
|
||||||
|
$scope.currentDuplicates = [];
|
||||||
|
|
||||||
|
$http.get('api/organizations/get?id=' + org.id).then(function successCallback(res) {
|
||||||
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
|
$scope.currentOrgDetails = res.data;
|
||||||
|
}, function errorCallback(res) {
|
||||||
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
|
});
|
||||||
|
|
||||||
|
$http.get('api/organizations/duplicates?id=' + org.id).then(function successCallback(res) {
|
||||||
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
|
$scope.currentDuplicates = res.data;
|
||||||
|
}, function errorCallback(res) {
|
||||||
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getInfo = function() {
|
||||||
|
suggestionInfo.updateInfo(function(info) {
|
||||||
|
if ($scope.country == '_') {
|
||||||
|
var found = '';
|
||||||
|
angular.forEach(info.data.byCountry, function(values, c) {
|
||||||
|
if (!found && values.nDuplicates > 0) {
|
||||||
|
found = c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (found) { $location.url('/duplicates/' + found); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.saveCurrentDuplicates = function() {
|
||||||
|
$http.defaults.headers.post["Content-Type"] = "application/json;charset=UTF-8";
|
||||||
|
$http.post('api/organizations/duplicates', $scope.currentDuplicates).then(function successCallback(res) {
|
||||||
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
|
|
||||||
|
$scope.getInfo();
|
||||||
|
|
||||||
|
$scope.currentOrg.numberOfDuplicates = 0;
|
||||||
|
for (var i=0; i<res.data.length; i++) {
|
||||||
|
if (res.data[i].relType == 'suggested') {
|
||||||
|
$scope.currentOrg.numberOfDuplicates++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope.currentDuplicates = [];
|
||||||
|
|
||||||
|
$timeout(function() {
|
||||||
|
if ($scope.duplicates.length > 1) {
|
||||||
|
$route.reload();
|
||||||
|
} else {
|
||||||
|
$location.url('/duplicates/_');
|
||||||
|
}
|
||||||
|
}, 600);
|
||||||
|
|
||||||
|
}, function errorCallback(res) {
|
||||||
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.refresh = function() {
|
||||||
|
$scope.duplicates = [];
|
||||||
|
|
||||||
|
if ($scope.country != '_') {
|
||||||
|
$http.get('api/organizations/duplicates/byCountry/' + $scope.country).then(function successCallback(res) {
|
||||||
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
|
$scope.duplicates = res.data;
|
||||||
|
}, function errorCallback(res) {
|
||||||
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$scope.getInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
orgsModule.controller('conflictsCtrl', function ($scope, $http, $routeParams, $location, $route, $q, suggestionInfo) {
|
||||||
|
$scope.info = suggestionInfo.getInfo();
|
||||||
|
$scope.conflicts = [];
|
||||||
|
$scope.country = $routeParams.country;
|
||||||
|
$scope.orgs = [];
|
||||||
|
|
||||||
|
$scope.prepareConflictsModal = function(list) {
|
||||||
|
$scope.orgs = [];
|
||||||
|
$scope.selectedOrgs = [];
|
||||||
|
|
||||||
|
var gets = list.map((o) => $http.get('api/organizations/get?id=' + o.id));
|
||||||
|
|
||||||
|
$q.all(gets).then(function(responses) {
|
||||||
|
$scope.orgs = responses.map((resp) => resp.data);
|
||||||
|
angular.forEach($scope.orgs, function(org) { org.show = 'secondary'; });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.getInfo = function() {
|
||||||
|
suggestionInfo.updateInfo(function(info) {
|
||||||
|
if ($scope.country == '_') {
|
||||||
|
var found = '';
|
||||||
|
|
||||||
|
angular.forEach(info.data.byCountry, function(values, c) {
|
||||||
|
if (!found && values.nConflicts > 0) {
|
||||||
|
found = c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (found) { $location.url('/conflicts/' + found); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.refresh = function() {
|
||||||
|
$scope.conflicts = [];
|
||||||
|
|
||||||
|
if ($scope.country != '_') {
|
||||||
|
$http.get('api/organizations/conflicts/byCountry/' + $scope.country).then(function successCallback(res) {
|
||||||
|
if((typeof res.data) == 'string') { alert("Session expired !"); location.reload(true); }
|
||||||
|
$scope.conflicts = res.data;
|
||||||
|
}, function errorCallback(res) {
|
||||||
|
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$scope.getInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
orgsModule.controller('usersCtrl', function ($scope, $http, $timeout, $route, vocabulariesService) {
|
orgsModule.controller('usersCtrl', function ($scope, $http, $timeout, $route, vocabulariesService) {
|
||||||
$scope.users = [];
|
$scope.users = [];
|
||||||
|
|
|
@ -15,16 +15,9 @@
|
||||||
<link rel="stylesheet" href="resources/css/fontawesome-all.min.css">
|
<link rel="stylesheet" href="resources/css/fontawesome-all.min.css">
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.table > tbody > tr > td {
|
.table > tbody > tr > td { vertical-align : middle !important; }
|
||||||
vertical-align: middle;
|
.card > .table { margin-bottom : 0 !important; }
|
||||||
}
|
fieldset > legend { font-size : 1.2rem !important; }
|
||||||
.card > .table {
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset > legend {
|
|
||||||
font-size: 1.2rem !important;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +26,7 @@ fieldset > legend {
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body ng-app="orgs" sec:authorize="isAuthenticated()">
|
<body ng-app="orgs" sec:authorize="isAuthenticated()">
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-primary" ng-controller="menuCtrl">
|
||||||
<a class="navbar-brand" href="#"> <img
|
<a class="navbar-brand" href="#"> <img
|
||||||
src="resources/images/openaire_logo_small.png" width="30" height="30" alt="OpenOrgs Database">
|
src="resources/images/openaire_logo_small.png" width="30" height="30" alt="OpenOrgs Database">
|
||||||
OpenOrgs Database
|
OpenOrgs Database
|
||||||
|
@ -45,7 +38,6 @@ fieldset > legend {
|
||||||
|
|
||||||
<div class="collapse navbar-collapse w-100 order-1" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse w-100 order-1" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav mr-auto">
|
<ul class="navbar-nav mr-auto">
|
||||||
<li class="nav-item"><a class="nav-link" href="#!/suggestions/_/0">Last suggestions</a></li>
|
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown">Search</a>
|
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown">Search</a>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
|
@ -55,17 +47,23 @@ fieldset > legend {
|
||||||
<a class="dropdown-item" href="#!/types">browse by type</a>
|
<a class="dropdown-item" href="#!/types">browse by type</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_ADMIN') or hasRole('ROLE_NATIONAL_ADMIN')">
|
||||||
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown">Actions</a>
|
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown">Advanced</a>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<a class="dropdown-item" href="#!/new">register an organization</a>
|
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#!/pendings/_"><span class="pr-2">pending organizations</span><span class="badge badge-primary badge-pill">{{info.data.total.nPendingOrgs}}</span></a>
|
||||||
|
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#!/duplicates/_"><span class="pr-2">duplicates</span><span class="badge badge-primary badge-pill">{{info.data.total.nDuplicates}}</span></a>
|
||||||
|
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#!/conflicts/_"><span class="pr-2">conflicts</span><span class="badge badge-danger badge-pill">{{info.data.total.nConflicts}}</span></a>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<a class="dropdown-item" href="#!/new">new from scratch</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_USER')">
|
||||||
|
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown">Advanced</a>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#!/duplicates/_"><span class="pr-2">duplicates</span><span class="badge badge-primary badge-pill">{{info.total.nDuplicates}}</span></a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="navbar-collapse collapse w-100 order-2">
|
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto">
|
||||||
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_ADMIN') or hasRole('ROLE_NATIONAL_ADMIN')">
|
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_ADMIN') or hasRole('ROLE_NATIONAL_ADMIN')">
|
||||||
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown"><i class="fa fa-cog"></i></a>
|
<a class="nav-link dropdown-toggle" href="javascript:void(0)" data-toggle="dropdown"><i class="fa fa-cog"></i></a>
|
||||||
|
@ -84,7 +82,7 @@ fieldset > legend {
|
||||||
<a class="dropdown-item" th:href="@{/logout}">Logout</a>
|
<a class="dropdown-item" th:href="@{/logout}">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item"><a class="btn btn-outline-secondary" href="doc">API</a></li>
|
<li class="nav-item"><a class="btn btn-outline-secondary" href="doc" target="_blank">API</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue