Project

General

Profile

1
import {AfterViewInit, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from "@angular/core";
2
import {SideBarService} from "../library/sharedComponents/sidebar/sideBar.service";
3
import {Indicator, IndicatorPath, Stakeholder} from "../utils/entities/stakeholder";
4
import {IndicatorUtils} from "../utils/indicator-utils";
5
import {FormArray, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
6
import {AlertModal} from "../openaireLibrary/utils/modal/alert";
7
import {StatisticsService} from "../utils/services/statistics.service";
8
import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class";
9
import {DomSanitizer} from "@angular/platform-browser";
10
import {StakeholderService} from "../services/stakeholder.service";
11
import {EnvProperties} from "../openaireLibrary/utils/properties/env-properties";
12

    
13
declare var UIkit;
14

    
15
@Component({
16
  selector: 'indicators',
17
  templateUrl: './indicators.component.html'
18
})
19
export class IndicatorsComponent implements OnInit, OnChanges {
20

    
21
  @Input()
22
  public properties: EnvProperties = null;
23
  @Input()
24
  public topicIndex: number = 0;
25
  @Input()
26
  public categoryIndex: number = 0;
27
  @Input()
28
  public subcategoryIndex: number = 0;
29
  @Input()
30
  public stakeholder: Stakeholder = null;
31
  public indicatorUtils: IndicatorUtils = new IndicatorUtils();
32
  public indicatorFb: FormGroup;
33
  public editIndicatorFb: FormGroup;
34
  /**
35
   * Editable indicator
36
   */
37
  public indicator: Indicator;
38
  public index: number;
39
  /**
40
   * Displayed chart and numbers base on Top filters
41
   */
42
  public displayCharts: Indicator[] = [];
43
  public displayNumbers: Indicator[] = [];
44
  /**
45
   * Top filters
46
   */
47
  public chartType: string = 'all';
48
  public privacy: string = 'all';
49
  public status: string = 'all';
50
  public keyword: string = null;
51
  /**
52
   * Grid or List View
53
   */
54
  public grid: boolean = true;
55

    
56
  @ViewChild('createIndicatorModal') createIndicatorModal: AlertModal;
57
  @ViewChild('editIndicatorModal') editIndicatorModal: AlertModal;
58

    
59
  constructor(private sideBarService: SideBarService,
60
              private stakeholderService: StakeholderService,
61
              private statisticsService: StatisticsService,
62
              private fb: FormBuilder,
63
              private sanitizer: DomSanitizer) {
64
  }
65

    
66
  ngOnInit(): void {
67
    if (document !== undefined) {
68
      let callback = (list): void => {
69
        let items: HTMLCollection = list.current.children;
70
        let reordered = [];
71
        let indicators = [];
72
        for (let i = 0; i < items.length; i++) {
73
          if (items.item(i).id) {
74
            reordered.push(+items.item(i).id);
75
          }
76
        }
77
        if(list.current.id === 'charts') {
78
          reordered.forEach((id, index) => {
79
            indicators[index] = HelperFunctions.copy(this.charts[id]);
80
          });
81
          this.reorderIndicators('chart', indicators);
82
        } else if(list.current.id === 'numbers') {
83
          reordered.forEach((id, index) => {
84
            indicators[index] = HelperFunctions.copy(this.numbers[id]);
85
          });
86
          this.reorderIndicators('number', indicators);
87
        }
88
      };
89
      UIkit.util.on(document, 'moved', '#charts', callback);
90
      UIkit.util.on(document, 'moved', '#numbers', callback);
91
    }
92
  }
93

    
94
  ngOnChanges(changes: SimpleChanges): void {
95
    if (this.canEdit) {
96
      this.filterCharts();
97
      this.filterNumbers();
98
    }
99
  }
100

    
101
  public toggleOpen(event = null) {
102
    if (!event) {
103
      this.sideBarService.setOpen(!this.open);
104
    } else if (event && event['value'] === true) {
105
      this.sideBarService.setOpen(false);
106
    }
107
  }
108

    
109
  public changeGrid(value) {
110
    this.grid = value;
111
  }
112

    
113
  filterCharts() {
114
    this.displayCharts = this.filterChartType(this.filterPrivacy(
115
      this.filterStatus(this.filterByKeyword(this.charts, this.keyword), this.status),
116
      this.privacy),
117
      this.chartType
118
    );
119
  }
120

    
121
  filterNumbers() {
122
    this.displayNumbers = this.filterPrivacy(this.filterStatus(
123
      this.filterByKeyword(this.numbers, this.keyword),
124
      this.status),
125
      this.privacy);
126
  }
127

    
128
  onChartTypeChange(value) {
129
    this.displayCharts = this.filterChartType(this.charts, value);
130
  }
131

    
132
  onPrivacyChange(value) {
133
    this.displayCharts = this.filterPrivacy(this.charts, value);
134
    this.displayNumbers = this.filterPrivacy(this.numbers, value);
135
  }
136

    
137
  onStatusChange(value) {
138
    this.displayCharts = this.filterStatus(this.charts, value);
139
    this.displayNumbers = this.filterStatus(this.numbers, value);
140
  }
141

    
142
  onKeywordChange(value) {
143
    this.displayCharts = this.filterByKeyword(this.charts, value);
144
    this.displayNumbers = this.filterByKeyword(this.numbers, value);
145
  }
146

    
147
  private filterChartType(indicators: Indicator[], value): Indicator[] {
148
    if (value === 'all') {
149
      return indicators;
150
    } else {
151
      return indicators.filter(indicator =>
152
        indicator.indicatorPaths.filter(indicatorPath => indicatorPath.type === value).length > 0);
153
    }
154
  }
155

    
156
  private filterPrivacy(indicators: Indicator[], value): Indicator[] {
157
    if (value === 'all') {
158
      return indicators;
159
    } else {
160
      return indicators.filter(indicator => indicator.isPublic === (value === 'public'));
161
    }
162
  }
163

    
164
  private filterStatus(indicators: Indicator[], value): Indicator[] {
165
    if (value === 'all') {
166
      return indicators;
167
    } else {
168
      return indicators.filter(indicator => indicator.isActive === (value === 'active'));
169
    }
170
  }
171

    
172
  private filterByKeyword(indicators: Indicator[], value): Indicator[] {
173
    if (value === null || value === '') {
174
      return indicators;
175
    } else {
176
      return indicators.filter(indicator => (indicator.name && indicator.name.includes(value))
177
        || (indicator.description && indicator.description.includes(value)));
178
    }
179
  }
180

    
181
  get charts(): Indicator[] {
182
    return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts;
183
  }
184

    
185
  set charts(indicators: Indicator[]) {
186
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts = indicators;
187
  }
188

    
189
  get numbers(): Indicator[] {
190
    return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers;
191
  }
192

    
193
  set numbers(indicators: Indicator[]) {
194
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = indicators;
195
  }
196

    
197
  get open(): boolean {
198
    return this.sideBarService.open;
199
  }
200

    
201
  get canNumbersReorder(): boolean {
202
    return this.displayNumbers.length === this.numbers.length;
203
  }
204

    
205
  get canChartsReorder(): boolean {
206
    return this.displayCharts.length === this.charts.length;
207
  }
208

    
209
  get canEdit() {
210
    return this.stakeholder &&
211
      this.stakeholder.topics[this.topicIndex] &&
212
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
213
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex];
214
  }
215

    
216
  public get urls(): FormArray {
217
    return this.indicatorFb.get('urls') as FormArray;
218
  }
219

    
220
  public get indicatorPaths(): FormArray {
221
    return this.editIndicatorFb.get('indicatorPaths') as FormArray;
222
  }
223

    
224
  public getParameters(index: number): FormArray {
225
    return this.indicatorPaths.at(index).get('parameters') as FormArray;
226
  }
227

    
228
  public getParameter(index: number, key: string): FormControl {
229
    return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as FormControl;
230
  }
231

    
232
  private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
233
    return this.sanitizer.bypassSecurityTrustResourceUrl(
234
      this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(indicatorPath)));
235
  }
