Project

General

Profile

1
import {ChangeDetectorRef, Component, OnDestroy, OnInit, ViewRef} from '@angular/core';
2
import {ActivatedRoute, Params, Router} from '@angular/router';
3
import {DomSanitizer, Meta, Title} from '@angular/platform-browser';
4
import {EnvProperties} from '../openaireLibrary/utils/properties/env-properties';
5

    
6
import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service';
7
import {Dates, StringUtils} from '../openaireLibrary/utils/string-utils.class';
8
import {ErrorCodes} from '../openaireLibrary/utils/properties/errorCodes';
9
import {ErrorMessagesComponent} from '../openaireLibrary/utils/errorMessages.component';
10
import {HelperService} from "../openaireLibrary/utils/helper/helper.service";
11
import {SEOService} from "../openaireLibrary/sharedComponents/SEO/SEO.service";
12
import {StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service";
13
import {Category, IndicatorPath, Stakeholder, SubCategory, Topic} from "../openaireLibrary/monitor/entities/stakeholder";
14
import {StatisticsService} from "../utils/services/statistics.service";
15
import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils";
16
import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
17
import {FormBuilder, FormControl} from "@angular/forms";
18
import {Subscription} from "rxjs";
19
import {Session, User} from "../openaireLibrary/login/utils/helper.class";
20
import {UserManagementService} from "../openaireLibrary/services/user-management.service";
21
import {RangeFilter} from "../openaireLibrary/utils/rangeFilter/rangeFilterHelperClasses.class";
22
import {Filter, Value} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class";
23
import {Location} from "@angular/common";
24
import {RouterHelper} from "../openaireLibrary/utils/routerHelper.class";
25
import {properties} from "../../environments/environment";
26

    
27
@Component({
28
  selector: 'monitor',
29
  templateUrl: 'monitor.component.html',
30
  styleUrls:['monitor.component.css']
31
})
32
export class MonitorComponent implements OnInit, OnDestroy {
33
  public user: User;
34
  public subscriptions: any[] = [];
35
  public piwiksub: any;
36
  public pageContents = null;
37
  public divContents = null;
38
  public status: number;
39
  public loading: boolean = true;
40
  public isViewPublic: boolean = false;
41
  public indicatorUtils: IndicatorUtils = new IndicatorUtils();
42
  public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
43
  public activeTopic: Topic = null;
44
  public activeCategory: Category = null;
45
  public activeSubCategory: SubCategory = null;
46
  public errorCodes: ErrorCodes;
47
  public stakeholder: Stakeholder;
48
  public numberResults: Map<string, number> = new Map<string, number>();
49
  public chartsActiveType: Map<string, IndicatorPath> = new Map<string, IndicatorPath>();
50
  private errorMessages: ErrorMessagesComponent;
51
  properties: EnvProperties;
52
  filterToggle = false;
53
  public routerHelper: RouterHelper = new RouterHelper();
54
  filters:Filter[] = [];
55
  queryParams = {};
56
  periodFilter:RangeFilter = { title: "Time range",  filterId: "year", originalFilterIdFrom: null, originalFilterIdTo: null, selectedFromValue: null, selectedToValue: null, selectedFromAndToValues: ""};
57
  privateStakeholder = false;
58
  public keyword: FormControl;
59
  constructor(
60
    private route: ActivatedRoute,
61
    private _router: Router,
62
    private _meta: Meta,
63
    private _title: Title,
64
    private _piwikService: PiwikService,
65
    private helper: HelperService,
66
    private stakeholderService: StakeholderService,
67
    private userManagementService: UserManagementService,
68
    private statisticsService: StatisticsService,
69
    private layoutService: LayoutService,
70
    private seoService: SEOService,
71
    private cdr: ChangeDetectorRef,
72
    private sanitizer: DomSanitizer, private _fb: FormBuilder,  private router: Router,
73
    private location: Location) {
74
    this.errorCodes = new ErrorCodes();
75
    this.errorMessages = new ErrorMessagesComponent();
76
    this.status = this.errorCodes.LOADING;
77
  }
78

    
79
  public ngOnInit() {
80
    this.keyword = this._fb.control('');
81
    this.keyword.valueChanges.subscribe(value => {
82
      console.log("Keyword Changed!");
83
      //TODO do a real action
84
    });
85
        let subscription: Subscription;
86
        this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
87
          this.user = user;
88

    
89
          this.route.params.subscribe(params => {
90
            this.loading = true;
91
            this.activeTopic = null;
92
            this.activeCategory = null;
93
            this.activeSubCategory = null;
94
            this.filterToggle = false;
95
            if (subscription) {
96
              subscription.unsubscribe();
97
            }
98
            this.properties = properties;
99
            var url = properties.domain + properties.baseLink + this._router.url;
100
            this.route.queryParams.subscribe(params => {
101
              this.queryParams = Object.assign({}, params);
102
              this.isViewPublic = (params['view'] == 'public');
103
            });
104
            if (!this.stakeholder || this.stakeholder.alias !== params['stakeholder']) {
105
              this.status = this.errorCodes.LOADING;
106
              this.numberResults = new Map<string, number>();
107
              this.chartsActiveType = new Map<string, IndicatorPath>();
108
              subscription = this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => {
109
                if (stakeholder) {
110
                  this.stakeholder = stakeholder;
111
                  // add fl0 filter only for EC
112
                  if(this.stakeholder.index_id == "ec__________::EC"){
113
                    this.filters.push({title: "Funding Stream",filterId: "relfundinglevel0_id",originalFilterId: "relfundinglevel0_id", countSelectedValues: 0,
114
                      values:[{name: "EC|FP7", id: "ec__________::EC::FP7", selected:  false, number: 0}, {name: "EC|H2020", id: "ec__________::EC::H2020", selected:  false, number: 0}]
115
                      ,filterOperator: "or", valueIsExact: true, filterType: "radio", radioValue:""});
116
                  }
117
                  if(this.stakeholder.type == "funder"){
118
                    // this.filters.push({title: "Co-funded research outcomes",filterId: "co-funded",originalFilterId: "co-funded", countSelectedValues: 0,
119
                    //   values:[{name: "true", id: "co-funded", selected:  false, number: 0}, {name: "false", id: "no-co-funded", selected:  false, number: 0}]
120
                    //   ,filterOperator: "or", valueIsExact: true, filterType: "radio", radioValue:""});
121
                    this.filters.push({title: "Co-funded",filterId: "co-funded",originalFilterId: "co-funded", countSelectedValues: 0,
122
                      values:[{name: "Co-funded research output", id: "co-funded-results", selected:  false, number: 0}]
123
                      ,filterOperator: "or", valueIsExact: true, filterType: "checkbox", radioValue:""});
124
                  }
125
                  this.initializeFilters();
126
                  if(stakeholder.isActive && (stakeholder.isPublic || this.isPublicOrIsMember(stakeholder.isPublic))) {
127
                    this.seoService.createLinkForCanonicalURL(url, false);
128
                    this._meta.updateTag({content: url}, "property='og:url'");
129
                    var description = "Monitor Dashboard | " + this.stakeholder.name;
130
                    var title = "Monitor Dashboard | " + this.stakeholder.name;
131
                    this._meta.updateTag({content: description}, "name='description'");
132
                    this._meta.updateTag({content: description}, "property='og:description'");
133
                    this._meta.updateTag({content: title}, "property='og:title'");
134
                    this._title.setTitle(title);
135
                    if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) {
136
                      this.piwiksub = this._piwikService.trackView(this.properties, title, this.properties.piwikSiteId).subscribe();
137
                    }
138
                    //this.getDivContents();
139
                    this.getPageContents();
140
                    this.status = this.errorCodes.DONE;
141
                    this.setView(params);
142
                  } else {
143
                    this.privateStakeholder = true;
144
                    // this.navigateToError();
145
                    if(subscription) {
146
                      subscription.unsubscribe();
147
                    }
148
                  }
149
                }
150
              });
151
              this.subscriptions.push(subscription);
152
            } else {
153
              console.debug(" stakeholder is already available")
154
              this.initializeFilters();
155
              this.setView(params);
156
            }
157
          });
158
        }));
