Merge branch 'develop' into new-claims-api

This commit is contained in:
argirok 2023-10-11 15:46:21 +03:00
commit 3f64332a8f
45 changed files with 434 additions and 182 deletions

View File

@ -6,6 +6,7 @@ import {EnvProperties} from '../../utils/properties/env-properties';
import {Subscriber} from "rxjs"; import {Subscriber} from "rxjs";
import {OpenaireEntities} from "../../utils/properties/searchFields"; import {OpenaireEntities} from "../../utils/properties/searchFields";
import {CommunitiesService} from "../../connect/communities/communities.service"; import {CommunitiesService} from "../../connect/communities/communities.service";
import {UserManagementService} from "../../services/user-management.service";
declare var UIkit: any; declare var UIkit: any;
@ -46,9 +47,14 @@ export class ClaimContextSearchFormComponent {
keyword = ""; keyword = "";
subscriptions = []; subscriptions = [];
communityLogos = {}; communityLogos = {};
communityIds = [];
user = null;
ngOnInit() { ngOnInit() {
this.entitiesSelectOptions = this.showOptions.selectOptions; this.entitiesSelectOptions = this.showOptions.selectOptions;
//get community logos //get community logos
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user;
this.subscriptions.push(this._communitiesService.getCommunities(this.properties, this.properties.communityAPI+"/communities/").subscribe( this.subscriptions.push(this._communitiesService.getCommunities(this.properties, this.properties.communityAPI+"/communities/").subscribe(
communitiesResults => { communitiesResults => {
if(communitiesResults!=null) { if(communitiesResults!=null) {
@ -58,6 +64,13 @@ export class ClaimContextSearchFormComponent {
this.communityLogos[community.communityId] = community; this.communityLogos[community.communityId] = community;
} }
} }
this.communityIds = communitiesResults.filter(community => {
return community.claim == "all" ||
Session.isCommunityCurator(this.user) ||
Session.isClaimsCurator(this.user) ||
(community.claim == "membersOnly" && Session.isSubscribedTo("community", community.communityId,this.user)) ||
(community.claim == "managersOnly" && Session.isManager("community", community.communityId,this.user))
}).map(community => community.communityId);
this.getCommunities(); this.getCommunities();
} }
}, },
@ -65,6 +78,10 @@ export class ClaimContextSearchFormComponent {
this.getCommunities(); this.getCommunities();
} }
)); ));
}, error => {
}));
} }
ngOnDestroy() { ngOnDestroy() {
@ -74,7 +91,7 @@ export class ClaimContextSearchFormComponent {
} }
}); });
} }
constructor(private _contextService: ContextsService, private router: Router, private _communitiesService: CommunitiesService) { constructor(private _contextService: ContextsService, private router: Router, private _communitiesService: CommunitiesService, private userManagementService: UserManagementService,) {
} }
@ -165,15 +182,16 @@ export class ClaimContextSearchFormComponent {
getCommunities() { getCommunities() {
this.loading = true; this.loading = true;
this.subscriptions.push(this._contextService.getPublicCommunitiesByState().subscribe( this.subscriptions.push(this._contextService.getCommunitiesByState().subscribe(
data => { data => {
this.communities = data; this.communities = data.filter(community => {
console.log(this.communities) return this.communityIds.indexOf(community.id) != -1
});
if (this.communities.length > 0) { if (this.communities.length > 0) {
this.communities.sort((n1, n2) => n1.label > n2.label); this.communities.sort((n1, n2) => n1.title > n2.title);
} }
this.loading = false; this.loading = false;
if (this.communityId != null) { if (this.communityId != null && this.communityIds.indexOf(this.communityId) != -1) {
//preselect community //preselect community
this.selectedCommunityId = this.communityId; this.selectedCommunityId = this.communityId;
for (let i = 0; i < this.communities.length; i++) { for (let i = 0; i < this.communities.length; i++) {

View File

@ -56,12 +56,11 @@ export class CommunitiesService {
result['description'] = resData.description; result['description'] = resData.description;
result['date'] = resData.creationDate; result['date'] = resData.creationDate;
result['status'] = 'all'; result['status'] = 'all';
result['claim'] = resData.claim;
result['membership'] = resData.membership;
if (resData.hasOwnProperty('status')) { if (resData.hasOwnProperty('status')) {
result['status'] = resData.status; result['status'] = resData.status;
const status = ['all', 'hidden', 'manager']; result.validateStatus();
if (status.indexOf(result['status']) === -1) {
result['status'] = 'hidden';
}
} }
if (resData.type != null) { if (resData.type != null) {
result['type'] = resData.type; result['type'] = resData.type;

View File

@ -98,14 +98,14 @@ export class CommunityService {
community.description = resData.description; community.description = resData.description;
community.date = resData.creationDate; community.date = resData.creationDate;
community.zenodoCommunity = resData.zenodoCommunity; community.zenodoCommunity = resData.zenodoCommunity;
community.status = 'all'; community.status = 'PUBLIC';
community.claim = resData.claim;
community.membership = resData.membership;
community.type = resData.type; community.type = resData.type;
community.otherZenodoCommunities = resData.otherZenodoCommunities;
if (resData.hasOwnProperty('status')) { if (resData.hasOwnProperty('status')) {
community.status = resData.status; community.status = resData.status;
const status = ['all', 'hidden', 'manager']; community.validateStatus();
if (status.indexOf(community['status']) === -1) {
community.status = 'hidden';
}
} }
if (resData.subjects != null) { if (resData.subjects != null) {
community.subjects = Array.isArray(resData.subjects)?resData.subjects:[resData.subjects]; community.subjects = Array.isArray(resData.subjects)?resData.subjects:[resData.subjects];

View File

@ -1,5 +1,4 @@
import {StringUtils} from "../../utils/string-utils.class"; import {StringUtils} from "../../utils/string-utils.class";
import {properties} from "../../../../environments/environment";
import {SelectionCriteria} from "../../utils/entities/contentProvider"; import {SelectionCriteria} from "../../utils/entities/contentProvider";
export class CommunityInfo { export class CommunityInfo {
@ -14,8 +13,11 @@ export class CommunityInfo {
managers: string[]; managers: string[];
date:Date; date:Date;
subjects: string[]; subjects: string[];
status:string; status:"all" | "manager" | "hidden" | "PUBLIC" | "RESTRICTED" | "PRIVATE";
claim: "all" | "managersOnly" | "membersOnly";
membership: "open" | "byInvitation";
zenodoCommunity:string; zenodoCommunity:string;
otherZenodoCommunities: string[];
isUpload: boolean; isUpload: boolean;
isSubscribed: boolean; isSubscribed: boolean;
isManager: boolean; isManager: boolean;
@ -33,5 +35,24 @@ export class CommunityInfo {
} }
return response; return response;
} }
public isOpen() {
return !(this.membership && this.membership === 'byInvitation');
}
public isPublic(){
return this.status == "all" || this.status == "PUBLIC";
}
public isRestricted(){
return this.status == "manager" || this.status == "RESTRICTED";
}
public isPrivate(){
return this.status == "hidden" || this.status == "PRIVATE";
}
public validateStatus(){
if(!(this.isPrivate() || this.isRestricted() || this.isPublic())){
this.status = "PRIVATE";
}
}
} }
// export const prodReadyCommunities = ["dh-ch", "ee", "fam", "mes", "ni", "covid-19", "dariah", "epos", "egi"]; // export const prodReadyCommunities = ["dh-ch", "ee", "fam", "mes", "ni", "covid-19", "dariah", "epos", "egi"];

View File

@ -1,6 +1,7 @@
import {HttpParams} from '@angular/common/http'; import {HttpParams} from '@angular/common/http';
import {properties} from "../../../environments/environment"; import {properties} from "../../../environments/environment";
import {Session} from "../login/utils/helper.class"; import {Session} from "../login/utils/helper.class";
import {CommunityInfo} from "./community/communityInfo";
export class ConnectHelper { export class ConnectHelper {
@ -53,7 +54,12 @@ export class ConnectHelper {
} }
public static isPrivate(community, user) { public static isPrivate(community: CommunityInfo, user) {
return community && (community.status == "hidden" || (community.status == "manager" && !(Session.isPortalAdministrator(user) || Session.isCommunityCurator(user) || Session.isManager("community", community.communityId, user)))) return community && (community.isPrivate() || (community.isRestricted() && !(
Session.isPortalAdministrator(user) ||
Session.isCommunityCurator(user) ||
Session.isManager("community", community.communityId, user) ||
(!community.isOpen() && Session.isMember('community', community.communityId, user))
)))
} }
} }

View File

@ -7,15 +7,25 @@ import {map} from "rxjs/operators";
export class SearchCommunityProjectsService { export class SearchCommunityProjectsService {
constructor(private http: HttpClient ) {} constructor(private http: HttpClient ) {}
searchProjects (properties:EnvProperties, pid: string):any { searchProjects (properties:EnvProperties, pid: string, page=1, size=500):any {
let url = properties.communityAPI+pid+"/projects"; return this.searchProjectsWithPaging(properties,pid,page, size, null, null);
}
searchProjectsWithPaging (properties:EnvProperties, pid: string, page=1, size=500, searchFilter, funder, orderBy = "name"):any {
let params = funder ? ["funder="+ funder] :[];
if (searchFilter) {
params.push("searchFilter="+ searchFilter)
}
params.push("orderBy="+ orderBy);
let url = properties.communityAPI+pid+"/projects/"+ (page-1) + "/" + size + (params.length > 0?"?" + params.join("&"):"");
return this.http.get((properties.useCache)? (properties.cacheUrl+encodeURIComponent(url)): url); return this.http.get((properties.useCache)? (properties.cacheUrl+encodeURIComponent(url)): url);
//.map(res => <any> res.json())
} }
countTotalProjects(properties:EnvProperties,pid:string) { countTotalProjects(properties:EnvProperties,pid:string) {
let url = properties.communityAPI+pid+"/projects"; let url = properties.communityAPI+pid+"/projects/0/1";
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
.pipe(map(res => res['length'])); .pipe(map(res => res['totalElements']));
}
getProjectFunders(properties:EnvProperties,pid:string) {
let url = properties.communityAPI+pid+"/funders";
return this.http.get<string[]>((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url);
} }
} }

View File

@ -1,15 +0,0 @@
import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import{EnvProperties} from '../../utils/properties/env-properties';
@Injectable()
export class SearchZenodoCommunitiesService {
constructor(private http: HttpClient ) {}
searchZCommunities (properties:EnvProperties, pid: string):any {
let url = properties.communityAPI+pid+"/zenodocommunities";
return this.http.get((properties.useCache)? (properties.cacheUrl+encodeURIComponent(url)): url);
//.map(res => <any> res.json())
}
}

View File

@ -1,21 +0,0 @@
import { NgModule} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {SearchZenodoCommunitiesService} from './searchZenodoCommunities.service';
@NgModule({
imports: [
CommonModule, FormsModule
],
declarations: [
],
providers:[
SearchZenodoCommunitiesService
],
exports: [
]
})
export class SearchZenodoCommunitiesServiceModule { }

View File

@ -16,12 +16,11 @@ export class ZenodoCommunitiesService {
//.map(res => <any> res.json()) //.map(res => <any> res.json())
.pipe(map(res => [this.parseZenodoCommunities(res['hits'].hits),res['hits'].total])); .pipe(map(res => [this.parseZenodoCommunities(res['hits'].hits),res['hits'].total]));
} }
getZenodoCommunityById(properties:EnvProperties, url: string, openaireId:string) { getZenodoCommunityById(properties:EnvProperties, url: string) {
return this.http.get((properties.useLongCache)? (properties.cacheUrl+encodeURIComponent(url)) : url) return this.http.get((properties.useLongCache)? (properties.cacheUrl+encodeURIComponent(url)) : url)
//.map(res => <any> res.json()) //.map(res => <any> res.json())
.pipe(map(res => { .pipe(map(res => {
var community = this.parseZenodoCommunity(res); var community = this.parseZenodoCommunity(res);
community["openaireId"]=openaireId;
return community; return community;
})); }));
} }

View File

@ -6,5 +6,4 @@ export class ZenodoCommunityInfo {
logoUrl: string; logoUrl: string;
date: Date; date: Date;
page: string; page: string;
openaireId:string;
} }

View File

@ -216,6 +216,7 @@ export class FosComponent implements OnInit, OnDestroy {
} }
public buildFosQueryParam(fos) { public buildFosQueryParam(fos) {
return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}; // return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)};
return (properties.environment !== 'production' ? ({'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}) : ({'fos': this.urlEncodeAndQuote(fos.id)}));
} }
} }

View File

@ -11,44 +11,59 @@ import {RouterHelper} from "../../utils/routerHelper.class";
selector: 'availableOn', selector: 'availableOn',
template: ` template: `
<ng-container *ngIf="availableOn && availableOn.length > 0"> <ng-container *ngIf="availableOn && availableOn.length > 0">
<div class="uk-flex uk-flex-middle" [ngClass]="isMobile && !(usedBy == 'landing') ? 'uk-margin-left uk-margin-xsmall-bottom' : ''"> <div class="uk-flex uk-flex-middle"
<ng-container *ngIf="availableOn[0].downloadUrl"> [ngClass]="isMobile ? ('uk-flex-column ' + (!(usedBy == 'landing') ? 'uk-margin-left uk-margin-xsmall-bottom' : '')) : 'uk-grid uk-grid-small uk-child-width-auto'"
<span [class]="'uk-margin-xsmall-right ' + (availableOn[0].accessRightIcon == 'open_access' ? 'open-access' : 'closed-access')" [attr.uk-grid]="!isMobile ? '' : null">
uk-tooltip [title]="getAccessLabel(availableOn[0].accessRight)"> <div *ngIf="properties.environment != 'production' && availableOn[0].fulltext" class="uk-flex uk-flex-middle"
<icon [name]="availableOn[0].accessRightIcon" [flex]="true" [ratio]="(isMobile && usedBy == 'landing') ? 1 : 0.8"></icon> [ngClass]="isMobile ? 'uk-width-1-1' : 'uk-text-bolder'">
</span> <a [href]="availableOn[0].fulltext" target="_blank"
<ng-container *ngIf="!isMobile"> class="uk-flex uk-flex-middle uk-button-link"
<a uk-tooltip="Source" target="_blank" [ngClass]="isMobile ? ((usedBy == 'landing') ? 'uk-width-1-1 uk-padding-small uk-padding-remove-horizontal' : '') : 'uk-flex-center'">
class="uk-flex uk-flex-middle uk-flex-center uk-button-link uk-text-bolder"> <!-- <icon [flex]="true" [ratio]="0.7" name="download" visuallyHidden="download"></icon>-->
<span>{{sliceString(availableOn[0].downloadNames.join("; "), 20)}}</span> <icon name="download" visuallyHidden="donwload" [flex]="true" [ratio]="(isMobile && usedBy == 'landing') ? 1 : 0.8"></icon>
<span> <span class="uk-margin-xsmall-left">Full-Text</span>
<!-- <icon [flex]="true" [name]="'expand_' + (isOpen?'less':'more')"></icon>--> </a>
<icon [flex]="true" [name]="(isOpen?'arrow_drop_up':'arrow_drop_down')"></icon> </div>
</span> <div *ngIf="isMobile && (usedBy == 'landing') && availableOn[0].fulltext" class="uk-width-1-1"><hr></div>
</a> <div *ngIf="availableOn[0].downloadUrl" [ngClass]="isMobile ? 'uk-width-1-1' : ''">
<div #dropElement uk-drop="mode: click; pos: bottom-left;" <div class="uk-flex uk-flex-middle" [ngClass]="isMobile ? ((usedBy == 'landing') ? 'uk-padding-small uk-padding-remove-horizontal' : '') : ''">
class="uk-drop download-drop uk-card uk-card-default uk-padding-small uk-padding-remove-horizontal uk-text-small uk-height-max-large uk-overflow-auto"> <span [class]="'uk-margin-xsmall-right ' + (availableOn[0].accessRightIcon == 'open_access' ? 'open-access' : 'closed-access')"
<ng-container *ngTemplateOutlet="availableOnList"></ng-container> uk-tooltip [title]="getAccessLabel(availableOn[0].accessRight)">
</div> <icon [name]="availableOn[0].accessRightIcon" [flex]="true" [ratio]="(isMobile && usedBy == 'landing') ? 1 : 0.8"></icon>
</ng-container>
<ng-container *ngIf="isMobile">
<a #toggle class="uk-flex uk-flex-between uk-flex-middle uk-flex-center uk-width-expand uk-button-link">
<span>{{sliceString(availableOn[0].downloadNames.join("; "), 20)}}</span>
<span>
<icon [flex]="true" ratio="1.5" name="arrow_right"></icon>
</span> </span>
</a> <ng-container *ngIf="!isMobile">
<mobile-dropdown [toggle]="toggle"> <a uk-tooltip="Source" target="_blank"
<div class="uk-text-emphasis uk-text-bolder uk-text-center uk-padding-small uk-padding-remove-vertical uk-text-uppercase"> class="uk-flex uk-flex-middle uk-flex-center uk-button-link uk-text-bolder">
Sources <span>{{sliceString(availableOn[0].downloadNames.join("; "), 20)}}</span>
</div> <span>
<div class="uk-text-small download-drop uk-padding uk-padding-remove-horizontal"> <!-- <icon [flex]="true" [name]="'expand_' + (isOpen?'less':'more')"></icon>-->
<icon [flex]="true" [name]="(isOpen?'arrow_drop_up':'arrow_drop_down')"></icon>
</span>
</a>
<div #dropElement uk-drop="mode: click; pos: bottom-left;"
class="uk-drop download-drop uk-card uk-card-default uk-padding-small uk-padding-remove-horizontal uk-text-small uk-height-max-large uk-overflow-auto">
<ng-container *ngTemplateOutlet="availableOnList"></ng-container> <ng-container *ngTemplateOutlet="availableOnList"></ng-container>
</div> </div>
</mobile-dropdown> </ng-container>
</ng-container>
</ng-container> <ng-container *ngIf="isMobile">
<a #toggle class="uk-flex uk-flex-between uk-flex-middle uk-flex-center uk-width-expand uk-button-link">
<span>{{sliceString(availableOn[0].downloadNames.join("; "), 20)}}</span>
<span>
<icon [flex]="true" ratio="1.5" name="arrow_right"></icon>
</span>
</a>
<mobile-dropdown [toggle]="toggle">
<div class="uk-text-emphasis uk-text-bolder uk-text-center uk-padding-small uk-padding-remove-vertical uk-text-uppercase">
Sources
</div>
<div class="uk-text-small download-drop uk-padding uk-padding-remove-horizontal">
<ng-container *ngTemplateOutlet="availableOnList"></ng-container>
</div>
</mobile-dropdown>
</ng-container>
</div>
</div>
</div> </div>
</ng-container> </ng-container>
@ -79,6 +94,14 @@ import {RouterHelper} from "../../utils/routerHelper.class";
</a> </a>
<ng-template #elseBlock> {{instance.license}}</ng-template> <ng-template #elseBlock> {{instance.license}}</ng-template>
</div> </div>
<div *ngIf="properties.environment != 'production' && instance.fulltext" class="uk-text-meta uk-text-truncate" uk-tooltip [title]="instance.fulltext">
Full-Text:
<a *ngIf="isUrl(instance.fulltext); else elseBlock"
[href]="instance.fulltext" target="_blank" class="custom-external uk-link-text">
{{instance.fulltext}}
</a>
<ng-template #elseBlock> {{instance.fulltext}}</ng-template>
</div>
<div *ngIf="instance.collectedNamesAndIds?.size > 0" class="uk-text-meta"> <div *ngIf="instance.collectedNamesAndIds?.size > 0" class="uk-text-meta">
<span>Data sources: </span> <span>Data sources: </span>
<a *ngFor="let collectedName of getKeys(instance.collectedNamesAndIds); let i=index" [routerLink]="dataProviderUrl" <a *ngFor="let collectedName of getKeys(instance.collectedNamesAndIds); let i=index" [routerLink]="dataProviderUrl"
@ -144,4 +167,6 @@ export class AvailableOnComponent {
} }
return obj; return obj;
} }
protected readonly properties = properties;
} }

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import {Component, Input} from "@angular/core"; import {Component, Input, ViewChild} from "@angular/core";
import {EnvProperties} from "../../utils/properties/env-properties"; import {EnvProperties} from "../../utils/properties/env-properties";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {OpenaireEntities} from "../../utils/properties/searchFields"; import {OpenaireEntities} from "../../utils/properties/searchFields";
@ -60,10 +60,10 @@ import {RouterHelper} from "../../utils/routerHelper.class";
<span>{{year}}</span> <span>{{year}}</span>
</ng-container> </ng-container>
<ng-container *ngIf="startYear && !endYear"> <ng-container *ngIf="startYear && !endYear">
<span>{{startYear}}</span> <span>From {{startYear}}</span>
</ng-container> </ng-container>
<ng-container *ngIf="!startYear && endYear"> <ng-container *ngIf="!startYear && endYear">
<span>{{endYear}}</span> <span>Until {{endYear}}</span>
</ng-container> </ng-container>
<ng-container *ngIf="startYear && endYear"> <ng-container *ngIf="startYear && endYear">
<ng-container> <ng-container>
@ -151,12 +151,32 @@ import {RouterHelper} from "../../utils/routerHelper.class";
<span>Thematic</span> <span>Thematic</span>
</ng-container> </ng-container>
<!-- Projects --> <!-- Projects -->
<span uk-tooltip="Funded By" *ngIf="projects && projects.length > 0" [class.truncated]="projects.length > 3"> <span *ngIf="projects && projects.length > 0"
{{projectNames.slice(0,3).join(', ')}} [attr.uk-tooltip]="projects.length > projectsLimit ? 'cls: uk-invisible' : 'pos: top; cls: uk-active'" title="Funded by">
{{showInline ? projectNames.join(', ') : projectNames.slice(0, projectsLimit).join(', ')}}
<span *ngIf="projects.length > projectsLimit">
<a *ngIf="!showInline" (click)="viewAllProjectsClick();" class="uk-background-muted custom-extra-entities">
+{{projects.length - projectsLimit | number}} projects
</a>
<a *ngIf="showInline && lessBtn" (click)="showInline = !showInline; lessBtn = false;"
class="uk-background-muted custom-extra-entities">
View less
</a>
</span>
</span> </span>
<!-- Organizations --> <!-- Organizations -->
<span uk-tooltip="Partners" *ngIf="organizations && organizations.length > 0" [class.truncated]="organizations.length > 3"> <span *ngIf="organizations && organizations.length > 0"
{{organizationNames.slice(0, 3).join(', ')}} [attr.uk-tooltip]="organizations.length > organizationsLimit ? 'cls: uk-invisible' : 'pos: top; cls: uk-active'" title="Partners">
{{showInline ? organizationNames.join(', ') : organizationNames.slice(0, organizationsLimit).join(', ')}}
<span *ngIf="organizations.length > organizationsLimit">
<a *ngIf="!showInline" (click)="viewAllPartnersClick();" class="uk-background-muted custom-extra-entities">
+{{organizations.length - organizationsLimit | number}} partners
</a>
<a *ngIf="showInline && lessBtn" (click)="showInline = !showInline; lessBtn = false;"
class="uk-background-muted custom-extra-entities">
View less
</a>
</span>
</span> </span>
<!-- Subjects --> <!-- Subjects -->
<span uk-tooltip="Subjects" *ngIf="subjects && subjects.length > 0" [class.truncated]="subjects.length > 3"> <span uk-tooltip="Subjects" *ngIf="subjects && subjects.length > 0" [class.truncated]="subjects.length > 3">
@ -169,10 +189,37 @@ import {RouterHelper} from "../../utils/routerHelper.class";
<span>{{relationName}}</span> <span>{{relationName}}</span>
</ng-container> </ng-container>
</div> </div>
<modal-alert *ngIf="!isMobile" #partnersModal>
<div class="uk-text-small uk-text-emphasis uk-grid uk-grid-column-collapse uk-grid-row-small" uk-grid>
<ng-container *ngFor="let item of organizations; let i = index">
<div class="uk-margin-xsmall-right">
{{item.name}}{{i == organizations.length - 1 ? '' : ','}}
</div>
</ng-container>
</div>
</modal-alert>
<modal-alert *ngIf="!isMobile" #projectsModal>
<div class="uk-text-small uk-text-emphasis uk-grid uk-grid-column-collapse uk-grid-row-small" uk-grid>
<ng-container *ngFor="let item of projects; let i = index">
<div class="uk-margin-xsmall-right">
<span
*ngIf="item['funderShortname'] || item['funderName']">{{item['funderShortname'] ? item['funderShortname'] : item['funderName']}}</span>
<span *ngIf="!item['funderShortname'] && !item['funderName']">[no funder available]</span>
<span *ngIf="item['acronym'] || item['title']">| {{ item['acronym'] ? item['acronym'] : item['title']}}</span>
{{i == projects.length - 1 ? '' : ','}}
</div>
</ng-container>
</div>
</modal-alert>
`, `,
styleUrls: ['entity-metadata.component.less'] styleUrls: ['entity-metadata.component.less']
}) })
export class EntityMetadataComponent { export class EntityMetadataComponent {
@Input() isMobile: boolean = false;
@Input() entityType: string; @Input() entityType: string;
@Input() types: string[]; @Input() types: string[];
@Input() year: string; // search result @Input() year: string; // search result
@ -204,6 +251,14 @@ export class EntityMetadataComponent {
@Input() subjects: string[]; @Input() subjects: string[];
@Input() prevPath: string = ""; @Input() prevPath: string = "";
@ViewChild('partnersModal') partnersModal;
@ViewChild('projectsModal') projectsModal;
organizationsLimit: number = 5;
projectsLimit: number = 3;
showInline: boolean = false;
lessBtn: boolean = false;
properties: EnvProperties = properties; properties: EnvProperties = properties;
public openaireEntities = OpenaireEntities; public openaireEntities = OpenaireEntities;
public routerHelper: RouterHelper = new RouterHelper(); public routerHelper: RouterHelper = new RouterHelper();
@ -260,4 +315,48 @@ export class EntityMetadataComponent {
} }
return obj; return obj;
} }
}
public viewAllPartnersClick() {
if(this.organizations.length <= this.organizationsLimit * 2) {
this.showInline = true;
this.lessBtn = true;
} else {
this.openPartnersModal();
}
}
public openPartnersModal() {
if (this.isMobile) {
this.partnersModal.okButton = false;
this.partnersModal.title = "Partners";
this.partnersModal.open();
} else {
this.partnersModal.cancelButton = false;
this.partnersModal.okButton = false;
this.partnersModal.alertTitle = "Partners";
this.partnersModal.open();
}
}
public viewAllProjectsClick() {
if(this.projects.length <= this.projectsLimit * 2) {
this.showInline = true;
this.lessBtn = true;
} else {
this.openProjectsModal();
}
}
public openProjectsModal() {
if (this.isMobile) {
this.projectsModal.okButton = false;
this.projectsModal.title = "Projects";
this.projectsModal.open();
} else {
this.projectsModal.cancelButton = false;
this.projectsModal.okButton = false;
this.projectsModal.alertTitle = "Projects";
this.projectsModal.open();
}
}
}

View File

@ -121,10 +121,12 @@ export class FosComponent {
} }
public buildFosQueryParam(fos) { public buildFosQueryParam(fos) {
return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}; // return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)};
return (properties.environment !== 'production' ? ({'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}) : ({'fos': this.urlEncodeAndQuote(fos.id)}));
} }
public buildFosHrefParam(fos): string { public buildFosHrefParam(fos): string {
return ('foslabel='+this.urlEncodeAndQuote(fos.id+"||"+fos.label)); // return ('foslabel='+this.urlEncodeAndQuote(fos.id+"||"+fos.label));
return (properties.environment !== 'production' ? ('foslabel='+this.urlEncodeAndQuote(fos.id+"||"+fos.label)) : ('fos='+this.urlEncodeAndQuote(fos.id)));
} }
} }

View File

@ -264,7 +264,8 @@ export class ParsingFunctions {
"accessRightIcon": "", "accessRightIcon": "",
"types": [], "types": [],
"years": [], "years": [],
"license": "" "license": "",
"fulltext": ""
}; };
if (instance.hasOwnProperty("hostedby")) { if (instance.hasOwnProperty("hostedby")) {
@ -353,43 +354,60 @@ export class ParsingFunctions {
if (instance.hasOwnProperty("license")) { if (instance.hasOwnProperty("license")) {
available.license = Array.isArray(instance['license']) ? instance['license'][0] : instance['license']; available.license = Array.isArray(instance['license']) ? instance['license'][0] : instance['license'];
} }
if(instance.hasOwnProperty("fulltext")) {
available.fulltext = instance['fulltext'];
}
hostedBy_collectedFrom.push(available); hostedBy_collectedFrom.push(available);
} }
compareHostedByCollectedFrom(a: HostedByCollectedFrom, b: HostedByCollectedFrom) { compareHostedByCollectedFrom(a: HostedByCollectedFrom, b: HostedByCollectedFrom) {
let retValue: number = 0;
let firstAccessRight: string = (a.accessRight ? a.accessRight.toLowerCase() : null); let firstAccessRight: string = (a.accessRight ? a.accessRight.toLowerCase() : null);
let secondAccessRight: string = (b.accessRight ? b.accessRight.toLowerCase() : null); let secondAccessRight: string = (b.accessRight ? b.accessRight.toLowerCase() : null);
if (firstAccessRight === secondAccessRight) { if (firstAccessRight !== secondAccessRight) {
return 0;
} else {
if (firstAccessRight === 'open access') { if (firstAccessRight === 'open access') {
return -1; retValue = -1;
} else if (secondAccessRight === 'open access') { } else if (secondAccessRight === 'open access') {
return 1; retValue = 1;
} else if (firstAccessRight === "open source") { } else if (firstAccessRight === "open source") {
return -1; retValue = -1;
} else if (secondAccessRight === "open source") { } else if (secondAccessRight === "open source") {
return 1; retValue = 1;
} else if (firstAccessRight === "embargo") { } else if (firstAccessRight === "embargo") {
return -1; retValue = -1;
} else if (secondAccessRight === "embargo") { } else if (secondAccessRight === "embargo") {
return 1; retValue = 1;
} else if (firstAccessRight === "restricted") { } else if (firstAccessRight === "restricted") {
return -1; retValue = -1;
} else if (secondAccessRight === "restricted") { } else if (secondAccessRight === "restricted") {
return 1; retValue = 1;
} else if (firstAccessRight === "closed access") { } else if (firstAccessRight === "closed access") {
return -1; retValue = -1;
} else if (secondAccessRight === "closed access") { } else if (secondAccessRight === "closed access") {
return 1; retValue = 1;
} else if (firstAccessRight === "not available") { } else if (firstAccessRight === "not available") {
return -1; retValue = -1;
} else if (secondAccessRight === "not available") { } else if (secondAccessRight === "not available") {
return 1; retValue = 1;
} }
} }
if(retValue == 0) {
let firstFulltext: string = (a.fulltext ? a.fulltext : null);
let secondFulltext: string = (b.fulltext ? b.fulltext : null);
if (firstFulltext && !secondFulltext) {
return -1;
} else if (!firstFulltext && secondFulltext) {
return 1;
}
} else {
return retValue;
}
return 0; return 0;
} }
@ -514,7 +532,8 @@ export class ParsingFunctions {
let identifiers = new Map<string, string[]>(); let identifiers = new Map<string, string[]>();
if (pid.hasOwnProperty("classid") && pid['classid'] != "") { if (pid.hasOwnProperty("classid") && pid['classid'] != "") {
if (pid.classid == "doi" || pid.classid == "pmc" || pid.classid == "handle" || pid.classid == "pmid" || pid.classid == "re3data") { if (pid.classid == "doi" || pid.classid == "pmc" || pid.classid == "handle" || pid.classid == "pmid" || pid.classid == "re3data"
|| pid.classid == "swhid") {
if (!identifiers.has(pid.classid)) { if (!identifiers.has(pid.classid)) {
identifiers.set(pid.classid, new Array<string>()); identifiers.set(pid.classid, new Array<string>());
} }
@ -522,7 +541,8 @@ export class ParsingFunctions {
} }
} else { } else {
for (let i = 0; i < pid.length; i++) { for (let i = 0; i < pid.length; i++) {
if (pid[i].classid == "doi" || pid[i].classid == "pmc" || pid[i].classid == "handle" || pid[i].classid == "pmid" || pid[i].classid == "re3data") { if (pid[i].classid == "doi" || pid[i].classid == "pmc" || pid[i].classid == "handle" || pid[i].classid == "pmid" || pid[i].classid == "re3data"
|| pid[i].classid == "swhid") {
if (!identifiers.has(pid[i].classid)) { if (!identifiers.has(pid[i].classid)) {
identifiers.set(pid[i].classid, new Array<string>()); identifiers.set(pid[i].classid, new Array<string>());
} }

View File

@ -19,7 +19,7 @@ import {AlertModalModule} from "../../utils/modal/alertModal.module";
import { SearchInputModule } from '../../sharedComponents/search-input/search-input.module'; import { SearchInputModule } from '../../sharedComponents/search-input/search-input.module';
import {EntityMetadataComponent} from "./entity-metadata.component"; import {EntityMetadataComponent} from "./entity-metadata.component";
import {IconsService} from "../../utils/icons/icons.service"; import {IconsService} from "../../utils/icons/icons.service";
import {closed_access, open_access, unknown_access} from "../../utils/icons/icons"; import {book, closed_access, cog, database, earth, open_access, unknown_access} from "../../utils/icons/icons";
import {FullScreenModalModule} from "../../utils/modal/full-screen-modal/full-screen-modal.module"; import {FullScreenModalModule} from "../../utils/modal/full-screen-modal/full-screen-modal.module";
import {MobileDropdownModule} from "../../utils/mobile-dropdown/mobile-dropdown.module"; import {MobileDropdownModule} from "../../utils/mobile-dropdown/mobile-dropdown.module";
@ -45,6 +45,6 @@ import {MobileDropdownModule} from "../../utils/mobile-dropdown/mobile-dropdown.
}) })
export class ResultLandingUtilsModule { export class ResultLandingUtilsModule {
constructor(private iconsService: IconsService) { constructor(private iconsService: IconsService) {
this.iconsService.registerIcons([open_access, closed_access, unknown_access]); this.iconsService.registerIcons([open_access, closed_access, unknown_access, book, cog, database, earth]);
} }
} }

View File

@ -26,7 +26,7 @@ import {properties} from "../../../../environments/environment";
<span class="uk-text-meta uk-text-small" [class.uk-text-uppercase]="key != 're3data'">{{key}}: </span> <span class="uk-text-meta uk-text-small" [class.uk-text-uppercase]="key != 're3data'">{{key}}: </span>
<span [class.uk-margin-small-left]="modal"> <span [class.uk-margin-small-left]="modal">
<ng-container *ngFor="let item of identifiers.get(key) let j=index"> <ng-container *ngFor="let item of identifiers.get(key) let j=index">
<a *ngIf="key == 'doi' || key == 'pmc' || key == 'pmid' || key == 'handle' || key == 're3data'" <a *ngIf="key == 'doi' || key == 'pmc' || key == 'pmid' || key == 'handle' || key == 're3data' || key == 'swhid'"
[href]="getUrl(key) + item" target="_blank" class="uk-display-inline-block custom-external"> [href]="getUrl(key) + item" target="_blank" class="uk-display-inline-block custom-external">
{{item}} {{item}}
</a> </a>
@ -124,6 +124,8 @@ export class ShowIdentifiersComponent implements AfterViewInit {
return properties.handleURL; return properties.handleURL;
} else if(key == "re3data") { } else if(key == "re3data") {
return properties.r3DataURL; return properties.r3DataURL;
} else if(key == "swhid") {
return properties.swhURL;
} }
} }

View File

@ -464,6 +464,7 @@ export class ProjectComponent {
this.subscriptions.push(this._projectService.getProjectInfo(id, this.properties).subscribe( this.subscriptions.push(this._projectService.getProjectInfo(id, this.properties).subscribe(
data => { data => {
this.projectInfo = data; this.projectInfo = data;
this.projectInfo.id = this.projectId;
this.actionsAfterGettingProjectInfo(); this.actionsAfterGettingProjectInfo();
}, },

View File

@ -611,7 +611,7 @@
</div> </div>
<div *ngIf="mobileContent == 'actions'" class="uk-container uk-section"> <div *ngIf="mobileContent == 'actions'" class="uk-container uk-section">
<ng-container *ngIf="resultLandingInfo?.hostedBy_collectedFrom"> <ng-container *ngIf="resultLandingInfo?.hostedBy_collectedFrom">
<div class="uk-padding-small uk-padding-remove-horizontal"> <div class="">
<div class="clickable uk-button-link uk-flex uk-flex-middle uk-h6 uk-margin-remove" <div class="clickable uk-button-link uk-flex uk-flex-middle uk-h6 uk-margin-remove"
(click)=" onSelectActiveTab('availableOn')"> (click)=" onSelectActiveTab('availableOn')">
<availableOn [availableOn]="resultLandingInfo.hostedBy_collectedFrom" (viewAllClicked)="viewAll=$event" <availableOn [availableOn]="resultLandingInfo.hostedBy_collectedFrom" (viewAllClicked)="viewAll=$event"

View File

@ -825,6 +825,8 @@ export class ResultLandingComponent {
return this.properties.pmidURL + id.value; return this.properties.pmidURL + id.value;
} else if (id.type === "handle") { } else if (id.type === "handle") {
return this.properties.handleURL + id.value; return this.properties.handleURL + id.value;
} else if (id.type === "swhid") {
return this.properties.swhURL + id.value;
} else { } else {
return null; return null;
} }
@ -839,6 +841,8 @@ export class ResultLandingComponent {
return 'PubMed'; return 'PubMed';
} else if (id.type === "handle") { } else if (id.type === "handle") {
return 'Handle.NET'; return 'Handle.NET';
} else if(id.type == "swhid") {
return 'Software Heritage';
} else { } else {
return null; return null;
} }

View File

@ -17,13 +17,13 @@
<div *ngIf="user.role.length > 1"> <div *ngIf="user.role.length > 1">
<span class="uk-text-muted"> Roles </span> <span> {{getTheRolesFormatted(user.role)}} </span> <span class="uk-text-muted"> Roles </span> <span> {{getTheRolesFormatted(user.role)}} </span>
</div> </div>
<div class="uk-margin-top" *ngIf="user.role.length > 1"> <div class="uk-margin-top" *ngIf="user.role.length > 1 && isPortalAdministrator">
<a *ngIf="isCurator" class="uk-button uk-button-primary" href="https://aai.openaire.eu/roles/index.php" <a class="uk-button uk-button-primary" href="https://aai.openaire.eu/roles/index.php"
target="_blank">Manage your roles</a> {{" "}} target="_blank">Manage your roles</a> {{" "}}
<a *ngIf="isUserManager" class="uk-button uk-button-primary uk-margin-top" <a class="uk-button uk-button-primary uk-margin-top"
href="https://aai.openaire.eu/roles/admin.php" href="https://aai.openaire.eu/roles/admin.php"
target="_blank">Manage role requests</a>{{" "}} target="_blank">Manage role requests</a>{{" "}}
<a *ngIf="isUserManager" class="uk-button uk-button-primary uk-margin-top" <a class="uk-button uk-button-primary uk-margin-top"
href="https://aai.openaire.eu/registry" href="https://aai.openaire.eu/registry"
target="_blank">Manage users</a> target="_blank">Manage users</a>
</div> </div>

View File

@ -100,12 +100,9 @@ export class UserComponent {
return formattedRoles.join(", "); return formattedRoles.join(", ");
} }
get isCurator() { get isPortalAdministrator() {
return Session.isPortalAdministrator(this.user) || Session.isMonitorCurator(this.user); return Session.isPortalAdministrator(this.user);
} }
get isUserManager() {
return Session.isUserManager(this.user);
}
} }

View File

@ -163,7 +163,7 @@ export class MyOrcidLinksComponent {
if(typeof document !== 'undefined') { if(typeof document !== 'undefined') {
this.tokenUrl = properties.orcidTokenURL this.tokenUrl = properties.orcidTokenURL
+ "clientid="+properties.orcidClientId + "client_id=" + properties.orcidClientId
// + "&response_type=code&scope=/activities/update" // + "&response_type=code&scope=/activities/update"
// + "&response_type=code&scope=/authenticate /activities/update /person/update /read-limited" // + "&response_type=code&scope=/authenticate /activities/update /person/update /read-limited"
+ "&response_type=code&scope=/activities/update /read-limited" + "&response_type=code&scope=/activities/update /read-limited"

View File

@ -34,7 +34,7 @@ import {ClearCacheService} from "../services/clear-cache.service";
<loading></loading> <loading></loading>
</div> </div>
</modal-alert> </modal-alert>
<modal-alert #memberModal [overflowBody]="false" *ngIf="service == 'monitor'" (cancelOutput)="cancel()" <modal-alert #memberModal [overflowBody]="false" (cancelOutput)="cancel()"
(alertOutput)="verifyMember()" [okDisabled]="(code.invalid || loading) && !isMember"> (alertOutput)="verifyMember()" [okDisabled]="(code.invalid || loading) && !isMember">
<div *ngIf="!isMember"> <div *ngIf="!isMember">
<div> <div>
@ -119,12 +119,8 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
ngAfterViewInit() { ngAfterViewInit() {
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user; this.user = user;
if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe();
}
this.paramsSubscription = this.route.queryParams.subscribe(params => { this.paramsSubscription = this.route.queryParams.subscribe(params => {
if (params) { if (params) {
this.isMember = !!params['isMember'];
this.cdr.detectChanges(); this.cdr.detectChanges();
if(params['verify'] && !this.isMember) { if(params['verify'] && !this.isMember) {
if (this.user) { if (this.user) {
@ -133,7 +129,7 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
if (this.user.email === this.verification.email.toLowerCase() && this.id === this.verification.entity && this.type === this.verification.type) { if (this.user.email === this.verification.email.toLowerCase() && this.id === this.verification.entity && this.type === this.verification.type) {
if (this.verification.verificationType === 'manager') { if (this.verification.verificationType === 'manager') {
this.openManagerModal(); this.openManagerModal();
} else if (this.verification.verificationType === 'member' && this.service === "monitor") { } else if (this.verification.verificationType === 'member') {
this.openMemberModal(); this.openMemberModal();
} else { } else {
this.openErrorModal(); this.openErrorModal();
@ -217,6 +213,9 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
this.managerModal.cancel(); this.managerModal.cancel();
this.error = null; this.error = null;
this.userManagementService.updateUserInfo(() => { this.userManagementService.updateUserInfo(() => {
if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe();
}
if (this.service === "monitor") { if (this.service === "monitor") {
this.loading = false; this.loading = false;
this.router.navigate(['/admin/' + this.verification.entity]); this.router.navigate(['/admin/' + this.verification.entity]);
@ -254,8 +253,12 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
this.clearCacheService.clearCache('Members updated'); this.clearCacheService.clearCache('Members updated');
this.loading = false; this.loading = false;
this.error = null; this.error = null;
this.isMember = true;
this.userManagementService.updateUserInfo(() => { this.userManagementService.updateUserInfo(() => {
this.router.navigate([], {queryParams: {'verify': null, 'isMember': true}}); if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe();
}
this.cancel();
}); });
}, error => { }, error => {
this.loading = false; this.loading = false;
@ -271,6 +274,7 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
} }
cancel() { cancel() {
this.router.navigate([], {queryParams: {'verify': null, 'isMember': null}}); this.isMember = false;
this.router.navigate([]);
} }
} }

View File

@ -160,7 +160,9 @@ export class SearchResearchResultsComponent {
this.searchUtils.validateSize(params['size']); this.searchUtils.validateSize(params['size']);
this.searchUtils.sortBy = (params['sortBy']) ? params['sortBy'] : ''; this.searchUtils.sortBy = (params['sortBy']) ? params['sortBy'] : '';
if (this.searchUtils.sortBy && this.searchUtils.sortBy != "resultdateofacceptance,descending" && this.searchUtils.sortBy != "resultdateofacceptance,ascending") { if (this.searchUtils.sortBy && this.searchUtils.sortBy != "resultdateofacceptance,descending" && this.searchUtils.sortBy != "resultdateofacceptance,ascending"
&& this.searchUtils.sortBy != "citation_count,descending" && this.searchUtils.sortBy != "popularity,descending"
&& this.searchUtils.sortBy != "influence,descending" && this.searchUtils.sortBy != "impulse,descending") {
this.searchUtils.sortBy = ""; this.searchUtils.sortBy = "";
} }
this.selectedFields = []; this.selectedFields = [];

View File

@ -8,11 +8,11 @@
<span>Member</span> <span>Member</span>
</div> </div>
<div [ngClass]="isMobile?'uk-flex uk-flex-middle uk-margin-left uk-margin-small-top':'uk-position-top-right uk-margin-top uk-margin-right uk-flex uk-flex-column uk-flex-middle'"> <div [ngClass]="isMobile?'uk-flex uk-flex-middle uk-margin-left uk-margin-small-top':'uk-position-top-right uk-margin-top uk-margin-right uk-flex uk-flex-column uk-flex-middle'">
<div *ngIf="type === 'community' && result.status === 'manager'"> <div *ngIf="type === 'community' && result.isRestricted()">
<icon [name]="visibilityIcon.get('RESTRICTED')" [ratio]="isMobile?0.8:1.2" [flex]="true"></icon> <icon [name]="visibilityIcon.get('RESTRICTED')" [ratio]="isMobile?0.8:1.2" [flex]="true"></icon>
<span class="uk-text-small uk-text-capitalize" [class.uk-text-xsmall]="isMobile" [class.uk-margin-xsmall-left]="isMobile">restricted</span> <span class="uk-text-small uk-text-capitalize" [class.uk-text-xsmall]="isMobile" [class.uk-margin-xsmall-left]="isMobile">restricted</span>
</div> </div>
<ng-container *ngIf="type === 'community' && result.status === 'hidden'"> <ng-container *ngIf="type === 'community' && result.isPrivate()">
<icon [name]="visibilityIcon.get('PRIVATE')" [ratio]="isMobile?0.8:1.2" [flex]="true"></icon> <icon [name]="visibilityIcon.get('PRIVATE')" [ratio]="isMobile?0.8:1.2" [flex]="true"></icon>
<span class="uk-text-small uk-text-capitalize" [class.uk-text-xsmall]="isMobile" [class.uk-margin-xsmall-left]="isMobile">private</span> <span class="uk-text-small uk-text-capitalize" [class.uk-text-xsmall]="isMobile" [class.uk-margin-xsmall-left]="isMobile">private</span>
</ng-container> </ng-container>

View File

@ -1,5 +1,6 @@
import {Component, Input, Output, EventEmitter} from '@angular/core'; import {Component, Input, Output, EventEmitter} from '@angular/core';
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
import {properties} from "../../../../environments/environment";
@Component({ @Component({
selector: 'search-sorting', selector: 'search-sorting',
@ -19,11 +20,21 @@ export class SearchSortingComponent {
@Input() entityType: string = ''; @Input() entityType: string = '';
@Output() sortByChange = new EventEmitter(); @Output() sortByChange = new EventEmitter();
public options: Option[]; public options: Option[];
private generalOptions = [ private generalOptions = properties.environment != "production" ?
{value: '', label: 'Relevance'}, [
{value: 'resultdateofacceptance,descending', label: 'Date (most recent)'}, {value: '', label: 'Relevance'},
{value: 'resultdateofacceptance,ascending', label: 'Date (least recent)'}, {value: 'resultdateofacceptance,descending', label: 'Date (most recent)'},
]; {value: 'resultdateofacceptance,ascending', label: 'Date (least recent)'},
{value: 'citation_count,descending', label: 'Citation Count'},
{value: 'popularity,descending', label: 'Popularity'},
{value: 'influence,descending', label: 'Influence'},
{value: 'impulse,descending', label: 'Impulse'}
] :
[
{value: '', label: 'Relevance'},
{value: 'resultdateofacceptance,descending', label: 'Date (most recent)'},
{value: 'resultdateofacceptance,ascending', label: 'Date (least recent)'}
];
private communityOptions = [ private communityOptions = [
{value: '', label: 'Title'}, {value: '', label: 'Title'},
{value: 'creationdate,descending', label: 'Creation Date (most recent)'}, {value: 'creationdate,descending', label: 'Creation Date (most recent)'},

View File

@ -248,10 +248,10 @@ export class SearchProjectsService {
} }
} }
} }
if(resData.hasOwnProperty("startdate")) { if(resData.hasOwnProperty("startdate") && resData['startdate']) {
result.startYear = resData.startdate.split('-')[0]; result.startYear = resData.startdate.split('-')[0];
} }
if(resData.hasOwnProperty("enddate")) { if(resData.hasOwnProperty("enddate") && resData['enddate']) {
result.endYear = resData.enddate.split('-')[0]; result.endYear = resData.enddate.split('-')[0];
} }
// Measure // Measure

View File

@ -109,7 +109,7 @@ import {properties} from "../../../../environments/environment";
+{{authors.length - authorsLimit | number}} more +{{authors.length - authorsLimit | number}} more
</span> </span>
<span *ngIf="showAll && authors && authors.length > authorsLimit && !viewAll"> <span *ngIf="showAll && authors && authors.length > authorsLimit && !viewAll">
<a (click)="viewAllClick();"> <a (click)="viewAllClick();" class="uk-background-muted custom-extra-entities">
+{{authors.length - authorsLimit | number}} Authors +{{authors.length - authorsLimit | number}} Authors
</a> </a>
</span> </span>

View File

@ -152,6 +152,7 @@ export class EGIDataTransferComponent {
this.init(); this.init();
if(!this.isMobile) { if(!this.isMobile) {
this.egiTransferModal.stayOpen = true;
// this.egiTransferModal.back = true; // this.egiTransferModal.back = true;
this.egiTransferModal.cancelButton = false; this.egiTransferModal.cancelButton = false;
this.egiTransferModal.okButton = true; this.egiTransferModal.okButton = true;

View File

@ -302,21 +302,23 @@ export class Composer {
return message; return message;
} }
public static composeEmailForCommunityDashboard(name: string, recipient: string) { public static composeEmailForCommunityDashboard(name: string, role: "manager" | "member", recipient: string) {
let email: Email = new Email(); let email: Email = new Email();
email.subject = 'OpenAIRE Connect | ' + name; email.subject = 'OpenAIRE Connect | ' + name;
email.body = this.composeMessageForCommunityDashboard(name); email.body = this.composeMessageForCommunityDashboard(name, role);
email.recipient = recipient; email.recipient = recipient;
return email; return email;
} }
public static composeMessageForCommunityDashboard(name: string, user: string = null, invitation: any = null) { public static composeMessageForCommunityDashboard(name: string, role: "manager" | "member", user: string = null, invitation: any = null) {
let message = '<p>Dear ((__user__)),</p>' + let message = '<p>Dear ((__user__)),</p>' +
'<p>You have been invited to be a manager of the OpenAIRE Research Community Dashboard for the ' + name + '.</p>' + '<p>You have been invited to be a ' + role + ' of the OpenAIRE Research Community Dashboard for the ' + name + '.</p>' +
'<p>Click <a href="((__link__))" target="_blank">this URL</a> and use the verification code below to accept the invitation.</p>' + '<p>Click <a href="((__link__))" target="_blank">this URL</a> and use the verification code below to accept the invitation.</p>' +
'<p>The verification code is <b>((__code__))</b>.</p>' + '<p>The verification code is <b>((__code__))</b>.</p>' +
(role === 'manager'?
'<p>As a manager of the OpenAIRE Research Community Dashboard, you will have access to the administration part of the dashboard, ' + '<p>As a manager of the OpenAIRE Research Community Dashboard, you will have access to the administration part of the dashboard, ' +
'where you will be able to customize and manage the content of the ' + name + '.</p>' + 'where you will be able to customize and manage the content of the ' + name + '.</p>':
'<p>As a member of the OpenAIRE Research Community Dashboard, you will have access to the community dashboard and link research results with projects, communities and other research projects.</p>') +
'<p>Please contact us at <a href="mailto:' + properties.helpdeskEmail+'">' + properties.helpdeskEmail + '<p>Please contact us at <a href="mailto:' + properties.helpdeskEmail+'">' + properties.helpdeskEmail +
'</a> if you have any questions or concerns.</p>' + '</a> if you have any questions or concerns.</p>' +
'<p>Kind Regards<br>The OpenAIRE Team</p>' + '<p>Kind Regards<br>The OpenAIRE Team</p>' +

View File

@ -8,7 +8,7 @@ import {
} from "../result-preview/result-preview"; } from "../result-preview/result-preview";
export interface Id { export interface Id {
type: "pmid" | "doi" | "pmc" | "handle" | "openaire"; type: "pmid" | "doi" | "pmc" | "handle" | "openaire" | "swhid";
value: string; value: string;
trust: number trust: number
} }

View File

@ -16,7 +16,7 @@ import {EnvProperties} from "../properties/env-properties";
routerLinkActive="router-link-active" routerLink="/participate/direct-claim" routerLinkActive="router-link-active" routerLink="/participate/direct-claim"
[title]="'Link '+openaireEntities.RESULTS+' with a '+openaireEntities.PROJECT+', a '+openaireEntities.COMMUNITY+' or other '+openaireEntities.RESULTS+' and make the new information available in OpenAIRE information space.'" [title]="'Link '+openaireEntities.RESULTS+' with a '+openaireEntities.PROJECT+', a '+openaireEntities.COMMUNITY+' or other '+openaireEntities.RESULTS+' and make the new information available in OpenAIRE information space.'"
[attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small uk-width-medium'" [attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small uk-width-medium'"
class="uk-flex uk-flex-middle uk-button-link uk-text-bolder" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-flex-center'"> class="uk-flex uk-flex-middle uk-button-link" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-text-bolder uk-flex-center'">
<icon [flex]="true" [ratio]="0.7" name="link_to" visuallyHidden="link"></icon> <icon [flex]="true" [ratio]="0.7" name="link_to" visuallyHidden="link"></icon>
<span class="uk-margin-xsmall-left">Link to</span> <span class="uk-margin-xsmall-left">Link to</span>
</a> </a>
@ -25,15 +25,15 @@ import {EnvProperties} from "../properties/env-properties";
<a (click)="openAddThisModal()" <a (click)="openAddThisModal()"
[title]="'Share this '+getTypeName() + ' in your social networks'" [title]="'Share this '+getTypeName() + ' in your social networks'"
[attr.uk-tooltip]="'pos: right; cls: uk-active uk-text-small uk-padding-small'" [attr.uk-tooltip]="'pos: right; cls: uk-active uk-text-small uk-padding-small'"
class="uk-flex uk-flex-middle uk-button-link uk-text-bolder" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-flex-center'"> class="uk-flex uk-flex-middle uk-button-link" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-text-bolder uk-flex-center'">
<icon [flex]="true" [ratio]="0.8" name="share" visuallyHidden="share"></icon> <icon class="uk-text-bolder" [flex]="true" [ratio]="0.8" name="share" visuallyHidden="share"></icon>
<span class="uk-margin-xsmall-left">Share</span> <span class="uk-margin-xsmall-left">Share</span>
</a> </a>
</div> </div>
<div *ngIf="cite"> <div *ngIf="cite">
<a (click)="openCiteModal()" <a (click)="openCiteModal()"
class="uk-flex uk-flex-middle uk-button-link uk-text-bolder" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-flex-center'"> class="uk-flex uk-flex-middle uk-button-link" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-text-bolder uk-flex-center'">
<icon [flex]="true" [ratio]="0.7" name="cite" visuallyHidden="cite"></icon> <icon class="uk-text-bolder" [flex]="true" [ratio]="0.7" name="cite" visuallyHidden="cite"></icon>
<span class="uk-margin-xsmall-left">Cite</span> <span class="uk-margin-xsmall-left">Cite</span>
</a> </a>
</div> </div>
@ -41,7 +41,7 @@ import {EnvProperties} from "../properties/env-properties";
<a routerLinkActive="router-link-active" routerLink="/participate/deposit/learn-how" <a routerLinkActive="router-link-active" routerLink="/participate/deposit/learn-how"
[title]="'Find a repository to deposit or publish your research in Open Access'" [title]="'Find a repository to deposit or publish your research in Open Access'"
[attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small uk-width-medium'" [attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small uk-width-medium'"
class="uk-flex uk-flex-middle uk-button-link uk-text-bolder" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-flex-center'"> class="uk-flex uk-flex-middle uk-button-link" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-text-bolder uk-flex-center'">
<icon flex="true" ratio="0.7" name="upload" visuallyHidden="upload"></icon> <icon flex="true" ratio="0.7" name="upload" visuallyHidden="upload"></icon>
<span class="uk-margin-xsmall-left">Deposit</span> <span class="uk-margin-xsmall-left">Deposit</span>
</a> </a>
@ -50,7 +50,7 @@ import {EnvProperties} from "../properties/env-properties";
<a (click)="openEmbedResultsModal()" <a (click)="openEmbedResultsModal()"
[title]="'Embed the related '+openaireEntities.RESULTS+' of this '+getTypeName()+' in your website'" [title]="'Embed the related '+openaireEntities.RESULTS+' of this '+getTypeName()+' in your website'"
[attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small uk-width-medium'" [attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small uk-width-medium'"
class="uk-flex uk-flex-middle uk-button-link uk-text-bolder" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-flex-center'"> class="uk-flex uk-flex-middle uk-button-link" [ngClass]="isMobile ? 'uk-margin-left uk-margin-xsmall-bottom' : 'uk-text-bolder uk-flex-center'">
<icon flex="true" ratio="0.8" name="code" visuallyHidden="code"></icon> <icon flex="true" ratio="0.8" name="code" visuallyHidden="code"></icon>
<span class="uk-margin-xsmall-left">Embed</span> <span class="uk-margin-xsmall-left">Embed</span>
</a> </a>

View File

@ -44,6 +44,7 @@ export interface EnvProperties {
cordisURL?: string; cordisURL?: string;
openDoarURL?: string; openDoarURL?: string;
r3DataURL?: string; r3DataURL?: string;
swhURL?: string;
fairSharingURL?: string, fairSharingURL?: string,
eoscMarketplaceURL?: string, eoscMarketplaceURL?: string,
sherpaURL?: string; sherpaURL?: string;

View File

@ -0,0 +1,25 @@
import {EnvProperties} from "../env-properties";
export let common: EnvProperties = {
swhURL: "https://archive.softwareheritage.org/",
// searchCrossrefAPIURL: "https://api.crossref.org/works",
// searchDataciteAPIURL: "https://api.datacite.org/works",
// searchOrcidURL: "https://pub.orcid.org/v2.1/",
// orcidURL: "https://orcid.org/",
// doiURL: "https://doi.org/",
// pmcURL: "http://europepmc.org/articles/",
// pmidURL: "https://www.ncbi.nlm.nih.gov/pubmed/",
// handleURL: "http://hdl.handle.net/",
// cordisURL: "http://cordis.europa.eu/projects/",
// openDoarURL: "http://v2.sherpa.ac.uk/id/repository/",
// r3DataURL: "http://service.re3data.org/repository/",
// fairSharingURL: "https://fairsharing.org/",
// sherpaURL: "http://sherpa.ac.uk/romeo/issn/",
// sherpaURLSuffix: "/",
// zenodo: "https://zenodo.org/",
// openAccess: "https://www.openaire.eu/support/faq#article-id-234",
// openAccessRepo: "https://www.openaire.eu/support/faq#article-id-310",
// fp7Guidlines: "https://www.openaire.eu/open-access-in-fp7-seventh-research-framework-programme",
// h2020Guidlines: "https://www.openaire.eu/oa-publications/h2020/open-access-in-horizon-2020",
// ercGuidlines: "http://erc.europa.eu/sites/default/files/document/file/ERC_Open_Access_Guidelines-revised_2014.pdf",
}

View File

@ -0,0 +1,6 @@
import {EnvProperties} from "../env-properties";
export let commonBeta: EnvProperties = {
// searchAPIURLLAst: "http://beta.services.openaire.eu/search/v2/api/",
// searchResourcesAPIURL: "https://beta.services.openaire.eu/search/v2/api/resources",
}

View File

@ -0,0 +1,6 @@
import {EnvProperties} from "../env-properties";
export let commonProd: EnvProperties = {
// searchAPIURLLAst: "https://services.openaire.eu/search/v2/api/",
// searchResourcesAPIURL: "https://services.openaire.eu/search/v2/api/resources",
}

View File

@ -0,0 +1,6 @@
import {EnvProperties} from "../env-properties";
export let commonTest: EnvProperties = {
// searchAPIURLLAst: "https://services.openaire.eu/shadowSearch/v2/api/",
// searchResourcesAPIURL: "https://services.openaire.eu/shadowSearch/v2/api/resources",
}

View File

@ -0,0 +1,6 @@
import {EnvProperties} from "../env-properties";
export let commonDev: EnvProperties = {
// searchAPIURLLAst: "http://beta.services.openaire.eu/search/v2/api/",
// searchResourcesAPIURL: "https://beta.services.openaire.eu/search/v2/api/resources",
}

View File

@ -14,7 +14,7 @@ export class SearchFields {
// Remove Collected From Filter "collectedfrom","collectedfrom" // Remove Collected From Filter "collectedfrom","collectedfrom"
public RESULT_REFINE_FIELDS = [ public RESULT_REFINE_FIELDS = [
"resultbestaccessright", "instancetypename", "foslabel", "relfunder", "resultbestaccessright", "instancetypename", properties.environment!='production'?"foslabel":'fos', "relfunder",
"relfundinglevel0_id", "relfundinglevel1_id", "relfundinglevel2_id", "relfundinglevel0_id", "relfundinglevel1_id", "relfundinglevel2_id",
"relproject", "sdg", "country", "resultlanguagename", "resulthostingdatasource", "community"]; "relproject", "sdg", "country", "resultlanguagename", "resulthostingdatasource", "community"];

View File

@ -214,7 +214,8 @@
<a class="uk-flex uk-flex-middle uk-link-reset"> <a class="uk-flex uk-flex-middle uk-link-reset">
<icon customClass="bip-icon-hover" [flex]="true" [ratio]="0.7" <icon customClass="bip-icon-hover" [flex]="true" [ratio]="0.7"
[name]="result.measure.bip[0].icon"></icon> [name]="result.measure.bip[0].icon"></icon>
<span class="uk-margin-xsmall-left">{{result.measure.bip[0].value}}</span> <span *ngIf="isNumber(result.measure.bip[0].value)" class="uk-margin-xsmall-left">{{formatNumber(result.measure.bip[0].value)}}</span>
<span *ngIf="!isNumber(result.measure.bip[0].value)" class="uk-margin-xsmall-left">{{result.measure.bip[0].value}}</span>
</a> </a>
<div uk-drop="pos: top-right" class="uk-card uk-card-default uk-border uk-box-no-shadow uk-padding-small"> <div uk-drop="pos: top-right" class="uk-card uk-card-default uk-border uk-box-no-shadow uk-padding-small">
<table> <table>
@ -223,7 +224,8 @@
<icon [flex]="true" [ratio]="0.7" [name]="metric.icon"></icon> <icon [flex]="true" [ratio]="0.7" [name]="metric.icon"></icon>
</td> </td>
<td class="uk-text-capitalize">{{metric.name}}</td> <td class="uk-text-capitalize">{{metric.name}}</td>
<td class="uk-text-bolder">{{metric.value}}</td> <td *ngIf="isNumber(metric.value)" class="uk-text-bolder">{{metric.value | number}}</td>
<td *ngIf="!isNumber(metric.value)" class="uk-text-bolder">{{metric.value}}</td>
</tr> </tr>
</table> </table>
<div class="uk-margin-top uk-flex uk-flex-middle uk-flex-center"> <div class="uk-margin-top uk-flex uk-flex-middle uk-flex-center">
@ -252,7 +254,7 @@
<div class="uk-margin-top uk-flex uk-flex-middle uk-flex-center"> <div class="uk-margin-top uk-flex uk-flex-middle uk-flex-center">
<span class="uk-text-uppercase">Powered by </span> <span class="uk-text-uppercase">Powered by </span>
<img class="uk-margin-xsmall-left" width="15" src="assets/common-assets/logo-small-usage-counts.png" <img class="uk-margin-xsmall-left" width="15" src="assets/common-assets/logo-small-usage-counts.png"
loading="lazy" alt="BIP!"> loading="lazy" alt="Usage counts">
</div> </div>
</div> </div>
</ng-container> </ng-container>

View File

@ -223,6 +223,10 @@ export class ResultPreviewComponent implements OnInit, OnChanges {
return formatted.number + formatted.size; return formatted.number + formatted.size;
} }
public isNumber(value): boolean {
return typeof value === 'number';
}
public getAccessLabel(accessRight) : string { public getAccessLabel(accessRight) : string {
if(accessRight) { if(accessRight) {
return (accessRight + (accessRight.toLowerCase().endsWith(" access") ? "" : " access")); return (accessRight + (accessRight.toLowerCase().endsWith(" access") ? "" : " access"));

View File

@ -11,6 +11,7 @@ export interface HostedByCollectedFrom {
years: string[]; years: string[];
accessRightIcon: string; accessRightIcon: string;
license?: string; license?: string;
fulltext?: string;
} }
export interface Journal { export interface Journal {

View File

@ -149,7 +149,7 @@ export class DOI {
} }
export class Identifier { export class Identifier {
class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" = null; class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" | "swhid" = null;
id: string; id: string;
public static getDOIsFromString(str: string): string[] { public static getDOIsFromString(str: string): string[] {
@ -202,13 +202,15 @@ export class Identifier {
return {"class": "handle", "id": pid}; return {"class": "handle", "id": pid};
} else if (Identifier.isValidRe3Data(pid)) { } else if (Identifier.isValidRe3Data(pid)) {
return {"class": "re3data", "id": pid}; return {"class": "re3data", "id": pid};
} else if (Identifier.isValidSwhId(pid)) {
return {"class": "swhid", "id": pid};
} }
//set it as a doi, to catch the case that doi has not valid format //set it as a doi, to catch the case that doi has not valid format
return (strict?null:{"class": "doi", "id": pid}); return (strict?null:{"class": "doi", "id": pid});
} }
public static getPIDFromIdentifiers(identifiers: Map<string, string[]>): Identifier { public static getPIDFromIdentifiers(identifiers: Map<string, string[]>): Identifier {
let classes:string [] = ["doi", "handle", "pmc", "pmid", "re3data"]; let classes:string [] = ["doi", "handle", "pmc", "pmid", "re3data", "swhid"];
if(identifiers) { if(identifiers) {
for (let cl of classes) { for (let cl of classes) {
if (identifiers.get(cl)) { if (identifiers.get(cl)) {
@ -257,6 +259,12 @@ export class Identifier {
let exp = /(r3d[1-9]\d{0,8})/g; let exp = /(r3d[1-9]\d{0,8})/g;
return str.match(exp) != null; return str.match(exp) != null;
} }
public static isValidSwhId(str: string): boolean {
// let exp = /swh:1:(snp|rel|rev|dir|cnt):[0-9a-f]{40}/g;
let exp = /swh:1:snp:[0-9a-f]{40}/g;
return str.match(exp) != null;
}
} }
export class StringUtils { export class StringUtils {