236

    
237
  public addUrl() {
238
    this.urls.push(this.fb.control('', [Validators.required,
239
      Validators.pattern('https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.' +
240
        '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.' +
241
        '[a-zA-Z0-9]+\.[^\s]{2,}')])
242
    );
243
  }
244

    
245
  public createIndicatorOpen() {
246
    this.indicatorFb = this.fb.group({
247
      name: this.fb.control('', Validators.required),
248
      description: this.fb.control(''),
249
      width: this.fb.control('small', Validators.required),
250
      urls: this.fb.array([]),
251
    });
252
    this.addUrl();
253
    this.createIndicatorModal.alertTitle = 'Create a new chart Indicator';
254
    this.createIndicatorModal.cancelButtonText = 'Cancel';
255
    this.createIndicatorModal.okButtonText = 'Create';
256
    this.createIndicatorModal.okButtonLeft = false;
257
    this.createIndicatorModal.alertMessage = false;
258
    this.createIndicatorModal.open();
259
  }
260

    
261
  public createIndicator() {
262
    this.indicator = new Indicator(
263
      this.indicatorFb.value.name,
264
      this.indicatorFb.value.description,
265
      'chart',
266
      this.indicatorFb.value.width,
267
      false,
268
      false,
269
      []
270
    );
271
    this.indicatorFb.value.urls.forEach(url => {
272
      this.indicator.indicatorPaths.push(
273
        this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(url), url));
274
    });