159

    
160
  }
161
  private initializeFilters(){
162
    this.periodFilter.selectedFromValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range")==0)?this.queryParams['year'].split("range")[1].split(":")[0]:"";
163
    this.periodFilter.selectedToValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range")==0)?this.queryParams['year'].split("range")[1].split(":")[1]:"";
164
    this.validateYearRange(false);
165

    
166
    for(let filter of this.filters) {
167
      if (this.queryParams[filter.filterId]) {
168
        for (let value of filter.values) {
169
          if (value.id == this.queryParams[filter.filterId]) {
170
            value.selected = true;
171
            filter.countSelectedValues = 1;
172
            break;
173
          }
174
        }
175
      }else{
176
        this.clearfFilter(filter);
177
      }
178
    }
179

    
180
  }
181
  private validateYearRange(navigateTo:boolean=false){
182
    let validYears = true;
183

    
184
    if(this.periodFilter.selectedToValue && (this.periodFilter.selectedToValue.length == 0 ||  !Dates.isValidYear(this.periodFilter.selectedToValue, Dates.currentYear - 20, Dates.currentYear))){
185
      this.periodFilter.selectedToValue = Dates.currentYear+"";
186
      validYears = false;
187
    }
188
    if( this.periodFilter.selectedFromValue && (this.periodFilter.selectedFromValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedFromValue, Dates.currentYear - 20, Dates.currentYear))){
189
      this.periodFilter.selectedFromValue = Dates.currentYear - 20+"";
190
      validYears = false;
191
    }
