Project

General

Profile

« Previous | Next » 

Revision 57888

[Monitor Dashboard | Trunk]: Reorder indicators: enable by long click

View differences:

indicators.component.ts
14 14
declare var UIkit;
15 15

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

  
22
    @Input()
23
    public properties: EnvProperties = null;
24
    @Input()
25
    public topicIndex: number = 0;
26
    @Input()
27
    public categoryIndex: number = 0;
28
    @Input()
29
    public subcategoryIndex: number = 0;
30
    @Input()
31
    public stakeholder: Stakeholder = null;
32
    public indicatorUtils: IndicatorUtils = new IndicatorUtils();
33
    public indicatorFb: 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 filters: FormGroup;
48
    public all: Option = {
49
        value: 'all',
50
        label: 'All'
51
    };
52
    /**
53
     * Grid or List View
54
     */
55
    public grid: boolean = true;
56
    private subscriptions: any[] = [];
57
    private urlSubscriptions: any[] = [];
58
    @ViewChild('editIndicatorModal') editIndicatorModal: AlertModal;
59
    @ViewChild('deleteIndicatorModal') deleteIndicatorModal: AlertModal;
60

  
61
    constructor(private layoutService: LayoutService,
62
                private stakeholderService: StakeholderService,
63
                private statisticsService: StatisticsService,
64
                private fb: FormBuilder,
65
                private sanitizer: DomSanitizer) {
21
  
22
  @Input()
23
  public properties: EnvProperties = null;
24
  @Input()
25
  public topicIndex: number = 0;
26
  @Input()
27
  public categoryIndex: number = 0;
28
  @Input()
29
  public subcategoryIndex: number = 0;
30
  @Input()
31
  public stakeholder: Stakeholder = null;
32
  public indicatorUtils: IndicatorUtils = new IndicatorUtils();
33
  public indicatorFb: 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 filters: FormGroup;
48
  public all: Option = {
49
    value: 'all',
50
    label: 'All'
51
  };
52
  /**
53
   * Toggles
54
   */
55
  public grid: boolean = true;
56
  public numberReorder: boolean = false;
57
  public chartReorder: boolean = false;
58
  private subscriptions: any[] = [];
59
  private urlSubscriptions: any[] = [];
60
  @ViewChild('editIndicatorModal') editIndicatorModal: AlertModal;
61
  @ViewChild('deleteIndicatorModal') deleteIndicatorModal: AlertModal;
62
  
63
  constructor(private layoutService: LayoutService,
64
              private stakeholderService: StakeholderService,
65
              private statisticsService: StatisticsService,
66
              private fb: FormBuilder,
67
              private sanitizer: DomSanitizer) {
68
  }
69
  
70
  ngOnInit(): void {
71
    this.buildFilters();
72
  }
73
  
74
  ngOnDestroy(): void {
75
    this.subscriptions.forEach(value => {
76
      if (value instanceof Subscriber) {
77
        value.unsubscribe();
78
      } else if (value instanceof Function) {
79
        value();
80
      }
81
    });
82
  }
83
  
84
  ngAfterViewInit(): void {
85
    if (document !== undefined) {
86
      let callback = (list): void => {
87
        let items: HTMLCollection = list.current.children;
88
        let reordered = [];
89
        for (let i = 0; i < items.length; i++) {
90
          if (items.item(i).id) {
91
            reordered.push(items.item(i).id);
92
          }
93
        }
94
        this.reorderIndicators(list.current.id, reordered);
95
      };
96
      this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart', callback));
97
      this.subscriptions.push(UIkit.util.on(document, 'moved', '#number', callback));
98
      this.subscriptions.push(UIkit.util.on(document, 'stop', '#chart', (): void => {
99
        this.chartReorder = false;
100
      }));
101
      this.subscriptions.push(UIkit.util.on(document, 'stop', '#number', (): void => {
102
        this.numberReorder = false;
103
      }));
66 104
    }
67

  
68
    ngOnInit(): void {
105
  }
106
  
107
  ngOnChanges(changes: SimpleChanges): void {
108
    if (this.canEdit) {
109
      if (changes.topicIndex || changes.categoryIndex || changes.subcategoryIndex) {
69 110
        this.buildFilters();
111
      }
112
      this.filterCharts();
113
      this.filterNumbers();
70 114
    }
71

  
72
    ngOnDestroy(): void {
73
        this.subscriptions.forEach(value => {
74
            if (value instanceof Subscriber) {
75
                value.unsubscribe();
76
            } else if (value instanceof Function) {
77
                value();
78
            }
79
        });
115
  }
116
  
117
  public toggleOpen(event = null) {
118
    if (!event) {
119
      this.layoutService.setOpen(!this.open);
120
    } else if (event && event['value'] === true) {
121
      this.layoutService.setOpen(false);
80 122
    }
81

  
82
    ngAfterViewInit(): void {
83
        if (document !== undefined) {
84
            let callback = (list): void => {
85
                let items: HTMLCollection = list.current.children;
86
                let reordered = [];
87
                for (let i = 0; i < items.length; i++) {
88
                    if (items.item(i).id) {
89
                        reordered.push(items.item(i).id);
90
                    }
91
                }
92
                this.reorderIndicators(list.current.id, reordered);
93
            };
94
            this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart', callback));
95
            this.subscriptions.push(UIkit.util.on(document, 'moved', '#number', callback));
96
        }
123
  }
124
  
125
  public changeGrid(value) {
126
    this.grid = value;
127
  }
128
  
129
  private buildFilters() {
130
    this.filters = this.fb.group({
131
      chartType: this.fb.control('all'),
132
      privacy: this.fb.control('all'),
133
      status: this.fb.control('all'),
134
      keyword: this.fb.control('')
135
    });
136
    this.subscriptions.push(this.filters.get('chartType').valueChanges.subscribe(value => {
137
      this.onChartTypeChange(value);
138
    }));
139
    this.subscriptions.push(this.filters.get('privacy').valueChanges.subscribe(value => {
140
      this.onPrivacyChange(value);
141
    }));
142
    this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => {
143
      this.onStatusChange(value);
144
    }));
145
    this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => {
146
      this.onKeywordChange(value);
147
    }));
148
  }
