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
  /** Safe Urls*/
77
  public safeUrls: Map<string, SafeResourceUrl> = new Map<string, SafeResourceUrl>([]);
78
  
79
  private subscriptions: any[] = [];
80
  private urlSubscriptions: any[] = [];
81
  @ViewChild('editChartModal') editChartModal: AlertModal;
82
  @ViewChild('editNumberModal') editNumberModal: AlertModal;
83
  @ViewChild('deleteModal') deleteModal: AlertModal;
84
  @ViewChild('deleteChartSectionModal') deleteChartSectionModal: AlertModal;
85
  @ViewChild('deleteNumberSectionModal') deleteNumberSectionModal: AlertModal;
86
  
87
  urlParameterizedMessage = "";
88
  constructor(private layoutService: LayoutService,
89
              private stakeholderService: StakeholderService,
90
              private statisticsService: StatisticsService,
91
              private userManagementService: UserManagementService,
92
              private fb: FormBuilder,
93
              private router: Router,
94
              private cdr: ChangeDetectorRef,
95
              private sanitizer: DomSanitizer) {
96
  }
97
  
98
  ngOnInit(): void {
99
    this.userManagementService.getUserInfo().subscribe(user => {
100
      this.user = user;
101
    });
102
    this.buildFilters();
103
    this.buildSections();
104
  }
105
  
106
  ngOnDestroy(): void {
107
    this.subscriptions.forEach(value => {
108
      if (value instanceof Subscriber) {
109
        value.unsubscribe();
110
      } else if (value instanceof Function) {
111
        value();
112
      }
113
    });
114
  }
115
  
116
  ngAfterViewInit(): void {
117
    this.initReorder();
118
  }
119
  
120
  ngOnChanges(changes: SimpleChanges): void {
121
    if (this.canEdit) {
122
      if (changes.topicIndex || changes.categoryIndex || changes.subcategoryIndex) {
123
        this.buildFilters();
124
      }
125
      this.filterCharts();
126
      this.filterNumbers();
127
    }
128
    if (this.topicIndex && this.categoryIndex && this.subcategoryIndex) {
129
      this.preview = '/' + this.stakeholder.alias + '/' + this.stakeholder.topics[this.topicIndex].alias +
130
        '/' + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].alias +
131
        '/' + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].alias;
132
    }
133
  }
134
  
135
  initReorder() {
136
    this.subscriptions.forEach(value => {
137
      if (value instanceof Function) {
138
        value();
139
      }
140
    });
141
    if (document !== undefined) {
142
      let callback = (list, type: IndicatorType): void => {
143
        let items: HTMLCollection = list.current.children;
144
        let reordered = [];
145
        for (let i = 0; i < items.length; i++) {
146
          if (items.item(i).id) {
147
            reordered.push(items.item(i).id);
148
          }
149
        }
150
        this.reorderIndicators(list.current.id.toString().split('-')[1], type, reordered);
151
      };
152
      this.numbers.forEach((section) => {
153
        this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart' + section._id, (list): void => {
154
          callback(list, "number");
155
        }));
156
        this.subscriptions.push(UIkit.util.on(document, 'added', '#chart' + section._id, (list): void => {
157
          callback(list, "number");
158
        }));
159
        this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart' + section._id, (list): void => {
160
          callback(list, "number");
161
        }));
162
      });
163
      this.charts.forEach((section) => {
164
        this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => {
165
          callback(list, "chart");
166
        }));
167
        this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => {
168
          callback(list, "chart");
169
        }));
170
        this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => {
171
          callback(list, "chart");
172
        }));
173
      });
174
    }
175
  }
176
  
177
  hide(element: any) {
178
    UIkit.dropdown(element).hide();
179
  }
180
  
181
  public changeGrid(value) {
182
    this.grid = value;
183
  }
184
  
185
  private buildFilters() {
186
    this.filters = this.fb.group({
187
      chartType: this.fb.control('all'),
188
      privacy: this.fb.control('all'),
189
      status: this.fb.control('all'),
190
      keyword: this.fb.control('')
191
    });
192
    this.subscriptions.push(this.filters.get('chartType').valueChanges.subscribe(value => {
193
      this.onChartTypeChange(value);
194
    }));
195
    this.subscriptions.push(this.filters.get('privacy').valueChanges.subscribe(value => {
196
      this.onPrivacyChange(value);
197
    }));
198
    this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => {
199
      this.onStatusChange(value);
200
    }));
