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 {
14
  Category,
15
  IndicatorPath,
16
  Stakeholder,
17
  SubCategory,
18
  Topic,
19
  Visibility
20
} from "../openaireLibrary/monitor/entities/stakeholder";
21
import {StatisticsService} from "../utils/services/statistics.service";
22
import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils";
23
import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
24
import {FormBuilder, FormControl} from "@angular/forms";
25
import {Subscription} from "rxjs";
26
import {Session, User} from "../openaireLibrary/login/utils/helper.class";
27
import {UserManagementService} from "../openaireLibrary/services/user-management.service";
28
import {RangeFilter} from "../openaireLibrary/utils/rangeFilter/rangeFilterHelperClasses.class";
29
import {Filter, Value} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class";
30
import {Location} from "@angular/common";
31
import {RouterHelper} from "../openaireLibrary/utils/routerHelper.class";
32
import {properties} from "../../environments/environment";
33

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

    
86
  public ngOnInit() {
87
    this.keyword = this._fb.control('');
88
    this.keyword.valueChanges.subscribe(value => {
89
      console.log("Keyword Changed!");
90
      //TODO do a real action
91
    });
92
        let subscription: Subscription;
93
        this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
94
          this.user = user;
95

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

    
167
  }
168
  private initializeFilters(){
169
    this.periodFilter.selectedFromValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range")==0)?this.queryParams['year'].split("range")[1].split(":")[0]:"";
170
    this.periodFilter.selectedToValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range")==0)?this.queryParams['year'].split("range")[1].split(":")[1]:"";
171
    this.validateYearRange(false);
172

    
173
    for(let filter of this.filters) {
174
      if (this.queryParams[filter.filterId]) {
175
        for (let value of filter.values) {
176
          if (value.id == this.queryParams[filter.filterId]) {
177
            value.selected = true;
178
            filter.countSelectedValues = 1;
179
            break;
180
          }
181
        }
182
      }else{
183
        this.clearfFilter(filter);
184
      }
185
    }
186

    
187
  }
188
  private validateYearRange(navigateTo:boolean=false){
189
    let validYears = true;
190

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

    
248
  private getPageContents() {
249
    this.helper.getPageHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
250
      this.pageContents = contents;
251
    })
252
  }
253

    
254
  private getDivContents() {
255
    this.helper.getDivHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
256
      this.divContents = contents;
257
    })
258
  }
259

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

    
322
  filter(){
323
    this.validateYearRange(true);
324
  }
325
  filterChanged($event, navigate:boolean = true) {
326
    let selected = "";
327
    for(let value of $event.value.values){
328
      if(value.selected){
329
        selected = value.id;
330
        break;
331
      }
332
    }
333
    if(selected){
334
      this.queryParams[$event.value.filterId]=selected;
335
    }else{
336
      delete this.queryParams[$event.value.filterId];
337
    }
338
    if(navigate) {
339
      this.router.navigate([], {queryParams: this.queryParams  });
340
      this.setIndicators();
341
    }
342

    
343
  }
344
  private getfl0(){
345
    if (this.queryParams["relfundinglevel0_id"] && this.filters.length > 0){
346
      return this.queryParams["relfundinglevel0_id"].split("::")[this.queryParams["relfundinglevel0_id"].split("::").length -1];
347
    }
348
    return null;
349
  }
350
  private getCoFunded(){
351
    if (this.queryParams["co-funded"] && this.filters.length > 0){
352
      return this.queryParams["co-funded"] && this.queryParams["co-funded"]=="co-funded-results";
353
    }
354
    return false;
355
  }
356
    clearPeriodFilter(){
357
    if(this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue){
358
      this.periodFilter.selectedFromValue = "";
359
      this.periodFilter.selectedToValue = "";
360
      this.filter();
361
    }
362

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

    
408
  public getUrlByStakeHolder(indicatorPath: IndicatorPath) {
409
    return this.sanitizer.bypassSecurityTrustResourceUrl(
410
      this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath,  this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded())));
411
  }
412

    
413
  public setActiveChart(i: number, j: number, type: string) {
414
    let activeChart = this.activeSubCategory.charts[i].indicators[j].indicatorPaths.filter(indicatorPath => indicatorPath.type === type)[0];
415
    activeChart.safeResourceUrl = this.getUrlByStakeHolder(activeChart);
416
    this.chartsActiveType.set(i + '-' + j, activeChart);
417
  }
418

    
419
  private navigateToError() {
420
    this._router.navigate(['/error'], {queryParams: {'page': this._router.url}});
421
  }
422

    
423
  public navigateTo(stakeholder: string, topic: string, category: string = null, subcategory: string = null) {
424
    let url = stakeholder + '/' + topic + ((category) ? ('/'
425
      + category) : '') + ((subcategory) ? ('/' + subcategory) : '');
426
    return this._router.navigate([url],{ queryParams: this.queryParams});
427
  }
428

    
429
  public quote(param: string): string {
430
    return StringUtils.quote(param);
431
  }
432

    
433
  public ngOnDestroy() {
434
    if (this.piwiksub) {
435
      this.piwiksub.unsubscribe();
436
    }
437
  }
438

    
439
  isAdmin(){
440
    return this.user && (Session.isPortalAdministrator(this.user) || Session.isCommunityCurator(this.user) || Session.isMonitorCurator(this.user));
441
  }
442

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