Project

General

Profile

1
import {
2
  AfterViewInit,
3
  ChangeDetectorRef,
4
  Component,
5
  Input,
6
  OnChanges,
7
  OnDestroy,
8
  OnInit,
9
  SimpleChanges,
10
  ViewChild
11
} from "@angular/core";
12
import {Indicator, IndicatorPath, IndicatorType, Section, Stakeholder} from "../openaireLibrary/monitor/entities/stakeholder";
13
import {IndicatorUtils} from "../utils/indicator-utils";
14
import {FormArray, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
15
import {AlertModal} from "../openaireLibrary/utils/modal/alert";
16
import {StatisticsService} from "../utils/services/statistics.service";
17
import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class";
18
import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser";
19
import {StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service";
20
import {EnvProperties} from "../openaireLibrary/utils/properties/env-properties";
21
import {Subscriber} from "rxjs";
22
import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
23
import {Option} from "../openaireLibrary/dashboard/sharedComponents/input/input.component";
24
import {Router} from "@angular/router";
25
import {Session} from "../openaireLibrary/login/utils/helper.class";
26
import {UserManagementService} from "../openaireLibrary/services/user-management.service";
27

    
28
declare var UIkit;
29

    
30
@Component({
31
  selector: 'indicators',
32
  templateUrl: './indicators.component.html'
33
})
34
export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
35
  
36
  @Input()
37
  public properties: EnvProperties = null;
38
  @Input()
39
  public topicIndex: number = 0;
40
  @Input()
41
  public categoryIndex: number = 0;
42
  @Input()
43
  public subcategoryIndex: number = 0;
44
  @Input()
45
  public stakeholder: Stakeholder = null;
46
  public user = null;
47
  public preview: string;
48
  public indicatorUtils: IndicatorUtils = new IndicatorUtils();
49
  public numberIndicatorFb: FormGroup;
50
  public chartIndicatorFb: FormGroup;
51
  public chartSections: FormArray;
52
  public numberSections: FormArray;
53
  /**
54
   * Editable indicator
55
   */
56
  public section: Section;
57
  public indicator: Indicator;
58
  public index: number = -1;
59
  /**
60
   * Displayed chart and numbers base on Top filters
61
   */
62
  public displayCharts: Section[] = [];
63
  public displayNumbers: Section[] = [];
64
  /**
65
   * Top filters
66
   */
67
  public filters: FormGroup;
68
  public all: Option = {
69
    value: 'all',
70
    label: 'All'
71
  };
72
  /**
73
   * Toggles
74
   */
75
  public grid: boolean = true;
76
  private reordering: boolean = false;
77
  /** Safe Urls*/
78
  public safeUrls: Map<string, SafeResourceUrl> = new Map<string, SafeResourceUrl>([]);
79
  
80
  private subscriptions: any[] = [];
81
  private urlSubscriptions: any[] = [];
82
  @ViewChild('editChartModal') editChartModal: AlertModal;
83
  @ViewChild('editNumberModal') editNumberModal: AlertModal;
84
  @ViewChild('deleteModal') deleteModal: AlertModal;
85
  @ViewChild('deleteChartSectionModal') deleteChartSectionModal: AlertModal;
86
  @ViewChild('deleteNumberSectionModal') deleteNumberSectionModal: AlertModal;
87
  
88
  urlParameterizedMessage = "";
89
  constructor(private layoutService: LayoutService,
90
              private stakeholderService: StakeholderService,
91
              private statisticsService: StatisticsService,
92
              private userManagementService: UserManagementService,
93
              private fb: FormBuilder,
94
              private router: Router,
95
              private cdr: ChangeDetectorRef,
96
              private sanitizer: DomSanitizer) {
97
  }
98
  
99
  ngOnInit(): void {
100
    this.userManagementService.getUserInfo().subscribe(user => {
101
      this.user = user;
102
    });
103
    this.buildFilters();
104
    this.buildSections();
105
  }
106
  
107
  ngOnDestroy(): void {
108
    this.subscriptions.forEach(value => {
109
      if (value instanceof Subscriber) {
110
        value.unsubscribe();
111
      } else if (value instanceof Function) {
112
        value();
113
      }
114
    });
115
  }
116
  
117
  ngAfterViewInit(): void {
118
    this.initReorder();
119
  }
120
  
121
  ngOnChanges(changes: SimpleChanges): void {
122
    if (this.canEdit) {
123
      if (changes.topicIndex || changes.categoryIndex || changes.subcategoryIndex) {
124
        this.buildFilters();
125
      }
126
      this.filterCharts();
127
      this.filterNumbers();
128
    }
129
    this.preview = '/' + this.stakeholder.alias + '/' + this.stakeholder.topics[this.topicIndex].alias;
130
    if(this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]) {
131
      this.preview += '/' + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].alias;
132
      if(this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
133
        this.preview += '/' + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].alias;
134
      }
135
    }