201
    this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => {
202
      this.onKeywordChange(value);
203
    }));
204
  }
205
  
206
  private buildSections() {
207
    this.numberSections = this.fb.array([]);
208
    this.numbers.forEach(section => {
209
      this.numberSections.push(this.fb.group({
210
        _id: this.fb.control(section._id),
211
        title: this.fb.control(section.title),
212
        stakeholderAlias: this.fb.control(section.stakeholderAlias),
213
        defaultId: this.fb.control(section.defaultId),
214
        type: this.fb.control(section.type),
215
        indicators: this.fb.control(section.indicators)
216
      }));
217
    });
218
    this.chartSections = this.fb.array([]);
219
    this.charts.forEach(section => {
220
      this.chartSections.push(this.fb.group({
221
        _id: this.fb.control(section._id),
222
        title: this.fb.control(section.title),
223
        stakeholderAlias: this.fb.control(section.stakeholderAlias),
224
        defaultId: this.fb.control(section.defaultId),
225
        type: this.fb.control(section.type),
226
        indicators: this.fb.control(section.indicators)
227
      }));
228
    });
229
  }
230
  
231
  filterCharts() {
232
    this.displayCharts = this.filterChartType(this.filterPrivacy(
233
      this.filterStatus(this.filterByKeyword(HelperFunctions.copy(this.charts), this.filters.value.keyword),
234
        this.filters.value.status),
235
      this.filters.value.privacy),
236
      this.filters.value.chartType
237
    );
238
    this.displayCharts.forEach(section => {
239
      section.indicators.forEach(indicator => {
240
        indicator.indicatorPaths.forEach(indicatorPath => {
241
          let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath);
242
          if (!this.safeUrls.get('url')) {
243
            indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
244
            this.safeUrls.set(url, indicatorPath.safeResourceUrl);
245
          }
246
        });
247
      })
248
    });
249
    this.buildSections();
250
  }
251
  
252
  filterNumbers() {
253
    this.displayNumbers = this.filterPrivacy(this.filterStatus(
254
      this.filterByKeyword(HelperFunctions.copy(this.numbers), this.filters.value.keyword),
255
      this.filters.value.status),
256
      this.filters.value.privacy);
257
    console.log(this.numbers);
258
    this.buildSections();
259
  }
260
  
261
  onChartTypeChange(value) {
262
    this.displayCharts = this.filterChartType(HelperFunctions.copy(this.charts), value);
263
  }
264
  
265
  onPrivacyChange(value) {
266
    this.displayCharts = this.filterPrivacy(HelperFunctions.copy(this.charts), value);
267
    this.displayNumbers = this.filterPrivacy(HelperFunctions.copy(this.numbers), value);
268
  }
269
  
270
  onStatusChange(value) {
271
    this.displayCharts = this.filterStatus(HelperFunctions.copy(this.charts), value);
272
    this.displayNumbers = this.filterStatus(HelperFunctions.copy(this.numbers), value);
273
  }
274
  
275
  onKeywordChange(value) {
276
    this.displayCharts = this.filterByKeyword(HelperFunctions.copy(this.charts), value);
277
    this.displayNumbers = this.filterByKeyword(HelperFunctions.copy(this.numbers), value);
278
  }
279
  
280
  private filterChartType(sections: Section[], value): Section[] {
281
    if (value !== 'all') {
282
      sections.forEach(section =>
283
        section.indicators = section.indicators.filter(indicator =>
284
          indicator.indicatorPaths.filter(indicatorPath => indicatorPath.type === value).length > 0));
285
    }
286
    return sections;
287
  }
288
  
289
  private filterPrivacy(sections: Section[], value): Section[] {
290
    if (value !== 'all') {
291
      sections.forEach(section =>
292
        section.indicators = section.indicators.filter(indicator => indicator.isPublic === value));
293
    }
294
    return sections;
295
  }
296
  
297
  private filterStatus(sections: Section[], value): Section[] {
298
    if (value !== 'all') {
299
      sections.forEach(section =>
300
        section.indicators = section.indicators.filter(indicator => indicator.isActive === value));
301
    }
302
    return sections;
303
  }