149
  
150
  filterCharts() {
151
    this.displayCharts = this.filterChartType(this.filterPrivacy(
152
      this.filterStatus(this.filterByKeyword(this.charts, this.filters.value.keyword),
153
        this.filters.value.status),
154
      this.filters.value.privacy),
155
      this.filters.value.chartType
156
    );
157
  }
158
  
159
  filterNumbers() {
160
    this.displayNumbers = this.filterPrivacy(this.filterStatus(
161
      this.filterByKeyword(this.numbers, this.filters.value.keyword),
162
      this.filters.value.status),
163
      this.filters.value.privacy);
164
  }
165
  
166
  onLongPress(type = 'chart') {
167
    if(type === 'number') {
168
      this.numberReorder = true;
169
    } else {
170
      this.chartReorder = true;
97 171
    }
98

  
99
    ngOnChanges(changes: SimpleChanges): void {
100
        if (this.canEdit) {
101
            if (changes.topicIndex || changes.categoryIndex || changes.subcategoryIndex) {
102
                this.buildFilters();
103
            }
104
            this.filterCharts();
105
            this.filterNumbers();
106
        }
172
  }
173
  
174
  onChartTypeChange(value) {
175
    this.displayCharts = this.filterChartType(this.charts, value);
176
  }
177
  
178
  onPrivacyChange(value) {
179
    this.displayCharts = this.filterPrivacy(this.charts, value);
180
    this.displayNumbers = this.filterPrivacy(this.numbers, value);
181
  }
182
  
183
  onStatusChange(value) {
184
    this.displayCharts = this.filterStatus(this.charts, value);
185
    this.displayNumbers = this.filterStatus(this.numbers, value);
186
  }
187
  
188
  onKeywordChange(value) {
189
    this.displayCharts = this.filterByKeyword(this.charts, value);
190
    this.displayNumbers = this.filterByKeyword(this.numbers, value);
191
  }
192
  
193
  private filterChartType(indicators: Indicator[], value): Indicator[] {
194
    if (value === 'all') {
195
      return indicators;
196
    } else {
197
      return indicators.filter(indicator =>
198
        indicator.indicatorPaths.filter(indicatorPath => indicatorPath.type === value).length > 0);
107 199
    }
108

  
109
    public toggleOpen(event = null) {
110
        if (!event) {
111
            this.layoutService.setOpen(!this.open);
112
        } else if (event && event['value'] === true) {
113
            this.layoutService.setOpen(false);
114
        }
200
  }
201
  
202
  private filterPrivacy(indicators: Indicator[], value): Indicator[] {
203
    if (value === 'all') {
204
      return indicators;
205
    } else {
206
      return indicators.filter(indicator => indicator.isPublic === value);
115 207
    }
116

  
117
    public changeGrid(value) {
118
        this.grid = value;
208
  }
209
  
210
  private filterStatus(indicators: Indicator[], value): Indicator[] {
211
    if (value === 'all') {
212
      return indicators;
213
    } else {
214
      return indicators.filter(indicator => indicator.isActive === value);
119 215
    }
120

  
121
    private buildFilters() {
122
        this.filters = this.fb.group({
123
            chartType: this.fb.control('all'),
124
            privacy: this.fb.control('all'),
125
            status: this.fb.control('all'),
126
            keyword: this.fb.control('')
127
        });
128
        this.subscriptions.push(this.filters.get('chartType').valueChanges.subscribe(value => {
129
            this.onChartTypeChange(value);
130
        }));
131
        this.subscriptions.push(this.filters.get('privacy').valueChanges.subscribe(value => {
132
            this.onPrivacyChange(value);
133
        }));
134
        this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => {
135
            this.onStatusChange(value);
136
        }));
137
        this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => {
138
            this.onKeywordChange(value);
139
        }));
216
  }