136
  }
137
  
138
  initReorder() {
139
    this.subscriptions.forEach(value => {
140
      if (value instanceof Function) {
141
        value();
142
      }
143
    });
144
    if (document !== undefined) {
145
      let callback = (list, type: IndicatorType): void => {
146
        let items: HTMLCollection = list.current.children;
147
        let reordered = [];
148
        for (let i = 0; i < items.length; i++) {
149
          if (items.item(i).id) {
150
            reordered.push(items.item(i).id);
151
          }
152
        }
153
        this.reordering = true;
154
        this.reorderIndicators(list.current.id.toString().split('-')[1], type, reordered);
155
      };
156
      this.numbers.forEach((section) => {
157
        this.subscriptions.push(UIkit.util.on(document, 'moved', '#number-' + section._id, (list): void => {
158
          callback(list, "number");
159
        }));
160
        this.subscriptions.push(UIkit.util.on(document, 'added', '#number-' + section._id, (list): void => {
161
          callback(list, "number");
162
        }));
163
        this.subscriptions.push(UIkit.util.on(document, 'removed', '#number-' + section._id, (list): void => {
164
          callback(list, "number");
165
        }));
166
      });
167
      this.charts.forEach((section) => {
168
        this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => {
169
          callback(list, "chart");
170
        }));
171
        this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => {
172
          callback(list, "chart");
173
        }));
174
        this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => {
175
          callback(list, "chart");
176
        }));
177
      });
178
    }
179
  }
180
  
181
  hide(element: any) {
182
    UIkit.dropdown(element).hide();
183
  }
184
  
185
  public changeGrid(value) {
186
    this.grid = value;
187
  }
188
  
189
  private buildFilters() {
190
    this.filters = this.fb.group({
191
      chartType: this.fb.control('all'),
192
      privacy: this.fb.control('all'),
193
      status: this.fb.control('all'),
194
      keyword: this.fb.control('')
195
    });
196
    this.subscriptions.push(this.filters.get('chartType').valueChanges.subscribe(value => {
197
      this.onChartTypeChange(value);
198
    }));
199
    this.subscriptions.push(this.filters.get('privacy').valueChanges.subscribe(value => {
200
      this.onPrivacyChange(value);
201
    }));
202
    this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => {
203
      this.onStatusChange(value);
204
    }));
205
    this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => {
206
      this.onKeywordChange(value);
207
    }));
208
  }
209
  
210
  private buildSections() {
211
    this.numberSections = this.fb.array([]);
212
    this.numbers.forEach(section => {
213
      this.numberSections.push(this.fb.group({
214
        _id: this.fb.control(section._id),
215
        title: this.fb.control(section.title),
216
        stakeholderAlias: this.fb.control(section.stakeholderAlias),
217
        defaultId: this.fb.control(section.defaultId),
218
        type: this.fb.control(section.type),
219
        indicators: this.fb.control(section.indicators)
220
      }));
221
    });
222
    this.chartSections = this.fb.array([]);
223
    this.charts.forEach(section => {
224
      this.chartSections.push(this.fb.group({
225
        _id: this.fb.control(section._id),
226
        title: this.fb.control(section.title),
227
        stakeholderAlias: this.fb.control(section.stakeholderAlias),
228
        defaultId: this.fb.control(section.defaultId),
229
        type: this.fb.control(section.type),
230
        indicators: this.fb.control(section.indicators)
231
      }));
232
    });
233
  }
234
  
