import {ChangeDetectorRef, Component, OnDestroy, OnInit, ViewRef} from '@angular/core'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {DomSanitizer, Meta, Title} from '@angular/platform-browser'; import {EnvProperties} from '../openaireLibrary/utils/properties/env-properties'; import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service'; import {Dates, StringUtils} from '../openaireLibrary/utils/string-utils.class'; import {ErrorCodes} from '../openaireLibrary/utils/properties/errorCodes'; import {ErrorMessagesComponent} from '../openaireLibrary/utils/errorMessages.component'; import {HelperService} from "../openaireLibrary/utils/helper/helper.service"; import {SEOService} from "../openaireLibrary/sharedComponents/SEO/SEO.service"; import {StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service"; import { Category, Indicator, IndicatorPath, IndicatorSize, Section, Stakeholder, SubCategory, Topic, Visibility } from "../openaireLibrary/monitor/entities/stakeholder"; import {StatisticsService} from "../utils/services/statistics.service"; import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils"; import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service"; import {FormBuilder, FormControl} from "@angular/forms"; import {Subscriber, Subscription} from "rxjs"; import {User} from "../openaireLibrary/login/utils/helper.class"; import {UserManagementService} from "../openaireLibrary/services/user-management.service"; import {RangeFilter} from "../openaireLibrary/utils/rangeFilter/rangeFilterHelperClasses.class"; import {Filter} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class"; import {Location} from "@angular/common"; import {RouterHelper} from "../openaireLibrary/utils/routerHelper.class"; import {properties} from "../../environments/environment"; import {IndexInfoService} from "../openaireLibrary/utils/indexInfo.service"; import {ConfigurationService} from "../openaireLibrary/utils/configuration/configuration.service"; @Component({ selector: 'monitor', templateUrl: 'monitor.component.html', styleUrls: ['monitor.component.css'] }) export class MonitorComponent implements OnInit, OnDestroy { public user: User; public subscriptions: any[] = []; piwikSiteId; title; description; public pageContents = null; public divContents = null; public status: number; public loading: boolean = true; public isViewPublic: boolean = false; public indicatorUtils: IndicatorUtils = new IndicatorUtils(); public stakeholderUtils: StakeholderUtils = new StakeholderUtils(); public activeTopic: Topic = null; public activeCategory: Category = null; public activeSubCategory: SubCategory = null; public errorCodes: ErrorCodes; public stakeholder: Stakeholder; public numberResults: Map = new Map(); public chartsActiveType: Map = new Map(); private errorMessages: ErrorMessagesComponent; properties: EnvProperties = properties; filterToggle = false; public routerHelper: RouterHelper = new RouterHelper(); filters: Filter[] = []; queryParams = {}; public currentYear = new Date().getFullYear(); periodFilter: RangeFilter = { title: "Time range", filterId: "year", originalFilterIdFrom: null, originalFilterIdTo: null, selectedFromValue: null, selectedToValue: null, selectedFromAndToValues: "" }; privateStakeholder = false; public keyword: FormControl; public statsUpdateDate: Date; constructor( private route: ActivatedRoute, private _router: Router, private _meta: Meta, private _title: Title, private _piwikService: PiwikService, private helper: HelperService, private stakeholderService: StakeholderService, private userManagementService: UserManagementService, private statisticsService: StatisticsService, private layoutService: LayoutService, private seoService: SEOService, private cdr: ChangeDetectorRef, private indexInfoService: IndexInfoService, private sanitizer: DomSanitizer, private _fb: FormBuilder, private router: Router, private configurationService: ConfigurationService) { this.errorCodes = new ErrorCodes(); this.errorMessages = new ErrorMessagesComponent(); this.status = this.errorCodes.LOADING; } public ngOnInit() { if (typeof document !== 'undefined') { this.subscriptions.push(this.indexInfoService.getStatsLastDate(this.properties).subscribe(lastIndexUpdate => { if (lastIndexUpdate) { this.statsUpdateDate = new Date(lastIndexUpdate); } })); } this.keyword = this._fb.control(''); this.subscriptions.push(this.keyword.valueChanges.subscribe(value => { console.log("Keyword Changed!"); //TODO do a real action })); let subscription: Subscription; this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.user = user; this.subscriptions.push(this.route.params.subscribe(params => { this.loading = true; this.activeTopic = null; this.activeCategory = null; this.activeSubCategory = null; this.filterToggle = false; if (subscription) { subscription.unsubscribe(); } var url = properties.domain + properties.baseLink + this._router.url; this.subscriptions.push(this.route.queryParams.subscribe(params => { this.queryParams = Object.assign({}, params); this.isViewPublic = (params['view'] == 'public'); })); if (!this.stakeholder || this.stakeholder.alias !== params['stakeholder']) { this.status = this.errorCodes.LOADING; this.numberResults = new Map(); this.chartsActiveType = new Map(); subscription = this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { if (stakeholder) { this.stakeholder = stakeholder; // add fl0 filter only for EC if (this.stakeholder.index_id == "ec__________::EC") { this.filters.push({ title: "Funding Stream", filterId: "relfundinglevel0_id", originalFilterId: "relfundinglevel0_id", countSelectedValues: 0, values: [{name: "EC|FP7", id: "ec__________::EC::FP7", selected: false, number: 0}, { name: "EC|H2020", id: "ec__________::EC::H2020", selected: false, number: 0 }] , filterOperator: "or", valueIsExact: true, filterType: "radio", radioValue: "" }); } if (this.stakeholder.type == "funder") { // this.filters.push({title: "Co-funded research outcomes",filterId: "co-funded",originalFilterId: "co-funded", countSelectedValues: 0, // values:[{name: "true", id: "co-funded", selected: false, number: 0}, {name: "false", id: "no-co-funded", selected: false, number: 0}] // ,filterOperator: "or", valueIsExact: true, filterType: "radio", radioValue:""}); this.filters.push({ title: "Co-funded", filterId: "co-funded", originalFilterId: "co-funded", countSelectedValues: 0, values: [{name: "Co-funded research output", id: "co-funded-results", selected: false, number: 0}] , filterOperator: "or", valueIsExact: true, filterType: "checkbox", radioValue: "" }); } this.initializeFilters(); this.seoService.createLinkForCanonicalURL(url, false); this._meta.updateTag({content: url}, "property='og:url'"); this.description = "Monitor Dashboard | " + this.stakeholder.name; this.title = "Monitor Dashboard | " + this.stakeholder.name; 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._title.setTitle(this.title); if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) { this.subscriptions.push(this.configurationService.communityInformationState.subscribe(portal => { if (portal && portal.piwik) { console.debug(portal) this.piwikSiteId = portal.piwik; console.debug(this.piwikSiteId) this.subscriptions.push(this._piwikService.trackView(this.properties, this.title, this.piwikSiteId).subscribe()); } })); } if (this.isPublicOrIsMember(stakeholder.visibility)) { //this.getDivContents(); // this.getPageContents(); this.status = this.errorCodes.DONE; this.setView(params); } else { this.privateStakeholder = true; // this.navigateToError(); if (subscription) { subscription.unsubscribe(); } } } else { this.navigateToError(); if (subscription) { subscription.unsubscribe(); } } }); this.subscriptions.push(subscription); } else { if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) { if (this.piwikSiteId) { console.debug(this.piwikSiteId) this.subscriptions.push(this._piwikService.trackView(this.properties, this.title, this.piwikSiteId).subscribe()); } } this.initializeFilters(); this.setView(params); } })); })); } private 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.clearfFilter(filter); } } } private 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.location.go(location.pathname, this.routerHelper.createQueryParamsString( Object.keys(this.queryParams), Object.values(this.queryParams))); this.router.navigate([], {queryParams: this.queryParams}); this.setIndicators(); } } clearAll() { for (let filter of this.filters) { this.clearfFilter(filter); } this.periodFilter.selectedFromValue = ""; this.periodFilter.selectedToValue = ""; this.validateYearRange(true) } clearfFilter(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]; } } countSelectedFilters(): number { let count = 0; if (this.periodFilter.selectedFromAndToValues.length > 0) { count += 2; } for (let filter of this.filters) { count += filter.countSelectedValues; } return count; } public get isSmallScreen() { return this.layoutService.isSmallScreen; } public get open() { return this.layoutService.open; } private getPageContents() { this.subscriptions.push(this.helper.getPageHelpContents(this.properties, this.properties.adminToolsCommunity, this._router.url).subscribe(contents => { this.pageContents = contents; })); } private getDivContents() { this.subscriptions.push(this.helper.getDivHelpContents(this.properties, this.properties.adminToolsCommunity, this._router.url).subscribe(contents => { this.divContents = contents; })); } private setView(params: Params) { this.loading = false; if (params['topic']) { this.activeTopic = this.stakeholder.topics.find(topic => topic.alias === decodeURIComponent(params['topic']) && this.isPublicOrIsMember(topic.visibility)); if (this.activeTopic) { if (params['category']) { this.activeCategory = this.activeTopic.categories.find(category => (category.alias === params['category']) && this.isPublicOrIsMember(category.visibility)); if (!this.activeCategory) { this.navigateToError(); return; } } else { this.activeCategory = this.activeTopic.categories.find(category => this.isPublicOrIsMember(category.visibility)); if (this.activeCategory) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.isPublicOrIsMember(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.isPublicOrIsMember(subCategory.visibility))); if (!this.activeSubCategory) { this.navigateToError(); return; } } else { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.isPublicOrIsMember(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.isPublicOrIsMember(topic.visibility)); if (this.activeTopic) { this.activeCategory = this.activeTopic.categories.find(category => this.isPublicOrIsMember(category.visibility)); if (this.activeCategory) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.isPublicOrIsMember(subCategory.visibility)); if (this.activeSubCategory) { this.setIndicators(); } } } } } filter() { this.validateYearRange(true); } filterChanged($event, navigate: boolean = true) { let selected = ""; for (let value of $event.value.values) { if (value.selected) { selected = value.id; break; } } if (selected) { this.queryParams[$event.value.filterId] = StringUtils.quote(StringUtils.URIEncode(selected)); } else { delete this.queryParams[$event.value.filterId]; } if (navigate) { this.router.navigate([], {queryParams: this.queryParams}); this.setIndicators(); } } private getfl0() { if (this.queryParams["relfundinglevel0_id"] && this.filters.length > 0) { let value = StringUtils.URIDecode(StringUtils.unquote(this.queryParams["relfundinglevel0_id"])); return value.split("::")[value.split("::").length - 1]; } return null; } private getCoFunded() { if (this.queryParams["co-funded"] && this.filters.length > 0) { return this.queryParams["co-funded"] && StringUtils.URIDecode(StringUtils.unquote(this.queryParams["co-funded"])) == "co-funded-results"; } return false; } clearPeriodFilter() { if (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue) { this.periodFilter.selectedFromValue = ""; this.periodFilter.selectedToValue = ""; this.filter(); } } private 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 = new Map(); this.activeSubCategory.numbers.forEach((section, i) => { section.indicators.forEach((number, j) => { if (this.isPublicOrIsMember(number.visibility)) { let url = this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, number.indicatorPaths[0], this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded()); 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); this.subscriptions.push(this.statisticsService.getNumbers(this.statisticsService.getSourceType(pair[0]), pair[1]).subscribe(response => { indexes.forEach(([i, 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.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath, this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded()))); } 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); } private navigateToError() { this._router.navigate(['/error'], {queryParams: {'page': this._router.url}}); } public navigateTo(stakeholder: string, topic: string, category: string = null, subcategory: string = null) { let url = stakeholder + '/' + topic + ((category) ? ('/' + category) : '') + ((subcategory) ? ('/' + subcategory) : ''); return this._router.navigate([url], {queryParams: this.queryParams}); } public quote(param: string): string { return StringUtils.quote(param); } public ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); } public isPublicOrIsMember(visibility: Visibility): boolean { if (visibility == "PRIVATE" || (this.isViewPublic && visibility != "PUBLIC")) { return false; } return true; } public countSubCategoriesToShow(category: Category): number { let counter = 0; for (let sub of category.subCategories) { if (this.isPublicOrIsMember(sub.visibility)) { counter++; } } return counter; } public countSectionsWithIndicatorsToShow(sections: Section[]):number { let counter = 0; sections.forEach(section => { section.indicators.forEach(indicator => { if (this.isPublicOrIsMember(indicator.visibility)) { counter++; } }); }); return counter; } public countIndicatorsToShow(indicators: Indicator[]): number { let counter = 0; indicators.forEach(indicator => { if (this.isPublicOrIsMember(indicator.visibility)) { counter++; } }); return counter; } public get feedback() { return "mailto:" + this.properties.feedbackmail + "?subject=%5BOpenAIRE%20Monitor%5D%20" + (this.stakeholder ? this.stakeholder.name : "") + "%20dashboard%20feedback" } public getNumberClassBySize(size: IndicatorSize) { if (size === 'small') { return 'uk-width-medium'; } 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) { 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 printData() { window.print(); } }