217
  
218
  private filterByKeyword(indicators: Indicator[], value): Indicator[] {
219
    if (value === null || value === '') {
220
      return indicators;
221
    } else {
222
      return indicators.filter(indicator => (indicator.name && indicator.name.toLowerCase().includes(value.toLowerCase()))
223
        || (indicator.description && indicator.description.toLowerCase().includes(value.toLowerCase())));
140 224
    }
141

  
142
    filterCharts() {
143
        this.displayCharts = this.filterChartType(this.filterPrivacy(
144
            this.filterStatus(this.filterByKeyword(this.charts, this.filters.value.keyword),
145
                this.filters.value.status),
146
            this.filters.value.privacy),
147
            this.filters.value.chartType
148
        );
149
    }
150

  
151
    filterNumbers() {
152
        this.displayNumbers = this.filterPrivacy(this.filterStatus(
153
            this.filterByKeyword(this.numbers, this.filters.value.keyword),
154
            this.filters.value.status),
155
            this.filters.value.privacy);
156
    }
157

  
158
    onChartTypeChange(value) {
159
        this.displayCharts = this.filterChartType(this.charts, value);
160
    }
161

  
162
    onPrivacyChange(value) {
163
        this.displayCharts = this.filterPrivacy(this.charts, value);
164
        this.displayNumbers = this.filterPrivacy(this.numbers, value);
165
    }
166

  
167
    onStatusChange(value) {
168
        this.displayCharts = this.filterStatus(this.charts, value);
169
        this.displayNumbers = this.filterStatus(this.numbers, value);
170
    }
171

  
172
    onKeywordChange(value) {
173
        this.displayCharts = this.filterByKeyword(this.charts, value);
174
        this.displayNumbers = this.filterByKeyword(this.numbers, value);
175
    }
176

  
177
    private filterChartType(indicators: Indicator[], value): Indicator[] {
178
        if (value === 'all') {
179
            return indicators;
180
        } else {
181
            return indicators.filter(indicator =>
182
                indicator.indicatorPaths.filter(indicatorPath => indicatorPath.type === value).length > 0);
225
  }
226
  
227
  get charts(): Indicator[] {
228
    return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts;
229
  }
230
  
231
  set charts(indicators: Indicator[]) {
232
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts = indicators;
233
  }
234
  
235
  get numbers(): Indicator[] {
236
    return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers;
237
  }
238
  
239
  set numbers(indicators: Indicator[]) {
240
    this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = indicators;
241
  }
242
  
243
  get open(): boolean {
244
    return this.layoutService.open;
245
  }
246
  
247
  get canNumbersReorder(): boolean {
248
    return this.numberReorder && this.displayNumbers.length === this.numbers.length && this.grid;
249
  }
250
  
251
  get canChartsReorder(): boolean {
252
    return this.chartReorder && this.displayCharts.length === this.charts.length && this.grid;
253
  }
254
  
255
  get canEdit() {
256
    return this.stakeholder &&
257
      this.stakeholder.topics[this.topicIndex] &&
258
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
259
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex];
260
  }
261
  
262
  public get indicatorPaths(): FormArray {
263
    return this.indicatorFb.get('indicatorPaths') as FormArray;
264
  }
265
  
266
  public getParameters(index: number): FormArray {
267
    return this.indicatorPaths.at(index).get('parameters') as FormArray;
268
  }
269
  
270
  public getParameter(index: number, key: string): FormControl {
271
    return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as FormControl;
272
  }
273
  
274
  private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) {
275
    return this.sanitizer.bypassSecurityTrustResourceUrl(
276
      this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(indicatorPath)));