235
  filterCharts() {
236
    this.displayCharts = this.filterChartType(this.filterPrivacy(
237
      this.filterStatus(this.filterByKeyword(HelperFunctions.copy(this.charts), this.filters.value.keyword),
238
        this.filters.value.status),
239
      this.filters.value.privacy),
240
      this.filters.value.chartType
241
    );
242
    this.displayCharts.forEach(section => {
243
      section.indicators.forEach(indicator => {
244
        indicator.indicatorPaths.forEach(indicatorPath => {
245
          let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath);
246
          if (!this.safeUrls.get('url')) {
247
            indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
248
            this.safeUrls.set(url, indicatorPath.safeResourceUrl);
249
          }
250
        });
251
      })
252
    });
253
    this.buildSections();
254
  }
255
  
256
  filterNumbers() {
257
    this.displayNumbers = this.filterPrivacy(this.filterStatus(
258
      this.filterByKeyword(HelperFunctions.copy(this.numbers), this.filters.value.keyword),
259
      this.filters.value.status),
260
      this.filters.value.privacy);
261
    console.log(this.numbers);
262
    this.buildSections();
263
  }
264
  
265
  onChartTypeChange(value) {
266
    this.displayCharts = this.filterChartType(HelperFunctions.copy(this.charts), value);
267
  }
268
  
269
  onPrivacyChange(value) {
270
    this.displayCharts = this.filterPrivacy(HelperFunctions.copy(this.charts), value);
271
    this.displayNumbers = this.filterPrivacy(HelperFunctions.copy(this.numbers), value);
272
  }
273
  
274
  onStatusChange(value) {
275
    this.displayCharts = this.filterStatus(HelperFunctions.copy(this.charts), value);
276
    this.displayNumbers = this.filterStatus(HelperFunctions.copy(this.numbers), value);
277
  }
278
  
279
  onKeywordChange(value) {
280
    this.displayCharts = this.filterByKeyword(HelperFunctions.copy(this.charts), value);
281
    this.displayNumbers = this.filterByKeyword(HelperFunctions.copy(this.numbers), value);
282
  }
283
  
284
  private filterChartType(sections: Section[], value): Section[] {
285
    if (value !== 'all') {
286
      sections.forEach(section =>
287
        section.indicators = section.indicators.filter(indicator =>
288
          indicator.indicatorPaths.filter(indicatorPath => indicatorPath.type === value).length > 0));
289
    }
290
    return sections;
291
  }
292
  
293
  private filterPrivacy(sections: Section[], value): Section[] {
294
    if (value !== 'all') {
295
      sections.forEach(section =>
296
        section.indicators = section.indicators.filter(indicator => indicator.isPublic === value));
297
    }
298
    return sections;
299
  }
300
  
301
  private filterStatus(sections: Section[], value): Section[] {
302
    if (value !== 'all') {
303
      sections.forEach(section =>
304
        section.indicators = section.indicators.filter(indicator => indicator.isActive === value));
305
    }
306
    return sections;
307
  }
308
  
309
  private filterByKeyword(sections: Section[], value): Section[] {
310
    if (value !== null && value !== '') {
311
      sections.forEach(section =>
312
        section.indicators = section.indicators.filter(indicator => (indicator.name && indicator.name.toLowerCase().includes(value.toLowerCase()))
313
          || (indicator.description && indicator.description.toLowerCase().includes(value.toLowerCase()))
314
          || indicator.indicatorPaths.filter(indicatorPath => (indicatorPath.parameters && indicatorPath.parameters.title &&
315
            indicatorPath.parameters.title.includes(value.toLowerCase()))).length > 0));
316
    }
317
    return sections;
318
  }
319
  
320
  get charts(): Section[] {
321
    if (this.stakeholder.topics[this.topicIndex] &&
322
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
323
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
324
      return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts;
325
    } else {
326
      return [];
327
    }
328
  }
329
  
330
  set charts(sections: Section[]) {
331
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts = sections;
332
  }
333
  
334
  get numbers(): Section[] {
335
    if (this.stakeholder.topics[this.topicIndex] &&
336
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
337
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
338
      return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers;
339
    } else {
340
      return [];
341
    }
342
  }
343
  
344
  set numbers(sections: Section[]) {
345
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = sections;
346
  }
347
  
348
  get open(): boolean {
349
    return this.layoutService.open;
350
  }
351
  
352
  get canReorder(): boolean {
353
    return this.filters.value.chartType === 'all' && this.filters.value.privacy === 'all' &&
354
      this.filters.value.status === 'all' && this.filters.value.keyword === '' && this.grid && !this.reordering;
355
  }