192
    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)){
193
      this.periodFilter.selectedFromValue = this.periodFilter.selectedToValue;
194
      validYears = false;
195
    }
196
    if(!validYears || navigateTo){
197
      if(this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue){
198
        this.queryParams["year"]='range'+(this.periodFilter.selectedFromValue?this.periodFilter.selectedFromValue:'')+":"+(this.periodFilter.selectedToValue?this.periodFilter.selectedToValue:"");
199
      }else{
200
         delete this.queryParams["year"];
201
      }
202
      // this.location.go(location.pathname, this.routerHelper.createQueryParamsString( Object.keys(this.queryParams), Object.values(this.queryParams)));
203
      this.router.navigate([], {queryParams: this.queryParams });
204
      this.setIndicators();
205
    }
206
  }
207
  clearAll(){
208
    for(let filter of this.filters) {
209
      this.clearfFilter(filter);
210
    }
211
    this.periodFilter.selectedFromValue = "";
212
    this.periodFilter.selectedToValue = "";
213
    this.validateYearRange(true)
214
  }
215
  clearfFilter(filter:Filter){
216
    filter.countSelectedValues = 0;
217
    filter.radioValue = "";
218
    for (let value of filter.values) {
219
      if (value.selected) {
220
        value.selected = false;
221
      }
222
    }
223
    if (this.queryParams[filter.filterId]) {
224
      delete this.queryParams[filter.filterId];
225
    }
226
  }
227
  countSelectedFilters():number{
228
    let count = 0;
229
    if(this.periodFilter.selectedFromAndToValues.length > 0){
230
      count+=2;
231
    }
232
    for(let filter of this.filters) {
233
      count +=filter.countSelectedValues;
234
    }
235
    return count;
236
  }
237
  public get open() {
238
    return this.layoutService.open;
239
  }
240

    
241
  private getPageContents() {
242
    this.helper.getPageHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
243
      this.pageContents = contents;
244
    })
245
  }
246

    
247
  private getDivContents() {
248
    this.helper.getDivHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
249
      this.divContents = contents;
250
    })
251
  }