304
  
305
  private filterByKeyword(sections: Section[], value): Section[] {
306
    if (value !== null && value !== '') {
307
      sections.forEach(section =>
308
        section.indicators = section.indicators.filter(indicator => (indicator.name && indicator.name.toLowerCase().includes(value.toLowerCase()))
309
          || (indicator.description && indicator.description.toLowerCase().includes(value.toLowerCase()))
310
          || indicator.indicatorPaths.filter(indicatorPath => (indicatorPath.parameters && indicatorPath.parameters.title &&
311
            indicatorPath.parameters.title.includes(value.toLowerCase()))).length > 0));
312
    }
313
    return sections;
314
  }
315
  
316
  get charts(): Section[] {
317
    if (this.stakeholder.topics[this.topicIndex] &&
318
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
319
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
320
      return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts;
321
    } else {
322
      return [];
323
    }
324
  }
325
  
326
  set charts(sections: Section[]) {
327
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts = sections;
328
  }
329
  
330
  get numbers(): Section[] {
331
    if (this.stakeholder.topics[this.topicIndex] &&
332
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
333
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) {
334
      return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers;
335
    } else {
336
      return [];
337
    }
338
  }
339
  
340
  set numbers(sections: Section[]) {
341
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = sections;
342
  }
343
  
344
  get open(): boolean {
345
    return this.layoutService.open;
346
  }
347
  
348
  get canReorder(): boolean {
349
    return this.filters.value.chartType === 'all' && this.filters.value.privacy === 'all' &&
350
      this.filters.value.status === 'all' && this.filters.value.keyword === '' && this.grid;
351
  }
352
  
353
  get canEdit() {
354
    return this.stakeholder &&
355
      this.stakeholder.topics[this.topicIndex] &&
356
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
357
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex];
358
  }
359
  
360
  public get numberIndicatorPaths(): FormArray {
361
    return this.numberIndicatorFb.get('indicatorPaths') as FormArray;
362
  }
363
  
364
  public get chartIndicatorPaths(): FormArray {
365
    return this.chartIndicatorFb.get('indicatorPaths') as FormArray;
366
  }
367
  
368
  public addJsonPath(index: number) {
369
    this.getJsonPath(index).push(this.fb.control('', Validators.required));
370
  }
371
  
372
  public removeJsonPath(i: number, j:number) {
373
    this.getJsonPath(i).removeAt(j);
374
  }
375
  
376
  public getJsonPath(index: number): FormArray {
377
    return this.numberIndicatorPaths.at(index).get('jsonPath') as FormArray;
378
  }
379
  
380
  public getParameters(index: number): FormArray {
381
    return this.chartIndicatorPaths.at(index).get('parameters') as FormArray;
382
  }
383
  
384
  public getParameter(index: number, key: string): FormControl {
385
    return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as FormControl;
386
  }
387
  
388
  private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) {
389
    return this.sanitizer.bypassSecurityTrustResourceUrl(
390
      this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)));
391
  }
392
  
393
  private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
394
    return this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath));
395
  }
396
  
397
  public addNumberIndicatorPath(url: string = '', source: string = 'search', jsonPath: FormArray = new FormArray([])) {
398
    if(jsonPath.length === 0) {
399
      jsonPath.push(this.fb.control('', Validators.required));
400
    }
401
    this.numberIndicatorPaths.push(this.fb.group({
402
        url: this.fb.control(url, Validators.required),
403
        jsonPath: jsonPath,
404
        source: this.fb.control(source, Validators.required)
405
      }
406
    ));
407
  }
408
  