277
  }
278
  
279
  private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
280
    return this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(indicatorPath));
281
  }
282
  
283
  public addIndicatorPath(value: string = '', parameters: FormArray = new FormArray([])) {
284
    this.indicatorPaths.push(this.fb.group({
285
        url: this.fb.control(value, [Validators.required,
286
          Validators.pattern('https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.' +
287
            '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.' +
288
            '[a-zA-Z0-9]+\.[^\s]{2,}')]),
289
        parameters: parameters
290
      }
291
    ));
292
    let index = this.indicatorPaths.length - 1;
293
    this.urlSubscriptions.push(this.indicatorPaths.at(index).valueChanges.subscribe(value => {
294
        if (this.indicatorPaths.at(index).valid) {
295
          let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(value.url), value.url);
296
          let parameters = this.getParametersAsFormArray(indicatorPath);
297
          (this.indicatorPaths.at(index) as FormGroup).setControl('parameters', parameters);
298
          if (!this.indicator.indicatorPaths[index]) {
299
            this.indicator.indicatorPaths[index] = indicatorPath;
300
            this.indicator.indicatorPaths[index].safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
301
          } else {
302
            indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl;
303
            this.indicator.indicatorPaths[index] = indicatorPath;
304
          }
183 305
        }
184
    }
185

  
186
    private filterPrivacy(indicators: Indicator[], value): Indicator[] {
187
        if (value === 'all') {
188
            return indicators;
189
        } else {
190
            return indicators.filter(indicator => indicator.isPublic === value);
306
      })
307
    );
308
  }
309
  
310
  private getParametersAsFormArray(indicatorPath: IndicatorPath): FormArray {
311
    let parameters = this.fb.array([]);
312
    if (indicatorPath.parameters) {
313
      Object.keys(indicatorPath.parameters).forEach(key => {
314
        if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) {
315
          if (this.indicatorUtils.parametersValidators.has(key)) {
316
            parameters.push(this.fb.group({
317
              key: this.fb.control(key),
318
              value: this.fb.control(indicatorPath.parameters[key], this.indicatorUtils.parametersValidators.get(key))
319
            }));
320
          } else {
321
            parameters.push(this.fb.group({
322
              key: this.fb.control(key),
323
              value: this.fb.control(indicatorPath.parameters[key])
324
            }));
325
          }
191 326
        }
327
      });
192 328
    }
193

  
194
    private filterStatus(indicators: Indicator[], value): Indicator[] {
195
        if (value === 'all') {
196
            return indicators;
197
        } else {
198
            return indicators.filter(indicator => indicator.isActive === value);
199
        }
329
    return parameters;
330
  }
331
  