356
  
357
  get canEdit() {
358
    return this.stakeholder &&
359
      this.stakeholder.topics[this.topicIndex] &&
360
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
361
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex];
362
  }
363
  
364
  public get numberIndicatorPaths(): FormArray {
365
    return this.numberIndicatorFb.get('indicatorPaths') as FormArray;
366
  }
367
  
368
  public get chartIndicatorPaths(): FormArray {
369
    return this.chartIndicatorFb.get('indicatorPaths') as FormArray;
370
  }
371
  
372
  public addJsonPath(index: number) {
373
    this.getJsonPath(index).push(this.fb.control('', Validators.required));
374
  }
375
  
376
  public removeJsonPath(i: number, j:number) {
377
    this.getJsonPath(i).removeAt(j);
378
  }
379
  
380
  public getJsonPath(index: number): FormArray {
381
    return this.numberIndicatorPaths.at(index).get('jsonPath') as FormArray;
382
  }
383
  
384
  public getParameters(index: number): FormArray {
385
    return this.chartIndicatorPaths.at(index).get('parameters') as FormArray;
386
  }
387
  
388
  public getParameter(index: number, key: string): FormControl {
389
    return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as FormControl;
390
  }
391
  
392
  private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) {
393
    return this.sanitizer.bypassSecurityTrustResourceUrl(
394
      this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)));
395
  }
396
  
397
  private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
398
    return this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath));
399
  }
400
  
401
  public addNumberIndicatorPath(url: string = '', source: string = 'search', jsonPath: FormArray = new FormArray([])) {
402
    if(jsonPath.length === 0) {
403
      jsonPath.push(this.fb.control('', Validators.required));
404
    }
405
    this.numberIndicatorPaths.push(this.fb.group({
406
        url: this.fb.control(url, Validators.required),
407
        jsonPath: jsonPath,
408
        source: this.fb.control(source, Validators.required)
409
      }
410
    ));
411

    
412
    for(let index = 0; index < this.numberIndicatorPaths.length; index++) {
413
      this.subscriptions.push(this.numberIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
414
          if (this.numberIndicatorPaths.at(index).get('url').valid) {
415
            let indicatorPath: IndicatorPath = this.indicatorUtils.parseNumberIndicatortUrl(this.numberIndicatorPaths.at(index).get('source').value, value, this.stakeholder);
416
            // if(indicatorPath.url.indexOf("index_id") ==-1 &&  indicatorPath.url.indexOf("index_name") ==-1  && (indicatorPath.url).indexOf("index_shortName") ==-1 ){
417
            //
418
            // }else {
419
            //   this.urlParameterizedMessage = "";
420
            // }
421
            if(value != indicatorPath.url) {
422
              (this.numberIndicatorPaths.at(index) as FormGroup).get('url').setValue( indicatorPath.url);
423
            }
424
              this.indicator.indicatorPaths[index] = indicatorPath;
425
          }
426
        })
427
      );
428
    }
429
  }
430
  
431
  public addChartIndicatorPath(value: string = '', parameters: FormArray = new FormArray([]), disableUrl: boolean = false, type:string=null) {
432
    this.chartIndicatorPaths.push(this.fb.group({
433
        url: this.fb.control(value, [Validators.required,
434
          Validators.pattern('https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.' +
435
            '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.' +
436
            '[a-zA-Z0-9]+\.[^\s]{2,}')]),
437
        parameters: parameters,
438
        type: this.fb.control(type)
439
      }
440
    ));
441
    if(disableUrl) {
442
      for(let index = 0; index < this.chartIndicatorPaths.length; index++) {
443
        this.chartIndicatorPaths.at(index).get('url').disable();
444
      }
445
    } else {
446
      for(let index = 0; index < this.chartIndicatorPaths.length; index++) {
447
        this.urlSubscriptions.push(this.chartIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
448
            if (this.chartIndicatorPaths.at(index).get('url').valid) {
449
              let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder);
450
              if(indicatorPath.chartObject && Object.keys(indicatorPath.parameters).indexOf("index_id") ==-1 && Object.keys(indicatorPath.parameters).indexOf("index_name") ==-1  && Object.keys(indicatorPath.parameters).indexOf("index_shortName") ==-1 ){
451
                // default profile
452
                if(this.stakeholder.defaultId == null){
453
                  this.urlParameterizedMessage = "This chart couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly."
454
                }else{
455
                  this.urlParameterizedMessage = "This chart couldn't be generated properly. Please make sure chart data is for the current stakeholder."
456
                }
457
              }else {
458
                this.urlParameterizedMessage = "";
459
              }
460
              (this.chartIndicatorPaths.at(index) as FormGroup).get('type').setValue(indicatorPath.type);
461
              let parameters = this.getParametersAsFormArray(indicatorPath);
462
              (this.chartIndicatorPaths.at(index) as FormGroup).setControl('parameters', parameters);
463
              if (!this.indicator.indicatorPaths[index]) {
464
                this.indicator.indicatorPaths[index] = indicatorPath;
465
                this.indicator.indicatorPaths[index].safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
466
              } else {
467
                indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl;
468
                this.indicator.indicatorPaths[index] = indicatorPath;
469
              }
470
            }
471
          })
472
        );