409
  public addChartIndicatorPath(value: string = '', parameters: FormArray = new FormArray([]), disableUrl: boolean = false, type:string=null) {
410
    this.chartIndicatorPaths.push(this.fb.group({
411
        url: this.fb.control(value, [Validators.required,
412
          Validators.pattern('https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.' +
413
            '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.' +
414
            '[a-zA-Z0-9]+\.[^\s]{2,}')]),
415
        parameters: parameters,
416
        type: this.fb.control(type)
417
      }
418
    ));
419
    if(disableUrl) {
420
      for(let index = 0; index < this.chartIndicatorPaths.length; index++) {
421
        this.chartIndicatorPaths.at(index).get('url').disable();
422
      }
423
    } else {
424
      for(let index = 0; index < this.chartIndicatorPaths.length; index++) {
425
        this.urlSubscriptions.push(this.chartIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
426
            if (this.chartIndicatorPaths.at(index).get('url').valid) {
427
              let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder);
428
              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 ){
429
                // default profile
430
                if(this.stakeholder.defaultId == null){
431
                  this.urlParameterizedMessage = "This chart couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly."
432
                }else{
433
                  this.urlParameterizedMessage = "This chart couldn't be generated properly. Please make sure chart data is for the current stakeholder."
434
                }
435
              }else {
436
                this.urlParameterizedMessage = "";
437
              }
438
              (this.chartIndicatorPaths.at(index) as FormGroup).get('type').setValue(indicatorPath.type);
439
              let parameters = this.getParametersAsFormArray(indicatorPath);
440
              (this.chartIndicatorPaths.at(index) as FormGroup).setControl('parameters', parameters);
441
              if (!this.indicator.indicatorPaths[index]) {
442
                this.indicator.indicatorPaths[index] = indicatorPath;
443
                this.indicator.indicatorPaths[index].safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
444
              } else {
445
                indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl;
446
                this.indicator.indicatorPaths[index] = indicatorPath;
447
              }
448
            }
449
          })
450
        );
451
      }
452
    }
453
  }
454
  
455
  private getJsonPathAsFormArray(indicatorPath: IndicatorPath): FormArray {
456
    let jsonPath = this.fb.array([]);
457
    if (indicatorPath.jsonPath) {
458
      indicatorPath.jsonPath.forEach(path => {
459
        jsonPath.push(this.fb.control(path, Validators.required));
460
      });
461
    }
462
    return jsonPath;
463
  }
464
  
465
  private getParametersAsFormArray(indicatorPath: IndicatorPath): FormArray {
466
    let parameters = this.fb.array([]);
467
    if (indicatorPath.parameters) {
468
      Object.keys(indicatorPath.parameters).forEach(key => {
469
        if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) {
470
          if (this.indicatorUtils.parametersValidators.has(key)) {
471
            parameters.push(this.fb.group({
472
              key: this.fb.control(key),
473
              value: this.fb.control(indicatorPath.parameters[key], this.indicatorUtils.parametersValidators.get(key))
474
            }));
475
          } else {
476
            parameters.push(this.fb.group({
477
              key: this.fb.control(key),
478
              value: this.fb.control(indicatorPath.parameters[key])
479
            }));
480
          }
481
        }
482
      });
483
    }
484
    return parameters;
485
  }
486
  
487
  public editNumberIndicatorOpen(section: Section, id = null) {
488
    this.section = section;
489
    this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1;
490
    if (this.index !== -1) {
491
      this.indicator = HelperFunctions.copy(this.section.indicators[this.index]);
492
      this.numberIndicatorFb = this.fb.group({
493
        _id: this.fb.control(this.indicator._id),
494
        name: this.fb.control(this.indicator.name),
495
        description: this.fb.control(this.indicator.description),
496
        isPublic: this.fb.control(this.indicator.isPublic),
497
        isActive: this.fb.control(this.indicator.isActive),
498
        indicatorPaths: this.fb.array([], Validators.required),
499
        type: this.fb.control(this.indicator.type),
500
        width: this.fb.control(this.indicator.width),
501
        defaultId: this.fb.control(this.indicator.defaultId)
502
      });
503
      this.indicator.indicatorPaths.forEach(indicatorPath => {
504
        this.addNumberIndicatorPath(indicatorPath.url, indicatorPath.source, this.getJsonPathAsFormArray(indicatorPath));
505
      });
506
    } else {
507
      this.indicator = new Indicator('', '', 'number', 'small', false, false, []);
508
      this.numberIndicatorFb = this.fb.group({
509
        _id: this.fb.control(this.indicator._id),
510
        name: this.fb.control(this.indicator.name),
511
        description: this.fb.control(this.indicator.description),
512
        isPublic: this.fb.control(this.indicator.isPublic),
513
        isActive: this.fb.control(this.indicator.isActive),
514
        indicatorPaths: this.fb.array([], Validators.required),
515
        type: this.fb.control(this.indicator.type),
516
        width: this.fb.control(this.indicator.width),
517
        defaultId: this.fb.control(this.indicator.defaultId)
518
      });
519
      this.addNumberIndicatorPath();
520
    }
521
    this.editNumberModal.cancelButtonText = 'Cancel';
522
    this.editNumberModal.okButtonLeft = false;
523
    this.editNumberModal.alertMessage = false;
524
    if (this.index === -1) {
525
      this.editNumberModal.alertTitle = 'Create a new number indicator';
526
      this.editNumberModal.okButtonText = 'Save';
527
    } else {
528
      this.editNumberModal.alertTitle = 'Edit number indicator\'s information';
529
      this.editNumberModal.okButtonText = 'Save Changes';
530
    }
531
    this.editNumberModal.open();
532
  }