332
  public editChartIndicatorOpen(id = null) {
333
    this.urlSubscriptions.forEach(value => {
334
      if (value instanceof Subscriber) {
335
        value.unsubscribe();
336
      }
337
    });
338
    this.index = (id) ? this.charts.findIndex(value => value._id === id) : -1;
339
    if (this.index !== -1) {
340
      this.indicator = HelperFunctions.copy(this.charts[this.index]);
341
      this.indicatorFb = this.fb.group({
342
        id: this.fb.control(this.indicator._id),
343
        name: this.fb.control(this.indicator.name/*, Validators.required*/),
344
        description: this.fb.control(this.indicator.description),
345
        isPublic: this.fb.control(this.indicator.isPublic),
346
        isActive: this.fb.control(this.indicator.isActive),
347
        indicatorPaths: this.fb.array([]),
348
        width: this.fb.control(this.indicator.width),
349
      });
350
      this.indicator.indicatorPaths.forEach(indicatorPath => {
351
        this.addIndicatorPath(this.getUrlByStakeHolder(indicatorPath), this.getParametersAsFormArray(indicatorPath));
352
        indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath)
353
      });
354
    } else {
355
      this.indicator = new Indicator('', '', 'chart', 'small', false, false, []);
356
      this.indicatorFb = this.fb.group({
357
        id: this.fb.control(null),
358
        name: this.fb.control(''),
359
        description: this.fb.control(''),
360
        isPublic: this.fb.control(false),
361
        isActive: this.fb.control(false),
362
        indicatorPaths: this.fb.array([]),
363
        width: this.fb.control('small', Validators.required),
364
      });
365
      this.addIndicatorPath();
200 366
    }
201

  
202
    private filterByKeyword(indicators: Indicator[], value): Indicator[] {
203
        if (value === null || value === '') {
204
            return indicators;
205
        } else {
206
            return indicators.filter(indicator => (indicator.name && indicator.name.toLowerCase().includes(value.toLowerCase()))
207
                || (indicator.description && indicator.description.toLowerCase().includes(value.toLowerCase())));
208
        }
367
    this.editIndicatorModal.cancelButtonText = 'Cancel';
368
    this.editIndicatorModal.okButtonLeft = false;
369
    this.editIndicatorModal.alertMessage = false;
370
    if (this.index === -1) {
371
      this.editIndicatorModal.alertTitle = 'Create a new chart Indicator';
372
      this.editIndicatorModal.okButtonText = 'Save';
373
    } else {
374
      this.editIndicatorModal.okButtonText = 'Save Changes';
209 375
    }
210

  
211
    get charts(): Indicator[] {
212
        return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts;
376
    this.editIndicatorModal.open();
377
  }
378
  
379
  saveIndicator() {
380
    if (this.indicator.type === 'chart') {
381
      this.indicator = this.indicatorUtils.generateIndicatorByForm(this.indicatorFb.value, this.indicator.indicatorPaths);
213 382
    }
214

  
215
    set charts(indicators: Indicator[]) {
216
        this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts = indicators;
383
    let path = [
384
      this.stakeholder._id,
385
      this.stakeholder.topics[this.topicIndex]._id,
386
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
387
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
388
    ];
389
    this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.indicator, path).subscribe(indicator => {
390
      if (this.index !== -1) {
391
        this.charts[this.index] = indicator;
392
      } else {
393
        this.charts.push(indicator);
394
      }
395
      this.filterCharts();
396
      this.stakeholderService.setStakeholder(this.stakeholder);
397
      this.indicatorFb = null;
398
    }, error => {
399
      this.indicatorFb = null;
400
    });
401
  }
402
  
403
  reorderIndicators(type: string, indicatorIds: string[]) {
404
    let path = [
405
      this.stakeholder._id,
406
      this.stakeholder.topics[this.topicIndex]._id,
407
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
408
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
409
    ];
410
    this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicatorIds, type).subscribe(indicators => {
411
      if (type === 'chart') {
412
        this.charts = indicators;
413
        this.filterCharts();
414
      } else {
415
        this.numbers = indicators;
416
        this.filterNumbers();
417
      }
418
      this.stakeholderService.setStakeholder(this.stakeholder);
419
    });
420
  }
421
  
422
  hasDifference(index: number): boolean {
423
    return this.indicator.indicatorPaths[index].safeResourceUrl.toString() !==
424
      this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString();
425
  }
426
  