473
      }
474
    }
475
  }
476
  
477
  private getJsonPathAsFormArray(indicatorPath: IndicatorPath): FormArray {
478
    let jsonPath = this.fb.array([]);
479
    if (indicatorPath.jsonPath) {
480
      indicatorPath.jsonPath.forEach(path => {
481
        jsonPath.push(this.fb.control(path, Validators.required));
482
      });
483
    }
484
    return jsonPath;
485
  }
486
  
487
  private getParametersAsFormArray(indicatorPath: IndicatorPath): FormArray {
488
    let parameters = this.fb.array([]);
489
    if (indicatorPath.parameters) {
490
      Object.keys(indicatorPath.parameters).forEach(key => {
491
        if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) {
492
          if (this.indicatorUtils.parametersValidators.has(key)) {
493
            parameters.push(this.fb.group({
494
              key: this.fb.control(key),
495
              value: this.fb.control(indicatorPath.parameters[key], this.indicatorUtils.parametersValidators.get(key))
496
            }));
497
          } else {
498
            parameters.push(this.fb.group({
499
              key: this.fb.control(key),
500
              value: this.fb.control(indicatorPath.parameters[key])
501
            }));
502
          }
503
        }
504
      });
505
    }
506
    return parameters;
507
  }
508
  
509
  public editNumberIndicatorOpen(section: Section, id = null) {
510
    this.section = section;
511
    this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1;
512
    if (this.index !== -1) {
513
      this.indicator = HelperFunctions.copy(this.section.indicators[this.index]);
514
      this.numberIndicatorFb = this.fb.group({
515
        _id: this.fb.control(this.indicator._id),
516
        name: this.fb.control(this.indicator.name),
517
        description: this.fb.control(this.indicator.description),
518
        isPublic: this.fb.control(this.indicator.isPublic),
519
        isActive: this.fb.control(this.indicator.isActive),
520
        indicatorPaths: this.fb.array([], Validators.required),
521
        type: this.fb.control(this.indicator.type),
522
        width: this.fb.control(this.indicator.width),
523
        defaultId: this.fb.control(this.indicator.defaultId)
524
      });
525
      this.indicator.indicatorPaths.forEach(indicatorPath => {
526
        this.addNumberIndicatorPath(indicatorPath.url, indicatorPath.source, this.getJsonPathAsFormArray(indicatorPath));
527
      });
528
    } else {
529
      this.indicator = new Indicator('', '', 'number', 'small', true, true, []);
530
      this.numberIndicatorFb = this.fb.group({
531
        _id: this.fb.control(this.indicator._id),
532
        name: this.fb.control(this.indicator.name),
533
        description: this.fb.control(this.indicator.description),
534
        isPublic: this.fb.control(this.indicator.isPublic),
535
        isActive: this.fb.control(this.indicator.isActive),
536
        indicatorPaths: this.fb.array([], Validators.required),
537
        type: this.fb.control(this.indicator.type),
538
        width: this.fb.control(this.indicator.width),
539
        defaultId: this.fb.control(this.indicator.defaultId)
540
      });
541
      this.addNumberIndicatorPath();
542
    }
543
    this.editNumberModal.cancelButtonText = 'Cancel';
544
    this.editNumberModal.okButtonLeft = false;
545
    this.editNumberModal.alertMessage = false;
546
    if (this.index === -1) {
547
      this.editNumberModal.alertTitle = 'Create a new number indicator';
548
      this.editNumberModal.okButtonText = 'Save';
549
    } else {
550
      this.editNumberModal.alertTitle = 'Edit number indicator\'s information';
551
      this.editNumberModal.okButtonText = 'Save Changes';
552
    }
553
    this.editNumberModal.open();
554
  }