252

    
253
  private setView(params: Params) {
254
    this.loading = false;
255
    if (params['topic']) {
256
      this.activeTopic = this.stakeholder.topics.find(topic => topic.alias === decodeURIComponent(params['topic']) && this.isPublicOrIsMember(topic.isPublic) && topic.isActive);
257
      if (this.activeTopic) {
258
        if (params['category']) {
259
          this.activeCategory = this.activeTopic.categories.find(category =>
260
            (category.alias === params['category']) && this.isPublicOrIsMember(category.isPublic) && category.isActive);
261
          if (!this.activeCategory) {
262
            this.navigateToError();
263
            return;
264
          }
265
        } else {
266
          this.activeCategory = this.activeTopic.categories.find(category => this.isPublicOrIsMember(category.isPublic) && category.isActive);
267
          if (this.activeCategory) {
268
            this.activeSubCategory = this.activeCategory.subCategories.find(subCategory =>
269
              this.isPublicOrIsMember(subCategory.isPublic) && subCategory.isActive);
270
            if (this.activeSubCategory) {
271
              this.setIndicators();
272
            }
273
          }
274
          return;
275
        }
276
        if (this.activeCategory) {
277
          if (params['subCategory']) {
278
            this.activeSubCategory = this.activeCategory.subCategories.find(subCategory =>
279
              (subCategory.alias === params['subCategory'] && this.isPublicOrIsMember(subCategory.isPublic) && subCategory.isActive));
280
            if (!this.activeSubCategory) {
281
              this.navigateToError();
282
              return;
283
            }
284
          } else {
285
            this.activeSubCategory = this.activeCategory.subCategories.find(subCategory =>
286
              this.isPublicOrIsMember(subCategory.isPublic) && subCategory.isActive);
287
          }
288
          if (this.activeSubCategory) {
289
            this.setIndicators();
290
          } else {
291
            this.navigateToError();
292
          }
293
          return;
294
        } else {
295
          this.activeSubCategory = null;
296
        }
297
      } else {
298
        this.navigateToError();
299
        return;
300
      }
301
    } else {
302
      this.activeTopic = this.stakeholder.topics.find(topic => this.isPublicOrIsMember(topic.isPublic) && topic.isActive);
303
      if (this.activeTopic) {
304
        this.activeCategory = this.activeTopic.categories.find(category => this.isPublicOrIsMember(category.isPublic) && category.isActive);
305
        if (this.activeCategory) {
306
          this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.isPublicOrIsMember(subCategory.isPublic) && subCategory.isActive);
307
          if (this.activeSubCategory) {
308
            this.setIndicators();
309
          }
310
        }
311
      }
312
    }
313
  }
314

    
315
  filter(){
316
    this.validateYearRange(true);
317
  }
318
  filterChanged($event, navigate:boolean = true) {
319
    let selected = "";
320
    for(let value of $event.value.values){
321
      if(value.selected){
322
        selected = value.id;
323
        break;
324
      }
325
    }
326
    if(selected){
327
      this.queryParams[$event.value.filterId]=selected;
328
    }else{
329
      delete this.queryParams[$event.value.filterId];
330
    }
331
    if(navigate) {
332
      this.router.navigate([], {queryParams: this.queryParams  });
333
      this.setIndicators();
334
    }
335

    
336
  }
337
  private getfl0(){
338
    if (this.queryParams["relfundinglevel0_id"] && this.filters.length > 0){
339
      return this.queryParams["relfundinglevel0_id"].split("::")[this.queryParams["relfundinglevel0_id"].split("::").length -1];
340
    }
341
    return null;
342
  }
343
  private getCoFunded(){
344
    if (this.queryParams["co-funded"] && this.filters.length > 0){
345
      return this.queryParams["co-funded"] && this.queryParams["co-funded"]=="co-funded-results";
346
    }
347
    return false;
348
  }
349
    clearPeriodFilter(){
350
    if(this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue){
351
      this.periodFilter.selectedFromValue = "";
352
      this.periodFilter.selectedToValue = "";
353
      this.filter();
354
    }
355

    
356
  }
357
  private setIndicators() {
358
    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:"") +
359
      (this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue?" - ":"")+ (this.periodFilter.selectedToValue?this.periodFilter.selectedToValue:"")):"");
360
    //clear numbers when filters change
361
    this.numberResults.clear();
362
    let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>();