427
  refreshIndicator() {
428
    this.indicator = this.indicatorUtils.generateIndicatorByForm(this.indicatorFb.value, this.indicator.indicatorPaths);
429
    this.indicator.indicatorPaths.forEach(indicatorPath => {
430
      indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
431
    });
432
  }
433
  
434
  deleteIndicatorOpen(id: string, type: string = 'chart') {
435
    if (type === 'chart') {
436
      this.indicator = this.charts.find(value => value._id == id);
437
    } else {
438
      this.indicator = this.numbers.find(value => value._id == id);
217 439
    }
218

  
219
    get numbers(): Indicator[] {
220
        return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers;
221
    }
222

  
223
    set numbers(indicators: Indicator[]) {
224
        this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = indicators;
225
    }
226

  
227
    get open(): boolean {
228
        return this.layoutService.open;
229
    }
230

  
231
    get canNumbersReorder(): boolean {
232
        return this.displayNumbers.length === this.numbers.length;
233
    }
234

  
235
    get canChartsReorder(): boolean {
236
        return this.displayCharts.length === this.charts.length;
237
    }
238

  
239
    get canEdit() {
240
        return this.stakeholder &&
241
            this.stakeholder.topics[this.topicIndex] &&
242
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
243
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex];
244
    }
245

  
246
    public get indicatorPaths(): FormArray {
247
        return this.indicatorFb.get('indicatorPaths') as FormArray;
248
    }
249

  
250
    public getParameters(index: number): FormArray {
251
        return this.indicatorPaths.at(index).get('parameters') as FormArray;
252
    }
253

  
254
    public getParameter(index: number, key: string): FormControl {
255
        return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as FormControl;
256
    }
257

  
258
    private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) {
259
        return this.sanitizer.bypassSecurityTrustResourceUrl(
260
            this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(indicatorPath)));
261
    }
262

  
263
    private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
264
        return this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(indicatorPath));
265
    }
266

  
267
    public addIndicatorPath(value: string = '', parameters: FormArray = new FormArray([])) {
268
        this.indicatorPaths.push(this.fb.group({
269
                url: this.fb.control(value, [Validators.required,
270
                    Validators.pattern('https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.' +
271
                        '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.' +
272
                        '[a-zA-Z0-9]+\.[^\s]{2,}')]),
273
                parameters: parameters
274
            }
275
        ));
276
        let index = this.indicatorPaths.length - 1;
277
        this.urlSubscriptions.push(this.indicatorPaths.at(index).valueChanges.subscribe(value => {
278
                if (this.indicatorPaths.at(index).valid) {
279
                    let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(value.url), value.url);
280
                    let parameters = this.getParametersAsFormArray(indicatorPath);
281
                    (this.indicatorPaths.at(index) as FormGroup).setControl('parameters', parameters);
282
                    if (!this.indicator.indicatorPaths[index]) {
283
                        this.indicator.indicatorPaths[index] = indicatorPath;
284
                        this.indicator.indicatorPaths[index].safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
285
                    } else {
286
                        indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl;
287
                        this.indicator.indicatorPaths[index] = indicatorPath;
288
                    }
289
                }
290
            })
291
        );
292
    }
293

  
294
    private getParametersAsFormArray(indicatorPath: IndicatorPath): FormArray {
295
        let parameters = this.fb.array([]);
296
        if (indicatorPath.parameters) {
297
            Object.keys(indicatorPath.parameters).forEach(key => {
298
                if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) {
299
                    if (this.indicatorUtils.parametersValidators.has(key)) {
300
                        parameters.push(this.fb.group({
301
                            key: this.fb.control(key),
302
                            value: this.fb.control(indicatorPath.parameters[key], this.indicatorUtils.parametersValidators.get(key))
303
                        }));
304
                    } else {
305
                        parameters.push(this.fb.group({
306
                            key: this.fb.control(key),
307
                            value: this.fb.control(indicatorPath.parameters[key])
308
                        }));
309
                    }
310
                }
311
            });
312
        }
313
        return parameters;
314
    }
