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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
438
  public isPublicOrIsMember(visibility: Visibility): boolean {
439
    if(visibility == "PRIVATE" || (this.isViewPublic && visibility != "PUBLIC")) {
440
      return false;
441
    }
442
    return true;
443
  }
444
  public countSubCategoriesToShow(category:Category): number {
445
    let counter = 0;
446
    for (let sub of category.subCategories) {
447
      if(this.isPublicOrIsMember(sub.visibility)) {
448
        counter++;
449
      }
450
    }
451
    return counter;
452
  }
453
  /*
454
  Feedback mail
455
   */
456
  public get mailText() {
457
    return "mailto:"+this.properties.feedbackmail+"?subject=%5BOpenAIRE%20Monitor%5D%20"+(this.stakeholder?this.stakeholder.name:"")+"%20dashboard%20feedback"
458
  }
459
  mailMe(){
460
    window.location.href = this.mailText;
461
  }
462
}
(4-4/5)