275
    this.editIndicatorOpen();
276
  }
277

    
278
  public editIndicatorOpen(index: number = -1) {
279
    this.index = index;
280
    if (this.index !== -1) {
281
      this.indicator = HelperFunctions.copy(this.charts[index]);
282
    }
283
    let indicatorPaths = this.fb.array([]);
284
    this.indicator.indicatorPaths.forEach(indicatorPath => {
285
      let parameters = this.fb.array([]);
286
      if (indicatorPath.parameters) {
287
        Object.keys(indicatorPath.parameters).forEach(key => {
288
          if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) {
289
            if (this.indicatorUtils.parametersValidators.has(key)) {
290
              parameters.push(this.fb.group({
291
                key: this.fb.control(key),
292
                value: this.fb.control(indicatorPath.parameters[key], this.indicatorUtils.parametersValidators.get(key))
293
              }));
294
            } else {
295
              parameters.push(this.fb.group({
296
                key: this.fb.control(key),
297
                value: this.fb.control(indicatorPath.parameters[key], Validators.required)
298
              }));
299
            }
300
          }
301
        });
302
      }
303
      indicatorPaths.push(this.fb.group({
304
        parameters: parameters
305
      }));
306
    });
307
    this.editIndicatorFb = this.fb.group({
308
      id: this.fb.control(this.indicator._id),
309
      name: this.fb.control(this.indicator.name, Validators.required),
310
      description: this.fb.control(this.indicator.description),
311
      isPublic: this.fb.control(this.indicator.isPublic),
312
      isActive: this.fb.control(this.indicator.isActive),
313
      indicatorPaths: indicatorPaths,
314
      width: this.fb.control(this.indicator.width, Validators.required),
315
    });
316
    this.editIndicatorModal.cancelButtonText = 'Cancel';
317
    this.editIndicatorModal.okButtonText = 'Save Changes';
318
    this.editIndicatorModal.okButtonLeft = false;
319
    this.editIndicatorModal.alertMessage = false;
320
    this.editIndicatorModal.open();
321
    setTimeout(() => {
322
      this.indicator.indicatorPaths.forEach(indicatorPath => {
323
        indicatorPath.safeResourceUrl = this.getUrlByStakeHolder(indicatorPath)
324
      });
325
    }, 500);
326
  }
327

    
328
  saveIndicator() {
329
    this.indicator = this.indicatorUtils.generateIndicatorByForm(this.editIndicatorFb.value, this.indicator.indicatorPaths);
330
    let path = [
331
      this.stakeholder._id,
332
      this.stakeholder.topics[this.topicIndex]._id,
333
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
334
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
335
    ];
336
    this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.indicator, path).subscribe(indicator => {
337
      if (this.index !== -1) {
338
        this.charts[this.index] = indicator;
339
      } else {
340
        this.charts.push(indicator);
341
      }
342
      this.filterCharts();
343
      this.stakeholderService.setStakeholder(this.stakeholder);
344
    });
345
  }
346

    
347
  reorderIndicators(type: string, indicators: Indicator[]) {
348
    let path = [
349
      this.stakeholder._id,
350
      this.stakeholder.topics[this.topicIndex]._id,
351
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
352
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
353
    ];
354
    this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicators, type).
355
    subscribe(() => {
356
      if(type === 'chart') {
357
        this.charts = indicators;
358
        this.filterCharts();
359
      } else {
360
        this.numbers = indicators;
361
        this.filterNumbers();
362
      }
363
      this.stakeholderService.setStakeholder(this.stakeholder);
364
    });
365
  }
366

    
367
  refreshIndicator(index: number) {
368
    this.indicator = this.indicatorUtils.generateIndicatorByForm(this.editIndicatorFb.value, this.indicator.indicatorPaths);
369
    this.indicator.indicatorPaths.forEach(indicatorPath => {
370
      indicatorPath.safeResourceUrl = this.getUrlByStakeHolder(indicatorPath)
371
    });
372
    this.indicatorPaths.at(index).markAsPristine({onlySelf: true});
373
  }
374
}
(2-2/6)