533
  
534
  public editChartIndicatorOpen(section: Section, id = null) {
535
    this.urlParameterizedMessage = "";
536
    this.urlSubscriptions.forEach(value => {
537
      if (value instanceof Subscriber) {
538
        value.unsubscribe();
539
      }
540
    });
541
    this.section = section;
542
    this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1;
543
    if (this.index !== -1) {
544
      this.indicator = HelperFunctions.copy(this.section.indicators[this.index]);
545
      this.chartIndicatorFb = this.fb.group({
546
        _id: this.fb.control(this.indicator._id),
547
        name: this.fb.control(this.indicator.name),
548
        description: this.fb.control(this.indicator.description),
549
        isPublic: this.fb.control(this.indicator.isPublic),
550
        isActive: this.fb.control(this.indicator.isActive),
551
        indicatorPaths: this.fb.array([]),
552
        width: this.fb.control(this.indicator.width),
553
        defaultId: this.fb.control(this.indicator.defaultId)
554
      });
555
      this.indicator.indicatorPaths.forEach(indicatorPath => {
556
        this.addChartIndicatorPath(this.getUrlByStakeHolder(indicatorPath),
557
          this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type);
558
        indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
559
      });
560
    } else {
561
      this.indicator = new Indicator('', '', 'chart', 'small', false, false, []);
562
      this.chartIndicatorFb = this.fb.group({
563
        _id: this.fb.control(null),
564
        name: this.fb.control(''),
565
        description: this.fb.control(''),
566
        isPublic: this.fb.control(false),
567
        isActive: this.fb.control(false),
568
        indicatorPaths: this.fb.array([]),
569
        width: this.fb.control('small', Validators.required),
570
        defaultId: this.fb.control(null)
571
      });
572
      this.addChartIndicatorPath();
573
    }
574
    this.editChartModal.cancelButtonText = 'Cancel';
575
    this.editChartModal.okButtonLeft = false;
576
    this.editChartModal.alertMessage = false;
577
    if (this.index === -1) {
578
      this.editChartModal.alertTitle = 'Create a new chart indicator';
579
      this.editChartModal.okButtonText = 'Save';
580
    } else {
581
      this.editChartModal.alertTitle = 'Edit chart indicator\'s information';
582
      this.editChartModal.okButtonText = 'Save Changes';
583
    }
584
    this.editChartModal.open();
585
  }
586
  
587
  saveIndicator() {
588
    if (this.indicator.type === 'chart') {
589
      this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths);
590
      this.section = this.charts.find(section => section._id === this.section._id);
591
    } else {
592
      this.indicator = this.numberIndicatorFb.value;
593
    }
594
    let path = [
595
      this.stakeholder._id,
596
      this.stakeholder.topics[this.topicIndex]._id,
597
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
598
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
599
      this.section._id
600
    ];
601
    this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.indicator, path).subscribe(indicator => {
602
      if (this.index !== -1) {
603
        this.section.indicators[this.index] = indicator;
604
      } else {
605
        this.section.indicators.push(indicator);
606
      }
607
      this.filterCharts();
608
      this.chartIndicatorFb = null;
609
      UIkit.notification('Indicator has been successfully saved', {
610
        status: 'success',
611
        timeout: 3000,
612
        pos: 'top-left'
613
      });
614
    }, error => {
615
      this.chartIndicatorFb = null;
616
      UIkit.notification(error.error.message, {
617
        status: 'danger',
618
        timeout: 3000,
619
        pos: 'top-left'
620
      });
621
    });
622
  }
623
  
