Production release February 2024 [CONNECT] #34

Merged
konstantina.galouni merged 168 commits from develop into master 2024-02-15 11:04:20 +01:00
106 changed files with 3183 additions and 1389 deletions

View File

@ -21,14 +21,38 @@ export class SearchOrcidService {
let url = properties.searchOrcidURL + term + '/record'; let url = properties.searchOrcidURL + term + '/record';
return this.http.get(url, { headers: headers }) return this.http.get(url, { headers: headers })
//.map(res => res.json()['person']) //.map(res => res.json()['person'])
.pipe(map(res => res['person'])) .pipe(map(res => res['person']))
.pipe(map(res => [res['name']['given-names'], .pipe(map(res => [res['name']['given-names'],
res['name']['family-name'], res['name']['family-name'],
res['name']])) res['name'], res['name']['institution-name']]))
.pipe(map(res => SearchOrcidService.parseOrcidAuthor(res, authorIds, authors, addId)));
}
.pipe(map(res => SearchOrcidService.parseOrcidAuthor(res, authorIds, authors, addId)));
}
searchOrcidSingleAuthor(term: string, properties: EnvProperties, addId): any {
//var headers = new Headers();
//headers.append('Accept', 'application/orcid+json');
let headers = new HttpHeaders({'Accept': 'application/orcid+json'});
let url ="https://pub.orcid.org/v3.0/expanded-search/?q=orcid:" + term + '&start=0&rows=50';
return this.http.get(url, {headers: headers})
.pipe(map(res => res['expanded-result']))
.pipe(map(res => {
if(res) {
for (let auth_result of res) {
const author = {};
author['id'] = auth_result['orcid-id'];
author['authorGivenName'] = auth_result['given-names'];
author['authorFamilyName'] = auth_result['family-names'];
author['institutions'] = auth_result['institution-name'];
return author;
}
}
return null;
}));
}
searchOrcidAuthors(term: string, searchOrcidAuthors(term: string,
properties: EnvProperties): any { properties: EnvProperties): any {
@ -45,17 +69,46 @@ export class SearchOrcidService {
} }
searchOrcidAuthorsNew(term: string,
properties: EnvProperties, size = 10): any {
let headers = new HttpHeaders({'Accept': 'application/orcid+json'});
// let url = properties.searchOrcidURL+'search?defType=edismax&q='+term+'&qf=given-name^1.0+family-name^2.0+other-names^1.0+credit-name^1.0&start=0&rows=10';
let url = /*properties.searchOrcidURL +*/ 'https://pub.orcid.org/v3.0/expanded-search?q=' + StringUtils.URIEncode('{!edismax qf="given-and-family-names^50.0 family-name^10.0 given-names^10.0 credit-name^10.0 other-names^5.0 text^1.0" pf="given-and-family-names^50.0" bq="current-institution-affiliation-name:[* TO *]^100.0 past-institution-affiliation-name:[* TO *]^70" mm=1}') + term + '&start=0&rows=' + size;
// given-and-family-names^50.0 family-name^10.0 given-names^10.0 credit-name^10.0 other-names^5.0 text^1.0" pf="given-and-family-names^50.0" bq="current-institution-affiliation-name:[* TO *]^100.0 past-institution-affiliation-name:[* TO *]^70" mm=1}
// https://pub.orcid.org/v3.0/expanded-search/?q=%7B!edismax%20qf%3D%22given-and-family-names%5E50.0%20family-name%5E10.0%20given-names%5E10.0%20credit-name%5E10.0%20other-names%5E5.0%20text%5E1.0%22%20pf%3D%22given-and-family-names%5E50.0%22%20bq%3D%22current-institution-affiliation-name%3A%5B*%20TO%20*%5D%5E100.0%20past-institution-affiliation-name%3A%5B*%20TO%20*%5D%5E70%22%20mm%3D1%7Dpaolo%20manghi&start=0&rows=50
//q={!edismax qf="given-and-family-names^50.0 family-name^10.0 given-names^5.0 credit-name^10.0 other-names^5.0 text^1.0" pf="given-and-family-names^50.0" mm=1}alessia bardi&start=0&rows=10
let key = url;
return this.http.get(url, {headers: headers})
.pipe(map(res => res['expanded-result']))
.pipe(map(res => {
let authors = [];
if(res) {
for (let auth_result of res) {
const author = {};
author['id'] = auth_result['orcid-id'];
author['authorGivenName'] = auth_result['given-names'];
author['authorFamilyName'] = auth_result['family-names'];
author['institutions'] = auth_result['institution-name'];
authors.push(author);
}
}
return authors;
}));
}
searchOrcidPublications(id: string, properties: EnvProperties, parse: boolean = false): any { searchOrcidPublications(id: string, properties: EnvProperties, parse: boolean = false): any {
let headers = new HttpHeaders({'Accept': 'application/orcid+json'}); let headers = new HttpHeaders({'Accept': 'application/orcid+json'});
let url = properties.searchOrcidURL + id + '/works'; let url = properties.searchOrcidURL + id + '/works';
return this.http.get(url, { headers: headers }) return this.http.get(url, { headers: headers })
.pipe(map(res => res['group'])) .pipe(map(res => res['group']))
.pipe(map(request => (parse ? SearchOrcidService.parse(id, request) : request))); .pipe(map(request => (parse ? SearchOrcidService.parse(id, request) : request)));
} }
static parseOrcidAuthor(data: any, authorIds: string[], authors, addId): any { static parseOrcidAuthor(data: any, authorIds: string[], authors, addId): any {
console.log(data)
if (data[2] != null) { if (data[2] != null) {
if (addId) { if (addId) {
authorIds.push(data[2].path); authorIds.push(data[2].path);
@ -72,7 +125,12 @@ export class SearchOrcidService {
} else { } else {
author['authorFamilyName'] = ""; author['authorFamilyName'] = "";
} }
if (data[3] != null) {
author['institution'] = data[3];
}
console.log(author['institution'])
authors.push(author); authors.push(author);
return true; return true;
} }
return false; return false;

View File

@ -0,0 +1,19 @@
import { NgModule} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {SearchOrcidService} from "./searchOrcid.service";
@NgModule({
imports: [
CommonModule, FormsModule
],
declarations: [
],
providers:[
SearchOrcidService
],
exports: [
]
})
export class SearchOrcidServiceModule { }

View File

@ -37,7 +37,6 @@ export class ClaimsAdminComponent {
@Input() isConnect: boolean = false; @Input() isConnect: boolean = false;
@Input() externalPortalUrl: string; @Input() externalPortalUrl: string;
@Input() claimsInfoURL: string; @Input() claimsInfoURL: string;
@Input() userInfoURL: string;
public user: User = null; public user: User = null;
sub; sub;

View File

@ -29,7 +29,7 @@ export class DirectLinkingComponent {
// 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", "orp", "project", "context"]; validEntityTypes = ["dataset", "publication", "software", "other", "project", "context"];
sources: ClaimEntity[] = []; sources: ClaimEntity[] = [];
inlineEntity: ClaimEntity = null; inlineEntity: ClaimEntity = null;
validInput: boolean = null;//'true; validInput: boolean = null;//'true;
@ -74,7 +74,7 @@ export class DirectLinkingComponent {
this.getResearchResultById("dataset", this.id); this.getResearchResultById("dataset", this.id);
} else if (this.type == "software") { } else if (this.type == "software") {
this.getResearchResultById("software", this.id); this.getResearchResultById("software", this.id);
} else if (this.type == "orp") { } else if (this.type == "other") {
this.getResearchResultById("other", this.id); this.getResearchResultById("other", this.id);
} else { } else {
this.validInput = this.isValidInput(null); this.validInput = this.isValidInput(null);
@ -110,9 +110,9 @@ export class DirectLinkingComponent {
return false; return false;
} else if (this.type == "project" && this.showOptions.linkTo != "result") { } else if (this.type == "project" && this.showOptions.linkTo != "result") {
return false; return false;
} else if (["dataset", "publication", "software", "orp"].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", "orp"].indexOf(this.type) == -1) { } else if (["project", "dataset", "publication", "software", "other"].indexOf(this.type) == -1) {
return false; return false;
} else { } else {
return true; return true;

View File

@ -16,6 +16,7 @@ import {
import {UserManagementService} from "../../../services/user-management.service"; import {UserManagementService} from "../../../services/user-management.service";
import {Subscriber, timer} from "rxjs"; import {Subscriber, timer} from "rxjs";
import {map} from "rxjs/operators"; import {map} from "rxjs/operators";
import {LogService} from "../../../utils/log/log.service";
@Component({ @Component({
selector: 'claim-insert', selector: 'claim-insert',
@ -59,7 +60,7 @@ import {map} from "rxjs/operators";
}) })
export class ClaimInsertComponent { export class ClaimInsertComponent {
constructor(private claimService: ClaimsService, private _router: Router, private route: ActivatedRoute, constructor(private claimService: ClaimsService, private _router: Router, private route: ActivatedRoute,
private userManagementService: UserManagementService) { private userManagementService: UserManagementService, private _logService: LogService) {
} }
subscriptions = []; subscriptions = [];
ngOnDestroy() { ngOnDestroy() {
@ -127,6 +128,7 @@ export class ClaimInsertComponent {
public feedRecordsJob; public feedRecordsJob;
public claims2Insert; public claims2Insert;
public records2Insert public records2Insert
infoToLog = [];
public insert() { public insert() {
this.confirmOpen(); this.confirmOpen();
} }
@ -145,6 +147,7 @@ export class ClaimInsertComponent {
this.errorInClaims = []; this.errorInClaims = [];
this.insertedRecords = []; this.insertedRecords = [];
this.errorInRecords = []; this.errorInRecords = [];
this.infoToLog = [];
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
if (!user) { if (!user) {
this.saveAndNavigate(); this.saveAndNavigate();
@ -190,10 +193,11 @@ export class ClaimInsertComponent {
} 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));
} }
this.infoToLog.push([ result.title?result.title: result.id, entity.title?entity.title:entity.id]);
} }
if (this.inlineEntity) { if (this.inlineEntity) {
this.infoToLog.push([ this.inlineEntity.title?this.inlineEntity.title: this.inlineEntity.id, entity.title?entity.title:entity.id]);
if (this.inlineEntity.result) { if (this.inlineEntity.result) {
if (entity.result) { if (entity.result) {
@ -256,6 +260,12 @@ export class ClaimInsertComponent {
data => { data => {
this.claims2Insert = claims.length; this.claims2Insert = claims.length;
this.claimsJob = data.data; this.claimsJob = data.data;
if(this.properties.logServiceUrl) {
for(let info of this.infoToLog) {
this.subscriptions.push(this._logService.logLink(this.properties, info[0],info[1]).subscribe(res => {
}));
}
}
this.saveLocalStorage(); this.saveLocalStorage();
let timerSubscription = timer(0, 10000).pipe( let timerSubscription = timer(0, 10000).pipe(
map(() => { map(() => {
@ -375,7 +385,7 @@ export class ClaimInsertComponent {
localStorage.removeItem(this.localStoragePrefix + "claimsJob"); localStorage.removeItem(this.localStoragePrefix + "claimsJob");
localStorage.removeItem(this.localStoragePrefix + "feedRecordsJob"); localStorage.removeItem(this.localStoragePrefix + "feedRecordsJob");
this._router.navigate(['/myclaims'], {queryParams: this.params}); this._router.navigate([this.properties.myClaimsLink], {queryParams: this.params});
} }
} }

View File

@ -6,10 +6,11 @@ import {LoadingModalModule} from '../../../utils/modal/loadingModal.module';
import {ClaimInsertComponent} from './insertClaim.component'; import {ClaimInsertComponent} from './insertClaim.component';
import {ClaimServiceModule} from '../../claim-utils/service/claimsService.module'; import {ClaimServiceModule} from '../../claim-utils/service/claimsService.module';
import {IconsModule} from "../../../utils/icons/icons.module"; import {IconsModule} from "../../../utils/icons/icons.module";
import {LogServiceModule} from "../../../utils/log/LogService.module";
@NgModule({ @NgModule({
imports: [ imports: [
SharedModule, AlertModalModule, LoadingModalModule, ClaimServiceModule, IconsModule SharedModule, AlertModalModule, LoadingModalModule, ClaimServiceModule, IconsModule, LogServiceModule
], ],
declarations: [ClaimInsertComponent], declarations: [ClaimInsertComponent],
exports:[ ClaimInsertComponent] exports:[ ClaimInsertComponent]

View File

@ -30,7 +30,6 @@ import {Subscriber} from "rxjs";
export class MyClaimsComponent { export class MyClaimsComponent {
@Input() claimsInfoURL: string; @Input() claimsInfoURL: string;
@Input() communityId:string; @Input() communityId:string;
@Input() userInfoURL: string;
public user: User = null; public user: User = null;
constructor(private userManagementService: UserManagementService, private _router: Router) {} constructor(private userManagementService: UserManagementService, private _router: Router) {}

View File

@ -6,6 +6,9 @@ import {CommunityInfo} from "./community/communityInfo";
export class ConnectHelper { export class ConnectHelper {
public static getCommunityFromDomain(domain: string): string{ public static getCommunityFromDomain(domain: string): string{
if(properties.dashboard === 'irish') {
return properties.adminToolsCommunity;
}
if(properties.environment == "development" && if(properties.environment == "development" &&
(properties.adminToolsPortalType == "connect" || properties.adminToolsPortalType == "community" (properties.adminToolsPortalType == "connect" || properties.adminToolsPortalType == "community"
|| properties.adminToolsPortalType == "aggregator" || properties.adminToolsPortalType == "eosc")) { || properties.adminToolsPortalType == "aggregator" || properties.adminToolsPortalType == "eosc")) {

View File

@ -1,17 +1,18 @@
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
import {StakeholderEntities} from "../../monitor/entities/stakeholder"; import {StakeholderConfiguration} from "../../monitor-admin/utils/indicator-utils";
export class PortalUtils{ export class PortalUtils {
portalTypes: Option[] = [ portalTypes: Option[] = [
{value: 'explore', label: 'Explore Portal'}, {value: 'explore', label: 'Explore Portal'},
{value: 'connect', label: 'Connect portal'}, {value: 'connect', label: 'Connect portal'},
{value: 'monitor', label: 'Monitor portal'}, {value: 'monitor', label: 'Monitor portal'},
{value: 'community', label: 'Community Gateway'}, {value: 'community', label: 'Community Gateway'},
{value: 'funder', label: StakeholderEntities.FUNDER + ' Dashboard'}, {value: 'funder', label: StakeholderConfiguration.ENTITIES.funder + ' ' + StakeholderConfiguration.ENTITIES.stakeholder},
{value: 'ri', label: StakeholderEntities.RI + ' Dashboard'}, {value: 'ri', label: StakeholderConfiguration.ENTITIES.ri + ' ' + StakeholderConfiguration.ENTITIES.stakeholder},
{value: 'organization', label: StakeholderEntities.ORGANIZATION + ' Dashboard'}, {value: 'organization', label: StakeholderConfiguration.ENTITIES.organization + ' ' + StakeholderConfiguration.ENTITIES.stakeholder},
{value: 'project', label: StakeholderEntities.PROJECT + ' Dashboard'} {value: 'project', label: StakeholderConfiguration.ENTITIES.project + ' ' + StakeholderConfiguration.ENTITIES.stakeholder},
{value: 'country', label: StakeholderConfiguration.ENTITIES.country + ' ' + StakeholderConfiguration.ENTITIES.stakeholder},
]; ];
} }

View File

@ -83,7 +83,11 @@ export class LayoutService {
* Add hasStickyHeaderOnMobile: true in order to activate uk-sticky in header of mobile/tablet devices. * Add hasStickyHeaderOnMobile: true in order to activate uk-sticky in header of mobile/tablet devices.
* */ * */
private hasStickyHeaderOnMobileSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); private hasStickyHeaderOnMobileSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
/**
* Add a class in root element of the html. (For different theme apply)
* Handle it manually in the component, it doesn't use data
* */
private rootClassSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
private subscriptions: any[] = []; private subscriptions: any[] = [];
ngOnDestroy() { ngOnDestroy() {
@ -329,4 +333,14 @@ export class LayoutService {
setHasStickyHeaderOnMobile(value: boolean) { setHasStickyHeaderOnMobile(value: boolean) {
this.hasStickyHeaderOnMobileSubject.next(value); this.hasStickyHeaderOnMobileSubject.next(value);
} }
get rootClass(): Observable<string> {
return this.rootClassSubject.asObservable();
}
setRootClass(value: string = null): void {
if(this.rootClassSubject.value != value) {
this.rootClassSubject.next(value);
}
}
} }

View File

@ -28,6 +28,9 @@
[class.hide-on-close]="backItem.icon">{{backItem.title}}</span> [class.hide-on-close]="backItem.icon">{{backItem.title}}</span>
</a> </a>
</div> </div>
<div *ngIf="logoURL" id="sidebar_logo" class="uk-margin-top">
<img [src]="logoURL">
</div>
<div *ngIf="items.length > 0" class="menu_section uk-margin-large-top" [class.mobile]="mobile" style="min-height: 30vh"> <div *ngIf="items.length > 0" class="menu_section uk-margin-large-top" [class.mobile]="mobile" style="min-height: 30vh">
<ul #nav class="uk-list uk-nav" [class.uk-list-large]="mobile" <ul #nav class="uk-list uk-nav" [class.uk-list-large]="mobile"
[class.uk-nav-default]="!mobile" [class.uk-nav-primary]="mobile" uk-nav="duration: 400"> [class.uk-nav-default]="!mobile" [class.uk-nav-primary]="mobile" uk-nav="duration: 400">

View File

@ -28,6 +28,7 @@ export class SideBarComponent implements OnInit, AfterViewInit, OnDestroy, OnCha
@Input() activeSubItem: string = ''; @Input() activeSubItem: string = '';
@Input() backItem: MenuItem = null; @Input() backItem: MenuItem = null;
@Input() queryParamsHandling; @Input() queryParamsHandling;
@Input() logoURL: string;
@ViewChild("nav") nav: ElementRef; @ViewChild("nav") nav: ElementRef;
@ViewChild("sidebar_offcanvas") sidebar_offcanvas: ElementRef; @ViewChild("sidebar_offcanvas") sidebar_offcanvas: ElementRef;
public offset: number; public offset: number;

View File

@ -0,0 +1,48 @@
import {ChangeDetectorRef, Directive, OnInit} from "@angular/core";
import {BaseComponent} from "../../../sharedComponents/base/base.component";
import {MenuItem} from "../../../sharedComponents/menu";
import {LayoutService} from "./layout.service";
@Directive()
export class SidebarBaseComponent extends BaseComponent implements OnInit {
hasSidebar: boolean = false;
hasInternalSidebar: boolean = false;
hasAdminMenu: boolean = false;
/**
* Menu Items
* */
sideBarItems: MenuItem[] = [];
adminMenuItems: MenuItem[] = [];
backItem: MenuItem = null;
protected layoutService: LayoutService;
protected cdr: ChangeDetectorRef;
constructor() {
super();
}
ngOnInit() {
this.subscriptions.push(this.layoutService.hasSidebar.subscribe(hasSidebar => {
this.hasSidebar = hasSidebar;
this.cdr.detectChanges();
}));
this.subscriptions.push(this.layoutService.hasInternalSidebar.subscribe(hasInternalSidebar => {
this.hasInternalSidebar = hasInternalSidebar;
this.cdr.detectChanges();
}));
this.subscriptions.push(this.layoutService.hasAdminMenu.subscribe(hasAdminMenu => {
this.hasAdminMenu = hasAdminMenu;
this.cdr.detectChanges();
}));
this.layoutService.setOpen(true);
}
public get open() {
return this.layoutService.open;
}
public get hover() {
return this.layoutService.hover;
}
}

View File

@ -8,14 +8,7 @@ import {
SimpleChanges, SimpleChanges,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { import {UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators} from '@angular/forms';
UntypedFormArray,
UntypedFormBuilder,
UntypedFormControl,
UntypedFormGroup,
ValidatorFn,
Validators
} from '@angular/forms';
import {AlertModal} from "../../../utils/modal/alert"; import {AlertModal} from "../../../utils/modal/alert";
import {UserRegistryService} from "../../../services/user-registry.service"; import {UserRegistryService} from "../../../services/user-registry.service";
import {EnvProperties} from "../../../utils/properties/env-properties"; import {EnvProperties} from "../../../utils/properties/env-properties";
@ -29,7 +22,6 @@ import {forkJoin, of, Subscription} from "rxjs";
import {NotificationHandler} from "../../../utils/notification-handler"; 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 notification = CKEDITOR.plugins.notification;
import {InputComponent} from "../../../sharedComponents/input/input.component"; import {InputComponent} from "../../../sharedComponents/input/input.component";
class InvitationResponse { class InvitationResponse {
@ -148,9 +140,8 @@ 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).subscribe(users => { this.subs.push(this.userRegistryService.getActive(this.type, this.id, this.role, true).subscribe(users => {
this.active = users; this.active = users;
// users.forEach(user => this.active.push(user));
this.filterActiveBySearch(this.filterForm.value.active); this.filterActiveBySearch(this.filterForm.value.active);
this.loadActive = false; this.loadActive = false;
this.exists = true; this.exists = true;
@ -162,7 +153,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).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;
@ -214,8 +205,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.mapType(this.type) + '.' + this.id, Validators.required), name: this.fb.control(Role.roleName(this.type, this.id), Validators.required),
description: this.fb.control(Role.mapType(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();
@ -285,7 +276,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges {
if (!this.pending.includes(response.email)) { if (!this.pending.includes(response.email)) {
this.pending.push(response.email); this.pending.push(response.email);
} }
if(this.notificationFn) { if(this.notificationFn && properties.notificationsAPIURL) {
return this.notificationService.sendNotification(this.notificationFn(this.name, response.email, this.role, response.invitation)).pipe(map(notification => { return this.notificationService.sendNotification(this.notificationFn(this.name, response.email, this.role, response.invitation)).pipe(map(notification => {
return notification; return notification;
}), tap(() => { }), tap(() => {

View File

@ -105,7 +105,7 @@ export class SubscribersComponent implements OnInit, OnDestroy, OnChanges {
updateList() { updateList() {
this.loading = true; this.loading = true;
this.subs.push( this.userRegistryService.getActive(this.type, this.id, 'member').subscribe(users => { this.subs.push( this.userRegistryService.getActive(this.type, this.id, 'member', true).subscribe(users => {
this.subscribers = users; this.subscribers = users;
this.filterBySearch(this.filterForm.value.keyword); this.filterBySearch(this.filterForm.value.keyword);
this.loading = false; this.loading = false;

View File

@ -15,7 +15,7 @@ import {FullScreenModalComponent} from '../utils/modal/full-screen-modal/full-sc
@Component({ @Component({
selector: 'deposit-first-page', selector: 'deposit-first-page',
template: ` template: `
<div class="deposit"> <div>
<div class="uk-container uk-container-large uk-section uk-section-small uk-padding-remove-bottom"> <div class="uk-container uk-container-large uk-section uk-section-small uk-padding-remove-bottom">
<div class="uk-padding-small uk-padding-remove-horizontal"> <div class="uk-padding-small uk-padding-remove-horizontal">
<breadcrumbs [breadcrumbs]="breadcrumbs"></breadcrumbs> <breadcrumbs [breadcrumbs]="breadcrumbs"></breadcrumbs>

View File

@ -11,7 +11,7 @@ import * as url from "url";
@Injectable() @Injectable()
export class ErrorInterceptorService implements HttpInterceptor { export class ErrorInterceptorService implements HttpInterceptor {
private static UNAUTHORIZED_WHITELIST = [properties.userInfoUrl, properties.orcidAPIURL, properties.registryUrl? (properties.registryUrl + 'verification/'):null, properties.eoscDataTransferAPI].filter(value => !!value); private static UNAUTHORIZED_WHITELIST = [properties.orcidAPIURL, properties.registryUrl? (properties.registryUrl + 'verification/'):null, properties.eoscDataTransferAPI].filter(value => !!value);
private url: string = null; private url: string = null;
constructor(private router: Router) { constructor(private router: Router) {

View File

@ -9,7 +9,8 @@
<landing-header *ngIf="resultLandingInfo" [properties]="properties" [title]="title" <landing-header *ngIf="resultLandingInfo" [properties]="properties" [title]="title"
[subTitle]="resultLandingInfo.subtitle" [underCuration]="resultLandingInfo.underCurationMessage" [subTitle]="resultLandingInfo.subtitle" [underCuration]="resultLandingInfo.underCurationMessage"
[entityType]="entityType" [types]="resultLandingInfo.types" [entityType]="entityType" [types]="resultLandingInfo.types"
[year]="resultLandingInfo.date" [embargoEndDate]="resultLandingInfo.embargoEndDate"> [year]="resultLandingInfo.date" [embargoEndDate]="resultLandingInfo.embargoEndDate"
[publiclyFunded]="resultLandingInfo.publiclyFunded" [projects]="resultLandingInfo.fundedByProjects">
</landing-header> </landing-header>
<landing-header *ngIf="organizationInfo" [properties]="properties" [title]="title" <landing-header *ngIf="organizationInfo" [properties]="properties" [title]="title"
[subTitle]="(organizationInfo.name && organizationInfo.title.name !== organizationInfo.name)?organizationInfo.name:null" [subTitle]="(organizationInfo.name && organizationInfo.title.name !== organizationInfo.name)?organizationInfo.name:null"

View File

@ -93,10 +93,12 @@ import {RouterHelper} from "../../utils/routerHelper.class";
{{instance.downloadNames.join("; ")}} {{instance.downloadNames.join("; ")}}
</a> </a>
</span> </span>
<div *ngIf="instance.types?.length > 0 || instance.years?.length > 0" class="uk-text-meta"> <div *ngIf="instance.types?.length > 0 || instance.years?.length > 0 || instance.peerReviewed" class="uk-text-meta">
<span *ngIf="instance.types?.length > 0" class="uk-text-capitalize">{{instance.types.join(" . ")}}</span> <span *ngIf="instance.types?.length > 0" class="uk-text-capitalize">{{instance.types.join(" . ")}}</span>
<span *ngIf="instance.types?.length > 0 && instance.years?.length > 0"> . </span> <span *ngIf="instance.types?.length > 0 && instance.years?.length > 0"> . </span>
<span *ngIf="instance.years?.length > 0">{{instance.years.join(" . ")}}</span> <span *ngIf="instance.years?.length > 0">{{instance.years.join(" . ")}}</span>
<span *ngIf="(instance.types?.length > 0 || instance.years?.length > 0) && instance.peerReviewed"> . </span>
<span *ngIf="instance.peerReviewed">Peer-reviewed</span>
</div> </div>
<div *ngIf="instance.license" class="uk-text-meta uk-text-truncate" uk-tooltip [title]="instance.license"> <div *ngIf="instance.license" class="uk-text-meta uk-text-truncate" uk-tooltip [title]="instance.license">
License: License:

View File

@ -31,22 +31,20 @@ import {RouterHelper} from "../../utils/routerHelper.class";
<!-- types --> <!-- types -->
<span *ngIf="entityType" class="uk-flex-inline uk-flex-middle uk-flex-wrap" <span *ngIf="entityType" class="uk-flex-inline uk-flex-middle uk-flex-wrap"
[class.other-separator]="types && removeUnknown(types, true).length > 0"> [class.other-separator]="types && removeUnknown(types, true).length > 0">
<span class="uk-margin-xsmall-right"> <icon *ngIf="entityType.toLowerCase() == 'publication'" name="description" type="outlined"
<icon *ngIf="entityType.toLowerCase() == 'publication'" name="description" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
[flex]="true" [ratio]="0.8"></icon> <icon *ngIf="entityType.toLowerCase() == 'research data'" name="database" type="outlined"
<icon *ngIf="entityType.toLowerCase() == 'research data'" name="database" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
[flex]="true" [ratio]="0.8"></icon> <icon *ngIf="entityType.toLowerCase() == 'research software'" name="integration_instructions"
<icon *ngIf="entityType.toLowerCase() == 'research software'" name="integration_instructions" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
type="outlined" [flex]="true" [ratio]="0.8"></icon> <icon *ngIf="entityType.toLowerCase() == 'other research product'" name="apps" type="outlined"
<icon *ngIf="entityType.toLowerCase() == 'other research product'" name="apps" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
[flex]="true" [ratio]="0.8"></icon> <icon *ngIf="entityType.toLowerCase() == 'project'" name="assignment_turned_in" type="outlined"
<icon *ngIf="entityType.toLowerCase() == 'project'" name="assignment_turned_in" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
[flex]="true" [ratio]="0.8"></icon> <icon *ngIf="entityType.toLowerCase() == 'data source'" name="note_add" type="outlined"
<icon *ngIf="entityType.toLowerCase() == 'data source'" name="note_add" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
[flex]="true" [ratio]="0.8"></icon> <icon *ngIf="entityType.toLowerCase() == 'organization'" name="corporate_fare" type="outlined"
<icon *ngIf="entityType.toLowerCase() == 'organization'" name="corporate_fare" type="outlined" [flex]="true" [ratio]="0.8" class="uk-margin-xsmall-right"></icon>
[flex]="true" [ratio]="0.8"></icon>
</span>
<u class="uk-text-capitalize uk-text-bolder">{{entityType}}</u> <u class="uk-text-capitalize uk-text-bolder">{{entityType}}</u>
<span *ngIf="types && removeUnknown(types, true).length > 0"> <span *ngIf="types && removeUnknown(types, true).length > 0">
<icon name="keyboard_double_arrow_right" [flex]="true" [ratio]="0.8"></icon> <icon name="keyboard_double_arrow_right" [flex]="true" [ratio]="0.8"></icon>
@ -150,6 +148,9 @@ import {RouterHelper} from "../../utils/routerHelper.class";
<ng-container *ngIf="thematic"> <ng-container *ngIf="thematic">
<span>Thematic</span> <span>Thematic</span>
</ng-container> </ng-container>
<ng-container *ngIf="publiclyFunded">
<span>Publicly funded</span>
</ng-container>
<!-- Projects --> <!-- Projects -->
<span *ngIf="projects && projects.length > 0" <span *ngIf="projects && projects.length > 0"
[attr.uk-tooltip]="projects.length > projectsLimit ? 'cls: uk-invisible' : 'pos: top; cls: uk-active'" title="Funded by"> [attr.uk-tooltip]="projects.length > projectsLimit ? 'cls: uk-invisible' : 'pos: top; cls: uk-active'" title="Funded by">
@ -246,6 +247,7 @@ export class EntityMetadataComponent {
@Input() type; // data provider landing @Input() type; // data provider landing
@Input() provenanceAction: string; // search result @Input() provenanceAction: string; // search result
@Input() relationName: string; // search result @Input() relationName: string; // search result
@Input() publiclyFunded: boolean; // search result
@Input() projects: Project[]; @Input() projects: Project[];
@Input() organizations: Organization[]; @Input() organizations: Organization[];
@Input() subjects: string[]; @Input() subjects: string[];

View File

@ -0,0 +1,16 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {EntityMetadataComponent} from './entity-metadata.component';
import {IconsModule} from '../../utils/icons/icons.module';
import {AlertModalModule} from '../../utils/modal/alertModal.module';
import {ShowPublisherModule} from "./showPublisher.module";
@NgModule({
imports: [
CommonModule, IconsModule, AlertModalModule, ShowPublisherModule
],
declarations: [EntityMetadataComponent],
providers:[],
exports: [EntityMetadataComponent]
})
export class EntityMetadataModule { }

View File

@ -21,7 +21,7 @@ import {AlertModal} from "../../../utils/modal/alert";
[languages]="languages" [programmingLanguages]="programmingLanguages" [languages]="languages" [programmingLanguages]="programmingLanguages"
[compatibility]="compatibility" [aggregationStatus]="aggregationStatus" [compatibility]="compatibility" [aggregationStatus]="aggregationStatus"
[thematic]="thematic" [type]="type" [prevPath]="prevPath" [thematic]="thematic" [type]="type" [prevPath]="prevPath"
[countries]="countries" [projects]="projects" [countries]="countries" [publiclyFunded]="publiclyFunded" [projects]="projects"
></entity-metadata> ></entity-metadata>
</div> </div>
<div *ngIf="authors"> <div *ngIf="authors">
@ -63,5 +63,6 @@ export class LandingHeaderComponent {
@Input() type; // data provider landing @Input() type; // data provider landing
@Input() prevPath: string = ""; @Input() prevPath: string = "";
@Input() countries; @Input() countries;
@Input() publiclyFunded;
@Input() projects; @Input() projects;
} }

View File

@ -4,12 +4,12 @@ import {CommonModule} from "@angular/common";
import {LandingModule} from "../landing.module"; import {LandingModule} from "../landing.module";
import {ShowAuthorsModule} from "../../../utils/authors/showAuthors.module"; import {ShowAuthorsModule} from "../../../utils/authors/showAuthors.module";
import {IconsModule} from "src/app/openaireLibrary/utils/icons/icons.module"; import {IconsModule} from "src/app/openaireLibrary/utils/icons/icons.module";
import {ShowPublisherModule} from "../showPublisher.module";
import {RouterModule} from "@angular/router"; import {RouterModule} from "@angular/router";
import {ResultLandingUtilsModule} from "../resultLandingUtils.module"; import {ResultLandingUtilsModule} from "../resultLandingUtils.module";
import {EntityMetadataModule} from "../entity-metadata.module";
@NgModule({ @NgModule({
imports: [CommonModule, LandingModule, ShowAuthorsModule, IconsModule, ShowPublisherModule, RouterModule, ResultLandingUtilsModule], imports: [CommonModule, LandingModule, ShowAuthorsModule, IconsModule, RouterModule, ResultLandingUtilsModule, EntityMetadataModule],
declarations: [LandingHeaderComponent], declarations: [LandingHeaderComponent],
exports: [LandingHeaderComponent] exports: [LandingHeaderComponent]
}) })

View File

@ -265,7 +265,8 @@ export class ParsingFunctions {
"types": [], "types": [],
"years": [], "years": [],
"license": "", "license": "",
"fulltext": "" "fulltext": "",
"peerReviewed": null
}; };
if (instance.hasOwnProperty("hostedby")) { if (instance.hasOwnProperty("hostedby")) {
@ -359,6 +360,10 @@ export class ParsingFunctions {
available.fulltext = instance['fulltext']; available.fulltext = instance['fulltext'];
} }
if(instance.hasOwnProperty("refereed") && instance.refereed.classname == "peerReviewed") {
available.peerReviewed = true;
}
hostedBy_collectedFrom.push(available); hostedBy_collectedFrom.push(available);
} }

View File

@ -9,7 +9,6 @@ import {ShowSubjectsComponent} from './showSubjects.component';
import {FundedByComponent} from './fundedBy.component'; import {FundedByComponent} from './fundedBy.component';
import {AvailableOnComponent} from './availableOn.component'; import {AvailableOnComponent} from './availableOn.component';
import {TabTableComponent} from './tabTable.component'; import {TabTableComponent} from './tabTable.component';
import {ShowPublisherComponent} from "./showPublisher.component";
import {ShowPublisherModule} from "./showPublisher.module"; import {ShowPublisherModule} from "./showPublisher.module";
import {RelatedToComponent} from "./relatedTo.component"; import {RelatedToComponent} from "./relatedTo.component";
import {FosComponent} from "./fos.component"; import {FosComponent} from "./fos.component";
@ -17,13 +16,11 @@ import {SdgComponent} from "./sdg.component";
import {IconsModule} from "../../utils/icons/icons.module"; import {IconsModule} from "../../utils/icons/icons.module";
import {AlertModalModule} from "../../utils/modal/alertModal.module"; import {AlertModalModule} from "../../utils/modal/alertModal.module";
import { SearchInputModule } from '../../sharedComponents/search-input/search-input.module'; import { SearchInputModule } from '../../sharedComponents/search-input/search-input.module';
import {EntityMetadataComponent} from "./entity-metadata.component";
import {IconsService} from "../../utils/icons/icons.service"; import {IconsService} from "../../utils/icons/icons.service";
import {book, closed_access, cog, database, earth, open_access, unknown_access} from "../../utils/icons/icons"; import {book, closed_access, cog, database, earth, open_access, unknown_access} from "../../utils/icons/icons";
import {FullScreenModalModule} from "../../utils/modal/full-screen-modal/full-screen-modal.module"; import {FullScreenModalModule} from "../../utils/modal/full-screen-modal/full-screen-modal.module";
import {MobileDropdownModule} from "../../utils/mobile-dropdown/mobile-dropdown.module"; import {MobileDropdownModule} from "../../utils/mobile-dropdown/mobile-dropdown.module";
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, FormsModule, RouterModule, PagingModule, ShowPublisherModule, IconsModule, AlertModalModule, CommonModule, FormsModule, RouterModule, PagingModule, ShowPublisherModule, IconsModule, AlertModalModule,
@ -32,15 +29,14 @@ import {MobileDropdownModule} from "../../utils/mobile-dropdown/mobile-dropdown.
declarations: [ declarations: [
ShowIdentifiersComponent,ShowSubjectsComponent, ShowIdentifiersComponent,ShowSubjectsComponent,
FundedByComponent,AvailableOnComponent,TabTableComponent, FundedByComponent,AvailableOnComponent,TabTableComponent,
RelatedToComponent, FosComponent, SdgComponent, RelatedToComponent, FosComponent, SdgComponent
EntityMetadataComponent
], ],
providers:[ providers:[
], ],
exports: [ exports: [
ShowIdentifiersComponent, ShowSubjectsComponent, ShowIdentifiersComponent, ShowSubjectsComponent,
FundedByComponent,AvailableOnComponent, TabTableComponent, ShowPublisherComponent, FundedByComponent,AvailableOnComponent, TabTableComponent,
RelatedToComponent, FosComponent, SdgComponent, EntityMetadataComponent RelatedToComponent, FosComponent, SdgComponent
] ]
}) })
export class ResultLandingUtilsModule { export class ResultLandingUtilsModule {

View File

@ -27,7 +27,7 @@ import {HelperFunctions} from "../../../utils/HelperFunctions.class";
<ul class="uk-list uk-margin"> <ul class="uk-list uk-margin">
<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" [isCard]="false" [prevPath]="prevPath" [showInline]="true" [showOrcid]="false" [prevPath]="prevPath" [showInline]="true"
[isDeletedByInferenceModal]="true"></result-preview> [isDeletedByInferenceModal]="true"></result-preview>
</li> </li>
</ul> </ul>

View File

@ -229,6 +229,7 @@
[publisher]="resultLandingInfo.publisher" [journal]="resultLandingInfo.journal" [publisher]="resultLandingInfo.publisher" [journal]="resultLandingInfo.journal"
[languages]="resultLandingInfo.languages" [programmingLanguages]="resultLandingInfo.programmingLanguages" [languages]="resultLandingInfo.languages" [programmingLanguages]="resultLandingInfo.programmingLanguages"
[prevPath]="prevPath" [countries]="resultLandingInfo.countries" [prevPath]="prevPath" [countries]="resultLandingInfo.countries"
[publiclyFunded]="resultLandingInfo.publiclyFunded"
[projects]="resultLandingInfo.fundedByProjects"> [projects]="resultLandingInfo.fundedByProjects">
</landing-header> </landing-header>
<!-- Labels --> <!-- Labels -->
@ -454,6 +455,29 @@
<!-- </div>--> <!-- </div>-->
</div> </div>
</div> </div>
<div *ngIf="resultLandingInfo && resultLandingInfo.oaRoutes && !viewAll"
class="uk-margin-medium-top uk-padding uk-padding-remove-vertical">
<div class="landing-oaroutes-card uk-text-small uk-flex uk-padding-small">
<div>
<div class="uk-flex uk-flex-top" uk-grid>
<div *ngIf="resultLandingInfo.oaRoutes.green" class="uk-flex-nowrap uk-flex uk-flex-middle uk-margin-xsmall-bottom uk-margin-remove-top">
<div class="dot green"></div>
<div class="uk-text-capitalize">Green</div>
</div>
<div *ngIf="resultLandingInfo.oaRoutes.oaColor" class="uk-flex-nowrap uk-flex uk-flex-middle uk-margin-xsmall-bottom uk-margin-remove-top">
<div class="dot" [ngClass]="resultLandingInfo.oaRoutes.oaColor"></div>
<div class="uk-text-capitalize">{{resultLandingInfo.oaRoutes.oaColor}}</div>
</div>
</div>
<div *ngIf="resultLandingInfo.oaRoutes.isInDiamondJournal" class="uk-flex-nowrap uk-flex uk-flex-middle uk-margin-xsmall-bottom uk-text-truncate">
<div class="dot diamond"></div>
<div>Published in a Diamond OA journal</div>
</div>
</div>
</div>
</div>
<div class="uk-margin-medium-top uk-list uk-list-large uk-padding uk-padding-remove-vertical" [class.uk-list-divider]="!viewAll"> <div class="uk-margin-medium-top uk-list uk-list-large uk-padding uk-padding-remove-vertical" [class.uk-list-divider]="!viewAll">
<!-- EOSC Services--> <!-- EOSC Services-->
<div *ngIf="resultLandingInfo.eoscSubjects?.length > 0 && properties.adminToolsPortalType == 'eosc' <div *ngIf="resultLandingInfo.eoscSubjects?.length > 0 && properties.adminToolsPortalType == 'eosc'
@ -523,6 +547,7 @@
[date]="resultLandingInfo.dateofacceptance" [embargoEndDate]="resultLandingInfo.embargoEndDate" [date]="resultLandingInfo.dateofacceptance" [embargoEndDate]="resultLandingInfo.embargoEndDate"
[publisher]="resultLandingInfo.publisher" [journal]="resultLandingInfo.journal" [publisher]="resultLandingInfo.publisher" [journal]="resultLandingInfo.journal"
[languages]="resultLandingInfo.languages" [programmingLanguages]="resultLandingInfo.programmingLanguages" [languages]="resultLandingInfo.languages" [programmingLanguages]="resultLandingInfo.programmingLanguages"
[publiclyFunded]="resultLandingInfo.publiclyFunded" [projects]="resultLandingInfo.fundedByProjects"
[isMobile]="true" [prevPath]="prevPath"> [isMobile]="true" [prevPath]="prevPath">
</landing-header> </landing-header>
<div class="uk-text-small"> <div class="uk-text-small">
@ -540,6 +565,31 @@
<fos [subjects]="resultLandingInfo.fos" (suggestClicked)="suggestMobileClicked($event)" <fos [subjects]="resultLandingInfo.fos" (suggestClicked)="suggestMobileClicked($event)"
(viewAllClicked)="viewAllMobile=$event; openFsModal(fosFsModal, 'Fields of Science (FoS)')"></fos> (viewAllClicked)="viewAllMobile=$event; openFsModal(fosFsModal, 'Fields of Science (FoS)')"></fos>
</div> </div>
<!-- OA Routes -->
<div *ngIf="resultLandingInfo.oaRoutes && !viewAllMobile" class="uk-margin-top uk-grid uk-grid-small uk-grid-divider" uk-grid>
<div class="uk-width-auto uk-text-meta">
Access Routes
</div>
<div class="uk-width-expand uk-flex">
<div>
<div class="uk-flex uk-flex-top" uk-grid>
<div *ngIf="resultLandingInfo.oaRoutes.green" class="uk-flex-nowrap uk-flex uk-flex-middle uk-margin-xsmall-bottom uk-margin-remove-top">
<div class="dot green"></div>
<div class="uk-text-capitalize">Green</div>
</div>
<div *ngIf="resultLandingInfo.oaRoutes.oaColor" class="uk-flex-nowrap uk-flex uk-flex-middle uk-margin-xsmall-bottom uk-margin-remove-top">
<div class="dot" [ngClass]="resultLandingInfo.oaRoutes.oaColor"></div>
<div class="uk-text-capitalize">{{resultLandingInfo.oaRoutes.oaColor}}</div>
</div>
</div>
<div *ngIf="resultLandingInfo.oaRoutes.isInDiamondJournal" class="uk-flex-nowrap uk-flex uk-flex-middle uk-margin-xsmall-bottom uk-text-truncate">
<div class="dot diamond"></div>
<div>Published in a Diamond OA journal</div>
</div>
</div>
</div>
</div>
</div> </div>
<div class="uk-section uk-margin-top uk-text-large uk-text-empashis uk-text-bold"> <div class="uk-section uk-margin-top uk-text-large uk-text-empashis uk-text-bold">
<hr> <hr>

View File

@ -142,6 +142,19 @@ export class ResultLandingService {
this.resultLandingInfo.publisher = data[0].publisher; this.resultLandingInfo.publisher = data[0].publisher;
this.resultLandingInfo.description = this.parsingFunctions.parseDescription(data[0] && data[0].description ? data[0].description : []); this.resultLandingInfo.description = this.parsingFunctions.parseDescription(data[0] && data[0].description ? data[0].description : []);
this.resultLandingInfo.embargoEndDate = data[0].embargoenddate ? Dates.getDate(data[0].embargoenddate) : null; this.resultLandingInfo.embargoEndDate = data[0].embargoenddate ? Dates.getDate(data[0].embargoenddate) : null;
if(data[0].hasOwnProperty("publiclyfunded") && data[0].publiclyfunded) {
this.resultLandingInfo.publiclyFunded = data[0].publiclyfunded;
}
if((data[0].hasOwnProperty("isgreen") && data[0].isgreen)
|| (data[0].hasOwnProperty("openaccesscolor") && data[0].openaccesscolor)
|| (data[0].hasOwnProperty("isindiamondjournal") && data[0].isindiamondjournal)) {
this.resultLandingInfo.oaRoutes = {
"green": data[0].isgreen,
"oaColor": data[0].openaccesscolor,
"isInDiamondJournal":data[0].isindiamondjournal
};
}
} }
if (data[0]['bestaccessright'] && data[0]['bestaccessright'].hasOwnProperty("classname")) { if (data[0]['bestaccessright'] && data[0]['bestaccessright'].hasOwnProperty("classname")) {
@ -325,11 +338,13 @@ export class ResultLandingService {
if (this.resultLandingInfo.fos) { if (this.resultLandingInfo.fos) {
this.resultLandingInfo.fos.sort((a, b) => a.id.localeCompare(b.id)); this.resultLandingInfo.fos.sort((a, b) => a.id.localeCompare(b.id));
} }
this.resultLandingInfo.sdg = subjectResults[4]; if(properties.dashboard != "irish") {
if (this.resultLandingInfo.sdg) { this.resultLandingInfo.sdg = subjectResults[4];
this.resultLandingInfo.sdg.sort((a, b) => { if (this.resultLandingInfo.sdg) {
return HelperFunctions.sortSDGs(a, b); this.resultLandingInfo.sdg.sort((a, b) => {
}) return HelperFunctions.sortSDGs(a, b);
})
}
} }
// if(!this.resultLandingInfo.eoscSubjects) { // if(!this.resultLandingInfo.eoscSubjects) {

View File

@ -27,7 +27,6 @@ export class UserComponent {
public errorCode: string = ""; public errorCode: string = "";
public redirectUrl: string = ""; public redirectUrl: string = "";
public routerHelper: RouterHelper = new RouterHelper(); public routerHelper: RouterHelper = new RouterHelper();
public loginUrl;
public properties: EnvProperties = properties; public properties: EnvProperties = properties;
@Input() mainComponent = true; @Input() mainComponent = true;
@ -40,7 +39,6 @@ export class UserComponent {
} }
ngOnInit() { ngOnInit() {
this.loginUrl = this.properties.loginUrl;
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
this.server = false; this.server = false;
this.userManagementsService.updateUserInfo( () => { this.userManagementsService.updateUserInfo( () => {

View File

@ -122,12 +122,8 @@ export class UserMiniComponent implements OnInit, OnChanges {
public isAuthorized: boolean = false; public isAuthorized: boolean = false;
@Input() public mobileView: boolean = false; @Input() public mobileView: boolean = false;
public firstLetters: string = ""; public firstLetters: string = "";
public server: boolean = true;
public routerHelper: RouterHelper = new RouterHelper(); public routerHelper: RouterHelper = new RouterHelper();
@Input() userMenuItems; @Input() userMenuItems;
@Input() logInUrl;
@Input() logOutUrl;
@Input() cookieDomain;
@Input() notificationConfiguration: NotificationConfiguration; @Input() notificationConfiguration: NotificationConfiguration;
@ViewChild('notificationsSidebar') notificationsSidebar: NotificationsSidebarComponent; @ViewChild('notificationsSidebar') notificationsSidebar: NotificationsSidebarComponent;
public showNotifications = false; public showNotifications = false;
@ -137,9 +133,6 @@ export class UserMiniComponent implements OnInit, OnChanges {
} }
ngOnInit() { ngOnInit() {
if (typeof document !== 'undefined') {
this.server = false;
}
this.initUser(); this.initUser();
} }

View File

@ -1,4 +1,5 @@
import {stakeholderTypes} from "../../monitor/entities/stakeholder"; import {StakeholderConfiguration} from "../../monitor-admin/utils/indicator-utils";
export class User { export class User {
email: string; email: string;
@ -9,6 +10,7 @@ export class User {
expirationDate: number; expirationDate: number;
role: string[]; role: string[];
accessToken?: string; accessToken?: string;
orcid?: string;
refreshToken?: string; refreshToken?: string;
constructor(info: any) { constructor(info: any) {
@ -22,6 +24,9 @@ export class User {
if(info.refreshToken) { if(info.refreshToken) {
this.refreshToken = info.refreshToken; this.refreshToken = info.refreshToken;
} }
if(info.orcid) {
this.orcid = info.orcid;
}
this.fullname = (info.name) ? info.name : ""; this.fullname = (info.name) ? info.name : "";
if (this.fullname == "") { if (this.fullname == "") {
if (this.firstname != "") { if (this.firstname != "") {
@ -37,7 +42,7 @@ export class User {
this.role = []; this.role = [];
if (info.roles) { if (info.roles) {
info.roles.forEach(role => { info.roles.forEach(role => {
this.role.push(role); this.role.push(decodeURIComponent(role).replace('$$', '::'));
}); });
} else { } else {
if (info.edu_person_entitlements) { if (info.edu_person_entitlements) {
@ -63,20 +68,31 @@ export class Session {
var cookie = COOKIE.getCookie(COOKIE.cookieName_id); var cookie = COOKIE.getCookie(COOKIE.cookieName_id);
return (cookie != null && cookie != ""); return (cookie != null && cookie != "");
} }
public static clearReloadUrl() {
COOKIE.setCookie("reloadURLs", JSON.stringify([]), -1);
}
public static setReloadUrl(host: string, path: string, params: string, fragment: string) { public static setReloadUrl(host: string, path: string, params: string, fragment: string) {
var URL = {}; let URLs:any[] = this.getReloadUrl();
let URL = {};
URL["host"] = host; URL["host"] = host;
URL["path"] = path; URL["path"] = path;
URL["params"] = params; URL["params"] = params;
URL["fragment"] = fragment; URL["fragment"] = fragment;
COOKIE.setCookie("reloadURL", JSON.stringify(URL), -1); URLs.push(URL);
COOKIE.setCookie("reloadURLs", JSON.stringify(URLs), -1);
} }
public static getReloadUrl() { public static getReloadUrl() {
var URL = COOKIE.getCookie("reloadURL"); let URLs = COOKIE.getCookie("reloadURLs");
URL = JSON.parse(URL); let array = JSON.parse(URLs);
return URL; return array?array:[];
}
public static popReloadUrl() {
let array = this.getReloadUrl();
let Url = array.length>0?array[0]:null;
COOKIE.setCookie("reloadURLs", JSON.stringify(array.slice(1)), -1);
return Url;
} }
@ -100,7 +116,7 @@ export class Session {
} }
public static isMonitorCurator(user: User): boolean { public static isMonitorCurator(user: User): boolean {
return stakeholderTypes.filter(stakeholderType => this.isTypeCurator(stakeholderType.value, user)).length > 0; return StakeholderConfiguration.TYPES.filter(stakeholderType => this.isTypeCurator(stakeholderType.value, user)).length > 0;
} }
public static isCommunityCurator(user: User): boolean { public static isCommunityCurator(user: User): boolean {
@ -112,7 +128,7 @@ export class Session {
} }
public static isCurator(type: string, user: User): boolean { public static isCurator(type: string, user: User): boolean {
return (type === 'community' || stakeholderTypes.find(stakeholderType => stakeholderType.value == type)) && this.isTypeCurator(type, user); return (type === 'community' || StakeholderConfiguration.TYPES.find(stakeholderType => stakeholderType.value == type)) && this.isTypeCurator(type, user);
} }
public static isPortalAdministrator(user: User): boolean { public static isPortalAdministrator(user: User): boolean {
@ -206,12 +222,16 @@ export class COOKIE {
} }
export class Role { export class Role {
public static GROUP = '';
public static PORTAL_ADMIN = 'PORTAL_ADMINISTRATOR'; public static PORTAL_ADMIN = 'PORTAL_ADMINISTRATOR';
public static REGISTERED_USER = 'REGISTERED_USER'; public static REGISTERED_USER = 'REGISTERED_USER';
public static ANONYMOUS_USER = 'ROLE_ANONYMOUS'; public static ANONYMOUS_USER = 'ROLE_ANONYMOUS';
public static USER_MANAGER = 'USER_MANAGER'; public static USER_MANAGER = 'USER_MANAGER';
public static CURATOR_CLAIM = 'CURATOR_CLAIM'; public static CURATOR_CLAIM = 'CURATOR_CLAIM';
public static roleName(type: string, id: string) {
return this.GROUP + this.mapType(type) + '.' + id;
}
public static mapType(type: string, communityMap: boolean = true): string { public static mapType(type: string, communityMap: boolean = true): string {
if (type == "ri" && communityMap) { if (type == "ri" && communityMap) {
@ -219,7 +239,7 @@ export class Role {
} else if (type == "organization") { } else if (type == "organization") {
type = "institution"; type = "institution";
} }
return type; return Role.GROUP + type;
} }
/** /**

View File

@ -1,11 +1,8 @@
import {Component, Input, OnDestroy, ViewChild} from "@angular/core"; import {Component, Input, ViewChild} from "@angular/core";
import {Stakeholder} from "../../../monitor/entities/stakeholder"; import {Stakeholder} from "../../../monitor/entities/stakeholder";
import {UntypedFormBuilder, UntypedFormGroup, Validators} from "@angular/forms"; import {UntypedFormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
import {StakeholderUtils} from "../../utils/indicator-utils";
import {Option} from "../../../sharedComponents/input/input.component"; import {Option} from "../../../sharedComponents/input/input.component";
import {Subscription} from "rxjs"; import {Subscription} from "rxjs";
import {EnvProperties} from "../../../utils/properties/env-properties";
import {properties} from "src/environments/environment";
import {StakeholderService} from "../../../monitor/services/stakeholder.service"; import {StakeholderService} from "../../../monitor/services/stakeholder.service";
import {UtilitiesService} from "../../../services/utilities.service"; import {UtilitiesService} from "../../../services/utilities.service";
import {Role, Session, User} from "../../../login/utils/helper.class"; import {Role, Session, User} from "../../../login/utils/helper.class";
@ -16,121 +13,132 @@ import {NotificationUtils} from "../../../notifications/notification-utils";
import {Notification} from "../../../notifications/notifications"; import {Notification} from "../../../notifications/notifications";
import {NotificationHandler} from "../../../utils/notification-handler"; import {NotificationHandler} from "../../../utils/notification-handler";
import {StatsProfilesService} from "../../utils/services/stats-profiles.service"; import {StatsProfilesService} from "../../utils/services/stats-profiles.service";
import {StakeholderBaseComponent} from "../../utils/stakeholder-base.component";
@Component({ @Component({
selector: 'edit-stakeholder', selector: 'edit-stakeholder',
template: ` template: `
<form *ngIf="stakeholderFb" [formGroup]="stakeholderFb"> <div class="uk-margin-medium-bottom">
<div class="uk-grid uk-grid-large" uk-grid> <form *ngIf="stakeholderFb" [formGroup]="stakeholderFb">
<div class="uk-width-1-2@m"> <div class="uk-grid uk-grid-large" uk-grid>
<div input id="name" [formInput]="stakeholderFb.get('name')" <div class="uk-width-1-2@m">
placeholder="Name"></div> <div input id="name" [formInput]="stakeholderFb.get('name')"
</div> placeholder="Name"></div>
<div class="uk-width-1-2@m"> </div>
<div input [formInput]="stakeholderFb.get('alias')" <div class="uk-width-1-2@m">
placeholder="URL Alias"></div> <div input [formInput]="stakeholderFb.get('alias')"
</div> placeholder="URL Alias"></div>
<div class="uk-width-1-3@m">
<div input [formInput]="stakeholderFb.get('index_id')"
placeholder="Index ID"></div>
</div>
<div class="uk-width-1-3@m">
<div input [formInput]="stakeholderFb.get('index_name')"
placeholder="Index Name"></div>
</div>
<div class="uk-width-1-3@m">
<div input [formInput]="stakeholderFb.get('index_shortName')"
placeholder="Index Short Name"></div>
</div>
<ng-container *ngIf="isCurator">
<div class="uk-width-1-3@m">
<div *ngIf="statsProfiles" input [formInput]="stakeholderFb.get('statsProfile')" [type]="'select'"
[options]="statsProfiles"
placeholder="Stats Profile"></div>
</div> </div>
<div class="uk-width-1-3@m"> <div class="uk-width-1-3@m">
<div input [formInput]="stakeholderFb.get('projectUpdateDate')" [type]="'date'" <div input [formInput]="stakeholderFb.get('index_id')"
placeholder="Last Project Update"></div> placeholder="Index ID"></div>
</div> </div>
</ng-container> <div class="uk-width-1-3@m">
<div class="uk-width-1-3@m"> <div input [formInput]="stakeholderFb.get('index_name')"
<div input [formInput]="stakeholderFb.get('locale')" [type]="'select'" placeholder="Index Name"></div>
[options]="stakeholderUtils.locales" </div>
placeholder="Locale"></div> <div class="uk-width-1-3@m">
</div> <div input [formInput]="stakeholderFb.get('index_shortName')"
<div class="uk-width-1-1"> placeholder="Index Short Name"></div>
<div input [type]="'textarea'" placeholder="Description" </div>
[rows]="4" [formInput]="stakeholderFb.get('description')"></div> <ng-container *ngIf="isCurator">
</div> <div class="uk-width-1-3@m">
<div class="uk-width-1-1"> <div *ngIf="statsProfiles" input [formInput]="stakeholderFb.get('statsProfile')"
<input #file id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/> [type]="'select'"
<div *ngIf="!stakeholderFb.get('isUpload').value" class="uk-grid uk-grid-column-large" uk-grid> [options]="statsProfiles"
<div class="uk-margin-top uk-width-auto@l uk-width-1-1"> placeholder="Stats Profile"></div>
<div class="uk-grid uk-grid-column-large uk-flex-middle" uk-grid> </div>
<div class="uk-width-auto@l uk-width-1-1 uk-flex uk-flex-center"> <div class="uk-width-1-3@m">
<button class="uk-button uk-button-primary uk-flex uk-flex-middle uk-flex-wrap" <div input [formInput]="stakeholderFb.get('projectUpdateDate')" [type]="'date'"
(click)="file.click()"> placeholder="Last Project Update"></div>
<icon name="cloud_upload" [flex]="true"></icon> </div>
<span class="uk-margin-small-left">Upload a file</span> </ng-container>
</button> <div class="uk-width-1-3@m">
</div> <div input [formInput]="stakeholderFb.get('locale')" [type]="'select'"
<div class="uk-text-center uk-text-bold uk-width-expand"> [options]="stakeholderUtils.locales"
OR placeholder="Locale"></div>
</div>
<div class="uk-width-1-1">
<div input [type]="'textarea'" placeholder="Description"
[rows]="4" [formInput]="stakeholderFb.get('description')"></div>
</div>
<div class="uk-width-1-1">
<input #file id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/>
<div *ngIf="!stakeholderFb.get('isUpload').value" class="uk-grid uk-grid-column-large" uk-grid>
<div class="uk-margin-xsmall-top uk-width-auto@l uk-width-1-1">
<div class="uk-grid uk-grid-column-large uk-flex-middle" uk-grid>
<div class="uk-width-auto@l uk-width-1-1 uk-flex uk-flex-center">
<button class="uk-button uk-button-primary uk-flex uk-flex-middle uk-flex-wrap"
(click)="file.click()">
<icon name="cloud_upload" [flex]="true"></icon>
<span class="uk-margin-small-left">Upload a file</span>
</button>
</div>
<div class="uk-text-center uk-text-bold uk-width-expand">
OR
</div>
</div> </div>
</div> </div>
<div input class="uk-width-expand" type="logoURL" [placeholder]="'Link to the logo'"
[formInput]="stakeholderFb.get('logoUrl')"></div>
</div> </div>
<div input class="uk-width-expand" type="logoURL" [placeholder]="'Link to the logo'" <div *ngIf="stakeholderFb.get('isUpload').value" class="uk-width-1-1 uk-flex uk-flex-middle">
[formInput]="stakeholderFb.get('logoUrl')"></div> <div class="uk-card uk-card-default uk-text-center uk-border-circle">
<img class="uk-position-center uk-blend-multiply" [src]="photo">
</div>
<div class="uk-margin-left">
<button (click)="remove()" class="uk-button-danger uk-icon-button uk-icon-button-small">
<icon [flex]="true" ratio="0.8" name="delete"></icon>
</button>
</div>
<div class="uk-margin-small-left">
<button class="uk-button-secondary uk-icon-button uk-icon-button-small"
(click)="file.click()">
<icon [flex]="true" ratio="0.8" name="edit"></icon>
</button>
</div>
</div>
<!-- Full width error message -->
<div *ngIf="uploadError"
class="uk-text-danger uk-margin-small-top uk-width-1-1">{{uploadError}}</div>
</div> </div>
<div *ngIf="stakeholderFb.get('isUpload').value" class="uk-width-1-1 uk-flex uk-flex-middle"> <div class="uk-width-1-1">
<div class="uk-card uk-card-default uk-text-center uk-border-circle"> <div class="uk-grid uk-child-width-expand@m uk-child-width-1-1" uk-grid>
<img class="uk-position-center uk-blend-multiply" [src]="photo"> <div *ngIf="showVisibility">
</div> <div input [formInput]="stakeholderFb.get('visibility')"
<div class="uk-margin-left"> [placeholder]="'Select a status'"
<button (click)="remove()" class="uk-button-danger uk-icon-button uk-icon-button-small"> [options]="stakeholderUtils.visibilities" type="select"></div>
<icon [flex]="true" ratio="0.8" name="delete"></icon> </div>
</button> <div [class.uk-width-1-2@m]="!showVisibility && !showFunderType && !canChooseTemplate">
</div> <div input [formInput]="stakeholderFb.get('type')"
<div class="uk-margin-small-left"> [placeholder]="'Select a type of ' + entities.stakeholder"
<button class="uk-button-secondary uk-icon-button uk-icon-button-small" [options]="typesByRole" type="select"></div>
(click)="file.click()"> </div>
<icon [flex]="true" ratio="0.8" name="edit"></icon> <div *ngIf="showFunderType">
</button> <div input [formInput]="stakeholderFb.get('funderType')"
[placeholder]="'Select a type of ' + entities.funder"
[options]="stakeholderUtils.funderTypes" type="select"></div>
</div>
<div *ngIf="canChooseTemplate">
<div [placeholder]="'Select a template'"
input [formInput]="stakeholderFb.get('defaultId')"
[options]="defaultStakeholdersOptions" type="select"></div>
</div>
</div> </div>
</div> </div>
<!-- Full width error message -->
<div *ngIf="uploadError" class="uk-text-danger uk-margin-small-top uk-width-1-1">{{uploadError}}</div>
</div> </div>
<div [class]="canChooseTemplate ? 'uk-width-1-3@m' : 'uk-width-1-2@m'"> </form>
<div input [formInput]="stakeholderFb.get('visibility')" <div #notify [class.uk-hidden]="!stakeholderFb" notify-form
[placeholder]="'Select a status'" class="uk-width-1-1 uk-margin-large-top"></div>
[options]="stakeholderUtils.statuses" type="select"></div> </div>
</div>
<div [class]="canChooseTemplate ? 'uk-width-1-3@m' : 'uk-width-1-2@m'">
<div input [formInput]="stakeholderFb.get('type')"
[placeholder]="'Select a type'"
[options]="types" type="select"></div>
</div>
<ng-container *ngIf="canChooseTemplate">
<div class="uk-width-1-3@m">
<div [placeholder]="'Select a template'"
input [formInput]="stakeholderFb.get('defaultId')"
[options]="defaultStakeholdersOptions" type="select"></div>
</div>
</ng-container>
</div>
</form>
<div #notify [class.uk-hidden]="!stakeholderFb" notify-form
class="uk-width-1-1 uk-margin-large-top uk-margin-medium-bottom"></div>
`, `,
styleUrls: ['edit-stakeholder.component.less'] styleUrls: ['edit-stakeholder.component.less']
}) })
export class EditStakeholderComponent implements OnDestroy { export class EditStakeholderComponent extends StakeholderBaseComponent {
@Input() @Input()
public disableAlias: boolean = false; public disableAlias: boolean = false;
public stakeholderFb: UntypedFormGroup; public stakeholderFb: UntypedFormGroup;
public secure: boolean = false; public secure: boolean = false;
public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
public defaultStakeholdersOptions: Option[]; public defaultStakeholdersOptions: Option[];
public defaultStakeholders: Stakeholder[]; public defaultStakeholders: Stakeholder[];
public alias: string[]; public alias: string[];
@ -138,10 +146,8 @@ export class EditStakeholderComponent implements OnDestroy {
public isDefault: boolean; public isDefault: boolean;
public isNew: boolean; public isNew: boolean;
public loading: boolean = false; public loading: boolean = false;
public types: Option[]; public typesByRole: Option[];
public statsProfiles: string[]; public statsProfiles: string[];
public properties: EnvProperties = properties;
private subscriptions: any[] = [];
/** /**
* Photo upload * Photo upload
* */ * */
@ -158,16 +164,21 @@ export class EditStakeholderComponent implements OnDestroy {
private stakeholderService: StakeholderService, private stakeholderService: StakeholderService,
private statsProfileService: StatsProfilesService, private statsProfileService: StatsProfilesService,
private utilsService: UtilitiesService, private userManagementService: UserManagementService,) { private utilsService: UtilitiesService, private userManagementService: UserManagementService,) {
super();
} }
ngOnDestroy() { ngOnDestroy() {
this.reset(); this.reset();
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) {
this.reset(); this.reset();
this.deleteCurrentPhoto = false; this.deleteCurrentPhoto = false;
this.stakeholder = stakeholder; this.stakeholder = stakeholder;
if (this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities)) {
this.stakeholder.visibility = this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities);
}
this.alias = alias; this.alias = alias;
this.defaultStakeholders = defaultStakeholders; this.defaultStakeholders = defaultStakeholders;
this.isDefault = isDefault; this.isDefault = isDefault;
@ -183,7 +194,7 @@ export class EditStakeholderComponent implements OnDestroy {
} else { } else {
this.statsProfiles = []; this.statsProfiles = [];
} }
this.types = this.stakeholderUtils.getTypesByUserRoles(this.user, this.stakeholder.alias); this.typesByRole = this.stakeholderUtils.getTypesByUserRoles(this.user, this.stakeholder.alias);
this.stakeholderFb = this.fb.group({ this.stakeholderFb = this.fb.group({
_id: this.fb.control(this.stakeholder._id), _id: this.fb.control(this.stakeholder._id),
defaultId: this.fb.control(this.stakeholder.defaultId), defaultId: this.fb.control(this.stakeholder.defaultId),
@ -191,21 +202,22 @@ export class EditStakeholderComponent implements OnDestroy {
description: this.fb.control(this.stakeholder.description), description: this.fb.control(this.stakeholder.description),
index_name: this.fb.control(this.stakeholder.index_name, Validators.required), index_name: this.fb.control(this.stakeholder.index_name, Validators.required),
index_id: this.fb.control(this.stakeholder.index_id, Validators.required), index_id: this.fb.control(this.stakeholder.index_id, Validators.required),
index_shortName: this.fb.control(this.stakeholder.index_shortName, Validators.required), index_shortName: this.fb.control(this.stakeholder.index_shortName),
statsProfile: this.fb.control(this.stakeholder.statsProfile, Validators.required), statsProfile: this.fb.control(this.stakeholder.statsProfile, Validators.required),
locale: this.fb.control(this.stakeholder.locale, Validators.required), locale: this.fb.control(this.stakeholder.locale, Validators.required),
projectUpdateDate: this.fb.control(this.stakeholder.projectUpdateDate), projectUpdateDate: this.fb.control(this.stakeholder.projectUpdateDate),
creationDate: this.fb.control(this.stakeholder.creationDate), creationDate: this.fb.control(this.stakeholder.creationDate),
alias: this.fb.control(this.stakeholder.alias, alias: this.fb.control(this.stakeholder.alias,
[ [
Validators.required, Validators.required,
this.stakeholderUtils.aliasValidatorString( this.stakeholderUtils.aliasValidatorString(
this.alias.filter(alias => alias !== this.stakeholder.alias) this.alias.filter(alias => alias !== this.stakeholder.alias)
)] )]
), ),
isDefault: this.fb.control((this.isDefault)), isDefault: this.fb.control((this.isDefault)),
visibility: this.fb.control(this.stakeholder.visibility, Validators.required), visibility: this.fb.control(this.stakeholder.visibility, Validators.required),
type: this.fb.control(this.stakeholder.type, Validators.required), type: this.fb.control(this.stakeholder.type, Validators.required),
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),
logoUrl: this.fb.control(this.stakeholder.logoUrl), logoUrl: this.fb.control(this.stakeholder.logoUrl),
@ -234,7 +246,7 @@ export class EditStakeholderComponent implements OnDestroy {
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(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);
@ -280,8 +292,8 @@ export class EditStakeholderComponent implements OnDestroy {
public get disabled(): boolean { public get disabled(): boolean {
return (this.stakeholderFb && this.stakeholderFb.invalid) || return (this.stakeholderFb && this.stakeholderFb.invalid) ||
(this.stakeholderFb && this.stakeholderFb.pristine && !this.isNew && !this.file) || (this.stakeholderFb && this.stakeholderFb.pristine && !this.isNew && !this.file) ||
(this.uploadError && this.uploadError.length > 0); (this.uploadError && this.uploadError.length > 0);
} }
public get dirty(): boolean { public get dirty(): boolean {
@ -303,7 +315,7 @@ export class EditStakeholderComponent implements OnDestroy {
} }
onTypeChange(value, defaultStakeholders: Stakeholder[]) { onTypeChange(value, defaultStakeholders: Stakeholder[]) {
this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, (this.isDefault && !this.isNew)?[]:Validators.required)); this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, (this.isDefault && !this.isNew) ? [] : Validators.required));
this.defaultStakeholdersOptions = [{ this.defaultStakeholdersOptions = [{
label: 'New blank profile', label: 'New blank profile',
value: '-1' value: '-1'
@ -340,9 +352,9 @@ export class EditStakeholderComponent implements OnDestroy {
if (this.isNew) { if (this.isNew) {
let defaultStakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.getRawValue().defaultId); let defaultStakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.getRawValue().defaultId);
this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.getRawValue(), this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.getRawValue(),
(defaultStakeholder ? defaultStakeholder.topics : []), this.stakeholderFb.getRawValue().isDefault)); (defaultStakeholder ? defaultStakeholder.topics : []), this.stakeholderFb.getRawValue().isDefault));
this.removePhoto(); this.removePhoto();
if(this.stakeholderFb.getRawValue().isDefault) { if (this.stakeholderFb.getRawValue().isDefault) {
this.stakeholderFb.get('defaultId').setValue(null); this.stakeholderFb.get('defaultId').setValue(null);
} }
this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL, this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL,
@ -437,7 +449,11 @@ export class EditStakeholderComponent implements OnDestroy {
public deletePhoto() { public deletePhoto() {
if (this.stakeholder.logoUrl && this.stakeholder.isUpload) { if (this.stakeholder.logoUrl && this.stakeholder.isUpload) {
this.subscriptions.push(this.utilsService.deletePhoto(this.properties.utilsService + '/delete/' + this.subscriptions.push(this.utilsService.deletePhoto(this.properties.utilsService + '/delete/' +
encodeURIComponent(this.stakeholder.type) + "/" + encodeURIComponent(this.stakeholder.alias) + "/" + this.stakeholder.logoUrl).subscribe()); encodeURIComponent(this.stakeholder.type) + "/" + encodeURIComponent(this.stakeholder.alias) + "/" + this.stakeholder.logoUrl).subscribe());
} }
} }
get showFunderType() {
return super.showFunderType && this.stakeholderFb?.get('type').value === 'funder' && !this.isDefault;
}
} }

View File

@ -1,29 +1,28 @@
import {ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild} from "@angular/core"; import {ChangeDetectorRef, Component, OnInit, ViewChild} from "@angular/core";
import {StakeholderService} from "../../monitor/services/stakeholder.service"; import {StakeholderService} from "../../monitor/services/stakeholder.service";
import {EnvProperties} from "../../utils/properties/env-properties";
import {Stakeholder} from "../../monitor/entities/stakeholder"; import {Stakeholder} from "../../monitor/entities/stakeholder";
import { Subscription, zip} from "rxjs"; import {zip} from "rxjs";
import {EditStakeholderComponent} from "./edit-stakeholder/edit-stakeholder.component"; import {EditStakeholderComponent} from "./edit-stakeholder/edit-stakeholder.component";
import {properties} from "src/environments/environment";
import {Title} from "@angular/platform-browser"; import {Title} from "@angular/platform-browser";
import {BaseComponent} from "../../sharedComponents/base/base.component";
import {ActivatedRoute} from "@angular/router";
@Component({ @Component({
selector: 'general', selector: 'general',
templateUrl: "./general.component.html" templateUrl: "./general.component.html"
}) })
export class GeneralComponent implements OnInit, OnDestroy { export class GeneralComponent extends BaseComponent implements OnInit {
public stakeholder: Stakeholder; public stakeholder: Stakeholder;
public alias: string[]; public alias: string[];
public properties: EnvProperties = properties;
public defaultStakeholders: Stakeholder[]; public defaultStakeholders: Stakeholder[];
public loading: boolean = false; public loading: boolean = false;
private subscriptions: any[] = [];
@ViewChild('editStakeholderComponent') editStakeholderComponent: EditStakeholderComponent; @ViewChild('editStakeholderComponent') editStakeholderComponent: EditStakeholderComponent;
constructor(private stakeholderService: StakeholderService, constructor(private stakeholderService: StakeholderService,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
private title: Title) { protected _route: ActivatedRoute,
protected _title: Title) {
super();
} }
ngOnInit() { ngOnInit() {
@ -32,7 +31,8 @@ export class GeneralComponent implements OnInit, OnDestroy {
this.stakeholder = stakeholder; this.stakeholder = stakeholder;
this.cdr.detectChanges(); this.cdr.detectChanges();
if(this.stakeholder) { if(this.stakeholder) {
this.title.setTitle(this.stakeholder.name + " | General"); this.title = this.stakeholder.name + " | General";
this.setMetadata();
let data = zip( let data = zip(
this.stakeholderService.getDefaultStakeholders(this.properties.monitorServiceAPIURL), this.stakeholderService.getDefaultStakeholders(this.properties.monitorServiceAPIURL),
this.stakeholderService.getAlias(this.properties.monitorServiceAPIURL) this.stakeholderService.getAlias(this.properties.monitorServiceAPIURL)
@ -51,10 +51,9 @@ export class GeneralComponent implements OnInit, OnDestroy {
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)
} }
public save() { public save() {
this.loading = true; this.loading = true;
this.editStakeholderComponent.save((stakeholder) => { this.editStakeholderComponent.save(stakeholder => {
this.stakeholder = stakeholder; this.stakeholder = stakeholder;
this.stakeholderService.setStakeholder(this.stakeholder); this.stakeholderService.setStakeholder(this.stakeholder);
this.reset(); this.reset();
@ -64,12 +63,4 @@ export class GeneralComponent implements OnInit, OnDestroy {
this.loading = false; this.loading = false;
}); });
} }
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if(subscription instanceof Subscription) {
subscription.unsubscribe();
}
});
}
} }

View File

@ -1,138 +1,173 @@
<div page-content> <div page-content>
<div header> <div header>
<sidebar-mobile-toggle class="uk-margin-top uk-hidden@m uk-display-block"></sidebar-mobile-toggle> <sidebar-mobile-toggle class="uk-margin-top uk-hidden@m uk-display-block"></sidebar-mobile-toggle>
<div *ngIf="isCurator()" class="uk-margin-remove-bottom uk-margin-medium-top"> <div *ngIf="isCurator()" class="uk-margin-remove-bottom uk-margin-medium-top">
<slider-tabs [type]="'dynamic'" (activeEmitter)="tab = $event"> <slider-tabs [type]="'dynamic'" (activeEmitter)="tab = $event">
<slider-tab tabTitle="All" [tabId]="'all'" [active]="tab === 'all'"></slider-tab> <slider-tab tabTitle="All" [tabId]="'all'" [active]="tab === 'all'"></slider-tab>
<slider-tab tabTitle="Profile templates" [tabId]="'templates'" [active]="tab === 'templates'"></slider-tab> <slider-tab tabTitle="Profile templates" [tabId]="'templates'"
<slider-tab tabTitle="Profiles" [tabId]="'profiles'" [active]="tab === 'profiles'"></slider-tab> [active]="tab === 'templates'"></slider-tab>
</slider-tabs> <slider-tab tabTitle="Profiles" [tabId]="'profiles'" [active]="tab === 'profiles'"></slider-tab>
</slider-tabs>
</div>
</div> </div>
</div> <div actions>
<div actions> <div class="uk-section-xsmall">
<div class="uk-section-xsmall"> <div class="uk-flex 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"> [ngClass]="properties.dashboard == 'irish' ? 'uk-flex-between@m' : 'uk-flex-right@m'">
<div search-input [searchControl]="filters.get('keyword')" [expandable]="true" placeholder="Search Profiles" searchInputClass="outer" <div *ngIf="properties.dashboard == 'irish'" class="uk-width-medium uk-margin-small-bottom">
class="uk-width-1-3@xl uk-width-2-5@l uk-width-1-2@m uk-width-1-1 uk-flex uk-flex-right"></div> <div input type="select" placeholder="Type"
</div> [options]="typeOptions" [formInput]="filters.get('type')">
</div>
</div>
<div search-input [searchControl]="filters.get('keyword')" [expandable]="true"
placeholder="Search Profiles" searchInputClass="outer"
class="uk-width-1-3@xl uk-width-2-5@l uk-width-1-2@m uk-width-1-1 uk-flex uk-flex-right"></div>
</div>
</div>
</div> </div>
</div> <div inner>
<div inner> <div *ngIf="loading" class="uk-margin-medium-top uk-padding-large">
<div *ngIf="loading" class="uk-margin-medium-top uk-padding-large"> <loading></loading>
<loading></loading> </div>
</div> <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">
<h4>Profile Templates</h4> <h4 class="uk-margin-remove">Profile Templates</h4>
<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> <paging-no-load *ngIf="displayDefaultStakeholders?.length > pageSize"
<ng-template ngFor [ngForOf]="displayDefaultStakeholders" let-stakeholder> (pageChange)="updateCurrentTemplatesPage($event)"
<ng-container *ngTemplateOutlet="stakeholderBox; context: {stakeholder:stakeholder}"></ng-container> [currentPage]="currentTemplatesPage" [size]="pageSize"
</ng-template> [totalResults]="displayDefaultStakeholders.length">
<div *ngIf="!loading && isCurator()"> </paging-no-load>
<ng-container *ngTemplateOutlet="newBox; context: {text:'Create a new default profile.', isDefault:true}"></ng-container> </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> uk-grid>
</div> <ng-template ngFor
<div *ngIf="!isManager()" class="message"> [ngForOf]="displayDefaultStakeholders.slice((currentTemplatesPage-1)*pageSize, currentTemplatesPage*pageSize)"
<h4 class="uk-text-center"> let-stakeholder>
No profiles to manage yet <ng-container
</h4> *ngTemplateOutlet="stakeholderBox; context: {stakeholder:stakeholder}"></ng-container>
</div> </ng-template>
<div *ngIf="tab != 'templates' && isManager()" class="uk-section"> <div *ngIf="!loading && isCurator()">
<h4>Profiles</h4> <ng-container
<div class="uk-grid uk-grid-match uk-child-width-1-3@l uk-child-width-1-2@m uk-child-width-1-1" uk-grid> *ngTemplateOutlet="newBox; context: {text:'Create a new default profile.', isDefault:true}"></ng-container>
<ng-template ngFor [ngForOf]="displayStakeholders" let-stakeholder> </div>
<ng-container *ngTemplateOutlet="stakeholderBox; context: {stakeholder:stakeholder}"></ng-container> </div>
</ng-template> </div>
<div *ngIf="!loading && isCurator()"> <div *ngIf="!isManager()" class="message">
<ng-container *ngTemplateOutlet="newBox; context: {text:'Create a new profile by selecting the type ('+typesAsString+') and ' + <h4 class="uk-text-center">
No profiles to manage yet
</h4>
</div>
<div *ngIf="tab != 'templates' && isManager()" class="uk-section">
<div class="uk-flex uk-flex-middle uk-flex-between uk-margin-small-bottom">
<h4 class="uk-margin-remove">Profiles</h4>
<paging-no-load *ngIf="displayStakeholders?.length > pageSize"
(pageChange)="updateCurrentPage($event)"
[currentPage]="currentPage" [size]="pageSize"
[totalResults]="displayStakeholders.length">
</paging-no-load>
</div>
<div class="uk-grid uk-grid-match uk-child-width-1-3@l uk-child-width-1-2@m uk-child-width-1-1"
uk-grid>
<ng-template ngFor
[ngForOf]="displayStakeholders.slice((currentPage-1)*pageSize, currentPage*pageSize)"
let-stakeholder>
<ng-container
*ngTemplateOutlet="stakeholderBox; context: {stakeholder:stakeholder}"></ng-container>
</ng-template>
<div *ngIf="!loading && isCurator()">
<ng-container *ngTemplateOutlet="newBox; context: {text:'Create a new profile by selecting the type ('+typesAsString+') and ' +
'select indicators based on a default or a blank profile.', isDefault:false}"></ng-container> 'select indicators based on a default or a blank profile.', isDefault:false}"></ng-container>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
</div>
</div> </div>
<ng-template #stakeholderBox let-stakeholder="stakeholder"> <ng-template #stakeholderBox let-stakeholder="stakeholder">
<div *ngIf="stakeholder"> <div *ngIf="stakeholder">
<div class="uk-card uk-card-default uk-card-body uk-position-relative" [ngClass]="stakeholder.type"> <div class="uk-card uk-card-default uk-card-body uk-position-relative" [ngClass]="stakeholder.type">
<div class="uk-position-top-right uk-margin-small-right uk-margin-small-top"> <div class="uk-position-top-right uk-margin-small-right uk-margin-small-top">
<a class="uk-link-reset uk-flex uk-flex-middle"> <a class="uk-link-reset uk-flex uk-flex-middle">
<icon [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(stakeholder.visibility)" ratio="0.6"></icon> <icon *ngIf="showVisibility" [flex]="true"
<icon [flex]="true" name="more_vert"></icon> [name]="stakeholderUtils.visibilityIcon.get(stakeholder.visibility)" ratio="0.6"></icon>
</a> <icon [flex]="true" name="more_vert"></icon>
<div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0;">
<ul class="uk-nav uk-dropdown-nav">
<li>
<a (click)="editStakeholder(stakeholder, !stakeholder.defaultId); hide(element)">Edit</a>
</li>
<li *ngIf="isCurator">
<a (click)="createReport(stakeholder);hide(element)">Cache Indicators</a>
</li>
<li class="uk-nav-divider"></li>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v>
<li [class.uk-active]="stakeholder.visibility === v.value">
<a (click)="changeStakeholderStatus(stakeholder, v.value);hide(element)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" [name]="v.icon" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">{{v.label}}</span>
<icon *ngIf="stakeholder.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon>
</div>
</a> </a>
</li> <div #element class="uk-dropdown"
</ng-template> uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0;">
<hr *ngIf="isProfileManager(stakeholder)" class="uk-nav-divider"> <ul class="uk-nav uk-dropdown-nav">
<li *ngIf="isProfileManager(stakeholder)"><a <li>
(click)="deleteStakeholderOpen(stakeholder);hide(element)">Delete</a> <a (click)="editStakeholder(stakeholder, !stakeholder.defaultId); hide(element)">Edit</a>
</li> </li>
</ul> <li *ngIf="isCurator && stakeholderUtils.isCachingIndicators">
<a (click)="createReport(stakeholder);hide(element)">Cache Indicators</a>
</li>
<li *ngIf="showVisibility" class="uk-nav-divider"></li>
<ng-template *ngIf="showVisibility" ngFor [ngForOf]="stakeholderUtils.visibilities" let-v>
<li [class.uk-active]="stakeholder.visibility === v.value">
<a (click)="changeStakeholderStatus(stakeholder, v.value);hide(element)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" [name]="v.icon" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">{{v.label}}</span>
<icon *ngIf="stakeholder.visibility === v.value" [flex]="true" name="done"
class="uk-text-secondary" ratio="0.8"></icon>
</div>
</a>
</li>
</ng-template>
<hr *ngIf="isProfileManager(stakeholder)" class="uk-nav-divider">
<li *ngIf="isProfileManager(stakeholder)"><a
(click)="deleteStakeholderOpen(stakeholder);hide(element)">Delete</a>
</li>
</ul>
</div>
</div>
<a class="uk-display-block uk-text-center uk-link-reset" [routerLink]="'/admin/' + stakeholder.alias">
<div class="titleContainer uk-h6 uk-margin-remove-bottom uk-margin-top multi-line-ellipsis lines-2">
<p *ngIf="stakeholder.name" class="uk-margin-remove">
{{stakeholder.name}}
</p>
</div>
<div class="logoContainer uk-margin-top uk-flex uk-flex-column uk-flex-center uk-flex-middle">
<img [src]="stakeholder | logoUrl" class="uk-blend-multiply" style="max-height: 80px;">
</div>
</a>
</div> </div>
</div>
<a class="uk-display-block uk-text-center uk-link-reset" [routerLink]="'/admin/' + stakeholder.alias">
<div class="titleContainer uk-h6 uk-margin-remove-bottom uk-margin-top multi-line-ellipsis lines-2">
<p *ngIf="stakeholder.name" class="uk-margin-remove">
{{stakeholder.name}}
</p>
</div>
<div class="logoContainer uk-margin-top uk-flex uk-flex-column uk-flex-center uk-flex-middle">
<img [src]="stakeholder | logoUrl" class="uk-blend-multiply" style="max-height: 80px;">
</div>
</a>
</div> </div>
</div>
</ng-template> </ng-template>
<ng-template #newBox let-text="text" let-isDefault="isDefault"> <ng-template #newBox let-text="text" let-isDefault="isDefault">
<ng-container *ngIf="!loading"> <ng-container *ngIf="!loading">
<div class="uk-card uk-card-default uk-text-center uk-card-body clickable" (click)="editStakeholder(null, isDefault)"> <div class="uk-card uk-card-default uk-text-center uk-card-body clickable"
<div class="uk-text-small uk-text-muted"> (click)="editStakeholder(null, isDefault)">
{{text}} <div class="uk-text-small uk-text-muted">
</div> {{text}}
<div class="uk-margin-medium-top uk-margin-small-bottom"> </div>
<div class="uk-margin-medium-top uk-margin-small-bottom">
<span class="uk-text-secondary"> <span class="uk-text-secondary">
<icon name="add" [ratio]="3"></icon> <icon name="add" [ratio]="3"></icon>
</span> </span>
</div> </div>
</div> </div>
</ng-container> </ng-container>
</ng-template> </ng-template>
<modal-alert #editStakeholderModal [large]="true" classTitle="uk-background-primary uk-light" <modal-alert #editStakeholderModal [large]="true" classTitle="uk-background-primary uk-light"
(alertOutput)="editStakeholderComponent.save(callback)" (cancelOutput)="editStakeholderComponent.removePhoto()" (alertOutput)="editStakeholderComponent.save(callback)"
[okDisabled]="editStakeholderComponent.disabled"> (cancelOutput)="editStakeholderComponent.removePhoto()"
<div class="uk-height-large uk-position-relative" *ngIf="editStakeholderComponent.loading"> [okDisabled]="editStakeholderComponent.disabled">
<loading class="uk-position-center"></loading> <div class="uk-height-large uk-position-relative" *ngIf="editStakeholderComponent.loading">
</div> <loading class="uk-position-center"></loading>
<div class="uk-padding" [class.uk-hidden]="editStakeholderComponent.loading"> </div>
<edit-stakeholder #editStakeholderComponent></edit-stakeholder> <div class="uk-padding" [class.uk-hidden]="editStakeholderComponent.loading">
</div> <edit-stakeholder #editStakeholderComponent></edit-stakeholder>
</div>
</modal-alert> </modal-alert>
<modal-alert #deleteStakeholderModal [overflowBody]="false" (alertOutput)="deleteStakeholder()"> <modal-alert #deleteStakeholderModal [overflowBody]="false" (alertOutput)="deleteStakeholder()">
<div class="uk-height-medium uk-position-relative" *ngIf="deleteLoading"> <div class="uk-height-medium uk-position-relative" *ngIf="deleteLoading">
<loading class="uk-position-center"></loading> <loading class="uk-position-center"></loading>
</div> </div>
<div *ngIf="!deleteLoading"> <div *ngIf="!deleteLoading">
This stakeholder will permanently be deleted. Are you sure you want to proceed? This stakeholder will permanently be deleted. Are you sure you want to proceed?
</div> </div>
</modal-alert> </modal-alert>

View File

@ -1,7 +1,8 @@
@import (reference) "~src/assets/openaire-theme/less/color.less"; @import (reference) "~src/assets/openaire-theme/less/color.less";
@import (optional) "~src/assets/extend-theme/less/color.less";
.setType(@color) { .setType(@color) {
border-bottom: 4px solid fade(@color, 30%); border-bottom: 4px solid if(@color = none, none, fade(@color, 30%));
& .type { & .type {
color: @color; color: @color;
@ -20,4 +21,12 @@
&.organization { &.organization {
.setType(@organization-color); .setType(@organization-color);
} }
&.country {
.setType(@country-color);
}
&.datasource {
.setType(@datasource-color);
}
} }

View File

@ -1,9 +1,7 @@
import {Component, OnDestroy, OnInit, ViewChild} from "@angular/core"; import {Component, OnDestroy, OnInit, ViewChild} from "@angular/core";
import {StakeholderService} from "../../monitor/services/stakeholder.service"; import {StakeholderService} from "../../monitor/services/stakeholder.service";
import {EnvProperties} from "../../utils/properties/env-properties"; import {Stakeholder, Visibility} from "../../monitor/entities/stakeholder";
import {Stakeholder, StakeholderEntities, Visibility} from "../../monitor/entities/stakeholder"; import {zip} from "rxjs";
import {Subscriber, zip} from "rxjs";
import {StakeholderUtils} from "../utils/indicator-utils";
import {UntypedFormBuilder, UntypedFormGroup} from "@angular/forms"; import {UntypedFormBuilder, UntypedFormGroup} from "@angular/forms";
import {AlertModal} from "../../utils/modal/alert"; import {AlertModal} from "../../utils/modal/alert";
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
@ -11,10 +9,10 @@ import {Title} from "@angular/platform-browser";
import {UserManagementService} from "../../services/user-management.service"; import {UserManagementService} from "../../services/user-management.service";
import {Session} from "../../login/utils/helper.class"; import {Session} from "../../login/utils/helper.class";
import {EditStakeholderComponent} from "../general/edit-stakeholder/edit-stakeholder.component"; import {EditStakeholderComponent} from "../general/edit-stakeholder/edit-stakeholder.component";
import {properties} from "src/environments/environment";
import {ActivatedRoute} from "@angular/router"; import {ActivatedRoute} from "@angular/router";
import {CacheIndicatorsService} from "../utils/cache-indicators/cache-indicators.service"; import {CacheIndicatorsService} from "../utils/cache-indicators/cache-indicators.service";
import {NotificationHandler} from "../../utils/notification-handler"; import {NotificationHandler} from "../../utils/notification-handler";
import {StakeholderBaseComponent} from "../utils/stakeholder-base.component";
type Tab = 'all' | 'templates'| 'profiles'; type Tab = 'all' | 'templates'| 'profiles';
@ -25,12 +23,9 @@ declare var UIkit;
templateUrl: "./manageStakeholders.component.html", templateUrl: "./manageStakeholders.component.html",
styleUrls: ["./manageStakeholders.component.less"] styleUrls: ["./manageStakeholders.component.less"]
}) })
export class ManageStakeholdersComponent implements OnInit, OnDestroy { export class ManageStakeholdersComponent extends StakeholderBaseComponent implements OnInit, OnDestroy {
public properties: EnvProperties;
public loading: boolean = true; public loading: boolean = true;
public deleteLoading: boolean = false; public deleteLoading: boolean = false;
public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
public defaultStakeholders: Stakeholder[]; public defaultStakeholders: Stakeholder[];
public stakeholders: Stakeholder[]; public stakeholders: Stakeholder[];
public alias: string[]; public alias: string[];
@ -38,26 +33,24 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
public index: number; public index: number;
public user = null; public user = null;
public tab: Tab = 'all'; public tab: Tab = 'all';
public currentPage: number = 1;
public currentTemplatesPage: number = 1;
public pageSize: number = 15;
public typeOptions: Option[];
/** /**
* Filtered Stakeholders * Filtered Stakeholders
*/ */
public displayDefaultStakeholders: Stakeholder[]; public displayDefaultStakeholders: Stakeholder[] = [];
public displayStakeholders: Stakeholder[]; public displayStakeholders: Stakeholder[] = [];
/** /**
* Top filters * Top filters
*/ */
public filters: UntypedFormGroup; public filters: UntypedFormGroup;
public all: Option = {
value: 'all',
label: 'All'
};
public callback: Function; public callback: Function;
/** /**
* Grid or List View * Grid or List View
*/ */
private subscriptions: any[] = [];
@ViewChild('editStakeholderModal', { static: true }) editStakeholderModal: AlertModal; @ViewChild('editStakeholderModal', { static: true }) editStakeholderModal: AlertModal;
@ViewChild('deleteStakeholderModal', { static: true }) deleteStakeholderModal: AlertModal; @ViewChild('deleteStakeholderModal', { static: true }) deleteStakeholderModal: AlertModal;
@ViewChild('editStakeholderComponent', { static: true }) editStakeholderComponent: EditStakeholderComponent; @ViewChild('editStakeholderComponent', { static: true }) editStakeholderComponent: EditStakeholderComponent;
@ -65,15 +58,17 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
constructor(private stakeholderService: StakeholderService, constructor(private stakeholderService: StakeholderService,
private cacheIndicatorsService: CacheIndicatorsService, private cacheIndicatorsService: CacheIndicatorsService,
private userManagementService: UserManagementService, private userManagementService: UserManagementService,
private route: ActivatedRoute, protected _route: ActivatedRoute,
private title: Title, protected _title: Title,
private fb: UntypedFormBuilder) { private fb: UntypedFormBuilder) {
super();
} }
ngOnInit(): void { ngOnInit(): void {
this.typeOptions = [{value: 'all', label: 'All'}].concat(this.stakeholderUtils.types);
this.buildFilters(); this.buildFilters();
this.properties = properties; this.title = 'Manage Profiles';
this.title.setTitle('Manage profiles'); this.setMetadata();
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user; this.user = user;
})); }));
@ -94,45 +89,28 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
})); }));
} }
ngOnDestroy(): void {
this.subscriptions.forEach(value => {
if (value instanceof Subscriber) {
value.unsubscribe();
} else if (value instanceof Function) {
value();
}
});
}
hide(element: any) { hide(element: any) {
UIkit.dropdown(element).hide(); UIkit.dropdown(element).hide();
} }
private buildFilters() { private buildFilters() {
this.filters = this.fb.group({ this.filters = this.fb.group({
status: this.fb.control('all'), status: this.fb.control('all'),
type: this.fb.control('all'),
keyword: this.fb.control('') keyword: this.fb.control('')
}); });
this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => { this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => {
this.onStatusChange(value); this.filtering();
}));
this.subscriptions.push(this.filters.get('type').valueChanges.subscribe(value => {
this.filtering();
})); }));
this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => { this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => {
this.onKeywordChange(value); this.filtering();
})); }));
} }
onStatusChange(value) { private filterByStatus(stakeholders: Stakeholder[], value): Stakeholder[] {
this.displayDefaultStakeholders = this.filterStatus(this.defaultStakeholders, value);
this.displayStakeholders = this.filterStatus(this.stakeholders, value);
}
onKeywordChange(value) {
this.displayDefaultStakeholders = this.filterByKeyword(this.defaultStakeholders, value);
this.displayStakeholders = this.filterByKeyword(this.stakeholders, value);
}
private filterStatus(stakeholders: Stakeholder[], value): Stakeholder[] {
if (value === 'all') { if (value === 'all') {
return stakeholders; return stakeholders;
} else { } else {
@ -140,6 +118,14 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
} }
} }
private filterByType(stakeholders: Stakeholder[], value) {
if(value == 'all') {
return stakeholders;
} else {
return stakeholders.filter(item => item.type == value);
}
}
private filterByKeyword(stakeholders: Stakeholder[], value): Stakeholder[] { private filterByKeyword(stakeholders: Stakeholder[], value): Stakeholder[] {
if (!value) { if (!value) {
return stakeholders; return stakeholders;
@ -154,6 +140,26 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
} }
} }
filtering() {
let keyword = this.filters.get('keyword').value;
let type = this.filters.get('type').value;
let status = this.filters.get('status').value;
let displayStakeholders = this.stakeholders;
let displayDefaultStakeholders = this.defaultStakeholders;
displayStakeholders = this.filterByKeyword(displayStakeholders, keyword);
displayStakeholders = this.filterByType(displayStakeholders, type);
displayStakeholders = this.filterByStatus(displayStakeholders, status);
displayDefaultStakeholders = this.filterByKeyword(displayDefaultStakeholders, keyword);
displayDefaultStakeholders = this.filterByType(displayDefaultStakeholders, type);
displayDefaultStakeholders = this.filterByStatus(displayDefaultStakeholders, status);
this.displayStakeholders = displayStakeholders;
this.displayDefaultStakeholders = displayDefaultStakeholders;
this.currentPage = 1;
this.currentTemplatesPage = 1;
}
public editStakeholder(stakeholder: Stakeholder = null, isDefault: boolean = false) { public editStakeholder(stakeholder: Stakeholder = null, isDefault: boolean = false) {
if (isDefault) { if (isDefault) {
this.index = (stakeholder) ? this.defaultStakeholders.findIndex(value => value._id === stakeholder._id) : -1; this.index = (stakeholder) ? this.defaultStakeholders.findIndex(value => value._id === stakeholder._id) : -1;
@ -193,6 +199,7 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
} }
this.alias.push(stakeholder.alias); this.alias.push(stakeholder.alias);
this.editStakeholderModal.cancel(); this.editStakeholderModal.cancel();
this.filtering();
}; };
this.editStakeholderModal.alertTitle = 'Create a new ' + (isDefault?'Default ':'') + 'Profile'; this.editStakeholderModal.alertTitle = 'Create a new ' + (isDefault?'Default ':'') + 'Profile';
this.editStakeholderModal.okButtonText = 'Create'; this.editStakeholderModal.okButtonText = 'Create';
@ -244,6 +251,7 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
this.alias = this.alias.filter(item => item !== this.stakeholder.alias); this.alias = this.alias.filter(item => item !== this.stakeholder.alias);
this.deleteLoading = false; this.deleteLoading = false;
this.deleteStakeholderModal.cancel(); this.deleteStakeholderModal.cancel();
this.filtering();
}, error => { }, error => {
UIkit.notification('An error has occurred. Please try again later', { UIkit.notification('An error has occurred. Please try again later', {
status: 'danger', status: 'danger',
@ -296,16 +304,11 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
' or ' + this.stakeholderUtils.types[this.stakeholderUtils.types.length - 1].label ' or ' + this.stakeholderUtils.types[this.stakeholderUtils.types.length - 1].label
} }
private isTab(tab: Tab): boolean { public updateCurrentPage($event) {
switch (tab) { this.currentPage = $event.value;
case "all": }
return true;
case "profiles": public updateCurrentTemplatesPage($event) {
return true; this.currentTemplatesPage = $event.value;
case "templates":
return true;
default:
return false;
}
} }
} }

View File

@ -19,6 +19,7 @@ import {
} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module"; } from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module";
import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module"; import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module";
import {EditStakeholderModule} from "../general/edit-stakeholder/edit-stakeholder.module"; import {EditStakeholderModule} from "../general/edit-stakeholder/edit-stakeholder.module";
import {PagingModule} from "../../utils/paging.module";
@NgModule({ @NgModule({
declarations: [ManageStakeholdersComponent], declarations: [ManageStakeholdersComponent],
@ -36,7 +37,8 @@ import {EditStakeholderModule} from "../general/edit-stakeholder/edit-stakeholde
LogoUrlPipeModule, LogoUrlPipeModule,
SearchInputModule, SearchInputModule,
SidebarMobileToggleModule, SidebarMobileToggleModule,
SliderTabsModule SliderTabsModule,
PagingModule
], ],
providers: [ providers: [
PreviousRouteRecorder, PreviousRouteRecorder,

View File

@ -39,26 +39,28 @@
<div *ngIf="!dragging" <div *ngIf="!dragging"
class="uk-position-top-right uk-margin-small-right uk-margin-small-top"> class="uk-position-top-right uk-margin-small-right uk-margin-small-top">
<a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing"> <a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing">
<icon [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)" ratio="0.6"></icon> <icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)" ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0"> <div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
<li><a (click)="editNumberIndicatorOpen(number, indicator._id); hide(element)">Edit</a></li> <li><a (click)="editNumberIndicatorOpen(number, indicator._id); hide(element)">Edit</a></li>
<li class="uk-nav-divider"></li>
</ng-container> </ng-container>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v> <ng-container *ngIf="showVisibility">
<li> <li *ngIf="isCurator" class="uk-nav-divider"></li>
<a (click)="changeIndicatorStatus(number._id, indicator, v.value);hide(element)"> <ng-template ngFor [ngForOf]="stakeholderUtils.visibilities" let-v>
<div class="uk-flex uk-flex-middle"> <li>
<icon [flex]="true" [name]="v.icon" ratio="0.6"></icon> <a (click)="changeIndicatorStatus(number._id, indicator, v.value);hide(element)">
<span class="uk-margin-small-left uk-width-expand">{{v.label}}</span> <div class="uk-flex uk-flex-middle">
<icon *ngIf="indicator.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon> <icon [flex]="true" [name]="v.icon" ratio="0.6"></icon>
</div> <span class="uk-margin-small-left uk-width-expand">{{v.label}}</span>
</a> <icon *ngIf="indicator.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon>
</li> </div>
</ng-template> </a>
</li>
</ng-template>
</ng-container>
<ng-container *ngIf="!indicator.defaultId && !editing && isCurator"> <ng-container *ngIf="!indicator.defaultId && !editing && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li><a (click)="deleteIndicatorOpen(number, indicator._id, 'number', 'delete');hide(element)">Delete</a></li> <li><a (click)="deleteIndicatorOpen(number, indicator._id, 'number', 'delete');hide(element)">Delete</a></li>
@ -136,26 +138,28 @@
<div *ngIf="!dragging" <div *ngIf="!dragging"
class="uk-position-top-right uk-margin-small-right uk-margin-small-top"> class="uk-position-top-right uk-margin-small-right uk-margin-small-top">
<a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing"> <a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing">
<icon [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)" ratio="0.6"></icon> <icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)" ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0"> <div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
<li><a (click)="editChartIndicatorOpen(chart, indicator._id); hide(element)">Edit</a></li> <li><a (click)="editChartIndicatorOpen(chart, indicator._id); hide(element)">Edit</a></li>
<li class="uk-nav-divider"></li>
</ng-container> </ng-container>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v> <ng-container *ngIf="showVisibility">
<li> <li *ngIf="isCurator" class="uk-nav-divider"></li>
<a (click)="changeIndicatorStatus(chart._id, indicator, v.value);"> <ng-template ngFor [ngForOf]="stakeholderUtils.visibilities" let-v>
<div class="uk-flex uk-flex-middle"> <li>
<icon [flex]="true" [name]="v.icon" ratio="0.6"></icon> <a (click)="changeIndicatorStatus(chart._id, indicator, v.value);">
<span class="uk-margin-small-left uk-width-expand">{{v.label}}</span> <div class="uk-flex uk-flex-middle">
<icon *ngIf="indicator.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon> <icon [flex]="true" [name]="v.icon" ratio="0.6"></icon>
</div> <span class="uk-margin-small-left uk-width-expand">{{v.label}}</span>
</a> <icon *ngIf="indicator.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon>
</li> </div>
</ng-template> </a>
</li>
</ng-template>
</ng-container>
<ng-container *ngIf="!indicator.defaultId && !editing && isCurator"> <ng-container *ngIf="!indicator.defaultId && !editing && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li><a (click)="deleteIndicatorOpen(chart, indicator._id, 'chart', 'delete');hide(element)">Delete</a></li> <li><a (click)="deleteIndicatorOpen(chart, indicator._id, 'chart', 'delete');hide(element)">Delete</a></li>
@ -231,8 +235,8 @@
<div input class="uk-width-1-1" *ngIf="stakeholder.defaultId" [formInput]="numberIndicatorFb.get('additionalDescription')" <div input class="uk-width-1-1" *ngIf="stakeholder.defaultId" [formInput]="numberIndicatorFb.get('additionalDescription')"
placeholder="Description" type="textarea"> placeholder="Description" type="textarea">
</div> </div>
<div input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('visibility')" <div *ngIf="showVisibility" input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('visibility')"
placeholder="Visibility" [options]="stakeholderUtils.visibility" type="select"> placeholder="Visibility" [options]="stakeholderUtils.visibilities" type="select">
</div> </div>
<div input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('width')" <div input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('width')"
placeholder="Number Size" [options]="indicatorUtils.indicatorSizes" type="select"> placeholder="Number Size" [options]="indicatorUtils.indicatorSizes" type="select">
@ -346,8 +350,8 @@
<div *ngIf="stakeholder.defaultId" input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('additionalDescription')" <div *ngIf="stakeholder.defaultId" input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('additionalDescription')"
placeholder="Description" type="textarea"> placeholder="Description" type="textarea">
</div> </div>
<div input class="uk-width-1-2@m" [formInput]="chartIndicatorFb.get('visibility')" <div *ngIf="showVisibility" input class="uk-width-1-2@m" [formInput]="chartIndicatorFb.get('visibility')"
placeholder="Status" [options]="stakeholderUtils.visibility" type="select"> placeholder="Status" [options]="stakeholderUtils.visibilities" type="select">
</div> </div>
<div input class="uk-width-1-2@m" [formInput]="chartIndicatorFb.get('width')" placeholder="Chart width" <div input class="uk-width-1-2@m" [formInput]="chartIndicatorFb.get('width')" placeholder="Chart width"
[options]="indicatorUtils.indicatorSizes" type="select"> [options]="indicatorUtils.indicatorSizes" type="select">

View File

@ -5,7 +5,6 @@ import {
HostListener, HostListener,
Input, Input,
OnChanges, OnChanges,
OnDestroy,
OnInit, OnInit,
SimpleChanges, SimpleChanges,
ViewChild ViewChild
@ -20,7 +19,6 @@ import {
Stakeholder, Stakeholder,
Visibility Visibility
} from "../../monitor/entities/stakeholder"; } from "../../monitor/entities/stakeholder";
import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils";
import { import {
AbstractControl, AbstractControl,
UntypedFormArray, UntypedFormArray,
@ -34,7 +32,6 @@ 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 {Reorder, StakeholderService} from "../../monitor/services/stakeholder.service";
import {EnvProperties} from "../../utils/properties/env-properties";
import {Observable, Subscriber} from "rxjs"; import {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";
@ -44,8 +41,9 @@ import {Notification} from "../../notifications/notifications";
import {NotificationUtils} from "../../notifications/notification-utils"; import {NotificationUtils} from "../../notifications/notification-utils";
import {NotifyFormComponent} from "../../notifications/notify-form/notify-form.component"; import {NotifyFormComponent} from "../../notifications/notify-form/notify-form.component";
import {NotificationService} from "../../notifications/notification.service"; import {NotificationService} from "../../notifications/notification.service";
import {properties} from "src/environments/environment";
import {NotificationHandler} from "../../utils/notification-handler"; import {NotificationHandler} from "../../utils/notification-handler";
import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component";
import {properties} from "../../../../environments/environment";
declare var UIkit; declare var UIkit;
declare var copy; declare var copy;
@ -54,10 +52,9 @@ declare var copy;
selector: 'indicators', selector: 'indicators',
templateUrl: './indicators.component.html' templateUrl: './indicators.component.html'
}) })
export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit { export class IndicatorsComponent extends IndicatorStakeholderBaseComponent implements OnInit, OnChanges, AfterViewInit {
filesToUpload: Array<File>; filesToUpload: Array<File>;
errorMessage = ""; errorMessage = "";
public properties: EnvProperties = properties;
@Input() @Input()
public topicIndex: number = 0; public topicIndex: number = 0;
@Input() @Input()
@ -71,8 +68,6 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
@Input() @Input()
public user: User = null; public user: User = null;
public preview: string; public preview: string;
public indicatorUtils: IndicatorUtils = new IndicatorUtils();
public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
public numberIndicatorFb: UntypedFormGroup; public numberIndicatorFb: UntypedFormGroup;
public chartIndicatorFb: UntypedFormGroup; public chartIndicatorFb: UntypedFormGroup;
public chartSections: UntypedFormArray; public chartSections: UntypedFormArray;
@ -118,7 +113,6 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
/** /**
* Subscriptions * Subscriptions
**/ **/
private subscriptions: any[] = [];
private urlSubscriptions: any[] = []; private urlSubscriptions: any[] = [];
private numberSubscription: any[] = []; private numberSubscription: any[] = [];
@ -127,9 +121,10 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
private statisticsService: StatisticsService, private statisticsService: StatisticsService,
private notificationService: NotificationService, private notificationService: NotificationService,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private router: Router, protected _router: Router,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
private sanitizer: DomSanitizer) { private sanitizer: DomSanitizer) {
super()
this.filesToUpload = []; this.filesToUpload = [];
} }
@ -146,13 +141,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
} }
ngOnDestroy(): void { ngOnDestroy(): void {
this.subscriptions.forEach(value => { super.ngOnDestroy();
if (value instanceof Subscriber) {
value.unsubscribe();
} else if (value instanceof Function) {
value();
}
});
this.urlSubscriptions.forEach(value => { this.urlSubscriptions.forEach(value => {
if (value instanceof Subscriber) { if (value instanceof Subscriber) {
value.unsubscribe(); value.unsubscribe();
@ -857,39 +846,42 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
this.setCharts(); this.setCharts();
this.setNumbers(); this.setNumbers();
this.initReorder(); this.initReorder();
this.notification = NotificationUtils.importIndicators(this.user.fullname, this.stakeholder.alias); if(properties.notificationsAPIURL) {
this.notification.entity = this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index]._id; this.notification = NotificationUtils.importIndicators(this.user.fullname, this.stakeholder.alias);
this.notification.name = this.user.firstname; this.notification.entity = this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index]._id;
this.notification.surname = this.user.lastname; this.notification.name = this.user.firstname;
this.notification.stakeholder = this.stakeholder.alias; this.notification.surname = this.user.lastname;
this.notification.stakeholderType = this.stakeholder.type; this.notification.stakeholder = this.stakeholder.alias;
this.notification.groups = [Role.curator(this.stakeholder.type)]; this.notification.stakeholderType = this.stakeholder.type;
if (this.stakeholder.defaultId) { this.notification.groups = [Role.curator(this.stakeholder.type)];
this.notification.groups.push(Role.manager(this.stakeholder.type, this.stakeholder.alias)); if (this.stakeholder.defaultId) {
this.notificationService.sendNotification(this.notification).subscribe(notification => { this.notification.groups.push(Role.manager(this.stakeholder.type, this.stakeholder.alias));
UIkit.notification('A notification has been <b>sent</b> successfully', {
status: 'success',
timeout: 6000,
pos: 'bottom-right'
});
}, error => {
UIkit.notification('An error has occurred. Please try again later', {
status: 'danger',
timeout: 6000,
pos: 'bottom-right'
});
});
} else {
this.stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL, null, this.stakeholder._id).subscribe(stakeholders => {
stakeholders.forEach(value => {
this.notification.groups.push(Role.manager(value.type, value.alias))
});
this.notificationService.sendNotification(this.notification).subscribe(notification => { this.notificationService.sendNotification(this.notification).subscribe(notification => {
NotificationHandler.rise('A notification has been <b>sent</b> successfully'); UIkit.notification('A notification has been <b>sent</b> successfully', {
status: 'success',
timeout: 6000,
pos: 'bottom-right'
});
}, error => { }, error => {
NotificationHandler.rise('An error has occurred. Please try again later', 'danger'); UIkit.notification('An error has occurred. Please try again later', {
status: 'danger',
timeout: 6000,
pos: 'bottom-right'
});
}); });
}); } else {
this.stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL, null, this.stakeholder._id).subscribe(stakeholders => {
stakeholders.forEach(value => {
this.notification.groups.push(Role.manager(value.type, value.alias))
});
this.notificationService.sendNotification(this.notification).subscribe(notification => {
NotificationHandler.rise('A notification has been <b>sent</b> successfully');
}, error => {
NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
});
});
}
} }
this.editing = false; this.editing = false;
this.importLoading = false; this.importLoading = false;
@ -1207,7 +1199,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
} }
private checkForSchemaEnhancements(url: string) { private checkForSchemaEnhancements(url: string) {
this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url); this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url) && this.properties.dashboard != 'irish';
} }
migrateFromOldImportJsonFile(charts) { migrateFromOldImportJsonFile(charts) {
@ -1237,6 +1229,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
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);
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 = [];
@ -1295,7 +1288,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
noValidParams++; noValidParams++;
} }
if (!exists) { if (!exists) {
let i: Indicator = new Indicator(chart.name, chart.description, chart.additionalDescription, chart.type, chart.width, chart.height, "RESTRICTED", [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), [indicatorPath]);
sectionsToSave[chart['sectionIndex']].indicators.push(i); sectionsToSave[chart['sectionIndex']].indicators.push(i);
countIndicators++; countIndicators++;
} }
@ -1309,7 +1302,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
pos: 'bottom-right' pos: 'bottom-right'
}); });
} }
if (noValidParams > 0) { if (noValidParams > 0 && !(this.stakeholder.type == 'country')) {
let noValidMessage = "Some indicators couldn't be generated properly. Please make sure chart data is for the current stakeholder."; let noValidMessage = "Some indicators couldn't be generated properly. Please make sure chart data is for the current stakeholder.";
if (this.stakeholder.defaultId == null) { if (this.stakeholder.defaultId == null) {
noValidMessage = "Some indicators couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly."; noValidMessage = "Some indicators couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly.";
@ -1379,7 +1372,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
let topic = this.stakeholder ? this.stakeholder.topics[this.topicIndex] : null; let topic = this.stakeholder ? this.stakeholder.topics[this.topicIndex] : null;
let category = topic ? topic.categories[this.categoryIndex] : null; let category = topic ? topic.categories[this.categoryIndex] : null;
let subCategory = category ? category.subCategories[this.subcategoryIndex] : null; let subCategory = category ? category.subCategories[subcategoryIndex] : null;
var jsonFileUrl = window.URL.createObjectURL(new Blob([JSON.stringify(indicators)], {type: 'application/json'})); var jsonFileUrl = window.URL.createObjectURL(new Blob([JSON.stringify(indicators)], {type: 'application/json'}));
var a = window.document.createElement('a'); var a = window.document.createElement('a');

View File

@ -9,6 +9,9 @@
<span class="uk-width-expand uk-text-truncate uk-margin-left hide-on-close">Indicators</span> <span class="uk-width-expand uk-text-truncate uk-margin-left hide-on-close">Indicators</span>
</a> </a>
</div> </div>
<div *ngIf="showLogo" id="sidebar_logo" class="uk-margin-top">
<img [src]="stakeholder | logoUrl">
</div>
<div class="menu_section uk-margin-large-top"> <div class="menu_section uk-margin-large-top">
<ul class="uk-list uk-nav uk-nav-default" transition-group [id]="'topics'" <ul class="uk-list uk-nav uk-nav-default" transition-group [id]="'topics'"
uk-nav="duration: 400"> uk-nav="duration: 400">
@ -26,12 +29,11 @@
<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"> <a class="uk-link-reset uk-flex uk-flex-middle">
<icon [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 <div #element 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">
<li> <li>
@ -59,9 +61,10 @@
</div> </div>
</a> </a>
</li> </li>
<li class="uk-nav-divider"></li>
</ng-container> </ng-container>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v> <ng-container *ngIf="showVisibility">
<li *ngIf="isCurator" class="uk-nav-divider"></li>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibilities" let-v>
<li [class.uk-active]="topic.visibility === v.value"> <li [class.uk-active]="topic.visibility === v.value">
<a (click)="openVisibilityModal(i, v.value, 'topic'); hide(element)"> <a (click)="openVisibilityModal(i, v.value, 'topic'); hide(element)">
<div class="uk-flex uk-flex-middle"> <div class="uk-flex uk-flex-middle">
@ -73,6 +76,7 @@
</a> </a>
</li> </li>
</ng-template> </ng-template>
</ng-container>
<ng-container *ngIf="!topic.defaultId && isCurator"> <ng-container *ngIf="!topic.defaultId && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li> <li>
@ -103,7 +107,7 @@
<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"> <a class="uk-link-reset uk-flex uk-flex-middle">
<icon [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>
@ -137,9 +141,11 @@
</div> </div>
</a> </a>
</li> </li>
<li class="uk-nav-divider"></li>
</ng-container> </ng-container>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v> <ng-container *ngIf="showVisibility">
<li *ngIf="isCurator" class="uk-nav-divider"></li>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibilities" let-v>
<li [class.uk-active]="category.visibility === v.value"> <li [class.uk-active]="category.visibility === v.value">
<a (click)="openVisibilityModal(j, v.value, 'category'); hide(element)"> <a (click)="openVisibilityModal(j, v.value, 'category'); hide(element)">
<div class="uk-flex uk-flex-middle"> <div class="uk-flex uk-flex-middle">
@ -151,6 +157,7 @@
</a> </a>
</li> </li>
</ng-template> </ng-template>
</ng-container>
<ng-container *ngIf="!category.defaultId && isCurator"> <ng-container *ngIf="!category.defaultId && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li> <li>
@ -191,8 +198,8 @@
</div> </div>
</aside> </aside>
<div #pageContent *ngIf="stakeholder && filters" class="uk-width-1-1" page-content> <div #pageContent *ngIf="stakeholder && filters" class="uk-width-1-1" page-content>
<div actions> <div actions class="uk-margin-medium-top">
<div *ngIf="stakeholder.topics.length > 0" class="uk-flex uk-flex-center uk-margin-medium-top uk-flex-right@m uk-width-1-1"> <div *ngIf="stakeholder.topics.length > 0 && showVisibility" class="uk-flex uk-flex-center uk-flex-right@m uk-width-1-1">
<button class="uk-button uk-button-primary uk-flex uk-flex-middle"> <button class="uk-button uk-button-primary uk-flex uk-flex-middle">
<icon name="visibility" [flex]="true"></icon> <icon name="visibility" [flex]="true"></icon>
<span class="uk-margin-small-left uk-margin-small-right">Preview</span> <span class="uk-margin-small-left uk-margin-small-right">Preview</span>
@ -229,7 +236,7 @@
[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"> <a class="uk-link-reset uk-flex uk-flex-middle">
<icon [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>
@ -279,9 +286,10 @@
</div> </div>
</a> </a>
</li> </li>
<li class="uk-nav-divider"></li>
</ng-container> </ng-container>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v> <ng-container *ngIf="showVisibility">
<li *ngIf="isCurator" class="uk-nav-divider"></li>
<ng-template ngFor [ngForOf]="stakeholderUtils.visibilities" let-v>
<li [class.uk-active]="subCategory.visibility === v.value"> <li [class.uk-active]="subCategory.visibility === v.value">
<a (click)="openVisibilityModal(i, v.value, 'subcategory'); hide(element)"> <a (click)="openVisibilityModal(i, v.value, 'subcategory'); hide(element)">
<div class="uk-flex uk-flex-middle"> <div class="uk-flex uk-flex-middle">
@ -293,6 +301,7 @@
</a> </a>
</li> </li>
</ng-template> </ng-template>
</ng-container>
<ng-container *ngIf="!subCategory.defaultId && isCurator"> <ng-container *ngIf="!subCategory.defaultId && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li> <li>
@ -348,8 +357,8 @@
<div *ngIf="form" [class.uk-hidden]="loading" <div *ngIf="form" [class.uk-hidden]="loading"
class="uk-grid uk-padding uk-padding-remove-horizontal uk-child-width-1-1" [formGroup]="form" uk-grid> class="uk-grid uk-padding uk-padding-remove-horizontal uk-child-width-1-1" [formGroup]="form" uk-grid>
<div input [formInput]="form.get('name')" class="uk-width-1-2@m" placeholder="Title"></div> <div input [formInput]="form.get('name')" class="uk-width-1-2@m" placeholder="Title"></div>
<div input [formInput]="form.get('visibility')" class="uk-width-1-2@m" placeholder="Status" <div *ngIf="showVisibility" input [formInput]="form.get('visibility')" class="uk-width-1-2@m" placeholder="Status"
[options]="stakeholderUtils.visibility" type="select"></div> [options]="stakeholderUtils.visibilities" type="select"></div>
<div input [formInput]="form.get('description')" placeholder="Description" type="textarea" rows="4"></div> <div input [formInput]="form.get('description')" placeholder="Description" type="textarea" rows="4"></div>
<div *ngIf="form.get('icon')" input [formInput]="form.get('icon')" placeholder="Icon(SVG)" type="textarea"></div> <div *ngIf="form.get('icon')" input [formInput]="form.get('icon')" placeholder="Icon(SVG)" type="textarea"></div>
</div> </div>

View File

@ -1,32 +1,32 @@
import { import {
AfterViewInit, AfterViewInit,
ChangeDetectorRef, ChangeDetectorRef,
Component, Inject, Component,
Inject,
OnDestroy, OnDestroy,
OnInit, PLATFORM_ID, OnInit,
PLATFORM_ID,
QueryList, QueryList,
ViewChild, ViewChild,
ViewChildren ViewChildren
} from '@angular/core'; } from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {EnvProperties} from '../../utils/properties/env-properties';
import {Category, Stakeholder, SubCategory, Topic, Visibility} from "../../monitor/entities/stakeholder"; import {Category, Stakeholder, SubCategory, Topic, Visibility} from "../../monitor/entities/stakeholder";
import {StakeholderService} from "../../monitor/services/stakeholder.service"; import {StakeholderService} from "../../monitor/services/stakeholder.service";
import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {AlertModal} from "../../utils/modal/alert"; import {AlertModal} from "../../utils/modal/alert";
import {BehaviorSubject, Subject, Subscriber, Subscription} from "rxjs"; import {BehaviorSubject, Subject, Subscriber, Subscription} from "rxjs";
import {UntypedFormBuilder, UntypedFormGroup, Validators} from "@angular/forms"; import {UntypedFormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
import {StakeholderUtils} from "../utils/indicator-utils";
import {StringUtils} from "../../utils/string-utils.class"; import {StringUtils} from "../../utils/string-utils.class";
import {IDeactivateComponent} from "../../utils/can-exit.guard"; import {IDeactivateComponent} from "../../utils/can-exit.guard";
import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service";
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
import {properties} from "src/environments/environment"; import {properties} from "src/environments/environment";
import {Session, User} from "../../login/utils/helper.class"; import {Session, User} from "../../login/utils/helper.class";
import {UserManagementService} from "../../services/user-management.service"; import {UserManagementService} from "../../services/user-management.service";
import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component"; import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component";
import {NotificationHandler} from "../../utils/notification-handler"; import {NotificationHandler} from "../../utils/notification-handler";
import {StakeholderBaseComponent} from "../utils/stakeholder-base.component";
declare var UIkit; declare var UIkit;
@ -34,14 +34,12 @@ declare var UIkit;
selector: 'topic', selector: 'topic',
templateUrl: './topic.component.html', templateUrl: './topic.component.html',
}) })
export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeactivateComponent { export class TopicComponent extends StakeholderBaseComponent implements OnInit, OnDestroy, AfterViewInit, IDeactivateComponent {
private topicSubscriptions: any[] = []; private topicSubscriptions: any[] = [];
private subscriptions: any[] = [];
public properties: EnvProperties = properties;
public offset: number; public offset: number;
public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
public loading: boolean = false; public loading: boolean = false;
public stakeholder: Stakeholder; public stakeholder: Stakeholder;
public showLogo: boolean = false;
public user: User; public user: User;
/** /**
* Stakeholder change event * Stakeholder change event
@ -84,18 +82,21 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
}; };
constructor( constructor(
private route: ActivatedRoute, protected _route: ActivatedRoute,
private router: Router, protected _router: Router,
private title: Title, protected _title: Title,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private stakeholderService: StakeholderService, private stakeholderService: StakeholderService,
private userManagementService: UserManagementService, private userManagementService: UserManagementService,
private layoutService: LayoutService, protected cdr: ChangeDetectorRef,
private cdr: ChangeDetectorRef,
@Inject(PLATFORM_ID) private platformId) { @Inject(PLATFORM_ID) private platformId) {
super();
} }
public ngOnInit() { public ngOnInit() {
if(this._route.snapshot.data?.showLogo === true) {
this.showLogo = true;
}
if (typeof document !== "undefined") { if (typeof document !== "undefined") {
this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height')); this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height'));
} }
@ -115,7 +116,7 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
this.subCategoryIndex = index; this.subCategoryIndex = index;
}); });
})); }));
this.subscriptions.push(this.route.params.subscribe(params => { this.subscriptions.push(this._route.params.subscribe(params => {
if (subscription) { if (subscription) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
@ -136,7 +137,8 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
if (this.topicIndex === -1) { if (this.topicIndex === -1) {
this.navigateToError(); this.navigateToError();
} else { } else {
this.title.setTitle(stakeholder.name + " | Indicators"); this.title = stakeholder.name + " | Indicators"
this.setMetadata();
} }
} }
}); });
@ -163,16 +165,12 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
} }
public ngOnDestroy() { public ngOnDestroy() {
super.ngOnDestroy();
this.topicSubscriptions.forEach(value => { this.topicSubscriptions.forEach(value => {
if (value instanceof Subscriber) { if (value instanceof Subscriber) {
value.unsubscribe(); value.unsubscribe();
} }
}); });
this.subscriptions.forEach(value => {
if (value instanceof Subscriber) {
value.unsubscribe();
}
});
} }
canExit(): boolean { canExit(): boolean {
@ -665,10 +663,6 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
}); });
} }
private navigateToError() {
this.router.navigate([this.properties.errorLink], {queryParams: {'page': this.router.url}});
}
get isCurator(): boolean { get isCurator(): boolean {
return Session.isPortalAdministrator(this.user) || Session.isCurator(this.stakeholder.type, this.user); return Session.isPortalAdministrator(this.user) || Session.isCurator(this.stakeholder.type, this.user);
} }
@ -714,8 +708,8 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
this.editModal.cancel(); this.editModal.cancel();
NotificationHandler.rise(message); NotificationHandler.rise(message);
if (redirect) { if (redirect) {
this.router.navigate(['../' + saveElement.alias], { this._router.navigate(['../' + saveElement.alias], {
relativeTo: this.route relativeTo: this._route
}); });
} }
}, error => { }, error => {
@ -758,8 +752,8 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
} }
back() { back() {
this.router.navigate(['../'], { this._router.navigate(['../'], {
relativeTo: this.route relativeTo: this._route
}); });
} }
@ -775,19 +769,6 @@ export class TopicComponent implements OnInit, OnDestroy, AfterViewInit, IDeacti
} }
} }
public get isSmallScreen() {
return this.layoutService.isSmallScreen;
}
public get open() {
return this.layoutService.open;
}
public toggleOpen(event: MouseEvent) {
event.preventDefault();
this.layoutService.setOpen(!this.open);
}
public openVisibilityModal(index: number, visibility: Visibility, type: any) { public openVisibilityModal(index: number, visibility: Visibility, type: any) {
this.index = index; this.index = index;
this.visibility = visibility; this.visibility = visibility;

View File

@ -8,12 +8,14 @@ import {StakeholderService} from "../../monitor/services/stakeholder.service";
import {Observable, zip} from "rxjs"; import {Observable, zip} from "rxjs";
@Injectable() @Injectable({
providedIn: 'root'
})
export class AdminDashboardGuard { export class AdminDashboardGuard {
constructor(private router: Router, constructor(protected router: Router,
private stakeholderService: StakeholderService, protected stakeholderService: StakeholderService,
private userManagementService: UserManagementService) { protected userManagementService: UserManagementService) {
} }
check(path: string, alias: string): Observable<boolean> | boolean { check(path: string, alias: string): Observable<boolean> | boolean {
@ -38,6 +40,6 @@ export class AdminDashboardGuard {
} }
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.check(state.url, childRoute.params.stakeholder); return this.check(state.url, childRoute.data?.stakeholder?childRoute.data.stakeholder:childRoute.params.stakeholder);
} }
} }

View File

@ -7,11 +7,9 @@ import {
IndicatorPathType, IndicatorPathType,
IndicatorType, IndicatorType,
SourceType, SourceType,
Stakeholder, Stakeholder, SubCategory,
StakeholderEntities, Topic,
SubCategory, Visibility,
Topic, stakeholderTypes,
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";
@ -19,34 +17,85 @@ import {Session} from "../../login/utils/helper.class";
import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {properties} from "src/environments/environment"; import {properties} from "src/environments/environment";
export class StakeholderUtils { class Entities {
stakeholder = 'Dashboard';
funder = 'Funder';
ri = 'Research Initiative';
organization = 'Research Institution';
project = 'Project';
country = 'National';
datasource = 'Repository';
researcher = 'Researcher';
statuses: Option[] = [ stakeholders = 'Dashboards';
{value: 'PUBLIC', label: 'Public'}, funders = 'Funders';
{value: 'RESTRICTED', label: 'Restricted'}, ris = 'Research Initiatives';
{value: 'PRIVATE', label: 'Private'} organizations = 'Research Institutions';
projects = 'Projects';
datasources = 'Repositories';
researchers = 'Researchers';
}
export class StakeholderConfiguration {
public static ENTITIES: Entities = new Entities();
public static TYPES: Option[] = [
{value: 'funder', label: StakeholderConfiguration.ENTITIES.funder},
{value: 'ri', label: StakeholderConfiguration.ENTITIES.ri},
{value: 'organization', label: StakeholderConfiguration.ENTITIES.organization},
{value: 'project', label: StakeholderConfiguration.ENTITIES.project}
]; ];
public static LOCALES: Option[] = [
types: Option[] = [ {value: "en", label: 'English'},
...stakeholderTypes {value: "eu", label: 'Europe'}
]; ];
public static FUNDER_TYPES: Option[] = [];
visibility: Option[] = [ public static VISIBILITIES: Option[] = [
{icon: 'earth', value: "PUBLIC", label: 'Public'}, {icon: 'earth', value: "PUBLIC", label: 'Public'},
{icon: 'restricted', value: "RESTRICTED", label: 'Restricted'}, {icon: 'restricted', value: "RESTRICTED", label: 'Restricted'},
{icon: 'incognito', value: "PRIVATE", label: 'Private'}, {icon: 'incognito', value: "PRIVATE", label: 'Private'},
]; ];
public static CACHE_INDICATORS: boolean = true;
}
locales: Option[] = [ export class StakeholderUtils {
{value: "en", label: 'English'}, get entities() {
{value: "eu", label: 'Europe'} return StakeholderConfiguration.ENTITIES;
]; }
visibilityIcon: Map<Visibility, string> = new Map<Visibility, string>([ get types() {
["PUBLIC", 'earth'], return StakeholderConfiguration.TYPES
["PRIVATE", 'incognito'], }
["RESTRICTED", 'restricted']
]); get funderTypes() {
return StakeholderConfiguration.FUNDER_TYPES;
}
get locales() {
return StakeholderConfiguration.LOCALES;
}
get visibilities() {
return StakeholderConfiguration.VISIBILITIES;
}
get isCachingIndicators() {
return StakeholderConfiguration.CACHE_INDICATORS;
}
visibilityIcon: Map<Visibility, string> = new Map<Visibility, string>(this.visibilities.map(option => [option.value, option.icon]));
defaultValue(options: Option[]) {
return options.length === 1?options[0].value:null;
}
showField(options: Option[]) {
return options.length > 1;
}
getLabel(options: Option[], value) {
let option = options.find(option => option.value === value);
return option?option.label:null;
}
getTypesByUserRoles(user, id: string = null): Option[] { getTypesByUserRoles(user, id: string = null): Option[] {
let types = []; let types = [];
@ -116,7 +165,7 @@ export class StakeholderUtils {
aliasValidatorString(elements: string[]): ValidatorFn { aliasValidatorString(elements: string[]): ValidatorFn {
return (control: AbstractControl): { [key: string]: string } | null => { return (control: AbstractControl): { [key: string]: string } | null => {
if (control.value && elements.find(element => if (control.value && elements.find(element =>
element === control.value element === control.value
)) { )) {
return {'error': 'Alias already in use'}; return {'error': 'Alias already in use'};
} }
@ -127,7 +176,7 @@ export class StakeholderUtils {
aliasValidator(elements: any[]): ValidatorFn { aliasValidator(elements: any[]): ValidatorFn {
return (control: AbstractControl): { [key: string]: string } | null => { return (control: AbstractControl): { [key: string]: string } | null => {
if (control.value && elements.find(element => if (control.value && elements.find(element =>
element.alias === control.value element.alias === control.value
)) { )) {
return {'error': 'Alias already in use'}; return {'error': 'Alias already in use'};
} }
@ -197,16 +246,16 @@ export class IndicatorUtils {
constructor() { constructor() {
this.numberSources.set('statistics', [properties.statisticsAPIURL]); this.numberSources.set('statistics', [properties.statisticsAPIURL]);
this.numberSources.set('search', [properties.searchAPIURLLAst]); this.numberSources.set('search', [properties.searchAPIURLLAst]);
this.numberSources.set('stats-tool', [properties.monitorStatsFrameUrl, "http://marilyn.athenarc.gr:8080/stats-api/", "http://88.197.53.71:8080/stats-api/", "https://stats.madgik.di.uoa.gr/stats-api/","https://beta.services.openaire.eu/stats-tool/","https://services.openaire.eu/stats-tool/","https://services.openaire.eu/monitor-stats-tool/"]); this.numberSources.set('stats-tool', [properties.monitorStatsFrameUrl, "http://marilyn.athenarc.gr:8080/stats-api/", "http://88.197.53.71:8080/stats-api/", "https://stats.madgik.di.uoa.gr/stats-api/", "https://beta.services.openaire.eu/stats-tool/", "https://services.openaire.eu/stats-tool/", "https://services.openaire.eu/monitor-stats-tool/"]);
this.chartSources.set('stats-tool', [properties.monitorStatsFrameUrl, "http://marilyn.athenarc.gr:8080/stats-api/", "http://88.197.53.71:8080/stats-api/", "https://stats.madgik.di.uoa.gr/stats-api/","https://beta.services.openaire.eu/stats-tool/","https://services.openaire.eu/stats-tool/","https://services.openaire.eu/monitor-stats-tool/"]); this.chartSources.set('stats-tool', [properties.monitorStatsFrameUrl, "http://marilyn.athenarc.gr:8080/stats-api/", "http://88.197.53.71:8080/stats-api/", "https://stats.madgik.di.uoa.gr/stats-api/", "https://beta.services.openaire.eu/stats-tool/", "https://services.openaire.eu/stats-tool/", "https://services.openaire.eu/monitor-stats-tool/"]);
this.chartSources.set('old', [properties.statisticsFrameAPIURL]); this.chartSources.set('old', [properties.statisticsFrameAPIURL]);
this.chartSources.set('image', [""]); this.chartSources.set('image', [""]);
} }
getSourceType(source:string): SourceType{ getSourceType(source: string): SourceType {
let sourceType: SourceType = 'search'; let sourceType: SourceType = 'search';
this.numberSources.forEach((values, key) => { this.numberSources.forEach((values, key) => {
if(key == source) { if (key == source) {
sourceType = key; sourceType = key;
} }
}); });
@ -343,12 +392,71 @@ export class IndicatorUtils {
return (indicatorPath.chartObject ? indicatorPath.url + encodeURIComponent(replacedUrl) : replacedUrl); return (indicatorPath.chartObject ? indicatorPath.url + encodeURIComponent(replacedUrl) : replacedUrl);
} }
public getFullUrlWithFilters(stakeholder: Stakeholder, indicatorPath: IndicatorPath, fundingL0: string = null, startYear: string = null, endYear: string = null, coFunded: boolean = false): string { public getFullUrlWithFilters(stakeholder: Stakeholder, indicatorPath: IndicatorPath, fundingL0: string = null, startYear: string = null, endYear: string = null, coFunded: boolean = false, foslvl1:string[]=[], foslvl2:string[]=[], publiclyFunded: "all"| "true"| "false"= "all" ): string {
let filterSubtitleText = [];
indicatorPath.filtersApplied = 0; indicatorPath.filtersApplied = 0;
let replacedUrl = indicatorPath.chartObject ? indicatorPath.chartObject : indicatorPath.url; let replacedUrl = indicatorPath.chartObject ? indicatorPath.chartObject : indicatorPath.url;
if (stakeholder.statsProfile) { if (stakeholder.statsProfile) {
replacedUrl = replacedUrl.split(ChartHelper.prefix + this.statsProfileParameter + ChartHelper.suffix).join(stakeholder.statsProfile); replacedUrl = replacedUrl.split(ChartHelper.prefix + this.statsProfileParameter + ChartHelper.suffix).join(stakeholder.statsProfile);
} }
if (fundingL0) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'fundingL0', fundingL0);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
filterSubtitleText.push( "Funding level 0: " ) ;
}
}
if (startYear) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'start_year', startYear);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
}
}
if (endYear) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'end_year', endYear);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
}
}
if(startYear || endYear) {
filterSubtitleText.push(startYear && endYear ? (startYear + ' - ' + endYear) : (endYear ? ('until ' + endYear) : ''));
}
if (coFunded) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'co-funded', coFunded);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
filterSubtitleText.push( "Co-funded: " + (coFunded?'yes':'no') ) ;
}
}
if (publiclyFunded && publiclyFunded !="all") {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'publicly-funded', publiclyFunded);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
filterSubtitleText.push( "Publicly funded: " + (publiclyFunded?'yes':'no') ) ;
}
}
if (foslvl1) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'foslvl1', foslvl1);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied +=filterResults.filtersApplied?foslvl1.length:0;
}
}
if (foslvl2) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'foslvl2', foslvl2);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied?foslvl2.length:0;
}
}
if((foslvl1 && foslvl1.length > 0) || (foslvl2 && foslvl2.length > 0)){
filterSubtitleText.push( "Field of Science: " + foslvl1.join(', ') + ( foslvl1.length > 0 && foslvl2.length > 0? ', ': '') + foslvl2.join(", ") ) ;
}
if (indicatorPath.parameters) { if (indicatorPath.parameters) {
Object.keys(indicatorPath.parameters).forEach(key => { Object.keys(indicatorPath.parameters).forEach(key => {
let replacedValue = indicatorPath.parameters[key]; let replacedValue = indicatorPath.parameters[key];
@ -371,39 +479,12 @@ export class IndicatorUtils {
if (key == "index_shortName") { if (key == "index_shortName") {
replacedValue = stakeholder.index_shortName.toLowerCase(); replacedValue = stakeholder.index_shortName.toLowerCase();
} }
if (key == "subtitle" && filterSubtitleText.length > 0) {
replacedValue = replacedValue + (replacedValue.length > 0 ? ' - ':'') + ' Active filters: ('+filterSubtitleText.join(", ") + ')';
}
replacedUrl = replacedUrl.split(ChartHelper.prefix + key + ChartHelper.suffix).join(replacedValue) replacedUrl = replacedUrl.split(ChartHelper.prefix + key + ChartHelper.suffix).join(replacedValue)
}); });
} }
if (fundingL0) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'fundingL0', fundingL0);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
}
}
if (startYear) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'start_year', startYear);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
}
}
if (endYear) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'end_year', endYear);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
}
}
if (coFunded) {
if (indicatorPath.source == "stats-tool" && indicatorPath.chartObject) {
let filterResults = this.addFilter(replacedUrl, 'co-funded', endYear);
replacedUrl = filterResults.url;
indicatorPath.filtersApplied += filterResults.filtersApplied;
}
}
//For numbers //For numbers
if (replacedUrl.indexOf(ChartHelper.prefix + 'index_id' + ChartHelper.suffix) != -1) { if (replacedUrl.indexOf(ChartHelper.prefix + 'index_id' + ChartHelper.suffix) != -1) {
replacedUrl = replacedUrl.split(ChartHelper.prefix + 'index_id' + ChartHelper.suffix).join(encodeURIComponent(stakeholder.index_id)); replacedUrl = replacedUrl.split(ChartHelper.prefix + 'index_id' + ChartHelper.suffix).join(encodeURIComponent(stakeholder.index_id));
@ -414,7 +495,6 @@ export class IndicatorUtils {
if (replacedUrl.indexOf(ChartHelper.prefix + 'index_shortName' + ChartHelper.suffix) != -1) { if (replacedUrl.indexOf(ChartHelper.prefix + 'index_shortName' + ChartHelper.suffix) != -1) {
replacedUrl = replacedUrl.split(ChartHelper.prefix + 'index_shortName' + ChartHelper.suffix).join(encodeURIComponent(stakeholder.index_shortName)); replacedUrl = replacedUrl.split(ChartHelper.prefix + 'index_shortName' + ChartHelper.suffix).join(encodeURIComponent(stakeholder.index_shortName));
} }
//Check apply enhancements return this.applySchemaEnhancements( ..);
return (indicatorPath.chartObject ? indicatorPath.url + encodeURIComponent(replacedUrl) : replacedUrl); return (indicatorPath.chartObject ? indicatorPath.url + encodeURIComponent(replacedUrl) : replacedUrl);
} }
@ -493,7 +573,7 @@ export class IndicatorUtils {
/*Chart with proper json object*/ /*Chart with proper json object*/
//apply the filter in any select fields //apply the filter in any select fields
for (let select of queries["query"]["select"]) { for (let select of queries["query"]["select"]) {
let filterString = IndicatorFilterUtils.getFilter(select["field"], filterType); let filterString = IndicatorFilterUtils.getFilter(select["field"], filterType,filterValue);
if (filterString) { if (filterString) {
let filter = JSON.parse(filterString); let filter = JSON.parse(filterString);
//check if filter already exists //check if filter already exists
@ -557,7 +637,7 @@ export class IndicatorUtils {
generateIndicatorByForm(form: any, indicatorPaths: IndicatorPath[], type: IndicatorType, addParameters: boolean = true): Indicator { generateIndicatorByForm(form: any, indicatorPaths: IndicatorPath[], type: IndicatorType, addParameters: boolean = true): Indicator {
let indicator: Indicator = new Indicator(form.name, form.description, form.additionalDescription, type, let indicator: Indicator = new Indicator(form.name, form.description, form.additionalDescription, type,
form.width, form.height, form.visibility, indicatorPaths, form.defaultId); form.width, form.height, form.visibility, indicatorPaths, form.defaultId);
indicator._id = form._id; indicator._id = form._id;
form.indicatorPaths.forEach((indicatorPath, index) => { form.indicatorPaths.forEach((indicatorPath, index) => {
indicator.indicatorPaths[index].type = indicatorPath.type; indicator.indicatorPaths[index].type = indicatorPath.type;
@ -703,6 +783,8 @@ export class IndicatorUtils {
this.extractFunder(obj, indicatorPath, stakeholder); this.extractFunder(obj, indicatorPath, stakeholder);
this.extractRI(obj, indicatorPath, stakeholder); this.extractRI(obj, indicatorPath, stakeholder);
this.extractOrganization(obj, indicatorPath, stakeholder); this.extractOrganization(obj, indicatorPath, stakeholder);
this.extractDatasource(obj, indicatorPath, stakeholder);
this.extractResearcher(obj, indicatorPath, stakeholder);
} }
private extractFunder(obj, indicatorPath: IndicatorPath, stakeholder: Stakeholder) { private extractFunder(obj, indicatorPath: IndicatorPath, stakeholder: Stakeholder) {
@ -719,15 +801,13 @@ export class IndicatorUtils {
for (let filter of query["query"]["filters"]) { for (let filter of query["query"]["filters"]) {
for (let gfilter of filter["groupFilters"]) { for (let gfilter of filter["groupFilters"]) {
//ignore field No Of Funders //ignore field No Of Funders
if (gfilter["field"].indexOf(" funder") != -1 && gfilter["field"].indexOf(" funders") == -1) {//new statistcs schema let replacedValue = this.replaceIndexValues(gfilter["values"][0], stakeholder, indicatorPath.parameters);
gfilter["values"][0] = ChartHelper.prefix + "index_name" + ChartHelper.suffix; if(replacedValue) { // don't proceed in replacement if no replaced value matches
indicatorPath.parameters["index_name"] = stakeholder.index_name; if ((gfilter["field"].indexOf(" funder") != -1 && gfilter["field"].indexOf(" funders") == -1 ) ||
} else if (gfilter["field"].indexOf(".funder") != -1) { (gfilter["field"].indexOf(".funder") != -1) ||
gfilter["values"][0] = ChartHelper.prefix + "index_name" + ChartHelper.suffix; (gfilter["field"].indexOf(".funder.id") != -1)) {
indicatorPath.parameters["index_name"] = stakeholder.index_name; gfilter["values"][0] = replacedValue;
} else if (gfilter["field"].indexOf(".funder.id") != -1) { }
gfilter["values"][0] = ChartHelper.prefix + "index_shortName" + ChartHelper.suffix;
indicatorPath.parameters["index_shortName"] = stakeholder.index_shortName;
} }
} }
} }
@ -747,12 +827,12 @@ export class IndicatorUtils {
} }
for (let filter of query["query"]["filters"]) { for (let filter of query["query"]["filters"]) {
for (let gfilter of filter["groupFilters"]) { for (let gfilter of filter["groupFilters"]) {
if (gfilter["field"].indexOf(".context.name") != -1) { let replacedValue = this.replaceIndexValues(gfilter["values"][0], stakeholder, indicatorPath.parameters);
gfilter["values"][0] = ChartHelper.prefix + "index_name" + ChartHelper.suffix; if(replacedValue) { // don't proceed in replacement if no replaced value matches
indicatorPath.parameters["index_name"] = stakeholder.index_name; if ((gfilter["field"].indexOf(".context.name") != -1)
} else if (gfilter["field"].indexOf(".context.id") != -1) { || (gfilter["field"].indexOf(".context.id") != -1)) {
gfilter["values"][0] = ChartHelper.prefix + "index_shortName" + ChartHelper.suffix; gfilter["values"][0] = replacedValue;
indicatorPath.parameters["index_shortName"] = stakeholder.index_shortName; }
} }
} }
} }
@ -774,18 +854,80 @@ export class IndicatorUtils {
} }
for (let filter of query["query"]["filters"]) { for (let filter of query["query"]["filters"]) {
for (let gfilter of filter["groupFilters"]) { for (let gfilter of filter["groupFilters"]) {
if (gfilter["field"].indexOf(".organization.name") != -1) { let replacedValue = this.replaceIndexValues(gfilter["values"][0], stakeholder, indicatorPath.parameters);
gfilter["values"][0] = ChartHelper.prefix + "index_name" + ChartHelper.suffix; if(replacedValue) { // don't proceed in replacement if no replaced value matches
indicatorPath.parameters["index_name"] = stakeholder.index_name; if ((gfilter["field"].indexOf(".organization.name") != -1)||
} else if (gfilter["field"].indexOf(".organization.id") != -1) { (gfilter["field"].indexOf(".organization.id") != -1)) {
gfilter["values"][0] = ChartHelper.prefix + "index_shortName" + ChartHelper.suffix; gfilter["values"][0] = replacedValue;
indicatorPath.parameters["index_shortName"] = stakeholder.index_shortName; }
} }
} }
} }
} }
} }
private extractDatasource(obj, indicatorPath: IndicatorPath, stakeholder: Stakeholder) {
// works for .datasource.name and .HostedBy datasource
// and .datasource.id
if (stakeholder.type != "datasource") {
return;
}
for (let query of this.getQueryObjectName(obj) ? obj[this.getDescriptionObjectName(obj)][this.getQueryObjectName(obj)] : obj[this.getDescriptionObjectName(obj)]) {
if (query["query"]["profile"]) {
query["query"]["profile"] = ChartHelper.prefix + this.statsProfileParameter + ChartHelper.suffix;
}
if (!query["query"]["filters"]) {
return;
}
for (let filter of query["query"]["filters"]) {
for (let gfilter of filter["groupFilters"]) {
let replacedValue = this.replaceIndexValues(gfilter["values"][0], stakeholder, indicatorPath.parameters);
if(replacedValue) { // don't proceed in replacement if no replaced value matches
if ((gfilter["field"].indexOf(".datasource.name") != -1 || gfilter["field"].indexOf(".HostedBy datasource") != -1)||
(gfilter["field"].indexOf(".datasource.id") != -1) || (gfilter["field"].indexOf(".hostedby") != -1)) {
gfilter["values"][0] = replacedValue;
}
}
}
}
}
}
private extractResearcher(obj, indicatorPath: IndicatorPath, stakeholder: Stakeholder) {
// works for .orcid
if (stakeholder.type != "researcher") {
return;
}
for (let query of this.getQueryObjectName(obj) ? obj[this.getDescriptionObjectName(obj)][this.getQueryObjectName(obj)] : obj[this.getDescriptionObjectName(obj)]) {
if (query["query"]["profile"]) {
query["query"]["profile"] = ChartHelper.prefix + this.statsProfileParameter + ChartHelper.suffix;
}
if (!query["query"]["filters"]) {
return;
}
for (let filter of query["query"]["filters"]) {
for (let gfilter of filter["groupFilters"]) {
let replacedValue = this.replaceIndexValues(gfilter["values"][0], stakeholder, indicatorPath.parameters);
if(replacedValue) { // don't proceed in replacement if no replaced value matches
if ((gfilter["field"].indexOf(".orcid") != -1 )) {
gfilter["values"][0] = replacedValue;
}
}
}
}
}
}
private replaceIndexValues(currentValue, stakeholder, parameters ){
if(currentValue == stakeholder.index_name){
parameters["index_name"] = stakeholder.index_name;
return ChartHelper.prefix + "index_name" + ChartHelper.suffix;
}else if(currentValue == stakeholder.index_id){
parameters["index_id"] = stakeholder.index_id;
return ChartHelper.prefix + "index_id" + ChartHelper.suffix;
}else if(currentValue == stakeholder.index_shortName) {
parameters["index_shortName"] = stakeholder.index_shortName;
return ChartHelper.prefix + "index_shortName" + ChartHelper.suffix;
}
}
private extractStartYear(obj, indicatorPath: IndicatorPath) { private extractStartYear(obj, indicatorPath: IndicatorPath) {
let start_year; let start_year;
for (let query of obj[this.getDescriptionObjectName(obj)][this.getQueryObjectName(obj)]) { for (let query of obj[this.getDescriptionObjectName(obj)][this.getQueryObjectName(obj)]) {

View File

@ -0,0 +1,54 @@
import {Directive} from "@angular/core";
import {BaseComponent} from "../../sharedComponents/base/base.component";
import {IndicatorUtils, StakeholderUtils} from "./indicator-utils";
import {ConnectHelper} from "../../connect/connectHelper";
@Directive()
export abstract class StakeholderBaseComponent extends BaseComponent {
stakeholderUtils: StakeholderUtils = new StakeholderUtils();
get entities() {
return this.stakeholderUtils.entities;
}
get showVisibility() {
return this.stakeholderUtils.showField(this.stakeholderUtils.visibilities);
}
get showType() {
return this.stakeholderUtils.showField(this.stakeholderUtils.types);
}
get showFunderType() {
return this.stakeholderUtils.showField(this.stakeholderUtils.funderTypes);
}
getFunderTypeLabel(value: any) {
return this.stakeholderUtils.getLabel(this.stakeholderUtils.funderTypes, value);
}
get showLocale() {
return this.stakeholderUtils.showField(this.stakeholderUtils.locales);
}
protected navigateToError() {
this._router.navigate([this.properties.errorLink], {queryParams: {'page': this._router.url}});
}
setProperties(id, type = null, configurationService) {
this.properties.adminToolsCommunity = id;
if (type) {
this.properties.adminToolsPortalType = type;
} else {
ConnectHelper.setPortalTypeFromPid(id);
}
configurationService.initPortal(this.properties, this.properties.adminToolsCommunity);
}
}
@Directive()
export abstract class IndicatorStakeholderBaseComponent extends StakeholderBaseComponent {
indicatorUtils: IndicatorUtils = new IndicatorUtils();
}

View File

@ -1,24 +1,25 @@
import {SafeResourceUrl} from "@angular/platform-browser"; import {SafeResourceUrl} from "@angular/platform-browser";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {Session, User} from "../../login/utils/helper.class"; import {Session, User} from "../../login/utils/helper.class";
import {Option} from "../../sharedComponents/input/input.component";
export const ChartHelper = { export const ChartHelper = {
prefix: "((__", prefix: "((__",
suffix: "__))" suffix: "__))"
}; };
export type StakeholderType = 'funder' | 'ri' | 'project' | 'organization'; export type StakeholderType = 'funder' | 'ri' | 'project' | 'organization' | 'country' | 'researcher' | 'datasource';
export type IndicatorType = 'number' | 'chart'; export type IndicatorType = 'number' | 'chart';
export type IndicatorSize = 'small' | 'medium' | 'large'; export type IndicatorSize = 'small' | 'medium' | 'large';
export type IndicatorPathType = 'table' | 'bar' | 'column' | 'pie' | 'line' | 'other'; export type IndicatorPathType = 'table' | 'bar' | 'column' | 'pie' | 'line' | 'other';
export type SourceType = 'statistics' | 'search' |'stats-tool' | 'old' | 'image'; export type SourceType = 'statistics' | 'search' |'stats-tool' | 'old' | 'image';
export type Format = 'NUMBER' | 'PERCENTAGE'; export type Format = 'NUMBER' | 'PERCENTAGE';
export type Visibility = 'PUBLIC' | 'PRIVATE' | 'RESTRICTED'; export type Visibility = 'PUBLIC' | 'PRIVATE' | 'RESTRICTED';
export type Overlay = 'embed' | 'description' | false;
export class Stakeholder { export class Stakeholder {
_id: string; _id: string;
type: StakeholderType; type: StakeholderType;
funderType: string;
name: string; name: string;
index_id; index_id;
index_name: string; index_name: string;
@ -36,8 +37,9 @@ export class Stakeholder {
isUpload: boolean = false; isUpload: boolean = false;
description: string; description: string;
topics: any[]; topics: any[];
details?: any;
constructor(_id: string, type: StakeholderType, index_id, 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) {
this._id = _id; this._id = _id;
this.type = type; this.type = type;
this.index_id = index_id; this.index_id = index_id;
@ -170,7 +172,7 @@ export class Indicator {
visibility: Visibility; visibility: Visibility;
defaultId: string; defaultId: string;
indicatorPaths: IndicatorPath[]; indicatorPaths: IndicatorPath[];
descriptionOverlay: boolean = 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) {
this._id = null; this._id = null;
@ -221,66 +223,104 @@ export class IndicatorPath {
} }
export type FilterType = "fundingL0"|"start_year" | "end_year" | "co-funded"; export type FilterType = "fundingL0"|"start_year" | "end_year" | "co-funded" | "foslvl1" | "foslvl2" | "publicly-funded";
export class IndicatorFilterUtils { export class IndicatorFilterUtils {
public static filteredFields = {
"year":{
"result": "result.year",
"indi_pub_downloads_year": "indi_pub_downloads_year.year", //exclude indi_pub_downloads_year.year because it throws errors. when there is a solution remove the exclusion
"indi_pub_downloads":"indi_pub_downloads.result.year",
"result_apc":"result_apc.result.year",
"result_apc_affiliations":"result_apc_affiliations.result.year",
"result_country":"result_country.result.year",
"indi_impact_measures": "indi_impact_measures.result.year",
"project": "project.start year"
},
"fundingL0":{
"result": "result.project funding level 0",
"project": "project.funding level 0",
"country":"country.organization.project.funding level 0",
"organization":"organization.project.funding level 0"
},
"co-funded":{
"result": "result.No of funders",
},
"foslvl1":
{
"publication":"publication.topics.result.result_fos.lvl1",
"result":"result.topics.result.result_fos.lvl1",
"indi_pub_downloads":"indi_pub_downloads.result.result_fos.lvl1",
"indi_pub_downloads_year":"indi_pub_downloads_year.result.result_fos.lvl1",
"indi_impact_measures":"indi_impact_measures.result.result_fos.lvl1",
"result_apc":"result_apc.result.result_fos.lvl1",
"result_apc_affiliations":"result_apc_affiliations.result.result_fos.lvl1",
"result_country":"result_country.result.result_fos.lvl1",
"historical_snapshots_irish_fos":"historical_snapshots_irish_fos.lvl1"
},
"foslvl2":{
"publication":"publication.topics.result.result_fos.lvl2",
"result":"result.topics.result.result_fos.lvl2",
"indi_pub_downloads":"indi_pub_downloads.result.result_fos.lvl2",
"indi_pub_downloads_year":"indi_pub_downloads_year.result.result_fos.lvl2",
"indi_impact_measures":"indi_impact_measures.result.result_fos.lvl2",
"result_apc":"result_apc.result.result_fos.lvl2",
"result_apc_affiliations":"result_apc_affiliations.result.result_fos.lvl2",
"result_country":"result_country.result.result_fos.lvl2",
"historical_snapshots_irish_fos":"historical_snapshots_irish_fos.lvl2"
},
"publicly-funded":{
"result":"result.indi_pub_publicly_funded.publicly_funded",
"indi_pub_downloads":"indi_pub_downloads.result.indi_pub_publicly_funded.publicly_funded",
"indi_pub_downloads_year":"indi_pub_downloads_year.result.indi_pub_publicly_funded.publicly_funded",
"indi_impact_measures":"indi_impact_measures.result.indi_pub_publicly_funded.publicly_funded",
"result_apc":"result_apc.result.indi_pub_publicly_funded.publicly_funded",
"result_apc_affiliations":"result_apc_affiliations.result.indi_pub_publicly_funded.publicly_funded",
"result_country":"result_country.result.indi_pub_publicly_funded.publicly_funded"
}
static getFilter(fieldPath: string, filterType:FilterType) { }
if((filterType == "start_year" || filterType == "end_year") && (fieldPath.indexOf(".year") != -1 || fieldPath.indexOf(".start year") != -1) static getFieldForTable(field, table){
&& fieldPath.indexOf("indi_pub_downloads_year.year") == -1){ if(["publication", "software", "dataset", "other", "result"].indexOf(table)!=-1 && IndicatorFilterUtils.filteredFields[field]["result"]){
// make it work for any table with field year or start year no matter the type or the table name return IndicatorFilterUtils.filteredFields[field]["result"];
//exclude indi_pub_downloads_year.year because it throws errors. when there is a solution remove the exclusion }else{
return IndicatorFilterUtils.filteredFields[field][table];
}
}
static getFilter(fieldPath: string, filterType:FilterType, value:string|string[] =null) {
let tablename = fieldPath.split(".")[0];
if ((filterType == "start_year" || filterType == "end_year") && (IndicatorFilterUtils.getFieldForTable("year",tablename))){
if (filterType == "start_year") { if (filterType == "start_year") {
return '{"groupFilters":[{"field":"' + fieldPath + '","type":">=","values":["' + ChartHelper.prefix + 'start_year' + ChartHelper.suffix + '"]}],"op":"AND"}'; return '{"groupFilters":[{"field":"' + IndicatorFilterUtils.getFieldForTable("year",tablename) + '","type":">=","values":["' + ChartHelper.prefix + 'start_year' + ChartHelper.suffix + '"]}],"op":"AND"}';
} else if (filterType == "end_year") { } else if (filterType == "end_year") {
return '{"groupFilters":[{"field":"' + fieldPath + '","type":"<=","values":["' + ChartHelper.prefix + 'end_year' + ChartHelper.suffix + '"]}],"op":"AND"}'; return '{"groupFilters":[{"field":"' + IndicatorFilterUtils.getFieldForTable("year",tablename) + '","type":"<=","values":["' + ChartHelper.prefix + 'end_year' + ChartHelper.suffix + '"]}],"op":"AND"}';
} }
} }
let table = fieldPath&&fieldPath.length > 0? fieldPath.split(".")[0]:""; if (filterType == "fundingL0" && IndicatorFilterUtils.getFieldForTable("fundingL0",tablename)) {
if(["publication", "software", "dataset", "other", "result"].indexOf(table)!=-1){ return '{"groupFilters":[{"field":"' + IndicatorFilterUtils.getFieldForTable("fundingL0",tablename) + '","type":"=","values":["' + ChartHelper.prefix + 'fundingL0' + ChartHelper.suffix + '"]}],"op":"AND"}';
return this.getResultFilter(table,filterType);
}else if (table == "project"){
return this.getProjectFilter(filterType);
}
else if (table == "country"){
return this.getCountryFilter(filterType);
}else if (table == "organization"){
return this.getOrganizationFilter(filterType);
}
return ""; }else if (filterType == "co-funded" && IndicatorFilterUtils.getFieldForTable("co-funded",tablename)) {
} return '{"groupFilters":[{"field":"' + IndicatorFilterUtils.getFieldForTable("co-funded",tablename) + '","type":">","values":["1"]}],"op":"AND"}';
static getResultFilter(table: string = null, filterType:FilterType) { }else if (filterType == "publicly-funded" && IndicatorFilterUtils.getFieldForTable("publicly-funded",tablename)) {
//works for tables ["publication", "software", "dataset", "other", "result"] return '{"groupFilters":[{"field":"' + IndicatorFilterUtils.getFieldForTable("publicly-funded",tablename) + '","type":"=","values":["' + (value=="true"?"1":"0") +'"]}],"op":"AND"}';
if (filterType == "fundingL0") { }else if (filterType == "foslvl1" && IndicatorFilterUtils.getFieldForTable("foslvl1",tablename) && value && value.length > 0) {
if(properties.useOldStatisticsSchema) { let filterString = '{"groupFilters":[' ;
return '{"groupFilters":[{"field":"' + table + '.project.funding level 0","type":"=","values":["' + ChartHelper.prefix + 'fundingL0' + ChartHelper.suffix + '"]}],"op":"AND"}'; let filters = [];
}else{//new statistcs schema for(let v of value) {
return '{"groupFilters":[{"field":"' + table + '.project funding level 0","type":"=","values":["' + ChartHelper.prefix + 'fundingL0' + ChartHelper.suffix + '"]}],"op":"AND"}'; filters.push('{"field":"' + IndicatorFilterUtils.getFieldForTable("foslvl1",tablename) + '","type":"=","values":["' + v + '"]}');
} }
}else if (filterType == "co-funded") { filterString+=filters.join(", ")
return '{"groupFilters":[{"field":"' + table + '.No of funders","type":">","values":["1"]}],"op":"AND"}'; filterString+='],"op":"OR"}'
} return filterString;
return ""; }else if (filterType == "foslvl2" && IndicatorFilterUtils.getFieldForTable("foslvl2",tablename) && value && value.length > 0) {
} let filterString = '{"groupFilters":[' ;
static getProjectFilter( filterType:FilterType) { let filters = [];
//works for table "project" for(let v of value) {
if (filterType == "fundingL0") { filters.push('{"field":"' + IndicatorFilterUtils.getFieldForTable("foslvl2",tablename) + '","type":"=","values":["' + v + '"]}');
return '{"groupFilters":[{"field":"project.funding level 0","type":"=","values":["' + ChartHelper.prefix + 'fundingL0' + ChartHelper.suffix + '"]}],"op":"AND"}'; }
} filterString+=filters.join(", ")
return ""; filterString+='],"op":"OR"}'
} return filterString;
static getOrganizationFilter( filterType:FilterType) {
//works for table "organization"
if (filterType == "fundingL0") {
return '{"groupFilters":[{"field":"organization.project.funding level 0","type":"=","values":["' + ChartHelper.prefix + 'fundingL0' + ChartHelper.suffix + '"]}],"op":"AND"}';
}
return "";
}
static getCountryFilter( filterType:FilterType) {
//works for table "country"
if (filterType == "fundingL0") {
return '{"groupFilters":[{"field":"country.organization.project.funding level 0","type":"=","values":["' + ChartHelper.prefix + 'fundingL0' + ChartHelper.suffix + '"]}],"op":"AND"}';
} }
return ""; return "";
} }
@ -297,12 +337,18 @@ export class IndicatorFilterUtils {
} }
} }
/**
* @deprecated
*
* TODO: Remove after merge with develop
* */
export enum StakeholderEntities { export enum StakeholderEntities {
STAKEHOLDER = 'Dashboard', STAKEHOLDER = 'Dashboard',
FUNDER = 'Funder', FUNDER = 'Funder',
RI = 'Research Initiative', RI = 'Research Initiative',
ORGANIZATION = 'Research Institution', ORGANIZATION = 'Research Institution',
PROJECT = 'Project', PROJECT = 'Project',
COUNTRY = 'National',
STAKEHOLDERS = 'Dashboards', STAKEHOLDERS = 'Dashboards',
FUNDERS = 'Funders', FUNDERS = 'Funders',
@ -310,10 +356,3 @@ export enum StakeholderEntities {
ORGANIZATIONS = 'Research Institutions', ORGANIZATIONS = 'Research Institutions',
PROJECTS = 'Projects' PROJECTS = 'Projects'
} }
export let stakeholderTypes: Option[] = [
{value: 'funder', label: StakeholderEntities.FUNDER},
{value: 'ri', label: StakeholderEntities.RI},
{value: 'organization', label: StakeholderEntities.ORGANIZATION},
{value: 'project', label: StakeholderEntities.PROJECT}
];

View File

@ -5,7 +5,7 @@ import {Meta, Title} from "@angular/platform-browser";
import {SEOService} from "../../sharedComponents/SEO/SEO.service"; import {SEOService} from "../../sharedComponents/SEO/SEO.service";
import {Breadcrumb} from "../../utils/breadcrumbs/breadcrumbs.component"; import {Breadcrumb} from "../../utils/breadcrumbs/breadcrumbs.component";
import {Subscriber} from "rxjs"; import {Subscriber} from "rxjs";
import {StakeholderEntities} from "../entities/stakeholder"; import {StakeholderBaseComponent} from "../../monitor-admin/utils/stakeholder-base.component";
@Component({ @Component({
selector: 'indicator-themes-page', selector: 'indicator-themes-page',
@ -30,10 +30,10 @@ import {StakeholderEntities} from "../entities/stakeholder";
This is the current set of indicator themes we cover. Well keep enriching it as new requests and data are coming into the <a href="https://graph.openaire.eu" class="text-graph" target="_blank">OpenAIRE Graph</a>. We are at your disposal, should you have any recommendations! This is the current set of indicator themes we cover. Well keep enriching it as new requests and data are coming into the <a href="https://graph.openaire.eu" class="text-graph" target="_blank">OpenAIRE Graph</a>. We are at your disposal, should you have any recommendations!
</p> </p>
<p> <p>
Check out the indicator pages (for <a [routerLink]="['../funder']" [relativeTo]="route">funders</a>, Check out the indicator pages (for <a [routerLink]="['../funder']" [relativeTo]="_route">funders</a>,
<a [routerLink]="['../organization']" [relativeTo]="route">research institutions</a> and <a [routerLink]="['../organization']" [relativeTo]="_route">research institutions</a> and
<a [routerLink]="['../ri']" [relativeTo]="route">research initiatives</a>) <a [routerLink]="['../ri']" [relativeTo]="_route">research initiatives</a>)
for the specific indicators for each type of dashboard, and the <a [routerLink]="['../../methodology']" [relativeTo]="route">methodology and terminology</a> page on how we produce the metrics. for the specific indicators for each type of dashboard, and the <a [routerLink]="['../../methodology']" [relativeTo]="_route">methodology and terminology</a> page on how we produce the metrics.
</p> </p>
</div> </div>
</div> </div>
@ -54,10 +54,10 @@ import {StakeholderEntities} from "../entities/stakeholder";
This is the current set of indicator themes we cover. Well keep enriching it as new requests and data are coming into the <a href="https://graph.openaire.eu" class="text-graph" target="_blank">OpenAIRE Graph</a>. We are at your disposal, should you have any recommendations! This is the current set of indicator themes we cover. Well keep enriching it as new requests and data are coming into the <a href="https://graph.openaire.eu" class="text-graph" target="_blank">OpenAIRE Graph</a>. We are at your disposal, should you have any recommendations!
</p> </p>
<p> <p>
Check out the indicator pages (for <a [routerLink]="['../funder']" [relativeTo]="route" class="uk-text-lowercase">{{entities.FUNDERS}}</a>, Check out the indicator pages (for <a [routerLink]="['../funder']" [relativeTo]="_route" class="uk-text-lowercase">{{entities.funders}}</a>,
<a [routerLink]="['../organization']" [relativeTo]="route" class="uk-text-lowercase">{{entities.ORGANIZATIONS}}</a> and <a [routerLink]="['../organization']" [relativeTo]="_route" class="uk-text-lowercase">{{entities.organizations}}</a> and
<a [routerLink]="['../ri']" [relativeTo]="route" class="uk-text-lowercase">{{entities.RIS}}</a>) <a [routerLink]="['../ri']" [relativeTo]="_route" class="uk-text-lowercase">{{entities.ris}}</a>)
for the specific indicators for each type of dashboard, and the <a [routerLink]="['../../methodology']" [relativeTo]="route">methodology and terminology</a> page on how we produce the metrics. for the specific indicators for each type of dashboard, and the <a [routerLink]="['../../methodology']" [relativeTo]="_route">methodology and terminology</a> page on how we produce the metrics.
</p> </p>
</div> </div>
</div> </div>
@ -65,44 +65,24 @@ import {StakeholderEntities} from "../entities/stakeholder";
</div> </div>
` `
}) })
export class IndicatorThemesComponent implements OnInit, OnDestroy { export class IndicatorThemesComponent extends StakeholderBaseComponent implements OnInit {
private subscriptions: any[] = [];
public properties = properties;
public entities = StakeholderEntities;
public breadcrumbs: Breadcrumb[] = [{name: 'home', route: '/'}, {name: 'Resources - Themes'}]; public breadcrumbs: Breadcrumb[] = [{name: 'home', route: '/'}, {name: 'Resources - Themes'}];
constructor(private router: Router, constructor(protected _router: Router,
private meta: Meta, protected _meta: Meta,
private title: Title, protected _title: Title,
private seoService: SEOService, protected seoService: SEOService,
public route: ActivatedRoute) { protected _route: ActivatedRoute) {
super();
} }
ngOnInit() { ngOnInit() {
this.subscriptions.push(this.route.params.subscribe(params => { this.subscriptions.push(this._route.params.subscribe(params => {
const description = "Monitor | Indicator Themes"; this.title = "Monitor | Indicator Themes";
const title = "Monitor | Indicator Themes"; this.description = "Monitor | Indicator Themes";
this.metaTags(title, description); this.setMetadata();
this.breadcrumbs[0].route = '/' + (params['stakeholder']?params['stakeholder']:''); this.breadcrumbs[0].route = '/' + (params['stakeholder']?params['stakeholder']:'');
this.breadcrumbs[0].name = (params['stakeholder']?'dashboard':'home'); this.breadcrumbs[0].name = (params['stakeholder']?'dashboard':'home');
})); }));
} }
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe();
}
});
}
metaTags(title, description) {
const url = properties.domain + properties.baseLink + this.router.url;
this.seoService.createLinkForCanonicalURL(url, false);
this.meta.updateTag({content: url}, "property='og:url'");
this.meta.updateTag({content: description}, "name='description'");
this.meta.updateTag({content: description}, "property='og:description'");
this.meta.updateTag({content: title}, "property='og:title'");
this.title.setTitle(title);
}
} }

View File

@ -0,0 +1,484 @@
import {ChangeDetectorRef, Directive, HostListener, OnInit, ViewRef} from "@angular/core";
import {IndicatorStakeholderBaseComponent} from "../monitor-admin/utils/stakeholder-base.component";
import {DomSanitizer} from "@angular/platform-browser";
import {
Category,
Indicator, IndicatorPath,
IndicatorSize, Overlay,
Section,
Stakeholder,
SubCategory,
Topic,
Visibility
} from "./entities/stakeholder";
import {LayoutService} from "../dashboard/sharedComponents/sidebar/layout.service";
import {ClickEvent} from "../utils/click/click-outside-or-esc.directive";
import {Session, User} from "../login/utils/helper.class";
import {Filter, Value} from "../searchPages/searchUtils/searchHelperClasses.class";
import {RangeFilter} from "../utils/rangeFilter/rangeFilterHelperClasses.class";
import {RangeFilterComponent} from "../utils/rangeFilter/rangeFilter.component";
import {Dates, StringUtils} from "../utils/string-utils.class";
import {Params} from "@angular/router";
import {StatisticsService} from "../monitor-admin/utils/services/statistics.service";
import {SearchResearchResultsService} from "../services/searchResearchResults.service";
import {CustomFilterService} from "../shared/customFilter.service";
@Directive()
export abstract class MonitorIndicatorStakeholderBaseComponent extends IndicatorStakeholderBaseComponent implements OnInit {
/** Status */
public loading: boolean = true;
public isMobile: boolean = false;
public isFullscreen: boolean = false;
/** Variables */
public user: User;
public requireLogin: boolean = true;
public view: Visibility;
public stakeholder: Stakeholder;
public activeTopic: Topic = null;
public activeCategory: Category = null;
public activeSubCategory: SubCategory = null;
public filters: Filter[] = [];
public queryParams: any = {};
public periodFilter: RangeFilter = {
title: "Time range",
filterId: "year",
originalFilterIdFrom: null,
originalFilterIdTo: null,
selectedFromValue: null,
selectedToValue: null,
selectedFromAndToValues: ""
};
rangeFilter: RangeFilterComponent;
public numberResults: Map<string, number> = new Map<string, number>();
public chartsActiveType: Map<string, IndicatorPath> = new Map<string, IndicatorPath>();
public currentYear = new Date().getFullYear();
public clipboard;
/** Services */
protected sanitizer: DomSanitizer;
protected cdr: ChangeDetectorRef;
protected layoutService: LayoutService;
protected statisticsService: StatisticsService;
protected searchResearchResultsService: SearchResearchResultsService;
protected customFilterService: CustomFilterService;
@HostListener('fullscreenchange', ['$event'])
@HostListener('webkitfullscreenchange', ['$event'])
@HostListener('mozfullscreenchange', ['$event'])
@HostListener('MSFullscreenChange', ['$event'])
screenChange() {
this.isFullscreen = !this.isFullscreen;
}
ngOnInit() {
this.layoutService.isMobile.subscribe(isMobile => {
this.isMobile = isMobile;
this.cdr.detectChanges();
});
this.createClipboard();
}
protected setView(params: Params) {
this.setSelectedFilters();
this.loading = false;
if (params['topic']) {
this.activeTopic = this.stakeholder.topics.find(topic => topic.alias === decodeURIComponent(params['topic']) && this.hasPermission(topic.visibility));
if (this.activeTopic) {
if (params['category']) {
this.activeCategory = this.activeTopic.categories.find(category =>
(category.alias === params['category']) && this.hasPermission(category.visibility));
if (!this.activeCategory) {
this.navigateToError();
return;
}
} else {
this.activeCategory = this.activeTopic.categories.find(category => this.hasPermission(category.visibility));
if (this.activeCategory) {
this.activeSubCategory = this.activeCategory.subCategories.find(subCategory =>
this.hasPermission(subCategory.visibility));
if (this.activeSubCategory) {
this.setIndicators();
}
}
return;
}
if (this.activeCategory) {
if (params['subCategory']) {
this.activeSubCategory = this.activeCategory.subCategories.find(subCategory =>
(subCategory.alias === params['subCategory'] && this.hasPermission(subCategory.visibility)));
if (!this.activeSubCategory) {
this.navigateToError();
return;
}
} else {
this.activeSubCategory = this.activeCategory.subCategories.find(subCategory =>
this.hasPermission(subCategory.visibility));
}
if (this.activeSubCategory) {
this.setIndicators();
} else {
this.navigateToError();
}
return;
} else {
this.activeSubCategory = null;
}
} else {
this.navigateToError();
return;
}
} else {
this.activeTopic = this.stakeholder.topics.find(topic => this.hasPermission(topic.visibility));
if (this.activeTopic) {
this.activeCategory = this.activeTopic.categories.find(category => this.hasPermission(category.visibility));
if (this.activeCategory) {
this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.hasPermission(subCategory.visibility));
if (this.activeSubCategory) {
this.setIndicators();
}
}
}
}
}
protected handleQueryParams(queryParams, params) {
this.queryParams = Object.assign({}, queryParams);
this.initializeFilters();
this.setView(params);
if(this.requireLogin && !this.user && (this.filters.filter(filter => this.queryParams[filter.filterId]).length > 0 || this.queryParams['year'])) {
if(queryParams['view']) {
this._router.navigate([], {queryParams: {view: queryParams['view']}});
} else {
this._router.navigate([], {queryParams: {}});
}
}
this.view = queryParams['view'];
}
protected initializeFilters() {
this.periodFilter.selectedFromValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range") == 0) ? this.queryParams['year'].split("range")[1].split(":")[0] : "";
this.periodFilter.selectedToValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range") == 0) ? this.queryParams['year'].split("range")[1].split(":")[1] : "";
this.validateYearRange(false);
for (let filter of this.filters) {
if (this.queryParams[filter.filterId]) {
for (let value of filter.values) {
if (value.id == StringUtils.URIDecode(StringUtils.unquote(this.queryParams[filter.filterId]))) {
value.selected = true;
filter.countSelectedValues = 1;
break;
}
}
} else {
this.clearFilter(filter);
}
}
}
protected validateYearRange(navigateTo: boolean = false) {
let validYears = true;
if (this.periodFilter.selectedToValue && (this.periodFilter.selectedToValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedToValue, Dates.currentYear - 20, Dates.currentYear))) {
this.periodFilter.selectedToValue = Dates.currentYear + "";
validYears = false;
}
if (this.periodFilter.selectedFromValue && (this.periodFilter.selectedFromValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedFromValue, Dates.currentYear - 20, Dates.currentYear))) {
this.periodFilter.selectedFromValue = Dates.currentYear - 20 + "";
validYears = false;
}
if (this.periodFilter.selectedFromValue && this.periodFilter.selectedFromValue.length && this.periodFilter.selectedToValue && this.periodFilter.selectedToValue.length > 0 && parseInt(this.periodFilter.selectedFromValue, 10) > parseInt(this.periodFilter.selectedToValue, 10)) {
this.periodFilter.selectedFromValue = this.periodFilter.selectedToValue;
validYears = false;
}
if (!validYears || navigateTo) {
if (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue) {
this.queryParams["year"] = 'range' + (this.periodFilter.selectedFromValue ? this.periodFilter.selectedFromValue : '') + ":" + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "");
} else {
delete this.queryParams["year"];
}
this._router.navigate([], {queryParams: this.queryParams});
this.setIndicators();
}
}
protected getFullUrl(indicatorPath: IndicatorPath) {
let fosValues = this.getSelectedFilterValues("fos");
return this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath,null, this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, false, fosValues?fosValues.lvl1:[],fosValues?fosValues.lvl2:[], this.getSelectedFilterValues("publiclyfunded"));
}
protected setIndicators() {
this.periodFilter.selectedFromAndToValues = (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue ? ((this.periodFilter.selectedFromValue && !this.periodFilter.selectedToValue ? "From " : "") + (!this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? "Until " : "") + (this.periodFilter.selectedFromValue ? this.periodFilter.selectedFromValue : "") +
(this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : "");
//clear numbers when filters change
this.numberResults.clear();
let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>();
this.activeSubCategory.numbers.forEach((section, i) => {
section.indicators.forEach((number, j) => {
if (this.hasPermission(number.visibility)) {
let url = this.getFullUrl(number.indicatorPaths[0]);
const pair = JSON.stringify([number.indicatorPaths[0].source, url]);
const indexes = urls.get(pair) ? urls.get(pair) : [];
indexes.push([i, j]);
urls.set(pair, indexes);
}
});
});
urls.forEach((indexes, pair) => {
pair = JSON.parse(pair);
let activeSubcategory = this.activeSubCategory._id;
this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => {
if(activeSubcategory === this.activeSubCategory._id) {
indexes.forEach(([i, j]) => {
if( this.activeSubCategory?.numbers[i]?.indicators[j]) {
let result = JSON.parse(JSON.stringify(response));
this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => {
if (result) {
result = result[jsonPath];
}
});
if (typeof result === 'string' || typeof result === 'number') {
result = Number(result);
if (result === Number.NaN) {
result = 0;
}
} else {
result = 0;
}
this.numberResults.set(i + '-' + j, result);
}
});
}
}));
});
this.activeSubCategory.charts.forEach((section, i) => {
section.indicators.forEach((indicator, j) => {
if (indicator.indicatorPaths.length > 0) {
indicator.indicatorPaths[0].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[0]);
this.chartsActiveType.set(i + '-' + j, indicator.indicatorPaths[0]);
}
});
});
if (this.cdr && !(this.cdr as ViewRef).destroyed) {
this.cdr.detectChanges();
}
}
public getUrlByStakeHolder(indicatorPath: IndicatorPath) {
return this.sanitizer.bypassSecurityTrustResourceUrl(
this.indicatorUtils.getChartUrl(indicatorPath.source, this.getFullUrl(indicatorPath)));
}
public setActiveChart(i: number, j: number, type: string) {
let activeChart = this.activeSubCategory.charts[i].indicators[j].indicatorPaths.filter(indicatorPath => indicatorPath.type === type)[0];
activeChart.safeResourceUrl = this.getUrlByStakeHolder(activeChart);
this.chartsActiveType.set(i + '-' + j, activeChart);
}
public filter() {
this.validateYearRange(true);
}
public filterChanged($event, navigate: boolean = true) {
let selected = [];
for (let value of $event.value.values) {
if (value.selected) {
selected.push( StringUtils.quote(StringUtils.URIEncode(value.id)));
}
}
if (selected.length > 0) {
this.queryParams[$event.value.filterId] = selected.join(",");
} else {
delete this.queryParams[$event.value.filterId];
}
if (navigate) {
this._router.navigate([], {queryParams: this.queryParams});
this.setIndicators();
}
}
public countSelectedFilters(): number {
let count = 0;
if (this.periodFilter.selectedFromAndToValues.length > 0) {
count += 1;
}
for (let filter of this.filters) {
count += filter.countSelectedValues;
}
return count;
}
public clearAll() {
for (let filter of this.filters) {
this.clearFilter(filter);
}
this.periodFilter.selectedFromValue = "";
this.periodFilter.selectedToValue = "";
this.validateYearRange(true)
}
public clearFilter(filter: Filter) {
filter.countSelectedValues = 0;
filter.radioValue = "";
for (let value of filter.values) {
if (value.selected) {
value.selected = false;
}
}
if (this.queryParams[filter.filterId]) {
delete this.queryParams[filter.filterId];
}
}
clearPeriodFilter() {
if (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue) {
this.periodFilter.selectedFromValue = "";
this.periodFilter.selectedToValue = "";
if(this.rangeFilter) {
this.rangeFilter.clearFilter();
}
this.filter();
}
}
clearFilterValue(filter: Filter, value: Value) {
value.selected = false;
filter.radioValue = '';
filter.countSelectedValues = filter.countSelectedValues - 1;
this.filterChanged({
value:filter
});
}
public hasPermission(visibility: Visibility): boolean {
if(visibility === 'PUBLIC') {
return true;
} else if(visibility === 'RESTRICTED') {
return (!this.view || this.view === 'RESTRICTED') && this.isMember(this.stakeholder);
} else {
return !this.view && this.isManager(this.stakeholder);
}
}
public isMember(stakeholder: Stakeholder) {
return this.user && (Session.isPortalAdministrator(this.user) || Session.isCurator(stakeholder.type, this.user)
|| Session.isManager(stakeholder.type, stakeholder.alias, this.user) || Session.isMember(stakeholder.type, stakeholder.alias, this.user));
}
public isManager(stakeholder: Stakeholder) {
return this.user && (Session.isPortalAdministrator(this.user) || Session.isCurator(stakeholder.type, this.user) || Session.isManager(stakeholder.type, stakeholder.alias, this.user));
}
public countSubCategoriesToShow(category: Category): number {
return category.subCategories.filter(subCategory => this.hasPermission(subCategory.visibility)).length;
}
public countSectionsWithIndicatorsToShow(sections: Section[]):number {
return sections.map(section => this.countIndicatorsToShow(section.indicators)).reduce((sum, current) => sum + current, 0);
}
public countIndicatorsToShow(indicators: Indicator[]): number {
return indicators.filter(indicator => this.hasPermission(indicator.visibility)).length;
}
public getNumberClassBySize(size: IndicatorSize) {
if (size === 'small') {
return 'uk-width-medium@m uk-width-1-1';
} else if (size === 'medium') {
return 'uk-width-1-4@l uk-width-1-2@m uk-width-1-1';
} else {
return 'uk-width-1-2@l uk-width-1-1@m uk-width-1-1';
}
}
public getChartClassBySize(size: IndicatorSize): string {
if (size === 'small') {
return 'uk-width-1-3@xl uk-width-1-2@m uk-width-1-1';
} else if (size === 'medium') {
return 'uk-width-1-2@l uk-width-1-1';
} else {
return 'uk-width-1-1';
}
}
public printReport() {
window.print();
}
changeOverlay(event, indicator: Indicator, overlay: Overlay) {
event.stopPropagation();
indicator.overlay = overlay;
}
closeOverlay(event: ClickEvent, indicator: Indicator) {
if(event.clicked && indicator.overlay) {
indicator.overlay = false;
}
}
private createClipboard() {
if (typeof window !== 'undefined') {
delete this.clipboard;
let Clipboard;
Clipboard = require('clipboard');
this.clipboard = new Clipboard('.clipboard_btn');
}
}
//Refine Type Filters
setSelectedFilters(){
for (var i = 0; i < this.filters.length; i++) {
var filter: Filter = this.filters[i];
filter.countSelectedValues = 0;
let parameterNames = Object.keys(this.queryParams);
if (parameterNames.indexOf(filter.filterId) != -1) {
let values = (decodeURIComponent(this.queryParams[filter.filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, -1);
for (let filterValue of filter.values) {
if (values.indexOf(StringUtils.quote(filterValue.id)) > -1) {
filterValue.selected = true;
filter.countSelectedValues++;
} else {
filterValue.selected = false;
}
}
} else {
for (let filterValue of filter.values) {
filterValue.selected = false;
}
}
}
}
getSelectedFilterValues(filterId){
let values = null;
for (let filter of this.filters) {
if(filterId == filter.filterId && filter.countSelectedValues > 0) {
values =filterId == "fos"?{lvl1:[],lvl2:[]}:[];
for (let filterValue of filter.values) {
if (filterValue.selected) {
if(filterId == "fos"){
let code = filterValue.id.split(" ")[0];
if(code.length == 2){
values.lvl1.push(filterValue.id)
}else{
values.lvl2.push(filterValue.id)
}
}else if(filterId == "publiclyfunded"){
// console.log("publiclyFunded", filterValue)
return filterValue.id;
}else{
values.push(filterValue.id);
}
}
}
}
}
return values;
}
}

View File

@ -1,12 +1,12 @@
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {MenuItem} from "../../sharedComponents/menu"; import {MenuItem} from "../../sharedComponents/menu";
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
import {StakeholderEntities} from "../entities/stakeholder";
import {from, Subscription} from "rxjs"; import {from, Subscription} from "rxjs";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {Page} from "../../utils/entities/adminTool/page"; import {Page} from "../../utils/entities/adminTool/page";
import {map} from "rxjs/operators"; import {map} from "rxjs/operators";
import {StakeholderConfiguration} from "../../monitor-admin/utils/indicator-utils";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -16,12 +16,7 @@ export class ResourcesService {
private subscription: Subscription; private subscription: Subscription;
private routes = ResourcesService.types.map(type => '/indicators/' + type.value); private routes = ResourcesService.types.map(type => '/indicators/' + type.value);
public static readonly types: Option[] = [ public static readonly types: Option[] = StakeholderConfiguration.TYPES;
{value: 'funder', label: StakeholderEntities.FUNDERS},
{value: 'ri', label: StakeholderEntities.RIS},
{value: 'project', label: StakeholderEntities.PROJECTS},
{value: 'organization', label: StakeholderEntities.ORGANIZATIONS}
];
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
} }

View File

@ -53,6 +53,30 @@ export class StakeholderService {
} }
return from(this.getStakeholderAsync()); return from(this.getStakeholderAsync());
} }
getResearcherStakeholder( orcid, name, results, shouldUpdate: boolean = false): Observable<Stakeholder> {
if (!this.stakeholderSubject.value || this.stakeholderSubject.value.alias !== orcid || shouldUpdate) {
this.promise = new Promise<void>((resolve, reject) => {
this.sub = this.http.get<Stakeholder>(properties.monitorServiceAPIURL + '/stakeholder/' + encodeURIComponent("researcher"), CustomOptions.registryOptions()).pipe(map(stakeholder => {
return this.formalize(this.checkIsUpload(stakeholder));
})).subscribe(stakeholder => {
stakeholder.index_id = orcid;
stakeholder.index_name = name;
stakeholder.name = name;
stakeholder.alias = orcid;
if(results <7 && stakeholder.topics[0]?.categories[0]?.subCategories[0]){
stakeholder.topics[0].categories[0].subCategories[0].charts=[]; // keep only numbers - charts wont show much anyway
}
this.stakeholderSubject.next(stakeholder);
resolve();
}, error => {
let stakeholder = new Stakeholder(null,"researcher", orcid,name,name,orcid,"PUBLIC", null, null,"");
this.stakeholderSubject.next(stakeholder);
resolve();
});
});
}
return from(this.getStakeholderAsync());
}
async getStakeholderAsync() { async getStakeholderAsync() {
if (this.promise) { if (this.promise) {

View File

@ -1,4 +1,5 @@
@import "~src/assets/openaire-theme/less/_import-variables"; @import (reference) "~src/assets/openaire-theme/less/_import-variables";
@import (optional) "~src/assets/extend-theme/less/_import-variables";
#notifications-switcher { #notifications-switcher {
top: 480px !important; top: 480px !important;

View File

@ -40,7 +40,7 @@ export class NotificationConfiguration {
<span *ngIf="mobile" class="uk-margin-right"> <span *ngIf="mobile" class="uk-margin-right">
<icon ratio="1.5" name="west" visuallyHidden="back" [flex]="true"></icon> <icon ratio="1.5" name="west" visuallyHidden="back" [flex]="true"></icon>
</span> </span>
<div class="uk-text-bold">Notifications</div> <span class="uk-text-bold">Notifications</span>
</h4> </h4>
<div class="uk-flex uk-flex-right@m uk-flex-center uk-padding uk-padding-remove-vertical"> <div class="uk-flex uk-flex-right@m uk-flex-center uk-padding uk-padding-remove-vertical">
<button [disabled]="unreadCount === 0" (click)="readAll()" class="uk-button uk-button-link">Mark As Read ({{unreadCount}})</button> <button [disabled]="unreadCount === 0" (click)="readAll()" class="uk-button uk-button-link">Mark As Read ({{unreadCount}})</button>
@ -75,7 +75,7 @@ export class NotificationConfiguration {
<span class="uk-margin-right"> <span class="uk-margin-right">
<icon ratio="1.5" name="west" visuallyHidden="back" [flex]="true"></icon> <icon ratio="1.5" name="west" visuallyHidden="back" [flex]="true"></icon>
</span> </span>
<div *ngIf="notification.title" class="uk-text-bold">{{notification.title}}</div> <span *ngIf="notification.title" class="uk-text-bold">{{notification.title}}</span>
</h4> </h4>
<div class="uk-flex uk-flex-middle uk-margin-medium-bottom"> <div class="uk-flex uk-flex-middle uk-margin-medium-bottom">
<notification-user [name]="notification.name" [surname]="notification.surname" colorClass="uk-text-secondary" [outline]="true"></notification-user> <notification-user [name]="notification.name" [surname]="notification.surname" colorClass="uk-text-secondary" [outline]="true"></notification-user>

View File

@ -7,11 +7,12 @@ import {NotificationService} from "../notification.service";
import {Notification} from "../notifications"; import {Notification} from "../notifications";
import {InputComponent, Option} from "../../sharedComponents/input/input.component"; import {InputComponent, Option} from "../../sharedComponents/input/input.component";
import {NotificationHandler} from "../../utils/notification-handler"; import {NotificationHandler} from "../../utils/notification-handler";
import {BaseComponent} from "../../sharedComponents/base/base.component";
@Component({ @Component({
selector: '[notify-form]', selector: '[notify-form]',
template: ` template: `
<form *ngIf="user && form" [formGroup]="form"> <form *ngIf="user && form && properties.notificationsAPIURL" [formGroup]="form">
<ng-template [ngIf]="form.get('notify')"> <ng-template [ngIf]="form.get('notify')">
<label><input name="notify" type="checkbox" class="uk-checkbox" formControlName="notify"><span class="uk-margin-small-left">{{label}}</span></label> <label><input name="notify" type="checkbox" class="uk-checkbox" formControlName="notify"><span class="uk-margin-small-left">{{label}}</span></label>
<div [class.uk-hidden]="!form.get('notify').value" class="uk-position-relative uk-margin-medium-top"> <div [class.uk-hidden]="!form.get('notify').value" class="uk-position-relative uk-margin-medium-top">
@ -44,7 +45,7 @@ import {NotificationHandler} from "../../utils/notification-handler";
styleUrls: ['notify-form.component.less'], styleUrls: ['notify-form.component.less'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class NotifyFormComponent implements OnInit, OnDestroy { export class NotifyFormComponent extends BaseComponent implements OnInit {
@Input() @Input()
public label: string = 'Notify Managers'; public label: string = 'Notify Managers';
public form: UntypedFormGroup; public form: UntypedFormGroup;
@ -57,13 +58,13 @@ export class NotifyFormComponent implements OnInit, OnDestroy {
public focused: boolean = false; public focused: boolean = false;
@ViewChild('recipients', { static: false }) recipients: InputComponent; @ViewChild('recipients', { static: false }) recipients: InputComponent;
private notification: Notification; private notification: Notification;
private subscriptions: any[] = [];
public sending: boolean = false; public sending: boolean = false;
constructor(private fb: UntypedFormBuilder, constructor(private fb: UntypedFormBuilder,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
private userManagementService: UserManagementService, private userManagementService: UserManagementService,
private notificationService: NotificationService) { private notificationService: NotificationService) {
super();
} }
@Input() @Input()
@ -79,14 +80,6 @@ export class NotifyFormComponent implements OnInit, OnDestroy {
})); }));
} }
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscription) {
subscription.unsubscribe();
}
})
}
reset(message: string = null) { reset(message: string = null) {
if (!this.availableGroups) { if (!this.availableGroups) {
this.form = this.fb.group({ this.form = this.fb.group({
@ -116,7 +109,7 @@ export class NotifyFormComponent implements OnInit, OnDestroy {
} }
sendNotification(notification: Notification = null) { sendNotification(notification: Notification = null) {
if (this.message) { if (this.message && this.properties.notificationsAPIURL) {
if(notification === null) { if(notification === null) {
notification = new Notification('CUSTOM', [this.service], null, null); notification = new Notification('CUSTOM', [this.service], null, null);
notification.groups = this.parseGroups(); notification.groups = this.parseGroups();
@ -162,16 +155,12 @@ export class NotifyFormComponent implements OnInit, OnDestroy {
} }
get message(): string { get message(): string {
if ((this.form.get('notify') && !this.form.get('notify').value) || (this.groupsAsFromArray && this.groupsAsFromArray.length === 0)) { if (!this.properties.notificationsAPIURL || (this.form.get('notify') && !this.form.get('notify').value) || (this.groupsAsFromArray && this.groupsAsFromArray.length === 0)) {
return null; return null;
} }
return this.form.get('message').value; return this.form.get('message').value;
} }
onFocus(event: boolean) {
this.focused = event;
}
focus(event) { focus(event) {
this.focused = true; this.focused = true;
event.stopPropagation(); event.stopPropagation();

View File

@ -32,10 +32,14 @@ declare var UIkit: any;
My ORCID links My ORCID links
</div> </div>
<span *ngIf="authorNameParam" class="uk-width-1-1 uk-width-expand@m"> <span *ngIf="authorNameParam" class="uk-width-1-1 uk-width-expand@m">
<a class="uk-button-text uk-align-left uk-align-right@m" [queryParams]="authorNameParam" <a *ngIf="!properties.orcidDiscoverLinksPage" class="uk-button uk-button-text uk-align-left uk-align-right@m" [queryParams]="authorNameParam"
[routerLink]="properties.searchLinkToAdvancedResults" routerLinkActive="router-link-active"> [routerLink]="properties.searchLinkToAdvancedResults" routerLinkActive="router-link-active">
Discover {{openaireEntities.RESULTS | lowercase}} related to you Discover {{openaireEntities.RESULTS | lowercase}} related to you
</a> </a>
<a *ngIf="properties.orcidDiscoverLinksPage" class="uk-button uk-button-text uk-align-left uk-align-right@m"
[routerLink]="properties.orcidDiscoverLinksPage" routerLinkActive="router-link-active">
Discover {{openaireEntities.RESULTS | lowercase}} related to you
</a>
</span> </span>
</div> </div>
@ -203,7 +207,7 @@ export class MyOrcidLinksComponent {
this.subscriptions.push(this._orcidService.getPersonalDetails().subscribe( this.subscriptions.push(this._orcidService.getPersonalDetails().subscribe(
details => { details => {
let author: string = ""; let author: string = "";
console.log(details)
if(details && details['name']) { if(details && details['name']) {
let name: string = details['name']; let name: string = details['name'];
if(name['given-names'] && name['given-names']['value']) { if(name['given-names'] && name['given-names']['value']) {

View File

@ -12,6 +12,8 @@ import {EnvProperties} from "../utils/properties/env-properties";
import {UserManagementService} from "../services/user-management.service"; import {UserManagementService} from "../services/user-management.service";
import {OpenaireEntities} from "../utils/properties/searchFields"; import {OpenaireEntities} from "../utils/properties/searchFields";
import {FullScreenModalComponent} from "../utils/modal/full-screen-modal/full-screen-modal.component"; import {FullScreenModalComponent} from "../utils/modal/full-screen-modal/full-screen-modal.component";
import {LogService} from "../utils/log/log.service";
import {UserProfileService} from "../services/userProfile.service";
declare var UIkit: any; declare var UIkit: any;
@ -20,88 +22,54 @@ declare var UIkit: any;
template: ` template: `
<ng-container *ngIf="pageType == 'landing' || pageType == 'search'"> <ng-container *ngIf="pageType == 'landing' || pageType == 'search'">
<span *ngIf="!putCodes || putCodes.length == 0" <span *ngIf="!putCodes || putCodes.length == 0"
(click)="currentAction='add'; saveWorkPreparation();" [ngClass]="isMobile && pageType == 'landing' ? ' uk-width-1-1' : ''"
[class.uk-disabled]="showLoading || !isLoggedIn || (!pids && (!identifiers || identifiers.size == 0))" [attr.uk-tooltip]="isMobile? 'cls: uk-invisible' : 'pos: bottom; cls: uk-active uk-text-small uk-padding-small'"
[class.clickable]="!showLoading && isLoggedIn && (pids || (identifiers && identifiers.size > 0))" [title]="(noPids || !isLoggedIn) ? ((noPids) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipAdd">
[ngClass]="isMobile && pageType == 'landing' ? ' uk-width-1-1' : ''" <span (click)="currentAction='add'; saveWorkPreparation();"
[attr.uk-tooltip]="isMobile? 'cls: uk-invisible' : 'pos: bottom; cls: uk-active uk-text-small uk-padding-small'" [class.uk-disabled]="isDisabled"
[title]="((!pids && (!identifiers || identifiers.size == 0)) || !isLoggedIn) ? ((!pids && (!identifiers || identifiers.size == 0)) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipAdd"> [class.clickable]="!isDisabled">
<a class="uk-flex uk-flex-middle uk-button-link" <a class="uk-flex uk-flex-middle uk-button-link"
[ngClass]="isMobile && !(pageType == 'landing') ? 'uk-margin-left' : ''" [ngClass]="isMobile && !(pageType == 'landing') ? 'uk-margin-left' : ''"
[class.uk-text-bolder]="!(isMobile && pageType == 'landing')" [class.uk-text-bolder]="!(isMobile && pageType == 'landing')"
[class.uk-text-muted]="showLoading || !isLoggedIn || (!pids && (!identifiers || identifiers.size == 0))" [class.uk-text-muted]="isDisabled">
(mouseover)="hoverEvent($event)" (mouseout)="hoverEvent($event)"> <icon *ngIf="!showLoading" [class.text-orcid]="properties.environment != 'beta' && !showLoading && isLoggedIn && (pids || identifiers?.size > 0)"
<icon *ngIf="!showLoading" [class.text-orcid]="!showLoading && isLoggedIn && (pids || identifiers?.size > 0)" [class.uk-text-muted]="isDisabled"
[class.uk-text-muted]="showLoading || !isLoggedIn || (!pids && (!identifiers || identifiers.size == 0))" name="orcid_add" [ratio]="(isMobile && pageType == 'search') ? 0.7 : 1" visuallyHidden="add"></icon>
name="orcid_add" [ratio]="(isMobile && pageType == 'search') ? 0.7 : 1" visuallyHidden="add"></icon> <span *ngIf="showLoading" class="uk-icon"><loading
<span *ngIf="showLoading" class="uk-icon"><loading [top_margin]="false" [size]="'small'"></loading></span>
[top_margin]="false" [size]="'small'"></loading></span> <span [ngClass]="(isMobile && pageType == 'landing') ? 'uk-margin-small-left' : 'uk-margin-xsmall-left'">Claim</span>
<span [ngClass]="(isMobile && pageType == 'landing') ? 'uk-margin-small-left' : 'uk-margin-xsmall-left'">Claim</span> </a>
</a> <div *ngIf="isMobile && pageType == 'landing'" class="uk-margin-xsmall-top uk-padding uk-padding-remove-vertical uk-text-meta uk-text-xsmall"
<div *ngIf="isMobile && pageType == 'landing'" class="uk-margin-xsmall-top uk-padding uk-padding-remove-vertical uk-text-meta uk-text-xsmall" [innerHTML]="(noPids || !isLoggedIn) ? ((noPids) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipAdd"></div>
[innerHTML]="((!pids && (!identifiers || identifiers.size == 0)) || !isLoggedIn) ? ((!pids && (!identifiers || identifiers.size == 0)) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipAdd"></div> </span>
</span> </span>
<span *ngIf="putCodes && putCodes.length > 0" <span *ngIf="putCodes && putCodes.length > 0" [ngClass]="isMobile && pageType == 'landing' ? ' uk-width-1-1' : ''"
(click)="currentAction='delete'; deleteWorks();"
[class.uk-disabled]="showLoading || !isLoggedIn || (!pids && (!identifiers || identifiers.size == 0))"
[class.clickable]="!showLoading && isLoggedIn && (pids || (identifiers && identifiers.size > 0))"
[ngClass]="isMobile && pageType == 'landing' ? ' uk-width-1-1' : ''"
[attr.uk-tooltip]="isMobile? 'cls: uk-invisible' : 'pos: bottom; cls: uk-active uk-text-small uk-padding-small'" [attr.uk-tooltip]="isMobile? 'cls: uk-invisible' : 'pos: bottom; cls: uk-active uk-text-small uk-padding-small'"
[title]="((!pids && (!identifiers || identifiers.size == 0)) || !isLoggedIn) ? ((!pids && (!identifiers || identifiers.size == 0)) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipDelete"> [title]="(noPids || !isLoggedIn) ? ((noPids) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipDelete">
<a class="uk-flex uk-flex-middle uk-button-link" <span (click)="currentAction='delete'; deleteWorks();"
[ngClass]="isMobile && !(pageType == 'landing') ? 'uk-margin-left' : ''" [class.uk-disabled]="isDisabled"
[class.uk-text-bolder]="!(isMobile && pageType == 'landing')" [class.clickable]="!isDisabled">
[class.uk-text-muted]="showLoading || !isLoggedIn || (!pids && (!identifiers || identifiers.size == 0))" <a class="uk-flex uk-flex-middle uk-button-link"
(mouseover)="hoverEvent($event, 'delete')" (mouseout)="hoverEvent($event, 'delete')"> [ngClass]="isMobile && !(pageType == 'landing') ? 'uk-margin-left' : ''"
<icon *ngIf="!showLoading" [class.text-orcid]="!showLoading && isLoggedIn && (pids || identifiers?.size > 0)" [class.uk-text-bolder]="!(isMobile && pageType == 'landing')"
[class.uk-text-muted]="showLoading || !isLoggedIn || (!pids && (!identifiers || identifiers.size == 0))" [class.uk-text-muted]="isDisabled">
name="orcid_bin" [ratio]="(isMobile && pageType == 'search') ? 0.7 : 1" visuallyHidden="delete"></icon> <icon *ngIf="!showLoading" [class.text-orcid]="!showLoading && isLoggedIn && (pids || identifiers?.size > 0)"
<span *ngIf="showLoading" class="uk-icon"><loading [class.uk-text-muted]="isDisabled"
[top_margin]="false" [size]="'small'"></loading></span> name="orcid_bin" [ratio]="(isMobile && pageType == 'search') ? 0.7 : 1" visuallyHidden="delete"></icon>
<span [ngClass]="(isMobile && pageType == 'landing') ? 'uk-margin-small-left' : 'uk-margin-xsmall-left'">Remove</span> <span *ngIf="showLoading" class="uk-icon"><loading
</a> [top_margin]="false" [size]="'small'"></loading></span>
<div *ngIf="isMobile && pageType == 'landing'" class="uk-margin-xsmall-top uk-padding uk-padding-remove-vertical uk-text-meta uk-text-xsmall" <span [ngClass]="(isMobile && pageType == 'landing') ? 'uk-margin-small-left' : 'uk-margin-xsmall-left'">Remove</span>
[innerHTML]="((!pids && (!identifiers || identifiers.size == 0)) || !isLoggedIn) ? ((!pids && (!identifiers || identifiers.size == 0)) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipDelete"></div> </a>
<div *ngIf="isMobile && pageType == 'landing'" class="uk-margin-xsmall-top uk-padding uk-padding-remove-vertical uk-text-meta uk-text-xsmall"
[innerHTML]="(noPids || !isLoggedIn) ? ((noPids) ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipDelete"></div>
</span>
</span> </span>
<!-- Old 'remove' code -->
<!-- <span *ngIf="putCodes && putCodes.length > 0"
[attr.uk-tooltip]="'pos: bottom; cls: uk-active uk-text-small uk-padding-small'"
[title]="(!pids || !isLoggedIn) ? (!pids ? tooltipNoPid : tooltipNoLoggedInUser) : tooltipDelete">
<a *ngIf="!showLoading" (click)="currentAction='delete'; deleteWorks();"
class="uk-icon-button uk-icon landing-action-button landing-action-button-orcid"
[class.uk-disabled]="showLoading || !isLoggedIn || !pids"
(mouseover)="hoverEvent($event, 'delete')" (mouseout)="hoverEvent($event, 'delete')">
<icon *ngIf="!hoverDelete" name="orcid_bin" ratio="1.1" visuallyHidden="delete"></icon>
<icon *ngIf="hoverDelete" name="delete_outline" class="uk-text-danger" visuallyHidden="delete"></icon>
</a>
<span *ngIf="showLoading" class="uk-icon icon-button uk-icon-button-small"><loading
[top_margin]="false" [size]="'small'"></loading></span>
</span> -->
</ng-container> </ng-container>
<modal-alert *ngIf="!isMobile" #grantModal [overflowBody]=false (alertOutput)="openGrantWindow()"> <modal-alert *ngIf="!isMobile" #grantModal [overflowBody]=false (alertOutput)="openGrantWindow()">
<div> <div>
<div>{{requestGrantMessage}}</div> <div>{{requestGrantMessage}}</div>
<!-- <div class="uk-margin-medium-top uk-align-right">-->
<!-- <button (click)="closeGrantModal()" type="submit"-->
<!-- class="uk-button uk-padding-small uk-padding-remove-vertical uk-button-default">-->
<!-- <span>Cancel</span>-->
<!-- </button>-->
<!-- <button (click)="openGrantWindow()" type="submit"-->
<!-- class="uk-button uk-padding-small uk-padding-remove-vertical uk-margin-left uk-button-primary">-->
<!-- <span>Grant OpenAIRE</span>-->
<!-- </button>-->
<!--&lt;!&ndash; <button (click)="openGrantWindow()" type="submit"&ndash;&gt;-->
<!--&lt;!&ndash; class="uk-button uk-padding-small uk-padding-remove-vertical uk-margin-left orcid-button">&ndash;&gt;-->
<!--&lt;!&ndash; <img src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt="">{{" "}}&ndash;&gt;-->
<!--&lt;!&ndash; <span>Create or Connect your ORCID iD</span>&ndash;&gt;-->
<!--&lt;!&ndash; </button>&ndash;&gt;-->
<!-- </div>-->
</div> </div>
</modal-alert> </modal-alert>
@ -290,18 +258,6 @@ declare var UIkit: any;
instead. instead.
</div> </div>
</div> </div>
<!-- <div class="uk-margin-medium-top uk-align-right">-->
<!-- <button (click)="closePropagationModal()" type="submit"-->
<!-- class="uk-button uk-padding-small uk-padding-remove-vertical uk-button-default">-->
<!-- <span>Cancel</span>-->
<!-- </button>-->
<!-- <button (click)="confirmedPropagation()" type="submit"-->
<!-- class="uk-button uk-padding-small uk-padding-remove-vertical uk-margin-left uk-button-primary">-->
<!-- <span>Continue</span>-->
<!-- </button>-->
<!-- </div>-->
</modal-alert> </modal-alert>
<fs-modal #propagationFsModal classTitle="uk-tile-default uk-border-bottom"> <fs-modal #propagationFsModal classTitle="uk-tile-default uk-border-bottom">
@ -364,12 +320,9 @@ export class OrcidWorkComponent {
public window: any; public window: any;
public isLoggedIn: boolean = false; public isLoggedIn: boolean = false;
public hasConsent: boolean = false;
public currentAction: string = ""; public currentAction: string = "";
public hoverAdd: boolean = false;
public hoverDelete: boolean = false;
public properties: EnvProperties = properties; public properties: EnvProperties = properties;
public openaireEntities = OpenaireEntities; public openaireEntities = OpenaireEntities;
@ -377,7 +330,7 @@ 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 userManagementService: UserManagementService, private _logService: LogService, private _userProfileService: UserProfileService) {
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
this.tokenUrl = properties.orcidTokenURL this.tokenUrl = properties.orcidTokenURL
+ "client_id=" + properties.orcidClientId + "client_id=" + properties.orcidClientId
@ -389,18 +342,27 @@ export class OrcidWorkComponent {
} }
ngOnInit() { ngOnInit() {
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { if(this.properties.environment != 'beta') {
if (user) { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.isLoggedIn = true; if (user) {
if (!this.givenPutCode) { this.isLoggedIn = true;
this.getPutCode(); if (!this.givenPutCode) {
this.getPutCode();
}
} else {
this.isLoggedIn = false;
} }
} else { }, error => {
this.isLoggedIn = false; this.isLoggedIn = false;
}));
if (properties.dashboard == 'irish') {
this.subscriptions.push(this._userProfileService.getUserProfile().subscribe(userProfile => {
this.hasConsent = userProfile.consent;
}, error => {
this.hasConsent = false;
}));
} }
}, error => { }
this.isLoggedIn = false;
}));
} }
ngOnDestroy() { ngOnDestroy() {
@ -441,7 +403,7 @@ export class OrcidWorkComponent {
} }
openGrantWindow() { openGrantWindow() {
if (!Session.isLoggedIn()) { if (!this.isLoggedIn) {
//this.userValidMessage = "User session has expired. Please login again."; //this.userValidMessage = "User session has expired. Please login again.";
this._router.navigate(['/user-info'], { this._router.navigate(['/user-info'], {
queryParams: { queryParams: {
@ -513,7 +475,7 @@ export class OrcidWorkComponent {
} }
public saveWorkPreparation() { public saveWorkPreparation() {
if (!Session.isLoggedIn()) { if (!this.isLoggedIn) {
//this.userValidMessage = "User session has expired. Please login again."; //this.userValidMessage = "User session has expired. Please login again.";
this._router.navigate(['/user-info'], { this._router.navigate(['/user-info'], {
queryParams: { queryParams: {
@ -522,7 +484,15 @@ export class OrcidWorkComponent {
} }
}); });
} else { } else {
if(properties.dashboard == 'irish' && !this.hasConsent){
this._router.navigate(['/consent'], {
queryParams: {
"errorCode": LoginErrorCodes.NOT_VALID,
"redirectUrl": this._router.url
}
});
return;
}
if (this.requestGrant) { if (this.requestGrant) {
this.openGrantModal("Add, delete or edit work in your ORCID record"); this.openGrantModal("Add, delete or edit work in your ORCID record");
} else { } else {
@ -540,7 +510,9 @@ export class OrcidWorkComponent {
private saveWork() { private saveWork() {
this.subscriptions.push(this.orcidService.saveWork(this.resultLandingInfo, this.pids).subscribe( this.subscriptions.push(this.orcidService.saveWork(this.resultLandingInfo, this.pids).subscribe(
response => { response => {
if(this.properties.logServiceUrl) {
this.subscriptions.push(this._logService.logOrcidLink(this.properties, "added", this.resultLandingInfo.title, this.resultLandingInfo.identifiers.get('doi')[0]).subscribe(res => { }));
}
// for testing only // for testing only
// this.openGrantModal("Add work in your ORCID record"); // this.openGrantModal("Add work in your ORCID record");
// this.requestGrant = true; // this.requestGrant = true;
@ -722,6 +694,9 @@ export class OrcidWorkComponent {
if (deletedPutCodes) { if (deletedPutCodes) {
for (let i = 0; i < deletedPutCodes.length; i++) { for (let i = 0; i < deletedPutCodes.length; i++) {
let deletedPutCode = deletedPutCodes[i]; let deletedPutCode = deletedPutCodes[i];
if(this.properties.logServiceUrl) {
this.subscriptions.push(this._logService.logRemoveOrcidLink(this.properties, deletedPutCode).subscribe(res => { }));
}
if (deletedPutCode == null) { if (deletedPutCode == null) {
deletedAll = false; deletedAll = false;
} else { } else {
@ -873,12 +848,17 @@ export class OrcidWorkComponent {
this.showLoading = false; this.showLoading = false;
} }
get tooltipBETA() {
// return "Login to the production environment to add works to your <span class=\"text-orcid\">ORCID</span> record";
return "Add or delete a work from your <span class=\"text-orcid\">ORCID</span> record. This feature is not available on BETA.";
}
get tooltipAdd() { get tooltipAdd() {
return "Add this work to your <span class=\"text-orcid\">ORCID</span> record" + ((properties.environment == "beta") ? ". The action will affect your real ORCID iD." : ""); return (properties.environment == "beta") ? this.tooltipBETA : ("Add this work to your <span class=\"text-orcid\">ORCID</span> record" + ((properties.environment == "test") ? ". The action will affect your real ORCID iD." : ""));
} }
get tooltipDelete() { get tooltipDelete() {
return "Delete this work from your <span class=\"text-orcid\">ORCID</span> record" + ((properties.environment == "beta") ? ". The action will affect your real ORCID iD." : ""); return "Delete this work from your <span class=\"text-orcid\">ORCID</span> record" + ((properties.environment == "test") ? ". The action will affect your real ORCID iD." : "");
} }
get tooltipNoPid() { get tooltipNoPid() {
@ -886,16 +866,14 @@ export class OrcidWorkComponent {
} }
get tooltipNoLoggedInUser() { get tooltipNoLoggedInUser() {
return "Add or delete a work from your <span class=\"text-orcid\">ORCID</span> record. Please log in first." return (properties.environment == "beta") ? this.tooltipBETA : "Add or delete a work from your <span class=\"text-orcid\">ORCID</span> record. Please log in first."
} }
hoverEvent($event, action: string = "add") { get isDisabled() {
if (action == "add") { return (this.properties.environment == 'beta' || this.showLoading || !this.isLoggedIn || (!this.pids && (!this.identifiers || this.identifiers.size == 0)));
this.hoverAdd = $event.type == "mouseover"; }
this.hoverDelete = false;
} else if (action == "delete") { get noPids() {
this.hoverDelete = $event.type == "mouseover"; return (!this.pids && (!this.identifiers || this.identifiers.size == 0));
this.hoverAdd = false;
}
} }
} }

View File

@ -16,11 +16,12 @@ import {IconsModule} from '../utils/icons/icons.module';
import {IconsService} from "../utils/icons/icons.service"; import {IconsService} from "../utils/icons/icons.service";
import {orcid_add, orcid_bin} from "../utils/icons/icons"; import {orcid_add, orcid_bin} from "../utils/icons/icons";
import {FullScreenModalModule} from "../utils/modal/full-screen-modal/full-screen-modal.module"; import {FullScreenModalModule} from "../utils/modal/full-screen-modal/full-screen-modal.module";
import {LogServiceModule} from "../utils/log/LogService.module";
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, RouterModule, AlertModalModule, LoadingModule, ResultLandingUtilsModule, CommonModule, RouterModule, AlertModalModule, LoadingModule, ResultLandingUtilsModule,
IconsModule, FullScreenModalModule IconsModule, FullScreenModalModule, LogServiceModule
], ],
declarations: [ declarations: [
OrcidComponent, OrcidComponent,

View File

@ -15,7 +15,7 @@ export class ReloadComponent {
} }
public ngOnInit() { public ngOnInit() {
let URL = Session.getReloadUrl(); let URL = Session.popReloadUrl();
if (URL && URL["path"] && URL["path"] != "") { if (URL && URL["path"] && URL["path"] != "") {
let url: string = URL["path"]; let url: string = URL["path"];
let host = URL["host"]; let host = URL["host"];
@ -24,14 +24,12 @@ export class ReloadComponent {
let baseUrl = (document && document.getElementsByTagName('base')) ? document.getElementsByTagName('base')[0].href.split(document.location.host)[1] : "/"; let baseUrl = (document && document.getElementsByTagName('base')) ? document.getElementsByTagName('base')[0].href.split(document.location.host)[1] : "/";
url = (baseUrl.length > 1 && url.indexOf(baseUrl) != -1) ? ("/" + url.split(baseUrl)[1]) : url; url = (baseUrl.length > 1 && url.indexOf(baseUrl) != -1) ? ("/" + url.split(baseUrl)[1]) : url;
if (paramsObject) { if (paramsObject) {
Session.setReloadUrl("", "", "", "");
if(URL['fragment'] && URL['fragment'] !== '') { if(URL['fragment'] && URL['fragment'] !== '') {
this._router.navigate([url], {queryParams: paramsObject, fragment: URL['fragment']}); this._router.navigate([url], {queryParams: paramsObject, fragment: URL['fragment']});
} else { } else {
this._router.navigate([url], {queryParams: paramsObject}); this._router.navigate([url], {queryParams: paramsObject});
} }
} else { } else {
Session.setReloadUrl("", "", "", "");
if(URL['fragment'] && URL['fragment'] !== '') { if(URL['fragment'] && URL['fragment'] !== '') {
this._router.navigate([url], {fragment: URL['fragment']}); this._router.navigate([url], {fragment: URL['fragment']});
} else { } else {
@ -39,12 +37,10 @@ export class ReloadComponent {
} }
} }
} else { } else {
Session.setReloadUrl("", "", "", "");
window.location.href = host + url + ((URL["params"] && URL["params"] != null) ? ((URL["params"].indexOf("?") == -1 ? "?" : "") + URL["params"]) : ""); window.location.href = host + url + ((URL["params"] && URL["params"] != null) ? ((URL["params"].indexOf("?") == -1 ? "?" : "") + URL["params"]) : "");
} }
} else { } else {
Session.setReloadUrl("", "", "", "");
this._router.navigate(['/']); this._router.navigate(['/']);
} }
} }

View File

@ -1,16 +1,17 @@
import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild} from "@angular/core"; import {AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewChild} from "@angular/core";
import {User} from "../login/utils/helper.class"; import {Role, User} from "../login/utils/helper.class";
import {ActivatedRoute, Router} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {UserManagementService} from "../services/user-management.service"; import {UserManagementService} from "../services/user-management.service";
import {UserRegistryService} from "../services/user-registry.service"; import {UserRegistryService} from "../services/user-registry.service";
import {LoginErrorCodes} from "../login/utils/guardHelper.class"; import {LoginErrorCodes} from "../login/utils/guardHelper.class";
import {Subscriber, Subscription} from "rxjs"; import {Subscription} from "rxjs";
import {UntypedFormBuilder, UntypedFormControl, Validators} from "@angular/forms"; import {UntypedFormBuilder, UntypedFormControl, Validators} from "@angular/forms";
import {AlertModal} from "../utils/modal/alert"; import {AlertModal} from "../utils/modal/alert";
import {properties} from "../../../environments/environment"; import {properties} from "../../../environments/environment";
import {EmailService} from "../utils/email/email.service"; 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";
@Component({ @Component({
selector: 'role-verification', selector: 'role-verification',
@ -77,15 +78,17 @@ import {ClearCacheService} from "../services/clear-cache.service";
</modal-alert> </modal-alert>
` `
}) })
export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewInit { export class RoleVerificationComponent extends BaseComponent implements OnInit, AfterViewInit {
@Input() @Input()
public id: string; public id: string;
@Input() @Input()
public type: string; set type(type: string) {
this._type = Role.GROUP + type;
}
@Input() @Input()
public name: string; public name: string;
@Input() @Input()
public service: "connect" | "monitor" = "monitor"; public service: "connect" | "monitor" | "irish" = "monitor";
@Input() @Input()
public userInfoLinkPrefix = ''; public userInfoLinkPrefix = '';
@Input() @Input()
@ -93,7 +96,7 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
public user: User; public user: User;
public verification: any; public verification: any;
public code: UntypedFormControl; public code: UntypedFormControl;
private subscriptions: any[] = []; private _type: string;
private paramsSubscription: Subscription; private paramsSubscription: Subscription;
@ViewChild('managerModal') managerModal: AlertModal; @ViewChild('managerModal') managerModal: AlertModal;
@ViewChild('memberModal') memberModal: AlertModal; @ViewChild('memberModal') memberModal: AlertModal;
@ -102,14 +105,15 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
public loading: boolean = false; public loading: boolean = false;
public isMember: boolean = false; public isMember: boolean = false;
constructor(private route: ActivatedRoute, constructor(protected _route: ActivatedRoute,
private router: Router, protected _router: Router,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private emailService: EmailService, private emailService: EmailService,
private userManagementService: UserManagementService, private userManagementService: UserManagementService,
private userRegistryService: UserRegistryService, private userRegistryService: UserRegistryService,
private clearCacheService: ClearCacheService, private clearCacheService: ClearCacheService,
private cdr: ChangeDetectorRef) { private cdr: ChangeDetectorRef) {
super();
} }
ngOnInit() { ngOnInit() {
@ -119,14 +123,14 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
ngAfterViewInit() { ngAfterViewInit() {
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user; this.user = user;
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'] && !this.isMember) {
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;
if (this.user.email === this.verification.email.toLowerCase() && this.id === this.verification.entity && this.type === this.verification.type) { if (this.user.email === this.verification.email.toLowerCase() && this.id === this.verification.entity && this._type === this.verification.type) {
if (this.verification.verificationType === 'manager') { if (this.verification.verificationType === 'manager') {
this.openManagerModal(); this.openManagerModal();
} else if (this.verification.verificationType === 'member') { } else if (this.verification.verificationType === 'member') {
@ -141,12 +145,12 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
this.openErrorModal(); this.openErrorModal();
})); }));
} else { } else {
this.router.navigate(['user-info'], { this._router.navigate(['user-info'], {
queryParams: { queryParams: {
'errorCode': LoginErrorCodes.NOT_LOGIN, 'errorCode': LoginErrorCodes.NOT_LOGIN,
'redirectUrl': this.router.url 'redirectUrl': this._router.url
}, },
relativeTo: this.route relativeTo: this._route
}); });
} }
} else if(this.isMember) { } else if(this.isMember) {
@ -161,14 +165,10 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
} }
ngOnDestroy() { ngOnDestroy() {
super.ngOnDestroy();
if (this.paramsSubscription instanceof Subscription) { if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe(); this.paramsSubscription.unsubscribe();
} }
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe();
}
});
} }
public openManagerModal() { public openManagerModal() {
@ -216,9 +216,12 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
if (this.paramsSubscription instanceof Subscription) { if (this.paramsSubscription instanceof Subscription) {
this.paramsSubscription.unsubscribe(); this.paramsSubscription.unsubscribe();
} }
if (this.service === "monitor") { if(this.service === "irish") {
this.loading = false; this.loading = false;
this.router.navigate(['/admin/' + this.verification.entity]); 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 { } else {
this.subscriptions.push(this.emailService.notifyManagers(this.id, 'manager', this.subscriptions.push(this.emailService.notifyManagers(this.id, 'manager',
Composer.composeEmailToInformOldManagersForTheNewOnes(this.name, this.id)).subscribe(() => { Composer.composeEmailToInformOldManagersForTheNewOnes(this.name, this.id)).subscribe(() => {
@ -275,6 +278,6 @@ export class RoleVerificationComponent implements OnInit, OnDestroy, AfterViewIn
cancel() { cancel() {
this.isMember = false; this.isMember = false;
this.router.navigate([]); this._router.navigate([]);
} }
} }

View File

@ -1,4 +1,5 @@
@import (reference) "~src/assets/openaire-theme/less/_import-variables"; @import (reference) "~src/assets/openaire-theme/less/_import-variables";
@import (optional) "~src/assets/extend-theme/less/_import-variables";
@sdgs: #E6233D, #DF9F00, #19A220, #D70023, #FF0B00, #00BFE8, #FFC300, #B10240, #FF5D00, @sdgs: #E6233D, #DF9F00, #19A220, #D70023, #FF0B00, #00BFE8, #FFC300, #B10240, #FF5D00,
#F50D86, #FF8A00, #CA8A03, #2B772B, #0098DF, #00B91C, #0069A2, #1C336A; #F50D86, #FF8A00, #CA8A03, #2B772B, #0098DF, #00B91C, #0069A2, #1C336A;

View File

@ -53,8 +53,15 @@ import {RefineFieldResultsService} from "../services/refineFieldResults.service"
export class SearchDataProvidersComponent { export class SearchDataProvidersComponent {
private errorCodes: ErrorCodes; private errorCodes: ErrorCodes;
private errorMessages: ErrorMessagesComponent; private errorMessages: ErrorMessagesComponent;
@Input() customFilter:SearchCustomFilter= null; @Input() customFilters: SearchCustomFilter[] = null;
@Input() tableViewLink; @Input()
set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) {
if(!Array.isArray(customFilter)) {
this.customFilters = customFilter?[customFilter]:null;
}else{
this.customFilters = customFilter;
}
} @Input() tableViewLink;
@Input() searchForm: SearchForm = {class: 'search-form', dark: true}; @Input() searchForm: SearchForm = {class: 'search-form', dark: true};
public results =[]; public results =[];
public filters =[]; public filters =[];
@ -159,7 +166,7 @@ export class SearchDataProvidersComponent {
this.searchPage.keywordFields = this.searchFields.DEPOSIT_DATASOURCE_KEYWORD_FIELDS; this.searchPage.keywordFields = this.searchFields.DEPOSIT_DATASOURCE_KEYWORD_FIELDS;
this.searchPage.usedBy = "deposit"; this.searchPage.usedBy = "deposit";
} }
this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, [], this.staticFields, this.fieldIdsMap,this.customFilter,params, this.entityType); this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, [],this.staticFields, this.fieldIdsMap,this.customFilters,params, this.entityType);
if(refine) { if(refine) {
this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(params), this.searchUtils.page, 0, true, this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad)); this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(params), this.searchUtils.page, 0, true, this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
} else { } else {
@ -381,7 +388,7 @@ export class SearchDataProvidersComponent {
} }
let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId); let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId);
filter.isOpen = true; filter.isViewAllOpen = true;
this.filters[index] = filter; this.filters[index] = filter;
this.cdr.detectChanges(); this.cdr.detectChanges();
}, },

View File

@ -62,8 +62,15 @@ export class SearchOrganizationsComponent {
public loadPaging: boolean = true; public loadPaging: boolean = true;
public oldTotalResults: number = 0; public oldTotalResults: number = 0;
public pagingLimit: number = 0; public pagingLimit: number = 0;
@Input() customFilter:SearchCustomFilter= null; @Input() customFilters: SearchCustomFilter[] = null;
public refineFields: string[] = this.searchFields.ORGANIZATION_REFINE_FIELDS; @Input()
set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) {
if(!Array.isArray(customFilter)) {
this.customFilters = customFilter?[customFilter]:null;
}else{
this.customFilters = customFilter;
}
} public refineFields: string[] = this.searchFields.ORGANIZATION_REFINE_FIELDS;
@ViewChild(NewSearchPageComponent, { static: true }) searchPage: NewSearchPageComponent; @ViewChild(NewSearchPageComponent, { static: true }) searchPage: NewSearchPageComponent;
@Input() simpleView: boolean = true; @Input() simpleView: boolean = true;
@Input() simpleSearchLink: string = ""; @Input() simpleSearchLink: string = "";
@ -132,7 +139,7 @@ export class SearchOrganizationsComponent {
// this.searchPage.fieldIdsMap = this.fieldIdsMap; // this.searchPage.fieldIdsMap = this.fieldIdsMap;
// this.searchPage.customFilter = this.customFilter; // this.searchPage.customFilter = this.customFilter;
// this.searchPage.getSelectedFiltersFromUrl(params); // this.searchPage.getSelectedFiltersFromUrl(params);
this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, [], [], this.fieldIdsMap,this.customFilter,params, "organization"); this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, [], [], this.fieldIdsMap,this.customFilters,params, "organization");
if(refine) { if(refine) {
this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, true, this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad)); this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, true, this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
} else { } else {
@ -340,7 +347,7 @@ export class SearchOrganizationsComponent {
} }
let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId); let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId);
filter.isOpen = true; filter.isViewAllOpen = true;
this.filters[index] = filter; this.filters[index] = filter;
this.cdr.detectChanges(); this.cdr.detectChanges();
}, },

View File

@ -46,8 +46,15 @@ import {RefineFieldResultsService} from "../services/refineFieldResults.service"
export class SearchProjectsComponent { export class SearchProjectsComponent {
private errorCodes: ErrorCodes; private errorCodes: ErrorCodes;
private errorMessages: ErrorMessagesComponent; private errorMessages: ErrorMessagesComponent;
@Input() customFilter: SearchCustomFilter = null; @Input() customFilters: SearchCustomFilter[] = null;
@Input() searchForm: SearchForm = {class: 'search-form', dark: true}; @Input()
set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) {
if(!Array.isArray(customFilter)) {
this.customFilters = customFilter?[customFilter]:null;
}else{
this.customFilters = customFilter;
}
} @Input() searchForm: SearchForm = {class: 'search-form', dark: true};
public results = []; public results = [];
public filters = []; public filters = [];
public rangeFilters: RangeFilter[] = []; public rangeFilters: RangeFilter[] = [];
@ -133,7 +140,7 @@ export class SearchProjectsComponent {
this.searchPage.fieldIds = this.fieldIds; this.searchPage.fieldIds = this.fieldIds;
this.selectedFields = []; this.selectedFields = [];
this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields, [], this.fieldIdsMap, this.customFilter, params, "project"); this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields,[], this.fieldIdsMap, this.customFilters, params, "project");
if (refine) { if (refine) {
this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params) + this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad)); this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params) + this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
} else { } else {
@ -369,7 +376,7 @@ export class SearchProjectsComponent {
} }
let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId); let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId);
filter.isOpen = true; filter.isViewAllOpen = true;
this.filters[index] = filter; this.filters[index] = filter;
this.cdr.detectChanges(); this.cdr.detectChanges();
}, },

View File

@ -19,7 +19,7 @@ import {RefineFieldResultsService} from "../services/refineFieldResults.service"
selector: 'search-research-results', selector: 'search-research-results',
template: ` template: `
<new-search-page <new-search-page
pageTitle="{{(simpleView?'':'Advanced ')}} Search for {{ getEntityName(resultType, true, true) | titlecase }}" pageTitle="{{pageTitlePrefix}}{{(simpleView?'':'Advanced ')}} Search for {{ getEntityName(resultType, true, true) | titlecase }}"
[entityType]="resultType" [entityType]="resultType"
[type]="getEntityName(resultType, true, true)" [type]="getEntityName(resultType, true, true)"
[results]="results" [results]="results"
@ -83,7 +83,15 @@ export class SearchResearchResultsComponent {
public loadPaging: boolean = true; public loadPaging: boolean = true;
public oldTotalResults: number = 0; public oldTotalResults: number = 0;
@Input() openaireLink: string = null; @Input() openaireLink: string = null;
@Input() customFilter: SearchCustomFilter = null; @Input() customFilters: SearchCustomFilter[] = null;
@Input()
set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) {
if(!Array.isArray(customFilter)) {
this.customFilters = customFilter?[customFilter]:null;
}else{
this.customFilters = customFilter;
}
}
public pagingLimit: number = 0; public pagingLimit: number = 0;
properties: EnvProperties = properties; properties: EnvProperties = properties;
public openaireEntities = OpenaireEntities; public openaireEntities = OpenaireEntities;
@ -113,7 +121,7 @@ export class SearchResearchResultsComponent {
@Input() usedBy: string = "search"; @Input() usedBy: string = "search";
@Input() orcidQuery: string = ""; @Input() orcidQuery: string = "";
@Input() identifiers: string[] = []; @Input() identifiers: string[] = [];
@Input() pageTitlePrefix: string = "";
private refineQuery: string = ""; private refineQuery: string = "";
constructor(private route: ActivatedRoute, private _router: Router, constructor(private route: ActivatedRoute, private _router: Router,
@ -183,7 +191,8 @@ export class SearchResearchResultsComponent {
this.searchUtils.sortBy = ""; this.searchUtils.sortBy = "";
} }
this.selectedFields = []; this.selectedFields = [];
this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields, this.staticFields, this.fieldIdsMap,this.customFilter,params, this.resultType, this.quickFilter);
this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields, this.staticFields, this.fieldIdsMap,this.customFilters,params, this.resultType, this.quickFilter);
if(refine) { if(refine) {
this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad)); this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
} else { } else {
@ -309,7 +318,14 @@ export class SearchResearchResultsComponent {
} }
if (refine) { if (refine) {
this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults); let refineFilters = this.searchPage.prepareFiltersToShow(filters, totalResults);
// for(let filter of refineFilters) {
// let index = this.filters.findIndex(oldFilter => oldFilter.filterId == filter.filterId);
// if(index != -1 && this.filters[index].isOpen) {
// filter.isOpen = true;
// }
// }
this.filters = refineFilters;
this.rangeFilters = this.searchPage.prepareRangeFiltersToShow(); this.rangeFilters = this.searchPage.prepareRangeFiltersToShow();
this.staticFilters = this.searchPage.prepareStaticFiltersToShow(); this.staticFilters = this.searchPage.prepareStaticFiltersToShow();
@ -319,9 +335,14 @@ export class SearchResearchResultsComponent {
if (group.type == "refine") { if (group.type == "refine") {
let groupedFilters = {title: group.title, values: []}; let groupedFilters = {title: group.title, values: []};
for (let field of group.values) { for (let field of group.values) {
let index = this.filters.findIndex(filter => filter.filterId == field); let index = this.staticFilters.findIndex(filter => filter.filterId == field);
if (index > -1) { if (index > -1) {
groupedFilters.values.push(this.filters[index]); groupedFilters.values.push(this.staticFilters[index]);
} else {
index = this.filters.findIndex(filter => filter.filterId == field);
if (index > -1) {
groupedFilters.values.push(this.filters[index]);
}
} }
} }
if (groupedFilters.values.length > 0) { if (groupedFilters.values.length > 0) {
@ -526,7 +547,7 @@ export class SearchResearchResultsComponent {
} }
let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId); let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId);
filter.isOpen = true; filter.isViewAllOpen = true;
filter.countSelectedValues = oldFilter.countSelectedValues; filter.countSelectedValues = oldFilter.countSelectedValues;
filter.radioValue = oldFilter.radioValue; filter.radioValue = oldFilter.radioValue;
this.filters[index] = filter; this.filters[index] = filter;

View File

@ -106,7 +106,8 @@ export class EntitiesSelectionComponent {
})); }));
} else if ((this.customFilter && this.customFilter.queryFieldName == "community") || } else if ((this.customFilter && this.customFilter.queryFieldName == "community") ||
(this.customFilter && (this.customFilter.queryFieldName == "relfunder" || this.customFilter.queryFieldName == "funder")) || (this.customFilter && (this.customFilter.queryFieldName == "relfunder" || this.customFilter.queryFieldName == "funder")) ||
(this.customFilter && this.customFilter.queryFieldName == "relorganizationid")) { (this.customFilter && this.customFilter.queryFieldName == "relorganizationid")
|| this.properties.dashboard == "irish") {
this.entities.push({label: OpenaireEntities.RESULTS, value: 'result'}); this.entities.push({label: OpenaireEntities.RESULTS, value: 'result'});
this.entities.push({label: OpenaireEntities.PROJECTS, value: 'project'}); this.entities.push({label: OpenaireEntities.PROJECTS, value: 'project'});
this.entities.push({label: OpenaireEntities.ORGANIZATIONS, value: 'organization'}); this.entities.push({label: OpenaireEntities.ORGANIZATIONS, value: 'organization'});

View File

@ -4,15 +4,15 @@
<div [class.uk-invisible]="list.children.length === 0" class="uk-position-relative"> <div [class.uk-invisible]="list.children.length === 0" class="uk-position-relative">
<div class="uk-slider-container"> <div class="uk-slider-container">
<ul #list class="uk-slider-items uk-grid uk-grid-small uk-margin-small-right uk-flex-nowrap" style="padding-bottom: 1px"> <ul #list class="uk-slider-items uk-grid uk-grid-small uk-margin-small-right uk-flex-nowrap" style="padding-bottom: 1px">
<ng-container *ngIf="customFilter && ((customFilterEnabled && <ng-container *ngFor="let customFilter of customFilters">
refineFields.indexOf(customFilter.queryFieldName) == <ng-container *ngIf="customFilter.isHiddenFilter">
-1) ||customFilter.isHiddenFilter)">
<li class="uk-flex uk-flex-middle"> <li class="uk-flex uk-flex-middle">
<span class="uk-label uk-label-secondary uk-text-truncate"> <span class="uk-label uk-label-secondary uk-text-truncate">
{{customFilter.valueName}} {{customFilter.valueName}}
</span> </span>
</li> </li>
</ng-container> </ng-container>
</ng-container>
<ng-container *ngIf="resultTypes && resultTypes.countSelectedValues > 0"> <ng-container *ngIf="resultTypes && resultTypes.countSelectedValues > 0">
<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">
@ -49,9 +49,13 @@
<span class="uk-label uk-label-primary uk-flex uk-flex-middle"> <span class="uk-label uk-label-primary uk-flex uk-flex-middle">
<span <span
class="uk-margin-small-right uk-width-expand uk-text-truncate"> class="uk-margin-small-right uk-width-expand uk-text-truncate">
<span *ngIf="filter.type && filter.type == 'boolean' else noboolean">{{filter.title}}: <ng-container *ngIf="filter.type && (filter.type == 'boolean' || filter.type == 'triplet') else noboolean">
{{value.name=='true'?'Yes':'No'}} <!-- *ngIf="filter.type == 'boolean'"-->
</span> <span>{{filter.title}}:
{{(value.name=='true'||value.name=='Yes')?'Yes':'No'}}
</span>
<!-- <span *ngIf="filter.type == 'triplet'">{{value.name=='true'?'':'Not '}}{{filter.title}}</span>-->
</ng-container>
<ng-template #noboolean> <ng-template #noboolean>
{{value.name}} {{value.name}}
</ng-template></span> </ng-template></span>
@ -66,14 +70,16 @@
<ng-container *ngFor="let filter of filters "> <ng-container *ngFor="let filter of filters ">
<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="!customFilter || (customFilter.isHiddenFilter && customFilter.valueId != value.id)" <li *ngIf="!customFilters || (customFilters[0].isHiddenFilter && customFilters[0].valueId != value.id)"
class=""> class="">
<span class="uk-label uk-label-primary uk-flex uk-flex-middle"> <span class="uk-label uk-label-primary uk-flex uk-flex-middle">
<span <span
class="uk-margin-small-right uk-width-expand uk-text-truncate"> class="uk-margin-small-right uk-width-expand uk-text-truncate">
<span *ngIf="filter.type && filter.type == 'boolean' else noboolean">{{filter.title}}: <ng-container *ngIf="filter.type && (filter.type == 'boolean' || filter.type == 'triplet') else noboolean">
{{value.name=='true'?'Yes':'No'}} <span>{{filter.title}}:
</span> {{(value.name=='true'||value.name=='Yes')?'Yes':'No'}}
</span>
</ng-container>
<ng-template #noboolean> <ng-template #noboolean>
{{value.name}} {{value.name}}
</ng-template></span> </ng-template></span>
@ -94,13 +100,13 @@
</h1> </h1>
</ng-template> </ng-template>
<ng-template #search_filter let-filter="filter" let-showResultCount="showResultCount"> <ng-template #search_filter let-filter="filter" let-showResultCount="showResultCount" let-grouped="grouped">
<search-filter [filterValuesNum]="filterValuesNum" [showMoreInline]="showMoreFilterValuesInline" <search-filter [filterValuesNum]="filterValuesNum" [showMoreInline]="showMoreFilterValuesInline"
[isDisabled]="disabled" [isDisabled]="disabled"
[filter]="filter" [showResultCount]=showResultCount [filter]="filter" [showResultCount]=showResultCount
(onFilterChange)="filterChanged($event)" (onFilterChange)="filterChanged($event)"
(onFilterToggle)="filterToggled($event)" (onFilterToggle)="filterToggled($event)"
[actionRoute]="true"></search-filter> [actionRoute]="true" [grouped]="grouped"></search-filter>
</ng-template> </ng-template>
<ng-template #filters_column> <ng-template #filters_column>
@ -125,15 +131,15 @@
<ul *ngIf="!showUnknownFilters" class="uk-list uk-list-xlarge"> <ul *ngIf="!showUnknownFilters" class="uk-list uk-list-xlarge">
<ng-container *ngIf="orderedFilters && orderedFilters.length > 0"> <ng-container *ngIf="orderedFilters && orderedFilters.length > 0">
<ng-container *ngFor="let group of orderedFilters"> <ng-container *ngFor="let group of orderedFilters">
<h5 *ngIf="group.title" class="uk-h5">{{group.title}}</h5> <h6 *ngIf="group.title" class="uk-h6">{{group.title}}</h6>
<ng-container *ngFor="let filter of group.values"> <ng-container *ngFor="let filter of group.values; let i=index">
<li *ngIf="filter.originalFilterIdFrom && filter.originalFilterIdTo; else refineBlock"> <li *ngIf="filter.originalFilterIdFrom && filter.originalFilterIdTo; else refineBlock">
<range-filter [isDisabled]="disabled" [filter]="filter" <range-filter [isDisabled]="disabled" [filter]="filter"
(onFilterChange)="filterChanged($event)" [actionRoute]="true"></range-filter> (onFilterChange)="filterChanged($event)" [actionRoute]="true"></range-filter>
</li> </li>
<ng-template #refineBlock> <ng-template #refineBlock>
<li *ngIf="filter.values && filter.values.length > 0"> <li *ngIf="filter.values && filter.values.length > 0" [ngClass]="group.title && i==0 ? 'uk-margin-small-top' : ''">
<ng-container *ngTemplateOutlet="search_filter; context: {filter: filter, showResultCount: filter.type!='static'}"></ng-container> <ng-container *ngTemplateOutlet="search_filter; context: {filter: filter, showResultCount: filter.type!='static', grouped: !!group.title}"></ng-container>
</li> </li>
</ng-template> </ng-template>
</ng-container> </ng-container>
@ -222,12 +228,13 @@
</div> </div>
<!-- TODO - Clean up --> <!-- TODO - Clean up -->
<div *ngIf="!includeOnlyResultsAndFilter" [class]="usedBy != 'deposit' && usedBy != 'orcid' && (!customFilter || customFilter.queryFieldName != 'communityId') ? <div *ngIf="!includeOnlyResultsAndFilter" [class]="usedBy != 'deposit' && usedBy != 'orcid' &&
(!customFilters || (customFilters && customFilters[0].queryFieldName != 'communityId')) ?
(stickyForm?'':' ') : (stickyForm?'':' ') :
(+ (stickyForm?'':' uk-section') +' uk-padding-remove-bottom uk-padding-remove-top ' + (+ (stickyForm?'':' uk-section') +' uk-padding-remove-bottom uk-padding-remove-top ' +
((usedBy == 'deposit' || usedBy == 'orcid') ? ' uk-padding-remove-top ' : ' '))" ((usedBy == 'deposit' || usedBy == 'orcid') ? ' uk-padding-remove-top ' : ' '))"
[attr.uk-sticky]="((stickyForm || (simpleView && mobile))?'{offset:100;start:90;cls-active:uk-active uk-sticky-below;cls-inactive:uk-sticky '+ [attr.uk-sticky]="((stickyForm || (simpleView && mobile))?'{offset:100;start:90;cls-active:uk-active uk-sticky-below;cls-inactive:uk-sticky '+
(usedBy != 'deposit' && usedBy != 'orcid' && (!customFilter || customFilter.queryFieldName != 'communityId') ? (usedBy != 'deposit' && usedBy != 'orcid' && (!customFilters || customFilters[0].queryFieldName != 'communityId') ?
' uk-position-relative ' :(' uk-section ' ))+'}':null)"> ' uk-position-relative ' :(' uk-section ' ))+'}':null)">
<div class="uk-background-norepeat uk-background-bottom-center" [ngClass]="searchForm.class"> <div class="uk-background-norepeat uk-background-bottom-center" [ngClass]="searchForm.class">
<div class="uk-width-1-1"> <div class="uk-width-1-1">
@ -254,7 +261,7 @@
[advancedSearchLinkParameters]="this.routerHelper.createQueryParams(this.parameterNames, this.parameterValues)" [advancedSearchLinkParameters]="this.routerHelper.createQueryParams(this.parameterNames, this.parameterValues)"
[simpleView]="simpleView" [formPlaceholderText]="formPlaceholderText" [isMobile]="mobile" [simpleView]="simpleView" [formPlaceholderText]="formPlaceholderText" [isMobile]="mobile"
[resultTypes]="resultTypes" [quickFilter]="quickFilter" [entitiesSelection]="entitiesSelection" [resultTypes]="resultTypes" [quickFilter]="quickFilter" [entitiesSelection]="entitiesSelection"
[showSwitchSearchLink]="showSwitchSearchLink" [customFilter]="customFilter" [showSwitchSearchLink]="showSwitchSearchLink" [customFilter]="customFilters?customFilters[0]:null"
> >
</advanced-search-form> </advanced-search-form>
</div> </div>
@ -317,18 +324,13 @@
</div> </div>
<div class="uk-width-expand@m uk-with-1-1@s"> <div class="uk-width-expand@m uk-with-1-1@s">
<div [class.uk-padding-small]="mobile" class="uk-padding-remove-vertical"> <div [class.uk-padding-small]="mobile" class="uk-padding-remove-vertical">
<!-- Results only for Custom Filter? -->
<div *ngIf="customFilter && !customFilter.isHiddenFilter &&
customFilter.selected == false && customFilter.promptToAddFilter"
class="uk-alert uk-animation-slide-top-small">
Do you want to see results only for {{customFilter.valueName}}? <a
(click)="addCustomFilter();">Click here</a>.
</div>
<!-- Related results for Custom Filter Alert --> <!-- Related results for Custom Filter Alert -->
<div *ngIf="openaireLink && (searchUtils.totalResults > 0 || !loadPaging )" <div *ngIf="openaireLink && (searchUtils.totalResults > 0 || !loadPaging )"
class="uk-alert uk-margin-small-top "> class="uk-alert uk-margin-small-top ">
<span *ngIf="customFilter">The following results are related to <span class="uk-text-primary uk-text-bold" <ng-container *ngFor="let customFilter of customFilters">
<span *ngIf="customFilter.showFilterMessage">The following results are related to <span class="uk-text-primary uk-text-bold"
>{{customFilter.valueName}}</span>.</span> >{{customFilter.valueName}}</span>.</span>
</ng-container>
Are you interested to view more results? Visit Are you interested to view more results? Visit
<a <a
class="uk-margin-top uk-link" class="uk-margin-top uk-link"
@ -338,7 +340,7 @@
<div class="uk-flex uk-flex-middle uk-flex-wrap uk-child-width-1-1 uk-child-width-auto@m" [class.uk-flex-between]="!mobile" <div class="uk-flex uk-flex-middle uk-flex-wrap uk-child-width-1-1 uk-child-width-auto@m" [class.uk-flex-between]="!mobile"
[class.uk-margin-top]="mobile"> [class.uk-margin-top]="mobile">
<!-- Total results, number of pages --> <!-- Total results, number of pages -->
<div class="uk-width-xlarge@m uk-margin-remove-bottom uk-text-truncate uk-margin-medium-right" [class.uk-h6]="!mobile" [class.uk-text-center]="mobile"> <div class="uk-width-expand@m uk-margin-remove-bottom uk-text-truncate" [class.uk-margin-medium-right]="!mobile" [class.uk-h6]="!mobile" [class.uk-text-center]="mobile">
<ng-container *ngIf="results && searchUtils.totalResults > 0"> <ng-container *ngIf="results && searchUtils.totalResults > 0">
<span>{{searchUtils.totalResults|number}}</span> <span>{{searchUtils.totalResults|number}}</span>
<span class="uk-text-meta uk-text-capitalize"> {{type}}</span> <span class="uk-text-meta uk-text-capitalize"> {{type}}</span>
@ -365,6 +367,11 @@
[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'">
<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>
</a>
</ng-container>
</div> </div>
</div> </div>
<div *ngIf="(searchUtils.status !== errorCodes.LOADING || !loadPaging) && !mobile" class="uk-margin-top"> <div *ngIf="(searchUtils.status !== errorCodes.LOADING || !loadPaging) && !mobile" class="uk-margin-top">
@ -444,4 +451,3 @@
<div *ngIf="isMobile || isServer" class="uk-hidden@m"> <div *ngIf="isMobile || isServer" class="uk-hidden@m">
<ng-container *ngTemplateOutlet="main; context: {mobile: true}"></ng-container> <ng-container *ngTemplateOutlet="main; context: {mobile: true}"></ng-container>
</div> </div>
<modal-alert #removeCustomFilter (alertOutput)="closeCustomFilterModal()"></modal-alert>

View File

@ -69,7 +69,15 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
@Input() loadPaging: boolean = true; @Input() loadPaging: boolean = true;
@Input() oldTotalResults: number = 0; @Input() oldTotalResults: number = 0;
@Input() openaireLink: string; @Input() openaireLink: string;
@Input() customFilter: SearchCustomFilter; @Input() customFilters: SearchCustomFilter[] = null;
@Input()
set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) {
if(!Array.isArray(customFilter)) {
this.customFilters = customFilter?[customFilter]:null;
}else{
this.customFilters = customFilter;
}
}
@Input() sort: boolean = true; @Input() sort: boolean = true;
@Input() sortedByChanged: string = ""; @Input() sortedByChanged: string = "";
@Input() searchForm: SearchForm = {class: 'search-form', dark: true}; @Input() searchForm: SearchForm = {class: 'search-form', dark: true};
@ -144,11 +152,9 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
//Dashboard //Dashboard
filterToggle = false; filterToggle = false;
customFilterEnabled: boolean = false;
//stickyform //stickyform
@Input() stickyForm: boolean = false; @Input() stickyForm: boolean = false;
@ViewChild('removeCustomFilter') removeCustomFilter: AlertModal;
currentValueToRemove; currentValueToRemove;
currentFilterToRemove; currentFilterToRemove;
public indexUpdateDate: Date; public indexUpdateDate: Date;
@ -195,7 +201,6 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
if (params['page'] && params['page'] != 1) { if (params['page'] && params['page'] != 1) {
HelperFunctions.scrollToId("searchForm"); HelperFunctions.scrollToId("searchForm");
} }
this.customFilterEnabled = params['cf'] && params['cf'] == "true";
if (this.basicMetaDescription.length == 0) { if (this.basicMetaDescription.length == 0) {
if (this.entityType == "result") { if (this.entityType == "result") {
this.basicMetaDescription = [OpenaireEntities.RESULTS, "Discover" + (this.properties.adminToolsCommunity == 'openaire' ? " over 100 million of" : "") + " "+OpenaireEntities.RESULTS+" ", "categorized by research type, year range, funder, languages, "+OpenaireEntities.COMMUNITY+" and "+OpenaireEntities.DATASOURCES+"."]; this.basicMetaDescription = [OpenaireEntities.RESULTS, "Discover" + (this.properties.adminToolsCommunity == 'openaire' ? " over 100 million of" : "") + " "+OpenaireEntities.RESULTS+" ", "categorized by research type, year range, funder, languages, "+OpenaireEntities.COMMUNITY+" and "+OpenaireEntities.DATASOURCES+"."];
@ -229,14 +234,14 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
} }
private getPageContents() { private getPageContents() {
this.subscriptions.push(this.helper.getPageHelpContents(this.properties, (this.customFilter && this.customFilter.queryFieldName == "communityId") ? this.customFilter.valueId : this.properties.adminToolsCommunity, this.router.url).subscribe(contents => { this.subscriptions.push(this.helper.getPageHelpContents(this.properties, (this.customFilters && this.customFilters[0] && this.customFilters[0].queryFieldName == "communityId") ? this.customFilters[0].valueId : this.properties.adminToolsCommunity, this.router.url).subscribe(contents => {
this.pageContents = contents; this.pageContents = contents;
})); }));
} }
private getDivContents() { private getDivContents() {
this.subscriptions.push(this.helper.getDivHelpContents(this.properties, (this.customFilter && this.customFilter.queryFieldName == "communityId") ? this.customFilter.valueId : this.properties.adminToolsCommunity, this.router.url).subscribe(contents => { this.subscriptions.push(this.helper.getDivHelpContents(this.properties, (this.customFilters && this.customFilters[0] && this.customFilters[0].queryFieldName == "communityId") ? this.customFilters[0].valueId : this.properties.adminToolsCommunity, this.router.url).subscribe(contents => {
this.divContents = contents; this.divContents = contents;
})); }));
} }
@ -422,13 +427,19 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
/* /*
* Get A sub-array of this.refineFields array, which contains the ids of the selected filters * Get A sub-array of this.refineFields array, which contains the ids of the selected filters
*/ */
public getSelectedFilters(): string[] { public getSelectedFilters(): Map<string, string[]> {
var selected: string[] = []; var selected: Map<string, string[]> = new Map<string, string[]>();
var filters = this.URLCreatedFilters; var filters = this.URLCreatedFilters;
for (var i = 0; i < filters.length; i++) { for (var i = 0; i < filters.length; i++) {
var filter: Filter = filters[i]; var filter: Filter = filters[i];
if (filter.countSelectedValues > 0) { if (filter.countSelectedValues > 0) {
selected.push(filter.filterId); let selectedValues: string[] = [];
for(let value of filter.values) {
if(value.selected) {
selectedValues.push(value.id);
}
}
selected.set(filter.filterId, selectedValues);
} }
} }
return selected; return selected;
@ -437,11 +448,63 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
/* /*
* Get A sub-array of this.refineFields array, which contains the ids of the selected parameters * Get A sub-array of this.refineFields array, which contains the ids of the selected parameters
*/ */
private getSelectedParameters(): string[] { private getSelectedParameters(): Map<string, string[]> {
var selected: string[] = []; var selected: Map<string, string[]> = new Map<string, string[]>();
for (var i = 0; i < this.refineFields.length; i++) { for (var i = 0; i < this.refineFields.length; i++) {
if (this.parameterNames.indexOf(this.refineFields[i]) != -1) { let selectedValues: string[] = [];
selected.push(this.refineFields[i]); let index = this.parameterNames.indexOf(this.refineFields[i]);
if (index != -1) {
for(let values of this.parameterValues[index]) {
let split = values.split('"');
for(let value of split) {
if(value != "" && value != ",") {
selectedValues.push(value);
}
}
}
selected.set(this.refineFields[i], selectedValues);
}
}
return selected;
}
/*
* Get A sub-array of this.staticFields array, which contains the ids of the selected filters
*/
public getSelectedStaticFilters(): Map<string, string[]> {
var selected: Map<string, string[]> = new Map<string, string[]>();
var filters = this.URLCreatedStaticFilters;
for (var i = 0; i < filters.length; i++) {
var filter: Filter = filters[i];
if (filter.countSelectedValues > 0) {
let selectedValues: string[] = [];
for(let value of filter.values) {
if(value.selected) {
selectedValues.push(value.id);
}
}
selected.set(filter.filterId, selectedValues);
}
}
return selected;
}
/*
* Get A sub-array of this.staticFields array, which contains the ids of the selected parameters
*/
private getSelectedStaticParameters(): Map<string, string[]> {
var selected: Map<string, string[]> = new Map<string, string[]>();
for (var i = 0; i < this.staticFields.length; i++) {
let selectedValues: string[] = [];
let index = this.parameterNames.indexOf(this.staticFields[i]);
if (index != -1) {
let split = this.parameterValues[index].split('"');
for(let value of split) {
if(value != "" && value != ",") {
selectedValues.push(value);
}
}
selected.set(this.staticFields[i], selectedValues);
} }
} }
return selected; return selected;
@ -451,17 +514,30 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
* Get A sub-array of this.refineFields array, which hides hidden fields (e.g Funding level 0,1,2,..), and contains those that depend on another fields (e.g Funding level 0 if Funder is selected ) * Get A sub-array of this.refineFields array, which hides hidden fields (e.g Funding level 0,1,2,..), and contains those that depend on another fields (e.g Funding level 0 if Funder is selected )
*/ */
public getFields(): string[] { public getFields(): string[] {
var selected_filters: string[] = this.getSelectedFilters(); var selected_filters: Map<string, string[]> = this.getSelectedFilters();
if (selected_filters.length == 0) { if (selected_filters.size == 0) {
selected_filters = this.getSelectedParameters(); selected_filters = this.getSelectedParameters();
} }
var selected_static_filters: Map<string, string[]> = this.getSelectedStaticFilters();
if (selected_static_filters.size == 0) {
selected_static_filters = this.getSelectedStaticParameters();
}
let all_selected_filters = new Map([...selected_filters, ...selected_static_filters]);
// let all_selected_filters = selected_filters.concat(selected_static_filters);
var fields: string[] = []; var fields: string[] = [];
for (var i = 0; i < this.refineFields.length; i++) { for (var i = 0; i < this.refineFields.length; i++) {
var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]]; var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.refineFields[i]];
var dependentToValues = this.searchFieldsHelper.DEPENDENT_FIELDS_AND_VALUES[this.refineFields[i]];
// TODO check again the checks // TODO check again the checks
//if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected //if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
if (this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1 if (this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.refineFields[i]) == -1
|| (selected_filters.indexOf(dependentTo) != -1) || (selected_filters.indexOf(this.refineFields[i]) != -1) || (all_selected_filters.has(this.refineFields[i]))
|| (!dependentTo && !dependentToValues)
|| (all_selected_filters.has(dependentTo))
|| (dependentToValues && (all_selected_filters.has(dependentToValues.field) && dependentToValues.values.some(dependentValue=> all_selected_filters.get(dependentToValues.field).includes(dependentValue))))
|| (this.resultTypes && this.resultTypes.filterId == dependentTo && this.resultTypes.countSelectedValues > 0) || (this.resultTypes && this.resultTypes.filterId == dependentTo && this.resultTypes.countSelectedValues > 0)
// || (this.resultAccesses && this.resultAccesses.filterId == dependentTo && this.resultAccesses.countSelectedValues > 0) // || (this.resultAccesses && this.resultAccesses.filterId == dependentTo && this.resultAccesses.countSelectedValues > 0)
) { ) {
@ -490,8 +566,12 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
*/ */
public checkSelectedFilters(filters: Filter[]) { public checkSelectedFilters(filters: Filter[]) {
this.filters = filters; this.filters = filters;
if (this.customFilter && !this.customFilter.isHiddenFilter) { if (this.customFilters) {
this.customFilter.selected = null; for (let customFilter of this.customFilters) {
if (!customFilter.isHiddenFilter) {
customFilter.selected = null;
}
}
} }
for (var i = 0; i < filters.length; i++) { for (var i = 0; i < filters.length; i++) {
var filter: Filter = filters[i]; var filter: Filter = filters[i];
@ -507,8 +587,10 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
} }
} }
if (this.customFilter) { if (this.customFilters) {
this.customFilter.selected = this.customFilter.queryFieldName == filter.filterId && values.indexOf(StringUtils.quote(this.customFilter.valueId)) != -1; for (let customFilter of this.customFilters) {
customFilter.selected = customFilter.queryFieldName == filter.filterId && values.indexOf(StringUtils.quote(customFilter.valueId)) != -1;
}
} }
// } else if (this.quickFilter && this.quickFilter.filterId == filter.filterId && this.quickFilter.selected) { // } else if (this.quickFilter && this.quickFilter.filterId == filter.filterId && this.quickFilter.selected) {
// for (let filterValue of filter.values) { // for (let filterValue of filter.values) {
@ -528,11 +610,6 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
// this.quickFilter.filter = filter; // this.quickFilter.filter = filter;
// } // }
} }
if (this.parameterNames.indexOf("cf") != -1 && this.parameterValues[this.parameterNames.indexOf("cf")] == "true") {
this.customFilter.selected = true;
} else if (this.customFilter && this.customFilter.selected == null) {
this.customFilter.selected = false;
}
this.filterFilterValues(this.filters); this.filterFilterValues(this.filters);
if (!this.includeOnlyResultsAndFilter) { if (!this.includeOnlyResultsAndFilter) {
this.updateMeta(this.pageTitle); this.updateMeta(this.pageTitle);
@ -720,10 +797,6 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
public removeFilter(value: Value, filter: Filter, forceRemove: boolean = false) { public removeFilter(value: Value, filter: Filter, forceRemove: boolean = false) {
this.currentValueToRemove = value; this.currentValueToRemove = value;
this.currentFilterToRemove = filter; this.currentFilterToRemove = filter;
if (!forceRemove && this.customFilter && this.customFilter.queryFieldName == filter.filterId && this.customFilter.valueId == value.id && this.customFilter.promptToAddFilter) {
this.openRemoveCustomFilterModal();
return;
}
filter.countSelectedValues--; filter.countSelectedValues--;
this.selectedFilters--; this.selectedFilters--;
if (value.selected == true) { if (value.selected == true) {
@ -738,19 +811,6 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
this.goTo(1); this.goTo(1);
} }
public openRemoveCustomFilterModal() {
this.removeCustomFilter.alertTitle = 'Remove filter';
this.removeCustomFilter.message = 'You are about to see results that are not related to ' + this.customFilter.valueName + '. Do you want to proceed?';
this.removeCustomFilter.okButtonText = 'Yes';
this.removeCustomFilter.cancelButtonText = 'No';
this.removeCustomFilter.open();
}
closeCustomFilterModal() {
this.customFilterEnabled = false;
this.removeFilter(this.currentValueToRemove, this.currentFilterToRemove, true);
}
public removeRangeFilter(filter: RangeFilter) { public removeRangeFilter(filter: RangeFilter) {
filter.selectedFromValue = null; filter.selectedFromValue = null;
filter.selectedToValue = null; filter.selectedToValue = null;
@ -798,41 +858,6 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
} }
}*/ }*/
/**
* Set selected the value of the custom filter.
*/
addCustomFilter() {
this.customFilter.selected = true;
this.customFilterEnabled = true;
if (this.refineFields.indexOf(this.customFilter.queryFieldName) != -1) {
let found = false;
for (let filter of this.filters) {
if (this.customFilter.queryFieldName == filter.filterId) {
for (let value of filter.values) {
if (value.id == this.customFilter.valueId) {
value.selected = true;
filter.countSelectedValues++;
found = true;
break;
}
}
//add filter when field exist in refine but not in the refine values
if (!found) {
filter.countSelectedValues++;
filter.values.push({
selected: true,
name: this.customFilter.valueName,
id: this.customFilter.valueId,
number: 0
});
}
break;
}
}
}
this.filterChanged(null);
}
// for loading // for loading
public openLoading() { public openLoading() {
@ -1219,9 +1244,16 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
} }
} }
this.customFilterEnabled = URLparams["cf"] == "true"; if (this.customFilters) {
if (this.customFilter && (this.customFilter.isHiddenFilter || this.customFilterEnabled)) { for (let customFilter of this.customFilters) {
allFqs += "&fq=" + StringUtils.URIEncode(this.customFilter.queryFieldName + " exact " + StringUtils.quote((this.customFilter.valueId))); if (customFilter.isHiddenFilter) {
if(customFilter.customQuery){
allFqs += "&fq=" + StringUtils.URIEncode(customFilter.customQuery);
}else {
allFqs += "&fq=" + StringUtils.URIEncode(customFilter.queryFieldName + " exact " + StringUtils.quote((customFilter.valueId)));
}
}
}
} }
/* if (this.quickFilter && this.entityType == "result") { /* if (this.quickFilter && this.entityType == "result") {
@ -1580,11 +1612,6 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
this.parameterValues.push(this.searchUtils.keyword); this.parameterValues.push(this.searchUtils.keyword);
} }
if (this.customFilterEnabled) {
this.parameterNames.push("cf");
this.parameterValues.push("true");
}
// if (this.searchUtils.size != this.resultsPerPage) { // if (this.searchUtils.size != this.resultsPerPage) {
// // allLimits += ((allLimits.length == 0) ? '?' : '&') + 'size=' + this.searchUtils.size; // // allLimits += ((allLimits.length == 0) ? '?' : '&') + 'size=' + this.searchUtils.size;
// this.parameterNames.push("size"); // this.parameterNames.push("size");
@ -1812,7 +1839,38 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges {
} }
public prepareStaticFiltersToShow() { public prepareStaticFiltersToShow() {
this.staticFilters = RefineResultsUtils.parse(this.staticFieldValues, this.staticFields, this.entityType, "search", true); var selected_filters: Map<string, string[]> = this.getSelectedFilters();
if (selected_filters.size == 0) {
selected_filters = this.getSelectedParameters();
}
var selected_static_filters: Map<string, string[]> = this.getSelectedStaticFilters();
if (selected_static_filters.size == 0) {
selected_static_filters = this.getSelectedStaticParameters();
}
let all_selected_filters = new Map([...selected_filters, ...selected_static_filters]);
// let all_selected_filters = selected_filters.concat(selected_static_filters);
let staticFields: string[] = [];
for (var i = 0; i < this.staticFields.length; i++) {
var dependentTo = this.searchFieldsHelper.DEPENDENT_FIELDS[this.staticFields[i]];
var dependentToValues = this.searchFieldsHelper.DEPENDENT_FIELDS_AND_VALUES[this.staticFields[i]];
// TODO check again the checks
//if filter is not marked as hidden OR it is hidden but it is dependent to a field that it IS selected
if (this.searchFieldsHelper.HIDDEN_FIELDS.indexOf(this.staticFields[i]) == -1
|| (all_selected_filters.has(this.staticFields[i]))
|| (!dependentTo && !dependentToValues)
|| (all_selected_filters.has(dependentTo))
|| (dependentToValues && (all_selected_filters.has(dependentToValues.field) && dependentToValues.values.some(dependentValue=> all_selected_filters.get(dependentToValues.field).includes(dependentValue))))
) {
staticFields.push(this.staticFields[i]);
}
}
this.staticFilters = RefineResultsUtils.parse(this.staticFieldValues, staticFields, this.entityType, "search", true);
this.checkSelectedStaticFilters(this.staticFilters); this.checkSelectedStaticFilters(this.staticFilters);
this.countSelectedStaticFilters(this.staticFilters); this.countSelectedStaticFilters(this.staticFilters);
this.cdr.detectChanges(); this.cdr.detectChanges();

View File

@ -1,5 +1,6 @@
@import (reference) "~src/assets/openaire-theme/less/color.less";
@import (reference) "~src/assets/openaire-theme/less/_import-variables.less"; @import (reference) "~src/assets/openaire-theme/less/_import-variables.less";
@import (optional) "~src/assets/extend-theme/less/_import-variables.less";
.setType(@color, @position: left) { .setType(@color, @position: left) {
border-@{position}: 4px solid fade(@color, 30%); border-@{position}: 4px solid fade(@color, 30%);

View File

@ -60,7 +60,7 @@ export class PortalSearchResultComponent implements OnInit{
hasPermission(result: CommunityInfo & StakeholderInfo) { hasPermission(result: CommunityInfo & StakeholderInfo) {
if(this.type === "community") { if(this.type === "community") {
return result.status === "all" || (result.status === "manager" && result.isManager); return result.isPublic() || (result.isRestricted() && result.isManager);
} else if(this.type === "stakeholder") { } else if(this.type === "stakeholder") {
return result.visibility === "PUBLIC" || (result.visibility === "RESTRICTED" && (result.isManager || result.isMember)) || return result.visibility === "PUBLIC" || (result.visibility === "RESTRICTED" && (result.isManager || result.isMember)) ||
(result.visibility === "PRIVATE" && result.isManager); (result.visibility === "PRIVATE" && result.isManager);

View File

@ -14,12 +14,13 @@ import {properties} from "../../../../environments/environment";
@Component({ @Component({
selector: 'search-download', selector: 'search-download',
template: ` template: `
<button [attr.uk-tooltip]="'title: Download' + ((totalResults > csvLimit)?' the first 2000 ':' ') + 'results;'" <button [attr.uk-tooltip]="'title: Download' + ((totalResults > csvLimit)?' the first 2000 ':' ') + 'results.' +
((totalResults > csvLimit && properties.zenodoDumpUrl)?' To get all results download the data dump. ':' ') "
class="uk-button uk-button-link uk-flex uk-flex-middle" [class.uk-disabled]="isDisabled" class="uk-button uk-button-link uk-flex uk-flex-middle" [class.uk-disabled]="isDisabled"
[disabled]="isDisabled" [disabled]="isDisabled"
(click)="downloadfile(downloadURLAPI+'?format=csv'+csvParams,type+'-report-'+((totalResults > csvLimit)?'2000 ':totalResults))"> (click)="downloadfile(downloadURLAPI+'?format=csv'+csvParams,type+'-report-'+((totalResults > csvLimit)?'2000 ':totalResults))">
<icon name="download" [flex]="true"></icon> <icon name="download" [flex]="true"></icon>
<span class="uk-margin-small-left">Download Results</span> <span class="uk-margin-xsmall-left">Download Results</span>
</button> </button>
<modal-loading></modal-loading> <modal-loading></modal-loading>
<modal-alert #AlertModalCsvError></modal-alert> <modal-alert #AlertModalCsvError></modal-alert>

View File

@ -1,9 +1,35 @@
<div *ngIf="filter.values.length >0"> <div *ngIf="filter.values.length >0">
<div class="uk-flex uk-flex-middle uk-margin-bottom"> <div *ngIf="!grouped else groupedTitle" class="uk-flex uk-flex-middle uk-margin-bottom">
<h6 [title]="filter.title" class="uk-margin-remove-bottom">{{_formatTitle(filter.title, filter.values.length)}}</h6> <h6 [title]="filter.title" class="uk-margin-remove-bottom">{{_formatTitle(filter.title, filter.values.length)}}</h6>
<a *ngIf="filter.countSelectedValues>0" class="uk-text-small uk-margin-left" (click)="clearFilter()" [class.uk-disabled]="isDisabled">Clear</a> <a *ngIf="filter.countSelectedValues>0" class="uk-text-small uk-margin-left" (click)="clearFilter()" [class.uk-disabled]="isDisabled">Clear</a>
</div> </div>
<div> <ng-template #groupedTitle>
<div class="uk-flex uk-flex-middle uk-margin-small-bottom">
<div [title]="filter.title" class="uk-margin-remove-bottom uk-text-meta">{{_formatTitle(filter.title, filter.values.length)}}</div>
<a *ngIf="filter.countSelectedValues>0" class="uk-text-small uk-margin-left" (click)="clearFilter()" [class.uk-disabled]="isDisabled">Clear</a>
</div>
</ng-template>
<div *ngIf="filter.type && filter.type == 'triplet'">
<span>
<mat-button-toggle-group [name]="filter.title" [aria-label]="filter.title" class="uk-text-xsmall"
[(ngModel)]="filter.radioValue" (ngModelChange)="tripletFilterChange()" [disabled]="isDisabled">
<mat-button-toggle *ngFor="let value of filter.values" [value]="value.id" class="filter-button-toggle">
<div style="width: 50px">{{value.name}}</div>
</mat-button-toggle>
<!-- <ng-container *ngFor="let value of filter.values">-->
<!-- <mat-button-toggle value="true">-->
<!-- {{filter.title}}-->
<!-- </mat-button-toggle>-->
<!-- <mat-button-toggle value="false">-->
<!-- Not {{filter.title}}-->
<!-- </mat-button-toggle>-->
<!-- </ng-container>-->
</mat-button-toggle-group>
</span>
</div>
<div *ngIf="!filter.type || filter.type != 'triplet'">
<div *ngFor="let value of getSelectedAndTopValues(filter, filterValuesNum)" <div *ngFor="let value of getSelectedAndTopValues(filter, filterValuesNum)"
class="uk-animation-fade uk-text-small uk-margin-small-bottom"> class="uk-animation-fade uk-text-small uk-margin-small-bottom">
<div [title]="value.name"> <div [title]="value.name">
@ -12,10 +38,10 @@
</div> </div>
<div *ngIf="addShowMore && hasMoreValues"> <div *ngIf="addShowMore && hasMoreValues">
<a *ngIf="filterValuesNum > 0 " class="uk-text-small view-more-less-link uk-margin-small-top" [ngClass]="((isDisabled)?'uk-disabled uk-link-muted ':'')" (click)="toggle($event)"> <a *ngIf="filterValuesNum > 0 " class="uk-text-small view-more-less-link uk-margin-small-top" [ngClass]="((isDisabled)?'uk-disabled uk-link-muted ':'')" (click)="toggle($event)">
<span *ngIf="!filter.isOpen">View all</span> <span *ngIf="!filter.isViewAllOpen">View all</span>
<span *ngIf="filter.isOpen">View less </span> <span *ngIf="filter.isViewAllOpen">View less </span>
</a> </a>
<div *ngIf="filter.isOpen" class="uk-text-small uk-margin-small-top uk-margin-small-bottom"> <div *ngIf="filter.isViewAllOpen" class="uk-text-small uk-margin-small-top uk-margin-small-bottom">
<div *ngIf="filter.countAllValues == -1"> <div *ngIf="filter.countAllValues == -1">
<loading class="uk-height-small uk-display-block" size="medium"></loading> <loading class="uk-height-small uk-display-block" size="medium"></loading>
</div> </div>
@ -49,6 +75,67 @@
</div> </div>
</div> </div>
</div> </div>
<!--<ul *ngIf="filter.values.length >0" class="uk-accordion">-->
<!-- <li (click)="filter.isOpen = !filter.isOpen" [class]="filter.isOpen ? 'uk-open' : ''">-->
<!-- <a class="uk-accordion-title">-->
<!-- {{filter.isOpen}}-->
<!-- <span>{{_formatTitle(filter.title, filter.values.length)}}</span>-->
<!-- <span *ngIf="filter.countSelectedValues>0" class="uk-margin-left">{{filter.countSelectedValues}}</span>-->
<!-- </a>-->
<!-- <div *ngIf="filter.isOpen" class="uk-accordion-content">-->
<!-- <div *ngFor="let value of getSelectedAndTopValues(filter, filterValuesNum)"-->
<!-- class="uk-animation-fade uk-text-small uk-margin-small-bottom">-->
<!-- <div [title]="value.name">-->
<!-- <ng-container *ngTemplateOutlet="input_label_wrapper; context: {filter: filter, value: value}"></ng-container>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div *ngIf="addShowMore && hasMoreValues">-->
<!-- <a *ngIf="filterValuesNum > 0 " class="uk-text-small view-more-less-link uk-margin-small-top" [ngClass]="((isDisabled)?'uk-disabled uk-link-muted ':'')" (click)="toggle($event)">-->
<!-- <span *ngIf="!filter.isViewAllOpen">View all</span>-->
<!-- <span *ngIf="filter.isViewAllOpen">View less </span>-->
<!-- </a>-->
<!-- <div *ngIf="filter.isViewAllOpen" class="uk-text-small uk-margin-small-top uk-margin-small-bottom">-->
<!-- <div *ngIf="filter.countAllValues == -1">-->
<!-- <loading class="uk-height-small uk-display-block" size="medium"></loading>-->
<!-- </div>-->
<!-- <div *ngIf="filter.countAllValues == 0">-->
<!-- <span class="uk-text-warning">An error occured. </span><span><a class="uk-button-link" (click)="toggleWithoutUpdate()">Please try again</a>.</span>-->
<!-- </div>-->
<!-- <ng-container *ngIf="(!filter.countAllValues && filter.countAllValues != 0) || filter.countAllValues > 0">-->
<!-- <div class="uk-margin-small-left">-->
<!-- <div class="uk-text-meta">Top 100 values are shown in the filters</div>-->
<!-- <div class="uk-flex uk-flex-bottom uk-margin-top">-->
<!-- <div input class="uk-width-1-2@m uk-margin-right" [placeholder]="{label: 'Search', static: true}" inputClass="inner small" [(value)]="keyword" (valueChange)="initMatching()"></div>-->
<!-- <div *ngIf="showResultCount === true" input type="select" class="uk-width-expand" placeholder="Sort by"-->
<!-- inputClass="border-bottom" [(value)]="sortBy" [options]="sortByOptions" (valueChange)="sort()"></div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="uk-overflow-auto uk-height-max-small uk-margin-small-left uk-margin-small-right uk-margin-top">-->
<!-- <ng-container *ngFor="let value of this.sortedValues">-->
<!-- <div *ngIf="filterKeywords(value.name)" title="{{value.name}}"-->
<!-- class="uk-animation-fade uk-text-small">-->
<!-- <ng-container *ngTemplateOutlet="input_label_wrapper; context: {filter: filter, value: value}"></ng-container>-->
<!-- </div>-->
<!-- </ng-container>-->
<!-- <ng-container *ngIf="!hasMatch">-->
<!-- <div class="uk-padding-small uk-text-meta">-->
<!-- No filters available with that term-->
<!-- </div>-->
<!-- </ng-container>-->
<!-- </div>-->
<!-- </ng-container>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </li>-->
<!--</ul>-->
<ng-template #input_label let-filter="filter" let-value="value"> <ng-template #input_label let-filter="filter" let-value="value">
<span *ngIf="filter.filterType == 'checkbox' || filter.filterType == 'radio'" class="uk-flex uk-flex-middle" <span *ngIf="filter.filterType == 'checkbox' || filter.filterType == 'radio'" class="uk-flex uk-flex-middle"
[class.uk-disabled]="isDisabled || (showResultCount && value.number === 0)"> [class.uk-disabled]="isDisabled || (showResultCount && value.number === 0)">
@ -65,7 +152,7 @@
{{value.name=='true'?'Yes':'No'}} {{value.name=='true'?'Yes':'No'}}
</span> </span>
<ng-template #noboolean> <ng-template #noboolean>
{{_formatName(value)}} <span class="uk-text-capitalize">{{_formatName(value)}} </span>
</ng-template> </ng-template>
<span *ngIf="showResultCount">({{value.number|number}})</span> <span *ngIf="showResultCount">({{value.number|number}})</span>

View File

@ -43,9 +43,10 @@ export class SearchFilterComponent implements OnInit, OnChanges {
@Input() actionRoute: boolean = false; @Input() actionRoute: boolean = false;
@Input() quickFilter: { filter: Filter, selected: boolean, filterId: string, value: string }; @Input() quickFilter: { filter: Filter, selected: boolean, filterId: string, value: string };
sub; sub;
@Input() isOpen: boolean = false; // @Input() isViewAllOpen: boolean = false;
sortedValues; sortedValues;
hasMatch: boolean = false; hasMatch: boolean = false;
@Input() grouped: boolean = false;
constructor(private _router: Router, constructor(private _router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
@ -60,11 +61,11 @@ export class SearchFilterComponent implements OnInit, OnChanges {
ngOnInit() { ngOnInit() {
if(this.filterValuesNum == 0){ if(this.filterValuesNum == 0){
this.filter.isOpen = true; this.filter.isViewAllOpen = true;
this.sortBy = "num"; this.sortBy = "num";
} }
// else{ // else{
// this.filter.isOpen = false; // this.filter.isViewAllOpen = false;
// } // }
this.sub = this.route.queryParams.subscribe(params => { this.sub = this.route.queryParams.subscribe(params => {
this.queryParams = Object.assign({}, params); this.queryParams = Object.assign({}, params);
@ -90,7 +91,7 @@ export class SearchFilterComponent implements OnInit, OnChanges {
// && value.name.toLowerCase() != "null" // && value.name.toLowerCase() != "null"
// ); // );
if (this.filter.filterType == "radio") { if (this.filter.filterType == "radio" || this.filter.filterType == "triplet") {
this.filter.radioValue = ""; this.filter.radioValue = "";
this.filter.values.forEach(value => { this.filter.values.forEach(value => {
if (value.selected) { if (value.selected) {
@ -165,6 +166,20 @@ export class SearchFilterComponent implements OnInit, OnChanges {
}); });
} }
tripletFilterChange() {
if(this.filter.radioValue == "") {
this.clearFilter();
} else {
this.filter.countSelectedValues = 1;
this.filter.values.forEach(value => {
value.selected = (value.id == this.filter.radioValue);
});
this.onFilterChange.emit({
value: this.filter
});
}
}
clearFilter() { clearFilter() {
for (var i = 0; i < this.filter.values.length; i++) { for (var i = 0; i < this.filter.values.length; i++) {
this.filter.values[i].selected = false; this.filter.values[i].selected = false;
@ -274,7 +289,7 @@ export class SearchFilterComponent implements OnInit, OnChanges {
} }
toggle(event) { toggle(event) {
this.filter.isOpen = !this.filter.isOpen; this.filter.isViewAllOpen = !this.filter.isViewAllOpen;
event.stopPropagation(); event.stopPropagation();
this.toggleWithoutUpdate(); this.toggleWithoutUpdate();
} }
@ -283,7 +298,7 @@ export class SearchFilterComponent implements OnInit, OnChanges {
if(this.filter.countAllValues == 0) { if(this.filter.countAllValues == 0) {
this.filter.countAllValues = -1; // if request failed, try again automatically if toggled again this.filter.countAllValues = -1; // if request failed, try again automatically if toggled again
} }
if(this.filter.isOpen && this.filter.countAllValues < 0) { if(this.filter.isViewAllOpen && this.filter.countAllValues < 0) {
this.onFilterToggle.emit(this.filter); this.onFilterToggle.emit(this.filter);
} }
} }

View File

@ -9,11 +9,12 @@ import {RouterModule} from "@angular/router";
import {InputModule} from '../../sharedComponents/input/input.module'; import {InputModule} from '../../sharedComponents/input/input.module';
import {IconsModule} from "../../utils/icons/icons.module"; import {IconsModule} from "../../utils/icons/icons.module";
import {LoadingModule} from "../../utils/loading/loading.module"; import {LoadingModule} from "../../utils/loading/loading.module";
import {MatButtonToggleModule} from "@angular/material/button-toggle";
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, FormsModule, ModalModule, RouterModule, CommonModule, FormsModule, ModalModule, RouterModule,
InputModule, IconsModule, LoadingModule InputModule, IconsModule, LoadingModule, MatButtonToggleModule
], ],
declarations: [ declarations: [
SearchFilterComponent, SearchFilterModalComponent SearchFilterComponent, SearchFilterModalComponent

View File

@ -12,7 +12,8 @@ export class Filter{
public radioValue?: string = ""; public radioValue?: string = "";
// public uniqueValueIdSelected: string; // public uniqueValueIdSelected: string;
public countAllValues?: number = -1; // -1: not yet requested, 0: request failed, >0 OK public countAllValues?: number = -1; // -1: not yet requested, 0: request failed, >0 OK
public isOpen?: boolean = false; // public isOpen?: boolean = false;
public isViewAllOpen?: boolean = false;
public countUnfilteredValues?: number = 0; public countUnfilteredValues?: number = 0;
} }

View File

@ -27,18 +27,20 @@ export class SearchCustomFilter{
valueName:string; // Greece valueName:string; // Greece
isHiddenFilter:boolean; isHiddenFilter:boolean;
selected:boolean; selected:boolean;
promptToAddFilter:boolean; showFilterMessage:boolean;
constructor( fieldName:string, queryFieldName:string, valueId:string, valueName:string ){ customQuery:string;
constructor( fieldName:string, queryFieldName:string, valueId:string, valueName:string, showFilterMessage:boolean = true, customQuery = null ){
if(valueId == "test" && properties.environment == "development"){ if(valueId == "test" && properties.environment == "development"){
valueId = "covid-19"; valueId = "covid-19";
} }
this.showFilterMessage = showFilterMessage;
this.isHiddenFilter = true; this.isHiddenFilter = true;
this.fieldName = fieldName; this.fieldName = fieldName;
this.queryFieldName = queryFieldName; this.queryFieldName = queryFieldName;
this.valueId = valueId; this.valueId = valueId;
this.valueName = valueName; this.valueName = valueName;
this.selected = null; this.selected = null;
this.promptToAddFilter = false; this.customQuery = customQuery;
} }
public getParameters(params={}){ public getParameters(params={}){

View File

@ -6,6 +6,7 @@ import {StringUtils} from '../utils/string-utils.class';
import{EnvProperties} from '../utils/properties/env-properties'; import{EnvProperties} from '../utils/properties/env-properties';
import {map} from "rxjs/operators"; import {map} from "rxjs/operators";
import {ParsingFunctions} from "../landingPages/landing-utils/parsingFunctions.class"; import {ParsingFunctions} from "../landingPages/landing-utils/parsingFunctions.class";
import {properties} from '../../../environments/environment';
@Injectable() @Injectable()
export class SearchDataprovidersService { export class SearchDataprovidersService {
@ -116,7 +117,7 @@ export class SearchDataprovidersService {
} else { } else {
result['englishname'] = ""; result['englishname'] = "";
} }
result['originalId'] = resData.originalId;
//result['title'].url = OpenaireProperties.getsearchLinkToDataProvider(); //result['title'].url = OpenaireProperties.getsearchLinkToDataProvider();
//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'];
@ -289,4 +290,11 @@ export class SearchDataprovidersService {
return this.http.get((properties.useCache)? (properties.cacheUrl+encodeURIComponent(url)): url) return this.http.get((properties.useCache)? (properties.cacheUrl+encodeURIComponent(url)): url)
.pipe(map(res => res['meta']['total'])); .pipe(map(res => res['meta']['total']));
} }
searchDataproviderById(id: string):any {
let url = properties.searchAPIURLLAst + "datasources/" + id + '?format=json';
return this.http.get((properties.useCache)? (properties.cacheUrl+encodeURIComponent(url)): url)
.pipe(map(res => this.parseResults(res)));
}
} }

View File

@ -427,6 +427,20 @@ export class SearchResearchResultsService {
result.hostedBy_collectedFrom, result.publisher, result.hostedBy_collectedFrom, result.publisher,
result['journal']?result['journal'].journal:null, result.identifiers); result['journal']?result['journal'].journal:null, result.identifiers);
if(resData.hasOwnProperty("publiclyfunded") && resData.publiclyfunded) {
result.publiclyFunded = resData.publiclyfunded;
}
if((resData.hasOwnProperty("isgreen") && resData.isgreen)
|| (resData.hasOwnProperty("openaccesscolor") && resData.openaccesscolor)
|| (resData.hasOwnProperty("isindiamondjournal") && resData.isindiamondjournal)) {
result.oaRoutes = {
"green": resData.isgreen,
"oaColor": resData.openaccesscolor,
"isInDiamondJournal":resData.isindiamondjournal
};
}
results.push(result); results.push(result);
} }
return results; return results;
@ -598,4 +612,9 @@ export class SearchResearchResultsService {
return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) return this.http.get((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
.pipe(map(res => res['meta']['total'])); .pipe(map(res => res['meta']['total']));
} }
fetchByDOIs(DOIs:string[],query:string): any {
let url = properties.searchAPIURLLAst + "/researchProducts/byDoi?type=publications" + (query?query:"");
return this.http.post(url, {doiArray: DOIs})
.pipe(map(res => [res['meta'].total, this.parseResults("result", res['results'], properties), RefineResultsUtils.parse(res['refineResults'], null, "publication")]));
}
} }

View File

@ -7,13 +7,18 @@ import {properties} from "../../../environments/environment";
import {StringUtils} from "../utils/string-utils.class"; import {StringUtils} from "../utils/string-utils.class";
import {CustomOptions} from "./servicesUtils/customOptions.class"; import {CustomOptions} from "./servicesUtils/customOptions.class";
import {AdvancedAsyncSubject} from "../utils/AdvancedAsyncSubject"; import {AdvancedAsyncSubject} from "../utils/AdvancedAsyncSubject";
import {isArray} from "rxjs/internal-compatibility";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class UserManagementService { export class UserManagementService {
private readonly getUserInfoSubject: AdvancedAsyncSubject<User> = new AdvancedAsyncSubject<User>(); private readonly getUserInfoSubject: AdvancedAsyncSubject<User> = new AdvancedAsyncSubject<User>();
private static LOGIN = 'openid_connect_login';
private static LOGOUT: string = 'openid_logout';
private static USERINFO: string = 'userInfo';
public fixRedirectURL: string = null; public fixRedirectURL: string = null;
public allowDoubleRedirectToFixAndCurrentPage: boolean = false;
private redirectUrl: string = null; private redirectUrl: string = null;
private subscription; private subscription;
private readonly routerSubscription; private readonly routerSubscription;
@ -31,6 +36,10 @@ export class UserManagementService {
} }
} }
public static userInfoUrl(index = 0): string {
return (isArray(properties.loginServiceURL)?properties.loginServiceURL[index]:properties.loginServiceURL) + UserManagementService.USERINFO;
}
public get user(): User { public get user(): User {
return this.getUserInfoSubject.getValue(); return this.getUserInfoSubject.getValue();
} }
@ -39,10 +48,15 @@ export class UserManagementService {
return this.getUserInfoSubject.asObservable(); return this.getUserInfoSubject.asObservable();
} }
public updateUserInfo(resolve: Function = null) { public getUserInfoAt(index = 0): Observable<User> {
this.subscription = this.http.get<User>(properties.userInfoUrl, CustomOptions.registryOptions()).pipe(map(userInfo => { return this.http.get<User>(UserManagementService.userInfoUrl(index), CustomOptions.registryOptions()).pipe(map(userInfo => {
return new User(userInfo); return new User(userInfo);
})).subscribe(user => { }))
}
public updateUserInfo(resolve: Function = null) {
this.subscription = this.getUserInfoAt().subscribe(user => {
this.getUserInfoSubject.next(user); this.getUserInfoSubject.next(user);
if (resolve) { if (resolve) {
resolve(); resolve();
@ -55,8 +69,9 @@ export class UserManagementService {
}); });
} }
public setRedirectUrl(url: string = null) { public setRedirectUrl(redirectTo: string | string [] = null) {
if (url) { let urls = Array.isArray(redirectTo)?redirectTo:(redirectTo?[redirectTo]:[])
for(let url of urls) {
let parts = url.split('?'); let parts = url.split('?');
let path = properties.baseLink + parts[0]; let path = properties.baseLink + parts[0];
let params = null; let params = null;
@ -74,24 +89,47 @@ export class UserManagementService {
Session.setReloadUrl(location.protocol + "//" + location.host, path, params, fragment); Session.setReloadUrl(location.protocol + "//" + location.host, path, params, fragment);
} }
this.redirectUrl = StringUtils.URIEncode(location.protocol + "//" + location.host + this.fixRedirectURL); this.redirectUrl = StringUtils.URIEncode(location.protocol + "//" + location.host + this.fixRedirectURL);
} else { }
if(urls.length == 0){
this.redirectUrl = StringUtils.URIEncode(location.href); this.redirectUrl = StringUtils.URIEncode(location.href);
Session.setReloadUrl(location.protocol + "//" + location.host, location.pathname, location.search, location.hash); Session.setReloadUrl(location.protocol + "//" + location.host, location.pathname, location.search, location.hash);
} }
} }
public login() { public login(redirect: string = null) {
if (this.fixRedirectURL) { Session.clearReloadUrl();
this.setRedirectUrl(this.fixRedirectURL); if(redirect) {
this.redirectUrl = redirect;
} else if (this.fixRedirectURL) {
this.setRedirectUrl(this.allowDoubleRedirectToFixAndCurrentPage?[this.fixRedirectURL,location.href.split(location.host)[1]]:this.fixRedirectURL);
} else { } else {
this.setRedirectUrl(); this.setRedirectUrl();
} }
window.location.href = properties.loginUrl + "?redirect=" + this.redirectUrl; let loginURL: string | string[] = isArray(properties.loginServiceURL)?properties.loginServiceURL.map(url => url + UserManagementService.LOGIN):(properties.loginServiceURL + UserManagementService.LOGIN);
window.location.href = this.setURL(loginURL) + this.redirectUrl;
} }
public logout() { public logout() {
Session.clearReloadUrl();
this.setRedirectUrl(); this.setRedirectUrl();
Session.removeUser(); Session.removeUser();
window.location.href = properties.logoutUrl + "?redirect=" + this.redirectUrl; let logoutURL: string | string[] = isArray(properties.loginServiceURL)?properties.loginServiceURL.map(url => url + UserManagementService.LOGOUT):(properties.loginServiceURL + UserManagementService.LOGOUT);
window.location.href = this.setURL(logoutURL) + this.redirectUrl;
}
setURL(url: string | string[]) {
if(isArray(url)) {
let redirectURL = '';
url.forEach((url, index) => {
if(index === 0) {
redirectURL = url + "?redirect=";
} else {
redirectURL += encodeURIComponent(url + "?redirect=");
}
});
return redirectURL;
} else {
return url + "?redirect=";
}
} }
} }

View File

@ -1,9 +1,10 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {properties} from '../../../environments/environment'; import {properties} from '../../../environments/environment';
import {CustomOptions} from './servicesUtils/customOptions.class'; import {CustomOptions} from './servicesUtils/customOptions.class';
import {map} from 'rxjs/operators'; import {map} from 'rxjs/operators';
import {Role} from "../login/utils/helper.class";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -14,7 +15,7 @@ export class UserRegistryService {
} }
public createRole(type: string, id: string): Observable<any[]> { public createRole(type: string, id: string): Observable<any[]> {
return this.http.post<any>(properties.registryUrl + 'create/' + type + '/' + id, null, return this.http.post<any>(properties.registryUrl + 'create/' + Role.GROUP + type + '/' + id, null,
CustomOptions.registryOptions()).pipe(map((response: any) => response.response)); CustomOptions.registryOptions()).pipe(map((response: any) => response.response));
} }
@ -35,12 +36,12 @@ export class UserRegistryService {
public remove(type: string, id: string, email: string, role: "member" | "manager" = "manager"): Observable<any> { public remove(type: string, id: string, email: string, role: "member" | "manager" = "manager"): Observable<any> {
return this.http.delete<any>(properties.registryUrl + return this.http.delete<any>(properties.registryUrl +
type + '/' + id + '/' + role + '/' + encodeURIComponent(email), CustomOptions.registryOptions()); Role.GROUP + type + '/' + id + '/' + role + '/' + encodeURIComponent(email), CustomOptions.registryOptions());
} }
public invite(type: string, id: string, details: any, role: "member" | "manager" = "manager"): Observable<any[]> { public invite(type: string, id: string, details: any, role: "member" | "manager" = "manager"): Observable<any[]> {
return this.http.post<any>(properties.registryUrl + 'invite/' + return this.http.post<any>(properties.registryUrl + 'invite/' +
type + '/' + id + '/' + role, details, Role.GROUP + type + '/' + id + '/' + role, details,
CustomOptions.registryOptions()).pipe(map((response: any) => response.response)); CustomOptions.registryOptions()).pipe(map((response: any) => response.response));
} }
@ -57,9 +58,9 @@ export class UserRegistryService {
return this.http.delete<any>(properties.registryUrl + 'verification/' + id, CustomOptions.registryOptions()); return this.http.delete<any>(properties.registryUrl + 'verification/' + id, CustomOptions.registryOptions());
} }
public getActive(type: string, id: string, role: "member" | "manager" = "manager"): Observable<any[]> { public getActive(type: string, id: string, role: "member" | "manager" = "manager", admin = false): Observable<any[]> {
let url = properties.registryUrl + type + '/' + id + "/" + role + 's'; let url = properties.registryUrl + Role.GROUP + type + '/' + id + "/" + role + 's';
return this.http.get<any>((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url, return this.http.get<any>((properties.useCache && !admin) ? (properties.cacheUrl + encodeURIComponent(url)) : url,
CustomOptions.registryOptions()).pipe(map((response:any) => response.response), map(users => { CustomOptions.registryOptions()).pipe(map((response:any) => response.response), map(users => {
if(users.length > 0 && !users[0].email) { if(users.length > 0 && !users[0].email) {
return []; return [];
@ -69,15 +70,15 @@ export class UserRegistryService {
})); }));
} }
public getPending(type: string, id: string, role: "member" | "manager" = "manager"): Observable<any[]> { public getPending(type: string, id: string, role: "member" | "manager" = "manager", admin = false): Observable<any[]> {
let url = properties.registryUrl + 'invite/' +type + '/' +id + "/" + role + 's/'; let url = properties.registryUrl + 'invite/' + Role.GROUP + type + '/' +id + "/" + role + 's/';
return this.http.get<any>((properties.useCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url, return this.http.get<any>((properties.useCache && !admin) ? (properties.cacheUrl + encodeURIComponent(url)) : url,
CustomOptions.registryOptions()).pipe(map((response: any) => response.response)); CustomOptions.registryOptions()).pipe(map((response: any) => response.response));
} }
public cancelInvitation(type: string, id: string, email: string, role: "member" | "manager" = "manager"): Observable<any> { public cancelInvitation(type: string, id: string, email: string, role: "member" | "manager" = "manager"): Observable<any> {
return this.http.delete<any>(properties.registryUrl + 'invite/' + return this.http.delete<any>(properties.registryUrl + 'invite/' +
type + '/' + id + '/' + role + '/' + encodeURIComponent(email), Role.GROUP + type + '/' + id + '/' + role + '/' + encodeURIComponent(email),
CustomOptions.registryOptions()); CustomOptions.registryOptions());
} }
} }

View File

@ -0,0 +1,70 @@
import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";
import {EnvProperties} from "../utils/properties/env-properties";
import {CustomOptions} from "./servicesUtils/customOptions.class";
import {AdvancedAsyncSubject} from "../utils/AdvancedAsyncSubject";
import {properties} from "../../../environments/environment";
import {map} from "rxjs/operators";
export class UserProfile{
id:string;
aaiId:string;
consent:boolean = false;
constructor(consent:boolean) {
this.consent = consent;
}
}
@Injectable({
providedIn: "root"
})
export class UserProfileService {
private subscription;
private readonly userProfileSubject: AdvancedAsyncSubject<UserProfile> = new AdvancedAsyncSubject<UserProfile>();
constructor(private http: HttpClient) {
}
clearSubscriptions() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
public get user(): UserProfile {
return this.userProfileSubject.getValue();
}
public getUserProfile(): Observable<UserProfile> {
return this.userProfileSubject.asObservable();
}
public setUserProfile(userProfile:UserProfile) {
this.userProfileSubject.next(userProfile?userProfile:new UserProfile(false));
}
public initUserProfile(resolve: Function = null) {
this.subscription = this.http.get<UserProfile>(properties.monitorServiceAPIURL + 'user', CustomOptions.registryOptions()).pipe(map(userProfile => {
return userProfile;
})).subscribe(user => {
this.userProfileSubject.next(user);
if (resolve) {
resolve();
}
}, error => {
this.userProfileSubject.next(new UserProfile(false));
if (resolve) {
resolve();
}
});
}
saveConsentInUserProfile(properties:EnvProperties): Observable<UserProfile> {
return this.http.post<UserProfile>(properties.monitorServiceAPIURL + 'user/save', new UserProfile(true), CustomOptions.registryOptions(),);
}
undoConsentInUserProfile(properties:EnvProperties): Observable<UserProfile> {
return this.http.post<UserProfile>(properties.monitorServiceAPIURL + 'user/save', new UserProfile(false), CustomOptions.registryOptions(),);
}
}

View File

@ -0,0 +1,56 @@
import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {BehaviorSubject, from, Observable, Subscriber} from "rxjs";
import {SearchCustomFilter} from "../searchPages/searchUtils/searchUtils.class";
@Injectable({
providedIn: "root"
})
export class CustomFilterService {
private customFilterSubject: BehaviorSubject<SearchCustomFilter[]> = null;
private promise: Promise<void>;
private sub;
constructor(private http: HttpClient) {
this.customFilterSubject = new BehaviorSubject<SearchCustomFilter[]>(null);
}
ngOnDestroy() {
this.clearSubscriptions();
}
clearSubscriptions() {
if (this.sub instanceof Subscriber) {
this.sub.unsubscribe();
}
}
async getCustomFilterAsync() {
if (this.promise) {
await this.promise;
this.promise = null;
}
this.clearSubscriptions();
return this.customFilterSubject.getValue();
}
getCustomFilterAsObservable(): Observable<SearchCustomFilter[]> {
return this.customFilterSubject.asObservable();
}
setCustomFilter(customFilters: SearchCustomFilter[]) {
this.customFilterSubject.next(customFilters);
}
/*
static getDefaultFilters(){
let defaultFilters = new Map<string, SearchCustomFilter[]>();
defaultFilters.set("result",[new SearchCustomFilter("National", "country", "IE", "Irish National Monitor")]);
defaultFilters.set("project",[new SearchCustomFilter("National", "country", "IE", "Irish National Monitor")]);
defaultFilters.set("organization",[new SearchCustomFilter("National", "country", "IE", "Irish National Monitor")]);
defaultFilters.set("datasource",[new SearchCustomFilter("National", "country", "IE", "Irish National Monitor")]);
return defaultFilters;
}*/
}

View File

@ -2,7 +2,9 @@ import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { Optional, RendererFactory2, ViewEncapsulation } from '@angular/core'; import { Optional, RendererFactory2, ViewEncapsulation } from '@angular/core';
@Injectable() @Injectable({
providedIn: 'root'
})
export class SEOService { export class SEOService {
constructor( @Inject(DOCUMENT) private doc, constructor( @Inject(DOCUMENT) private doc,
private rendererFactory: RendererFactory2, private rendererFactory: RendererFactory2,

View File

@ -0,0 +1,112 @@
import {Directive, OnDestroy} from "@angular/core";
import {BehaviorSubject, Subscriber} from "rxjs";
import {EnvProperties} from "../../utils/properties/env-properties";
import {properties} from "src/environments/environment";
import {PiwikService} from "../../utils/piwik/piwik.service";
import {Meta, Title} from "@angular/platform-browser";
import {SEOService} from "../SEO/SEO.service";
import {ActivatedRoute, Data, NavigationEnd, Params, Router} from "@angular/router";
import {StringUtils} from "../../utils/string-utils.class";
import {RouterHelper} from "../../utils/routerHelper.class";
@Directive()
export abstract class BaseComponent implements OnDestroy {
public properties: EnvProperties = properties;
/** Router params */
protected paramsResolved: boolean = false;
protected params: BehaviorSubject<Params>;
protected data: BehaviorSubject<Data>;
protected subscriptions: any[] = [];
/** Metadata */
public title: string;
public description: string;
public url: string;
protected _route: ActivatedRoute;
protected _piwikService: PiwikService;
protected _meta: Meta;
protected seoService: SEOService;
protected _title: Title;
protected _router: Router;
public routerHelper: RouterHelper = new RouterHelper();
protected constructor() {
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe()
} else if (subscription instanceof Function) {
subscription();
} else if (typeof IntersectionObserver !== 'undefined' && subscription instanceof IntersectionObserver) {
subscription.disconnect();
} else if (typeof ResizeObserver !== 'undefined' && subscription instanceof ResizeObserver) {
subscription.disconnect();
}
});
}
/**
* Initialize router params and data (should be called in the constructor of a component with router-outlet)
* */
initRouterParams(route: ActivatedRoute = null, navigationChange: ((event: NavigationEnd) => void) = null) {
if (route) {
this.params = new BehaviorSubject<Params>(null);
this.data = new BehaviorSubject<Data>(null);
this.subscriptions.push(this._router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if(navigationChange) {
navigationChange(event);
}
let r = route;
while (r.firstChild) {
r = r.firstChild;
}
let data = r.snapshot.data;
let params = r.snapshot.params;
let current = r.snapshot;
while (current.parent) {
data = {...current.parent.data, ...data};
params = {...current.parent.params, ...params};
current = current.parent;
}
r.snapshot.data = data;
r.snapshot.params = params;
this.paramsResolved = true;
this.params.next(r.snapshot.params);
this.data.next(r.snapshot.data);
}
}));
}
}
public setMetadata() {
if (this._title && this.title) {
this.title = (this._route?.snapshot.data?.title ? this._route.snapshot.data?.title : '') + this.title;
this._title.setTitle(this.title);
}
if (this._router) {
this.url = properties.domain + properties.baseLink + this._router.url;
if (this.seoService) {
this.seoService.createLinkForCanonicalURL(this.url, false);
}
if (this._meta) {
this._meta.updateTag({content: this.url}, "property='og:url'");
this._meta.updateTag({content: this.description}, "name='description'");
this._meta.updateTag({content: this.description}, "property='og:description'");
this._meta.updateTag({content: this.title}, "property='og:title'");
}
}
this.trackView();
}
public trackView() {
if (this._piwikService) {
this.subscriptions.push(this._piwikService.trackView(properties, this.title).subscribe());
}
}
public quote(str: string) {
return StringUtils.quote(str);
}
}

View File

@ -66,7 +66,7 @@ export type CookieLawTarget = '_blank' | '_self';
}) })
export class CookieLawComponent implements OnInit { export class CookieLawComponent implements OnInit {
public cookieLawSeen: boolean; public cookieLawSeen: boolean;
@Input() cookieName = "cookieLawSeen";
@Input('learnMore') @Input('learnMore')
get learnMore() { return this._learnMore; } get learnMore() { return this._learnMore; }
set learnMore(value: string) { set learnMore(value: string) {
@ -109,10 +109,11 @@ export class CookieLawComponent implements OnInit {
this.isSeenEvt = new EventEmitter<boolean>(); this.isSeenEvt = new EventEmitter<boolean>();
this.animation = 'topIn'; this.animation = 'topIn';
this._position = 'bottom'; this._position = 'bottom';
this.cookieLawSeen = this._service.seen();
} }
ngOnInit(): void { ngOnInit(): void {
this.cookieLawSeen = this._service.seen(this.cookieName);
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
this.animation = this.position === 'bottom' ? 'bottomIn' : 'topIn'; this.animation = this.position === 'bottom' ? 'bottomIn' : 'topIn';
@ -142,7 +143,7 @@ export class CookieLawComponent implements OnInit {
evt.preventDefault(); evt.preventDefault();
} }
this._service.storeCookie(); this._service.storeCookie(this.cookieName);
this.animation = this.position === 'top' ? 'topOut' : 'bottomOut'; this.animation = this.position === 'top' ? 'topOut' : 'bottomOut';
} }
} }

View File

@ -12,12 +12,12 @@ import { Injectable } from '@angular/core';
export class CookieLawService { export class CookieLawService {
seen(): boolean { seen(cookieName): boolean {
return this.cookieExists('cookieLawSeen'); return this.cookieExists(cookieName);
} }
storeCookie(): void { storeCookie(cookieName): void {
return this.setCookie('cookieLawSeen'); return this.setCookie(cookieName);
} }
/** /**

View File

@ -65,8 +65,6 @@ export interface ControlConfiguration {
declare var UIkit; declare var UIkit;
/** /**
* WARNING! dashboard-input selector is @deprecated, use input instead
*
* Autocomplete soft allows values that are not listed in options list. In order to work as expected * Autocomplete soft allows values that are not listed in options list. In order to work as expected
* avoid providing options with different label and value. * avoid providing options with different label and value.
* *
@ -478,7 +476,7 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (this.formControl) { if (this.formControl) {
if (changes.value) { if (changes.value && changes.value.currentValue !== changes.value.previousValue) {
this.formControl.setValue(this.value); this.formControl.setValue(this.value);
} }
if (changes.validators) { if (changes.validators) {
@ -826,6 +824,7 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang
resetValue(event: any) { resetValue(event: any) {
event.stopPropagation(); event.stopPropagation();
console.log(1)
this.formControl.setValue(''); this.formControl.setValue('');
this.focus(true, event); this.focus(true, event);
} }

View File

@ -12,9 +12,7 @@
</div> </div>
<div *ngIf="!onlyTop || userMenu" class="uk-navbar-right" [class.uk-light]='activeHeader.darkBg'> <div *ngIf="!onlyTop || userMenu" class="uk-navbar-right" [class.uk-light]='activeHeader.darkBg'>
<ng-container *ngIf="userMenu"> <ng-container *ngIf="userMenu">
<user-mini [user]="user" mobileView=true <user-mini [user]="user" mobileView=true [userMenuItems]=userMenuItems [notificationConfiguration]="notificationConfiguration"></user-mini>
[userMenuItems]=userMenuItems [logInUrl]=properties.loginUrl [notificationConfiguration]="notificationConfiguration"
[logOutUrl]=properties.logoutUrl [cookieDomain]=properties.cookieDomain></user-mini>
</ng-container> </ng-container>
</div> </div>
</nav> </nav>
@ -151,11 +149,15 @@
<div id="main-menu" class="uk-visible@m"> <div id="main-menu" class="uk-visible@m">
<div *ngIf="activeHeader" [class.uk-light]='activeHeader.darkBg'> <div *ngIf="activeHeader" [class.uk-light]='activeHeader.darkBg'>
<div class="uk-navbar-container" uk-sticky> <div class="uk-navbar-container" uk-sticky>
<div *ngIf="(properties.environment =='beta' || properties.environment =='development') && showLogo && activeHeader.badge"> <a *ngIf="(properties.environment =='beta' || properties.environment =='development' || activeHeader.environmentBadge) && showLogo && activeHeader.badge"
<img class="uk-position-top-left" [routerLink]="activeHeader.environmentBadge?.routerLink?activeHeader.environmentBadge.routerLink:null" target="_blank">
<img *ngIf="!activeHeader.environmentBadge" class="uk-position-top-left"
[src]="'assets/common-assets/'+(properties.environment =='beta'?'beta_flag.svg':'prototype_flag.svg')" [src]="'assets/common-assets/'+(properties.environment =='beta'?'beta_flag.svg':'prototype_flag.svg')"
alt="BETA" style="height: 65px; width: 65px; z-index: 1000"> alt="BETA" style="height: 65px; width: 65px; z-index: 1000">
</div> <img *ngIf="activeHeader.environmentBadge" class="uk-position-top-left"
[src]="activeHeader.environmentBadge.asset" [alt]="properties.environment"
style="height: 75px; width: 75px; z-index: 1000">
</a>
<div class="uk-container uk-container-expand"> <div class="uk-container uk-container-expand">
<nav class="uk-navbar" uk-navbar="delay-hide: 400"> <nav class="uk-navbar" uk-navbar="delay-hide: 400">
<ng-container *ngIf="!onlyTop"> <ng-container *ngIf="!onlyTop">
@ -192,9 +194,7 @@
</div> </div>
</div> </div>
<user-mini *ngIf="!searchMode && userMenu" [user]="user" <user-mini *ngIf="!searchMode && userMenu" [user]="user" [userMenuItems]=userMenuItems></user-mini>
[userMenuItems]=userMenuItems [logInUrl]=properties.loginUrl [logOutUrl]=properties.logoutUrl
[cookieDomain]=properties.cookieDomain></user-mini>
<div class="uk-visible@m"> <div class="uk-visible@m">
<ng-content select="[extra-m]"></ng-content> <ng-content select="[extra-m]"></ng-content>
</div> </div>

View File

@ -24,6 +24,12 @@ import {RouterHelper} from "../utils/routerHelper.class";
declare var UIkit; declare var UIkit;
export interface Badge {
asset: string,
routerLink?: string,
external?: boolean
}
export interface Header { export interface Header {
route?: string, route?: string,
url?: string, url?: string,
@ -33,6 +39,7 @@ export interface Header {
logoInfo?: string, logoInfo?: string,
position: 'left' | 'center' | 'right', position: 'left' | 'center' | 'right',
badge: boolean, badge: boolean,
environmentBadge?: Badge,
darkBg?: boolean, darkBg?: boolean,
menuPosition?: 'center' | 'right', menuPosition?: 'center' | 'right',
replaceHeader?: Header; replaceHeader?: Header;

View File

@ -1,4 +1,5 @@
import {Component, Input} from "@angular/core"; import {Component, Input} from "@angular/core";
import {ActivatedRoute} from "@angular/router";
@Component({ @Component({
selector: 'slider-tab', selector: 'slider-tab',
@ -22,4 +23,6 @@ export class SliderTabComponent {
@Input() @Input()
public customClass: string = ''; public customClass: string = '';
@Input() tabTemplate: any; @Input() tabTemplate: any;
@Input()
public relativeTo: ActivatedRoute = null;
} }

View File

@ -43,7 +43,7 @@ declare var UIkit;
</ng-container> </ng-container>
<ng-container *ngIf="type === 'dynamic'"> <ng-container *ngIf="type === 'dynamic'">
<li *ngFor="let tab of leftTabs; let i=index;" [class.uk-active]="tab.active" [style.max-width]="(position === 'horizontal')?'50%':null"> <li *ngFor="let tab of leftTabs; let i=index;" [class.uk-active]="tab.active" [style.max-width]="(position === 'horizontal')?'50%':null">
<a [routerLink]="tab.routerLink" [queryParams]="tab.queryParams" [ngClass]="tab.customClass" <a [routerLink]="tab.routerLink" [queryParams]="tab.queryParams" [ngClass]="tab.customClass" [relativeTo]="tab.relativeTo"
(click)="showActive(i)" (click)="showActive(i)"
class="uk-text-capitalize uk-text-truncate uk-display-block"> class="uk-text-capitalize uk-text-truncate uk-display-block">
<span *ngIf="tab.title">{{tab.title}}</span> <span *ngIf="tab.title">{{tab.title}}</span>
@ -52,7 +52,7 @@ declare var UIkit;
</li> </li>
<li *ngFor="let tab of rightTabs; let i=index;" [style.max-width]="(position === 'horizontal')?'50%':null" [class.uk-active]="tab.active" <li *ngFor="let tab of rightTabs; let i=index;" [style.max-width]="(position === 'horizontal')?'50%':null" [class.uk-active]="tab.active"
[ngClass]="i === 0?'uk-flex-1 uk-flex uk-flex-right':''"> [ngClass]="i === 0?'uk-flex-1 uk-flex uk-flex-right':''">
<a [routerLink]="tab.routerLink" [queryParams]="tab.queryParams" [ngClass]="tab.customClass" <a [routerLink]="tab.routerLink" [queryParams]="tab.queryParams" [ngClass]="tab.customClass" [relativeTo]="tab.relativeTo"
(click)="showActive(i)" (click)="showActive(i)"
class="uk-text-capitalize uk-text-truncate uk-display-block"> class="uk-text-capitalize uk-text-truncate uk-display-block">
<span *ngIf="tab.title">{{tab.title}}</span> <span *ngIf="tab.title">{{tab.title}}</span>

View File

@ -1,4 +1,13 @@
import {Component, Inject, Input, PLATFORM_ID, ViewChild} from '@angular/core'; import {
AfterContentInit,
AfterViewInit,
ChangeDetectorRef,
Component,
Inject,
Input,
PLATFORM_ID,
ViewChild
} from '@angular/core';
import {ActivatedRoute} from "@angular/router"; import {ActivatedRoute} from "@angular/router";
import {RouterHelper} from "../routerHelper.class"; import {RouterHelper} from "../routerHelper.class";
import {EnvProperties} from '../properties/env-properties'; import {EnvProperties} from '../properties/env-properties';
@ -11,89 +20,89 @@ import {properties} from "../../../../environments/environment";
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">
<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 + ";"}}
</span> </span>
<ng-container *ngIf="!isSticky && (author.orcid || author.orcid_pending) && isBrowser"> <ng-container *ngIf="!isSticky && (author.orcid || author.orcid_pending) && isBrowser">
<a #toggle class="uk-flex-inline uk-flex-middle uk-link-text"> <a #toggle class="uk-flex-inline uk-flex-middle uk-link-text">
<img *ngIf="author.orcid" src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt="orcid" <img *ngIf="author.orcid" src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt="orcid"
loading="lazy" style="width:16px; height:16px; margin-right: 3px;"> loading="lazy" style="width:16px; height:16px; margin-right: 3px;">
<img *ngIf="!author.orcid && author.orcid_pending" <img *ngIf="!author.orcid && author.orcid_pending"
src="assets/common-assets/common/ORCIDiD_iconbw16x16.png" alt="orcid bw" loading="lazy" src="assets/common-assets/common/ORCIDiD_iconbw16x16.png" alt="orcid bw" loading="lazy"
style="margin-right: 3px;"> style="margin-right: 3px;">
<span style="margin-right: 5px;" [class.uk-text-italic]="italic"> <span style="margin-right: 5px;" [class.uk-text-italic]="italic">
{{author.fullName + ";"}} {{author.fullName + ";"}}
</span> </span>
</a> </a>
<div *ngIf="!isMobile" class="default-dropdown uk-margin-remove-top uk-dropdown orcid-dropdown" uk-dropdown="mode:click; offset: 4; container: true" style="min-width: 465px !important;"> <div *ngIf="!isMobile" class="default-dropdown uk-margin-remove-top uk-dropdown orcid-dropdown"
<ng-container *ngTemplateOutlet="dropdown"></ng-container> uk-dropdown="mode:click; offset: 4;" style="min-width: 465px !important;" [attr.container]="isModal?'#modal-container':true">
</div> <ng-container *ngTemplateOutlet="dropdown"></ng-container>
<mobile-dropdown *ngIf="isMobile" [toggle]="toggle"> </div>
<div class="orcid-dropdown"> <mobile-dropdown *ngIf="isMobile" [toggle]="toggle">
<ng-container *ngTemplateOutlet="dropdown"></ng-container> <div class="orcid-dropdown">
</div> <ng-container *ngTemplateOutlet="dropdown"></ng-container>
</mobile-dropdown> </div>
<ng-template #dropdown> </mobile-dropdown>
<div class="uk-padding-small"> <ng-template #dropdown>
<h6 class="uk-margin-remove">{{author.fullName}}</h6> <div class="uk-padding-small">
<div> <h6 class="uk-margin-remove">{{author.fullName}}</h6>
<div class="uk-text-meta uk-margin-bottom">ORCID</div> <div>
<div class="uk-text-meta uk-margin-bottom">ORCID</div>
<div class="uk-text-meta uk-text-xsmall uk-margin-small-top uk-margin-small-bottom"> <div class="uk-text-meta uk-text-xsmall uk-margin-small-top uk-margin-small-bottom">
<img *ngIf="author.orcid" src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt="" <img *ngIf="author.orcid" src="assets/common-assets/common/ORCIDiD_icon16x16.png" alt=""
loading="lazy">{{" "}} loading="lazy">{{" "}}
<img *ngIf="!author.orcid && author.orcid_pending" <img *ngIf="!author.orcid && author.orcid_pending"
src="assets/common-assets/common/ORCIDiD_iconbw16x16.png" alt="" loading="lazy">{{" "}} src="assets/common-assets/common/ORCIDiD_iconbw16x16.png" alt="" loading="lazy">{{" "}}
<i *ngIf="author.orcid">Harvested from ORCID Public Data File</i> <i *ngIf="author.orcid">Harvested from ORCID Public Data File</i>
<i *ngIf="!author.orcid && author.orcid_pending">Derived by OpenAIRE algorithms or harvested <i *ngIf="!author.orcid && author.orcid_pending">Derived by OpenAIRE algorithms or harvested
from 3d party repositories</i> from 3d party repositories</i>
</div> </div>
<div> <div>
<div class="clipboard-wrapper uk-width-1-1 uk-flex uk-flex-middle uk-flex-center" <div class="clipboard-wrapper uk-width-1-1 uk-flex uk-flex-middle uk-flex-center"
style="min-height: 43px; min-width: 280px;"> style="min-height: 43px; min-width: 280px;">
<input #element class="uk-padding-small uk-text-emphasis uk-width-expand uk-disabled" <input #element class="uk-padding-small uk-text-emphasis uk-width-expand uk-disabled"
[value]="properties.orcidURL+(author.orcid ? author.orcid : author.orcid_pending)"/> [value]="properties.orcidURL+(author.orcid ? author.orcid : author.orcid_pending)"/>
<button class="uk-button uk-button-link uk-margin-small-right copy orcid_clipboard_btn" [ngClass]="'orcid_clipboard_btn_auhtor_'+i" <button class="uk-button uk-button-link uk-margin-small-right copy orcid_clipboard_btn" [ngClass]="'orcid_clipboard_btn_auhtor_'+i"
title="Copy to clipboard" (click)="copyToClipboard(element)"> title="Copy to clipboard" (click)="copyToClipboard(element)">
<icon name="content_copy" visuallyHidden="Copy to clipboard" [flex]="true"></icon> <icon name="content_copy" visuallyHidden="Copy to clipboard" [flex]="true"></icon>
</button> </button>
</div> </div>
<div class="uk-text-center uk-margin-small-top"> <div class="uk-text-center uk-margin-small-top">
<a class="uk-button uk-button-text custom-external" <a class="uk-button uk-button-text custom-external"
title="Visit author in ORCID" title="Visit author in ORCID"
[href]="properties.orcidURL+(author.orcid ? author.orcid : author.orcid_pending)" [href]="properties.orcidURL+(author.orcid ? author.orcid : author.orcid_pending)"
target="_blank"> target="_blank">
VISIT AUTHOR IN ORCID VISIT AUTHOR IN ORCID
</a> </a>
</div> </div>
</div> </div>
</div> </div>
<hr>
<div class="uk-margin-top uk-text-bold uk-text-emphasis uk-text-center">
{{author.fullName}} in OpenAIRE
</div>
<div class="uk-text-center uk-margin-top uk-margin-large-left uk-margin-large-right">
<a *ngIf="properties.adminToolsPortalType !== 'eosc'"
class="uk-button uk-button-primary uk-text-bold uk-padding-remove-top uk-padding-remove-bottom"
(click)="onClick()"
[queryParams]="routerHelper.createQueryParams(['orcid','oc'],[(author['orcid'] ? author['orcid'] : author['orcid_pending']),'and'])"
routerLinkActive="router-link-active" [routerLink]="properties.searchLinkToAdvancedResults">
<span class="space">Search</span>
</a>
<a *ngIf="properties.adminToolsPortalType == 'eosc'"
class="uk-button uk-button-primary uk-text-bold uk-padding-remove-top uk-padding-remove-bottom uk-light"
[href]="'https://explore.openaire.eu'+properties.searchLinkToAdvancedResults+'?orcid='+(author['orcid'] ? author['orcid'] : author['orcid_pending'])+'&oc=and'"
target="_blank">
<span class="space custom-external">Search in OpenAIRE</span>
</a>
</div>
</div>
</ng-template>
</ng-container>
<hr>
<div class="uk-margin-top uk-text-bold uk-text-emphasis uk-text-center">
{{author.fullName}} in OpenAIRE
</div>
<div class="uk-text-center uk-margin-top uk-margin-large-left uk-margin-large-right">
<a *ngIf="properties.adminToolsPortalType !== 'eosc'"
class="uk-button uk-button-primary uk-text-bold uk-padding-remove-top uk-padding-remove-bottom"
(click)="onClick()"
[queryParams]="routerHelper.createQueryParams(['orcid','oc'],[(author['orcid'] ? author['orcid'] : author['orcid_pending']),'and'])"
routerLinkActive="router-link-active" [routerLink]="properties.searchLinkToAdvancedResults">
<span class="space">Search</span>
</a>
<a *ngIf="properties.adminToolsPortalType == 'eosc'"
class="uk-button uk-button-primary uk-text-bold uk-padding-remove-top uk-padding-remove-bottom uk-light"
[href]="'https://explore.openaire.eu'+properties.searchLinkToAdvancedResults+'?orcid='+(author['orcid'] ? author['orcid'] : author['orcid_pending'])+'&oc=and'"
target="_blank">
<span class="space custom-external">Search in OpenAIRE</span>
</a>
</div>
</div>
</ng-template>
</ng-container>
</ng-template> </ng-template>
<div *ngIf="authors" <div *ngIf="authors"
@ -144,6 +153,7 @@ 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;

View File

@ -94,6 +94,19 @@ export class Composer {
return email; return email;
} }
public static composeEmailforIrishMonitor(contactForm: any, admins: any): Email {
let email: Email = new Email();
email.subject = "National OA Monitor Ireland | " + contactForm.subject;
email.body = "<div style='font-size:" + this.noteBodySize + "'>"
+ "<span><b>Name</b>: " + contactForm.name + "</span><br>"
+ "<span><b>Email</b>: " + contactForm.email + "</span><br>"
+ "<p>" + contactForm.message + "</p>"
+ "</div>";
email.recipients = admins;
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() + "]";
@ -317,6 +330,26 @@ export class Composer {
return message; return message;
} }
public static composeMessageForIrishDashboard(name: string, recipient: string, role: "manager" | "member") {
let email: Email = new Email();
email.subject = 'National Open Access Monitor Ireland | ' + name;
email.recipient = recipient;
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>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>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"?
'<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 member of the OpenAIRE Monitor Dashboard, you will have access to the restricted access areas of the profile for the ' + name + '.') +
'<p>Please contact us at <a href="mailto:' + properties.helpdeskEmail+'">' + properties.helpdeskEmail +
'</a> if you have any questions or concerns.</p>' +
'<p>Kind Regards<br>The OpenAIRE Team</p>' +
'<p><a href="' + properties.domain + '" target="_blank">National Open Access Monitor, Ireland</a></p>';
return email;
}
public static composeEmailForCommunityDashboard(name: string, role: "manager" | "member", recipient: string) { public static composeEmailForCommunityDashboard(name: string, role: "manager" | "member", recipient: string) {
let email: Email = new Email(); let email: Email = new Email();
email.subject = 'OpenAIRE Connect | ' + name; email.subject = 'OpenAIRE Connect | ' + name;

View File

@ -1,7 +1,7 @@
import { import {
Author, Author,
HostedByCollectedFrom, HostedByCollectedFrom,
Journal, Journal, OARoutes,
Organization, Organization,
Project, Project,
RelationResult RelationResult
@ -96,6 +96,9 @@ export class ResultLandingInfo {
sdg: string[]; sdg: string[];
eoscSubjects: any[]; eoscSubjects: any[];
oaRoutes: OARoutes;
publiclyFunded: boolean;
// // percentage is for trust // // percentage is for trust
// relatedResearchResults: RelationResult[]; // relatedResearchResults: RelationResult[];
// // percentage is for similarity // // percentage is for similarity

View File

@ -1,4 +1,12 @@
import {Author, HostedByCollectedFrom, Journal, Organization, Project, ResultTitle} from "../result-preview/result-preview"; import {
Author,
HostedByCollectedFrom,
Journal,
OARoutes,
Organization,
Project,
ResultTitle
} from "../result-preview/result-preview";
import {Measure, Metric} from "./resultLandingInfo"; import {Measure, Metric} from "./resultLandingInfo";
export class SearchResult { export class SearchResult {
@ -61,11 +69,15 @@ export class SearchResult {
compatibilityUNKNOWN: boolean; compatibilityUNKNOWN: boolean;
countries: string[]; countries: string[];
subjects: string[]; subjects: string[];
originalId: string;
entityType: string; entityType: string;
types: string[]; types: string[];
enermapsId: string; enermapsId: string;
oaRoutes: OARoutes;
publiclyFunded: boolean;
constructor() { constructor() {
} }

View File

@ -180,7 +180,7 @@ export class EntityActionsComponent implements OnInit {
isRouteAvailable(routeToCheck: string) { isRouteAvailable(routeToCheck: string) {
for (let i = 0; i < this.router.config.length; i++) { for (let i = 0; i < this.router.config.length; i++) {
let routePath: string = this.router.config[i].path; let routePath: string = this.router.config[i].path;
if (routePath == routeToCheck) { if (routePath == routeToCheck || routeToCheck.split('/')[0] == routePath) {
return true; return true;
} }
} }

View File

@ -47,11 +47,13 @@ export interface StopRule {
@Component({ @Component({
selector: 'icon', selector: 'icon',
template: ` template: `
<span #svgIcon *ngIf="icon.data" class="uk-icon" [class.uk-preserve]="gradient || icon.preserveColor" [class.uk-flex]="flex" [ngClass]="customClass" [ngStyle]="style" [innerHTML]="icon.data | safeHtml"></span> <ng-container *ngIf="icon">
<span *ngIf="!icon.data && icon.name" [class.uk-flex]="flex" [ngClass]="customClass" [class.uk-display-inline-block]="!flex"> <span #svgIcon *ngIf="icon.data" class="uk-icon" [class.uk-preserve]="gradient || icon.preserveColor" [class.uk-flex]="flex" [ngClass]="customClass" [ngStyle]="style" [innerHTML]="icon.data | safeHtml"></span>
<span class="material-icons" [ngClass]="type?type:icon.type" [ngStyle]="style">{{icon.name}}</span> <span *ngIf="!icon.data && icon.name" [class.uk-flex]="flex" [ngClass]="customClass" [class.uk-display-inline-block]="!flex">
</span> <span class="material-icons" [ngClass]="type?type:icon.type" [ngStyle]="style">{{icon.name}}</span>
<span *ngIf="visuallyHidden" class="visually-hidden">{{visuallyHidden}}</span> </span>
<span *ngIf="visuallyHidden" class="visually-hidden">{{visuallyHidden}}</span>
</ng-container>
` `
}) })
export class IconsComponent implements AfterViewInit, OnChanges { export class IconsComponent implements AfterViewInit, OnChanges {
@ -149,7 +151,7 @@ export class IconsComponent implements AfterViewInit, OnChanges {
} }
initIcon() { initIcon() {
if(this.icon.data && this.svgIcon) { if(this.icon?.data && this.svgIcon) {
this.cdr.detectChanges(); this.cdr.detectChanges();
let svg: Element = this.svgIcon.nativeElement.getElementsByTagName('svg').item(0); let svg: Element = this.svgIcon.nativeElement.getElementsByTagName('svg').item(0);
if(!this.defaultSize && svg) { if(!this.defaultSize && svg) {

View File

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

56
utils/log/log.service.ts Normal file
View File

@ -0,0 +1,56 @@
import {HttpClient} from "@angular/common/http";
import {EnvProperties} from '../properties/env-properties';
import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
export abstract class Log{
action: "link" | "orcid-link" | "upload-dois";
message:string;
protected constructor(action, message){
this.action =action;
this.message = message;
}
}
export class LinkLog extends Log{
constructor(sourceTitle,targetTitle) {
super("link","a user linked the \"" +sourceTitle+"\" " + " to the \"" +targetTitle+"\" " );
}
}
export class OrcidLinkLog extends Log{
constructor( action:'added'|'removed', title: string, id: string) {
super("orcid-link","user with ORCID ID " + action + " research product "+ (title?"\"" + title+ "\"":"") + " (" + id + ") " + (action == 'added'?'to':'from')
+ " their ORCID record.");
}
}
export class UploadLog extends Log{
constructor(dois:number) {
super("upload-dois","a user uploaded a list of " + dois +" DOIs to the Irish Monitor to check their presence and retrieve the Open Access types and additional key metadata");
}
}
@Injectable()
export class LogService {
constructor(private http: HttpClient) {
}
logUploadDOIs(properties: EnvProperties, dois:number){
return this.http.post(properties.logServiceUrl+"logAction", new UploadLog(dois) );
}
logLink(properties: EnvProperties, sourceTitle,targetTitle){
return this.http.post(properties.logServiceUrl+"logAction", new LinkLog(sourceTitle, targetTitle) );
}
logOrcidLink(properties: EnvProperties, action:'added'|'removed', title: string, doi: string){
return this.http.post(properties.logServiceUrl+"logAction", new OrcidLinkLog(action, title, doi) );
}
logRemoveOrcidLink(properties: EnvProperties, code: string){
return this.http.post(properties.logServiceUrl+"logAction", new OrcidLinkLog('removed',null, code) );
}
getLogs(properties: EnvProperties):Observable<any>{
return this.http.get(properties.logServiceUrl+"log");
}
}

View File

@ -1,4 +1,4 @@
import {Component, ElementRef, EventEmitter, Input, OnInit, Output} from "@angular/core"; import {ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnInit, Output} from "@angular/core";
import {NavigationStart, Router} from "@angular/router"; import {NavigationStart, Router} from "@angular/router";
@Component({ @Component({
@ -21,7 +21,7 @@ export class MobileDropdownComponent implements OnInit{
public opened: boolean = false; public opened: boolean = false;
private static MOBILE_DROPDOWN_CONTAINER = 'mobile-dropdown-container'; private static MOBILE_DROPDOWN_CONTAINER = 'mobile-dropdown-container';
constructor(private element: ElementRef, private router: Router) { constructor(private element: ElementRef, private router: Router, private cdr: ChangeDetectorRef) {
this.router.events.subscribe(event => { this.router.events.subscribe(event => {
if(event instanceof NavigationStart) { if(event instanceof NavigationStart) {
this.element.nativeElement.remove(); this.element.nativeElement.remove();
@ -63,6 +63,7 @@ export class MobileDropdownComponent implements OnInit{
close() { close() {
if(this.opened) { if(this.opened) {
this.opened = false; this.opened = false;
this.cdr.detectChanges();
this.onClose.emit(); this.onClose.emit();
document.getElementsByTagName('body')[0].setAttribute('style', ''); document.getElementsByTagName('body')[0].setAttribute('style', '');
} }

View File

@ -8,7 +8,9 @@ import {ConfigurationService} from "../configuration/configuration.service";
import {switchMap, take} from "rxjs/operators"; import {switchMap, take} from "rxjs/operators";
@Injectable() @Injectable({
providedIn: 'root'
})
export class PiwikService { export class PiwikService {
constructor(private http: HttpClient, private configurationService: ConfigurationService) { constructor(private http: HttpClient, private configurationService: ConfigurationService) {
} }
@ -69,6 +71,22 @@ export class PiwikService {
} }
public doTrackEvent(properties: EnvProperties, title, siteId, pageURL, eventCategory, eventAction, eventName, eventValue = 0): Observable<any> {
let ua = this.getUserAgent();
let referrer = this.getReferrer();
let piwikId = ((siteId != null) ? siteId : properties.piwikSiteId);
if (typeof location !== 'undefined' && piwikId) {
var url =`${properties.piwikBaseUrl}${piwikId}&rec=1&url=${encodeURIComponent(pageURL)}&action_name=${encodeURIComponent(title)}&e_c=${encodeURIComponent(eventCategory)}&e_a=${encodeURIComponent(eventAction)}&e_n=${encodeURIComponent(eventName)}&e_v=${encodeURIComponent(eventValue)}`
+((ua != null && ua.length > 0) ? ('&ua=' + StringUtils.URIEncode(ua)) : '') +
((referrer != null && referrer.length > 0) ? ('&urlref=' + StringUtils.URIEncode(referrer)) : '');
// console.log(trackingApiUrl)
console.log(url)
// return of(new Object()); // for testing
return this.http.get(url, {responseType: 'blob'});
}
}
private getUserAgent() { private getUserAgent() {
if (typeof navigator !== 'undefined') { if (typeof navigator !== 'undefined') {
return navigator.userAgent; return navigator.userAgent;

View File

@ -1,6 +1,6 @@
export type Environment = "development" | "test" | "beta" | "production"; export type Environment = "development" | "test" | "beta" | "production";
export type Dashboard = "explore" | "connect" | "monitor" | "aggregator" | "eosc" | "developers" | "faircore4eosc"; export type Dashboard = "explore" | "connect" | "monitor" | "aggregator" | "eosc" | "developers" | "faircore4eosc" | "irish";
export type PortalType = "explore" | "connect" | "community" | "monitor" | "funder" | "ri" | "project" | "organization" | "aggregator" | "eosc" | "faircore4eosc"; export type PortalType = "explore" | "connect" | "community" | "monitor" | "funder" | "ri" | "project" | "organization" | "aggregator" | "eosc" | "faircore4eosc" | "country";
export interface EnvProperties { export interface EnvProperties {
environment?: Environment; environment?: Environment;
@ -57,10 +57,8 @@ export interface EnvProperties {
vocabulariesAPI?: string; vocabulariesAPI?: string;
piwikBaseUrl?: string; piwikBaseUrl?: string;
piwikSiteId?: string; piwikSiteId?: string;
loginUrl?: string; loginServiceURL?: string | string[];
registryUrl?: string; registryUrl?: string;
logoutUrl?: string;
userInfoUrl?: string;
developersApiUrl?: string, developersApiUrl?: string,
cookieDomain?: string; cookieDomain?: string;
feedbackmail?: string; feedbackmail?: string;
@ -83,6 +81,7 @@ export interface EnvProperties {
baseLink?: string; baseLink?: string;
baseOpenaireLink?: string; baseOpenaireLink?: string;
afterLoginRedirectLink?: string; afterLoginRedirectLink?: string;
myClaimsLink?: string;
searchLinkToResult?: string; searchLinkToResult?: string;
searchLinkToPublication?: string; searchLinkToPublication?: string;
searchLinkToProject?: string; searchLinkToProject?: string;
@ -145,6 +144,14 @@ export interface EnvProperties {
eoscDataTransferLoginUrl?; eoscDataTransferLoginUrl?;
eoscDataTransferDestinations?; eoscDataTransferDestinations?;
hasMachineCache?: boolean; hasMachineCache?: boolean;
// irish
logFilesPath?:string;
matomoLogFilesPath?:string;
logServiceUrl?:string;
zenodoDumpUrl?:string;
openOrgsUrl?:string;
orcidDiscoverLinksPage?:string;
} }
export function checkPropertyValues(properties:EnvProperties){ export function checkPropertyValues(properties:EnvProperties){

View File

@ -33,7 +33,8 @@ export let common: EnvProperties = {
csvLimit: 2000, csvLimit: 2000,
pagingLimit: 20, pagingLimit: 20,
resultsPerPage: 10, resultsPerPage: 10,
baseLink: "", baseLink : "",
myClaimsLink: '/myclaims',
searchLinkToResult: "/search/result?id=", searchLinkToResult: "/search/result?id=",
searchLinkToPublication: "/search/publication?articleId=", searchLinkToPublication: "/search/publication?articleId=",
searchLinkToProject: "/search/project?projectId=", searchLinkToProject: "/search/project?projectId=",
@ -84,6 +85,7 @@ export let common: EnvProperties = {
shareInZenodoPage: '/participate/deposit/zenodo', shareInZenodoPage: '/participate/deposit/zenodo',
afterLoginRedirectLink: '/myCommunities', afterLoginRedirectLink: '/myCommunities',
searchLinkToCommunities: '/search/find/communities', searchLinkToCommunities: '/search/find/communities',
openOrgsUrl:"https://beta.orgs.openaire.eu",
} }
export let commonDev: EnvProperties = { export let commonDev: EnvProperties = {
@ -101,11 +103,9 @@ export let commonDev: EnvProperties = {
orcidAPIURL: "http://duffy.di.uoa.gr:19480/uoa-orcid-service/", orcidAPIURL: "http://duffy.di.uoa.gr:19480/uoa-orcid-service/",
orcidTokenURL: "https://sandbox.orcid.org/oauth/authorize?", orcidTokenURL: "https://sandbox.orcid.org/oauth/authorize?",
orcidClientId: "APP-A5M3KTX6NCN67L91", orcidClientId: "APP-A5M3KTX6NCN67L91",
utilsService: "http://dl170.madgik.di.uoa.gr:8000", utilsService: "http://mpagasas.di.uoa.gr:8000",
vocabulariesAPI: "https://dev-openaire.d4science.org/provision/mvc/vocabularies/", vocabulariesAPI: "https://dev-openaire.d4science.org/provision/mvc/vocabularies/",
loginUrl: "http://mpagasas.di.uoa.gr:19080/login-service/openid_connect_login", loginServiceURL: "http://mpagasas.di.uoa.gr:19080/login-service/",
userInfoUrl: "http://mpagasas.di.uoa.gr:19080/login-service/userInfo",
logoutUrl: "http://mpagasas.di.uoa.gr:19080/login-service/openid_logout",
cookieDomain: ".di.uoa.gr", cookieDomain: ".di.uoa.gr",
feedbackmail: "kostis30fylloy@gmail.com", feedbackmail: "kostis30fylloy@gmail.com",
cacheUrl: "http://dl170.madgik.di.uoa.gr:3000/get?url=", cacheUrl: "http://dl170.madgik.di.uoa.gr:3000/get?url=",
@ -123,7 +123,7 @@ export let commonDev: EnvProperties = {
//connect //connect
communitiesAPI: 'https://dev-openaire.d4science.org/openaire/community/communities', communitiesAPI: 'https://dev-openaire.d4science.org/openaire/community/communities',
registryUrl: 'http://mpagasas.di.uoa.gr:8080/dnet-openaire-users-1.0.0-SNAPSHOT/api/registry/', registryUrl: 'http://mpagasas.di.uoa.gr:8080/dnet-openaire-users-1.0.0-SNAPSHOT/api/registry/',
reCaptchaSiteKey: "6LcVtFIUAAAAAB2ac6xYivHxYXKoUvYRPi-6_rLu",
//admin //admin
miningBackendURL: 'https://beta.services.openaire.eu/interactive-mining', miningBackendURL: 'https://beta.services.openaire.eu/interactive-mining',
feedbackmailForMissingEntities: 'feedback@openaire.eu', feedbackmailForMissingEntities: 'feedback@openaire.eu',
@ -142,9 +142,7 @@ export let commonTest: EnvProperties = {
csvAPIURL: "https://services.openaire.eu/search/v2/api/reports", csvAPIURL: "https://services.openaire.eu/search/v2/api/reports",
utilsService: "https://explore.openaire.eu/utils-service", utilsService: "https://explore.openaire.eu/utils-service",
vocabulariesAPI: "https://services.openaire.eu/provision/mvc/vocabularies/", vocabulariesAPI: "https://services.openaire.eu/provision/mvc/vocabularies/",
loginUrl: " https://services.openaire.eu/login-service/openid_connect_login", loginServiceURL: " https://services.openaire.eu/login-service/",
userInfoUrl: " https://services.openaire.eu/login-service/userInfo",
logoutUrl: "https://services.openaire.eu/login-service/openid_logout",
cacheUrl: "https://explore.openaire.eu/cache/get?url=", cacheUrl: "https://explore.openaire.eu/cache/get?url=",
datasourcesAPI: "https://services.openaire.eu/openaire/ds/api/", datasourcesAPI: "https://services.openaire.eu/openaire/ds/api/",
monitorServiceAPIURL: "https://services.openaire.eu/uoa-monitor-service", monitorServiceAPIURL: "https://services.openaire.eu/uoa-monitor-service",
@ -173,9 +171,7 @@ export let commonBeta: EnvProperties = {
csvAPIURL: "https://beta.services.openaire.eu/search/v2/api/reports", csvAPIURL: "https://beta.services.openaire.eu/search/v2/api/reports",
utilsService: "https://demo.openaire.eu/utils-service", utilsService: "https://demo.openaire.eu/utils-service",
vocabulariesAPI: "https://beta.services.openaire.eu/provision/mvc/vocabularies/", vocabulariesAPI: "https://beta.services.openaire.eu/provision/mvc/vocabularies/",
loginUrl: "https://beta.services.openaire.eu/login-service/openid_connect_login", loginServiceURL: "https://beta.services.openaire.eu/login-service/",
userInfoUrl: "https://beta.services.openaire.eu/login-service/userInfo",
logoutUrl: "https://beta.services.openaire.eu/login-service/openid_logout",
cacheUrl: "https://demo.openaire.eu/cache/get?url=", cacheUrl: "https://demo.openaire.eu/cache/get?url=",
datasourcesAPI: "https://beta.services.openaire.eu/openaire/ds/api/", datasourcesAPI: "https://beta.services.openaire.eu/openaire/ds/api/",
monitorServiceAPIURL: "https://beta.services.openaire.eu/uoa-monitor-service", monitorServiceAPIURL: "https://beta.services.openaire.eu/uoa-monitor-service",
@ -214,9 +210,7 @@ export let commonProd: EnvProperties = {
csvAPIURL: "https://services.openaire.eu/search/v2/api/reports", csvAPIURL: "https://services.openaire.eu/search/v2/api/reports",
utilsService: "https://explore.openaire.eu/utils-service", utilsService: "https://explore.openaire.eu/utils-service",
vocabulariesAPI: "https://services.openaire.eu/provision/mvc/vocabularies/", vocabulariesAPI: "https://services.openaire.eu/provision/mvc/vocabularies/",
loginUrl: " https://services.openaire.eu/login-service/openid_connect_login", loginServiceURL: "https://services.openaire.eu/login-service/",
userInfoUrl: " https://services.openaire.eu/login-service/userInfo",
logoutUrl: "https://services.openaire.eu/login-service/openid_logout",
cacheUrl: "https://explore.openaire.eu/cache/get?url=", cacheUrl: "https://explore.openaire.eu/cache/get?url=",
datasourcesAPI: "https://services.openaire.eu/openaire/ds/api/", datasourcesAPI: "https://services.openaire.eu/openaire/ds/api/",
monitorServiceAPIURL: "https://services.openaire.eu/uoa-monitor-service", monitorServiceAPIURL: "https://services.openaire.eu/uoa-monitor-service",
@ -240,6 +234,9 @@ export let commonProd: EnvProperties = {
deleteCacheUrl: 'https://explore.openaire.eu/cache/clear', deleteCacheUrl: 'https://explore.openaire.eu/cache/clear',
deleteBrowserCacheUrl: 'https://services.openaire.eu/uoa-admin-tools/cache', deleteBrowserCacheUrl: 'https://services.openaire.eu/uoa-admin-tools/cache',
connectPortalUrl: 'https://connect.openaire.eu', connectPortalUrl: 'https://connect.openaire.eu',
//irish
openOrgsUrl:"https://orgs.openaire.eu"
} }

Some files were not shown because too many files have changed in this diff Show More