Production release May 2024 [EXPLORE] #40

Merged
konstantina.galouni merged 81 commits from develop into master 2024-05-23 18:26:50 +02:00
83 changed files with 2208 additions and 1321 deletions

View File

@ -1,6 +1,7 @@
//Classes used in linking / inlinelinking when selecting an entity //Classes used in linking / inlinelinking when selecting an entity
import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {OpenaireEntities} from "../../utils/properties/searchFields"; import {OpenaireEntities} from "../../utils/properties/searchFields";
import {ClaimsProperties} from "./claims.properties";
export class ClaimResult { export class ClaimResult {
public source: string; public source: string;
@ -28,6 +29,7 @@ export class ClaimResult {
export class ClaimProject { export class ClaimProject {
public funderId: string; public funderId: string;
public funderShortname: string;
public funderName: string; public funderName: string;
public acronym: string; public acronym: string;
public startDate: string; public startDate: string;
@ -37,6 +39,12 @@ export class ClaimProject {
public fundingLevel0: string; public fundingLevel0: string;
public url: string; public url: string;
} }
export class ClaimOrganization {
public name: string;
// public shortName: string;
public url: string;
// public country: string;
}
export class ClaimContext { export class ClaimContext {
public community: string; public community: string;
@ -71,6 +79,7 @@ export class ClaimEntity {
result: ClaimResult; result: ClaimResult;
project: ClaimProject; project: ClaimProject;
context: ClaimContext; context: ClaimContext;
organization: ClaimOrganization;
constructor() { constructor() {
this.warningMessages = []; this.warningMessages = [];
@ -92,6 +101,7 @@ export class ClaimRecord2Insert {
targetAccessRights: string; targetAccessRights: string;
targetEmbargoEndDate: string; targetEmbargoEndDate: string;
claimedInDashboard: string; claimedInDashboard: string;
idSuffix:string;
constructor() { constructor() {
@ -115,7 +125,12 @@ export class ClaimDBContext {
title: string; title: string;
openaireId: string; openaireId: string;
} }
export class ClaimDBOrganization {
openaireId: string;
name: string;
shortName: string;
country: string;
}
export class ClaimDBProject { export class ClaimDBProject {
openaireId: string; openaireId: string;
name: string; name: string;
@ -175,17 +190,18 @@ export class ShowOptions {
} }
initSelectOptions(){ initSelectOptions(claimProperties:ClaimsProperties){
let options =[]; let options =[];
if(this.linkToEntities.indexOf('result')!=-1){ if(this.linkToEntities.indexOf('result')!=-1){
options.push({value: 'result',label: OpenaireEntities.RESULTS}) options.push({value: 'result',label: OpenaireEntities.RESULTS})
} }
if(this.linkToEntities.indexOf('project')!=-1){ if(this.linkToEntities.indexOf('project')!=-1){
options.push({value: 'project',label: OpenaireEntities.PROJECTS}) options.push({value: 'project',label: claimProperties.SELECT_ENTITIES.projects})
} }
if(this.linkToEntities.indexOf('context')!=-1){ if(this.linkToEntities.indexOf('context')!=-1){
options.push({value: 'context',label: OpenaireEntities.COMMUNITIES}) options.push({value: 'context',label: OpenaireEntities.COMMUNITIES})
} }
this.selectOptions = options; this.selectOptions = options;
console.log(options, claimProperties.SELECT_ENTITIES.projects)
} }
} }

View File

@ -1,69 +1,25 @@
<div class="uk-width-xlarge@l uk-width-large" [ngClass]="centerAlign ? 'uk-align-center':''"> <div class="uk-width-xlarge@l uk-width-large" [ngClass]="centerAlign ? 'uk-align-center':''">
<advanced-search-input (searchEmitter)="search(page,size)"> <advanced-search-input (searchEmitter)="search(page,size)">
<div input type="select" [(value)]="showOptions.show" placeholder="Type" hint="Select..." <div input type="select" [(value)]="showOptions.show" placeholder="Type" hint="Select..."
[options]="showOptions.selectOptions" class="uk-width-2-5"></div> [options]="showOptions.selectOptions" class="uk-width-auto "></div>
<div class="uk-width-expand" input type="text" [(value)]="keyword" [searchable]="true" placeholder="Entities to link" <div *ngIf="funderOptions && funderOptions.length > 0" input type="select" [(value)]="selectedFunder" placeholder="Funder" hint="Select Funder..."
[hint]="'Search for ' + openaireEntities.PROJECTS + '...'" tooltip="true"></div> [options]="funderOptions" class="uk-width-expand" (valueChange)="funderChanged($event)"></div>
<div *ngIf="selectedFunder && selectedFunder.number > 1" class="uk-width-expand" input type="text" [(value)]="keyword" [searchable]="true" placeholder="Projects to link"
[hint]="'Search for ' + openaireEntities.PROJECTS + '...'" tooltip="true" [disabled]="!selectedFunder"></div>
</advanced-search-input> </advanced-search-input>
</div> </div>
<div *ngIf="!showResults"> <div *ngIf=" openaireResultsStatus != errorCodes.LOADING && !isNoProjectFunder && this.selectedFunder && openaireResults.length == 0">
<div class="uk-text-center uk-text-large uk-text-meta uk-margin-large-top">No {{openaireEntities.PROJECT.toLowerCase()}} results yet... <br>Start <div class="uk-text-center uk-text-large uk-text-meta uk-margin-large-top">No {{openaireEntities.PROJECT.toLowerCase()}} results yet... <br>Start
searching for {{openaireEntities.PROJECTS.toLowerCase()}} to add them in the Basket searching for {{openaireEntities.PROJECTS.toLowerCase()}} to add them in the Basket
</div> </div>
</div> </div>
<div *ngIf="showResults" class="uk-margin-top"> <div *ngIf=" openaireResultsStatus != errorCodes.LOADING && this.funderOptions.length > 1 && !this.selectedFunder">
<div class="uk-text-center uk-text-large uk-text-meta uk-margin-large-top">Select funder to proceed
</div>
</div>
<div class="uk-margin-top">
<div class="uk-grid" uk-grid> <div class="uk-grid" uk-grid>
<div class="search-filters uk-width-1-1"> <div *ngIf="!isNoProjectFunder && openaireResultsStatus != errorCodes.LOADING && openaireResultsNum > 1 " class="search-filters uk-width-1-1">
<!--<div *ngIf="countFilters()>0 && openaireResultsNum > 0" class="uk-grid uk-flex uk-flex-bottom">
<div class="uk-grid">
<h6 class="uk-text-bold">Filters</h6>
<a *ngIf="countFilters()>1" (click)="clearFilters()"
[class]="((openaireResultsStatus ==
errorCodes.LOADING)?'uk-disabled uk-link-muted':'')+' portal-link '">
Clear All
</a>
</div>
<div *ngIf="countFilters()>0" class="uk-grid uk-grid-small uk-text-small uk-margin-small-top " uk-grid>
<ng-container *ngFor="let filter of rangeFilters " >
<ng-container *ngIf = "filter.selectedFromAndToValues">
<span [title]="'Remove '+ filter.selectedFromAndToValues" (click) = "removeRangeFilter(filter) " >
<span class="selectedFilterLabel ">
<a [class]="((openaireResultsStatus ==
errorCodes.LOADING)?' uk-disabled':' ')+' uk-link-text '">
<span class=" clickable" aria-hidden="true">
<span class="uk-icon">
<svg width="16" height="16" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" icon="close" ratio="0.8"><path fill="none" stroke="#000" stroke-width="1.6" d="M16,16 L4,4"></path><path fill="none" stroke="#000" stroke-width="1.6" d="M16,4 L4,16"></path></svg>
</span>
</span>
<span class="uk-margin-small-left">{{filter.selectedFromAndToValues}}</span>
</a>
</span>
</span>
</ng-container>
</ng-container>
<ng-container *ngFor="let filter of filters " >
<ng-container *ngIf = "filter.countSelectedValues > 0">
<span *ngFor="let value of getSelectedValues(filter); let i = index; let end = last; "
[title]="'Remove '+value.name" (click) = "removeFilter(value, filter) " >
&lt;!&ndash; if no grid on the div above, remove it and move class 'selectedFilterLabel' on top span &ndash;&gt;
<span class="selectedFilterLabel ">
<a [class]="((openaireResultsStatus ==
errorCodes.LOADING)?' uk-disabled':' ')+' uk-link-text '">
<span class=" clickable" aria-hidden="true">
<span class="uk-icon">
<svg width="16" height="16" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" icon="close" ratio="0.8"><path fill="none" stroke="#000" stroke-width="1.6" d="M16,16 L4,4"></path><path fill="none" stroke="#000" stroke-width="1.6" d="M16,4 L4,16"></path></svg>
</span>
</span>
<span class="uk-margin-small-left" [innerHtml]="(value.name.length > 34)?value.name.substring(0,34)+'...':value.name"></span>
</a>
</span>
</span>
</ng-container>
</ng-container>
</div>
</div>-->
<!-- <ng-container *ngIf="openaireResultsNum > 0">-->
<div class="uk-grid uk-grid-small" uk-grid> <div class="uk-grid uk-grid-small" uk-grid>
<ng-container *ngFor="let filter of rangeFilters"> <ng-container *ngFor="let filter of rangeFilters">
<div> <div>
@ -104,9 +60,12 @@
role="alert">Service not available role="alert">Service not available
</div> </div>
<div *ngIf="openaireResultsStatus == errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1" <div *ngIf="openaireResultsStatus == errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1"
role="alert"><span class="loading-gif uk-align-center"></span></div> role="alert">
<loading></loading>
</div>
<claim-results [localStoragePrefix]="localStoragePrefix" [results]=openaireResults <claim-results [localStoragePrefix]="localStoragePrefix" [results]=openaireResults
[selectedResults]=selectedProjects [basketLimit]="basketLimit"></claim-results> [selectedResults]=selectedProjects [basketLimit]="basketLimit"></claim-results>
<div *ngIf="isNoProjectFunder && openaireResultsStatus != errorCodes.LOADING " class="uk-alert uk-alert-default"><span class=" uk-text-bold">{{selectedFunder.name}}</span> has no projects. Proceed to next step. </div>
<div *ngIf="openaireResultsNum != null && openaireResultsNum > 0 && openaireResultsStatus != errorCodes.LOADING " class="uk-flex uk-flex-center "> <div *ngIf="openaireResultsNum != null && openaireResultsNum > 0 && openaireResultsStatus != errorCodes.LOADING " class="uk-flex uk-flex-center ">
<paging-no-load [currentPage]="openaireResultsPage" <paging-no-load [currentPage]="openaireResultsPage"
[totalResults]="openaireResultsNum" [term]="keyword" [totalResults]="openaireResultsNum" [term]="keyword"

View File

@ -1,4 +1,4 @@
import {Component, ElementRef, EventEmitter, Input, Output} from '@angular/core'; import {Component, ElementRef, EventEmitter, Input, Output, ViewChild} from '@angular/core';
import {SearchProjectsService} from '../../services/searchProjects.service'; import {SearchProjectsService} from '../../services/searchProjects.service';
import {ProjectService} from '../../landingPages/project/project.service'; import {ProjectService} from '../../landingPages/project/project.service';
import {ClaimEntity, ClaimProject} from './claimHelper.class'; import {ClaimEntity, ClaimProject} from './claimHelper.class';
@ -10,6 +10,8 @@ import {RangeFilter} from "../../utils/rangeFilter/rangeFilterHelperClasses.clas
import {OpenaireEntities, SearchFields} from "../../utils/properties/searchFields"; import {OpenaireEntities, SearchFields} from "../../utils/properties/searchFields";
import {NewSearchPageComponent} from "../../searchPages/searchUtils/newSearchPage.component"; import {NewSearchPageComponent} from "../../searchPages/searchUtils/newSearchPage.component";
import {Subscriber} from "rxjs"; import {Subscriber} from "rxjs";
import { properties } from 'src/environments/environment';
import {error} from "protractor";
declare var UIkit:any; declare var UIkit:any;
@ -26,12 +28,11 @@ export class ClaimProjectsSearchFormComponent {
public elementRef; public elementRef;
@Output() projectSelected = new EventEmitter(); @Output() projectSelected = new EventEmitter();
@Input() public properties:EnvProperties; public properties:EnvProperties = properties;
@Input() public inlineClaim:boolean=false; @Input() public inlineClaim:boolean=false;
@Input() localStoragePrefix:string = ""; @Input() localStoragePrefix:string = "";
@Input() basketLimit; @Input() basketLimit;
@Input() showOptions; @Input() showOptions;
public errorCodes:ErrorCodes = new ErrorCodes(); public errorCodes:ErrorCodes = new ErrorCodes();
public projects:string[]; public projects:string[];
public warningMessage = ""; public warningMessage = "";
@ -53,47 +54,83 @@ export class ClaimProjectsSearchFormComponent {
public rangeFields:string[][] = this.searchFields.PROJECT_RANGE_FIELDS; public rangeFields:string[][] = this.searchFields.PROJECT_RANGE_FIELDS;
openaireEntities = OpenaireEntities; openaireEntities = OpenaireEntities;
sub; sub;
selectedFunder = null;
funderOptions = [];
isNoProjectFunder = false;
constructor(private _service: ProjectService, private _projectService: SearchProjectsService, myElement: ElementRef) { constructor(private _service: ProjectService, private _projectService: SearchProjectsService, myElement: ElementRef) {
this.elementRef = myElement; this.elementRef = myElement;
this.rangeFilters = RangeFilter.parse(this.rangeFields,"project"); this.rangeFilters = RangeFilter.parse(this.rangeFields,"project");
this.getFunders();
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub instanceof Subscriber) { if (this.sub instanceof Subscriber) {
this.sub.unsubscribe(); this.sub.unsubscribe();
} }
} }
getFunders(){
this.openaireResultsStatus = this.errorCodes.LOADING;
this.showResults = true;
this.sub = this._projectService.advancedSearchProjects("", 1, 0, this.properties,
this.refineFieldsQuery, this.refineFields, "&type=projects&sf=funder").subscribe(
data => {
for(let v of data[2][0].values){
let option = {value : v, label: v.name};
this.funderOptions.push(option);
}
this.openaireResultsStatus = this.errorCodes.DONE;
}, error =>{
this.openaireResultsStatus = this.errorCodes.ERROR;
})
}
search(page,size) { funderChanged(value){
if(this.keyword.length == 0){ this.keyword = ""
this.showResults =false; this.selectedFunder = value;
return; this.isNoProjectFunder = this.selectedFunder && this.selectedFunder.number == 1;
this.openaireResults = [];
if(this.isNoProjectFunder){
this.showResults = true;
this.search(1,1);
}else{
this.openaireResults = [];
} }
this.showResults =true; }
search(page,size) {
/* if (this.keyword.length == 0) {
this.showResults = false;
return;
}*/
this.showResults = true;
this.openaireResults = []; this.openaireResults = [];
this.openaireResultsStatus = this.errorCodes.LOADING; this.openaireResultsStatus = this.errorCodes.LOADING;
this.prevFilters = this.filters; this.prevFilters = this.filters;
//searchProjects (params: string, refineParams:string, page: number, size: number, refineFields:string[] , properties:EnvProperties ):any { //searchProjects (params: string, refineParams:string, page: number, size: number, refineFields:string[] , properties:EnvProperties ):any {
this.sub = this._projectService.searchProjects(this.createOpenaireQueryParams(),(page==1)? this.refineFieldsQuery:null, page, size, (page==1)?this.refineFields:[], this.properties).subscribe( this.sub = this._projectService.advancedSearchProjects(this.createOpenaireQueryParams(), page, size, this.properties, null, [], this.createOpenaireRefineQuery()).subscribe(
// this.sub = this._projectService.searchProjects(this.createOpenaireQueryParams(),(page==1)? this.refineFieldsQuery:null, page, size, (page==1)?this.refineFields:[], this.properties).subscribe(
data => { data => {
if(data != null) { if (data != null) {
this.openaireResultsPage=page; this.openaireResultsPage = page;
this.openaireResultsNum = data[0]; this.openaireResultsNum = data[0];
this.openaireResults =ClaimProjectsSearchFormComponent.openaire2ClaimEntity(data[1], this.properties); this.openaireResults = ClaimProjectsSearchFormComponent.openaire2ClaimEntity(data[1], this.properties);
if(data[2] && data[2].length > 0){ if (data[2] && data[2].length > 0) {
this.filters = this.checkSelectedFilters( data[2], this.prevFilters); this.filters = this.checkSelectedFilters(data[2], this.prevFilters);
}
this.openaireResultsStatus = this.errorCodes.DONE;
if(this.openaireResultsNum == 0){
this.openaireResultsStatus = this.errorCodes.NONE;
this.filters = this.checkSelectedFilters( [], this.prevFilters);
}
}else {
this.openaireResultsStatus = this.errorCodes.ERROR;
} }
},
this.openaireResultsStatus = this.errorCodes.DONE;
if (this.openaireResultsNum == 0) {
this.openaireResultsStatus = this.errorCodes.NONE;
this.filters = this.checkSelectedFilters([], this.prevFilters);
}
/* if(this.isNoProjectFunder && this.claimResultsComponent){
this.claimResultsComponent.add(this.openaireResults[0])
}*/
} else {
this.openaireResultsStatus = this.errorCodes.ERROR;
}
},
err => { err => {
this.openaireResultsStatus = this.errorCodes.ERROR; this.openaireResultsStatus = this.errorCodes.ERROR;
//console.log(err.status); //console.log(err.status);
@ -101,85 +138,23 @@ export class ClaimProjectsSearchFormComponent {
} }
); );
} }
// select(entity){ remove(item){
// if(this.selectedProjects.length > 50){
// UIkit.notification({
// message : 'Your basket exceeds the number of allowed projects (50)',
// status : 'warning',
// timeout : 1500,
// pos : 'top-center'
// });
// return;
// }
// this.query = "";
// // this.searchTermStream.next(this.query); //clear
// entity = entity.value;
// // var project: ClaimProject = new ClaimProject();
// // project.funderId = entity.funderId;
// // project.funderName = entity.funderName;
// // project.id = entity.id;
// // project.projectName = entity.projectName;
// // project.projectAcronym = entity.projectAcronym;
// // project.startDate = entity.startDate;
// // project.endDate = entity.endDate;
// // project.code = entity.code;
// // project.jurisdiction = entity.jurisdiction;
// // project.fundingLevel0 = entity.fundingLevel0;
//
//
// var index:number =this.selectedProjects.indexOf(entity);
// var found:boolean = false;
// this.warningMessage = "";
//
// for (var _i = 0; _i < this.selectedProjects.length; _i++) {
// let project = this.selectedProjects[_i];
// if(entity.id == project.id){
// found=true;
// this.warningMessage = "Project already in your basket";
// }
// }
//
// if (!found) {
// this.selectedProjects.push(entity);
// if(this.selectedProjects != null){
// localStorage.setItem(this.localStoragePrefix + "projects", JSON.stringify(this.selectedProjects));
// }
// this.projectSelected.emit({
// value: true
// });
//
// }
// }
/* static showItem(item):string{
return ((item.field[1]['@value'])?item.field[1]['@value']+" - ":"" ) + item.field[3]['@value'];
}*/
remove(item){
let index:number =this.selectedProjects.indexOf(item); let index:number =this.selectedProjects.indexOf(item);
if (index > -1) { if (index > -1) {
this.selectedProjects.splice(index, 1); this.selectedProjects.splice(index, 1);
} }
} }
/* handleClick(event){ static openaire2ClaimEntity(items, properties:EnvProperties){
var clickedComponent = event.target;
var inside = false;
do {
if (clickedComponent === this.elementRef.nativeElement) {
inside = true;
}
clickedComponent = clickedComponent.parentNode;
} while (clickedComponent);
}*/
static openaire2ClaimEntity(items, properties:EnvProperties){
const projects: ClaimEntity[] = []; const projects: ClaimEntity[] = [];
for(const item of items){ for(const item of items){
const entity: ClaimEntity = new ClaimEntity(); const entity: ClaimEntity = new ClaimEntity();
entity.project = new ClaimProject(); entity.project = new ClaimProject();
entity.project.funderId = item.funderId; entity.project.funderId = item.funderId;
entity.project.funderName = item.funderShortname; entity.project.funderShortname = item.funderShortname?item.funderShortname:(entity.project.funderId.split("::")[1]);
entity.project.funderName = item.funderName;
entity.id = item.id; entity.id = item.id;
entity.project.url = properties.searchLinkToProject + entity.id; entity.project.url = (item.code !="unidentified") ? properties.searchLinkToProject + entity.id : null;
entity.title = item.title.name; entity.title = item.title.name;
entity.project.acronym = item.acronym; entity.project.acronym = item.acronym;
entity.project.startDate = item.startYear; entity.project.startDate = item.startYear;
@ -202,12 +177,16 @@ export class ClaimProjectsSearchFormComponent {
} }
createOpenaireQueryParams():string { createOpenaireQueryParams(): string {
let query = ""; let query = "";
if(this.keyword.length > 0){ if (this.keyword.length > 0) {
query += "q=" + StringUtils.quote(StringUtils.URIEncode(this.keyword)); // query += "q=" + StringUtils.quote(StringUtils.URIEncode(this.keyword));
query += StringUtils.quote(StringUtils.URIEncode(this.keyword));
} }
return query;
}
createOpenaireRefineQuery(): string {
/*if(this.startYear.length > 0 ){ /*if(this.startYear.length > 0 ){
query+='&fq=projectstartyear exact \"'+this.startYear+'\"' query+='&fq=projectstartyear exact \"'+this.startYear+'\"'
} }
@ -215,30 +194,33 @@ export class ClaimProjectsSearchFormComponent {
query+='&fq=projectendyear exact \"'+this.endYear+'\"' query+='&fq=projectendyear exact \"'+this.endYear+'\"'
}*/ }*/
let allFqs = ""; let allFqs = "";
for (let filter of this.filters){ for (let filter of this.filters) {
if(filter.countSelectedValues > 0){ if (filter.countSelectedValues > 0) {
let count_selected=0; let count_selected = 0;
let fq = ""; let fq = "";
for (let value of filter.values){ for (let value of filter.values) {
if(value.selected == true){ if (value.selected == true) {
count_selected++; count_selected++;
fq+=(fq.length > 0 ? " " + filter.filterOperator + " ":"" ) + filter.filterId + " exact " + (StringUtils.quote(value.id)); fq += (fq.length > 0 ? " " + filter.filterOperator + " " : "") + filter.filterId + " exact " + (StringUtils.quote(value.id));
} }
} }
if(count_selected > 0){ if (count_selected > 0) {
fq="&fq="+StringUtils.URIEncode(fq); fq = "&fq=" + StringUtils.URIEncode(fq);
allFqs += fq; allFqs += fq;
} }
} }
} }
for (let i=0; i<this.rangeFilters.length; i++){ if(this.isNoProjectFunder){
allFqs += "&fq=" + StringUtils.URIEncode( "funder exact " + (StringUtils.quote(this.selectedFunder.id))); ;
}
for (let i = 0; i < this.rangeFilters.length; i++) {
let filter = this.rangeFilters[i]; let filter = this.rangeFilters[i];
//selectedFromValue, selectedToValue, equalityOp, equalityOpFrom, equalityOpTo, filterOp ){ //selectedFromValue, selectedToValue, equalityOp, equalityOpFrom, equalityOpTo, filterOp ){
allFqs+= NewSearchPageComponent.createRangeFilterQuery(this.rangeFields[i],filter.selectedFromValue, filter.selectedToValue, " within ", ">=" ,"<=", "and" ) allFqs += NewSearchPageComponent.createRangeFilterQuery(this.rangeFields[i], filter.selectedFromValue, filter.selectedToValue, " within ", ">=", "<=", "and")
} }
return query+allFqs; return allFqs + "&type=projects";
} }
public yearChanged() { public yearChanged() {
this.search(this.page, this.size); this.search(this.page, this.size);
@ -273,20 +255,21 @@ export class ClaimProjectsSearchFormComponent {
} }
} }
filter.countAllValues = filter.values.length;
} }
if(filters.length == 0 ){ if(filters.length == 0 ){
for(let j=0; j< prevFilters.length ; j++){ for(let j=0; j< prevFilters.length ; j++) {
let filter = Object.assign({}, prevFilters[j]); let filter = Object.assign({}, prevFilters[j]);
filter.values = []; filter.values = [];
for(let filterValue of prevFilters[j].values) { for (let filterValue of prevFilters[j].values) {
if(filterValue.selected){ if (filterValue.selected) {
filterValue.number = 0; filterValue.number = 0;
filter.values.push(filterValue); filter.values.push(filterValue);
}
}
filters.push(filter)
} }
}
filter.countAllValues = filter.values.length;
filters.push(filter)
}
} }
return filters; return filters;
} }

View File

@ -17,14 +17,15 @@ import {RangeFilterModule} from "../../utils/rangeFilter/rangeFilter.module";
import {AdvancedSearchInputModule} from "../../sharedComponents/advanced-search-input/advanced-search-input.module"; import {AdvancedSearchInputModule} from "../../sharedComponents/advanced-search-input/advanced-search-input.module";
import {InputModule} from "../../sharedComponents/input/input.module"; import {InputModule} from "../../sharedComponents/input/input.module";
import {DropdownFilterModule} from "../../utils/dropdown-filter/dropdown-filter.module"; import {DropdownFilterModule} from "../../utils/dropdown-filter/dropdown-filter.module";
import {LoadingModule} from "../../utils/loading/loading.module";
@NgModule({ @NgModule({
imports: [ imports: [
SharedModule, CommonModule, SharedModule, CommonModule,
// LoadingModalModule, // LoadingModalModule,
ProjectServiceModule, ProjectsServiceModule, EntitiesAutocompleteModule, HelperModule, ProjectServiceModule, ProjectsServiceModule, EntitiesAutocompleteModule, HelperModule,
PagingModule, SearchFilterModule, ClaimResultsModule, RangeFilterModule, AdvancedSearchInputModule, InputModule, DropdownFilterModule PagingModule, SearchFilterModule, ClaimResultsModule, RangeFilterModule, AdvancedSearchInputModule, InputModule, DropdownFilterModule, LoadingModule
], ],
providers:[ providers:[
], ],
declarations: [ declarations: [

View File

@ -51,7 +51,9 @@
</div> </div>
</div> </div>
<div *ngIf="crossrefStatus === errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1" <div *ngIf="crossrefStatus === errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1"
role="alert"><span class="loading-gif uk-align-center"></span></div> role="alert">
<loading></loading>
</div>
<div> <div>
<claim-results [localStoragePrefix]=localStoragePrefix [results]=crossrefResults <claim-results [localStoragePrefix]=localStoragePrefix [results]=crossrefResults
@ -114,7 +116,7 @@
<div *ngIf="openaireResultsStatus === errorCodes.LOADING" <div *ngIf="openaireResultsStatus === errorCodes.LOADING"
class="uk-animation-fade uk-margin-top uk-width-1-1" class="uk-animation-fade uk-margin-top uk-width-1-1"
role="alert"><span class="loading-gif uk-align-center">Loading...</span></div> role="alert"><loading></loading></div>
<claim-results [localStoragePrefix]=localStoragePrefix <claim-results [localStoragePrefix]=localStoragePrefix
[results]=openaireResults [selectedResults]=selectedResults [basketLimit]="basketLimit"></claim-results> [results]=openaireResults [selectedResults]=selectedResults [basketLimit]="basketLimit"></claim-results>
<div class="uk-flex uk-flex-center" *ngIf=" openaireResultsStatus != errorCodes.LOADING && openaireResultsNum != null && openaireResultsNum > 0" > <div class="uk-flex uk-flex-center" *ngIf=" openaireResultsStatus != errorCodes.LOADING && openaireResultsNum != null && openaireResultsNum > 0" >
@ -177,7 +179,7 @@
</div> </div>
</div> </div>
<div *ngIf="orcidStatus == errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1" role="alert"> <div *ngIf="orcidStatus == errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1" role="alert">
<span class="loading-gif uk-align-center"></span></div> <loading></loading></div>
</div> </div>
</div> </div>
<div *ngIf="activeTab == 'datacite'" id="datacite" class="uk-animation-fade"> <div *ngIf="activeTab == 'datacite'" id="datacite" class="uk-animation-fade">
@ -190,7 +192,7 @@
<div class="uk-margin-top"> <div class="uk-margin-top">
<div *ngIf="dataciteStatus == errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1" <div *ngIf="dataciteStatus == errorCodes.LOADING" class="uk-animation-fade uk-margin-top uk-width-1-1"
role="alert"><span class="loading-gif uk-align-center"></span></div> role="alert"><loading></loading></div>
<div> <div>
<claim-results [localStoragePrefix]=localStoragePrefix *ngIf="dataciteResults.length > 0 " <claim-results [localStoragePrefix]=localStoragePrefix *ngIf="dataciteResults.length > 0 "
[results]=dataciteResults [selectedResults]=selectedResults [basketLimit]="basketLimit"></claim-results> [results]=dataciteResults [selectedResults]=selectedResults [basketLimit]="basketLimit"></claim-results>

View File

@ -22,10 +22,11 @@ import {AdvancedSearchInputModule} from "../../sharedComponents/advanced-search-
import {InputModule} from "../../sharedComponents/input/input.module"; import {InputModule} from "../../sharedComponents/input/input.module";
import {SearchInputModule} from "../../sharedComponents/search-input/search-input.module"; import {SearchInputModule} from "../../sharedComponents/search-input/search-input.module";
import {DropdownFilterModule} from "../../utils/dropdown-filter/dropdown-filter.module"; import {DropdownFilterModule} from "../../utils/dropdown-filter/dropdown-filter.module";
import {LoadingModule} from "../../utils/loading/loading.module";
@NgModule({ @NgModule({
imports: [SharedModule, CommonModule, SearchResearchResultsServiceModule, PagingModule, SearchCrossrefServiceModule, imports: [SharedModule, CommonModule, SearchResearchResultsServiceModule, PagingModule, SearchCrossrefServiceModule,
SearchDataciteServiceModule, HelperModule, SearchFilterModule, ClaimResultsModule, MatSelectModule, QuickSelectionsModule, RangeFilterModule, ClaimProjectsSearchFormModule, AdvancedSearchInputModule, InputModule, SearchInputModule, DropdownFilterModule], SearchDataciteServiceModule, HelperModule, SearchFilterModule, ClaimResultsModule, MatSelectModule, QuickSelectionsModule, RangeFilterModule, ClaimProjectsSearchFormModule, AdvancedSearchInputModule, InputModule, SearchInputModule, DropdownFilterModule, LoadingModule],
providers:[ providers:[
SearchOrcidService SearchOrcidService
], ],

View File

@ -0,0 +1,23 @@
export class ClaimsProperties{
ALLOW_ORGANIZATION_LINKING:boolean = false;
SELECT_ENTITIES = {
projects:"Funding"
}
INLINE_ENTITY = {
show: true,
guideText : null
}
BASKET ={
source_title: "Source",
target_title: "Link source to"
}
METADATA_PREVIEW ={
source_title: "Source",
target_title: "Link to",
edit_source_title: "Edit",
edit_target_title: "Edit",
edit_target_icon: "edit"
}
}

View File

@ -1,25 +1,27 @@
<schema2jsonld *ngIf="url" [URL]="url" [name]="pageTitle" type="other"></schema2jsonld> <schema2jsonld *ngIf="url" [URL]="url" [name]="pageTitle" type="other"></schema2jsonld>
<div class="uk-grid"> <div class="uk-grid">
<div class="uk-width-expand uk-position-relative"> <div class="uk-width-expand uk-position-relative uk-margin-small-top">
<helper *ngIf="pageContents && pageContents['top'] && pageContents['top'].length > 0" <helper *ngIf="pageContents && pageContents['top'] && pageContents['top'].length > 0"
[texts]="pageContents['top']"></helper> [texts]="pageContents['top']"></helper>
<div *ngIf="filterForm" [id]="actions?'page_content_actions':null" [class.uk-blur-background]="actions" [attr.uk-sticky]="(actions)?'media: @m':null" [attr.offset]="offset"> <div *ngIf="filterForm" [id]="actions?'page_content_actions':null" [class.uk-blur-background]="actions" [attr.uk-sticky]="(actions)?'media: @m':null" [attr.offset]="offset">
<div [class.uk-padding-small]="actions" class="uk-padding-remove-vertical"> <div [class.uk-padding-small]="actions" class="uk-padding-remove-vertical">
<div class="uk-section-xsmall">
<div class="uk-flex uk-flex-right@m uk-flex-center uk-flex-wrap uk-flex-middle"> <div class="uk-flex uk-flex-right@m uk-flex-center uk-flex-wrap uk-flex-middle">
<div search-input [disabled]="loading" [searchControl]="filterForm.controls.keyword" searchInputClass="outer" <div search-input [disabled]="loading" [searchControl]="filterForm.controls.keyword" searchInputClass="outer"
placeholder="Search links" class="uk-width-1-3@xl uk-width-2-5@l uk-width-1-2@m uk-width-1-1" placeholder="Search links" class="uk-width-1-3@xl uk-width-2-5@l uk-width-1-2@m uk-width-1-1"
(searchEmitter)="changeKeyword()" [expandable]="true"></div> (searchEmitter)="changeKeyword()" [expandable]="true"></div>
</div> </div>
</div>
</div> </div>
</div> </div>
<div [class.uk-padding]="actions" class="uk-padding-remove-vertical"> <div [class.uk-padding]="actions" class="uk-padding-remove-vertical">
<div class="uk-margin-medium-top"> <div class="uk-margin-small-top">
<results-and-pages [type]="resultsNum !== 1?'Links':'Link'" [page]="page" [pageSize]="size" [hasSearch]="true" [searchTerm]="keyword" <results-and-pages [type]="resultsNum !== 1?'Links':'Link'" [page]="page" [pageSize]="size" [hasSearch]="true" [searchTerm]="keyword"
[totalResults]="resultsNum" customClasses="uk-margin-remove"></results-and-pages> [totalResults]="resultsNum" customClasses="uk-margin-remove"></results-and-pages>
</div> </div>
<div class="uk-grid uk-flex-middle uk-margin-medium-top" uk-grid> <div class="uk-grid uk-flex-middle uk-margin-small-top" uk-grid>
<div *ngIf="fetchBy != 'User' && properties.environment == 'development'" >
<input [(ngModel)]="mine" [checked]="mine" (ngModelChange)="goTo(1)" type="checkbox" class="uk-checkbox"> Mine
</div>
<div> <div>
<dropdown-filter #dropdownFilter dropdownClass="uk-width-medium uk-padding-small" <dropdown-filter #dropdownFilter dropdownClass="uk-width-medium uk-padding-small"
name="Type of Entity" [disabled]="loading" [count]="entities.length"> name="Type of Entity" [disabled]="loading" [count]="entities.length">
@ -43,6 +45,7 @@
type="select" [options]="sortOptions"> type="select" [options]="sortOptions">
</div> </div>
</div> </div>
<div class="uk-width-expand@l uk-width-1-1 uk-flex uk-flex-right@m uk-flex-center"> <div class="uk-width-expand@l uk-width-1-1 uk-flex uk-flex-right@m uk-flex-center">
<paging-no-load [currentPage]="page" [totalResults]="resultsNum" [size]="size" <paging-no-load [currentPage]="page" [totalResults]="resultsNum" [size]="size"
[loading]="false" (pageChange)="pageChange($event)"></paging-no-load> [loading]="false" (pageChange)="pageChange($event)"></paging-no-load>

View File

@ -40,7 +40,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
page: number = 1; page: number = 1;
size: number = 50; size: number = 50;
keyword: string; // the keyword string to give to the request as parameter keyword: string; // the keyword string to give to the request as parameter
types = ["All", "Project", "Context", "Result", "User"]; types = ["All", "Project", "Context", "Result", "User", "Organization"];
loading: boolean = false; loading: boolean = false;
@Input() fetchBy: string; @Input() fetchBy: string;
@Input() fetchId: string; @Input() fetchId: string;
@ -53,6 +53,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
public filterForm: FormGroup; public filterForm: FormGroup;
public entities: string[] = []; public entities: string[] = [];
selected = []; selected = [];
mine = false;
allOptions: Option[] = [ allOptions: Option[] = [
{label: OpenaireEntities.PUBLICATIONS, value: "publication"}, {label: OpenaireEntities.PUBLICATIONS, value: "publication"},
@ -133,6 +134,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
this.fetchId = this.fetchId ? this.fetchId : ''; this.fetchId = this.fetchId ? this.fetchId : '';
} }
let page = (params['page'] === undefined) ? 1 : +params['page']; let page = (params['page'] === undefined) ? 1 : +params['page'];
this.mine = (params['mine'] == 'true' ? true:false);
this.keyword = (params['keyword'] ? params['keyword'] : ""); this.keyword = (params['keyword'] ? params['keyword'] : "");
this.filterForm.get('keyword').setValue(this.keyword); this.filterForm.get('keyword').setValue(this.keyword);
this.page = (page <= 0) ? 1 : page; this.page = (page <= 0) ? 1 : page;
@ -186,6 +188,16 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
this.handleErrors(err, "Error getting claims for project with id: " + this.fetchId); this.handleErrors(err, "Error getting claims for project with id: " + this.fetchId);
} }
); );
} else if (this.fetchBy == "Organization") {
this.subResults = this._claimService.getClaimsByOrganization(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL, this.mine).subscribe(
data => {
this.manageAPIData(data);
this.loading = false;
},
err => {
this.handleErrors(err, "Error getting claims for project with id: " + this.fetchId);
}
);
} else if (this.fetchBy == "User") { } else if (this.fetchBy == "User") {
this.subResults = this._claimService.getClaimsByUser(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( this.subResults = this._claimService.getClaimsByUser(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
data => { data => {
@ -209,7 +221,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
} }
); );
} else if (this.fetchBy == "Context") { } else if (this.fetchBy == "Context") {
this.subResults = this._claimService.getClaimsBycontext(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( this.subResults = this._claimService.getClaimsBycontext(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL, this.mine).subscribe(
data => { data => {
this.manageAPIData(data); this.manageAPIData(data);
this.loading = false; this.loading = false;
@ -220,7 +232,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
} }
); );
} else { } else {
this.subResults = this._claimService.getClaims(this.size, this.page, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe( this.subResults = this._claimService.getClaims(this.size, this.page, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL, this.mine).subscribe(
data => { data => {
this.manageAPIData(data); this.manageAPIData(data);
this.loading = false; this.loading = false;
@ -259,15 +271,8 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
types += (types.length > 0 ? ',' : '') + type; types += (types.length > 0 ? ',' : '') + type;
} }
params += (this.entities.length > 0) ? (params.length > 0 ? '&' : '') + "types=" + types : ""; params += (this.entities.length > 0) ? (params.length > 0 ? '&' : '') + "types=" + types : "";
if (this.isAdmin) {
params += (this.fetchBy == 'All' ? "" : (params.length > 0 ? '&' : '') + "fetchBy=" + this.fetchBy);
params += (this.fetchId == '' ? "" : (params.length > 0 ? '&' : '') + "fetchId=" + this.fetchId);
}
params += (this.filterForm.get("sort").value.sort == 'date' && this.filterForm.get("sort").value.descending ? "" : (params.length > 0 ? '&' : '') + "sort=" + this.filterForm.get("sort").value.sort + "-" + this.filterForm.get("sort").value.descending); params += (this.filterForm.get("sort").value.sort == 'date' && this.filterForm.get("sort").value.descending ? "" : (params.length > 0 ? '&' : '') + "sort=" + this.filterForm.get("sort").value.sort + "-" + this.filterForm.get("sort").value.descending);
params += (this.keyword == '' ? "" : (params.length > 0 ? '&' : '') + "keyword=" + this.keyword); params += (this.keyword == '' ? "" : (params.length > 0 ? '&' : '') + "keyword=" + this.keyword);
if (this.communityId != null) {
params += "&communityId=" + this.communityId;
}
return params; return params;
} }
@ -364,7 +369,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy {
if (claimDateStr < lastUpdateDateStr) { if (claimDateStr < lastUpdateDateStr) {
return true; return true;
} else { } else {
return claim.target.collectedFrom != "infrastruct_::openaire" && claim.indexed; return claim.target.collectedFrom != "infrastruct_::openaire";
} }
} }

View File

@ -1,6 +1,6 @@
import {Component, Input} from '@angular/core'; import {Component, Input} from '@angular/core';
import {EnvProperties} from '../../../utils/properties/env-properties'; import {EnvProperties} from '../../../utils/properties/env-properties';
import {ClaimDBContext, ClaimDBProject, ClaimDBResult} from "../claimHelper.class"; import {ClaimDBContext, ClaimDBOrganization, ClaimDBProject, ClaimDBResult} from "../claimHelper.class";
import {OpenaireEntities} from "../../../utils/properties/searchFields"; import {OpenaireEntities} from "../../../utils/properties/searchFields";
import {StringUtils} from "../../../utils/string-utils.class"; import {StringUtils} from "../../../utils/string-utils.class";
@ -26,6 +26,10 @@ import {StringUtils} from "../../../utils/string-utils.class";
<project-title [project]="entity" [searchLink]=properties.searchLinkToProject <project-title [project]="entity" [searchLink]=properties.searchLinkToProject
[externalPortalUrl]=externalPortalUrl></project-title> [externalPortalUrl]=externalPortalUrl></project-title>
</div> </div>
<div *ngIf="type == 'organization'" [attr.uk-tooptip]="getEntityName(type)">
<span class="uk-text-meta uk-text-small uk-margin-small-right uk-text-nowrap">Link to:</span>
<organization-title [organization]="entity"></organization-title>
</div>
<div *ngIf="type == 'context'"> <div *ngIf="type == 'context'">
<span class="uk-text-meta uk-text-small uk-margin-small-right uk-text-nowrap">Link to:</span> <span class="uk-text-meta uk-text-small uk-margin-small-right uk-text-nowrap">Link to:</span>
<h6 class="uk-h6 uk-margin-remove"> <h6 class="uk-h6 uk-margin-remove">
@ -36,7 +40,7 @@ import {StringUtils} from "../../../utils/string-utils.class";
}) })
export class ClaimEntityFormatter { export class ClaimEntityFormatter {
@Input() entity: ClaimDBResult | ClaimDBContext | ClaimDBProject; @Input() entity: ClaimDBResult | ClaimDBContext | ClaimDBProject | ClaimDBOrganization;
@Input() type: string; @Input() type: string;
@Input() properties: EnvProperties; @Input() properties: EnvProperties;
@Input() externalPortalUrl: string = null; @Input() externalPortalUrl: string = null;

View File

@ -5,18 +5,19 @@ import { RouterModule } from '@angular/router';
import {ProjectTitleFormatter} from './projectTitleFormatter.component'; import {ProjectTitleFormatter} from './projectTitleFormatter.component';
import {PublicationTitleFormatter} from './publicationTitleFormatter.component'; import {PublicationTitleFormatter} from './publicationTitleFormatter.component';
import {ClaimEntityFormatter} from './claimEntityFormatter.component'; import {ClaimEntityFormatter} from './claimEntityFormatter.component';
import {OrganizationTitleFormatterComponent} from "./organizationTitleFormatter.component";
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, RouterModule CommonModule, RouterModule
], ],
declarations: [ declarations: [
ProjectTitleFormatter, PublicationTitleFormatter, ClaimEntityFormatter ProjectTitleFormatter, PublicationTitleFormatter, ClaimEntityFormatter, OrganizationTitleFormatterComponent
], ],
providers: [ ], providers: [ ],
exports: [ exports: [
ProjectTitleFormatter, PublicationTitleFormatter, ClaimEntityFormatter ProjectTitleFormatter, PublicationTitleFormatter, ClaimEntityFormatter, OrganizationTitleFormatterComponent
] ]
}) })

View File

@ -0,0 +1,18 @@
import {Component, Input} from '@angular/core';
@Component({
selector: 'organization-title',
template: `
<h6 *ngIf="organization" class="uk-margin-remove multi-line-ellipsis lines-2">
<p class="uk-margin-remove">
{{(organization.shortName ? ('[' + organization.shortName + '] ') : '')}}{{organization.name}}
</p>
</h6>
`
})
export class OrganizationTitleFormatterComponent {
@Input() organization: any;
public url: string;
}

View File

@ -10,10 +10,10 @@ import {properties} from "../../../../../environments/environment";
<ng-container> <ng-container>
<h6 class="uk-margin-remove multi-line-ellipsis lines-2"> <h6 class="uk-margin-remove multi-line-ellipsis lines-2">
<p class="uk-margin-remove"> <p class="uk-margin-remove">
<a *ngIf="externalPortalUrl" [href]="externalPortalUrl + projectUrl + '?projectId='+project['openaireId']" class="uk-link uk-link-heading"> <a *ngIf="externalPortalUrl" [href]="externalPortalUrl + projectUrl + '?projectId='+project['openaireId']" class="uk-link uk-link-heading" [class.uk-disabled]="project.name == 'unidentified'">
{{(project['acronym'] ? ('[' + project['acronym'] + '] ') : '')}}{{project['name']}} {{(project['acronym'] ? ('[' + project['acronym'] + '] ') : '')}}{{project['name']}}
</a> </a>
<a *ngIf="!externalPortalUrl" [routerLink]="projectUrl" [queryParams]="routerHelper.createQueryParam('projectId',project['openaireId'])" class="uk-link uk-link-heading"> <a *ngIf="!externalPortalUrl" [routerLink]="projectUrl" [queryParams]="routerHelper.createQueryParam('projectId',project['openaireId'])" class="uk-link uk-link-heading" [class.uk-disabled]="project.name == 'unidentified'">
{{(project['acronym'] ? ('[' + project['acronym'] + '] ') : '')}}{{project['name']}} {{(project['acronym'] ? ('[' + project['acronym'] + '] ') : '')}}{{project['name']}}
</a> </a>
</p> </p>

View File

@ -12,8 +12,8 @@ export class ClaimsService {
private getClaimRequest(size : number, page : number, url :string, fromCache:boolean):any { private getClaimRequest(size : number, page : number, url :string, fromCache:boolean):any {
return this.http.get(url, CustomOptions.getAuthOptionsWithBody()); return this.http.get(url, CustomOptions.getAuthOptionsWithBody());
} }
getClaims( size : number, page : number, keyword:string, sortby: string, descending: boolean, types: string, apiUrl:string):any { getClaims( size : number, page : number, keyword:string, sortby: string, descending: boolean, types: string, apiUrl:string, mine:boolean):any {
let url = apiUrl +"claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types); let url = apiUrl +"claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types) + (mine?"&mine=true":"") + (mine?"&mine=true":"");
return this.getClaimRequest(size,page,url,true); return this.getClaimRequest(size,page,url,true);
} }
@ -23,7 +23,7 @@ export class ClaimsService {
return this.getClaimRequest(size,page,url,false); return this.getClaimRequest(size,page,url,false);
} }
getClaimsBycontext( size : number, page : number, contextId:string, keyword:string, sortby: string, descending: boolean, types: string , apiUrl:string):any { getClaimsBycontext( size : number, page : number, contextId:string, keyword:string, sortby: string, descending: boolean, types: string , apiUrl:string, mine:boolean):any {
//console.info('ClaimsService: getClaims for context : '+contextId); //console.info('ClaimsService: getClaims for context : '+contextId);
let url = apiUrl +"contexts/"+contextId+"/claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types); let url = apiUrl +"contexts/"+contextId+"/claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types);
return this.getClaimRequest(size,page,url,true); return this.getClaimRequest(size,page,url,true);
@ -40,6 +40,10 @@ export class ClaimsService {
let url = apiUrl +"projects/"+projectId+"/claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types); let url = apiUrl +"projects/"+projectId+"/claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types);
return this.getClaimRequest(size,page,url,true); return this.getClaimRequest(size,page,url,true);
} }
getClaimsByOrganization( size : number, page : number, organizationId:string, keyword:string, sortby: string, descending: boolean, types: string, apiUrl:string, mine:boolean):any {
let url = apiUrl +"organizations/"+organizationId+"/claims"+"?offset="+(size*(page-1) + "&limit="+size)+"&keyword="+keyword+"&sortby="+sortby+"&descending="+descending+(types.length>0?"&"+types:types) + (mine?"&mine=true":"");
return this.getClaimRequest(size,page,url,true);
}
deleteClaimById(claimId:string , apiUrl:string):any{ deleteClaimById(claimId:string , apiUrl:string):any{
//console.warn('Trying to delete claim with id : '+claimId); //console.warn('Trying to delete claim with id : '+claimId);

View File

@ -58,22 +58,20 @@ export class SearchDataciteService {
entity.result.journal = null; entity.result.journal = null;
entity.result.DOI = item.attributes.doi; entity.result.DOI = item.attributes.doi;
entity.id = item.attributes.doi; entity.id = item.attributes.doi;
entity.title = item.attributes.title; entity.title = Array.isArray(item.attributes.titles) && item.attributes.titles[0].title?item.attributes.titles[0].title:null;
entity.result.url = properties.doiURL + item.attributes.doi; entity.result.url = properties.doiURL + item.attributes.doi;
entity.result.source = 'datacite'; entity.result.source = 'datacite';
entity.type = 'dataset'; entity.type = 'dataset';
entity.result.date = item.attributes.published; entity.result.date = item.attributes.publicationYear;
entity.result.accessRights = "OPEN"; entity.result.accessRights = "OPEN";
entity.result.publisher = item.attributes['container-title']; entity.result.publisher = item.attributes['publisher'];
entity.result.journal = null; entity.result.journal = null;
entity.result.record = item; entity.result.record = item;
if (item.attributes.author) { if (item.attributes.creators) {
entity.result.authors = []; entity.result.authors = [];
for (let j = 0; j < item.attributes.author.length; j++) { for (let j = 0; j < item.attributes.creators.length; j++) {
const author = item.attributes.author[j]; const author = item.attributes.creators[j].name;
if(author.family || author.literal) { entity.result.authors.push(author);
entity.result.authors.push((author.family) ? author.family + (author.given ? ', ' + author.given : '') : author.literal);
}
} }
} }
results.push(entity); results.push(entity);

View File

@ -1,6 +1,6 @@
<linking-generic *ngIf="validInput" [localStoragePrefix]="localStoragePrefix" [results]="results" [sources]="sources" <linking-generic *ngIf="validInput" [localStoragePrefix]="localStoragePrefix" [results]="results" [sources]="sources"
[communityId]="communityId" [inlineEntity]="inlineEntity" [showOptions]="showOptions" [communityId]="communityId" [inlineEntity]="inlineEntity" [showOptions]="showOptions"
pageTitle="Direct Linking"> pageTitle="Direct Linking" [claimsProperties]="claimsProperties">
</linking-generic> </linking-generic>
<div *ngIf="validInput== false" id="tm-main" class=" uk-section uk-padding-remove-top tm-middle"> <div *ngIf="validInput== false" id="tm-main" class=" uk-section uk-padding-remove-top tm-middle">

View File

@ -1,7 +1,7 @@
import {Component, Input, ViewChild} from '@angular/core'; import {Component, Input, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {EnvProperties} from '../../utils/properties/env-properties'; import {EnvProperties} from '../../utils/properties/env-properties';
import {ClaimEntity, ClaimProject, ShowOptions} from '../claim-utils/claimHelper.class'; import {ClaimEntity, ClaimOrganization, ClaimProject, ShowOptions} from '../claim-utils/claimHelper.class';
import {EntitiesSearchService} from '../../utils/entitiesAutoComplete/entitySearch.service'; import {EntitiesSearchService} from '../../utils/entitiesAutoComplete/entitySearch.service';
import {SearchResearchResultsService} from '../../services/searchResearchResults.service'; import {SearchResearchResultsService} from '../../services/searchResearchResults.service';
import {LinkingGenericComponent} from "../linking/linkingGeneric.component"; import {LinkingGenericComponent} from "../linking/linkingGeneric.component";
@ -11,6 +11,7 @@ import {properties} from "../../../../environments/environment";
import {OpenaireEntities} from "../../utils/properties/searchFields"; import {OpenaireEntities} from "../../utils/properties/searchFields";
import {StringUtils} from "../../utils/string-utils.class"; import {StringUtils} from "../../utils/string-utils.class";
import {ClaimProjectsSearchFormComponent} from "../claim-utils/claimProjectSearchForm.component"; import {ClaimProjectsSearchFormComponent} from "../claim-utils/claimProjectSearchForm.component";
import {ClaimsProperties} from "../claim-utils/claims.properties";
@Component({ @Component({
@ -24,18 +25,20 @@ export class DirectLinkingComponent {
// linkType: string = "project"; // link type (selected in home page) : project, context, software, etc // linkType: string = "project"; // link type (selected in home page) : project, context, software, etc
/* url Parameters for inline linking */ /* url Parameters for inline linking */
id: string = null; //entity id @Input() id: string = null; //entity id
type: string = null; // entity type (publication or dataset) type: string = null; // entity type (publication or dataset)
// linkTo: string = null; // entity type (project or context or entity) // linkTo: string = null; // entity type (project or context or entity)
// linkToEntities: string[] = []; // linkToEntities: string[] = [];
showOptions:ShowOptions = new ShowOptions(); showOptions:ShowOptions = new ShowOptions();
validEntityTypes = ["dataset", "publication", "software", "other", "project", "context"]; validEntityTypes = ["dataset", "publication", "software", "other", "project", "context", "organization"];
sources: ClaimEntity[] = []; sources: ClaimEntity[] = [];
inlineEntity: ClaimEntity = null; inlineEntity: ClaimEntity = null;
validInput: boolean = null;//'true; validInput: boolean = null;//'true;
properties: EnvProperties; properties: EnvProperties;
@Input() communityId: string = null; @Input() communityId: string = null;
localStoragePrefix: string = ""; localStoragePrefix: string = "";
@Input() organizationClaim: boolean = false;
@Input() claimsProperties:ClaimsProperties = new ClaimsProperties();
constructor(private _router: Router, private route: ActivatedRoute,private entitySearch:EntitiesSearchService, constructor(private _router: Router, private route: ActivatedRoute,private entitySearch:EntitiesSearchService,
private _searchResearchResultsService: SearchResearchResultsService) {} private _searchResearchResultsService: SearchResearchResultsService) {}
subscriptions = []; subscriptions = [];
@ -48,11 +51,18 @@ export class DirectLinkingComponent {
} }
ngOnInit() { ngOnInit() {
this.properties = properties; this.properties = properties;
/* if(!this.claimsProperties){
this.claimsProperties = new ClaimsProperties();
}*/
this.subscriptions.push(this.route.queryParams.subscribe(params => { this.subscriptions.push(this.route.queryParams.subscribe(params => {
this.id = params['id']; if(this.organizationClaim){
this.type = params['type']; this.type = "organization";
this.showOptions.linkTo = params['linkTo']; this.showOptions.linkTo = "result";
}else {
this.id = params['id'];
this.type = params['type'];
this.showOptions.linkTo = params['linkTo'];
}
if (this.type != null && this.showOptions.linkTo != null) { if (this.type != null && this.showOptions.linkTo != null) {
this.type = (this.validEntityTypes.indexOf(this.type) != -1) ? this.type : 'publication'; this.type = (this.validEntityTypes.indexOf(this.type) != -1) ? this.type : 'publication';
this.showOptions.linkTo = (this.validEntityTypes.indexOf(this.showOptions.linkTo) != -1 || this.showOptions.linkTo == "result") ? this.showOptions.linkTo : 'project'; this.showOptions.linkTo = (this.validEntityTypes.indexOf(this.showOptions.linkTo) != -1 || this.showOptions.linkTo == "result") ? this.showOptions.linkTo : 'project';
@ -68,6 +78,8 @@ export class DirectLinkingComponent {
if (this.type == "project") { if (this.type == "project") {
// this.linkType = "project"; // this.linkType = "project";
this.getProjectById(this.id); this.getProjectById(this.id);
} else if (this.type == "organization") {
this.getOrganizationById(this.id);
} else if (this.type == "publication") { } else if (this.type == "publication") {
this.getResearchResultById("publication", this.id); this.getResearchResultById("publication", this.id);
} else if (this.type == "dataset") { } else if (this.type == "dataset") {
@ -81,7 +93,7 @@ export class DirectLinkingComponent {
} }
//set which entities it is allowed to link to. //set which entities it is allowed to link to.
// add first the // add first the
if(this.type == "project"){ if(this.type == "project" || this.type == "organization"){
this.showOptions.linkToEntities = ["result"]; this.showOptions.linkToEntities = ["result"];
this.showOptions.linkTo = "result"; this.showOptions.linkTo = "result";
}else{ }else{
@ -95,24 +107,27 @@ export class DirectLinkingComponent {
this.showOptions.linkToEntities = ["result","project","context" ]; this.showOptions.linkToEntities = ["result","project","context" ];
} }
}
} else {
this.validInput = this.isValidInput(null);
} }
} else { }));
this.validInput = this.isValidInput(null);
}
}));
} }
isValidInput(result: ClaimEntity) { isValidInput(result: ClaimEntity) {
if (result == null) { if (result == null) {
return false; return false;
} else if (this.type == "project" && this.showOptions.linkTo != "result") { } else if (this.type == "organization" && !this.claimsProperties.ALLOW_ORGANIZATION_LINKING) {
return false;
} else if ((this.type == "project" || this.type == "organization") && this.showOptions.linkTo != "result") {
return false; return false;
} else if (["dataset", "publication", "software", "other"].indexOf(this.type) != -1 && (["project", "context", "result"].indexOf(this.showOptions.linkTo) == -1)) { } else if (["dataset", "publication", "software", "other"].indexOf(this.type) != -1 && (["project", "context", "result"].indexOf(this.showOptions.linkTo) == -1)) {
return false; return false;
} else if (["project", "dataset", "publication", "software", "other"].indexOf(this.type) == -1) { } else if (["project", "dataset", "publication", "software", "other", "organization"].indexOf(this.type) == -1) {
return false; return false;
} else { } else {
return true; return true;
@ -130,6 +145,17 @@ export class DirectLinkingComponent {
this.handleError("Error getting project by id: " + id, err); this.handleError("Error getting project by id: " + id, err);
})); }));
} }
getOrganizationById(id: string) {
this.subscriptions.push(this.entitySearch.fetchByType(id,"organization", this.properties).subscribe(
data => {
this.createClaimEntity(data, "organization");
},
err => {
this.validInput = this.isValidInput(null);
//console.log("An error occured")
this.handleError("Error getting project by id: " + id, err);
}));
}
getResearchResultById(resultType: string, id: string) { getResearchResultById(resultType: string, id: string) {
this.subscriptions.push(this._searchResearchResultsService.searchById(resultType, id, this.properties).subscribe(data => { this.subscriptions.push(this._searchResearchResultsService.searchById(resultType, id, this.properties).subscribe(data => {
@ -156,12 +182,23 @@ export class DirectLinkingComponent {
entity.project.code = project.code; entity.project.code = project.code;
entity.project.endDate = project.endDate; entity.project.endDate = project.endDate;
entity.project.funderId = project.funderId; entity.project.funderId = project.funderId;
entity.project.funderShortname = project.funderShortName?project.funderShortName:(entity.project.funderId.split("::")[1]);
entity.project.funderName = project.funderName; entity.project.funderName = project.funderName;
entity.project.fundingLevel0 = project.fundingLevel0; entity.project.fundingLevel0 = project.fundingLevel0;
entity.project.jurisdiction = project.jurisdiction; entity.project.jurisdiction = project.jurisdiction;
entity.project.startDate = project.startDate; entity.project.startDate = project.startDate;
this.inlineEntity = entity; this.inlineEntity = entity;
}else{ }else if(type =="organization"){
let organization = data[0];
let entity:ClaimEntity = new ClaimEntity();
entity.id = organization.id;
entity.type = "organization";
entity.title = organization.label;
entity.organization = new ClaimOrganization();
// entity.organization.url = properties.searchLinkToOrganization + entity.id;
entity.organization.name = organization.label;
this.inlineEntity = entity;
}else{
results = ClaimResultSearchFormComponent.openaire2ClaimResults(data, this.properties); results = ClaimResultSearchFormComponent.openaire2ClaimResults(data, this.properties);
} }

View File

@ -156,13 +156,14 @@ export class ClaimInsertComponent {
this.loading.open(); this.loading.open();
let claims: ClaimRecord2Insert[] = []; let claims: ClaimRecord2Insert[] = [];
let directclaims: DirectIndexRecord[] = []; let directclaims: DirectIndexRecord[] = [];
let idSuffix = (new Date()).getTime() + "";
let dashboard = this.properties.environment+"_"+this.properties.dashboard + (this.communityId?("_"+this.communityId):''); let dashboard = this.properties.environment+"_"+this.properties.dashboard + (this.communityId?("_"+this.communityId):'');
for (let j = 0; j < this.sources.length; j++) { // if an external result -> direct insert in the index for (let j = 0; j < this.sources.length; j++) { // if an external result -> direct insert in the index
const result: ClaimEntity = this.sources[j]; const result: ClaimEntity = this.sources[j];
if (result.result && ["crossref", "datacite", "orcid"].indexOf(result.result.source) != -1) { if (result.result && ["crossref", "datacite", "orcid"].indexOf(result.result.source) != -1) {
directclaims.push({ directclaims.push({
"id": result.id, "id": result.id,
"record": ClaimInsertComponent.createDirectClaim(result, this.results) "record": ClaimInsertComponent.createDirectClaim(result, this.results, idSuffix)
}); });
} }
} }
@ -173,12 +174,12 @@ export class ClaimInsertComponent {
if (this.sources.length > 0) { if (this.sources.length > 0) {
directclaims.push({ directclaims.push({
"id": entity.id, "id": entity.id,
"record": ClaimInsertComponent.createDirectClaim(entity, this.sources) "record": ClaimInsertComponent.createDirectClaim(entity, this.sources, idSuffix)
}); });
} else if (this.inlineEntity) { } else if (this.inlineEntity && this.inlineEntity.type != "organization") {
directclaims.push({ directclaims.push({
"id": entity.id, "id": entity.id,
"record": ClaimInsertComponent.createDirectClaim(entity, [this.inlineEntity]) "record": ClaimInsertComponent.createDirectClaim(entity, [this.inlineEntity], idSuffix)
}); });
} }
@ -187,11 +188,13 @@ export class ClaimInsertComponent {
for (let j = 0; j < this.sources.length; j++) { for (let j = 0; j < this.sources.length; j++) {
const result: ClaimEntity = this.sources[j]; // this is a research result const result: ClaimEntity = this.sources[j]; // this is a research result
if (entity.result) { if (entity.result) {
claims.push(ClaimInsertComponent.createResultClaim(result, entity, user.email, dashboard)); claims.push(ClaimInsertComponent.createResultClaim(result, entity, user.email, dashboard, idSuffix));
} else if (entity.context) { } else if (entity.context) {
claims.push(ClaimInsertComponent.createContextClaim(result, entity, user.email, dashboard)); claims.push(ClaimInsertComponent.createContextClaim(result, entity, user.email, dashboard, idSuffix));
} else if (entity.project) { } else if (entity.project) {
claims.push(ClaimInsertComponent.createProjectClaim(result, entity, user.email, dashboard)); claims.push(ClaimInsertComponent.createProjectClaim(result, entity, user.email, dashboard, idSuffix));
/* } else if (entity.organization) {
claims.push(ClaimInsertComponent.createOrganizationClaim(result, entity, user.email, dashboard, idSuffix));*/
} }
this.infoToLog.push([ result.title?result.title: result.id, entity.title?entity.title:entity.id]); this.infoToLog.push([ result.title?result.title: result.id, entity.title?entity.title:entity.id]);
@ -201,15 +204,19 @@ export class ClaimInsertComponent {
if (this.inlineEntity.result) { if (this.inlineEntity.result) {
if (entity.result) { if (entity.result) {
claims.push(ClaimInsertComponent.createResultClaim(this.inlineEntity, entity, user.email, dashboard)); claims.push(ClaimInsertComponent.createResultClaim(this.inlineEntity, entity, user.email, dashboard, idSuffix));
} else if (entity.context) { } else if (entity.context) {
claims.push(ClaimInsertComponent.createContextClaim(this.inlineEntity, entity, user.email, dashboard)); claims.push(ClaimInsertComponent.createContextClaim(this.inlineEntity, entity, user.email, dashboard, idSuffix));
} else if (entity.project) { } else if (entity.project) {
claims.push(ClaimInsertComponent.createProjectClaim(this.inlineEntity, entity, user.email, dashboard)); claims.push(ClaimInsertComponent.createProjectClaim(this.inlineEntity, entity, user.email, dashboard, idSuffix));
} }
} else if (this.inlineEntity.project) { } else if (this.inlineEntity.project) {
if (entity.result) { if (entity.result) {
claims.push(ClaimInsertComponent.createProjectClaim(entity, this.inlineEntity, user.email, dashboard)); claims.push(ClaimInsertComponent.createProjectClaim(entity, this.inlineEntity, user.email, dashboard, idSuffix));
}
} else if (this.inlineEntity.organization) {
if (entity.result) {
claims.push(ClaimInsertComponent.createOrganizationClaim(entity, this.inlineEntity, user.email, dashboard, idSuffix));
} }
} }
} }
@ -384,13 +391,18 @@ export class ClaimInsertComponent {
localStorage.removeItem(this.localStoragePrefix + "results"); localStorage.removeItem(this.localStoragePrefix + "results");
localStorage.removeItem(this.localStoragePrefix + "claimsJob"); localStorage.removeItem(this.localStoragePrefix + "claimsJob");
localStorage.removeItem(this.localStoragePrefix + "feedRecordsJob"); localStorage.removeItem(this.localStoragePrefix + "feedRecordsJob");
if(this.properties.myClaimsLink && this.properties.myClaimsLink.indexOf(".") == -1) {
this._router.navigate([this.properties.myClaimsLink], {queryParams: this.params}); this._router.navigate([this.properties.myClaimsLink], {queryParams: this.params});
}else if(this.properties.myClaimsLink && this.properties.myClaimsLink.indexOf(".") != -1) {
this._router.navigate([this.properties.myClaimsLink], {relativeTo: this.route});
}else{
this._router.navigate(["/"]);
}
} }
} }
private static createContextClaim(resultEntity: ClaimEntity, contextEntity: ClaimEntity, user: any, dashboard:string): ClaimRecord2Insert { private static createContextClaim(resultEntity: ClaimEntity, contextEntity: ClaimEntity, user: any, dashboard:string, idSuffix:string): ClaimRecord2Insert {
return { return {
claimedBy: user, claimedBy: user,
sourceId: contextEntity.context.concept.id, sourceId: contextEntity.context.concept.id,
@ -403,11 +415,12 @@ export class ClaimInsertComponent {
targetCollectedFrom: resultEntity.result.source, targetCollectedFrom: resultEntity.result.source,
targetAccessRights: resultEntity.result.accessRights, targetAccessRights: resultEntity.result.accessRights,
targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(resultEntity), targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(resultEntity),
claimedInDashboard : dashboard claimedInDashboard : dashboard,
idSuffix : idSuffix
}; };
} }
private static createProjectClaim(resultEntity: ClaimEntity, projectEntity: ClaimEntity, user: any, dashboard:string): ClaimRecord2Insert { private static createProjectClaim(resultEntity: ClaimEntity, projectEntity: ClaimEntity, user: any, dashboard:string, idSuffix:string): ClaimRecord2Insert {
return { return {
claimedBy: user, claimedBy: user,
sourceId: projectEntity.id, sourceId: projectEntity.id,
@ -420,11 +433,29 @@ export class ClaimInsertComponent {
targetCollectedFrom: resultEntity.result.source, targetCollectedFrom: resultEntity.result.source,
targetAccessRights: resultEntity.result.accessRights, targetAccessRights: resultEntity.result.accessRights,
targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(resultEntity), targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(resultEntity),
claimedInDashboard : dashboard claimedInDashboard : dashboard,
idSuffix : idSuffix
};
}
private static createOrganizationClaim(resultEntity: ClaimEntity, organizationEntity: ClaimEntity, user: any, dashboard:string, idSuffix:string): ClaimRecord2Insert {
return {
claimedBy: user,
sourceId: organizationEntity.id,
sourceType: "organization",
sourceCollectedFrom: "openaire",
sourceAccessRights: "OPEN",
sourceEmbargoEndDate: "",
targetId: resultEntity.id,
targetType: resultEntity.type,
targetCollectedFrom: resultEntity.result.source,
targetAccessRights: resultEntity.result.accessRights,
targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(resultEntity),
claimedInDashboard : dashboard,
idSuffix : idSuffix
}; };
} }
private static createResultClaim(inlineResult: ClaimEntity, resultEntity: ClaimEntity, user: string, dashboard:string): ClaimRecord2Insert { private static createResultClaim(inlineResult: ClaimEntity, resultEntity: ClaimEntity, user: string, dashboard:string, idSuffix:string): ClaimRecord2Insert {
return { return {
claimedBy: user, claimedBy: user,
@ -438,7 +469,9 @@ export class ClaimInsertComponent {
targetCollectedFrom: inlineResult.result.source, targetCollectedFrom: inlineResult.result.source,
targetAccessRights: inlineResult.result.accessRights, targetAccessRights: inlineResult.result.accessRights,
targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(inlineResult), targetEmbargoEndDate: ClaimInsertComponent.getEmbargoEndDate(inlineResult),
claimedInDashboard : dashboard claimedInDashboard : dashboard,
idSuffix : idSuffix
}; };
} }
@ -448,12 +481,13 @@ export class ClaimInsertComponent {
} }
return "" return ""
} }
static createOpenAIREId(id, idSuffix:string):string {
static createDirectClaim(resultEntity: ClaimEntity, results: ClaimEntity[]) { return id.indexOf( "::" ) == -1 ? ("userclaim___::" + Md5.hashStr(id + idSuffix)):id;
}
static createDirectClaim(resultEntity: ClaimEntity, results: ClaimEntity[], idSuffix:string) {
let entity = {}; let entity = {};
const md5_id = Md5.hashStr(resultEntity.id); entity["originalId"] = this.createOpenAIREId(resultEntity.id, idSuffix);
entity["originalId"] = "userclaim___::" + md5_id; entity["openaireId"] = this.createOpenAIREId(resultEntity.id, idSuffix);
entity["openaireId"] = "userclaim___::" + md5_id;
entity["title"] = resultEntity.title; entity["title"] = resultEntity.title;
entity["title"] = (Array.isArray(resultEntity.title) && resultEntity.title.length > 0) ? resultEntity.title[0] : resultEntity.title; entity["title"] = (Array.isArray(resultEntity.title) && resultEntity.title.length > 0) ? resultEntity.title[0] : resultEntity.title;
@ -502,7 +536,7 @@ export class ClaimInsertComponent {
entity["linksToProjects"] = []; entity["linksToProjects"] = [];
} }
let project: ClaimEntity = results[i]; let project: ClaimEntity = results[i];
entity["linksToProjects"].push("info:eu-repo/grantAgreement/" + project.project.funderName + "/" + project.project.fundingLevel0 + "/" + project.project.code + "/" + project.project.jurisdiction + "/" + project.title + "/" + project.project.acronym); entity["linksToProjects"].push("info:eu-repo/grantAgreement/" + project.project.funderShortname + "/" + project.project.fundingLevel0 + "/" + project.project.code + "/" + project.project.jurisdiction + "/" + project.title + "/" + project.project.acronym);
} else if (results[i].context) { } else if (results[i].context) {

View File

@ -67,18 +67,19 @@
[results]="results" [sources]="sources" [results]="results" [sources]="sources"
[localStoragePrefix]="localStoragePrefix" [inlineEntity]="inlineEntity" [localStoragePrefix]="localStoragePrefix" [inlineEntity]="inlineEntity"
[showOptions]="showOptions" [properties]=properties [pageContents]="pageContents" [showOptions]="showOptions" [properties]=properties [pageContents]="pageContents"
[defaultColors]="!communityId" [communityId]="communityId" [defaultColors]="!communityId" [communityId]="communityId" [claimsProperties]="claimsProperties"
> >
</metadata-preview> </metadata-preview>
<div id="tm-main" class="uk-section uk-padding-remove-top" *ngIf="showOptions.show != 'claim'"> <div id="tm-main" class="uk-section uk-padding-remove-top" *ngIf="showOptions.show != 'claim'">
<div> <div>
<schema2jsonld *ngIf="url" [URL]="url" name="Link your {{openaireEntities.RESULTS}}" type="other"></schema2jsonld> <schema2jsonld *ngIf="url" [URL]="url" name="Link your {{openaireEntities.RESULTS}}" type="other"></schema2jsonld>
<div class="uk-container uk-container-large"> <div class="uk-container uk-container-large">
<div *ngIf="properties" class="uk-section uk-padding-remove-top"> <div *ngIf="properties && claimsProperties" class="uk-section uk-padding-remove-top">
<div class="uk-container uk-container-large"> <div class="uk-container uk-container-large">
<div class="uk-grid basketContainer" *ngIf="showOptions.show!='claim'" uk-grid> <div class="uk-grid basketContainer" *ngIf="showOptions.show!='claim'" uk-grid>
<div class="uk-width-2-3@m uk-position-z-index uk-flex-first@m uk-flex-last uk-margin-medium-top"> <div class="uk-width-2-3@m uk-position-z-index uk-flex-first@m uk-flex-last uk-margin-medium-top">
<h2 *ngIf="inlineEntity" class="uk-text-center">Link source to</h2> <h2 *ngIf="inlineEntity && claimsProperties.INLINE_ENTITY.show" class="uk-text-center">Link source to</h2>
<div *ngIf="inlineEntity && claimsProperties.INLINE_ENTITY.guideText" class="uk-text-center">{{claimsProperties.INLINE_ENTITY.guideText}}</div>
<div *ngIf="showOptions.show=='source'"> <div *ngIf="showOptions.show=='source'">
<claim-result-search-form [selectedResults]="sources" [properties]=properties <claim-result-search-form [selectedResults]="sources" [properties]=properties
[localStoragePrefix]="localStoragePrefix+'sources'" [localStoragePrefix]="localStoragePrefix+'sources'"
@ -115,16 +116,16 @@
<div class="uk-card-body uk-padding-small"> <div class="uk-card-body uk-padding-small">
<div> <div>
<ng-container *ngIf="inlineEntity"> <ng-container *ngIf="inlineEntity">
<div class="uk-margin-small-bottom"> <div *ngIf="claimsProperties.INLINE_ENTITY.show" class="uk-margin-small-bottom">
<div class="uk-text-emphasis uk-text-bolder">Source</div> <div class="uk-text-emphasis uk-text-bolder">{{claimsProperties.BASKET.source_title}}</div>
<claim-selected-results [results]="[inlineEntity]" <claim-selected-results [results]="[inlineEntity]"
[localStoragePrefix]="localStoragePrefix+'sources'" class="" [localStoragePrefix]="localStoragePrefix+'sources'" class=""
[enableRemove]="false" type="source"> [enableRemove]="false" type="source">
</claim-selected-results> </claim-selected-results>
</div> </div>
<div class="uk-padding-small uk-padding-remove-horizontal"><hr class="uk-margin-remove"/></div> <div *ngIf="claimsProperties.INLINE_ENTITY.show" class="uk-padding-small uk-padding-remove-horizontal"><hr class="uk-margin-remove"/></div>
<div class="uk-margin-small-top"> <div class="uk-margin-small-top">
<div class="uk-text-emphasis uk-text-bolder">Link source to <span *ngIf="results.length> 0">({{(results.length) | number}})</span></div> <div class="uk-text-emphasis uk-text-bolder">{{claimsProperties.BASKET.target_title}} <span *ngIf="results.length> 0">({{(results.length) | number}})</span></div>
<ng-container *ngTemplateOutlet="destinations_basket"></ng-container> <ng-container *ngTemplateOutlet="destinations_basket"></ng-container>
</div> </div>
</ng-container> </ng-container>

View File

@ -18,6 +18,7 @@ import {RouterHelper} from "../../utils/routerHelper.class";
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import {LoginErrorCodes} from "../../login/utils/guardHelper.class"; import {LoginErrorCodes} from "../../login/utils/guardHelper.class";
import {UserManagementService} from "../../services/user-management.service"; import {UserManagementService} from "../../services/user-management.service";
import {ClaimsProperties} from "../claim-utils/claims.properties";
@Component({ @Component({
selector: 'linking-generic', selector: 'linking-generic',
@ -41,7 +42,7 @@ export class LinkingGenericComponent {
// show linkToEntities /values: result, project, context // show linkToEntities /values: result, project, context
@Input() sources:ClaimEntity[] =[]; @Input() sources:ClaimEntity[] =[];
properties:EnvProperties; properties:EnvProperties = properties;
public openaireEntities = OpenaireEntities; public openaireEntities = OpenaireEntities;
@Input() localStoragePrefix:string = "linking_"; @Input() localStoragePrefix:string = "linking_";
url=null; url=null;
@ -49,7 +50,7 @@ export class LinkingGenericComponent {
public pageContents = null; public pageContents = null;
@Input() breadcrumbs: Breadcrumb[] = []; @Input() breadcrumbs: Breadcrumb[] = [];
public routerHelper: RouterHelper = new RouterHelper(); public routerHelper: RouterHelper = new RouterHelper();
@Input() claimsProperties:ClaimsProperties = new ClaimsProperties();
constructor (private _router: Router, private route: ActivatedRoute, private entitySearch:EntitiesSearchService, constructor (private _router: Router, private route: ActivatedRoute, private entitySearch:EntitiesSearchService,
private _meta: Meta, private _title: Title, private _piwikService:PiwikService, private _meta: Meta, private _title: Title, private _piwikService:PiwikService,
private seoService: SEOService, private helper: HelperService, private cdr: ChangeDetectorRef, private seoService: SEOService, private helper: HelperService, private cdr: ChangeDetectorRef,
@ -58,6 +59,9 @@ export class LinkingGenericComponent {
subscriptions = []; subscriptions = [];
ngOnInit() { ngOnInit() {
/* if(!this.claimsProperties){
this.claimsProperties = new ClaimsProperties();
}*/
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
if (!user) { if (!user) {
this.saveStateAndRedirectLogin(); this.saveStateAndRedirectLogin();
@ -68,14 +72,13 @@ export class LinkingGenericComponent {
this.breadcrumbs.push({name: "Link", route: null}); this.breadcrumbs.push({name: "Link", route: null});
} }
this.showOptions.show = 'source'; this.showOptions.show = 'source';
this.showOptions.initSelectOptions(); this.showOptions.initSelectOptions(this.claimsProperties);
if(this.inlineEntity){ if(this.inlineEntity){
this.showOptions.showLinkTo(); this.showOptions.showLinkTo();
// this.showOptions.basketShowLinksTo = true; // this.showOptions.basketShowLinksTo = true;
this.showOptions.show = this.showOptions.linkTo; this.showOptions.show = this.showOptions.linkTo;
} }
this.properties = properties;
this.url = this.properties.domain + this.properties.baseLink+this._router.url; this.url = this.properties.domain + this.properties.baseLink+this._router.url;
var description = "Linking is a functionality provided by OpenAIRE, in order to link research results with a project, a research community or other research results."; var description = "Linking is a functionality provided by OpenAIRE, in order to link research results with a project, a research community or other research results.";

View File

@ -3,13 +3,21 @@ import {SharedModule} from '../../../../openaireLibrary/shared/shared.module';
import {ClaimEntityTitleComponent} from "./ClaimEntityTitle.component"; import {ClaimEntityTitleComponent} from "./ClaimEntityTitle.component";
import {ClaimEntityResultMetadataComponent} from "./ClaimEntityResultMetadata.component"; import {ClaimEntityResultMetadataComponent} from "./ClaimEntityResultMetadata.component";
import {ClaimEntityProjectMetadataComponent} from "./ClaimEntityProjectMetadata.component"; import {ClaimEntityProjectMetadataComponent} from "./ClaimEntityProjectMetadata.component";
import {IconsService} from "../../../utils/icons/icons.service";
import {coins} from "../../../utils/icons/icons";
import {IconsModule} from "../../../utils/icons/icons.module";
@NgModule({ @NgModule({
imports: [ imports: [
SharedModule SharedModule,
IconsModule
], ],
declarations: [ declarations: [
ClaimEntityTitleComponent, ClaimEntityResultMetadataComponent, ClaimEntityProjectMetadataComponent ClaimEntityTitleComponent, ClaimEntityResultMetadataComponent, ClaimEntityProjectMetadataComponent
], exports:[ ClaimEntityTitleComponent, ClaimEntityResultMetadataComponent, ClaimEntityProjectMetadataComponent] ], exports:[ ClaimEntityTitleComponent, ClaimEntityResultMetadataComponent, ClaimEntityProjectMetadataComponent]
}) })
export class ClaimEntitiesMetadataModule { } export class ClaimEntitiesMetadataModule {
constructor(private _iconsService:IconsService) {
this._iconsService.registerIcons([coins])
}
}

View File

@ -8,20 +8,28 @@ import {ClaimEntity} from '../../claim-utils/claimHelper.class';
<div *ngIf="!shortVersion" class="claim-entity-metadata uk-flex-inline uk-flex-wrap uk-text-xsmall uk-text-emphasis" <div *ngIf="!shortVersion" class="claim-entity-metadata uk-flex-inline uk-flex-wrap uk-text-xsmall uk-text-emphasis"
[class.uk-margin-xsmall-top]="!shortVersion"> [class.uk-margin-xsmall-top]="!shortVersion">
<span class="uk-text-capitalize"> <span class="uk-text-capitalize">
{{entity.type}} {{entity.type == 'project' && entity.project.code == 'unidentified'?'funder':entity.type}}
</span> </span>
<span *ngIf="entity.project.startDate || entity.project.endDate"> <span *ngIf="entity.project.startDate || entity.project.endDate">
{{(entity.project.startDate) ? entity.project.startDate : 'Unknown'}}{{'-' + ((entity.project.endDate) ? entity.project.endDate : 'Unknown')}} {{(entity.project.startDate) ? entity.project.startDate : 'Unknown'}}{{'-' + ((entity.project.endDate) ? entity.project.endDate : 'Unknown')}}
</span> </span>
</div> </div>
<div class="uk-text-small uk-flex uk-flex-wrap" [style.grid-gap]="shortVersion?'10px':'20px'" <div *ngIf="shortVersion && entity.type == 'project' && entity.project.code == 'unidentified'" class="claim-entity-metadata uk-flex-inline uk-flex-wrap uk-text-xsmall uk-text-emphasis"
[class.uk-margin-xsmall-top]="!shortVersion">
<span class="uk-text-capitalize">
funder
</span>
</div>
<div *ngIf="entity.project.code!='unidentified'" class="uk-text-small uk-flex uk-flex-wrap" [style.grid-gap]="shortVersion?'0px':'10px'"
[class.uk-margin-small-top]="!shortVersion"> [class.uk-margin-small-top]="!shortVersion">
<div *ngIf="entity.project.funderName">
<span class="uk-text-meta">Funder: </span>{{entity.project.funderName}}
</div>
<div *ngIf="entity.project.code"> <div *ngIf="entity.project.code">
<span class="uk-text-meta">Project Code: </span>{{entity.project.code}} <span class="uk-text-meta">Project Code: </span>{{entity.project.code}}
</div> </div>
<div *ngIf="entity.project.funderName || entity.project.funderShortname">
<span class="uk-text-meta">Funding: </span>{{entity.project.funderName?entity.project.funderName:entity.project.funderShortname}}
</div>
</div> </div>
</ng-container> </ng-container>
`, `,

View File

@ -5,16 +5,18 @@ import {ClaimEntity} from '../../claim-utils/claimHelper.class';
selector: 'claim-title', selector: 'claim-title',
template: ` template: `
<div class="uk-grid uk-flex uk-flex-middle"> <div class="uk-grid uk-flex uk-flex-middle">
<span *ngIf="showIcon" class="uk-flex"> <span *ngIf="showIcon" class="uk-flex uk-margin-xsmall-right">
<span *ngIf="entity.result" class="material-icons uk-text-small uk-text-meta"> <icon *ngIf="entity.result" class=" uk-text-small uk-text-meta" name="insert_drive_file">
insert_drive_file
</span> </icon>
<span *ngIf="entity.project" class="material-icons uk-text-small uk-text-meta"> <icon *ngIf="entity.project && entity.project.code !='unidentified'" class=" uk-text-small uk-text-meta" name="assignment_turned_in">
assignment_turned_in </icon>
</span> <icon *ngIf="entity.project && entity.project.code =='unidentified'" class="uk-text-small uk-text-meta" name="coins" [ratio]="1.4">
<span *ngIf="entity.type=='community'" class="material-icons uk-text-small uk-text-meta" style="margin-right: 2px;"> </icon>
people <icon *ngIf="entity.organization" class=" uk-text-small uk-text-meta" name="account_balance">
</span> </icon>
<icon *ngIf="entity.type=='community'" class=" uk-text-small uk-text-meta" style="margin-right: 2px;" name="people">
</icon>
</span> </span>
<div class="uk-width-expand multi-line-ellipsis lines-3" style="word-break: break-word;" <div class="uk-width-expand multi-line-ellipsis lines-3" style="word-break: break-word;"
[class.uk-padding-remove-left]="showIcon" [class.uk-text-truncate]="shortVersion"> [class.uk-padding-remove-left]="showIcon" [class.uk-text-truncate]="shortVersion">
@ -27,7 +29,15 @@ import {ClaimEntity} from '../../claim-utils/claimHelper.class';
<span *ngIf="(entity.result && !entity.result.url)"> <span *ngIf="(entity.result && !entity.result.url)">
{{entity.title ? sliceString(entity.title) : '[No title available]'}} {{entity.title ? sliceString(entity.title) : '[No title available]'}}
</span> </span>
<span *ngIf="entity.type=='project' && entity.project"> <span *ngIf="entity.type=='project' && entity.project && entity.project.code =='unidentified'">
<span *ngIf="!shortVersion">
{{(entity.project.funderShortname ? '[' + entity.project.funderShortname + '] ' : '') + entity.project.funderName}}
</span>
<span *ngIf="shortVersion">
{{sliceString(entity.project.funderName)}}
</span>
</span>
<span *ngIf="entity.type=='project' && entity.project && entity.project.code!='unidentified'">
<a *ngIf="entity.project && entity.project.url" target="_blank" [href]="entity.project.url" <a *ngIf="entity.project && entity.project.url" target="_blank" [href]="entity.project.url"
class="uk-link uk-text-decoration-none uk-width-expand"> class="uk-link uk-text-decoration-none uk-width-expand">
<span *ngIf="!shortVersion"> <span *ngIf="!shortVersion">
@ -46,6 +56,9 @@ import {ClaimEntity} from '../../claim-utils/claimHelper.class';
</span> </span>
</span> </span>
</span> </span>
<span *ngIf="entity.type=='organization' && entity.organization">
{{sliceString(entity.title)}}
</span>
<span *ngIf="entity.type=='community' && entity.context"> <span *ngIf="entity.type=='community' && entity.context">
<span *ngIf=" entity.context.community != entity.context.concept.label"> <span *ngIf=" entity.context.community != entity.context.concept.label">
{{entity.context.community }} > {{entity.context.category}} > {{entity.context.community }} > {{entity.context.category}} >

View File

@ -6,15 +6,14 @@
<div class="uk-width-expand"> <div class="uk-width-expand">
<div class="uk-card uk-card-default"> <div class="uk-card uk-card-default">
<div class="uk-card-body"> <div class="uk-card-body">
<div class="uk-grid uk-grid-divider uk-child-width-1-2@m uk-child-width-1-1@s" uk-grid> <div class="uk-grid uk-grid-divider uk-child-width-1-1@s" uk-grid [class.uk-child-width-1-2@m] = "claimsProperties.INLINE_ENTITY.show" >
<!-- Sources--> <!-- Sources-->
<div> <div *ngIf="claimsProperties.INLINE_ENTITY.show">
<div class=" uk-margin uk-animation-toggle"> <div class=" uk-margin uk-animation-toggle">
<span class="uk-h6 "> SOURCES ({{sources.length + (inlineEntity ? 1 : 0) | number}}) <span class="uk-h6 "> {{claimsProperties.METADATA_PREVIEW.source_title}} ({{sources.length + (inlineEntity ? 1 : 0) | number}})
</span> </span>
<a *ngIf="!inlineEntity" class="uk-float-right uk-text-small" (click)="showOptions.showSource() "> <span <a *ngIf="!inlineEntity" class="uk-float-right uk-text-small" (click)="showOptions.showSource() "> <span
uk-icon="pencil" class="uk-margin-xsmall-right"></span>Edit uk-icon="pencil" class="uk-margin-xsmall-right"></span>{{claimsProperties.METADATA_PREVIEW.edit_source_title}}</a>
sources</a>
</div> </div>
<ul *ngIf="inlineEntity" class="uk-list uk-animation-fade uk-list-divider"> <ul *ngIf="inlineEntity" class="uk-list uk-animation-fade uk-list-divider">
<li> <li>
@ -153,13 +152,15 @@
</div> </div>
<!-- Results--> <!-- Results-->
<div class=" "> <div class=" ">
<div class=" uk-margin "> <div class=" uk-margin uk-grid">
<span class=" uk-h6 "> LINK TO ({{results.length | number}})</span> <span class=" uk-h6 uk-width-expand"> {{claimsProperties.METADATA_PREVIEW.target_title}} ({{results.length | number}})</span>
<div class="uk-width-auto uk-flex">
<a class="uk-float-right uk-text-small" (click)="showOptions.showLinkTo()"> <span <icon [name]="claimsProperties.METADATA_PREVIEW.edit_target_icon" [flex]="true"></icon>
uk-icon="pencil" class="uk-margin-xsmall-right"></span>Edit <a class=" uk-margin-left-xsmall uk-text-small" (click)="showOptions.showLinkTo()">
entities</a> {{claimsProperties.METADATA_PREVIEW.edit_target_title}}</a>
</div>
</div> </div>
<div *ngIf="results.length == 0"> <div *ngIf="results.length == 0">
<div class="uk-alert dangerBorder no-selected-message uk-text-center"> <div class="uk-alert dangerBorder no-selected-message uk-text-center">

View File

@ -4,6 +4,7 @@ import {ClaimEntity, ClaimsErrorMessage, Message, ShowOptions} from '../../claim
import {EnvProperties} from "../../../utils/properties/env-properties"; import {EnvProperties} from "../../../utils/properties/env-properties";
import {Dates} from "../../../utils/string-utils.class"; import {Dates} from "../../../utils/string-utils.class";
import {HelperFunctions} from "../../../utils/HelperFunctions.class"; import {HelperFunctions} from "../../../utils/HelperFunctions.class";
import {ClaimsProperties} from "../../claim-utils/claims.properties";
@Component({ @Component({
selector: 'metadata-preview', selector: 'metadata-preview',
@ -28,6 +29,7 @@ export class MetadataPreviewComponent {
@ViewChild(AlertModal) alertApplyAll; @ViewChild(AlertModal) alertApplyAll;
@Input() localStoragePrefix: string = ""; @Input() localStoragePrefix: string = "";
@Input() communityId:string= null; @Input() communityId:string= null;
@Input() claimsProperties:ClaimsProperties;
errors:ClaimsErrorMessage[] = []; errors:ClaimsErrorMessage[] = [];
warnings:Message[] = []; warnings:Message[] = [];
public commonAccessRights = "OPEN"; // for access rights- changes when user apply a change to every entity public commonAccessRights = "OPEN"; // for access rights- changes when user apply a change to every entity

View File

@ -11,16 +11,17 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import {HelperModule} from "../../../utils/helper/helper.module"; import {HelperModule} from "../../../utils/helper/helper.module";
import {SelectedPublicationsModule} from "./selectedResults.module"; import {SelectedPublicationsModule} from "./selectedResults.module";
import {IconsModule} from "../../../utils/icons/icons.module";
@NgModule({ @NgModule({
imports: [ imports: [
SharedModule, SharedModule,
AlertModalModule, AlertModalModule,
ClaimEntitiesMetadataModule, ClaimEntitiesMetadataModule,
InsertClaimsModule, InsertClaimsModule,
MatDatepickerModule, MatNativeDateModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatDatepickerModule, MatNativeDateModule, MatFormFieldModule, MatInputModule, MatSelectModule,
HelperModule, SelectedPublicationsModule HelperModule, SelectedPublicationsModule, IconsModule
], ],
declarations: [MetadataPreviewComponent], declarations: [MetadataPreviewComponent],
exports:[MetadataPreviewComponent] exports:[MetadataPreviewComponent]
}) })

View File

@ -8,26 +8,26 @@
<div class="uk-flex uk-flex-left@m uk-flex-center uk-width-expand"> <div class="uk-flex uk-flex-left@m uk-flex-center uk-width-expand">
<ul class="uk-subnav uk-subnav-pill"> <ul class="uk-subnav uk-subnav-pill">
<li [class.uk-active]="showCurrent" (click)="showCurrent = true"> <li [class.uk-active]="showCurrent" (click)="showCurrent = true">
<a class="uk-text-capitalize">{{role}}s</a> <a class="uk-text-capitalize">{{stakeholderUtils.roles[role]}}s</a>
</li> </li>
<li [class.uk-active]="!showCurrent" (click)="showCurrent = false"> <li [class.uk-active]="!showCurrent" (click)="showCurrent = false">
<a>Pending {{role}}s</a> <a>Pending {{stakeholderUtils.roles[role]}}s</a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="uk-width-expand@m uk-width-1-1 uk-grid uk-flex-right@m uk-flex-center uk-flex-middle" uk-grid> <div class="uk-width-expand@m uk-width-1-1 uk-grid uk-flex-right@m uk-flex-center uk-flex-middle" uk-grid>
<div *ngIf="showCurrent" [disabled]="loadActive" search-input class="uk-width-expand@l uk-width-1-1" <div *ngIf="showCurrent" [disabled]="loadActive" search-input class="uk-width-expand@l uk-width-1-1"
[searchControl]="filterForm.get('active')" [expandable]="true" [placeholder]="'Search ' + role + 's'" searchInputClass="outer"> [searchControl]="filterForm.get('active')" [expandable]="true" [placeholder]="'Search ' + stakeholderUtils.roles[role] + 's'" searchInputClass="outer">
</div> </div>
<div *ngIf="!showCurrent" [disabled]="loadPending" search-input class="uk-width-expand@l uk-width-1-1" <div *ngIf="!showCurrent" [disabled]="loadPending" search-input class="uk-width-expand@l uk-width-1-1"
[searchControl]="filterForm.get('pending')" [expandable]="true" [placeholder]="'Search invitations'" searchInputClass="outer"> [searchControl]="filterForm.get('pending')" [expandable]="true" [placeholder]="'Search invitations'" searchInputClass="outer">
</div> </div>
<div> <div>
<button *ngIf="exists" class="uk-button uk-button-default uk-flex uk-flex-middle" <button *ngIf="canInvite" class="uk-button uk-button-default uk-flex uk-flex-middle"
[attr.uk-tooltip]="inviteDisableMessage" [class.uk-disabled]="loadPending || loadPending" [attr.uk-tooltip]="inviteDisableMessage" [class.uk-disabled]="loadPending || loadPending"
[disabled]="loadActive || loadPending || !!inviteDisableMessage" (click)="openInviteModal()"> [disabled]="loadActive || loadPending || !!inviteDisableMessage" (click)="openInviteModal()">
<icon name="person_add" [flex]="true" type="filled"></icon> <icon name="person_add" [flex]="true" type="filled"></icon>
<span class="uk-margin-small-left uk-text-bold uk-text-uppercase">Invite {{role}}</span> <span class="uk-margin-small-left uk-text-bold uk-text-uppercase">Invite {{stakeholderUtils.roles[role]}}</span>
</button> </button>
<button *ngIf="!exists && isCurator" class="uk-button uk-button-default uk-flex uk-flex-middle" <button *ngIf="!exists && isCurator" class="uk-button uk-button-default uk-flex uk-flex-middle"
(click)="openCreateRoleModal()"> (click)="openCreateRoleModal()">
@ -47,16 +47,16 @@
<div *ngIf="!loadActive && !loadPending"> <div *ngIf="!loadActive && !loadPending">
<div *ngIf="(showCurrent && showActive.length == 0) || (!showCurrent && showPending.length == 0)" <div *ngIf="(showCurrent && showActive.length == 0) || (!showCurrent && showPending.length == 0)"
class="uk-card uk-card-default uk-padding-large uk-text-center uk-margin-bottom uk-text-bold"> class="uk-card uk-card-default uk-padding-large uk-text-center uk-margin-bottom uk-text-bold">
<div *ngIf="showCurrent">No {{role}}s found</div> <div *ngIf="showCurrent">No {{stakeholderUtils.roles[role]}}s found</div>
<div *ngIf="!showCurrent">No pending {{role}} invitations found</div> <div *ngIf="!showCurrent">No pending {{stakeholderUtils.roles[role]}} invitations found</div>
</div> </div>
<div *ngIf="(showCurrent && showActive.length > 0) || (!showCurrent && showPending.length > 0)"> <div *ngIf="(showCurrent && showActive.length > 0) || (!showCurrent && showPending.length > 0)">
<no-load-paging *ngIf="showCurrent" [type]="(showActive.length > 1)?(role + 's'):role" <no-load-paging *ngIf="showCurrent" [type]="(showActive.length > 1)?(stakeholderUtils.roles[role] + 's'):role"
(pageChange)="updateActivePage($event)" (pageChange)="updateActivePage($event)"
[page]="activePage" [pageSize]="pageSize" [page]="activePage" [pageSize]="pageSize"
[totalResults]="showActive.length"> [totalResults]="showActive.length">
</no-load-paging> </no-load-paging>
<no-load-paging *ngIf="!showCurrent" [type]="role + ' ' + (showPending.length > 1?'invitations':'invitation')" <no-load-paging *ngIf="!showCurrent" [type]="stakeholderUtils.roles[role] + ' ' + (showPending.length > 1?'invitations':'invitation')"
(pageChange)="updatePendingPage($event)" (pageChange)="updatePendingPage($event)"
[page]="pendingPage" [pageSize]="pageSize" [page]="pendingPage" [pageSize]="pageSize"
[totalResults]="showPending.length"> [totalResults]="showPending.length">
@ -109,12 +109,12 @@
</modal-alert> </modal-alert>
<modal-alert #deleteModal [overflowBody]="false" (alertOutput)="deleteActive()" classTitle="uk-background-primary uk-light"> <modal-alert #deleteModal [overflowBody]="false" (alertOutput)="deleteActive()" classTitle="uk-background-primary uk-light">
<div *ngIf="selectedUser"> <div *ngIf="selectedUser">
Are you sure you want to remove <span class="uk-text-bold">{{selectedUser}}</span> from {{role}}s? Are you sure you want to remove <span class="uk-text-bold">{{selectedUser}}</span> from {{stakeholderUtils.roles[role]}}s?
</div> </div>
</modal-alert> </modal-alert>
<modal-alert #deletePendingModal [overflowBody]="false" (alertOutput)="deletePending()" classTitle="uk-background-primary uk-light"> <modal-alert #deletePendingModal [overflowBody]="false" (alertOutput)="deletePending()" classTitle="uk-background-primary uk-light">
<div *ngIf="selectedUser"> <div *ngIf="selectedUser">
Are you sure you want to cancel {{role}} invitation of <span class="uk-text-bold">{{selectedUser}}</span>? Are you sure you want to cancel {{stakeholderUtils.roles[role]}} invitation of <span class="uk-text-bold">{{selectedUser}}</span>?
</div> </div>
</modal-alert> </modal-alert>
<modal-alert #createRoleModal [overflowBody]="false" (alertOutput)="createGroup()" classTitle="uk-background-primary uk-light" <modal-alert #createRoleModal [overflowBody]="false" (alertOutput)="createGroup()" classTitle="uk-background-primary uk-light"

View File

@ -23,6 +23,7 @@ import {NotificationHandler} from "../../../utils/notification-handler";
import {ClearCacheService} from "../../../services/clear-cache.service"; import {ClearCacheService} from "../../../services/clear-cache.service";
import {catchError, map, tap} from "rxjs/operators"; import {catchError, map, tap} from "rxjs/operators";
import {InputComponent} from "../../../sharedComponents/input/input.component"; import {InputComponent} from "../../../sharedComponents/input/input.component";
import {StakeholderUtils} from "../../../monitor-admin/utils/indicator-utils";
class InvitationResponse { class InvitationResponse {
email: string; email: string;
@ -43,7 +44,9 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
@Input() @Input()
public id: string; public id: string;
@Input() @Input()
public type: string; set type(type: string) {
this._type = Role.mapType(type);
}
@Input() @Input()
public name: string; public name: string;
@Input() @Input()
@ -53,6 +56,8 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
@Input() @Input()
public deleteAuthorizationLevel: 'curator' | 'manager' = 'curator'; public deleteAuthorizationLevel: 'curator' | 'manager' = 'curator';
@Input() @Input()
public inviteAuthorizationLevel: 'curator' | 'manager' = 'manager';
@Input()
public message: string = null; public message: string = null;
@Input() @Input()
public emailComposer: Function; public emailComposer: Function;
@ -86,12 +91,13 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
@ViewChild('deleteModal') deleteModal: AlertModal; @ViewChild('deleteModal') deleteModal: AlertModal;
@ViewChild('deletePendingModal') deletePendingModal: AlertModal; @ViewChild('deletePendingModal') deletePendingModal: AlertModal;
@ViewChild('createRoleModal') createRoleModal: AlertModal; @ViewChild('createRoleModal') createRoleModal: AlertModal;
public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
private _type: string;
constructor(private userRegistryService: UserRegistryService, constructor(private userRegistryService: UserRegistryService,
private userManagementService: UserManagementService, private userManagementService: UserManagementService,
private clearCacheService: ClearCacheService, private clearCacheService: ClearCacheService,
private notificationService: NotificationService, private notificationService: NotificationService,
private router: Router,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
private fb: UntypedFormBuilder) { private fb: UntypedFormBuilder) {
} }
@ -140,7 +146,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
updateLists() { updateLists() {
this.loadActive = true; this.loadActive = true;
this.loadPending = true; this.loadPending = true;
this.subs.push(this.userRegistryService.getActive(this.type, this.id, this.role, true).subscribe(users => { this.subs.push(this.userRegistryService.getActive(this._type, this.id, this.role, true).subscribe(users => {
this.active = users; this.active = users;
this.filterActiveBySearch(this.filterForm.value.active); this.filterActiveBySearch(this.filterForm.value.active);
this.loadActive = false; this.loadActive = false;
@ -153,7 +159,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
} }
this.loadActive = false; this.loadActive = false;
})); }));
this.subs.push(this.userRegistryService.getPending(this.type, this.id, this.role, true).subscribe(users => { this.subs.push(this.userRegistryService.getPending(this._type, this.id, this.role, true).subscribe(users => {
this.pending = users; this.pending = users;
this.filterPendingBySearch(this.filterForm.value.pending); this.filterPendingBySearch(this.filterForm.value.pending);
this.loadPending = false; this.loadPending = false;
@ -182,7 +188,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
openDeleteModal(item: any) { openDeleteModal(item: any) {
if (this.showCurrent) { if (this.showCurrent) {
this.selectedUser = item.email; this.selectedUser = item.email;
this.deleteModal.alertTitle = 'Delete ' + this.role; this.deleteModal.alertTitle = 'Delete ' + this.stakeholderUtils.roles[this.role];
this.deleteModal.open(); this.deleteModal.open();
} else { } else {
this.selectedUser = item; this.selectedUser = item;
@ -192,7 +198,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
} }
openInviteModal() { openInviteModal() {
this.inviteModal.alertTitle = 'Invite ' + this.role; this.inviteModal.alertTitle = 'Invite ' + this.stakeholderUtils.roles[this.role];
this.inviteModal.okButtonLeft = false; this.inviteModal.okButtonLeft = false;
this.inviteModal.okButtonText = 'Send'; this.inviteModal.okButtonText = 'Send';
this.emailsForm = this.fb.array([], Validators.required); this.emailsForm = this.fb.array([], Validators.required);
@ -205,8 +211,8 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
this.createRoleModal.okButtonLeft = false; this.createRoleModal.okButtonLeft = false;
this.createRoleModal.okButtonText = 'Create'; this.createRoleModal.okButtonText = 'Create';
this.roleFb = this.fb.group({ this.roleFb = this.fb.group({
name: this.fb.control(Role.roleName(this.type, this.id), Validators.required), name: this.fb.control(Role.roleName(this._type, this.id), Validators.required),
description: this.fb.control(Role.roleName(this.type, this.id), Validators.required) description: this.fb.control(Role.roleName(this._type, this.id), Validators.required)
}); });
setTimeout(() => { setTimeout(() => {
this.roleFb.get('name').disable(); this.roleFb.get('name').disable();
@ -217,7 +223,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
deleteActive() { deleteActive() {
this.loadActive = true; this.loadActive = true;
this.subs.push(this.userRegistryService.remove(this.type, this.id, this.selectedUser, this.role).subscribe(() => { this.subs.push(this.userRegistryService.remove(this._type, this.id, this.selectedUser, this.role).subscribe(() => {
this.active = this.active.filter(user => user.email != this.selectedUser); this.active = this.active.filter(user => user.email != this.selectedUser);
if (this.currentActivePage.length === 0) { if (this.currentActivePage.length === 0) {
this.activePage = 1; this.activePage = 1;
@ -235,13 +241,13 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
deletePending() { deletePending() {
this.loadPending = true; this.loadPending = true;
this.subs.push(this.userRegistryService.cancelInvitation(this.type, this.id, this.selectedUser, this.role).subscribe(() => { this.subs.push(this.userRegistryService.cancelInvitation(this._type, this.id, this.selectedUser, this.role).subscribe(() => {
this.pending = this.pending.filter(user => user != this.selectedUser); this.pending = this.pending.filter(user => user != this.selectedUser);
this.filterPendingBySearch(this.filterForm.value.pending); this.filterPendingBySearch(this.filterForm.value.pending);
if (this.currentPendingPage.length === 0) { if (this.currentPendingPage.length === 0) {
this.pendingPage = 1; this.pendingPage = 1;
} }
NotificationHandler.rise(StringUtils.capitalize(this.role) + ' invitation to ' + this.selectedUser + ' has been <b>canceled</b>'); NotificationHandler.rise(StringUtils.capitalize(this.stakeholderUtils.roles[this.role]) + ' invitation to ' + this.selectedUser + ' has been <b>canceled</b>');
this.loadPending = false; this.loadPending = false;
}, error => { }, error => {
NotificationHandler.rise('An error has occurred. Please try again later', 'danger'); NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
@ -262,12 +268,12 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
let current = null; let current = null;
let invitations = (<Array<any>>this.emailsForm.value).map(email => { let invitations = (<Array<any>>this.emailsForm.value).map(email => {
current = email; current = email;
return this.userRegistryService.invite(this.type, this.id, { return this.userRegistryService.invite(this._type, this.id, {
link: this.link, link: this.link,
email: this.emailComposer(this.name, email, this.role) email: this.emailComposer(this.name, email, this.role)
}, this.role).pipe(map(invitation => new InvitationResponse(email, invitation), catchError(error => { }, this.role).pipe(catchError(error => {
return of(new InvitationResponse(current, null)); return of(null);
}))); }), map(invitation => new InvitationResponse(email, invitation)));
}); });
this.subs.push(forkJoin(invitations).subscribe(responses => { this.subs.push(forkJoin(invitations).subscribe(responses => {
let notifications = responses.map(response => { let notifications = responses.map(response => {
@ -289,7 +295,8 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
return of(null); return of(null);
} }
} else { } else {
NotificationHandler.rise('An error has occurred while sending the invitation mail to ' + response.email + '.Please try again later', 'danger'); NotificationHandler.rise('An error has occurred while sending the invitation mail to ' +
response.email + '.Check if the user is already a ' + this.stakeholderUtils.roles[this.role] + ' or try again later', 'danger');
return of(null); return of(null);
} }
}); });
@ -304,12 +311,12 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
createGroup() { createGroup() {
this.loadActive = true; this.loadActive = true;
this.loadPending = true; this.loadPending = true;
this.userRegistryService.createRole(this.type, this.id).subscribe(() => { this.userRegistryService.createRole(this._type, this.id).subscribe(() => {
NotificationHandler.rise('Group has been <b> successfully created</b>'); NotificationHandler.rise('Group has been <b> successfully created</b>');
this.updateLists(); this.updateLists();
}, error => { }, error => {
if(error.status === 409) { if(error.status === 409) {
NotificationHandler.rise('Group already exists. You can try to invite a ' + this.role + ' instead.', 'warning'); NotificationHandler.rise('Group already exists. You can try to invite a ' + this.stakeholderUtils.roles[this.role] + ' instead.', 'warning');
this.updateLists(); this.updateLists();
} else { } else {
NotificationHandler.rise('An error has occurred. Please try again later', 'danger'); NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
@ -322,17 +329,21 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
public get canDelete() { public get canDelete() {
return (this.deleteAuthorizationLevel === 'curator'?this.isCurator:this.isManager); return (this.deleteAuthorizationLevel === 'curator'?this.isCurator:this.isManager);
} }
public get canInvite() {
return this.exists && (this.inviteAuthorizationLevel === 'curator'?this.isCurator:this.isManager);
}
public isMe(userId: string) { public isMe(userId: string) {
return userId && userId.includes(this.user.id) && !this.isCurator; return userId && userId.includes(this.user.id) && !this.isCurator;
} }
public get isManager(): boolean { public get isManager(): boolean {
return this.isCurator || !!Session.isManager(this.type, this.id, this.user); return this.isCurator || !!Session.isManager(this._type, this.id, this.user);
} }
public get isCurator(): boolean { public get isCurator(): boolean {
return this.isPortalAdmin || !!Session.isCurator(this.type, this.user); return this.isPortalAdmin || !!Session.isCurator(this._type, this.user);
} }
public get isPortalAdmin(): boolean { public get isPortalAdmin(): boolean {

View File

@ -32,13 +32,15 @@
</div> </div>
</div> </div>
<div class="uk-width-2-5@m uk-width-1-1@s uk-text-center" uk-scrollspy-class> <div class="uk-width-2-5@m uk-width-1-1@s uk-text-center" uk-scrollspy-class>
<img src="assets/common-assets/fos/fos-hero-img.svg" loading="lazy"> <img src="assets/common-assets/fos/fos-hero-img.svg" loading="lazy" alt="FoS logo">
</div> </div>
</div> </div>
</div> </div>
<div *ngIf="fos?.length" class="uk-container uk-container-large uk-section" uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-slide-bottom-medium; delay: 200">
<div *ngIf="fos?.length" id="levels" class="uk-container uk-container-large uk-section"
uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-slide-bottom-medium; delay: 200">
<div class="uk-visible@m"> <div class="uk-visible@m">
<div uk-sticky="offset: 50;" class="uk-sticky uk-background-default uk-padding uk-padding-remove-bottom uk-padding-remove-horizontal"> <div id="keyword_search" uk-sticky="offset: 50;" class="uk-sticky uk-background-default uk-padding uk-padding-remove-bottom uk-padding-remove-horizontal">
<div class="uk-flex uk-flex-right uk-margin-small-bottom"> <div class="uk-flex uk-flex-right uk-margin-small-bottom">
<div search-input [searchControl]="keywordControl" [options]="fosOptions" iconPosition="left" placeholder="Write a key word to filter the content" <div search-input [searchControl]="keywordControl" [options]="fosOptions" iconPosition="left" placeholder="Write a key word to filter the content"
searchInputClass="border-bottom" class="uk-width-large"></div> searchInputClass="border-bottom" class="uk-width-large"></div>
@ -53,11 +55,29 @@
<ul *ngIf="!keyword" class="uk-tab uk-tab-left"> <ul *ngIf="!keyword" class="uk-tab uk-tab-left">
<li *ngFor="let item of fos; index as i" [class.uk-active]="activeSection === item.id" <li *ngFor="let item of fos; index as i" [class.uk-active]="activeSection === item.id"
class="uk-margin-small-bottom uk-text-capitalize"> class="uk-margin-small-bottom uk-text-capitalize">
<a routerLink="./" [fragment]="item.id">{{item.id}}</a> <a (click)="selectedParentLevels=[]" routerLink="./" [fragment]="item.id">
<div>
{{item.id}}
<ng-container *ngIf="selectedParentLevels.length > 0 && selectedParentLevels[0].id==item.id">
<div class="uk-margin-left uk-margin-xsmall-top">
<span class="uk-flex uk-flex-middle">
<icon [flex]="true" ratio="1" name="subdirectory_arrow_right"></icon>
{{selectedParentLevels[1].id}}
</span>
<div class="uk-margin-left uk-margin-xsmall-top">
<span class="uk-flex uk-flex-middle">
<icon [flex]="true" ratio="1" name="subdirectory_arrow_right"></icon>
{{selectedParentLevels[2].label}}
</span>
</div>
</div>
</ng-container>
</div>
</a>
</li> </li>
</ul> </ul>
<ul *ngIf="keyword?.length" class="uk-tab uk-tab-left"> <ul *ngIf="keyword?.length" class="uk-tab uk-tab-left">
<li *ngFor="let item of viewResults; index as i" <li *ngFor="let item of viewResults; index as i"
class="uk-margin-small-bottom uk-text-capitalize" [class.uk-active]="activeSection === item.id"> class="uk-margin-small-bottom uk-text-capitalize" [class.uk-active]="activeSection === item.id">
<a routerLink="./" [fragment]="item.id">{{item.id}}</a> <a routerLink="./" [fragment]="item.id">{{item.id}}</a>
</li> </li>
@ -91,7 +111,34 @@
</div> </div>
</div> </div>
<div class="uk-width-expand@m"> <div class="uk-width-expand@m">
<ng-container *ngIf="!keyword"> <div *ngIf="!keyword && selectedParentLevels.length > 0" [id]="selectedParentLevels[0].id+'||'+selectedParentLevels[1].code+'||'+selectedParentLevels[2].code">
<a (click)="backClicked();"
class="uk-button-link uk-flex uk-flex-middle uk-margin-bottom">
<icon name="arrow_back" visuallyHidden="back" flex="true" ratio="1"></icon>
<span class="uk-margin-small-left">Back</span>
</a>
<div>
<h2 class="uk-h4 uk-text-capitalize uk-margin-remove">
<a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(selectedParentLevels[2])"
class="uk-link-text">
{{selectedParentLevels[2].label}}
</a>
</h2>
<div class="uk-grid uk-child-width-1-3 uk-margin-large-top uk-margin-xlarge-bottom" uk-grid="masonry: false">
<div *ngFor="let level4 of selectedParentLevels[2].children">
<div class="uk-text-capitalize">
<h3 class="uk-h6 uk-margin-small-bottom">
<a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(level4)"
class="uk-link-text">
{{level4.label}}
</a>
</h3>
</div>
</div>
</div>
</div>
</div>
<ng-container *ngIf="!keyword && selectedParentLevels.length == 0">
<div [id]="item.id" *ngFor="let item of fos; index as i"> <div [id]="item.id" *ngFor="let item of fos; index as i">
<div class="uk-text-capitalize"> <div class="uk-text-capitalize">
<h2 class="uk-h4 uk-margin-remove"> <h2 class="uk-h4 uk-margin-remove">
@ -110,12 +157,51 @@
{{child.id}} {{child.id}}
</a> </a>
</h3> </h3>
<div *ngFor="let subChild of child.children" style="margin-bottom: 5px;"> <!-- class="parent uk-transition-toggle" tabindex="0"-->
<a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(subChild)" <div *ngFor="let subChild of child.children; let i=index" style="margin-bottom: 7px;"
class="uk-link-text"> class="uk-flex uk-flex-middle uk-flex-between uk-transition-toggle" tabindex="0">
{{searchFieldsHelper.getFosParameter() == 'foslabel' ? subChild.label : subChild.id}} <!-- <span class="uk-flex uk-flex-between">-->
</a> <a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(subChild)"
</div> class="uk-link-text uk-width-expand">
{{searchFieldsHelper.getFosParameter() == 'foslabel' ? subChild.label : subChild.id}}
</a>
<span *ngIf="properties.environment == 'development' && subChild.children?.length > 0" (click)="moreClicked(item, child, subChild)"
class="uk-transition-fade uk-width-auto uk-flex uk-flex-middle uk-margin-left label4 uk-text-small uk-text-meta">
<!-- <a class="view-more-less-link uk-link-text uk-text-lowercase">-->
<!-- +{{subChild.children.length}} more-->
<!--&lt;!&ndash; <icon [flex]="true" ratio="1" name="chevron_right"></icon>&ndash;&gt;-->
<!-- </a>-->
<icon [flex]="true" ratio="0.7" name="subdirectory_arrow_right"></icon>
<a class="uk-link-text uk-text-lowercase">
more
</a>
</span>
<!-- <div *ngIf="subChild.children?.length > 0" (click)="selectedParentLevels=[item, child, subChild]"-->
<!-- class="uk-flex uk-flex-middle uk-margin-left label4 uk-text-small uk-text-meta">-->
<!-- <a class="uk-link-text">{{subChild.children.length}} Subcategories</a>-->
<!-- <icon [flex]="true" ratio="1" name="chevron_right"></icon>-->
<!-- </div>-->
<!-- <span *ngIf="subChild?.children?.length > 0" (click)="fosAccordions.set(subChild.id, !fosAccordions.get(subChild.id))" class="uk-accordion-title uk-padding-remove"></span>-->
<!-- </span>-->
<!-- <div *ngIf="fosAccordions.get(subChild.id)" class="uk-margin-left">-->
<!-- <div *ngFor="let level4 of subChild.children" style="margin-bottom: 7px;">-->
<!-- <a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(level4)"-->
<!-- class="label4 uk-text-small uk-text-meta">-->
<!-- {{searchFieldsHelper.getFosParameter() == 'foslabel' ? level4.label : level4.id}}-->
<!-- </a>-->
<!-- </div>-->
<!-- </div>-->
<!-- uk-transition-slide-top-->
<!-- <div *ngIf="subChild.children?.length > 0" class="uk-transition-slide-top">-->
<!-- <div class="child">-->
<!-- <a class="uk-link uk-margin-left">{{subChild.children.length}} Subcategories ></a>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div> </div>
</div> </div>
</div> </div>
@ -137,10 +223,16 @@
class="uk-link-text" [innerHTML]="highlightKeyword(subItem.id)"> class="uk-link-text" [innerHTML]="highlightKeyword(subItem.id)">
</a> </a>
</h3> </h3>
<div *ngFor="let subSubItem of subItem.children" style="margin-bottom: 5px;"> <div *ngFor="let subSubItem of subItem.children" style="margin-bottom: 7px;">
<a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(subSubItem)" <a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(subSubItem)"
class="uk-link-text" [innerHTML]="highlightKeyword(searchFieldsHelper.getFosParameter() == 'foslabel' ? subSubItem.label : subSubItem.id)"> class="uk-link-text" [innerHTML]="highlightKeyword(searchFieldsHelper.getFosParameter() == 'foslabel' ? subSubItem.label : subSubItem.id)">
</a> </a>
<div *ngFor="let level4 of subSubItem?.children" class="uk-margin-left">
<a [routerLink]="properties.searchLinkToResults" [queryParams]="buildFosQueryParam(level4)"
class="uk-text-small uk-text-meta uk-margin-xsmall-bottom" [innerHTML]="highlightKeyword(searchFieldsHelper.getFosParameter() == 'foslabel' ? level4.label : level4.id)">
</a>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -16,6 +16,7 @@ import {debounceTime, distinctUntilChanged} from "rxjs/operators";
import Timeout = NodeJS.Timeout; import Timeout = NodeJS.Timeout;
import {ISVocabulariesService} from "../utils/staticAutoComplete/ISVocabularies.service"; import {ISVocabulariesService} from "../utils/staticAutoComplete/ISVocabularies.service";
import {SearchFields} from "../utils/properties/searchFields"; import {SearchFields} from "../utils/properties/searchFields";
import {HelperFunctions} from "../utils/HelperFunctions.class";
declare var UIkit; declare var UIkit;
@ -28,6 +29,8 @@ export class FosComponent implements OnInit, OnDestroy {
public url: string = null; public url: string = null;
public pageTitle: string = "OpenAIRE | Fields of Science"; public pageTitle: string = "OpenAIRE | Fields of Science";
public pageDescription: string = "We have integrated a Field-of-Science (FoS) taxonomy into our dataset to organize and discover research more effectively. Using the full capabilities of the OpenAIRE Graph (full-texts, citations, references, venues) we apply AI and bring forward any multidisciplinarity potential."; public pageDescription: string = "We have integrated a Field-of-Science (FoS) taxonomy into our dataset to organize and discover research more effectively. Using the full capabilities of the OpenAIRE Graph (full-texts, citations, references, venues) we apply AI and bring forward any multidisciplinarity potential.";
public scrollPos = 0;
public selectedParentLevels = [];
public fos: any[] = []; public fos: any[] = [];
public fosOptions: string[] = []; public fosOptions: string[] = [];
public activeSection: string; public activeSection: string;
@ -82,21 +85,43 @@ export class FosComponent implements OnInit, OnDestroy {
item.classList.remove('uk-active'); item.classList.remove('uk-active');
}); });
if (this.route.snapshot.fragment) { if (this.route.snapshot.fragment) {
this.activeSection = this.route.snapshot.fragment; let splitFragment = this.route.snapshot.fragment.split("||");
let i = this.fos.findIndex(item => item.id == this.route.snapshot.fragment); this.activeSection = this.route.snapshot.fragment.split("||")[0];
slider.show(i); let i = this.fos.findIndex(item => (item.id == this.route.snapshot.fragment || this.route.snapshot.fragment.startsWith(item.id+"||")));
if(i <0 || i>this.fos.length-1) {
this._router.navigate(['./'], {fragment: "", relativeTo: this.route, state: {disableScroll: true}});
} else {
if (splitFragment.length > 1) {
let level1 = this.fos[i];
let level2 = null;
let level3 = null;
if (level1.children) {
level2 = level1.children.find(item => item.code == splitFragment[1]);
if (level2 && level2.children) {
level3 = level2.children.find(item => item.code == splitFragment[2]);
this.selectedParentLevels = [this.fos[i], level2, level3];
}
}
if(!level2 || !level3) {
this._router.navigate(['./'], {fragment: level1.id, relativeTo: this.route, state: {disableScroll: true}});
}
} else {
slider.show(i);
}
}
} else { } else {
this.activeSection = this.fos[0].id; this.activeSection = this.fos[0].id;
} }
this.cdr.detectChanges(); this.cdr.detectChanges();
}); });
} }
this.subscriptions.push(this.route.fragment.subscribe(fragment => { this.subscriptions.push(this.route.fragment.subscribe(fragment => {
if(fragment) { if(fragment) {
this.activeSection = fragment; this.activeSection = fragment.split("||")[0];
if(this.tabs) { if(this.tabs) {
let slider = UIkit.slider(this.tabs.nativeElement); let slider = UIkit.slider(this.tabs.nativeElement);
let i = this.fos.findIndex(item => item.id == fragment); let i = this.fos.findIndex(item => (item.id == fragment || fragment.startsWith(item.id+"||")));
slider.show(i); slider.show(i);
} }
} else { } else {
@ -105,13 +130,16 @@ export class FosComponent implements OnInit, OnDestroy {
})); }));
this.keywordControl = this.fb.control(''); this.keywordControl = this.fb.control('');
this.subscriptions.push(this.keywordControl.valueChanges.pipe(debounceTime(500), distinctUntilChanged()).subscribe(value => { this.subscriptions.push(this.keywordControl.valueChanges.pipe(debounceTime(500), distinctUntilChanged()).subscribe(value => {
this.keyword = value; if(this.keyword !== undefined || value) {
this.findMatches(this.keyword); this.selectedParentLevels = [];
if (typeof IntersectionObserver !== 'undefined') { }
setTimeout(() => { this.keyword = value;
this.setObserver(); this.findMatches(this.keyword);
}); if (typeof IntersectionObserver !== 'undefined') {
} setTimeout(() => {
this.setObserver();
});
}
})); }));
}); });
} }
@ -154,11 +182,16 @@ export class FosComponent implements OnInit, OnDestroy {
this.fos.forEach(fos => { this.fos.forEach(fos => {
this.fosOptions.push(fos.id); this.fosOptions.push(fos.id);
if(fos.children) { if(fos.children) {
fos.children.forEach(child => { fos.children.forEach(l2 => {
this.fosOptions.push(child.id); this.fosOptions.push(l2.id);
if(child.children) { if(l2.children) {
child.children.forEach(child2 => { l2.children.forEach(l3 => {
this.fosOptions.push(child2.id); this.fosOptions.push(l3.id);
if(l3.children) {
l3.children.forEach(l4 => {
this.fosOptions.push(l4.id);
})
}
}); });
} }
}); });
@ -170,19 +203,29 @@ export class FosComponent implements OnInit, OnDestroy {
this.viewResults = JSON.parse(JSON.stringify(this.fos)); this.viewResults = JSON.parse(JSON.stringify(this.fos));
let matchLevel1: boolean = false; let matchLevel1: boolean = false;
let matchLevel2: boolean = false; let matchLevel2: boolean = false;
let matchLevel3: boolean = false;
// 1st level search // 1st level search
if(this.viewResults.length) { if(this.viewResults.length) {
this.viewResults = this.viewResults.filter(item => { this.viewResults = this.viewResults.filter(item => {
matchLevel1 = !!item.id.includes(value?.toLowerCase()); matchLevel1 = !!item.id.includes(value?.toLowerCase());
// // 2nd level search // 2nd level search
if(item.children?.length && !matchLevel1) { if(item.children?.length && !matchLevel1) {
item.children = item.children.filter(subItem => { item.children = item.children.filter(subItem => {
matchLevel2 = !!subItem.id.includes(value?.toLowerCase()); matchLevel2 = !!subItem.id.includes(value?.toLowerCase());
// 3rd level search // 3rd level search
if(subItem.children?.length && !matchLevel2) { if(subItem.children?.length && !matchLevel2) {
subItem.children = subItem.children.filter(subSubItem => subSubItem.id.includes(value?.toLowerCase())); subItem.children = subItem.children.filter(subSubItem => {
matchLevel3 = subSubItem.id.includes(value?.toLowerCase());
// 4th level search
if(subSubItem.children?.length && !matchLevel3) {
subSubItem.children = subSubItem.children.filter(level4Item => {
return level4Item.id.toLowerCase().includes(value?.toLowerCase())
});
}
return subSubItem.children?.length > 0 || matchLevel3;
});
} }
return subItem.children?.length > 0 || matchLevel2; return subItem.children?.length > 0;
}); });
} }
return item.children?.length > 0; return item.children?.length > 0;
@ -191,7 +234,7 @@ export class FosComponent implements OnInit, OnDestroy {
} }
highlightKeyword(name) { highlightKeyword(name) {
if(name.includes(this.keyword.toLowerCase())) { if(name.toLowerCase().includes(this.keyword.toLowerCase())) {
return name.replace(new RegExp(this.keyword, "gi"), (matchedValue) => `<mark class="highlighted">${matchedValue}</mark>`); return name.replace(new RegExp(this.keyword, "gi"), (matchedValue) => `<mark class="highlighted">${matchedValue}</mark>`);
} else { } else {
return name; return name;
@ -221,4 +264,41 @@ export class FosComponent implements OnInit, OnDestroy {
// return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}; // return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)};
return (this.searchFieldsHelper.getFosParameter() == 'foslabel' ? ({'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}) : ({'fos': this.urlEncodeAndQuote(fos.id)})); return (this.searchFieldsHelper.getFosParameter() == 'foslabel' ? ({'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}) : ({'fos': this.urlEncodeAndQuote(fos.id)}));
} }
public backClicked() {
let id = this.selectedParentLevels[0].id;
this.selectedParentLevels=[];
this.cdr.detectChanges();
if(this.scrollPos) {
HelperFunctions.scrollTo(0, this.scrollPos);
this._router.navigate(['./'], {fragment: id, relativeTo: this.route, state: {disableScroll: true}});
} else {
this._router.navigate(['./'], {
fragment: id,
relativeTo: this.route,
state: {disableScroll: false, behavior: 'auto'}
});
}
this.cdr.detectChanges();
if (typeof IntersectionObserver !== 'undefined') {
setTimeout(() => {
this.setObserver();
}, 200);
}
}
public moreClicked(level1, level2, level3) {
this.scrollPos = window.scrollY;
if(this.observer) {
this.observer.disconnect();
}
this.selectedParentLevels=[level1, level2, level3];
this.cdr.detectChanges();
this._router.navigate(['./'],
{fragment: this.selectedParentLevels[0].id+"||"+this.selectedParentLevels[1].code+"||"+this.selectedParentLevels[2].code,
relativeTo: this.route, state: {disableScroll: false, behavior: 'auto'}});
}
} }

View File

@ -33,8 +33,9 @@ import {RouterHelper} from "../../utils/routerHelper.class";
</a> </a>
</div> </div>
<div *ngIf="properties.environment != 'production' && isMobile && (usedBy == 'landing') && availableOn[0].fulltext" class="uk-width-1-1"><hr></div><div *ngIf="availableOn[0].downloadUrl" [ngClass]="isMobile ? 'uk-width-1-1' : ''"> <div *ngIf="isMobile && (usedBy == 'landing') && availableOn[0].fulltext" class="uk-width-1-1"><hr></div>
<div class="uk-flex uk-flex-middle" [ngClass]="isMobile ? ((usedBy == 'landing') ? 'uk-padding-small uk-padding-remove-horizontal' : '') : ''"> <div *ngIf="availableOn[0].downloadUrl" [ngClass]="isMobile ? 'uk-width-1-1' : ''">
<div class="uk-flex uk-flex-middle" [ngClass]="isMobile ? ((usedBy == 'landing') ? 'uk-padding-small uk-padding-remove-horizontal' : '') : ''">
<span [class]="'uk-margin-xsmall-right ' + (availableOn[0].accessRightIcon == 'open_access' ? 'open-access' : 'closed-access')" <span [class]="'uk-margin-xsmall-right ' + (availableOn[0].accessRightIcon == 'open_access' ? 'open-access' : 'closed-access')"
uk-tooltip [title]="getAccessLabel(availableOn[0].accessRight)"> uk-tooltip [title]="getAccessLabel(availableOn[0].accessRight)">
<icon [name]="availableOn[0].accessRightIcon" [flex]="true" [ratio]="(isMobile && usedBy == 'landing') ? 1 : 0.8"></icon> <icon [name]="availableOn[0].accessRightIcon" [flex]="true" [ratio]="(isMobile && usedBy == 'landing') ? 1 : 0.8"></icon>

View File

@ -89,7 +89,7 @@ import {RouterHelper} from "../../utils/routerHelper.class";
</ng-container> </ng-container>
</span> </span>
<ng-container *ngIf="status"> <ng-container *ngIf="status">
<span>{{status}}</span> <span>{{status}} <ng-container *ngIf="currentDate <= endDate && currentDate >= startDate">(M{{calcCurrentMonth}})</ng-container></span>
</ng-container> </ng-container>
<ng-container *ngIf="date"> <ng-container *ngIf="date">
<span>{{date | date: 'dd MMM yyyy': 'UTC'}}</span> <span>{{date | date: 'dd MMM yyyy': 'UTC'}}</span>
@ -295,7 +295,7 @@ export class EntityMetadataComponent {
return this.projects.map(project => { return this.projects.map(project => {
let value = project.funderShortname ? project.funderShortname : project.funderName; let value = project.funderShortname ? project.funderShortname : project.funderName;
if (project.acronym || project.title) { if (project.acronym || project.title) {
value = value + ' | ' + (project.acronym ? project.acronym : value = (value ? value + ' | ' : '') + (project.acronym ? project.acronym :
(project.title.length > 25 ? (project.title.slice(0, 25) + '...'): project.title)); (project.title.length > 25 ? (project.title.slice(0, 25) + '...'): project.title));
} }
// if(project.code) { // if(project.code) {
@ -364,4 +364,18 @@ export class EntityMetadataComponent {
this.projectsModal.open(); this.projectsModal.open();
} }
} }
public get calcCurrentMonth() {
let currentDate = new Date(this.currentDate);
let startDate = new Date(this.startDate);
var months;
months = (currentDate.getFullYear() - startDate.getFullYear()) * 12;
months -= startDate.getMonth();
months += currentDate.getMonth();
if(startDate.getDate() > currentDate.getDate()) {
months--;
}
return months <= 0 ? 0 : months+1;
}
} }

View File

@ -5,7 +5,6 @@ import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import {TabPagingComponent} from './tabPaging.component';
import {ShowTitleComponent} from './showTitle.component'; import {ShowTitleComponent} from './showTitle.component';
import {AddThisComponent} from './addThis.component'; import {AddThisComponent} from './addThis.component';
@ -14,11 +13,11 @@ import {AddThisComponent} from './addThis.component';
CommonModule, FormsModule, RouterModule CommonModule, FormsModule, RouterModule
], ],
declarations: [ declarations: [
TabPagingComponent, ShowTitleComponent, AddThisComponent ShowTitleComponent, AddThisComponent
], ],
providers:[], providers:[],
exports: [ exports: [
TabPagingComponent, ShowTitleComponent, AddThisComponent ShowTitleComponent, AddThisComponent
] ]
}) })
export class LandingModule { } export class LandingModule { }

View File

@ -581,7 +581,7 @@ export class ParsingFunctions {
return eoscSubjectsFound; return eoscSubjectsFound;
} }
// publication & dataset landing : for subjects and otherSubjects and classifiedSubjects // publication & dataset landing : for subjects and otherSubjects and classifiedSubjects
parseAllSubjects(_subjects: any, vocabulary: any): [string[], Map<string, string[]>, Map<string, string[]>, string[], string[],] { parseAllSubjects(_subjects: any, vocabulary: any): [string[], Map<string, string[]>, Map<string, string[]>, string[], string[],] {
// let eoscSubjectsFound = []; // let eoscSubjectsFound = [];
@ -590,12 +590,12 @@ export class ParsingFunctions {
let classifiedSubjects: Map<string, string[]>; let classifiedSubjects: Map<string, string[]>;
let fos: string[]; let fos: string[];
let sdg: string[]; let sdg: string[];
let setOfEoscSubjects: Set<string> = new Set(); let setOfEoscSubjects: Set<string> = new Set();
let subject; let subject;
let length = Array.isArray(_subjects) ? _subjects.length : 1; let length = Array.isArray(_subjects) ? _subjects.length : 1;
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
subject = Array.isArray(_subjects) ? _subjects[i] : _subjects; subject = Array.isArray(_subjects) ? _subjects[i] : _subjects;
if (subject.classid != "") { if (subject.classid != "") {
@ -628,7 +628,7 @@ export class ParsingFunctions {
if (classifiedSubjects == undefined) { if (classifiedSubjects == undefined) {
classifiedSubjects = new Map<string, string[]>(); classifiedSubjects = new Map<string, string[]>();
} }
let content: string = subject.content + ""; let content: string = subject.content + "";
// let checkAndAddEoscSubjectResp = this.checkAndAddEoscSubject(setOfEoscSubjects, eoscSubjectsFound, subject, content); // let checkAndAddEoscSubjectResp = this.checkAndAddEoscSubject(setOfEoscSubjects, eoscSubjectsFound, subject, content);
// let found: boolean = checkAndAddEoscSubjectResp["found"]; // let found: boolean = checkAndAddEoscSubjectResp["found"];
@ -639,7 +639,11 @@ export class ParsingFunctions {
if (!classifiedSubjects.has(subject.classname)) { if (!classifiedSubjects.has(subject.classname)) {
classifiedSubjects.set(subject.classname, new Array<string>()); classifiedSubjects.set(subject.classname, new Array<string>());
} }
classifiedSubjects.get(subject.classname).push(content); if(properties.environment == "production") {
classifiedSubjects.get(subject.classname).push(content);
} else {
classifiedSubjects.get(subject.classname).push(subject.classid + ": " + content);
}
// } // }
} }
} else { } else {
@ -659,6 +663,17 @@ export class ParsingFunctions {
} }
} }
} }
if(properties.environment != "production" && classifiedSubjects != null) {
if (subjects == undefined) {
subjects = new Array<string>();
}
for (let classified of classifiedSubjects.keys()) {
subjects = subjects.concat(classifiedSubjects.get(classified));
}
classifiedSubjects = null;
}
return [subjects, otherSubjects, classifiedSubjects, fos, sdg]; return [subjects, otherSubjects, classifiedSubjects, fos, sdg];
} }

View File

@ -1,24 +0,0 @@
import {Component, Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'tabPaging',
template: `
<div class="uk-panel" *ngIf="!showAll && length > 10">
<a (click)="changeShowAll.emit({value: true});">
<div class="uk-float-right">view all {{length | number}}</div>
</a>
</div>
`
})
export class TabPagingComponent {
@Input() showAll: boolean;
@Input() length: number;
@Output() changeShowAll: EventEmitter<any> = new EventEmitter();
constructor () {
}
ngOnInit() {
}
}

View File

@ -18,7 +18,7 @@ import {ResultPreviewModule} from "../../../utils/result-preview/result-preview.
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, FormsModule, ResultLandingUtilsModule, CommonModule, FormsModule, ResultLandingUtilsModule,
PagingModule, ErrorMessagesModule, ShowAuthorsModule, LandingModule, NoLoadPaging, ResultPreviewModule PagingModule, ErrorMessagesModule, ShowAuthorsModule, NoLoadPaging, ResultPreviewModule
], ],
declarations: [ declarations: [
OrganizationsDeletedByInferenceComponent OrganizationsDeletedByInferenceComponent

View File

@ -28,7 +28,7 @@ import {HelperFunctions} from "../../../utils/HelperFunctions.class";
<li *ngFor="let result of results.slice((page-1)*pageSize, page*pageSize)"> <li *ngFor="let result of results.slice((page-1)*pageSize, page*pageSize)">
<result-preview [modal]="modal" [properties]="properties" [hasLink]="false" [result]="getResultPreview(result)" <result-preview [modal]="modal" [properties]="properties" [hasLink]="false" [result]="getResultPreview(result)"
[showOrcid]="false" [prevPath]="prevPath" [showInline]="true" [showOrcid]="false" [prevPath]="prevPath" [showInline]="true"
[isDeletedByInferenceModal]="true"></result-preview> [isDeletedByInferenceModal]="true" [isMobile]="isMobile"></result-preview>
</li> </li>
</ul> </ul>
<no-load-paging *ngIf="results.length > pageSize" [type]="type" <no-load-paging *ngIf="results.length > pageSize" [type]="type"
@ -40,6 +40,7 @@ import {HelperFunctions} from "../../../utils/HelperFunctions.class";
` `
}) })
export class DeletedByInferenceComponent { export class DeletedByInferenceComponent {
@Input() isMobile: boolean = false;
@Input() prevPath: string = ""; @Input() prevPath: string = "";
public results: ResultLandingInfo[] = []; public results: ResultLandingInfo[] = [];
@Input() id: string; @Input() id: string;

View File

@ -145,8 +145,7 @@ export class DeletedByInferenceService {
if(author.orcid_pending) { if(author.orcid_pending) {
author.orcid_pending = author.orcid_pending.toUpperCase(); author.orcid_pending = author.orcid_pending.toUpperCase();
} }
if(result['authors'][author.rank] && result['authors'][author.rank].fullName == author.content) {
if(result['authors'][author.rank] && results['authors'][author.rank].fullName == author.content) {
if(!author.orcid && result['authors'][author.rank].orcid) { if(!author.orcid && result['authors'][author.rank].orcid) {
author.orcid = result['authors'][author.rank].orcid; author.orcid = result['authors'][author.rank].orcid;
} else if(!author.orcid_pending && result['authors'][author.rank].orcid_pending) { } else if(!author.orcid_pending && result['authors'][author.rank].orcid_pending) {

View File

@ -79,7 +79,8 @@
[type]="resultLandingInfo.resultType" [type]="resultLandingInfo.resultType"
[result]="resultLandingInfo" [id]="resultLandingInfo.objIdentifier"> [result]="resultLandingInfo" [id]="resultLandingInfo.objIdentifier">
<!-- ORCID --> <!-- ORCID -->
<div *ngIf="properties.adminToolsPortalType == 'explore' || properties.adminToolsPortalType == 'community' || properties.adminToolsPortalType == 'aggregator'" <div *ngIf="properties.adminToolsPortalType == 'explore' || properties.adminToolsPortalType == 'community'
|| properties.adminToolsPortalType == 'aggregator' || properties.dashboard == 'irish'"
class="uk-margin-small-right"> class="uk-margin-small-right">
<orcid-work [resultId]="id" [resultTitle]="resultLandingInfo.title" [resultLandingInfo]="resultLandingInfo" <orcid-work [resultId]="id" [resultTitle]="resultLandingInfo.title" [resultLandingInfo]="resultLandingInfo"
[pids]="pidsArrayString" [pageType]="'landing'"> [pids]="pidsArrayString" [pageType]="'landing'">
@ -544,7 +545,8 @@
</div> </div>
<hr class="uk-margin-remove"> <hr class="uk-margin-remove">
</ng-container> </ng-container>
<ng-container *ngIf="properties.adminToolsPortalType == 'explore' || properties.adminToolsPortalType == 'community' || properties.adminToolsPortalType == 'aggregator'" > <ng-container *ngIf="properties.adminToolsPortalType == 'explore' || properties.adminToolsPortalType == 'community'
|| properties.adminToolsPortalType == 'aggregator' || properties.dashboard == 'irish'" >
<div class="uk-padding-small uk-padding-remove-horizontal "> <div class="uk-padding-small uk-padding-remove-horizontal ">
<orcid-work [resultId]="id" [resultTitle]="resultLandingInfo?.title" [resultLandingInfo]="resultLandingInfo" <orcid-work [resultId]="id" [resultTitle]="resultLandingInfo?.title" [resultLandingInfo]="resultLandingInfo"
[pids]="pidsArrayString" [pageType]="'landing'" [isMobile]="true" [pids]="pidsArrayString" [pageType]="'landing'" [isMobile]="true"
@ -1167,19 +1169,27 @@
<deletedByInference *ngIf="type == 'publication' && deleteByInferenceOpened" <deletedByInference *ngIf="type == 'publication' && deleteByInferenceOpened"
[id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']" [id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']"
[ids]="resultLandingInfo.deletedByInferenceIds" [ids]="resultLandingInfo.deletedByInferenceIds"
[resultType]="type" [type]="openaireEntities.PUBLICATIONS"></deletedByInference> [resultType]="type" [type]="openaireEntities.PUBLICATIONS"
[isMobile]="isMobile"
[modal]="alertModalDeletedByInferenceFS"></deletedByInference>
<deletedByInference *ngIf="type == 'dataset' && deleteByInferenceOpened" <deletedByInference *ngIf="type == 'dataset' && deleteByInferenceOpened"
[id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']" [id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']"
[ids]="resultLandingInfo.deletedByInferenceIds" [ids]="resultLandingInfo.deletedByInferenceIds"
[resultType]="'dataset'" [type]="openaireEntities.DATASETS"></deletedByInference> [resultType]="'dataset'" [type]="openaireEntities.DATASETS"
[isMobile]="isMobile"
[modal]="alertModalDeletedByInferenceFS"></deletedByInference>
<deletedByInference *ngIf="type == 'software' && deleteByInferenceOpened" <deletedByInference *ngIf="type == 'software' && deleteByInferenceOpened"
[id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']" [id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']"
[ids]="resultLandingInfo.deletedByInferenceIds" [ids]="resultLandingInfo.deletedByInferenceIds"
[resultType]="type" [type]="openaireEntities.SOFTWARE"></deletedByInference> [resultType]="type" [type]="openaireEntities.SOFTWARE"
[isMobile]="isMobile"
[modal]="alertModalDeletedByInferenceFS"></deletedByInference>
<deletedByInference *ngIf="type == 'orp' && deleteByInferenceOpened" <deletedByInference *ngIf="type == 'orp' && deleteByInferenceOpened"
[id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']" [id]="resultLandingInfo.record['result']['header']['dri:objIdentifier']"
[ids]="resultLandingInfo.deletedByInferenceIds" [ids]="resultLandingInfo.deletedByInferenceIds"
[resultType]="'other'" [type]="openaireEntities.OTHER"></deletedByInference> [resultType]="'other'" [type]="openaireEntities.OTHER"
[isMobile]="isMobile"
[modal]="alertModalDeletedByInferenceFS"></deletedByInference>
</fs-modal> </fs-modal>
<fs-modal *ngIf="resultLandingInfo" #citeFsModal classTitle="uk-tile-default uk-border-bottom"> <fs-modal *ngIf="resultLandingInfo" #citeFsModal classTitle="uk-tile-default uk-border-bottom">

View File

@ -38,6 +38,7 @@ import {SafeHtmlPipeModule} from '../../utils/pipes/safeHTMLPipe.module';
import {EntityActionsModule} from "../../utils/entity-actions/entity-actions.module"; import {EntityActionsModule} from "../../utils/entity-actions/entity-actions.module";
import {ResultLandingRoutingModule} from "./resultLanding-routing.module"; import {ResultLandingRoutingModule} from "./resultLanding-routing.module";
import {OrcidCoreModule} from "../../orcid/orcid-core.module"; import {OrcidCoreModule} from "../../orcid/orcid-core.module";
import {SearchTabModule} from "../../utils/tabs/contents/search-tab.module";
@NgModule({ @NgModule({
imports: [ imports: [

View File

@ -20,7 +20,7 @@ import {StakeholderBaseComponent} from "../../utils/stakeholder-base.component";
template: ` template: `
<div class="uk-margin-medium-bottom"> <div class="uk-margin-medium-bottom">
<form *ngIf="stakeholderFb" [formGroup]="stakeholderFb"> <form *ngIf="stakeholderFb" [formGroup]="stakeholderFb">
<div class="uk-grid uk-grid-large" uk-grid> <div class="uk-grid" uk-grid>
<div class="uk-width-1-2@m"> <div class="uk-width-1-2@m">
<div input id="name" [formInput]="stakeholderFb.get('name')" <div input id="name" [formInput]="stakeholderFb.get('name')"
placeholder="Name"></div> placeholder="Name"></div>
@ -126,6 +126,19 @@ import {StakeholderBaseComponent} from "../../utils/stakeholder-base.component";
</div> </div>
</div> </div>
</div> </div>
<div *ngIf="canChangeCopy" class="uk-width-1-1">
<h6>Instance Type</h6>
<div class="uk-width-auto uk-flex uk-flex-middle">
<label class="uk-margin-right">
<input type="radio" [value]="true" formControlName="copy"/>
<span class="uk-margin-xsmall-left">Copy</span>
</label>
<label class="uk-margin-right">
<input type="radio" [value]="false" formControlName="copy"/>
<span class="uk-margin-xsmall-left">Reference</span>
</label>
</div>
</div>
</div> </div>
</form> </form>
<div #notify [class.uk-hidden]="!stakeholderFb" notify-form <div #notify [class.uk-hidden]="!stakeholderFb" notify-form
@ -145,6 +158,7 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
public stakeholder: Stakeholder; public stakeholder: Stakeholder;
public isDefault: boolean; public isDefault: boolean;
public isNew: boolean; public isNew: boolean;
public isFull: boolean;
public loading: boolean = false; public loading: boolean = false;
public typesByRole: Option[]; public typesByRole: Option[];
public statsProfiles: string[]; public statsProfiles: string[];
@ -172,7 +186,7 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
super.ngOnDestroy(); super.ngOnDestroy();
} }
public init(stakeholder: Stakeholder, alias: string[], defaultStakeholders: Stakeholder[], isDefault: boolean, isNew: boolean) { public init(stakeholder: Stakeholder, alias: string[], defaultStakeholders: Stakeholder[], isDefault: boolean, isNew: boolean, isFull: boolean = false) {
this.reset(); this.reset();
this.deleteCurrentPhoto = false; this.deleteCurrentPhoto = false;
this.stakeholder = stakeholder; this.stakeholder = stakeholder;
@ -183,6 +197,7 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
this.defaultStakeholders = defaultStakeholders; this.defaultStakeholders = defaultStakeholders;
this.isDefault = isDefault; this.isDefault = isDefault;
this.isNew = isNew; this.isNew = isNew;
this.isFull = isFull;
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user; this.user = user;
if (this.isCurator) { if (this.isCurator) {
@ -220,6 +235,7 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
funderType: this.fb.control(this.stakeholder.funderType), funderType: this.fb.control(this.stakeholder.funderType),
topics: this.fb.control(this.stakeholder.topics), topics: this.fb.control(this.stakeholder.topics),
isUpload: this.fb.control(this.stakeholder.isUpload), isUpload: this.fb.control(this.stakeholder.isUpload),
copy: this.fb.control(this.stakeholder.copy),
logoUrl: this.fb.control(this.stakeholder.logoUrl), logoUrl: this.fb.control(this.stakeholder.logoUrl),
}); });
if (this.stakeholder.isUpload) { if (this.stakeholder.isUpload) {
@ -246,7 +262,7 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
this.subscriptions.push(this.stakeholderFb.get('type').valueChanges.subscribe(value => { this.subscriptions.push(this.stakeholderFb.get('type').valueChanges.subscribe(value => {
this.onTypeChange(value, defaultStakeholders); this.onTypeChange(value, defaultStakeholders);
})); }));
this.stakeholderFb.setControl('defaultId', this.fb.control(stakeholder.defaultId, (this.isDefault && !this.isNew) ? [] : Validators.required)); this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, (this.isDefault && !this.isNew) ? [] : Validators.required));
if (!this.isNew) { if (!this.isNew) {
this.notification = NotificationUtils.editStakeholder(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); this.notification = NotificationUtils.editStakeholder(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.notify.reset(this.notification.message); this.notify.reset(this.notification.message);
@ -304,6 +320,13 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
return this.isNew && this.stakeholderFb.get('type').valid && !!this.defaultStakeholdersOptions; return this.isNew && this.stakeholderFb.get('type').valid && !!this.defaultStakeholdersOptions;
} }
public get canChangeCopy(): boolean {
return this.isCurator &&
!this.stakeholderFb.get('isDefault').getRawValue() &&
this.stakeholderFb.get('defaultId').getRawValue() &&
this.stakeholderFb.get('defaultId').getRawValue() !== '-1';
}
reset() { reset() {
this.uploadError = null; this.uploadError = null;
this.stakeholderFb = null; this.stakeholderFb = null;
@ -350,15 +373,15 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
public saveStakeholder(callback: Function, errorCallback: Function = null) { public saveStakeholder(callback: Function, errorCallback: Function = null) {
if (this.isNew) { if (this.isNew) {
let defaultStakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.getRawValue().defaultId); let copyId = null;
this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.getRawValue(),
(defaultStakeholder ? defaultStakeholder.topics : []), this.stakeholderFb.getRawValue().isDefault));
this.removePhoto();
if (this.stakeholderFb.getRawValue().isDefault) { if (this.stakeholderFb.getRawValue().isDefault) {
copyId = this.stakeholderFb.getRawValue().defaultId !== '-1'?this.stakeholderFb.getRawValue().defaultId:null;
this.stakeholderFb.get('defaultId').setValue(null); this.stakeholderFb.get('defaultId').setValue(null);
this.stakeholderFb.removeControl('isDefault');
} }
this.removePhoto();
this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL, this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL,
this.stakeholderFb.getRawValue()).subscribe(stakeholder => { this.stakeholderFb.getRawValue(), copyId).subscribe(stakeholder => {
this.notification.entity = stakeholder._id; this.notification.entity = stakeholder._id;
this.notification.stakeholder = stakeholder.alias; this.notification.stakeholder = stakeholder.alias;
this.notification.stakeholderType = stakeholder.type; this.notification.stakeholderType = stakeholder.type;
@ -375,7 +398,7 @@ export class EditStakeholderComponent extends StakeholderBaseComponent {
this.loading = false; this.loading = false;
})); }));
} else { } else {
this.subscriptions.push(this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.stakeholderFb.getRawValue()).subscribe(stakeholder => { this.subscriptions.push(this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.stakeholderFb.getRawValue(), [], this.isFull).subscribe(stakeholder => {
this.notification.entity = stakeholder._id; this.notification.entity = stakeholder._id;
this.notification.stakeholder = stakeholder.alias; this.notification.stakeholder = stakeholder.alias;
this.notification.stakeholderType = stakeholder.type; this.notification.stakeholderType = stakeholder.type;

View File

@ -5,9 +5,10 @@ import {InputModule} from "../../../sharedComponents/input/input.module";
import {ReactiveFormsModule} from "@angular/forms"; import {ReactiveFormsModule} from "@angular/forms";
import {IconsModule} from "../../../utils/icons/icons.module"; import {IconsModule} from "../../../utils/icons/icons.module";
import {NotifyFormModule} from "../../../notifications/notify-form/notify-form.module"; import {NotifyFormModule} from "../../../notifications/notify-form/notify-form.module";
import {MatSlideToggleModule} from "@angular/material/slide-toggle";
@NgModule({ @NgModule({
imports: [CommonModule, InputModule, ReactiveFormsModule, IconsModule, NotifyFormModule], imports: [CommonModule, InputModule, ReactiveFormsModule, IconsModule, NotifyFormModule, MatSlideToggleModule],
declarations: [EditStakeholderComponent], declarations: [EditStakeholderComponent],
exports: [EditStakeholderComponent] exports: [EditStakeholderComponent]
}) })

View File

@ -48,7 +48,7 @@ export class GeneralComponent extends BaseComponent implements OnInit {
} }
public reset() { public reset() {
this.editStakeholderComponent.init(this.stakeholder, this.alias, this.defaultStakeholders, this.stakeholder.defaultId == null, false) this.editStakeholderComponent.init(this.stakeholder, this.alias, this.defaultStakeholders, this.stakeholder.defaultId == null, false, true)
} }
public save() { public save() {

View File

@ -31,7 +31,7 @@
<div *ngIf="!loading" uk-height-match="target: .titleContainer; row: false"> <div *ngIf="!loading" uk-height-match="target: .titleContainer; row: false">
<div uk-height-match="target: .logoContainer; row: false"> <div uk-height-match="target: .logoContainer; row: false">
<div *ngIf="tab != 'profiles' && isCurator()" class="uk-section"> <div *ngIf="tab != 'profiles' && isCurator()" class="uk-section">
<div class="uk-flex uk-flex-middle uk-flex-between uk-margin-small-bottom"> <div class="uk-flex uk-flex-middle uk-flex-between uk-margin-bottom">
<h4 class="uk-margin-remove">Profile Templates</h4> <h4 class="uk-margin-remove">Profile Templates</h4>
<paging-no-load *ngIf="displayDefaultStakeholders?.length > pageSize" <paging-no-load *ngIf="displayDefaultStakeholders?.length > pageSize"
(pageChange)="updateCurrentTemplatesPage($event)" (pageChange)="updateCurrentTemplatesPage($event)"
@ -39,8 +39,7 @@
[totalResults]="displayDefaultStakeholders.length"> [totalResults]="displayDefaultStakeholders.length">
</paging-no-load> </paging-no-load>
</div> </div>
<div class="uk-grid uk-child-width-1-3@l uk-child-width-1-2@m uk-child-width-1-1 uk-grid-match" <div class="uk-grid uk-child-width-1-3@l uk-child-width-1-2@m uk-child-width-1-1 uk-grid-match" uk-grid>
uk-grid>
<ng-template ngFor <ng-template ngFor
[ngForOf]="displayDefaultStakeholders.slice((currentTemplatesPage-1)*pageSize, currentTemplatesPage*pageSize)" [ngForOf]="displayDefaultStakeholders.slice((currentTemplatesPage-1)*pageSize, currentTemplatesPage*pageSize)"
let-stakeholder> let-stakeholder>
@ -59,7 +58,7 @@
</h4> </h4>
</div> </div>
<div *ngIf="tab != 'templates' && isManager()" class="uk-section"> <div *ngIf="tab != 'templates' && isManager()" class="uk-section">
<div class="uk-flex uk-flex-middle uk-flex-between uk-margin-small-bottom"> <div class="uk-flex uk-flex-middle uk-flex-between uk-margin-bottom">
<h4 class="uk-margin-remove">Profiles</h4> <h4 class="uk-margin-remove">Profiles</h4>
<paging-no-load *ngIf="displayStakeholders?.length > pageSize" <paging-no-load *ngIf="displayStakeholders?.length > pageSize"
(pageChange)="updateCurrentPage($event)" (pageChange)="updateCurrentPage($event)"

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ import {
Visibility Visibility
} from "../../monitor/entities/stakeholder"; } from "../../monitor/entities/stakeholder";
import { import {
AbstractControl, AbstractControl, FormArray, FormGroup,
UntypedFormArray, UntypedFormArray,
UntypedFormBuilder, UntypedFormBuilder,
UntypedFormControl, UntypedFormControl,
@ -31,8 +31,8 @@ import {AlertModal} from "../../utils/modal/alert";
import {StatisticsService} from "../utils/services/statistics.service"; import {StatisticsService} from "../utils/services/statistics.service";
import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser";
import {Reorder, StakeholderService} from "../../monitor/services/stakeholder.service"; import {MoveIndicator, SectionInfo, StakeholderService} from "../../monitor/services/stakeholder.service";
import {Observable, Subscriber} from "rxjs"; import {BehaviorSubject, Observable, Subscriber} from "rxjs";
import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service"; import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {Role, Session, User} from "../../login/utils/helper.class"; import {Role, Session, User} from "../../login/utils/helper.class";
@ -45,6 +45,7 @@ import {NotificationHandler} from "../../utils/notification-handler";
import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component"; import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {StatsProfilesService} from "../utils/services/stats-profiles.service"; import {StatsProfilesService} from "../utils/services/stats-profiles.service";
import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component";
declare var UIkit; declare var UIkit;
declare var copy; declare var copy;
@ -82,6 +83,8 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
public index: number = -1; public index: number = -1;
public editing: boolean = false; public editing: boolean = false;
public dragging: boolean = false; public dragging: boolean = false;
/* Reorder indicators */
public to: BehaviorSubject<SectionInfo> = new BehaviorSubject<SectionInfo>(null);
/** Caches */ /** Caches */
public safeUrls: Map<string, SafeResourceUrl> = new Map<string, SafeResourceUrl>([]); public safeUrls: Map<string, SafeResourceUrl> = new Map<string, SafeResourceUrl>([]);
public numberResponses: Map<string, any> = new Map<string, any>(); public numberResponses: Map<string, any> = new Map<string, any>();
@ -94,12 +97,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
public sectionTypeToDelete: string; public sectionTypeToDelete: string;
public sectionChildrenActionOnDelete: string; public sectionChildrenActionOnDelete: string;
public indicatorChildrenActionOnDelete: string; public indicatorChildrenActionOnDelete: string;
urlParameterizedMessage = null;
showCheckForSchemaEnhancements: boolean = false;
private notification: Notification; private notification: Notification;
@ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent; @ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent;
@ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent; @ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent;
@ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent; @ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent;
/* Transition Groups */
@ViewChild('numbersTransition') numbersTransition: TransitionGroupComponent;
@ViewChild('chartsTransition') chartsTransition: TransitionGroupComponent;
public isFullscreen: boolean = false; public isFullscreen: boolean = false;
@ -124,7 +128,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
private notificationService: NotificationService, private notificationService: NotificationService,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
protected _router: Router, protected _router: Router,
private cdr: ChangeDetectorRef,
private sanitizer: DomSanitizer) { private sanitizer: DomSanitizer) {
super() super()
this.filesToUpload = []; this.filesToUpload = [];
@ -186,7 +189,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} }
}); });
if (document !== undefined) { if (document !== undefined) {
let callback = (list, type: IndicatorType, action: 'moved' | 'added' | 'removed'): void => { let callback = (list): string[] => {
let items: HTMLCollection = list.current.children; let items: HTMLCollection = list.current.children;
let reordered = []; let reordered = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
@ -194,12 +197,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
reordered.push(items.item(i).id); reordered.push(items.item(i).id);
} }
} }
let reorder: Reorder = { return reordered;
action: action,
target: list.detail[1].id,
ids: reordered
}
this.reorderIndicators(list.current.id.toString().split('-')[1], type, reorder);
}; };
this.numbers.forEach((section) => { this.numbers.forEach((section) => {
this.subscriptions.push(UIkit.util.on(document, 'start', '#number-' + section._id, (): void => { this.subscriptions.push(UIkit.util.on(document, 'start', '#number-' + section._id, (): void => {
@ -209,24 +207,32 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.dragging = false; this.dragging = false;
})); }));
this.subscriptions.push(UIkit.util.on(document, 'moved', '#number-' + section._id, (list): void => { this.subscriptions.push(UIkit.util.on(document, 'moved', '#number-' + section._id, (list): void => {
callback(list, "number", 'moved'); this.reorderIndicators(section._id, 'number', callback(list));
})); }));
this.subscriptions.push(UIkit.util.on(document, 'added', '#number-' + section._id, (list): void => { this.subscriptions.push(UIkit.util.on(document, 'added', '#number-' + section._id, (list): void => {
callback(list, "number", 'added'); this.to.next({id: section._id, indicators: callback(list)});
})); }));
this.subscriptions.push(UIkit.util.on(document, 'removed', '#number-' + section._id, (list): void => { this.subscriptions.push(UIkit.util.on(document, 'removed', '#number-' + section._id, (list): void => {
callback(list, "number", 'removed'); let sub = this.to.asObservable().subscribe(to => {
if (to) {
let from: SectionInfo = {id: section._id, indicators: callback(list)};
this.moveIndicator({target: list.detail[1].id, from: from, to: to});
setTimeout(() => {
sub.unsubscribe();
})
}
})
})); }));
}); });
this.charts.forEach((section) => { this.charts.forEach((section) => {
this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => { this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => {
callback(list, "chart", 'moved'); this.reorderIndicators(section._id, 'chart', callback(list));
})); }));
this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => { this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => {
callback(list, "chart", 'added'); //callback(list, "chart", 'added');
})); }));
this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => { this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => {
callback(list, "chart", 'removed'); // callback(list, "chart", 'removed');
})); }));
}); });
} }
@ -263,7 +269,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
setNumbers() { setNumbers() {
this.numberSections = this.fb.array([]); this.numberSections = this.fb.array([]);
this.numberResults.clear(); this.numberResults.clear();
let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>(); let urls: Map<string, [number, number, number][]> = new Map<string, [number, number, number][]>();
this.numbers.forEach((section, i) => { this.numbers.forEach((section, i) => {
this.numberSections.push(this.fb.group({ this.numberSections.push(this.fb.group({
_id: this.fb.control(section._id), _id: this.fb.control(section._id),
@ -275,11 +281,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
indicators: this.fb.control(section.indicators) indicators: this.fb.control(section.indicators)
})); }));
section.indicators.forEach((number, j) => { section.indicators.forEach((number, j) => {
let url = this.indicatorUtils.getFullUrl(this.stakeholder, number.indicatorPaths[0]); number.indicatorPaths.forEach((indicatorPath, k) => {
const pair = JSON.stringify([number.indicatorPaths[0].source, url]); let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath);
const indexes = urls.get(pair) ? urls.get(pair) : []; const pair = JSON.stringify([indicatorPath.source, url]);
indexes.push([i, j]); const indexes = urls.get(pair) ? urls.get(pair) : [];
urls.set(pair, indexes); indexes.push([i, j, k]);
urls.set(pair, indexes);
});
}); });
}); });
this.numberSubscription.forEach(value => { this.numberSubscription.forEach(value => {
@ -301,10 +309,10 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
}); });
} }
private calculateResults(response: any, indexes: [number, number][]) { private calculateResults(response: any, indexes: [number, number, number][]) {
indexes.forEach(([i, j]) => { indexes.forEach(([i, j, k]) => {
let result = JSON.parse(JSON.stringify(response)); let result = JSON.parse(JSON.stringify(response));
this.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { this.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => {
if (result) { if (result) {
result = result[jsonPath]; result = result[jsonPath];
} }
@ -317,14 +325,14 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} else { } else {
result = 0; result = 0;
} }
this.numberResults.set(i + '-' + j, result); this.numberResults.set(i + '-' + j + '-' + k, result);
}); });
} }
get charts(): Section[] { get charts(): Section[] {
if (this.stakeholder.topics[this.topicIndex] && if (this.stakeholder.topics[this.topicIndex] &&
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts; return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts;
} else { } else {
return []; return [];
@ -333,8 +341,8 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
get numbers(): Section[] { get numbers(): Section[] {
if (this.stakeholder.topics[this.topicIndex] && if (this.stakeholder.topics[this.topicIndex] &&
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers; return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers;
} else { } else {
return []; return [];
@ -351,9 +359,9 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
get canEdit() { get canEdit() {
return this.stakeholder && return this.stakeholder &&
this.stakeholder.topics[this.topicIndex] && this.stakeholder.topics[this.topicIndex] &&
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex] && !this.loading; this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex] && !this.loading;
} }
public get numberIndicatorPaths(): UntypedFormArray { public get numberIndicatorPaths(): UntypedFormArray {
@ -364,6 +372,14 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
return this.chartIndicatorFb.get('indicatorPaths') as UntypedFormArray; return this.chartIndicatorFb.get('indicatorPaths') as UntypedFormArray;
} }
public getActiveIndicatorPath(indicator: Indicator) {
if (indicator.activePath) {
return indicator.indicatorPaths[indicator.activePath];
} else {
return indicator.indicatorPaths[0];
}
}
public getNumberClassBySize(size: IndicatorSize) { public getNumberClassBySize(size: IndicatorSize) {
if (size === 'small') { if (size === 'small') {
return 'uk-width-medium@m uk-width-1-1'; return 'uk-width-medium@m uk-width-1-1';
@ -460,7 +476,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} }
public getParameters(index: number, type: IndicatorType = 'chart'): UntypedFormArray { public getParameters(index: number, type: IndicatorType = 'chart'): UntypedFormArray {
if(type === 'chart') { if (type === 'chart') {
return this.chartIndicatorPaths.at(index).get('parameters') as UntypedFormArray; return this.chartIndicatorPaths.at(index).get('parameters') as UntypedFormArray;
} else { } else {
return this.numberIndicatorPaths.at(index).get('parameters') as UntypedFormArray; return this.numberIndicatorPaths.at(index).get('parameters') as UntypedFormArray;
@ -473,7 +489,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) { private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) {
return this.sanitizer.bypassSecurityTrustResourceUrl( return this.sanitizer.bypassSecurityTrustResourceUrl(
this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath))); this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)));
} }
private getUrlByStakeHolder(indicatorPath: IndicatorPath) { private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
@ -485,61 +501,57 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
jsonPath.push(this.fb.control('', Validators.required)); jsonPath.push(this.fb.control('', Validators.required));
} }
this.numberIndicatorPaths.push(this.fb.group({ this.numberIndicatorPaths.push(this.fb.group({
url: this.fb.control(url, [Validators.required, StringUtils.urlValidator()]), url: this.fb.control(url, [Validators.required, StringUtils.urlValidator()]),
jsonPath: jsonPath, jsonPath: jsonPath,
result: this.fb.control(0, Validators.required), result: this.fb.control(0, Validators.required),
source: this.fb.control(source, Validators.required), source: this.fb.control(source, Validators.required),
parameters: parameters, parameters: parameters,
format: this.fb.control(format, Validators.required) format: this.fb.control(format, Validators.required)
} }
)); ));
let index = this.numberIndicatorPaths.length - 1; let index = this.numberIndicatorPaths.length - 1;
if (this.numberIndicatorPaths.at(index).get('url').valid) { if (this.numberIndicatorPaths.at(index).get('url').valid) {
this.validateJsonPath(index); this.validateJsonPath(index);
this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value);
} }
if (this.indicator.defaultId === null) { if (this.indicator.defaultId === null) {
this.subscriptions.push(this.numberIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => { this.subscriptions.push(this.numberIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
this.numberIndicatorPaths.at(index).get('result').setValue(null); this.numberIndicatorPaths.at(index).get('result').setValue(null);
if (this.numberIndicatorPaths.at(index).get('url').valid) { if (this.numberIndicatorPaths.at(index).get('url').valid) {
let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(value), value, this.stakeholder, this.numberIndicatorPaths.at(index).get('jsonPath').value, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(value))); let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(value), value, this.stakeholder, this.numberIndicatorPaths.at(index).get('jsonPath').value, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(value)));
this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value); if (this.indicator.indicatorPaths[index]) {
if (this.indicator.indicatorPaths[index]) { this.indicator.indicatorPaths[index] = indicatorPath;
this.indicator.indicatorPaths[index] = indicatorPath; } else {
} else { this.indicator.indicatorPaths.push(indicatorPath);
this.indicator.indicatorPaths.push(indicatorPath); }
} if (indicatorPath.source) {
if (indicatorPath.source) { this.numberIndicatorPaths.at(index).get('source').setValue(indicatorPath.source);
this.numberIndicatorPaths.at(index).get('source').setValue(indicatorPath.source); }
} (this.numberIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath));
(this.numberIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath)); if (indicatorPath.jsonPath.length > 1 && this.getJsonPath(index).length == 1) {
if (indicatorPath.jsonPath.length > 1 && this.getJsonPath(index).length == 1) { let paths = indicatorPath.jsonPath;
let paths = indicatorPath.jsonPath; for (let i = 0; i < paths.length; i++) {
for (let i = 0; i < paths.length; i++) { if (i == this.getJsonPath(index).length) {
if (i == this.getJsonPath(index).length) { this.getJsonPath(index).push(this.fb.control('', Validators.required));
this.getJsonPath(index).push(this.fb.control('', Validators.required)); }
} }
this.getJsonPath(index).setValue(paths)
} }
this.getJsonPath(index).setValue(paths)
} }
} else { })
this.urlParameterizedMessage = null;
}
})
); );
this.subscriptions.push(this.numberIndicatorPaths.at(index).get('jsonPath').valueChanges.subscribe(value => { this.subscriptions.push(this.numberIndicatorPaths.at(index).get('jsonPath').valueChanges.subscribe(value => {
if (this.indicator.indicatorPaths[index]) { if (this.indicator.indicatorPaths[index]) {
this.indicator.indicatorPaths[index].jsonPath = value; this.indicator.indicatorPaths[index].jsonPath = value;
} }
this.numberIndicatorPaths.at(index).get('result').setValue(null); this.numberIndicatorPaths.at(index).get('result').setValue(null);
}) })
); );
this.subscriptions.push(this.numberIndicatorPaths.at(index).get('source').valueChanges.subscribe(value => { this.subscriptions.push(this.numberIndicatorPaths.at(index).get('source').valueChanges.subscribe(value => {
if (this.indicator.indicatorPaths[index]) { if (this.indicator.indicatorPaths[index]) {
this.indicator.indicatorPaths[index].source = value; this.indicator.indicatorPaths[index].source = value;
} }
}) })
); );
} else { } else {
this.numberIndicatorPaths.at(index).get('url').disable(); this.numberIndicatorPaths.at(index).get('url').disable();
@ -550,20 +562,18 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
public addChartIndicatorPath(value: string = '', parameters: UntypedFormArray = new UntypedFormArray([]), disableUrl: boolean = false, type: string = null) { public addChartIndicatorPath(value: string = '', parameters: UntypedFormArray = new UntypedFormArray([]), disableUrl: boolean = false, type: string = null) {
this.chartIndicatorPaths.push(this.fb.group({ this.chartIndicatorPaths.push(this.fb.group({
url: this.fb.control(value, [Validators.required, StringUtils.urlValidator()]), url: this.fb.control(value, [Validators.required, StringUtils.urlValidator()]),
parameters: parameters, parameters: parameters,
type: this.fb.control(type) type: this.fb.control(type)
} }
)); ));
let index = this.chartIndicatorPaths.length - 1; let index = this.chartIndicatorPaths.length - 1;
if (disableUrl) { if (disableUrl) {
this.chartIndicatorPaths.at(index).get('url').disable(); this.chartIndicatorPaths.at(index).get('url').disable();
} else { } else {
this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value);
this.urlSubscriptions.push(this.chartIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => { this.urlSubscriptions.push(this.chartIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
if (this.chartIndicatorPaths.at(index).get('url').valid) { if (this.chartIndicatorPaths.at(index).get('url').valid) {
let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder); let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder);
this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value);
(this.chartIndicatorPaths.at(index) as UntypedFormGroup).get('type').setValue(indicatorPath.type); (this.chartIndicatorPaths.at(index) as UntypedFormGroup).get('type').setValue(indicatorPath.type);
(this.chartIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath)); (this.chartIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath));
if (!this.indicator.indicatorPaths[index]) { if (!this.indicator.indicatorPaths[index]) {
@ -573,13 +583,75 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl; indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl;
this.indicator.indicatorPaths[index] = indicatorPath; this.indicator.indicatorPaths[index] = indicatorPath;
} }
} else {
this.urlParameterizedMessage = null;
} }
})); }));
} }
} }
public removeNumberIndicatorPath(index: number) {
this.numberIndicatorPaths.removeAt(index);
this.indicator.indicatorPaths.splice(index, 1);
this.numbersTransition.init();
if (this.indicator.activePath === index) {
this.activeNumberIndicatorPath(Math.max(0, index - 1));
} else if (this.indicator.activePath > index) {
this.activeNumberIndicatorPath(this.indicator.activePath - 1);
}
this.numberIndicatorFb.markAsDirty();
}
public removeChartIndicatorPath(index: number) {
this.chartIndicatorPaths.removeAt(index);
this.indicator.indicatorPaths.splice(index, 1);
this.chartsTransition.init();
if (this.indicator.activePath === index) {
this.activeChartIndicatorPath(Math.max(0, index - 1));
} else if (this.indicator.activePath > index) {
this.activeChartIndicatorPath(this.indicator.activePath - 1);
}
this.chartIndicatorFb.markAsDirty();
}
public moveIndicatorPath(form: FormGroup,
type: 'number' | 'chart', index: number,
newIndex: number = index - 1) {
let indicatorPaths = type == 'number'?this.numberIndicatorPaths:this.chartIndicatorPaths;
if(type == 'number') {
this.numbersTransition.init();
} else {
this.chartsTransition.init();
}
let a = indicatorPaths.at(index);
let b = indicatorPaths.at(newIndex);
indicatorPaths.setControl(index, b);
indicatorPaths.setControl(newIndex, a);
HelperFunctions.swap(this.indicator.indicatorPaths, index, newIndex);
if (this.indicator.activePath === index) {
this.indicator.activePath = newIndex;
} else if (this.indicator.activePath === newIndex) {
this.indicator.activePath = index;
}
form.markAsDirty();
}
public activeNumberIndicatorPath(index: number) {
let paths = this.numberIndicatorPaths;
if (index == paths.length) {
this.addNumberIndicatorPath();
this.numbersTransition.init();
}
this.indicator.activePath = index;
}
public activeChartIndicatorPath(index: number) {
let paths = this.chartIndicatorPaths;
if (index == paths.length) {
this.addChartIndicatorPath();
this.chartsTransition.init();
}
this.indicator.activePath = index;
}
private getJsonPathAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray { private getJsonPathAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray {
let jsonPath = this.fb.array([]); let jsonPath = this.fb.array([]);
if (indicatorPath.jsonPath) { if (indicatorPath.jsonPath) {
@ -593,6 +665,9 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
private getParametersAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray { private getParametersAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray {
let parameters = this.fb.array([]); let parameters = this.fb.array([]);
if (indicatorPath.parameters) { if (indicatorPath.parameters) {
if(!indicatorPath.parameters.statsProfile) {
indicatorPath.parameters.statsProfile = null;
}
Object.keys(indicatorPath.parameters).forEach(key => { Object.keys(indicatorPath.parameters).forEach(key => {
if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) { if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) {
if (this.indicatorUtils.parametersValidators.has(key)) { if (this.indicatorUtils.parametersValidators.has(key)) {
@ -613,7 +688,21 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} }
public editNumberIndicatorOpen(section: Section, id = null) { public editNumberIndicatorOpen(section: Section, id = null) {
this.urlParameterizedMessage = null; this.editNumberModal.cancelButtonText = 'Cancel';
this.editNumberModal.okButtonLeft = false;
this.editNumberModal.alertMessage = false;
if (this.index === -1) {
this.editNumberModal.alertTitle = 'Create a new number indicator';
this.editNumberModal.okButtonText = 'Save';
this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.editNumberNotify.reset(this.notification.message);
} else {
this.editNumberModal.alertTitle = 'Edit number indicator\'s information';
this.editNumberModal.okButtonText = 'Save Changes';
this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.editNumberNotify.reset(this.notification.message);
}
this.editNumberModal.stayOpen = true;
this.section = section; this.section = section;
this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1; this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1;
if (this.index !== -1) { if (this.index !== -1) {
@ -655,26 +744,26 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.numberIndicatorFb.get('description').disable(); this.numberIndicatorFb.get('description').disable();
}, 0); }, 0);
} }
this.editNumberModal.cancelButtonText = 'Cancel';
this.editNumberModal.okButtonLeft = false;
this.editNumberModal.alertMessage = false;
if (this.index === -1) {
this.editNumberModal.alertTitle = 'Create a new number indicator';
this.editNumberModal.okButtonText = 'Save';
this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.editNumberNotify.reset(this.notification.message);
} else {
this.editNumberModal.alertTitle = 'Edit number indicator\'s information';
this.editNumberModal.okButtonText = 'Save Changes';
this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.editNumberNotify.reset(this.notification.message);
}
this.editNumberModal.stayOpen = true;
this.editNumberModal.open(); this.editNumberModal.open();
} }
public editChartIndicatorOpen(section: Section, id = null) { public editChartIndicatorOpen(section: Section, id = null) {
this.urlParameterizedMessage = null; this.editChartModal.cancelButtonText = 'Cancel';
this.editChartModal.okButtonLeft = false;
this.editChartModal.alertMessage = false;
if (this.index === -1) {
this.editChartModal.alertTitle = 'Create a new chart indicator';
this.editChartModal.okButtonText = 'Save';
this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.editChartNotify.reset(this.notification.message);
} else {
this.editChartModal.alertTitle = 'Edit chart indicator\'s information';
this.editChartModal.okButtonText = 'Save Changes';
this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
;
this.editChartNotify.reset(this.notification.message);
}
this.editChartModal.stayOpen = true;
this.urlSubscriptions.forEach(value => { this.urlSubscriptions.forEach(value => {
if (value instanceof Subscriber) { if (value instanceof Subscriber) {
value.unsubscribe(); value.unsubscribe();
@ -698,7 +787,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
}); });
this.indicator.indicatorPaths.forEach(indicatorPath => { this.indicator.indicatorPaths.forEach(indicatorPath => {
this.addChartIndicatorPath(this.getUrlByStakeHolder(indicatorPath), this.addChartIndicatorPath(this.getUrlByStakeHolder(indicatorPath),
this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type); this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type);
indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
}); });
} else { } else {
@ -721,22 +810,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.chartIndicatorFb.get('description').disable(); this.chartIndicatorFb.get('description').disable();
}, 0); }, 0);
} }
this.editChartModal.cancelButtonText = 'Cancel';
this.editChartModal.okButtonLeft = false;
this.editChartModal.alertMessage = false;
if (this.index === -1) {
this.editChartModal.alertTitle = 'Create a new chart indicator';
this.editChartModal.okButtonText = 'Save';
this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
this.editChartNotify.reset(this.notification.message);
} else {
this.editChartModal.alertTitle = 'Edit chart indicator\'s information';
this.editChartModal.okButtonText = 'Save Changes';
this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
;
this.editChartNotify.reset(this.notification.message);
}
this.editChartModal.stayOpen = true;
this.editChartModal.open(); this.editChartModal.open();
} }
@ -836,7 +909,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.setCharts(); this.setCharts();
this.setNumbers(); this.setNumbers();
this.initReorder(); this.initReorder();
if(properties.notificationsAPIURL) { if (properties.notificationsAPIURL) {
this.notification = NotificationUtils.importIndicators(this.user.fullname, this.stakeholder.alias); this.notification = NotificationUtils.importIndicators(this.user.fullname, this.stakeholder.alias);
this.notification.entity = this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index]._id; this.notification.entity = this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index]._id;
this.notification.name = this.user.firstname; this.notification.name = this.user.firstname;
@ -889,7 +962,23 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.loading = false; this.loading = false;
} }
reorderIndicators(sectionId: string, type: IndicatorType, reorder: Reorder) { moveIndicator(moveIndicator: MoveIndicator) {
this.editing = true;
let path = [
this.stakeholder._id,
this.stakeholder.topics[this.topicIndex]._id,
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
];
this.subscriptions.push(this.stakeholderService.moveIndicator(this.properties.monitorServiceAPIURL, path, moveIndicator).subscribe(subCategory => {
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex] = subCategory;
this.setCharts();
this.setNumbers();
this.editing = false;
}));
}
reorderIndicators(sectionId: string, type: IndicatorType, indicators: string[]) {
this.editing = true; this.editing = true;
let path = [ let path = [
this.stakeholder._id, this.stakeholder._id,
@ -898,7 +987,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
sectionId sectionId
]; ];
this.subscriptions.push(this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, reorder, type).subscribe(indicators => { this.subscriptions.push(this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicators).subscribe(indicators => {
if (type === 'chart') { if (type === 'chart') {
this.charts.find(section => section._id === sectionId).indicators = indicators; this.charts.find(section => section._id === sectionId).indicators = indicators;
this.setCharts(); this.setCharts();
@ -912,7 +1001,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
hasDifference(index: number, type: IndicatorType = 'chart'): boolean { hasDifference(index: number, type: IndicatorType = 'chart'): boolean {
let hasDifference = false; let hasDifference = false;
if(type === 'chart') { if (type === 'chart') {
this.chartIndicatorPaths.at(index).value.parameters.forEach(parameter => { this.chartIndicatorPaths.at(index).value.parameters.forEach(parameter => {
if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) { if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) {
hasDifference = true; hasDifference = true;
@ -921,7 +1010,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
}); });
return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !== return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !==
this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString(); this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString();
} else if(type === 'number') { } else if (type === 'number') {
let indicatorPath = this.numberIndicatorPaths.at(index).value; let indicatorPath = this.numberIndicatorPaths.at(index).value;
indicatorPath.parameters.forEach(parameter => { indicatorPath.parameters.forEach(parameter => {
if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) { if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) {
@ -942,12 +1031,12 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} }
refreshIndicator(type: IndicatorType = 'chart') { refreshIndicator(type: IndicatorType = 'chart') {
if(type === 'chart') { if (type === 'chart') {
this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths, 'chart'); this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths, 'chart');
this.indicator.indicatorPaths.forEach(indicatorPath => { this.indicator.indicatorPaths.forEach(indicatorPath => {
indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
}); });
} else if(type === 'number') { } else if (type === 'number') {
this.indicator = this.indicatorUtils.generateIndicatorByForm(this.numberIndicatorFb.value, this.indicator.indicatorPaths, 'number'); this.indicator = this.indicatorUtils.generateIndicatorByForm(this.numberIndicatorFb.value, this.indicator.indicatorPaths, 'number');
this.indicator.indicatorPaths.forEach((indicatorPath, index) => { this.indicator.indicatorPaths.forEach((indicatorPath, index) => {
this.validateJsonPath(index); this.validateJsonPath(index);
@ -1191,10 +1280,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
})); }));
} }
private checkForSchemaEnhancements(url: string) {
this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url) && this.properties.dashboard != 'irish';
}
migrateFromOldImportJsonFile(charts) { migrateFromOldImportJsonFile(charts) {
// first section contains numbers // first section contains numbers
// second contains charts // second contains charts
@ -1210,6 +1295,11 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
if (chart['sectionIndex'] == null) { if (chart['sectionIndex'] == null) {
chart['sectionIndex'] = chart['type'] == 'chart' ? chartsSection : 0; chart['sectionIndex'] = chart['type'] == 'chart' ? chartsSection : 0;
} }
if (chart.url && chart.jsonPath) {
chart.indicatorPaths = [{url: chart.url, jsonPath: chart.jsonPath}];
} else if(chart.url) {
chart.indicatorPaths = [{url: chart.url}];
}
} }
return charts; return charts;
} }
@ -1217,7 +1307,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
importIndicatorsAndSave(stakeholder: Stakeholder, charts: any[]) { importIndicatorsAndSave(stakeholder: Stakeholder, charts: any[]) {
let sectionsToSave: Section[] = []; let sectionsToSave: Section[] = [];
let countIndicators = 0; let countIndicators = 0;
if(stakeholder.type !== this.stakeholder.type) { if (stakeholder.type !== this.stakeholder.type) {
UIkit.notification("The type of this profile is not the same with the file's one!", { UIkit.notification("The type of this profile is not the same with the file's one!", {
status: 'warning', status: 'warning',
timeout: 6000, timeout: 6000,
@ -1230,23 +1320,25 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
let duplicates = 0; let duplicates = 0;
charts = this.migrateFromOldImportJsonFile(charts); charts = this.migrateFromOldImportJsonFile(charts);
for (let chart of charts) { for (let chart of charts) {
chart.visibility = this.showVisibility?chart.visibility:this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities); chart.visibility = this.showVisibility ? chart.visibility : this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities);
if (!sectionsToSave[chart['sectionIndex']]) { if (!sectionsToSave[chart['sectionIndex']]) {
let sectionToSave = new Section(chart['sectionType'] ? chart['sectionType'] : chart['type'], chart['sectionTitle']); let sectionToSave = new Section(chart['sectionType'] ? chart['sectionType'] : chart['type'], chart['sectionTitle']);
sectionToSave.indicators = []; sectionToSave.indicators = [];
sectionsToSave[chart['sectionIndex']] = sectionToSave; sectionsToSave[chart['sectionIndex']] = sectionToSave;
} }
let exists = false; let exists = false;
let indicatorPath; let indicatorPaths: IndicatorPath[] = [];
// validate indicators' schema from file // validate indicators' schema from file
let invalid_file_message; let invalid_file_message;
if (!chart.type) { if (!chart.type) {
invalid_file_message = "No indicator type is specified. Type should be chart or number."; invalid_file_message = "No indicator type is specified. Type should be chart or number.";
} else if (chart.type != "chart" && chart.type != "number") { } else if (chart.type != "chart" && chart.type != "number") {
invalid_file_message = "Invalid indicator type. Type should be chart or number."; invalid_file_message = "Invalid indicator type. Type should be chart or number.";
} else if (chart.type == "number" && !chart.jsonPath) { } else if (chart.indicatorPaths.length === 0) {
invalid_file_message = "No indicator paths are specified."
} else if (chart.type == "number" && chart.indicatorPaths.filter(path => !path.jsonPath).length > 0) {
invalid_file_message = "No jsonPath is specified for number indicator." invalid_file_message = "No jsonPath is specified for number indicator."
} else if (!chart.url) { } else if (chart.indicatorPaths.filter(path => !path.url).length > 0) {
invalid_file_message = "No indicator url is specified."; invalid_file_message = "No indicator url is specified.";
} }
@ -1261,29 +1353,38 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} }
if (chart.type == "chart") { if (chart.type == "chart") {
indicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(chart.url), chart.url, chart.type, stakeholder); indicatorPaths = chart.indicatorPaths.map(path => this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(path.url), path.url, chart.type, stakeholder));
for (let section of this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts.forEach((section: Section) => {
for (let chart of section.indicators) { section.indicators.forEach(indicator => {
if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) { indicator.indicatorPaths.forEach(path => {
duplicates++; let size = indicatorPaths.length;
exists = true; indicatorPaths = indicatorPaths.filter(indicatorPath => JSON.stringify(path.chartObject) !== JSON.stringify(indicatorPath.chartObject))
} if (indicatorPaths.length < size) {
} duplicates = duplicates + (size - indicatorPaths.length);
} exists = true;
}
});
});
});
} else if (chart.type == "number") { } else if (chart.type == "number") {
indicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(chart.url), chart.url, stakeholder, indicatorPaths = chart.indicatorPaths.map(path =>
chart.jsonPath, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(chart.url))); this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(path.url), path.url,
for (let section of this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers) { stakeholder, path.jsonPath, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(path.url))));
for (let chart of section.indicators) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers.forEach((section: Section) => {
if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) { section.indicators.forEach(indicator => {
duplicates++; indicator.indicatorPaths.forEach(path => {
exists = true; let size = indicatorPaths.length;
} indicatorPaths = indicatorPaths.filter(indicatorPath => JSON.stringify(path.chartObject) !== JSON.stringify(indicatorPath.chartObject))
} if (indicatorPaths.length < size) {
} duplicates = duplicates + (size - indicatorPaths.length);
exists = true;
}
});
});
});
} }
if (!exists) { if (indicatorPaths.length > 0) {
let i: Indicator = new Indicator(chart.name, chart.description, chart.additionalDescription, chart.type, chart.width, chart.height, this.showVisibility?"RESTRICTED":this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities), [indicatorPath]); let i: Indicator = new Indicator(chart.name, chart.description, chart.additionalDescription, chart.type, chart.width, chart.height, this.showVisibility ? "RESTRICTED" : this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities), indicatorPaths);
sectionsToSave[chart['sectionIndex']].indicators.push(i); sectionsToSave[chart['sectionIndex']].indicators.push(i);
countIndicators++; countIndicators++;
} }
@ -1315,36 +1416,41 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
let indexIndicator: number = 0; let indexIndicator: number = 0;
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].numbers.forEach(section => { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].numbers.forEach(section => {
section.indicators.forEach(indicator => { section.indicators.forEach(indicator => {
indicator.indicatorPaths.forEach(indicatorPath => { indicators[indexIndicator] = {
indicators[indexIndicator] = { "indicatorPaths": indicator.indicatorPaths.map(path => {
"type": indicator.type, "name": indicator.name, "jsonPath": indicatorPath.jsonPath, return {
"description": indicator.description, "additionalDescription": indicator.additionalDescription, jsonPath: path.jsonPath,
"visibility": indicator.visibility, "width": indicator.width, "height": indicator.height, url: this.indicatorUtils.getNumberUrl(path.source, this.indicatorUtils.getFullUrl(this.stakeholder, path))
"url": this.indicatorUtils.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)), }
"sectionTitle": section.title, }),
"sectionType": section.type, "type": indicator.type, "name": indicator.name,
"sectionIndex": index "description": indicator.description, "additionalDescription": indicator.additionalDescription,
}; "visibility": indicator.visibility, "width": indicator.width, "height": indicator.height,
indexIndicator++; "sectionTitle": section.title,
}); "sectionType": section.type,
"sectionIndex": index
};
indexIndicator++;
}); });
index++; index++;
}); });
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].charts.forEach(section => { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].charts.forEach(section => {
section.indicators.forEach(indicator => { section.indicators.forEach(indicator => {
indicator.indicatorPaths.forEach(indicatorPath => { indicators[indexIndicator] = {
indicators[indexIndicator] = { "indicatorPaths": indicator.indicatorPaths.map(path => {
"type": indicator.type, "name": indicator.name, return {
"description": indicator.description, "additionalDescription": indicator.additionalDescription, url: this.getUrlByStakeHolder(path)
"visibility": indicator.visibility, "width": indicator.width, "height": indicator.height, }
"url": this.getUrlByStakeHolder(indicatorPath), }),
"sectionTitle": section.title, "type": indicator.type, "name": indicator.name,
"sectionType": section.type, "description": indicator.description, "additionalDescription": indicator.additionalDescription,
"sectionIndex": index "visibility": indicator.visibility, "width": indicator.width, "height": indicator.height,
}; "sectionTitle": section.title,
indexIndicator++; "sectionType": section.type,
}); "sectionIndex": index
};
indexIndicator++;
}); });
index++; index++;
@ -1404,7 +1510,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
this.makeFileRequest(this.properties.utilsService + '/upload?type=json', [], this.filesToUpload).then(async (result: string) => { this.makeFileRequest(this.properties.utilsService + '/upload?type=json', [], this.filesToUpload).then(async (result: string) => {
let json = JSON.parse(result); let json = JSON.parse(result);
// validate file // validate file
if(json && Array.isArray(json)) { if (json && Array.isArray(json)) {
UIkit.notification("This file is not supported any more. Please export indicators and try again!", { UIkit.notification("This file is not supported any more. Please export indicators and try again!", {
status: 'danger', status: 'danger',
timeout: 6000, timeout: 6000,
@ -1466,4 +1572,8 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
document.body.removeChild(tempBox); document.body.removeChild(tempBox);
NotificationHandler.rise('Copied to clipboard'); NotificationHandler.rise('Copied to clipboard');
} }
get isEditable(): boolean {
return this.stakeholder.copy || this.stakeholder.defaultId == null || this.stakeholder.defaultId == '-1';
}
} }

View File

@ -28,12 +28,15 @@
</span> </span>
<span class="uk-margin-xsmall-left hide-on-close" [class.uk-invisible-hover]="topicIndex !== i" <span class="uk-margin-xsmall-left hide-on-close" [class.uk-invisible-hover]="topicIndex !== i"
(click)="$event.stopPropagation();$event.preventDefault()"> (click)="$event.stopPropagation();$event.preventDefault()">
<a class="uk-link-reset uk-flex uk-flex-middle"> <icon *ngIf="!isEditable && showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(topic.visibility)"
ratio="0.6"></icon>
<a *ngIf="isEditable && (isCurator || showVisibility)" class="uk-link-reset uk-flex uk-flex-middle">
<icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(topic.visibility)" <icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(topic.visibility)"
ratio="0.6"></icon> ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; flip: false; container: body"> <div #element *ngIf="isEditable && (isCurator || showVisibility)"
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; flip: false; container: body">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
<li> <li>
@ -106,12 +109,14 @@
<span class="uk-width-expand uk-text-truncate">{{category.name}}</span> <span class="uk-width-expand uk-text-truncate">{{category.name}}</span>
<span class="uk-margin-xsmall-left hide-on-close" [class.uk-invisible-hover]="categoryIndex !== j" <span class="uk-margin-xsmall-left hide-on-close" [class.uk-invisible-hover]="categoryIndex !== j"
(click)="$event.stopPropagation();$event.preventDefault()"> (click)="$event.stopPropagation();$event.preventDefault()">
<a class="uk-link-reset uk-flex uk-flex-middle"> <icon *ngIf="!isEditable && showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(category.visibility)"
ratio="0.6"></icon>
<a *ngIf="isEditable && (isCurator || showVisibility)" class="uk-link-reset uk-flex uk-flex-middle">
<icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(category.visibility)" <icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(category.visibility)"
ratio="0.6"></icon> ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element <div #element *ngIf="isEditable && (isCurator || showVisibility)"
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; flip: false; container: body"> uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; flip: false; container: body">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
@ -175,7 +180,7 @@
</div> </div>
</a> </a>
</li> </li>
<li *ngIf="isCurator"> <li *ngIf="isCurator && isEditable">
<a (click)="editCategoryOpen(); $event.preventDefault()" class="uk-flex uk-flex-middle"> <a (click)="editCategoryOpen(); $event.preventDefault()" class="uk-flex uk-flex-middle">
<icon name="add" [flex]="true"></icon> <icon name="add" [flex]="true"></icon>
<span class="hide-on-close">Create new category</span> <span class="hide-on-close">Create new category</span>
@ -183,7 +188,7 @@
</li> </li>
</ul> </ul>
</li> </li>
<li *ngIf="isCurator" class="hide-on-close"> <li *ngIf="isCurator && isEditable" class="hide-on-close">
<a (click)="editTopicOpen(-1); $event.preventDefault()"> <a (click)="editTopicOpen(-1); $event.preventDefault()">
<div class="uk-flex uk-flex-middle"> <div class="uk-flex uk-flex-middle">
<div class="uk-width-auto"> <div class="uk-width-auto">
@ -217,10 +222,6 @@
[queryParams]="{view: 'RESTRICTED'}" [queryParams]="{view: 'RESTRICTED'}"
(click)="hide(element)">Restricted view</a> (click)="hide(element)">Restricted view</a>
</li> </li>
<!--<li class="disabled"><a class="uk-disabled uk-text-muted"
uk-tooltip="Note: available only in administration dashboard"
(click)="hide(element)">Private view</a>
</li>-->
</ul> </ul>
</div> </div>
</div> </div>
@ -235,12 +236,15 @@
<span class="uk-flex uk-flex-column uk-flex-center uk-margin-small-left" <span class="uk-flex uk-flex-column uk-flex-center uk-margin-small-left"
[class.uk-invisible-hover]="subCategoryIndex !== i" [class.uk-invisible-hover]="subCategoryIndex !== i"
(click)="$event.stopPropagation();$event.preventDefault()"> (click)="$event.stopPropagation();$event.preventDefault()">
<a class="uk-link-reset uk-flex uk-flex-middle"> <icon *ngIf="!isEditable && showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(subCategory.visibility)"
ratio="0.6"></icon>
<a *ngIf="isEditable && (isCurator || showVisibility)" class="uk-link-reset uk-flex uk-flex-middle">
<icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(subCategory.visibility)" <icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(subCategory.visibility)"
ratio="0.6"></icon> ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; container: body"> <div #element *ngIf="isEditable && (isCurator || showVisibility)"
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; container: body">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
<li> <li>
@ -318,7 +322,7 @@
</span> </span>
</li> </li>
</ng-template> </ng-template>
<li *ngIf="isCurator"> <li *ngIf="isCurator && isEditable">
<a (click)="editSubCategoryOpen(); $event.preventDefault()" class="uk-flex uk-flex-middle"> <a (click)="editSubCategoryOpen(); $event.preventDefault()" class="uk-flex uk-flex-middle">
<icon name="add" [flex]="true"></icon> <icon name="add" [flex]="true"></icon>
<span class="uk-text-uppercase">Create new subcategory</span> <span class="uk-text-uppercase">Create new subcategory</span>

View File

@ -359,6 +359,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
this.stakeholder.topics.splice(this.index, 1); this.stakeholder.topics.splice(this.index, 1);
if(this.topicIndex === this.index) { if(this.topicIndex === this.index) {
this.chooseTopic(Math.max(0, this.index - 1)); this.chooseTopic(Math.max(0, this.index - 1));
} else if(this.topicIndex > this.index) {
this.chooseTopic(this.topicIndex - 1);
} }
}, true); }, true);
}; };
@ -500,6 +502,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1); this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1);
if(this.categoryIndex === this.index) { if(this.categoryIndex === this.index) {
this.chooseCategory(Math.max(0, this.index - 1)); this.chooseCategory(Math.max(0, this.index - 1));
} else if(this.categoryIndex > this.index) {
this.chooseCategory(this.categoryIndex - 1);
} }
}, true); }, true);
}; };
@ -640,6 +644,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories.splice(this.index, 1); this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories.splice(this.index, 1);
if(this.subCategoryIndex === this.index) { if(this.subCategoryIndex === this.index) {
this.chooseSubcategory(Math.max(0, this.index - 1)); this.chooseSubcategory(Math.max(0, this.index - 1));
} else if(this.subCategoryIndex > this.index) {
this.chooseSubcategory(this.subCategoryIndex - 1);
} }
}, true); }, true);
}; };
@ -777,4 +783,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
this.visibilityModal.alertFooter = false; this.visibilityModal.alertFooter = false;
this.visibilityModal.open(); this.visibilityModal.open();
} }
get isEditable(): boolean {
return this.stakeholder.copy || this.stakeholder.defaultId == null || this.stakeholder.defaultId == '-1';
}
} }

View File

@ -20,11 +20,12 @@ import {TransitionGroupModule} from "../../utils/transition-group/transition-gro
import {NumberRoundModule} from "../../utils/pipes/number-round.module"; import {NumberRoundModule} from "../../utils/pipes/number-round.module";
import {SideBarModule} from "../../dashboard/sharedComponents/sidebar/sideBar.module"; import {SideBarModule} from "../../dashboard/sharedComponents/sidebar/sideBar.module";
import {SidebarMobileToggleModule} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module"; import {SidebarMobileToggleModule} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module";
import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module";
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, TopicRoutingModule, ClickModule, RouterModule, FormsModule, AlertModalModule, CommonModule, TopicRoutingModule, ClickModule, RouterModule, FormsModule, AlertModalModule,
ReactiveFormsModule, InputModule, IconsModule, PageContentModule, LoadingModule, NotifyFormModule, LogoUrlPipeModule, TransitionGroupModule, NumberRoundModule, SideBarModule, SidebarMobileToggleModule ReactiveFormsModule, InputModule, IconsModule, PageContentModule, LoadingModule, NotifyFormModule, LogoUrlPipeModule, TransitionGroupModule, NumberRoundModule, SideBarModule, SidebarMobileToggleModule, SliderTabsModule
], ],
declarations: [ declarations: [
TopicComponent, IndicatorsComponent TopicComponent, IndicatorsComponent

View File

@ -7,16 +7,19 @@ import {
IndicatorPathType, IndicatorPathType,
IndicatorType, IndicatorType,
SourceType, SourceType,
Stakeholder, SubCategory, Stakeholder,
Topic,
Visibility, Visibility,
} from "../../monitor/entities/stakeholder"; } from "../../monitor/entities/stakeholder";
import {AbstractControl, ValidatorFn, Validators} from "@angular/forms"; import {AbstractControl, ValidatorFn, Validators} from "@angular/forms";
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
import {Session} from "../../login/utils/helper.class"; import {Session} from "../../login/utils/helper.class";
import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {properties} from "src/environments/environment"; import {properties} from "src/environments/environment";
class Roles {
manager = 'manager';
member = 'member';
}
class Entities { class Entities {
stakeholder = 'Dashboard'; stakeholder = 'Dashboard';
funder = 'Funder'; funder = 'Funder';
@ -36,7 +39,13 @@ class Entities {
researchers = 'Researchers'; researchers = 'Researchers';
} }
export interface OAIndicator {
numerator: IndicatorPath;
denominator: IndicatorPath;
}
export class StakeholderConfiguration { export class StakeholderConfiguration {
public static ROLES: Roles = new Roles();
public static ENTITIES: Entities = new Entities(); public static ENTITIES: Entities = new Entities();
public static TYPES: Option[] = [ public static TYPES: Option[] = [
{value: 'funder', label: StakeholderConfiguration.ENTITIES.funder}, {value: 'funder', label: StakeholderConfiguration.ENTITIES.funder},
@ -55,9 +64,16 @@ export class StakeholderConfiguration {
{icon: 'incognito', value: "PRIVATE", label: 'Private'}, {icon: 'incognito', value: "PRIVATE", label: 'Private'},
]; ];
public static CACHE_INDICATORS: boolean = true; public static CACHE_INDICATORS: boolean = true;
public static NUMBER_MULTI_INDICATOR_PATHS = false;
public static CHART_MULTI_INDICATOR_PATHS = true;
public static openAccess: Map<string, OAIndicator> = new Map();
} }
export class StakeholderUtils { export class StakeholderUtils {
get roles() {
return StakeholderConfiguration.ROLES;
}
get entities() { get entities() {
return StakeholderConfiguration.ENTITIES; return StakeholderConfiguration.ENTITIES;
} }
@ -82,6 +98,18 @@ export class StakeholderUtils {
return StakeholderConfiguration.CACHE_INDICATORS; return StakeholderConfiguration.CACHE_INDICATORS;
} }
get hasMultiNumberIndicatorPaths() {
return StakeholderConfiguration.NUMBER_MULTI_INDICATOR_PATHS;
}
get hasMultiChartIndicatorPaths() {
return StakeholderConfiguration.CHART_MULTI_INDICATOR_PATHS;
}
get openAccess(): Map<string, OAIndicator> {
return StakeholderConfiguration.openAccess;
}
visibilityIcon: Map<Visibility, string> = new Map<Visibility, string>(this.visibilities.map(option => [option.value, option.icon])); visibilityIcon: Map<Visibility, string> = new Map<Visibility, string>(this.visibilities.map(option => [option.value, option.icon]));
defaultValue(options: Option[]) { defaultValue(options: Option[]) {
@ -107,60 +135,6 @@ export class StakeholderUtils {
return types; return types;
} }
public createFunderFromDefaultProfile(funder: Stakeholder, defaultTopics: Topic[], isDefault: boolean = false): Stakeholder {
funder.topics = HelperFunctions.copy(defaultTopics);
for (let topic of funder.topics) {
topic.defaultId = !isDefault ? topic._id : null;
topic._id = null;
for (let category of topic.categories) {
category.defaultId = !isDefault ? category._id : null;
category._id = null;
let subTokeep: SubCategory[] = [];
for (let subCategory of category.subCategories) {
subCategory.defaultId = !isDefault ? subCategory._id : null;
subCategory._id = null;
subTokeep.push(subCategory);
for (let section of subCategory.charts) {
let chartsTokeep: Indicator[] = [];
section.defaultId = !isDefault ? section._id : null;
section.stakeholderAlias = funder.alias;
section._id = null;
for (let indicator of section.indicators) {
indicator.defaultId = !isDefault ? indicator._id : null;
indicator._id = null;
chartsTokeep.push(indicator);
for (let indicatorPath of indicator.indicatorPaths) {
if (indicatorPath.parameters) {
Object.keys(indicatorPath.parameters).forEach(key => {
if (key == "index_name") {
indicatorPath.parameters[key] = funder.index_name;
} else if (key == "index_id") {
indicatorPath.parameters[key] = funder.index_id;
} else if (key == "index_shortName") {
indicatorPath.parameters[key] = funder.index_shortName.toLowerCase();
}
});
}
}
}
section.indicators = chartsTokeep;
}
for (let section of subCategory.numbers) {
section.defaultId = !isDefault ? section._id : null;
section.stakeholderAlias = funder.alias;
section._id = null;
for (let indicator of section.indicators) {
indicator.defaultId = !isDefault ? indicator._id : null;
indicator._id = null;
}
}
}
category.subCategories = subTokeep;
}
}
return funder;
}
aliasValidatorString(elements: string[]): ValidatorFn { aliasValidatorString(elements: string[]): ValidatorFn {
return (control: AbstractControl): { [key: string]: string } | null => { return (control: AbstractControl): { [key: string]: string } | null => {
@ -588,11 +562,11 @@ export class IndicatorUtils {
filterApplied = true; filterApplied = true;
} else if (filterType == "start_year" || filterType == "end_year") { } else if (filterType == "start_year" || filterType == "end_year") {
//if has date filter already //if has date filter already
if (filterType == "start_year" && parseInt(filterValue) > parseInt(queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0])) { // if (filterType == "start_year" && parseInt(filterValue) > parseInt(queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0])) {
queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0] = filterValue; queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0] = filterValue;
} else if (filterType == "end_year" && parseInt(filterValue) < parseInt(queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0])) { // } else if (filterType == "end_year" && parseInt(filterValue) < parseInt(queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0])) {
queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0] = filterValue; queries["query"]["filters"][filterposition.filter]['groupFilters'][filterposition.groupFilter]["values"][0] = filterValue;
} // }
filterApplied = true; filterApplied = true;
} }
} else { } else {

View File

@ -0,0 +1,113 @@
import {ChangeDetectorRef, Directive, OnInit} from "@angular/core";
import {StakeholderBaseComponent} from "../../monitor-admin/utils/stakeholder-base.component";
import {OpenaireEntities} from "../../utils/properties/searchFields";
import {StakeholderType} from "../entities/stakeholder";
import {Option} from "../../sharedComponents/input/input.component";
import {FormBuilder, FormControl} from "@angular/forms";
import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service";
import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {debounceTime, distinctUntilChanged} from "rxjs/operators";
@Directive()
export class BrowseStakeholderBaseComponent<T> extends StakeholderBaseComponent implements OnInit {
openaireEntities = OpenaireEntities;
stakeholderType: StakeholderType;
stakeholders: T[] = [];
filteredStakeholders: T[] = [];
showLoading: boolean = true;
isMobile: boolean = false;
gridView: boolean = true;
sortOptions: Option[] = [
{value: 'alphAsc', label: 'Alphabetically Asc. (A-Z)'},
{value: 'alphDsc', label: 'Alphabetically Dsc. (Z-A)'},
];
pageOptions: number[] = [10, 20, 30, 40];
sortBy: string = null;
currentPage: number = 1;
pageSize: number = 10;
parameters = {};
keywordControl: FormControl;
hasPublications: boolean = true;
/* Services */
protected layoutService: LayoutService;
protected cdr: ChangeDetectorRef;
protected fb: FormBuilder;
constructor() {
super();
}
ngOnInit() {
this.keywordControl = this.fb.control(this._route.snapshot.queryParams.keyword);
this.subscriptions.push(this.layoutService.isMobile.subscribe(isMobile => {
this.isMobile = isMobile;
this.cdr.detectChanges();
}));
this.stakeholderType = this._route.snapshot.data.type;
if (!this.stakeholderType) {
this.navigateToError();
}
this.init();
this.subscriptions.push(this.keywordControl.valueChanges.pipe(debounceTime(200), distinctUntilChanged()).subscribe(value => {
this.filtering(value);
if (value?.length > 0) {
this.parameters['keyword'] = value;
} else {
delete this.parameters['keyword']
}
this._router.navigate([], {queryParams: this.parameters});
}));
}
init() {
this.stakeholders = [];
this.filteredStakeholders = [];
}
protected filtering(value) {
if (!value) {
this.filteredStakeholders = this.stakeholders;
} else {
this.filteredStakeholders = this.stakeholders.filter(item => (item['name'] && item['name'].toLowerCase().includes(value.toLowerCase())) || (item['alias'] && item['alias'].toLowerCase().includes(value.toLowerCase())));
}
this.afterStakeholdersInitialized();
this.currentPage = 1;
}
sortByChanged() {
switch (this.sortBy) {
case 'alphAsc':
this.stakeholders = this.stakeholders.sort((a, b) => a['name'].localeCompare(b['name']));
break;
case 'alphDsc':
this.stakeholders = this.stakeholders.sort((a, b) => b['name'].localeCompare(a['name']));
break;
default:
break;
}
}
sizeChanged($event) {
this.pageSize = $event;
this.currentPage = 1;
this.afterStakeholdersInitialized();
}
updateCurrentPage($event) {
this.currentPage = $event.value;
HelperFunctions.scrollToId('target');
this.afterStakeholdersInitialized();
}
get typeAsLabel() {
return this.stakeholderUtils.types.find(type => type.value === this.stakeholderType).label;
}
afterStakeholdersInitialized() {
// this is a method that will be overriden from the components extending this base component, if needed
this.showLoading = false;
}
}

View File

@ -37,6 +37,7 @@ export class Stakeholder {
isUpload: boolean = false; isUpload: boolean = false;
description: string; description: string;
topics: any[]; topics: any[];
copy: boolean = true;
details?: any; details?: any;
constructor(_id: string, type: StakeholderType, index_id: string, index_name: string, index_shortName: string, alias: string, visibility: Visibility, logoUrl: string, defaultId: string = null, description: string = null) { constructor(_id: string, type: StakeholderType, index_id: string, index_name: string, index_shortName: string, alias: string, visibility: Visibility, logoUrl: string, defaultId: string = null, description: string = null) {
@ -50,6 +51,7 @@ export class Stakeholder {
this.visibility = visibility; this.visibility = visibility;
this.logoUrl = logoUrl; this.logoUrl = logoUrl;
this.description = description; this.description = description;
this.copy = !!this.defaultId && this.defaultId !== '-1';
this.topics = []; this.topics = [];
} }
@ -183,6 +185,7 @@ export class Indicator {
visibility: Visibility; visibility: Visibility;
defaultId: string; defaultId: string;
indicatorPaths: IndicatorPath[]; indicatorPaths: IndicatorPath[];
activePath: number = 0;
overlay: Overlay = false; overlay: Overlay = false;
constructor(name: string, description: string, additionalDescription:string, type: IndicatorType, width: IndicatorSize,height: IndicatorSize, visibility: Visibility, indicatorPaths: IndicatorPath[], defaultId: string = null) { constructor(name: string, description: string, additionalDescription:string, type: IndicatorType, width: IndicatorSize,height: IndicatorSize, visibility: Visibility, indicatorPaths: IndicatorPath[], defaultId: string = null) {
@ -204,7 +207,7 @@ export class IndicatorPath {
type: IndicatorPathType; type: IndicatorPathType;
source: SourceType; source: SourceType;
url: string; url: string;
safeResourceUrl: SafeResourceUrl; // initialize on front end safeResourceUrl?: SafeResourceUrl; // initialize on front end
jsonPath: string[]; jsonPath: string[];
chartObject: string; chartObject: string;
parameters: any; parameters: any;
@ -293,7 +296,7 @@ export class IndicatorFilterUtils {
} }
static getFieldForTable(field, table){ static getFieldForTable(field, table){
if(["publication", "software", "dataset", "other", "result"].indexOf(table)!=-1 && IndicatorFilterUtils.filteredFields[field]["result"]){ if(["publication", "software", "dataset", "other", "result"].indexOf(table)!=-1 && IndicatorFilterUtils.filteredFields[field]["result"]){
return IndicatorFilterUtils.filteredFields[field]["result"]; return IndicatorFilterUtils.filteredFields[field]["result"].replace("result.",table + ".");
}else{ }else{
return IndicatorFilterUtils.filteredFields[field][table]; return IndicatorFilterUtils.filteredFields[field][table];
} }

View File

@ -53,7 +53,6 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
minYear = Dates.currentYear - 20; minYear = Dates.currentYear - 20;
maxYear = Dates.currentYear; maxYear = Dates.currentYear;
public numberResults: Map<string, number> = new Map<string, number>(); public numberResults: Map<string, number> = new Map<string, number>();
public chartsActiveType: Map<string, IndicatorPath> = new Map<string, IndicatorPath>();
public clipboard; public clipboard;
/** Services */ /** Services */
@ -214,15 +213,17 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
(this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : ""); (this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : "");
//clear numbers when filters change //clear numbers when filters change
this.numberResults.clear(); this.numberResults.clear();
let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>(); let urls: Map<string, [number, number, number][]> = new Map<string, [number, number, number][]>();
this.activeSubCategory.numbers.forEach((section, i) => { this.activeSubCategory.numbers.forEach((section, i) => {
section.indicators.forEach((number, j) => { section.indicators.forEach((number, j) => {
if (this.hasPermission(number.visibility)) { if (this.hasPermission(number.visibility)) {
let url = this.getFullUrl(number.indicatorPaths[0]); number.indicatorPaths.forEach((indicatorPath, k) => {
const pair = JSON.stringify([number.indicatorPaths[0].source, url]); let url = this.getFullUrl(indicatorPath);
const indexes = urls.get(pair) ? urls.get(pair) : []; const pair = JSON.stringify([indicatorPath.source, url]);
indexes.push([i, j]); const indexes = urls.get(pair) ? urls.get(pair) : [];
urls.set(pair, indexes); indexes.push([i, j, k]);
urls.set(pair, indexes);
})
} }
}); });
}); });
@ -231,10 +232,10 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
let activeSubcategory = this.activeSubCategory._id; let activeSubcategory = this.activeSubCategory._id;
this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => { this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => {
if(activeSubcategory === this.activeSubCategory._id) { if(activeSubcategory === this.activeSubCategory._id) {
indexes.forEach(([i, j]) => { indexes.forEach(([i, j, k]) => {
if( this.activeSubCategory?.numbers[i]?.indicators[j]) { if( this.activeSubCategory?.numbers[i]?.indicators[j]) {
let result = JSON.parse(JSON.stringify(response)); let result = JSON.parse(JSON.stringify(response));
this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => {
if (result) { if (result) {
result = result[jsonPath]; result = result[jsonPath];
} }
@ -247,7 +248,7 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
} else { } else {
result = 0; result = 0;
} }
this.numberResults.set(i + '-' + j, result); this.numberResults.set(i + '-' + j + '-' + k, result);
} }
}); });
} }
@ -255,10 +256,9 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
}); });
this.activeSubCategory.charts.forEach((section, i) => { this.activeSubCategory.charts.forEach((section, i) => {
section.indicators.forEach((indicator, j) => { section.indicators.forEach((indicator, j) => {
if (indicator.indicatorPaths.length > 0) { indicator.indicatorPaths.forEach((indicatorPath, k) => {
indicator.indicatorPaths[0].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[0]); indicator.indicatorPaths[k].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[k]);
this.chartsActiveType.set(i + '-' + j, indicator.indicatorPaths[0]); });
}
}); });
}); });
if (this.cdr && !(this.cdr as ViewRef).destroyed) { if (this.cdr && !(this.cdr as ViewRef).destroyed) {
@ -271,10 +271,12 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
this.indicatorUtils.getChartUrl(indicatorPath.source, this.getFullUrl(indicatorPath))); this.indicatorUtils.getChartUrl(indicatorPath.source, this.getFullUrl(indicatorPath)));
} }
public setActiveChart(i: number, j: number, type: string) { public getActiveIndicatorPath(indicator: Indicator) {
let activeChart = this.activeSubCategory.charts[i].indicators[j].indicatorPaths.filter(indicatorPath => indicatorPath.type === type)[0]; if(indicator.activePath) {
activeChart.safeResourceUrl = this.getUrlByStakeHolder(activeChart); return indicator.indicatorPaths[indicator.activePath];
this.chartsActiveType.set(i + '-' + j, activeChart); } else {
return indicator.indicatorPaths[0];
}
} }
public filter() { public filter() {

View File

@ -1,16 +1,21 @@
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {BehaviorSubject, from, Observable, Subscriber} from "rxjs"; import {BehaviorSubject, from, Observable, Subscriber} from "rxjs";
import {Indicator, Section, Stakeholder, StakeholderInfo, Visibility} from "../entities/stakeholder"; import {Indicator, Section, Stakeholder, StakeholderInfo, SubCategory, Visibility} from "../entities/stakeholder";
import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {map} from "rxjs/operators"; import {map} from "rxjs/operators";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {CustomOptions} from "../../services/servicesUtils/customOptions.class"; import {CustomOptions} from "../../services/servicesUtils/customOptions.class";
export interface Reorder { export interface SectionInfo {
action: 'moved' | 'added' | 'removed', id: string;
target: string, indicators: string[];
ids: string[]; }
export interface MoveIndicator {
target: string;
from: SectionInfo;
to: SectionInfo;
} }
@Injectable({ @Injectable({
@ -111,11 +116,15 @@ export class StakeholderService {
})); }));
} }
buildStakeholder(url: string, stakeholder: Stakeholder): Observable<Stakeholder> { buildStakeholder(url: string, stakeholder: Stakeholder, copyId: string): Observable<Stakeholder> {
if (stakeholder.alias && stakeholder.alias.startsWith('/')) { if (stakeholder.alias && stakeholder.alias.startsWith('/')) {
stakeholder.alias = stakeholder.alias.slice(1); stakeholder.alias = stakeholder.alias.slice(1);
} }
return this.http.post<Stakeholder>(url + '/build-stakeholder', stakeholder, CustomOptions.registryOptions()).pipe(map(stakeholder => { let copy = {
stakeholder: stakeholder,
copyId: copyId
}
return this.http.post<Stakeholder>(url + '/build-stakeholder', copy, CustomOptions.registryOptions()).pipe(map(stakeholder => {
return HelperFunctions.copy(Stakeholder.checkIsUpload(stakeholder)); return HelperFunctions.copy(Stakeholder.checkIsUpload(stakeholder));
})); }));
} }
@ -124,13 +133,12 @@ export class StakeholderService {
return this.http.post<Visibility>(url + '/' + path.join('/') + '/change-visibility' + '?visibility=' + visibility + (propagate ? '&propagate=true' : ''), null, CustomOptions.registryOptions()); return this.http.post<Visibility>(url + '/' + path.join('/') + '/change-visibility' + '?visibility=' + visibility + (propagate ? '&propagate=true' : ''), null, CustomOptions.registryOptions());
} }
saveElement(url: string, element: any, path: string[] = []): Observable<any> { saveElement(url: string, element: any, path: string[] = [], isFull: boolean = false): Observable<any> {
if (element.alias && element.alias.startsWith('/')) { if (element.alias && element.alias.startsWith('/')) {
element.alias = element.alias.slice(1); element.alias = element.alias.slice(1);
} }
path = HelperFunctions.encodeArray(path);
return this.http.post<any>(url + ((path.length > 0) ? '/' : '') + path.join('/') + return this.http.post<any>(url + ((path.length > 0) ? '/' : '') + path.join('/') +
'/save', element, CustomOptions.registryOptions()).pipe(map(element => { '/save' + (isFull?'/full':''), element, CustomOptions.registryOptions()).pipe(map(element => {
if (path.length === 0) { if (path.length === 0) {
return HelperFunctions.copy(Stakeholder.checkIsUpload(element)); return HelperFunctions.copy(Stakeholder.checkIsUpload(element));
} else { } else {
@ -140,7 +148,6 @@ export class StakeholderService {
} }
saveBulkElements(url: string, indicators, path: string[] = []): Observable<any> { saveBulkElements(url: string, indicators, path: string[] = []): Observable<any> {
path = HelperFunctions.encodeArray(path);
return this.http.post<any>(url + ((path.length > 0) ? '/' : '') + path.join('/') + return this.http.post<any>(url + ((path.length > 0) ? '/' : '') + path.join('/') +
'/save-bulk', indicators, CustomOptions.registryOptions()).pipe(map(element => { '/save-bulk', indicators, CustomOptions.registryOptions()).pipe(map(element => {
if (path.length === 0) { if (path.length === 0) {
@ -152,7 +159,6 @@ export class StakeholderService {
} }
saveSection(url: string, element: any, path: string[] = [], index: number = -1): Observable<Section> { saveSection(url: string, element: any, path: string[] = [], index: number = -1): Observable<Section> {
path = HelperFunctions.encodeArray(path);
return this.http.post<Section>(url + ((path.length > 0) ? '/' : '') + path.join('/') + return this.http.post<Section>(url + ((path.length > 0) ? '/' : '') + path.join('/') +
'/save/' + index, element, CustomOptions.registryOptions()).pipe(map(element => { '/save/' + index, element, CustomOptions.registryOptions()).pipe(map(element => {
return HelperFunctions.copy(element); return HelperFunctions.copy(element);
@ -160,7 +166,6 @@ export class StakeholderService {
} }
deleteElement(url: string, path: string[], childrenAction: string = null): Observable<any> { deleteElement(url: string, path: string[], childrenAction: string = null): Observable<any> {
path = HelperFunctions.encodeArray(path);
let params: string = ""; let params: string = "";
if (childrenAction) { if (childrenAction) {
params = "?children=" + childrenAction; params = "?children=" + childrenAction;
@ -169,17 +174,21 @@ export class StakeholderService {
} }
reorderElements(url: string, path: string[], ids: string[]): Observable<any> { reorderElements(url: string, path: string[], ids: string[]): Observable<any> {
path = HelperFunctions.encodeArray(path);
return this.http.post<any>(url + '/' + path.join('/') + '/reorder', ids, CustomOptions.registryOptions()); return this.http.post<any>(url + '/' + path.join('/') + '/reorder', ids, CustomOptions.registryOptions());
} }
reorderIndicators(url: string, path: string[], reorder: Reorder, type: string = 'chart'): Observable<Indicator[]> { reorderIndicators(url: string, path: string[], indicators: string[]): Observable<Indicator[]> {
path = HelperFunctions.encodeArray(path); return this.http.post<Indicator[]>(url + '/' + path.join('/') + '/reorder', indicators, CustomOptions.registryOptions()).pipe(map(indicators => {
return this.http.post<Indicator[]>(url + '/' + path.join('/') + '/' + type + '/reorder', reorder, CustomOptions.registryOptions()).pipe(map(indicators => {
return HelperFunctions.copy(indicators); return HelperFunctions.copy(indicators);
})); }));
} }
moveIndicator(url: string, path: string[], moveIndicator: MoveIndicator): Observable<SubCategory> {
return this.http.post<SubCategory>(url + '/' + path.join('/') + '/moveIndicator', moveIndicator, CustomOptions.registryOptions()).pipe(map(subCategory => {
return HelperFunctions.copy(subCategory);
}));
}
getStakeholderAsObservable(): Observable<Stakeholder> { getStakeholderAsObservable(): Observable<Stakeholder> {
return this.stakeholderSubject.asObservable(); return this.stakeholderSubject.asObservable();
} }

View File

@ -1,4 +1,4 @@
import {Component, Input, ViewChild} from '@angular/core'; import {ChangeDetectorRef, Component, Input, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {Subscriber, Subscription} from "rxjs"; import {Subscriber, Subscription} from "rxjs";
import {OrcidService} from "./orcid.service"; import {OrcidService} from "./orcid.service";
@ -85,7 +85,7 @@ declare var UIkit: any;
<ng-container *ngIf="!showOnlyUpdateButton"> <ng-container *ngIf="!showOnlyUpdateButton">
<span class="uk-margin-bottom uk-flex uk-flex-middle uk-flex-center"> <span class="uk-margin-bottom uk-flex uk-flex-middle uk-flex-center">
<span>ORCID&#160;</span> <span>ORCID&#160;</span>
<img src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt="" loading="lazy"> <img src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt="ORCID logo" loading="lazy">
<span>&#160;ACTIONS</span> <span>&#160;ACTIONS</span>
</span> </span>
@ -330,7 +330,8 @@ export class OrcidWorkComponent {
private _router: Router, private _router: Router,
private orcidService: OrcidService, private orcidService: OrcidService,
private resultLandingService: ResultLandingService, private resultLandingService: ResultLandingService,
private userManagementService: UserManagementService, private _logService: LogService, private _userProfileService: UserProfileService) { private userManagementService: UserManagementService, private _logService: LogService, private _userProfileService: UserProfileService,
private cdr: ChangeDetectorRef) {
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
this.tokenUrl = properties.orcidTokenURL this.tokenUrl = properties.orcidTokenURL
+ "client_id=" + properties.orcidClientId + "client_id=" + properties.orcidClientId
@ -444,6 +445,8 @@ export class OrcidWorkComponent {
this.subscriptions.push(this.orcidService.getPutCode(this.pids).subscribe( this.subscriptions.push(this.orcidService.getPutCode(this.pids).subscribe(
putCodes => { putCodes => {
this.putCodes = putCodes; this.putCodes = putCodes;
this.cdr.markForCheck();
// this.cdr.detectChanges();
}, error => { }, error => {
} }
@ -525,7 +528,9 @@ export class OrcidWorkComponent {
this.putCodes.push("" + response['put-code']); this.putCodes.push("" + response['put-code']);
this.creationDates.push(response['created-date']['value']); this.creationDates.push(response['created-date']['value']);
this.updateDates.push(response['last-modified-date']['value']); this.updateDates.push(response['last-modified-date']['value']);
this.cdr.markForCheck();
// this.cdr.detectChanges();
// this.closeGrantModal(); // this.closeGrantModal();
// this.message = "You have successfully added work with pids: "+this.pids+" in your ORCID record!"; // this.message = "You have successfully added work with pids: "+this.pids+" in your ORCID record!";
this.message = "You have successfully added work \"" + this.resultTitle + "\" in your ORCID record!"; this.message = "You have successfully added work \"" + this.resultTitle + "\" in your ORCID record!";
@ -701,6 +706,8 @@ export class OrcidWorkComponent {
deletedAll = false; deletedAll = false;
} else { } else {
this.putCodes.splice(i, 1); this.putCodes.splice(i, 1);
this.cdr.markForCheck();
// this.cdr.detectChanges();
this.creationDates.splice(i, 1); this.creationDates.splice(i, 1);
this.updateDates.splice(i, 1); this.updateDates.splice(i, 1);
// this.works.splice(i, 1); // this.works.splice(i, 1);

View File

@ -12,6 +12,8 @@ import {EmailService} from "../utils/email/email.service";
import {Composer} from "../utils/email/composer"; import {Composer} from "../utils/email/composer";
import {ClearCacheService} from "../services/clear-cache.service"; import {ClearCacheService} from "../services/clear-cache.service";
import {BaseComponent} from "../sharedComponents/base/base.component"; import {BaseComponent} from "../sharedComponents/base/base.component";
import {StakeholderUtils} from "../monitor-admin/utils/indicator-utils";
import {StringUtils} from "../utils/string-utils.class";
@Component({ @Component({
selector: 'role-verification', selector: 'role-verification',
@ -19,12 +21,9 @@ import {BaseComponent} from "../sharedComponents/base/base.component";
<modal-alert #managerModal [overflowBody]="false" (alertOutput)="verifyManager()" (cancelOutput)="cancel()" <modal-alert #managerModal [overflowBody]="false" (alertOutput)="verifyManager()" (cancelOutput)="cancel()"
[okDisabled]="code.invalid || loading"> [okDisabled]="code.invalid || loading">
<div> <div>
You have been invited to join <span You have been invited to join <span class="uk-text-bold">{{name}}</span> {{(dashboard)}} Dashboard as a {{stakeholderUtils.roles.manager}}.
class="uk-text-bold">{{name}}</span> {{(service === 'monitor' ? 'Monitor' : 'Research Community')}} Dashboard
as a manager.
<span class="uk-text-primary">Fill</span> in the <span class="uk-text-primary">verification code</span>, sent to <span class="uk-text-primary">Fill</span> in the <span class="uk-text-primary">verification code</span>, sent to
your your email, to accept the invitation request.
email, to accept the invitation request.
</div> </div>
<div *ngIf="!loading" class="uk-margin-medium-top uk-flex uk-flex-center"> <div *ngIf="!loading" class="uk-margin-medium-top uk-flex uk-flex-center">
<div input [formInput]="code" class="uk-width-medium" placeholder="Verification code"> <div input [formInput]="code" class="uk-width-medium" placeholder="Verification code">
@ -36,14 +35,12 @@ import {BaseComponent} from "../sharedComponents/base/base.component";
</div> </div>
</modal-alert> </modal-alert>
<modal-alert #memberModal [overflowBody]="false" (cancelOutput)="cancel()" <modal-alert #memberModal [overflowBody]="false" (cancelOutput)="cancel()"
(alertOutput)="verifyMember()" [okDisabled]="(code.invalid || loading) && !isMember"> (alertOutput)="verifyMember()" [okDisabled]="(code.invalid || loading)">
<div *ngIf="!isMember"> <div>
<div> <div>
You have been invited to join <span class="uk-text-bold">{{name}}</span> Monitor Dashboard as a member. You have been invited to join <span class="uk-text-bold">{{name}}</span> {{(dashboard)}} Dashboard as a {{stakeholderUtils.roles.member}}.
<span class="uk-text-primary">Fill</span> in the <span class="uk-text-primary">verification code</span>, sent <span class="uk-text-primary">Fill</span> in the <span class="uk-text-primary">verification code</span>, sent
to to your email, to accept the invitation request.
your
email, to accept the invitation request.
</div> </div>
<div *ngIf="!loading" class="uk-margin-medium-top uk-flex uk-flex-wrap uk-flex-center"> <div *ngIf="!loading" class="uk-margin-medium-top uk-flex uk-flex-wrap uk-flex-center">
<div input [formInput]="code" class="uk-width-medium" placeholder="Verification code"> <div input [formInput]="code" class="uk-width-medium" placeholder="Verification code">
@ -54,13 +51,6 @@ import {BaseComponent} from "../sharedComponents/base/base.component";
<loading></loading> <loading></loading>
</div> </div>
</div> </div>
<div *ngIf="isMember">
<div>
Welcome! You are now a member of the OpenAIRE Monitor Dashboard for the <span
class="uk-text-bold">{{name}}</span>!
From now on, you will have access to our restricted content.
</div>
</div>
</modal-alert> </modal-alert>
<modal-alert #errorModal (alertOutput)="cancel()" [overflowBody]="false"> <modal-alert #errorModal (alertOutput)="cancel()" [overflowBody]="false">
<div> <div>
@ -83,7 +73,7 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
public id: string; public id: string;
@Input() @Input()
set type(type: string) { set type(type: string) {
this._type = Role.GROUP + type; this._type = Role.GROUP + Role.mapType(type);
} }
@Input() @Input()
public name: string; public name: string;
@ -95,6 +85,8 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
public userInfoLink = null; public userInfoLink = null;
@Input() @Input()
public relativeTo: ActivatedRoute = this._route; public relativeTo: ActivatedRoute = this._route;
@Input()
public dashboard: string = 'Research Community';
public user: User; public user: User;
public verification: any; public verification: any;
public code: UntypedFormControl; public code: UntypedFormControl;
@ -105,8 +97,8 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
@ViewChild('errorModal') errorModal: AlertModal; @ViewChild('errorModal') errorModal: AlertModal;
public error: string = null; public error: string = null;
public loading: boolean = false; public loading: boolean = false;
public isMember: boolean = false; public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
constructor(protected _route: ActivatedRoute, constructor(protected _route: ActivatedRoute,
protected _router: Router, protected _router: Router,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
@ -117,18 +109,23 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
private cdr: ChangeDetectorRef) { private cdr: ChangeDetectorRef) {
super(); super();
} }
ngOnInit() { ngOnInit() {
this.reset(); this.reset();
} }
ngAfterViewInit() { ngAfterViewInit() {
this.init();
}
init() {
this.ngOnDestroy();
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user; this.user = user;
this.paramsSubscription = this._route.queryParams.subscribe(params => { this.paramsSubscription = this._route.queryParams.subscribe(params => {
if (params) { if (params) {
this.cdr.detectChanges(); this.cdr.detectChanges();
if(params['verify'] && !this.isMember) { if(params['verify']) {
if (this.user) { if (this.user) {
this.subscriptions.push(this.userRegistryService.getInvitation(params['verify']).subscribe(verification => { this.subscriptions.push(this.userRegistryService.getInvitation(params['verify']).subscribe(verification => {
this.verification = verification; this.verification = verification;
@ -155,51 +152,43 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
relativeTo: this.relativeTo relativeTo: this.relativeTo
}); });
} }
} else if(this.isMember) {
this.openMemberModal();
} }
} else { } else {
this.isMember = false;
this.cdr.detectChanges(); this.cdr.detectChanges();
} }
}); });
})); }));
} }
ngOnDestroy() { ngOnDestroy() {
super.ngOnDestroy(); super.ngOnDestroy();
if (this.paramsSubscription instanceof Subscription) { if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe(); this.paramsSubscription.unsubscribe();
} }
} }
public openManagerModal() { public openManagerModal() {
this.error = null; this.error = null;
this.managerModal.okButtonLeft = false; this.managerModal.okButtonLeft = false;
this.managerModal.okButtonText = 'Accept'; this.managerModal.okButtonText = 'Accept';
this.managerModal.stayOpen = true; this.managerModal.stayOpen = true;
this.managerModal.cancelButtonText = 'Cancel'; this.managerModal.cancelButtonText = 'Cancel';
this.managerModal.alertTitle = 'Manager Invitation'; this.managerModal.alertTitle = StringUtils.capitalize(this.stakeholderUtils.roles.manager) + ' Invitation';
this.managerModal.open(); this.managerModal.open();
} }
public openMemberModal() { public openMemberModal() {
this.error = null; this.error = null;
if(this.isMember) { this.memberModal.cancelButton = true;
this.memberModal.cancelButton = false; this.memberModal.okButtonText = 'Accept';
this.memberModal.okButtonText = 'Close';
} else {
this.memberModal.cancelButton = true;
this.memberModal.okButtonText = 'Accept';
}
this.memberModal.okButtonLeft = false; this.memberModal.okButtonLeft = false;
this.memberModal.stayOpen = true; this.memberModal.stayOpen = true;
this.memberModal.cancelButtonText = 'Cancel'; this.memberModal.cancelButtonText = 'Cancel';
this.memberModal.alertTitle = 'Member Invitation'; this.memberModal.alertTitle = StringUtils.capitalize(this.stakeholderUtils.roles.member) + ' Invitation';
this.cdr.detectChanges(); this.cdr.detectChanges();
this.memberModal.open(); this.memberModal.open();
} }
public openErrorModal() { public openErrorModal() {
this.error = null; this.error = null;
this.errorModal.cancelButton = false; this.errorModal.cancelButton = false;
@ -207,27 +196,20 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
this.errorModal.alertTitle = 'Invalid URL'; this.errorModal.alertTitle = 'Invalid URL';
this.errorModal.open(); this.errorModal.open();
} }
public verifyManager() { public verifyManager() {
this.loading = true; this.loading = true;
this.subscriptions.push(this.userRegistryService.verify(this.verification.id, this.code.value).subscribe(() => { this.subscriptions.push(this.userRegistryService.verify(this.verification.id, this.code.value).subscribe(() => {
this.clearCacheService.clearCache('Managers updated'); this.clearCacheService.clearCache('Managers updated');
this.managerModal.cancel(); this.managerModal.cancel();
this.error = null; this.error = null;
this.userManagementService.updateUserInfo(() => { if(this.service === "irish" || this.service === "monitor") {
if (this.paramsSubscription instanceof Subscription) { this.loading = false;
this.paramsSubscription.unsubscribe(); this.userManagementService.login(properties.domain + '/admin/' + this.verification.entity);
} } else {
if(this.service === "irish") { this.subscriptions.push(this.emailService.notifyManagers(this.id, 'manager',
this.loading = false;
this.userManagementService.login(properties.domain + '/admin/' + this.verification.entity);
} else if (this.service === "monitor" ) {
this.loading = false;
this._router.navigate(['/admin/' + this.verification.entity]);
} else {
this.subscriptions.push(this.emailService.notifyManagers(this.id, 'manager',
Composer.composeEmailToInformOldManagersForTheNewOnes(this.name, this.id)).subscribe(() => { Composer.composeEmailToInformOldManagersForTheNewOnes(this.name, this.id)).subscribe(() => {
this.subscriptions.push(this.emailService.notifyNewManager(Composer.composeEmailForNewManager(this.id, this.name)).subscribe( this.subscriptions.push(this.emailService.notifyNewManager(Composer.composeEmailForNewManager(this.id, this.name)).subscribe(
() => { () => {
this.loading = false; this.loading = false;
window.location.href = properties.adminPortalURL + '/' + this.verification.entity; window.location.href = properties.adminPortalURL + '/' + this.verification.entity;
@ -237,49 +219,38 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit,
this.loading = false; this.loading = false;
window.location.href = properties.adminPortalURL + '/' + this.verification.entity; window.location.href = properties.adminPortalURL + '/' + this.verification.entity;
} }
)); ));
}, error => { }, error => {
console.error(error); console.error(error);
this.loading = false; this.loading = false;
window.location.href = properties.adminPortalURL + '/' + this.verification.entity; window.location.href = properties.adminPortalURL + '/' + this.verification.entity;
})); }));
} }
});
}, error => { }, error => {
this.loading = false; this.loading = false;
this.error = 'The verification code is invalid'; this.error = 'The verification code is invalid';
})); }));
} }
public verifyMember() { public verifyMember() {
this.loading = true; this.loading = true;
if (!this.isMember) {
this.subscriptions.push(this.userRegistryService.verify(this.verification.id, this.code.value, "member").subscribe(() => { this.subscriptions.push(this.userRegistryService.verify(this.verification.id, this.code.value, "member").subscribe(() => {
this.clearCacheService.clearCache('Members updated'); this.clearCacheService.clearCache('Members updated');
this.memberModal.cancel();
this.loading = false; this.loading = false;
this.error = null; this.error = null;
this.isMember = true; window.location.href = window.location.href.split('?')[0];
this.userManagementService.updateUserInfo(() => {
if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe();
}
this.cancel();
});
}, error => { }, error => {
this.loading = false; this.loading = false;
this.error = 'The verification code is invalid'; this.error = 'The verification code is invalid';
})); }));
} else {
this.memberModal.cancel();
}
} }
public reset() { public reset() {
this.code = this.fb.control('', [Validators.required, Validators.pattern('^[+0-9]{6}$')]); this.code = this.fb.control('', [Validators.required, Validators.pattern('^[+0-9]{6}$')]);
} }
cancel() { cancel() {
this.isMember = false;
this._router.navigate([]); this._router.navigate([]);
} }
} }

View File

@ -34,9 +34,9 @@
</div> </div>
</div> </div>
<div class="uk-width-2-5@m uk-width-1-1@s uk-text-center uk-position-relative" uk-scrollspy-class> <div class="uk-width-2-5@m uk-width-1-1@s uk-text-center uk-position-relative" uk-scrollspy-class>
<img src="assets/common-assets/sdg/sdg-hero-img.svg" loading="lazy"> <img src="assets/common-assets/sdg/sdg-hero-img.svg" loading="lazy" alt="SDGs logo">
<div class="uk-position-bottom-left uk-card uk-card-default uk-padding"> <div class="uk-position-bottom-left uk-card uk-card-default uk-padding">
<img src="assets/common-assets/sdg/sdg-badge.png" loading="lazy" style="max-width: 215px"> <img src="assets/common-assets/sdg/sdg-badge.png" loading="lazy" style="max-width: 215px" alt="SDGs big logo">
</div> </div>
</div> </div>
</div> </div>
@ -61,7 +61,7 @@
</div> </div>
</div> </div>
<div class="uk-text-center"> <div class="uk-text-center">
<img [src]="'assets/common-assets/sdg/icons/g' + sdg.code + '.png'" alt=""> <img [src]="'assets/common-assets/sdg/icons/g' + sdg.code + '.png'" [alt]="'SDG code: '+sdg.code">
</div> </div>
<div class="uk-text-center uk-padding-small uk-background-default" style="border-radius: 0 0 4px 4px;"> <div class="uk-text-center uk-padding-small uk-background-default" style="border-radius: 0 0 4px 4px;">
<span class="uk-text-large uk-text-bold uk-margin-small-bottom">{{sdg.number == null ? '0' : sdg.number | number}}</span> <span class="uk-text-large uk-text-bold uk-margin-small-bottom">{{sdg.number == null ? '0' : sdg.number | number}}</span>

View File

@ -33,6 +33,7 @@ import {RefineFieldResultsService} from "../services/refineFieldResults.service"
[includeOnlyResultsAndFilter]="includeOnlyResultsAndFilter" [includeOnlyResultsAndFilter]="includeOnlyResultsAndFilter"
[searchForm]="searchForm" [searchForm]="searchForm"
[sort]="false" [sort]="false"
[showRefine]="refineFields?.length > 0"
[filters]="filters" [filters]="filters"
[simpleView]="simpleView" formPlaceholderText="Search by organization name..." [simpleView]="simpleView" formPlaceholderText="Search by organization name..."
[showSwitchSearchLink]="showSwitchSearchLink" [showSwitchSearchLink]="showSwitchSearchLink"

View File

@ -1,11 +1,11 @@
<ng-template #selected_filters_pills> <ng-template #selected_filters_pills>
<h1 class="uk-margin-remove"> <h1 class="uk-margin-remove">
<div [class.uk-invisible]="list.children.length === 0"> <div [class.uk-invisible]="list.children.length === 0" [class.uk-margin-top]="list.children.length > 0">
<ul #list class="uk-grid uk-grid-small uk-flex-wrap" uk-grid> <ul #list class="uk-grid uk-grid-small uk-flex-wrap" uk-grid>
<ng-container *ngFor="let customFilter of customFilters"> <ng-container *ngFor="let customFilter of customFilters">
<ng-container *ngIf="customFilter.isHiddenFilter"> <ng-container *ngIf="customFilter.isHiddenFilter">
<li class="uk-flex uk-flex-middle"> <li class="uk-flex uk-flex-middle">
<span class="uk-label uk-label-small uk-label-secondary uk-text-truncate target1"> <span class="uk-text-capitalize uk-label uk-label-small uk-label-secondary uk-text-truncate target1">
{{customFilter.valueName}} {{customFilter.valueName}}
</span> </span>
</li> </li>
@ -15,7 +15,7 @@
<ng-container *ngFor="let type of resultTypes.values; let i = index;"> <ng-container *ngFor="let type of resultTypes.values; let i = index;">
<ng-container *ngIf="type.selected"> <ng-container *ngIf="type.selected">
<li class=""> <li class="">
<span class="uk-label uk-label-small uk-label-primary uk-flex uk-flex-middle target2"> <span class="uk-text-capitalize uk-label uk-label-small uk-label-secondary uk-flex uk-flex-middle target2">
<span class="uk-margin-small-right uk-width-expand uk-text-truncate">{{type.name}}</span> <span class="uk-margin-small-right uk-width-expand uk-text-truncate">{{type.name}}</span>
<button [class.uk-disabled]="disabled" (click)="removeResultType(type.id)" class="uk-close uk-icon" [disabled]="disabled"> <button [class.uk-disabled]="disabled" (click)="removeResultType(type.id)" class="uk-close uk-icon" [disabled]="disabled">
<icon name="close" flex="true" ratio="0.7"></icon> <icon name="close" flex="true" ratio="0.7"></icon>
@ -29,7 +29,7 @@
<ng-container *ngFor="let filter of rangeFilters "> <ng-container *ngFor="let filter of rangeFilters ">
<ng-container *ngIf="filter.selectedFromAndToValues"> <ng-container *ngIf="filter.selectedFromAndToValues">
<li class=""> <li class="">
<span class="uk-label uk-label-small uk-label-primary uk-flex uk-flex-middle target3"> <span class="uk-text-capitalize uk-label uk-label-small uk-label-secondary uk-flex uk-flex-middle target3">
<span class="uk-margin-small-right uk-width-expand uk-text-truncate">{{filter.selectedFromAndToValues}}</span> <span class="uk-margin-small-right uk-width-expand uk-text-truncate">{{filter.selectedFromAndToValues}}</span>
<button [class.uk-disabled]="disabled" (click)="removeRangeFilter(filter)" class="uk-close uk-icon" [disabled]="disabled"> <button [class.uk-disabled]="disabled" (click)="removeRangeFilter(filter)" class="uk-close uk-icon" [disabled]="disabled">
<icon name="close" flex="true" ratio="0.7"></icon> <icon name="close" flex="true" ratio="0.7"></icon>
@ -44,7 +44,7 @@
<ng-container *ngFor="let value of getSelectedValues(filter); let i = index; let end = last; "> <ng-container *ngFor="let value of getSelectedValues(filter); let i = index; let end = last; ">
<li *ngIf="!customFilter || (customFilter.isHiddenFilter && customFilter.valueId != value.id)" <li *ngIf="!customFilter || (customFilter.isHiddenFilter && customFilter.valueId != value.id)"
class=""> class="">
<span class="uk-label uk-label-small uk-label-primary uk-flex uk-flex-middle target4"> <span class="uk-text-capitalize uk-label uk-label-small uk-label-secondary uk-flex uk-flex-middle target4">
<span <span
class="uk-margin-small-right uk-width-expand uk-text-truncate"> class="uk-margin-small-right uk-width-expand uk-text-truncate">
<ng-container *ngIf="filter.type && (filter.type == 'boolean' || filter.type == 'triplet') else noboolean"> <ng-container *ngIf="filter.type && (filter.type == 'boolean' || filter.type == 'triplet') else noboolean">
@ -73,7 +73,7 @@
<ng-container *ngIf="filter.countSelectedValues > 0"> <ng-container *ngIf="filter.countSelectedValues > 0">
<ng-container *ngFor="let value of getSelectedValues(filter); let i = index; let end = last; "> <ng-container *ngFor="let value of getSelectedValues(filter); let i = index; let end = last; ">
<li *ngIf="!customFilters || (customFilters[0].isHiddenFilter && customFilters[0].valueId != value.id)"> <li *ngIf="!customFilters || (customFilters[0].isHiddenFilter && customFilters[0].valueId != value.id)">
<span class="uk-label uk-label-small uk-label-primary uk-flex uk-flex-middle target5"> <span class="uk-text-capitalize uk-label uk-label-small uk-label-secondary uk-flex uk-flex-middle target5">
<span class="uk-margin-small-right uk-width-expand uk-text-truncate"> <span class="uk-margin-small-right uk-width-expand uk-text-truncate">
<ng-container *ngIf="filter.type && (filter.type == 'boolean' || filter.type == 'triplet') else noboolean"> <ng-container *ngIf="filter.type && (filter.type == 'boolean' || filter.type == 'triplet') else noboolean">
<span>{{filter.title}}: <span>{{filter.title}}:
@ -288,7 +288,15 @@
</div> </div>
<div class="uk-container uk-margin-top" [class.uk-container-large]="!mobile" [class.uk-container-expand]="mobile" [class.uk-padding-remove-horizontal]="mobile"> <div class="uk-container uk-margin-top" [class.uk-container-large]="!mobile" [class.uk-container-expand]="mobile" [class.uk-padding-remove-horizontal]="mobile">
<div class="uk-grid uk-margin-large-bottom" [class.uk-margin-top]="!mobile" uk-grid> <div class="uk-grid uk-margin-large-bottom" [class.uk-margin-top]="!mobile" uk-grid>
<div *ngIf="!mobile && showRefine && (results.length > 0 || (searchUtils.refineStatus == errorCodes.LOADING && searchUtils.status != errorCodes.LOADING) || (!hideFilters && <!-- <div *ngIf="!mobile && showRefine -->
<!-- && (searchUtils.refineStatus == errorCodes.DONE && ((orderedFilters && orderedFilters.length > 0) || (staticFilters && staticFilters.length > 0)-->
<!-- || (rangeFilters && rangeFilters.length > 0) || (filters && filters.length > 0)))-->
<!-- && (results.length > 0 || (searchUtils.refineStatus == errorCodes.LOADING && searchUtils.status != errorCodes.LOADING) || (!hideFilters &&-->
<!-- (existingFiltersWithValues > 0 || (selectedRangeFilters + selectedFilters + selectedTypesNum) > 0))) "-->
<!-- class="uk-width-1-4@m search-filters">-->
<!-- </div>-->
<div *ngIf="!mobile && showRefine
&& (results.length > 0 || (searchUtils.refineStatus == errorCodes.LOADING && searchUtils.status != errorCodes.LOADING) || (!hideFilters &&
(existingFiltersWithValues > 0 || (selectedRangeFilters + selectedFilters + selectedTypesNum) > 0))) " (existingFiltersWithValues > 0 || (selectedRangeFilters + selectedFilters + selectedTypesNum) > 0))) "
class="uk-width-1-4@m search-filters"> class="uk-width-1-4@m search-filters">
<ng-container *ngTemplateOutlet="filters_column; context: {}"></ng-container> <ng-container *ngTemplateOutlet="filters_column; context: {}"></ng-container>
@ -308,31 +316,47 @@
[href]="openaireLink+this.routerHelper.createQueryParamsString(this.parameterNames, this.parameterValues)" [href]="openaireLink+this.routerHelper.createQueryParamsString(this.parameterNames, this.parameterValues)"
target="_blank"> OpenAIRE - Explore</a>. target="_blank"> OpenAIRE - Explore</a>.
</div> </div>
<ng-container *ngIf="mobile">
<div class="uk-flex uk-flex-middle uk-child-width-auto uk-flex-between">
<!-- Total results, number of pages -->
<div class="uk-margin-remove-bottom uk-text-truncate" [class.uk-margin-medium-right]="!mobile" [class.uk-margin-right]="mobile" [class.uk-h6]="!mobile">
<ng-container *ngIf="results && searchUtils.totalResults > 0">
<span>{{searchUtils.totalResults|number}}</span>
<span class="uk-text-meta uk-text-capitalize"> {{type}}</span>
<ng-container *ngIf="searchTerm && simpleView">
<span class="uk-text-meta"> for </span>
<span class="uk-text-bold">{{searchTerm}}</span>
</ng-container>
<ng-container *ngIf="!simpleView && advancedSearchTerms > 0">
<span class="uk-text-bold"> ({{advancedSearchTerms}} rule{{advancedSearchTerms == 1 ? '' : 's'}} applied)</span>
</ng-container>
</ng-container>
<ng-container *ngIf="!loadPaging && oldTotalResults > 0 && searchUtils.status == errorCodes.LOADING">
<span>{{oldTotalResults|number}}</span>
<span class="uk-text-meta uk-text-capitalize"> {{type}}, page </span>
<span>{{searchUtils.page | number}}</span>
<span class="uk-text-meta"> of {{(totalPages(oldTotalResults)|number)}}</span>
</ng-container>
</div>
<!-- Download results --> <!-- Download results -->
<div *ngIf="showDownload && (searchUtils.status !== errorCodes.LOADING || !loadPaging)" <div *ngIf="mobile && showDownload && (searchUtils.status !== errorCodes.LOADING || !loadPaging)"
class="uk-margin-small-bottom uk-flex uk-flex-center"> class="uk-flex uk-flex-center">
<search-download <search-download
*ngIf="( entityType !='community' && entityType != 'stakeholder') && usedBy == 'search'" *ngIf="( entityType !='community' && entityType != 'stakeholder') && usedBy == 'search'"
[isDisabled]="disabled" [isDisabled]="disabled"
[type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults"> [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults">
</search-download> </search-download>
<ng-container *ngIf="properties.zenodoDumpUrl && entityType == 'result'"> <ng-container *ngIf="properties.zenodoDumpUrl && entityType == 'result'">
<a [href]="properties.zenodoDumpUrl" target="_blank" class=" uk-margin-left uk-button uk-button-link uk-flex uk-flex-middle"> <a [href]="properties.zenodoDumpUrl" target="_blank" class=" uk-margin-left uk-button uk-button-link uk-flex uk-flex-middle">
<img src="assets/common-assets/common/zenodoDump.png" width="20"><span class="uk-margin-xsmall-left">Data dump</span> <img src="assets/common-assets/common/zenodoDump.png" alt="Zenodo dump" width="20"><span class="uk-margin-xsmall-left">Data dump</span>
</a> </a>
</ng-container> </ng-container>
</div> </div>
</ng-container>
<div *ngIf="(searchUtils.status !== errorCodes.LOADING || !loadPaging) && !mobile" class="uk-flex uk-flex-top"> <div *ngIf="!mobile" class="uk-flex uk-flex-middle">
<!-- filters pills -->
<div class="uk-width-expand@m">
<ng-container *ngTemplateOutlet="selected_filters_pills;"></ng-container>
</div>
<div class="uk-width-auto@m uk-margin-medium-left uk-flex uk-flex-middle">
<div *ngIf="searchUtils.totalResults > 10 || sort || searchUtils.totalResults > searchUtils.size || <div *ngIf="searchUtils.totalResults > 10 || sort || searchUtils.totalResults > searchUtils.size ||
(!loadPaging && oldTotalResults > searchUtils.size && searchUtils.status == errorCodes.LOADING)" (!loadPaging && oldTotalResults > searchUtils.size && searchUtils.status == errorCodes.LOADING)"
class="uk-grid uk-flex-middle uk-child-width-1-1 uk-child-width-1-2@m" uk-grid> class="uk-grid uk-flex-middle uk-child-width-1-1 uk-child-width-1-2@m" uk-grid>
<div> <div>
<div class="uk-grid uk-flex-middle uk-grid-column-collapse" uk-grid> <div class="uk-grid uk-flex-middle uk-grid-column-collapse" uk-grid>
<search-sorting *ngIf="sort && searchUtils.totalResults > 0" <search-sorting *ngIf="sort && searchUtils.totalResults > 0"
@ -345,20 +369,27 @@
</div> </div>
<!-- Download results --> <!-- Download results -->
<div *ngIf="showDownload && (searchUtils.status !== errorCodes.LOADING || !loadPaging)" <div *ngIf="showDownload && (searchUtils.status !== errorCodes.LOADING || !loadPaging)"
class="uk-margin-small-left uk-flex uk-flex-middle" [class.uk-flex-center]="mobile" [class.uk-margin-medium-top]="mobile"> class="uk-margin-small-left uk-flex uk-flex-middle" [class.uk-flex-center]="mobile" [class.uk-margin-medium-top]="mobile">
<search-download <search-download
*ngIf="( entityType !='community' && entityType != 'stakeholder') && usedBy == 'search'" *ngIf="( entityType !='community' && entityType != 'stakeholder') && usedBy == 'search'"
[isDisabled]="disabled" [isDisabled]="disabled"
[type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults"> [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults">
</search-download> </search-download>
<ng-container *ngIf="properties.zenodoDumpUrl && entityType == 'result'"> <ng-container *ngIf="properties.zenodoDumpUrl && entityType == 'result'">
<a [href]="properties.zenodoDumpUrl" target="_blank" class=" uk-margin-left uk-button uk-button-link uk-flex uk-flex-middle"> <a [href]="properties.zenodoDumpUrl" target="_blank" class=" uk-margin-left uk-button uk-button-link uk-flex uk-flex-middle">
<img src="assets/common-assets/common/zenodoDump.png" width="20"><span class="uk-margin-xsmall-left">Data dump</span> <img src="assets/common-assets/common/zenodoDump.png" alt="Zenodo dump" width="20"><span class="uk-margin-xsmall-left">Data dump</span>
</a> </a>
</ng-container> </ng-container>
</div> </div>
</div> </div>
</div> </div>
<div *ngIf="(searchUtils.status !== errorCodes.LOADING || !loadPaging) && !mobile" class="uk-flex uk-flex-top">
<!-- filters pills -->
<div class="uk-width-expand@m">
<ng-container *ngTemplateOutlet="selected_filters_pills;"></ng-container>
</div>
</div>
<div [class]="searchUtils.page > pagingLimit ? 'search-results' : ''" <div [class]="searchUtils.page > pagingLimit ? 'search-results' : ''"
*ngIf="(searchUtils.page >= pagingLimit) && (searchUtils.totalResults > searchUtils.size*pagingLimit)"> *ngIf="(searchUtils.page >= pagingLimit) && (searchUtils.totalResults > searchUtils.size*pagingLimit)">
<p class="uk-alert uk-alert-warning" uk-alert>For more results please try a new, more specific query</p> <p class="uk-alert uk-alert-warning" uk-alert>For more results please try a new, more specific query</p>

View File

@ -1085,7 +1085,7 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
let params = ""; let params = "";
let doisParams = ""; let doisParams = "";
var DOIs: Identifier[] = Identifier.getIdentifiersFromString(value); var DOIs: Identifier[] = Identifier.getIdentifiersFromString(value);
if ((entityType == 'publication' || entityType == 'dataset' || entityType == 'software' || entityType == 'other' || entityType == "result" || entityType == "dataprovider" || entityType == "service")) { if ((entityType == 'publication' || entityType == 'dataset' || entityType == 'software' || entityType == 'other' || entityType == "result" || entityType == "dataprovider" || entityType == "service" || entityType == "organization")) {
for (let identifier of DOIs) { for (let identifier of DOIs) {
// console.log(identifier) // console.log(identifier)
// pidclassid exact \"doi\" and pid exact \"10.1016/j.nima.2015.11.134\" // pidclassid exact \"doi\" and pid exact \"10.1016/j.nima.2015.11.134\"

View File

@ -57,7 +57,7 @@ export class SearchResultComponent implements OnInit, OnChanges {
this.previewResults.push(this.getResultPreview(result)); this.previewResults.push(this.getResultPreview(result));
} }
if ((properties.adminToolsPortalType == "explore" || properties.adminToolsPortalType == "community" || properties.adminToolsPortalType == "aggregator") if ((properties.adminToolsPortalType == "explore" || properties.adminToolsPortalType == "community" || properties.adminToolsPortalType == "aggregator" || properties.dashboard == "irish")
&& Session.isLoggedIn() && this.results && this.results.length > 0 && Session.isLoggedIn() && this.results && this.results.length > 0
&& (this.type == "result" || this.type == "publication" || this.type == "dataset" || this.type == "software" || this.type == "other") && (this.type == "result" || this.type == "publication" || this.type == "dataset" || this.type == "software" || this.type == "other")
) { ) {
@ -78,6 +78,7 @@ export class SearchResultComponent implements OnInit, OnChanges {
// console.debug(i, this.previewResults[i].orcidPutCodes); // console.debug(i, this.previewResults[i].orcidPutCodes);
} }
} }
this.previewResults = JSON.parse(JSON.stringify(this.previewResults, this.replacer), this.reviver);
}, error => { }, error => {
} }
@ -85,6 +86,26 @@ export class SearchResultComponent implements OnInit, OnChanges {
} }
} }
private replacer(key, value) {
if(value instanceof Map) {
return {
dataType: 'Map',
value: Array.from(value.entries()), // or with spread: value: [...value]
};
} else {
return value;
}
}
private reviver(key, value) {
if(typeof value === 'object' && value !== null) {
if (value.dataType === 'Map') {
return new Map(value.value);
}
}
return value;
}
public getResultPreview(result: SearchResult): ResultPreview { public getResultPreview(result: SearchResult): ResultPreview {
return ResultPreview.searchResultConvert(result, (result.entityType) ? result.entityType : this.type); return ResultPreview.searchResultConvert(result, (result.entityType) ? result.entityType : this.type);
} }

View File

@ -95,7 +95,7 @@ export class OrganizationService {
} }
} }
if(organization['pid'] && properties.environment != "production") { if(organization['pid']) {
this.organizationInfo.identifiers = this.parsingFunctions.parseIdentifiers(organization['pid']); this.organizationInfo.identifiers = this.parsingFunctions.parseIdentifiers(organization['pid']);
} }
} }

View File

@ -100,13 +100,16 @@ export class SearchOrganizationsService {
result['title'] = {"name": '', "accessMode": ''}; result['title'] = {"name": '', "accessMode": ''};
if(resData.legalshortname) { if(resData.legalname) {
result['title'].name = StringUtils.HTMLToString(String(resData.legalshortname));
}
if(!result['title'].name || result['title'].name == '') {
result['title'].name = StringUtils.HTMLToString(String(resData.legalname)); result['title'].name = StringUtils.HTMLToString(String(resData.legalname));
} else {
result['title'].name = "";
} }
if(resData.legalshortname) {
result['acronym'] = StringUtils.HTMLToString(String(resData.legalshortname));
}
//result['title'].url = OpenaireProperties.getsearchLinkToOrganization(); //result['title'].url = OpenaireProperties.getsearchLinkToOrganization();
//result['title'].url += Array.isArray(data) ? data[i]['result']['header']['dri:objIdentifier'] : data['result']['header']['dri:objIdentifier']; //result['title'].url += Array.isArray(data) ? data[i]['result']['header']['dri:objIdentifier'] : data['result']['header']['dri:objIdentifier'];
result['id'] = Array.isArray(data) ? data[i]['result']['header']['dri:objIdentifier'] : data['result']['header']['dri:objIdentifier']; result['id'] = Array.isArray(data) ? data[i]['result']['header']['dri:objIdentifier'] : data['result']['header']['dri:objIdentifier'];
@ -175,7 +178,7 @@ export class SearchOrganizationsService {
result.country = resData.country.classname; result.country = resData.country.classname;
} }
if(resData['pid'] && properties.environment != "production") { if(resData['pid']) {
result.identifiers = this.parsingFunctions.parseIdentifiers(resData['pid']); result.identifiers = this.parsingFunctions.parseIdentifiers(resData['pid']);
} }

View File

@ -231,6 +231,7 @@ export class SearchProjectsService {
let fundingData = Array.isArray(resData['fundingtree']) ? resData['fundingtree'][z] : resData['fundingtree']; let fundingData = Array.isArray(resData['fundingtree']) ? resData['fundingtree'][z] : resData['fundingtree'];
if(fundingData.hasOwnProperty("funder")) { if(fundingData.hasOwnProperty("funder")) {
result['funderShortname'] = fundingData['funder'].shortname; result['funderShortname'] = fundingData['funder'].shortname;
result['funderName'] = fundingData['funder'].name;
result['funderId'] = fundingData['funder'].id; result['funderId'] = fundingData['funder'].id;
result['jurisdiction'] = (fundingData['funder']['id']['jurisdiction'] )?fundingData['funder']['id']['jurisdiction']:""; result['jurisdiction'] = (fundingData['funder']['id']['jurisdiction'] )?fundingData['funder']['id']['jurisdiction']:"";

View File

@ -70,7 +70,7 @@ export class RefineResultsUtils {
} }
public static inParenthesisThePartAfterCharacters(field, characters):string { public static inParenthesisThePartAfterCharacters(field, characters):string {
if( field.name.indexOf(characters) !=-1){ if( field.name.indexOf(characters) !=-1){
return field.name.split(characters)[0]+" ("+field.name.split(characters)[1]+")"; return field.name.split(characters)[0]+ (field.name.split(characters)[1]?(" ("+field.name.split(characters)[1]+")"):"");
} }
return field.name; return field.name;

View File

@ -0,0 +1,7 @@
import {ActivatedRouteSnapshot, BaseRouteReuseStrategy} from "@angular/router";
export class CustomRouteReuseStrategy extends BaseRouteReuseStrategy {
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig || (!!future.routeConfig?.component && future.routeConfig?.component === curr.routeConfig?.component)
}
}

View File

@ -58,15 +58,22 @@ export class AdvancedSearchInputComponent implements AfterContentInit, OnDestroy
} }
ngAfterContentInit() { ngAfterContentInit() {
this.inputs.forEach(input => { this.init();
input.inputClass = 'advanced-search'; this.inputs.changes.subscribe(input => {
input.selectArrow = null; this.init();
}); });
} }
ngOnDestroy() { ngOnDestroy() {
} }
init() {
this.inputs.forEach(input => {
input.inputClass = 'advanced-search';
input.selectArrow = null;
});
}
focusNext(input: InputComponent | EntitiesSelectionComponent, event: any = null) { focusNext(input: InputComponent | EntitiesSelectionComponent, event: any = null) {
if(!event || !event.init) { if(!event || !event.init) {
setTimeout(() => { setTimeout(() => {

View File

@ -101,7 +101,7 @@
<li><a <li><a
[href]="'https://'+(properties.environment =='beta' || properties.environment =='development'?'beta.':'')+'monitor.openaire.eu'" [href]="'https://'+(properties.environment =='beta' || properties.environment =='development'?'beta.':'')+'monitor.openaire.eu'"
target="_blank">Monitor</a></li> target="_blank">Monitor</a></li>
<li><a href="https://graph.openaire.eu/develop/" target="_blank">Develop</a></li> <li><a href="'https://'+(properties.environment =='beta' || properties.environment =='development'?'beta.':'')+'develop.openaire.eu" target="_blank">Develop</a></li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -12,7 +12,7 @@
Send a message Send a message
</div> </div>
<div *ngIf="images.length > 0" class="uk-margin-small avatars"> <div *ngIf="images.length > 0" class="uk-margin-small avatars">
<img *ngFor="let image of images" [src]="image" class="uk-border-circle" > <img *ngFor="let image of images" [src]="image" class="uk-border-circle" alt="contact person">
</div> </div>
<div class="uk-text-bold"> <div class="uk-text-bold">
How can we help? How can we help?

View File

@ -19,7 +19,7 @@ import {properties} from "../../../../environments/environment";
@Component({ @Component({
selector: 'showAuthors', selector: 'showAuthors',
template: ` template: `
<ng-template #author_template let-author="author" let-i="i" let-italic="italic"> <ng-template #author_template let-author="author" let-i="i" let-italic="italic" let-modal="modal">
<span *ngIf="isSticky || (!author.orcid && !author.orcid_pending) || !isBrowser" style="margin-right: 5px;" <span *ngIf="isSticky || (!author.orcid && !author.orcid_pending) || !isBrowser" style="margin-right: 5px;"
[class.uk-text-italic]="italic"> [class.uk-text-italic]="italic">
{{author.fullName + ";"}} {{author.fullName + ";"}}
@ -36,7 +36,7 @@ import {properties} from "../../../../environments/environment";
</span> </span>
</a> </a>
<div *ngIf="!isMobile" class="default-dropdown uk-margin-remove-top uk-dropdown orcid-dropdown" <div *ngIf="!isMobile" class="default-dropdown uk-margin-remove-top uk-dropdown orcid-dropdown"
uk-dropdown="mode:click; offset: 4;" style="min-width: 465px !important;" [attr.container]="isModal?'#modal-container':true"> uk-dropdown="mode:click; offset: 4; pos: bottom-right" style="min-width: 465px !important;" [attr.container]="'#modal-container'">
<ng-container *ngTemplateOutlet="dropdown"></ng-container> <ng-container *ngTemplateOutlet="dropdown"></ng-container>
</div> </div>
<mobile-dropdown *ngIf="isMobile" [toggle]="toggle"> <mobile-dropdown *ngIf="isMobile" [toggle]="toggle">
@ -112,7 +112,7 @@ import {properties} from "../../../../environments/environment";
</span> </span>
<ng-container *ngFor="let author of authors.slice(0, viewAll?authors.length:authorsLimit) let i=index"> <ng-container *ngFor="let author of authors.slice(0, viewAll?authors.length:authorsLimit) let i=index">
<ng-container <ng-container
*ngTemplateOutlet="author_template; context: { author: author, i:i, italic: true}"></ng-container> *ngTemplateOutlet="author_template; context: { author: author, i:i, italic: true, modal: modal}"></ng-container>
</ng-container> </ng-container>
<span *ngIf="!showAll && authors && authors.length > authorsLimit" class="uk-text-meta"> <span *ngIf="!showAll && authors && authors.length > authorsLimit" class="uk-text-meta">
+{{authors.length - authorsLimit | number}} more +{{authors.length - authorsLimit | number}} more
@ -127,18 +127,18 @@ import {properties} from "../../../../environments/environment";
</div> </div>
</div> </div>
<modal-alert *ngIf="!isMobile" #authorsModal> <modal-alert *ngIf="!isMobile && showAll && authors && authors.length > authorsLimit" #authorsModal>
<div class="uk-text-small uk-text-emphasis uk-grid uk-grid-column-collapse uk-grid-row-small" uk-grid> <div class="uk-text-small uk-text-emphasis uk-grid uk-grid-column-collapse uk-grid-row-small" uk-grid>
<ng-container *ngFor="let author of authors; let i=index"> <ng-container *ngFor="let author of authors; let i=index">
<ng-container *ngTemplateOutlet="author_template; context: { author: author, i:i}"></ng-container> <ng-container *ngTemplateOutlet="author_template; context: { author: author, i:i, modal: authorsModal}"></ng-container>
</ng-container> </ng-container>
</div> </div>
</modal-alert> </modal-alert>
<fs-modal *ngIf="isMobile" #authorsModal classTitle="uk-tile-default uk-border-bottom"> <fs-modal *ngIf="isMobile && showAll && authors && authors.length > authorsLimit" #authorsModal classTitle="uk-tile-default uk-border-bottom">
<div class="uk-text-small uk-text-emphasis uk-grid uk-grid-column-collapse uk-grid-row-small" uk-grid> <div class="uk-text-small uk-text-emphasis uk-grid uk-grid-column-collapse uk-grid-row-small" uk-grid>
<ng-container *ngFor="let author of authors; let i=index"> <ng-container *ngFor="let author of authors; let i=index">
<ng-container *ngTemplateOutlet="author_template; context: { author: author, i:i}"></ng-container> <ng-container *ngTemplateOutlet="author_template; context: { author: author, i:i, modal: authorsModal}"></ng-container>
</ng-container> </ng-container>
</div> </div>
</fs-modal> </fs-modal>
@ -153,7 +153,6 @@ export class ShowAuthorsComponent {
@Input() authorsLimit: number = 7; @Input() authorsLimit: number = 7;
@Input() showAll: boolean = true; @Input() showAll: boolean = true;
@Input() modal: AlertModal; @Input() modal: AlertModal;
@Input() isModal: boolean
@Input() viewAll: boolean = false; @Input() viewAll: boolean = false;
@Input() showInline: boolean = false; // do not open modal for "view more" when this is true @Input() showInline: boolean = false; // do not open modal for "view more" when this is true
public lessBtn: boolean = false; public lessBtn: boolean = false;
@ -171,10 +170,24 @@ export class ShowAuthorsComponent {
ngOnInit() {} ngOnInit() {}
ngOnDestroy() {
if(typeof document !== 'undefined') {
let modal_container = document.getElementById("modal-container");
modal_container.childNodes.forEach(c=> {
if (c['className'] && c['className'].includes("orcid-dropdown")) {
modal_container.removeChild(c);
}
});
}
}
public onClick() { public onClick() {
if (this.modal) { if (this.modal) {
this.modal.cancel(); this.modal.cancel();
} }
if(this.authorsModal) {
this.authorsModal.cancel();
}
} }
public viewAllClick() { public viewAllClick() {

View File

@ -2,6 +2,7 @@ import {Email} from "./email";
import {Body} from "./body"; import {Body} from "./body";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {User} from "../../login/utils/helper.class"; import {User} from "../../login/utils/helper.class";
import {StakeholderConfiguration} from "../../monitor-admin/utils/indicator-utils";
export class Composer { export class Composer {
private static noteBodySize = "14px"; private static noteBodySize = "14px";
@ -107,6 +108,20 @@ export class Composer {
return email; return email;
} }
public static composeEmailForDevelopPersonalInfo(user: User): Email {
let email: Email = new Email();
email.subject = "Welcome to The OpenAIRE API mailing list";
email.body = "<div style='font-size:" + this.noteBodySize + "'>"
+ "<p>Dear " + user.fullname + ",</p>"
+ "<p>As a user of the OpenAIRE APIs, you are a member of the openaire-api mailing list. " +
" We will use this list to inform you of relevant news and updates. If you wish to unsubscribe, " +
" please send an email to the list admin at <a href='mailto:gbikas@openaire.eu'>gbikas@openaire.eu</a> " +
" and <a href='mailto:stefania.amodeo@openaire.eu'>stefania.amodeo@openaire.eu</a>.</p>"
+ "<p>The OpenAIRE Graph team</p>";
email.recipients = [user.email];
return email;
}
public static composeEmailForDevelop(contactForm: any, admins: any, user: User): Email { public static composeEmailForDevelop(contactForm: any, admins: any, user: User): Email {
let email: Email = new Email(); let email: Email = new Email();
email.subject = "OpenAIRE - Develop [" + properties.environment.toUpperCase() + "]"; email.subject = "OpenAIRE - Develop [" + properties.environment.toUpperCase() + "]";
@ -335,13 +350,13 @@ export class Composer {
email.subject = 'National Open Access Monitor Ireland | ' + name; email.subject = 'National Open Access Monitor Ireland | ' + name;
email.recipient = recipient; email.recipient = recipient;
email.body = '<p>Dear user,</p>' + email.body = '<p>Dear user,</p>' +
'<p>You have been invited to be a ' + role +' of the for the National Open Access Monitor, Ireland dashboard for the ' + name + '.</p>' + '<p>You have been invited to be a ' + StakeholderConfiguration.ROLES[role] +' of the for the National Open Access Monitor, Ireland 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>' +
'<p>At your first sign in you will be asked to accept and consent to the "OpenAIRE Personal Data Protection Policy and Consent Form" to be able to use the service.</p>' + '<p>At your first sign in you will be asked to accept and consent to the "OpenAIRE Personal Data Protection Policy and Consent Form" to be able to use the service.</p>' +
(role === "manager"? (role === "manager"?
'<p>As a manager of the National Open Access Monitor, Ireland, you will have access to the administration part of the dashboard, where you will be able to also invite other users to become managers.</p>': '<p>As a ' + StakeholderConfiguration.ROLES[role] + ' of the National Open Access Monitor, Ireland, you will have access to the administration part of the dashboard, where you will be able to also invite other users to become ' + StakeholderConfiguration.ROLES['member'] + 's.</p>':
'<p>As a member of the OpenAIRE Monitor Dashboard, you will have access to the restricted access areas of the profile for the ' + name + '.') + '<p>As a ' + StakeholderConfiguration.ROLES[role] + ' of the National Open Access Monitor, Ireland, you will have access to the sandbox of the profile for the ' + name + '.') +
'<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

@ -48,6 +48,7 @@ export class SearchResult {
acronym: string; acronym: string;
code: string; code: string;
// callIdentifier?: string; // currently not parsed // callIdentifier?: string; // currently not parsed
funderName: string;
funderShortname: string; funderShortname: string;
budget?: string; budget?: string;
contribution?: string; contribution?: string;

View File

@ -237,7 +237,8 @@ private fetch (link,id,oafEntityType,type, properties:EnvProperties ){
if(resData['fundingtree'] && resData['fundingtree']['funder']){ if(resData['fundingtree'] && resData['fundingtree']['funder']){
value.funderId = (resData['fundingtree']['funder']['id'] )?resData['fundingtree']['funder']['id']:""; value.funderId = (resData['fundingtree']['funder']['id'] )?resData['fundingtree']['funder']['id']:"";
value.funderName = (resData['fundingtree']['funder']['shortname'] )?resData['fundingtree']['funder']['shortname']:""; value.funderName = (resData['fundingtree']['funder']['name'] )?resData['fundingtree']['funder']['name']:"";
value.funderShortName = (resData['fundingtree']['funder']['shortname'] )?resData['fundingtree']['funder']['shortname']:"";
value.jurisdiction = (resData['fundingtree']['funder']['jurisdiction'] )?resData['fundingtree']['funder']['jurisdiction']:""; value.jurisdiction = (resData['fundingtree']['funder']['jurisdiction'] )?resData['fundingtree']['funder']['jurisdiction']:"";
if(resData['fundingtree']['funding_level_2']){ if(resData['fundingtree']['funding_level_2']){
value.fundingLevel0 = (resData['fundingtree']['funding_level_2'] && resData['fundingtree']['funding_level_2']['parent'] && value.fundingLevel0 = (resData['fundingtree']['funding_level_2'] && resData['fundingtree']['funding_level_2']['parent'] &&

View File

@ -161,3 +161,8 @@ export const unknown_access: Icon = {
name: 'unknown_access', name: 'unknown_access',
data: '<svg xmlns="http://www.w3.org/2000/svg" width="373.336" height="490.004" viewBox="0 0 373.336 490.004"><g id="noun-lock-question-mark-250128" transform="translate(-163.328 -34.992)"><path id="Path_119172" data-name="Path 119172" d="M490,198.33H466.668V151.662a116.67,116.67,0,0,0-233.34,0V198.33H210A46.8,46.8,0,0,0,163.328,245v233.33A46.8,46.8,0,0,0,210,525H490a46.8,46.8,0,0,0,46.668-46.668V245A46.8,46.8,0,0,0,490,198.33ZM365.55,469.78H334.441V438.671H365.55ZM397.441,350l-14,14c-10.891,11.668-17.891,20.223-17.891,43.555H334.441v-7.777a61.712,61.712,0,0,1,17.891-43.555l19.445-19.445A30.98,30.98,0,1,0,318.891,315H287.782a62.223,62.223,0,0,1,124.446,0,49.983,49.983,0,0,1-14.785,35Zm24.887-151.67H277.668V151.662c0-39.668,32.668-72.332,72.332-72.332S422.332,112,422.332,151.662Z"/></g></svg>' data: '<svg xmlns="http://www.w3.org/2000/svg" width="373.336" height="490.004" viewBox="0 0 373.336 490.004"><g id="noun-lock-question-mark-250128" transform="translate(-163.328 -34.992)"><path id="Path_119172" data-name="Path 119172" d="M490,198.33H466.668V151.662a116.67,116.67,0,0,0-233.34,0V198.33H210A46.8,46.8,0,0,0,163.328,245v233.33A46.8,46.8,0,0,0,210,525H490a46.8,46.8,0,0,0,46.668-46.668V245A46.8,46.8,0,0,0,490,198.33ZM365.55,469.78H334.441V438.671H365.55ZM397.441,350l-14,14c-10.891,11.668-17.891,20.223-17.891,43.555H334.441v-7.777a61.712,61.712,0,0,1,17.891-43.555l19.445-19.445A30.98,30.98,0,1,0,318.891,315H287.782a62.223,62.223,0,0,1,124.446,0,49.983,49.983,0,0,1-14.785,35Zm24.887-151.67H277.668V151.662c0-39.668,32.668-72.332,72.332-72.332S422.332,112,422.332,151.662Z"/></g></svg>'
} }
export const coins: Icon = {
name: 'coins',
data: '<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 315.47 315.47"><g id="Layer_1-2"><g><g><ellipse class="" cx="116.85" cy="98.6" rx="63.94" ry="37.92"/><ellipse class="" cx="199.59" cy="167.66" rx="63.94" ry="37.92"/><path class="cls-3" d="M260.39,185.84c1.25-1.88,2.51-3.76,3.13-5.95-.31,13.48,1.25,14.42-.94,21.63-5.01,17.24-38.86,29.77-64.25,29.15-21.63-.31-39.18-2.82-54.85-15.98-4.39-3.76-9.4-7.52-9.72-12.85,0-10.03,0-11.6,.31-23.82,10.34,38.86,102.8,41.37,126.31,7.84Z"/><path class="cls-3" d="M262.58,209.66c.94,8.78-1.57,13.79-1.88,20.06-.94,14.73-35.1,24.76-61.43,25.07-31.34,.31-63.62-12.22-64.25-24.76-.63-11.28,0-5.33-.94-20.06,21.31,32.28,105.31,31.97,128.5-.31Z"/><path class="cls-3" d="M116.85,140.71c38.55,.31,57.67-17.86,61.74-25.07,1.88-3.45-.31,12.85-.94,13.16-14.1,4.07-31.03,10.03-40.43,21.94-2.82,3.45-3.76,7.52-5.01,12.54,0,.31-13.48-.31-14.42-.31-28.21,0-61.12-13.48-65.82-35.73-.63-4.39,0-8.15,0-17.55,10.03,19.75,36.67,30.71,64.88,31.03Z"/><path class="cls-3" d="M116.85,166.72c5.01,.31,15.04,0,15.04,0-.94,8.78-.63,12.85-1.25,23.19,0,.31-71.15,3.76-78.67-33.85-.63-4.07,0-7.84,0-17.55,15.67,21.31,42.94,27.27,64.88,28.21Z"/><path class="cls-3" d="M130.01,194.3s.94,12.54,.63,21.94c0,.31-68.95,1.88-78.04-27.58l-.63-21.31c16.92,23.51,52.65,27.58,78.04,26.95Z"/></g></g></g></svg>'
}

View File

@ -56,6 +56,7 @@ export class MobileDropdownComponent implements OnInit{
parent.removeChild(this.element.nativeElement); parent.removeChild(this.element.nativeElement);
container.append(this.element.nativeElement); container.append(this.element.nativeElement);
this.opened = true; this.opened = true;
this.cdr.markForCheck();
body.setAttribute('style', 'overflow-y: hidden'); body.setAttribute('style', 'overflow-y: hidden');
} }
} }

View File

@ -23,7 +23,7 @@ export let common: EnvProperties = {
rorURL: "https://ror.org/", rorURL: "https://ror.org/",
isniURL: "https://isni.org/isni/", isniURL: "https://isni.org/isni/",
wikiDataURL: "https://www.wikidata.org/wiki/", wikiDataURL: "https://www.wikidata.org/wiki/",
fundRefURL: "https://api.crossref.org/funders/", fundRefURL: "https://data.crossref.org/fundingdata/funder/",
fairSharingURL: "https://fairsharing.org/", fairSharingURL: "https://fairsharing.org/",
eoscMarketplaceURL: "https://marketplace.eosc-portal.eu/services/", eoscMarketplaceURL: "https://marketplace.eosc-portal.eu/services/",
sherpaURL: "http://sherpa.ac.uk/romeo/issn/", sherpaURL: "http://sherpa.ac.uk/romeo/issn/",

View File

@ -797,8 +797,8 @@ export class SearchFieldsBase {
//ORGANIZATION //ORGANIZATION
public ORGANIZATION_REFINE_FIELDS: string[] = ["country"] public ORGANIZATION_REFINE_FIELDS: string[] = ["countrynojurisdiction"]
public ORGANIZATION_ADVANCED_FIELDS: string[] = ["q", "organizationlegalname", "organizationlegalshortname", "country"]; public ORGANIZATION_ADVANCED_FIELDS: string[] = ["q", "organizationlegalname", "organizationlegalshortname", "countrynojurisdiction", "pid"];
public ORGANIZATION_FIELDS: { [key: string]: FieldDetails } = { public ORGANIZATION_FIELDS: { [key: string]: FieldDetails } = {
["q"]: {name: "Any field", type: "keyword", param: "q", operator: "op", equalityOperator: "=", filterType: null}, ["q"]: {name: "Any field", type: "keyword", param: "q", operator: "op", equalityOperator: "=", filterType: null},
@ -818,7 +818,7 @@ export class SearchFieldsBase {
equalityOperator: "=", equalityOperator: "=",
filterType: null filterType: null
}, },
["country"]: { ["countrynojurisdiction"]: {
name: "Country", name: "Country",
type: "vocabulary", type: "vocabulary",
param: "country", param: "country",
@ -826,6 +826,7 @@ export class SearchFieldsBase {
equalityOperator: " exact ", equalityOperator: " exact ",
filterType: "checkbox" filterType: "checkbox"
}, },
["pid"]: {name: "PID", type: "keyword", param: "pid", operator: "pd", equalityOperator: " exact ", filterType: null}
}; };
// public ORGANIZATION_INDEX:string[] = ["organizationcountryname"]//,"organizationeclegalbody"]; // public ORGANIZATION_INDEX:string[] = ["organizationcountryname"]//,"organizationeclegalbody"];
// public ADVANCED_SEARCH_ORGANIZATION_PARAM:string[] = ["q","contenttype","compatibility","country","type"]; // public ADVANCED_SEARCH_ORGANIZATION_PARAM:string[] = ["q","contenttype","compatibility","country","type"];
@ -961,7 +962,7 @@ export class SearchFieldsBase {
return "and"; return "and";
} else if (fieldId == "instancetypename" || fieldId == "eoscdatasourcetype" } else if (fieldId == "instancetypename" || fieldId == "eoscdatasourcetype"
|| fieldId == "resultlanguagename" || fieldId == "datasourceodlanguages" || fieldId == "resultlanguagename" || fieldId == "datasourceodlanguages"
|| fieldId == "datasourcecompatibilityname" || fieldId == "country" || fieldId == "datasourceodcontenttypes" || fieldId == "datasourcecompatibilityname" || fieldId == "country" || fieldId == "countrynojurisdiction" || fieldId == "datasourceodcontenttypes"
|| fieldId == "resulthostingdatasource" || fieldId == "collectedfrom") { || fieldId == "resulthostingdatasource" || fieldId == "collectedfrom") {
return "or"; return "or";
} }

View File

@ -95,12 +95,12 @@
<!-- 2nd section (funders, budget, authors, PIDs, publisher etc.) --> <!-- 2nd section (funders, budget, authors, PIDs, publisher etc.) -->
<div class="uk-text-small uk-margin-small-bottom"> <div class="uk-text-small uk-margin-small-bottom">
<!-- Funder --> <!-- Funder -->
<div *ngIf="result.funderShortname || result.code" class="uk-margin-xsmall-bottom"> <div *ngIf="(result.funderShortname || result.funderName) || result.code" class="uk-margin-xsmall-bottom">
<span *ngIf="result.funderShortname"> <span *ngIf="result.funderShortname || result.funderName">
<span class="uk-text-meta">Funder: </span> <span class="uk-text-meta">Funder: </span>
{{result.funderShortname}} {{result.funderName ? result.funderName : result.funderShortname}}
</span> </span>
<span *ngIf="result.code" [class.uk-margin-left]="result.funderShortname"> <span *ngIf="result.code" [class.uk-margin-left]="result.funderShortname || result.funderName">
<span class="uk-text-meta">{{openaireEntities.PROJECT}} Code: </span> <span class="uk-text-meta">{{openaireEntities.PROJECT}} Code: </span>
{{result.code}} {{result.code}}
</span> </span>
@ -125,7 +125,7 @@
</div> </div>
<!-- Authors --> <!-- Authors -->
<div *ngIf="result.authors" class="uk-margin-xsmall-bottom"> <div *ngIf="result.authors" class="uk-margin-xsmall-bottom">
<showAuthors [authors]="result.authors" [authorsLimit]=4 [modal]="modal" [isMobile]="isMobile" [isModal]="isDeletedByInferenceModal" <showAuthors [authors]="result.authors" [authorsLimit]=4 [modal]="modal" [isMobile]="isMobile"
[showAll]=true [showInline]="showInline"></showAuthors> [showAll]=true [showInline]="showInline"></showAuthors>
</div> </div>
<!-- Identifiers --> <!-- Identifiers -->
@ -218,7 +218,7 @@
<div *ngIf="result.oaRoutes" class="uk-first-column"> <div *ngIf="result.oaRoutes" class="uk-first-column">
<!-- class="metrics uk-text-xsmall uk-width-auto uk-flex uk-flex-middle uk-flex-right uk-text-meta">--> <!-- class="metrics uk-text-xsmall uk-width-auto uk-flex uk-flex-middle uk-flex-right uk-text-meta">-->
<a class="uk-flex uk-flex-middle uk-link-reset"> <a class="uk-flex uk-flex-middle uk-link-reset">
<span #badge class="access-route-badge" [ngClass]="'dots-' + badge.children.length.toString()"> <span #badge class="access-route-badge" [ngClass]="'dots-' + countDots">
<span *ngIf="result.oaRoutes.green" class="dot green"></span> <span *ngIf="result.oaRoutes.green" class="dot green"></span>
<span *ngIf="result.oaRoutes.oaColor" class="dot" [ngClass]="result.oaRoutes.oaColor"></span> <span *ngIf="result.oaRoutes.oaColor" class="dot" [ngClass]="result.oaRoutes.oaColor"></span>
<span *ngIf="result.oaRoutes.isInDiamondJournal" class="dot diamond"></span> <span *ngIf="result.oaRoutes.isInDiamondJournal" class="dot diamond"></span>

View File

@ -1,4 +1,4 @@
import {Component, Input, OnChanges, OnInit, SimpleChanges} from "@angular/core"; import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges} from "@angular/core";
import {ResultPreview} from "./result-preview"; import {ResultPreview} from "./result-preview";
import {EnvProperties} from "../properties/env-properties"; import {EnvProperties} from "../properties/env-properties";
import {RouterHelper} from "../routerHelper.class"; import {RouterHelper} from "../routerHelper.class";
@ -12,7 +12,8 @@ import {NumberUtils} from '../number-utils.class';
@Component({ @Component({
selector: 'result-preview', selector: 'result-preview',
templateUrl: 'result-preview.component.html', templateUrl: 'result-preview.component.html',
styleUrls: ['result-preview.component.less'] styleUrls: ['result-preview.component.less'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ResultPreviewComponent implements OnInit, OnChanges { export class ResultPreviewComponent implements OnInit, OnChanges {
@Input() prevPath: string = ""; @Input() prevPath: string = "";
@ -255,4 +256,8 @@ export class ResultPreviewComponent implements OnInit, OnChanges {
} }
return obj; return obj;
} }
public get countDots() {
return (this.result.oaRoutes.green ? 1 : 0) + (this.result.oaRoutes.oaColor ? 1 : 0) + (this.result.oaRoutes.isInDiamondJournal ? 1 : 0);
}
} }

View File

@ -123,6 +123,7 @@ export class ResultPreview {
acronym: string; acronym: string;
code: string; code: string;
// callIdentifier: string; // currently not parsed // callIdentifier: string; // currently not parsed
funderName: string;
funderShortname: string; funderShortname: string;
budget: string; budget: string;
contribution: string; contribution: string;
@ -188,6 +189,7 @@ export class ResultPreview {
resultPreview.acronym = result.acronym; resultPreview.acronym = result.acronym;
resultPreview.code = result.code; resultPreview.code = result.code;
// resultPreview.callIdentifier = result.callIdentifier; // currently not parsed // resultPreview.callIdentifier = result.callIdentifier; // currently not parsed
resultPreview.funderName = result.funderName;
resultPreview.funderShortname = result.funderShortname; resultPreview.funderShortname = result.funderShortname;
resultPreview.budget = result.budget; resultPreview.budget = result.budget;
resultPreview.contribution = result.contribution; resultPreview.contribution = result.contribution;

View File

@ -24,6 +24,7 @@ export class SmoothScroll {
} else if (event instanceof NavigationEnd) { } else if (event instanceof NavigationEnd) {
let headerOffset = (this.layoutService.isMobileValue?0:Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height'))) + 35; let headerOffset = (this.layoutService.isMobileValue?0:Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height'))) + 35;
if(!this.router.getCurrentNavigation().extras?.state?.disableScroll) { if(!this.router.getCurrentNavigation().extras?.state?.disableScroll) {
let behavior = this.router.getCurrentNavigation().extras?.state?.behavior ? this.router.getCurrentNavigation().extras?.state?.behavior : "smooth";
if (this.interval) { if (this.interval) {
clearInterval(this.interval); clearInterval(this.interval);
} }
@ -48,7 +49,7 @@ export class SmoothScroll {
} else { } else {
clearInterval(interval); clearInterval(interval);
const y = element.getBoundingClientRect().top + window.scrollY + yOffset; const y = element.getBoundingClientRect().top + window.scrollY + yOffset;
window.scrollTo({top: y, behavior: 'smooth'}); window.scrollTo({top: y, behavior: behavior});
} }
}, 50); }, 50);
} }
@ -58,7 +59,7 @@ export class SmoothScroll {
}, 100); }, 100);
} else { } else {
setTimeout( () => { setTimeout( () => {
window.scrollTo({top: 0, behavior: 'smooth'}); window.scrollTo({top: 0, behavior: behavior});
}, 0); }, 0);
} }
} }
@ -76,4 +77,4 @@ export class SmoothScroll {
clearInterval(this.interval); clearInterval(this.interval);
} }
} }
} }

View File

@ -150,7 +150,7 @@ export class DOI {
} }
export class Identifier { export class Identifier {
class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" | "swhid" = null; class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" | "swhid" | "ror" | "wikidata" | "fundref" | "isni" = null;
id: string; id: string;
public static getDOIsFromString(str: string): string[] { public static getDOIsFromString(str: string): string[] {
@ -205,14 +205,22 @@ export class Identifier {
return {"class": "re3data", "id": pid}; return {"class": "re3data", "id": pid};
} else if (Identifier.isValidSwhId(pid)) { } else if (Identifier.isValidSwhId(pid)) {
return {"class": "swhid", "id": pid}; return {"class": "swhid", "id": pid};
} else if (Identifier.isValidRor(pid)) {
return {"class": "ror", "id": pid};
} else if (Identifier.isValidFundRef(pid)) {
return {"class": "fundref", "id": pid};
} else if (Identifier.isValidWikidata(pid)) {
return {"class": "wikidata", "id": pid};
} else if (Identifier.isValidIsni(pid)) {
return {"class": "isni", "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", "swhid"]; let classes:string [] = ["doi", "handle", "pmc", "pmid", "re3data", "swhid", "ror", "wikidata", "fundref", "isni"];
if(identifiers) { if(identifiers && identifiers.size > 0) {
for (let cl of classes) { for (let cl of classes) {
if (identifiers.get(cl)) { if (identifiers.get(cl)) {
for (let pid of identifiers.get(cl)) { for (let pid of identifiers.get(cl)) {
@ -258,6 +266,7 @@ export class Identifier {
} }
public static isValidHANDLE(str: string): boolean { public static isValidHANDLE(str: string): boolean {
// let exp = /\b[0-9a-zA-Z-]*\/[0-9a-zA-Z-]*$/g; // resolve with url - need to add method for raw value
let exp = /^[0-9a-zA-Z-]*\/[0-9a-zA-Z-]*$/g; let exp = /^[0-9a-zA-Z-]*\/[0-9a-zA-Z-]*$/g;
return str.match(exp) != null; return str.match(exp) != null;
} }
@ -272,6 +281,28 @@ export class Identifier {
let exp = /swh:1:snp:[0-9a-f]{40}/g; let exp = /swh:1:snp:[0-9a-f]{40}/g;
return str.match(exp) != null; return str.match(exp) != null;
} }
public static isValidRor(str: string): boolean {
let exp = /0[a-z|0-9]{6}[0-9]{2}\b/g;
return str.match(exp) != null;
}
public static isValidIsni(str: string): boolean {
let exp = /^[0]{7}[0-9]{8}[0-9X]$/g;
return str.match(exp) != null;
}
public static isValidWikidata(str: string): boolean {
let exp = /^Q\d+$/g;
return str.match(exp) != null;
}
public static isValidFundRef(str: string): boolean {
// let exp = /aaa/g;
let exp = /^[1-9]\d+$/g;
return str.match(exp) != null;
}
} }
export class StringUtils { export class StringUtils {

View File

@ -1,6 +1,6 @@
import {TransitionGroupItemDirective} from "./transition-group-item.directive"; import {TransitionGroupItemDirective} from "./transition-group-item.directive";
import { import {
AfterViewInit, AfterViewInit, ChangeDetectorRef,
Component, Component,
ContentChildren, ContentChildren,
ElementRef, Input, ElementRef, Input,
@ -29,15 +29,15 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy {
@ContentChildren(TransitionGroupItemDirective) items: QueryList<TransitionGroupItemDirective>; @ContentChildren(TransitionGroupItemDirective) items: QueryList<TransitionGroupItemDirective>;
@Input() @Input()
public id: string; public id: string;
public size: number;
private disabled: boolean = false; private disabled: boolean = false;
private subscription: Subscription; private subscription: Subscription;
constructor(public element: ElementRef) {} constructor(public element: ElementRef) {}
ngAfterViewInit() { ngAfterViewInit() {
this.init();
this.subscription = this.items.changes.subscribe(items => { this.subscription = this.items.changes.subscribe(items => {
if(!this.disabled) { if(items.length === this.size && !this.disabled) {
items.forEach(item => item.prevPos = item.newPos || item.prevPos); items.forEach(item => item.prevPos = item.newPos || item.prevPos);
items.forEach(this.runCallback); items.forEach(this.runCallback);
this.refreshPosition('newPos'); this.refreshPosition('newPos');
@ -80,6 +80,7 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy {
init() { init() {
this.refreshPosition('prevPos'); this.refreshPosition('prevPos');
this.refreshPosition('newPos'); this.refreshPosition('newPos');
this.size = this.items.length;
} }
runCallback(item: TransitionGroupItemDirective) { runCallback(item: TransitionGroupItemDirective) {