315

  
316
    public editChartIndicatorOpen(id = null) {
317
        this.urlSubscriptions.forEach(value => {
318
           if(value instanceof Subscriber) {
319
               value.unsubscribe();
320
           }
321
        });
322
        this.index = (id) ? this.charts.findIndex(value => value._id === id) : -1;
323
        if (this.index !== -1) {
324
            this.indicator = HelperFunctions.copy(this.charts[this.index]);
325
            this.indicatorFb = this.fb.group({
326
                id: this.fb.control(this.indicator._id),
327
                name: this.fb.control(this.indicator.name/*, Validators.required*/),
328
                description: this.fb.control(this.indicator.description),
329
                isPublic: this.fb.control(this.indicator.isPublic),
330
                isActive: this.fb.control(this.indicator.isActive),
331
                indicatorPaths: this.fb.array([]),
332
                width: this.fb.control(this.indicator.width),
333
            });
334
            this.indicator.indicatorPaths.forEach(indicatorPath => {
335
                this.addIndicatorPath(this.getUrlByStakeHolder(indicatorPath), this.getParametersAsFormArray(indicatorPath));
336
                indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath)
337
            });
338
        } else {
339
            this.indicator = new Indicator('', '', 'chart', 'small', false, false, []);
340
            this.indicatorFb = this.fb.group({
341
                id: this.fb.control(null),
342
                name: this.fb.control(''),
343
                description: this.fb.control(''),
344
                isPublic: this.fb.control(false),
345
                isActive: this.fb.control(false),
346
                indicatorPaths: this.fb.array([]),
347
                width: this.fb.control('small', Validators.required),
348
            });
349
            this.addIndicatorPath();
350
        }
351
        this.editIndicatorModal.cancelButtonText = 'Cancel';
352
        this.editIndicatorModal.okButtonLeft = false;
353
        this.editIndicatorModal.alertMessage = false;
354
        if (this.index === -1) {
355
            this.editIndicatorModal.alertTitle = 'Create a new chart Indicator';
356
            this.editIndicatorModal.okButtonText = 'Save';
357
        } else {
358
            this.editIndicatorModal.okButtonText = 'Save Changes';
359
        }
360
        this.editIndicatorModal.open();
361
    }
362

  
363
    saveIndicator() {
364
        if (this.indicator.type === 'chart') {
365
            this.indicator = this.indicatorUtils.generateIndicatorByForm(this.indicatorFb.value, this.indicator.indicatorPaths);
366
        }
367
        let path = [
368
            this.stakeholder._id,
369
            this.stakeholder.topics[this.topicIndex]._id,
370
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
371
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
372
        ];
373
        this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.indicator, path).subscribe(indicator => {
374
            if (this.index !== -1) {
375
                this.charts[this.index] = indicator;
376
            } else {
377
                this.charts.push(indicator);
378
            }
379
            this.filterCharts();
380
            this.stakeholderService.setStakeholder(this.stakeholder);
381
            this.indicatorFb = null;
382
        }, error => {
383
            this.indicatorFb = null;
384
        });
385
    }
386

  
387
    reorderIndicators(type: string, indicatorIds: string[]) {
388
        let path = [
389
            this.stakeholder._id,
390
            this.stakeholder.topics[this.topicIndex]._id,
391
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
392
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id
393
        ];
394
        this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicatorIds, type).subscribe(indicators => {
395
            if (type === 'chart') {
396
                this.charts = indicators;
397
                this.filterCharts();
398
            } else {
399
                this.numbers = indicators;
400
                this.filterNumbers();
401
            }
402
            this.stakeholderService.setStakeholder(this.stakeholder);
403
        });
404
    }
405

  
406
    hasDifference(index: number): boolean {
407
        return this.indicator.indicatorPaths[index].safeResourceUrl.toString() !==
408
            this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString();
409
    }
410

  
411
    refreshIndicator() {
412
        this.indicator = this.indicatorUtils.generateIndicatorByForm(this.indicatorFb.value, this.indicator.indicatorPaths);
413
        this.indicator.indicatorPaths.forEach(indicatorPath => {
414
            indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
415
        });
416
    }