624
  reorderIndicators(sectionId: string, type: IndicatorType, indicatorIds: string[]) {
625
    let path = [
626
      this.stakeholder._id,
627
      this.stakeholder.topics[this.topicIndex]._id,
628
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
629
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
630
      sectionId
631
    ];
632
    this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicatorIds, type).subscribe(indicators => {
633
      if (type === 'chart') {
634
        this.charts.find(section => section._id === sectionId).indicators = indicators;
635
        this.filterCharts();
636
      } else {
637
        this.numbers.find(section => section._id === sectionId).indicators = indicators;
638
        this.filterNumbers();
639
      }
640
    });
641
  }
642
  
643
  hasDifference(index: number): boolean {
644
    let hasDifference = false;
645
    this.chartIndicatorPaths.at(index).value.parameters.forEach((parameter) => {
646
      if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) {
647
        hasDifference = true;
648
        return;
649
      }
650
    });
651
    return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !==
652
      this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString();
653
  }
654
  
655
  public get isAdministrator(): boolean {
656
    return Session.isPortalAdministrator(this.user) || Session.isMonitorCurator(this.user) || Session.isCommunityCurator(this.user)
657
  }
658
  
659
  refreshIndicator() {
660
    this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths);
661
    this.indicator.indicatorPaths.forEach(indicatorPath => {
662
      indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
663
    });
664
  }
665
  
666
  deleteIndicatorOpen(section: Section, indicatorId: string, type: string = 'chart') {
667
    this.section = section;
668
    if (type === 'chart') {
669
      this.index = this.charts.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId);
670
    } else {
671
      this.index = this.numbers.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId);
672
    }
673
    this.indicator = section.indicators.find(value => value._id == indicatorId);
674
    this.deleteModal.alertTitle = 'Delete indicator';
675
    this.deleteModal.cancelButtonText = 'No';
676
    this.deleteModal.okButtonText = 'Yes';
677
    this.deleteModal.open();
678
  }
679
  
680
  deleteIndicator() {
681
    let path = [
682
      this.stakeholder._id,
683
      this.stakeholder.topics[this.topicIndex]._id,
684
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
685
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
686
      this.section._id,
687
      this.indicator._id
688
    ];
689
    this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => {
690
      if (this.indicator.type === 'chart') {
691
        this.charts.find(section => section._id === this.section._id).indicators.splice(this.index, 1);
692
        this.filterCharts();
693
      } else {
694
        this.numbers.find(section => section._id === this.section._id).indicators.splice(this.index, 1);
695
        this.filterNumbers();
696
      }
697
      UIkit.notification('Indicator has been successfully deleted', {
698
        status: 'success',
699
        timeout: 3000,
700
        pos: 'top-left'
701
      });
702
    }, error => {
703
      UIkit.notification(error.error.message, {
704
        status: 'danger',
705
        timeout: 3000,
706
        pos: 'top-left'
707
      });
708
    });
709
  }
710
  
711
  toggleIndicatorStatus(sectionId: string, indicator: Indicator) {
712
    let path = [
713
      this.stakeholder._id,
714
      this.stakeholder.topics[this.topicIndex]._id,
715
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
716
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
717
      sectionId,
718
      indicator._id
719
    ];
720
    this.stakeholderService.toggleStatus(this.properties.monitorServiceAPIURL, path).subscribe(isActive => {
721
      indicator.isActive = isActive;
722
      UIkit.notification('Indicator has been successfully changed to ' + (isActive?'active':'inactive'), {
723
        status: 'success',
724
        timeout: 3000,
725
        pos: 'top-left'
726
      });
727
    }, error => {
728
      UIkit.notification(error.error.message, {
729
        status: 'danger',
730
        timeout: 3000,
731
        pos: 'top-left'
732
      });
733
    });
734
  }
735
  
736
  toggleIndicatorAccess(sectionId: string, indicator: Indicator) {
737
    let path = [
738
      this.stakeholder._id,
739
      this.stakeholder.topics[this.topicIndex]._id,
740
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
741
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
742
      sectionId,
743
      indicator._id
744
    ];
745
    this.stakeholderService.toggleAccess(this.properties.monitorServiceAPIURL, path).subscribe(isPublic => {
746
      indicator.isPublic = isPublic;
747
      UIkit.notification('Indicator has been successfully changed to ' + (isPublic?'public':'private'), {
748
        status: 'success',
749
        timeout: 3000,
750
        pos: 'top-left'
751
      });
752
    }, error => {
753
      UIkit.notification(error.error.message, {
754
        status: 'danger',
755
        timeout: 3000,
756
        pos: 'top-left'
757
      });
758
    });
759
  }