555
  
556
  public editChartIndicatorOpen(section: Section, id = null) {
557
    this.urlParameterizedMessage = "";
558
    this.urlSubscriptions.forEach(value => {
559
      if (value instanceof Subscriber) {
560
        value.unsubscribe();
561
      }
562
    });
563
    this.section = section;
564
    this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1;
565
    if (this.index !== -1) {
566
      this.indicator = HelperFunctions.copy(this.section.indicators[this.index]);
567
      this.chartIndicatorFb = this.fb.group({
568
        _id: this.fb.control(this.indicator._id),
569
        name: this.fb.control(this.indicator.name),
570
        description: this.fb.control(this.indicator.description),
571
        isPublic: this.fb.control(this.indicator.isPublic),
572
        isActive: this.fb.control(this.indicator.isActive),
573
        indicatorPaths: this.fb.array([]),
574
        width: this.fb.control(this.indicator.width),
575
        defaultId: this.fb.control(this.indicator.defaultId)
576
      });
577
      this.indicator.indicatorPaths.forEach(indicatorPath => {
578
        this.addChartIndicatorPath(this.getUrlByStakeHolder(indicatorPath),
579
          this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type);
580
        indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
581
      });
582
    } else {
583
      this.indicator = new Indicator('', '', 'chart', 'small', true, true, []);
584
      this.chartIndicatorFb = this.fb.group({
585
        _id: this.fb.control(this.indicator._id),
586
        name: this.fb.control(this.indicator.name),
587
        description: this.fb.control(this.indicator.description),
588
        isPublic: this.fb.control(this.indicator.isPublic),
589
        isActive: this.fb.control(this.indicator.isActive),
590
        indicatorPaths: this.fb.array([]),
591
        width: this.fb.control(this.indicator.width, Validators.required),
592
        defaultId: this.fb.control(this.indicator.defaultId)
593
      });
594
      this.addChartIndicatorPath();
595
    }
596
    this.editChartModal.cancelButtonText = 'Cancel';
597
    this.editChartModal.okButtonLeft = false;
598
    this.editChartModal.alertMessage = false;
599
    if (this.index === -1) {
600
      this.editChartModal.alertTitle = 'Create a new chart indicator';
601
      this.editChartModal.okButtonText = 'Save';
602
    } else {
603
      this.editChartModal.alertTitle = 'Edit chart indicator\'s information';
604
      this.editChartModal.okButtonText = 'Save Changes';
605
    }
606
    this.editChartModal.open();
607
  }
608
  
609
  saveIndicator() {
610
    if (this.indicator.type === 'chart') {
611
      this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths);
612
      this.section = this.charts.find(section => section._id === this.section._id);
613
    } else {
614
      this.indicator = this.numberIndicatorFb.value;
615
    }
616
    let path = [
617
      this.stakeholder._id,
618
      this.stakeholder.topics[this.topicIndex]._id,
619
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
620
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
621
      this.section._id
622
    ];
623
    this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.indicator, path).subscribe(indicator => {
624
      if (this.index !== -1) {
625
        this.section.indicators[this.index] = indicator;
626
      } else {
627
        this.section.indicators.push(indicator);
628
      }
629
      this.filterCharts();
630
      this.chartIndicatorFb = null;
631
      UIkit.notification('Indicator has been successfully saved', {
632
        status: 'success',
633
        timeout: 3000,
634
        pos: 'top-left'
635
      });
636
    }, error => {
637
      this.chartIndicatorFb = null;
638
      UIkit.notification(error.error.message, {
639
        status: 'danger',
640
        timeout: 3000,
641
        pos: 'top-left'
642
      });
643
    });
644
  }
645
  