417

  
418
    deleteIndicatorOpen(id: string, type: string = 'chart') {
419
        if (type === 'chart') {
420
            this.indicator = this.charts.find(value => value._id == id);
421
        } else {
422
            this.indicator = this.numbers.find(value => value._id == id);
423
        }
424
        this.deleteIndicatorModal.alertTitle = 'Delete ' + this.indicator.name;
425
        this.deleteIndicatorModal.cancelButtonText = 'No';
426
        this.deleteIndicatorModal.okButtonText = 'Yes';
427
        this.deleteIndicatorModal.message = 'This indicator will permanently be deleted. Are you sure you want to proceed?';
428
        this.deleteIndicatorModal.open();
429
    }
430

  
431
    deleteIndicator() {
432
        let path = [
433
            this.stakeholder._id,
434
            this.stakeholder.topics[this.topicIndex]._id,
435
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
436
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
437
            this.indicator._id
438
        ];
439
        this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => {
440
            if (this.indicator.type === 'chart') {
441
                this.charts.splice(this.index, 1);
442
            } else {
443
                this.numbers.splice(this.index, 1);
444
            }
445
            this.stakeholderService.setStakeholder(this.stakeholder);
446
        });
447
    }
448

  
449
    toggleIndicatorStatus(indicator: Indicator) {
450
        let path = [
451
            this.stakeholder._id,
452
            this.stakeholder.topics[this.topicIndex]._id,
453
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
454
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
455
            indicator._id
456
        ];
457
        this.stakeholderService.toggleStatus(this.properties.monitorServiceAPIURL, path).subscribe(isActive => {
458
            indicator.isActive = isActive;
459
            this.stakeholderService.setStakeholder(this.stakeholder);
460
        });
461
    }
462

  
463
    toggleIndicatorAccess(indicator: Indicator) {
464
        let path = [
465
            this.stakeholder._id,
466
            this.stakeholder.topics[this.topicIndex]._id,
467
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
468
            this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
469
            indicator._id
470
        ];
471
        this.stakeholderService.toggleAccess(this.properties.monitorServiceAPIURL, path).subscribe(isPublic => {
472
            indicator.isPublic = isPublic;
473
            this.stakeholderService.setStakeholder(this.stakeholder);
474
        });
475
    }
440
    this.deleteIndicatorModal.alertTitle = 'Delete ' + this.indicator.name;
441
    this.deleteIndicatorModal.cancelButtonText = 'No';
442
    this.deleteIndicatorModal.okButtonText = 'Yes';
443
    this.deleteIndicatorModal.message = 'This indicator will permanently be deleted. Are you sure you want to proceed?';
444
    this.deleteIndicatorModal.open();
445
  }
446
  
447
  deleteIndicator() {
448
    let path = [
449
      this.stakeholder._id,
450
      this.stakeholder.topics[this.topicIndex]._id,
451
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
452
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
453
      this.indicator._id
454
    ];
455
    this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => {
456
      if (this.indicator.type === 'chart') {
457
        this.charts.splice(this.index, 1);
458
      } else {
459
        this.numbers.splice(this.index, 1);
460
      }
461
      this.stakeholderService.setStakeholder(this.stakeholder);
462
    });
463
  }
464
  
465
  toggleIndicatorStatus(indicator: Indicator) {
466
    let path = [
467
      this.stakeholder._id,
468
      this.stakeholder.topics[this.topicIndex]._id,
469
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
470
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
471
      indicator._id
472
    ];
473
    this.stakeholderService.toggleStatus(this.properties.monitorServiceAPIURL, path).subscribe(isActive => {
474
      indicator.isActive = isActive;
475
      this.stakeholderService.setStakeholder(this.stakeholder);
476
    });
477
  }
478
  
479
  toggleIndicatorAccess(indicator: Indicator) {
480
    let path = [
481
      this.stakeholder._id,
482
      this.stakeholder.topics[this.topicIndex]._id,
483
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id,
484
      this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id,
485
      indicator._id
486
    ];
487
    this.stakeholderService.toggleAccess(this.properties.monitorServiceAPIURL, path).subscribe(isPublic => {
488
      indicator.isPublic = isPublic;
489
      this.stakeholderService.setStakeholder(this.stakeholder);
490
    });
491
  }
476 492
}

Also available in: Unified diff