363
    this.activeSubCategory.numbers.forEach((section, i) => {
364
      section.indicators.forEach((number, j) => {
365
        if (number.isActive && this.isPublicOrIsMember(number.isPublic)) {
366
          let url =this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, number.indicatorPaths[0], this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded());
367
          const pair = JSON.stringify([number.indicatorPaths[0].source, url]);
368
          const indexes = urls.get(pair) ? urls.get(pair) : [];
369
          indexes.push([i, j]);
370
          urls.set(pair, indexes);
371
        }
372
      });
373
    });
374
    urls.forEach((indexes, pair) => {
375
      pair = JSON.parse(pair);
376
      this.statisticsService.getNumbers(this.statisticsService.getSourceType(pair[0]),  pair[1]).subscribe(response => {
377
        indexes.forEach(([i, j]) => {
378
          let result = JSON.parse(JSON.stringify(response));
379
          this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => {
380
            if (result) {
381
              result = result[jsonPath];
382
            }
383
          });
384
          this.numberResults.set(i + '-' + j, result);
385
        });
386
      })
387
    });
388
    this.activeSubCategory.charts.forEach((section, i) => {
389
      section.indicators.forEach((indicator, j) => {
390
        if (indicator.indicatorPaths.length > 0) {
391
          indicator.indicatorPaths[0].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[0]);
392
          this.chartsActiveType.set(i + '-' + j, indicator.indicatorPaths[0]);
393
        }
394
      });
395
    });
396
    if (this.cdr && !(this.cdr as ViewRef).destroyed) {
397
      this.cdr.detectChanges();
398
    }
399
  }
400

    
401
  public getUrlByStakeHolder(indicatorPath: IndicatorPath) {
402
    return this.sanitizer.bypassSecurityTrustResourceUrl(
403
      this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath,  this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded())));
404
  }
405

    
406
  public setActiveChart(i: number, j: number, type: string) {
407
    let activeChart = this.activeSubCategory.charts[i].indicators[j].indicatorPaths.filter(indicatorPath => indicatorPath.type === type)[0];
408
    activeChart.safeResourceUrl = this.getUrlByStakeHolder(activeChart);
409
    this.chartsActiveType.set(i + '-' + j, activeChart);
410
  }
411

    
412
  private navigateToError() {
413
    this._router.navigate(['/error'], {queryParams: {'page': this._router.url}});
414
  }
415

    
416
  public navigateTo(stakeholder: string, topic: string, category: string = null, subcategory: string = null) {
417
    let url = stakeholder + '/' + topic + ((category) ? ('/'
418
      + category) : '') + ((subcategory) ? ('/' + subcategory) : '');
419
    return this._router.navigate([url],{ queryParams: this.queryParams});
420
  }
421

    
422
  public quote(param: string): string {
423
    return StringUtils.quote(param);
424
  }
425

    
426
  public ngOnDestroy() {
427
    if (this.piwiksub) {
428
      this.piwiksub.unsubscribe();
429
    }
430
  }
431

    
432
  isAdmin(){
433
    return this.user && (Session.isPortalAdministrator(this.user) || Session.isCommunityCurator(this.user) || Session.isMonitorCurator(this.user));
434
  }
435

    
436
  public isPublicOrIsMember(isPublic: boolean): boolean {
437
    if (isPublic) {
438
      return true;
439
    } else {
440
      if (this.isViewPublic) { // preview for not members
441
        return false;
442
      } else if(this.isAdmin()) {
443
        // if user is member, return true
444
        return true;
445
      }
446
      return false;
447
    }
448
  }
449
  public countSubCategoriesToShow(category:Category): number {
450
    let counter = 0;
451
    for (let sub of category.subCategories) {
452
      if(sub.isActive) {
453
        if (sub.isPublic) {
454
          // return true;
455
          counter++;
456
        }else if (this.isAdmin()) {
457
          counter++;
458
        }
459
      }
460
    }
461
    return counter;
462
  }
463
  /*
464
  Feedback mail
465
   */
466
  public get mailText() {
467
    return "mailto:"+this.properties.feedbackmail+"?subject=%5BOpenAIRE%20Monitor%5D%20"+(this.stakeholder?this.stakeholder.name:"")+"%20dashboard%20feedback"
468
  }
469
  mailMe(){
470
    window.location.href = this.mailText;
471
  }
472
}
(4-4/5)