646
  reorderIndicators(sectionId: string, type: IndicatorType, indicatorIds: string[]) {
647
    let path = [
648
      this.stakeholder._id,
649
      this.stakeholder.topics[this.topicIndex]._id,
650
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
651
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
652
      sectionId
653
    ];
654
    this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicatorIds, type).subscribe(indicators => {
655
      if (type === 'chart') {
656
        this.charts.find(section => section._id === sectionId).indicators = indicators;
657
        this.filterCharts();
658
      } else {
659
        this.numbers.find(section => section._id === sectionId).indicators = indicators;
660
        this.filterNumbers();
661
      }
662
      this.reordering = false;
663
    });
664
  }
665
  
666
  hasDifference(index: number): boolean {
667
    let hasDifference = false;
668
    this.chartIndicatorPaths.at(index).value.parameters.forEach((parameter) => {
669
      if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) {
670
        hasDifference = true;
671
        return;
672
      }
673
    });
674
    return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !==
675
      this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString();
676
  }
677
  
678
  public get isAdministrator(): boolean {
679
    return Session.isPortalAdministrator(this.user);
680
    // return Session.isPortalAdministrator(this.user) || Session.isMonitorCurator(this.user) || Session.isCommunityCurator(this.user)
681
  }
682
  
683
  refreshIndicator() {
684
    this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths);
685
    this.indicator.indicatorPaths.forEach(indicatorPath => {
686
      indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
687
    });
688
  }
689
  
690
  deleteIndicatorOpen(section: Section, indicatorId: string, type: string = 'chart') {
691
    this.section = section;
692
    if (type === 'chart') {
693
      this.index = this.charts.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId);
694
    } else {
695
      this.index = this.numbers.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId);
696
    }
697
    this.indicator = section.indicators.find(value => value._id == indicatorId);
698
    this.deleteModal.alertTitle = 'Delete indicator';
699
    this.deleteModal.cancelButtonText = 'No';
700
    this.deleteModal.okButtonText = 'Yes';
701
    this.deleteModal.open();
702
  }
703
  
704
  deleteIndicator() {
705
    let path = [
706
      this.stakeholder._id,
707
      this.stakeholder.topics[this.topicIndex]._id,
708
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
709
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
710
      this.section._id,
711
      this.indicator._id
712
    ];
713
    this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => {
714
      if (this.indicator.type === 'chart') {
715
        this.charts.find(section => section._id === this.section._id).indicators.splice(this.index, 1);
716
        this.filterCharts();
717
      } else {
718
        this.numbers.find(section => section._id === this.section._id).indicators.splice(this.index, 1);
719
        this.filterNumbers();
720
      }
721
      UIkit.notification('Indicator has been successfully deleted', {
722
        status: 'success',
723
        timeout: 3000,
724
        pos: 'top-left'
725
      });
726
    }, error => {
727
      UIkit.notification(error.error.message, {
728
        status: 'danger',
729
        timeout: 3000,
730
        pos: 'top-left'
731
      });
732
    });
733
  }
734
  
735
  toggleIndicatorStatus(sectionId: string, indicator: Indicator) {
736
    let path = [
737
      this.stakeholder._id,
738
      this.stakeholder.topics[this.topicIndex]._id,
739
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
740
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
741
      sectionId,
742
      indicator._id
743
    ];
744
    this.stakeholderService.toggleStatus(this.properties.monitorServiceAPIURL, path).subscribe(isActive => {
745
      indicator.isActive = isActive;
746
      UIkit.notification('Indicator has been successfully changed to ' + (isActive?'active':'inactive'), {
747
        status: 'success',
748
        timeout: 3000,
749
        pos: 'top-left'
750
      });
751
    }, error => {
752
      UIkit.notification(error.error.message, {
753
        status: 'danger',
754
        timeout: 3000,
755
        pos: 'top-left'
756
      });
757
    });
758
  }
759
  
760
  toggleIndicatorAccess(sectionId: string, indicator: Indicator) {
761
    let path = [
762
      this.stakeholder._id,
763
      this.stakeholder.topics[this.topicIndex]._id,
764
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
765
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
766
      sectionId,
767
      indicator._id
768
    ];
769
    this.stakeholderService.toggleAccess(this.properties.monitorServiceAPIURL, path).subscribe(isPublic => {
770
      indicator.isPublic = isPublic;
771
      UIkit.notification('Indicator has been successfully changed to ' + (isPublic?'public':'private'), {
772
        status: 'success',
773
        timeout: 3000,
774
        pos: 'top-left'
775
      });
776
    }, error => {
777
      UIkit.notification(error.error.message, {
778
        status: 'danger',
779
        timeout: 3000,
780
        pos: 'top-left'
781
      });
782
    });
783
  }