760
  
761
  saveSection(section: Section, index: number, type: IndicatorType = "chart") {
762
    let path = [
763
      this.stakeholder._id,
764
      this.stakeholder.topics[this.topicIndex]._id,
765
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
766
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
767
    ];
768
    this.stakeholderService.saveSection(this.properties.monitorServiceAPIURL, section, path, index).subscribe(section => {
769
      if (type === 'chart') {
770
        this.charts[index] = section;
771
        this.filterCharts();
772
      } else {
773
        this.numbers[index] = section;
774
        this.filterNumbers();
775
      }
776
      this.initReorder();
777
      UIkit.notification('Section has been successfully saved', {
778
        status: 'success',
779
        timeout: 3000,
780
        pos: 'top-left'
781
      });
782
    }, error => {
783
      UIkit.notification(error.error.message, {
784
        status: 'danger',
785
        timeout: 3000,
786
        pos: 'top-left'
787
      });
788
    });
789
  }
790
  
791
  createSection(index = -1, type: IndicatorType = 'chart') {
792
    this.section = new Section(type, null, null, this.stakeholder.alias);
793
    let path = [
794
      this.stakeholder._id,
795
      this.stakeholder.topics[this.topicIndex]._id,
796
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
797
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
798
    ];
799
    this.stakeholderService.saveSection(this.properties.monitorServiceAPIURL, this.section, path, index).subscribe(section => {
800
      if (type === 'chart') {
801
        if (index !== -1) {
802
          this.charts.splice(index, 0, section);
803
        } else {
804
          this.charts.push(section);
805
        }
806
        this.filterCharts();
807
      } else {
808
        if (index !== -1) {
809
          this.numbers.splice(index, 0, section);
810
        } else {
811
          this.numbers.push(section);
812
        }
813
        this.filterNumbers();
814
      }
815
      this.initReorder();
816
      UIkit.notification('Section has been successfully created', {
817
        status: 'success',
818
        timeout: 3000,
819
        pos: 'top-left'
820
      });
821
    }, error => {
822
      UIkit.notification(error.error.message, {
823
        status: 'danger',
824
        timeout: 3000,
825
        pos: 'top-left'
826
      });
827
    });
828
  }
829
  
830
  deleteNumberSectionOpen(section: Section, index: number) {
831
    this.section = section;
832
    this.index = index;
833
    this.deleteNumberSectionModal.alertTitle = 'Delete Section';
834
    this.deleteNumberSectionModal.cancelButtonText = 'No';
835
    this.deleteNumberSectionModal.okButtonText = 'Yes';
836
    this.deleteNumberSectionModal.open();
837
  }
838
  
839
  deleteChartSectionOpen(section: Section, index: number) {
840
    this.section = section;
841
    this.index = index;
842
    this.deleteChartSectionModal.alertTitle = 'Delete Section';
843
    this.deleteChartSectionModal.cancelButtonText = 'No';
844
    this.deleteChartSectionModal.okButtonText = 'Yes';
845
    this.deleteChartSectionModal.open();
846
  }
847
  
848
  deleteSection(type: IndicatorType = 'chart') {
849
    let path = [
850
      this.stakeholder._id,
851
      this.stakeholder.topics[this.topicIndex]._id,
852
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
853
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
854
      this.section._id
855
    ];
856
    this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => {
857
      if (type === "chart") {
858
        this.charts.splice(this.index, 1);
859
        this.filterCharts();
860
      } else {
861
        this.numbers.splice(this.index, 1);
862
        this.filterNumbers();
863
      }
864
      this.initReorder();
865
      UIkit.notification('Section has been successfully deleted', {
866
        status: 'success',
867
        timeout: 3000,
868
        pos: 'top-left'
869
      });
870
    }, error => {
871
      UIkit.notification(error.error.message, {
872
        status: 'danger',
873
        timeout: 3000,
874
        pos: 'top-left'
875
      });
876
    });
877
  }
878
}
(2-2/6)