784
  
785
  saveSection(section: Section, index: number, type: IndicatorType = "chart") {
786
    let path = [
787
      this.stakeholder._id,
788
      this.stakeholder.topics[this.topicIndex]._id,
789
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
790
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
791
    ];
792
    this.stakeholderService.saveSection(this.properties.monitorServiceAPIURL, section, path, index).subscribe(section => {
793
      if (type === 'chart') {
794
        this.charts[index] = section;
795
        this.filterCharts();
796
      } else {
797
        this.numbers[index] = section;
798
        this.filterNumbers();
799
      }
800
      this.initReorder();
801
      UIkit.notification('Section has been successfully saved', {
802
        status: 'success',
803
        timeout: 3000,
804
        pos: 'top-left'
805
      });
806
    }, error => {
807
      UIkit.notification(error.error.message, {
808
        status: 'danger',
809
        timeout: 3000,
810
        pos: 'top-left'
811
      });
812
    });
813
  }
814
  
815
  createSection(index = -1, type: IndicatorType = 'chart') {
816
    this.section = new Section(type, null, null, this.stakeholder.alias);
817
    let path = [
818
      this.stakeholder._id,
819
      this.stakeholder.topics[this.topicIndex]._id,
820
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
821
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
822
    ];
823
    this.stakeholderService.saveSection(this.properties.monitorServiceAPIURL, this.section, path, index).subscribe(section => {
824
      if (type === 'chart') {
825
        if (index !== -1) {
826
          this.charts.splice(index, 0, section);
827
        } else {
828
          this.charts.push(section);
829
        }
830
        this.filterCharts();
831
      } else {
832
        if (index !== -1) {
833
          this.numbers.splice(index, 0, section);
834
        } else {
835
          this.numbers.push(section);
836
        }
837
        this.filterNumbers();
838
      }
839
      this.initReorder();
840
      UIkit.notification('Section has been successfully created', {
841
        status: 'success',
842
        timeout: 3000,
843
        pos: 'top-left'
844
      });
845
    }, error => {
846
      UIkit.notification(error.error.message, {
847
        status: 'danger',
848
        timeout: 3000,
849
        pos: 'top-left'
850
      });
851
    });
852
  }
853
  
854
  deleteNumberSectionOpen(section: Section, index: number) {
855
    this.section = section;
856
    this.index = index;
857
    this.deleteNumberSectionModal.alertTitle = 'Delete Section';
858
    this.deleteNumberSectionModal.cancelButtonText = 'No';
859
    this.deleteNumberSectionModal.okButtonText = 'Yes';
860
    this.deleteNumberSectionModal.open();
861
  }
862
  
863
  deleteChartSectionOpen(section: Section, index: number) {
864
    this.section = section;
865
    this.index = index;
866
    this.deleteChartSectionModal.alertTitle = 'Delete Section';
867
    this.deleteChartSectionModal.cancelButtonText = 'No';
868
    this.deleteChartSectionModal.okButtonText = 'Yes';
869
    this.deleteChartSectionModal.open();
870
  }
871
  
872
  deleteSection(type: IndicatorType = 'chart') {
873
    let path = [
874
      this.stakeholder._id,
875
      this.stakeholder.topics[this.topicIndex]._id,
876
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
877
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
878
      this.section._id
879
    ];
880
    this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => {
881
      if (type === "chart") {
882
        this.charts.splice(this.index, 1);
883
        this.filterCharts();
884
      } else {
885
        this.numbers.splice(this.index, 1);
886
        this.filterNumbers();
887
      }
888
      this.initReorder();
889
      UIkit.notification('Section has been successfully deleted', {
890
        status: 'success',
891
        timeout: 3000,
892
        pos: 'top-left'
893
      });
894
    }, error => {
895
      UIkit.notification(error.error.message, {
896
        status: 'danger',
897
        timeout: 3000,
898
        pos: 'top-left'
899
      });
900
    });
901
  }
902
}
(2-2/6)