import { AfterViewInit, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from "@angular/core"; import { Indicator, IndicatorPath, IndicatorSize, IndicatorType, Section, Stakeholder, Visibility } from "../openaireLibrary/monitor/entities/stakeholder"; import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils"; import {FormArray, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; import {AlertModal} from "../openaireLibrary/utils/modal/alert"; import {StatisticsService} from "../utils/services/statistics.service"; import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class"; import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; import {Reorder, StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service"; import {EnvProperties} from "../openaireLibrary/utils/properties/env-properties"; import {Subscriber} from "rxjs"; import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service"; import {Router} from "@angular/router"; import {Role, Session, User} from "../openaireLibrary/login/utils/helper.class"; import {UserManagementService} from "../openaireLibrary/services/user-management.service"; import {StringUtils} from "../openaireLibrary/utils/string-utils.class"; import {Notification} from "../openaireLibrary/notifications/notifications"; import {NotificationUtils} from "../openaireLibrary/notifications/notification-utils"; import {NotifyFormComponent} from "../openaireLibrary/notifications/notify-form/notify-form.component"; declare var UIkit; @Component({ selector: 'indicators', templateUrl: './indicators.component.html', styleUrls: ['indicators.component.css'] }) export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit { @Input() public properties: EnvProperties = null; @Input() public topicIndex: number = 0; @Input() public categoryIndex: number = 0; @Input() public subcategoryIndex: number = 0; public stakeholder: Stakeholder = null; public user: User = null; public preview: string; public indicatorUtils: IndicatorUtils = new IndicatorUtils(); public stakeholderUtils: StakeholderUtils = new StakeholderUtils(); public numberIndicatorFb: FormGroup; public chartIndicatorFb: FormGroup; public chartSections: FormArray; public numberSections: FormArray; /** * Editable indicator */ public section: Section; public indicator: Indicator; public index: number = -1; /** * Displayed chart and numbers base on Top filters */ public displayCharts: Section[] = []; public displayNumbers: Section[] = []; /** * Top filters */ @Input() public filters: FormGroup; public editing: boolean = false; /** Safe Urls*/ public safeUrls: Map = new Map([]); public numberResults: Map = new Map(); private subscriptions: any[] = []; private urlSubscriptions: any[] = []; @ViewChild('editChartModal', { static: true }) editChartModal: AlertModal; @ViewChild('editNumberModal', { static: true }) editNumberModal: AlertModal; @ViewChild('deleteModal', { static: true }) deleteModal: AlertModal; //@ViewChild('deleteAllModal') deleteAllModal: AlertModal; //@ViewChild('deleteAndDisconnectModal') deleteAndDisconnectModal: AlertModal; //@ViewChild('deleteChartSectionModal') deleteChartSectionModal: AlertModal; //@ViewChild('deleteNumberSectionModal') deleteNumberSectionModal: AlertModal; @ViewChild('deleteSectionModal', { static: true }) deleteSectionModal: AlertModal; public sectionTypeToDelete: string; public sectionChildrenActionOnDelete: string; public indicatorChildrenActionOnDelete: string; private firstLoad: boolean = true; urlParameterizedMessage = null; showCheckForSchemaEnhancements:boolean = false; private notification: Notification; @ViewChild('editNumberNotify', { static: true }) editNumberNotify: NotifyFormComponent; @ViewChild('editChartNotify', { static: true }) editChartNotify: NotifyFormComponent; @ViewChild('deleteNotify', { static: true }) deleteNotify: NotifyFormComponent; constructor(private layoutService: LayoutService, private stakeholderService: StakeholderService, private statisticsService: StatisticsService, private userManagementService: UserManagementService, private fb: FormBuilder, private router: Router, private cdr: ChangeDetectorRef, private sanitizer: DomSanitizer) { } ngOnInit(): void { this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.user = user; })); this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { this.stakeholder = stakeholder; if (this.stakeholder && this.firstLoad) { this.buildFilters(); this.buildSections(); this.filterCharts(); this.filterNumbers(); this.setPreview(); this.firstLoad = false; } })); } ngOnDestroy(): void { this.subscriptions.forEach(value => { if (value instanceof Subscriber) { value.unsubscribe(); } else if (value instanceof Function) { value(); } }); this.urlSubscriptions.forEach(value => { if (value instanceof Subscriber) { value.unsubscribe(); } }); } ngAfterViewInit(): void { this.initReorder(); } ngOnChanges(changes: SimpleChanges): void { if (this.canEdit) { if (changes.topicIndex || changes.categoryIndex || changes.subcategoryIndex) { this.buildSections(); this.buildFilters(); this.initReorder(); } this.filterCharts(); this.filterNumbers(); } this.setPreview(); } setNumberIndicators() { this.numberResults.clear(); let urls: Map = new Map(); this.numbers.forEach((section, i) => { section.indicators.forEach((number, j) => { let url = this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, number.indicatorPaths[0]); const pair = JSON.stringify([number.indicatorPaths[0].source, url]); const indexes = urls.get(pair) ? urls.get(pair) : []; indexes.push([i, j]); urls.set(pair, indexes); }); }); urls.forEach((indexes, pair) => { pair = JSON.parse(pair); this.subscriptions.push(this.statisticsService.getNumbers(this.statisticsService.getSourceType(pair[0]), pair[1]).subscribe(response => { indexes.forEach(([i, j]) => { let result = JSON.parse(JSON.stringify(response)); this.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { if (result) { result = result[jsonPath]; } }); if (typeof result === 'string' || typeof result === 'number') { result = Number(result); if (result === Number.NaN) { result = 0; } } else { result = 0; } this.numberResults.set(i + '-' + j, result); }); })); }); } setPreview() { if (this.stakeholder) { this.preview = '/' + this.stakeholder.alias; if (this.stakeholder.topics[this.topicIndex]) { this.preview = '/' + this.stakeholder.alias + '/' + this.stakeholder.topics[this.topicIndex].alias; if (this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]) { this.preview += '/' + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].alias; if (this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { this.preview += '/' + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].alias; } } } } } initReorder() { this.subscriptions.forEach(value => { if (value instanceof Function) { value(); } }); if (document !== undefined) { let callback = (list, type: IndicatorType, action: 'moved' | 'added' | 'removed'): void => { let items: HTMLCollection = list.current.children; let reordered = []; for (let i = 0; i < items.length; i++) { if (items.item(i).id) { reordered.push(items.item(i).id); } } let reorder: Reorder = { action: action, target: list.detail[1].id, ids: reordered } this.reorderIndicators(list.current.id.toString().split('-')[1], type, reorder); }; this.numbers.forEach((section) => { this.subscriptions.push(UIkit.util.on(document, 'moved', '#number-' + section._id, (list): void => { callback(list, "number", 'moved'); })); this.subscriptions.push(UIkit.util.on(document, 'added', '#number-' + section._id, (list): void => { callback(list, "number", 'added'); })); this.subscriptions.push(UIkit.util.on(document, 'removed', '#number-' + section._id, (list): void => { callback(list, "number", 'removed'); })); }); this.charts.forEach((section) => { this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => { callback(list, "chart", 'moved'); })); this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => { callback(list, "chart", 'added'); })); this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => { callback(list, "chart", 'removed'); })); }); } } hide(element: any) { UIkit.dropdown(element).hide(); } private buildFilters() { this.subscriptions.push(this.filters.get('chartType').valueChanges.subscribe(value => { this.onChartTypeChange(value); })); this.subscriptions.push(this.filters.get('status').valueChanges.subscribe(value => { this.onStatusChange(value); })); this.subscriptions.push(this.filters.get('keyword').valueChanges.subscribe(value => { this.onKeywordChange(value); })); } private buildSections() { this.numberSections = this.fb.array([]); this.numbers.forEach(section => { this.numberSections.push(this.fb.group({ _id: this.fb.control(section._id), title: this.fb.control(section.title), creationDate: this.fb.control(section.creationDate), stakeholderAlias: this.fb.control(section.stakeholderAlias), defaultId: this.fb.control(section.defaultId), type: this.fb.control(section.type), indicators: this.fb.control(section.indicators) })); }); this.chartSections = this.fb.array([]); this.charts.forEach(section => { this.chartSections.push(this.fb.group({ _id: this.fb.control(section._id), title: this.fb.control(section.title), creationDate: this.fb.control(section.creationDate), stakeholderAlias: this.fb.control(section.stakeholderAlias), defaultId: this.fb.control(section.defaultId), type: this.fb.control(section.type), indicators: this.fb.control(section.indicators) })); }); } filterCharts() { this.displayCharts = this.filterChartType( this.filterStatus(this.filterByKeyword(HelperFunctions.copy(this.charts), this.filters.value.keyword), this.filters.value.status), this.filters.value.chartType ); this.displayCharts.forEach(section => { section.indicators.forEach(indicator => { indicator.indicatorPaths.forEach(indicatorPath => { let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath); if (!this.safeUrls.get('url')) { indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); this.safeUrls.set(url, indicatorPath.safeResourceUrl); } }); }) }); this.buildSections(); } filterNumbers() { this.displayNumbers = this.filterStatus( this.filterByKeyword(HelperFunctions.copy(this.numbers), this.filters.value.keyword), this.filters.value.status); this.buildSections(); this.setNumberIndicators(); } onChartTypeChange(value) { this.displayCharts = this.filterChartType(HelperFunctions.copy(this.charts), value); } onStatusChange(value) { this.displayCharts = this.filterStatus(HelperFunctions.copy(this.charts), value); this.displayNumbers = this.filterStatus(HelperFunctions.copy(this.numbers), value); } onKeywordChange(value) { this.displayCharts = this.filterByKeyword(HelperFunctions.copy(this.charts), value); this.displayNumbers = this.filterByKeyword(HelperFunctions.copy(this.numbers), value); } private filterChartType(sections: Section[], value): Section[] { if (value !== 'all') { sections.forEach(section => section.indicators = section.indicators.filter(indicator => indicator.indicatorPaths.filter(indicatorPath => indicatorPath.type === value).length > 0)); } return sections; } private filterStatus(sections: Section[], value): Section[] { if (value !== 'all') { sections.forEach(section => section.indicators = section.indicators.filter(indicator => indicator.visibility === value)); } return sections; } private filterByKeyword(sections: Section[], value): Section[] { if (value !== null && value !== '') { sections.forEach(section => section.indicators = section.indicators.filter(indicator => (indicator.name && indicator.name.toLowerCase().includes(value.toLowerCase())) || (indicator.description && indicator.description.toLowerCase().includes(value.toLowerCase())) || (indicator.additionalDescription && indicator.additionalDescription.toLowerCase().includes(value.toLowerCase())) || indicator.indicatorPaths.filter(indicatorPath => (indicatorPath.parameters && indicatorPath.parameters.title && indicatorPath.parameters.title.includes(value.toLowerCase()))).length > 0)); } return sections; } get charts(): Section[] { if (this.stakeholder.topics[this.topicIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts; } else { return []; } } set charts(sections: Section[]) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts = sections; } get numbers(): Section[] { if (this.stakeholder.topics[this.topicIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers; } else { return []; } } set numbers(sections: Section[]) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = sections; } get open(): boolean { return this.layoutService.open; } get canReorder(): boolean { return this.filters.value.chartType === 'all' && this.filters.value.status === 'all' && this.filters.value.keyword === '' && !this.editing; } get canEdit() { return this.stakeholder && this.stakeholder.topics[this.topicIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]; } public get numberIndicatorPaths(): FormArray { return this.numberIndicatorFb.get('indicatorPaths') as FormArray; } public get chartIndicatorPaths(): FormArray { return this.chartIndicatorFb.get('indicatorPaths') as FormArray; } public getNumberClassBySize(size: IndicatorSize) { if (size === 'small') { return 'uk-width-1-4@xl uk-width-1-3@l uk-width-1-2@m uk-width-1-1'; } else if (size === 'medium') { return 'uk-width-1-3@l uk-width-1-2@m uk-width-1-1'; } else { return 'uk-width-1-2@l uk-width-1-1@m uk-width-1-1'; } } public getChartClassBySize(size: IndicatorSize) { if (size === 'small') { return 'uk-width-1-3@xl uk-width-1-2@m uk-width-1-1'; } else if (size === 'medium') { return 'uk-width-1-2@l uk-width-1-1'; } else { return 'uk-width-1-1'; } } public addJsonPath(index: number) { if (index == 0 && this.getJsonPath(index).getRawValue()[index].indexOf(",") != -1) { //if in the first path there are more than one paths comma separated, split them and autogenerate the forms let paths = this.getJsonPath(index).getRawValue()[index].split(","); for (let i = 0; i < paths.length; i++) { if (i != 0) { this.getJsonPath(index).push(this.fb.control('', Validators.required)); } } this.getJsonPath(index).setValue(paths) } else { this.getJsonPath(index).push(this.fb.control('', Validators.required)); } } public removeJsonPath(i: number, j: number) { if (this.getJsonPath(i).enabled) { this.getJsonPath(i).removeAt(j); } } public validateJsonPath(index: number, dirty: boolean = false) { let indicatorPath: FormGroup = this.numberIndicatorPaths.at(index); if (this.indicator.defaultId === null) { this.getJsonPath(index).disable(); } indicatorPath.get('result').setErrors({validating: true}); this.subscriptions.push(this.statisticsService.getNumbers(null, indicatorPath.get('url').value).subscribe(response => { let result = JSON.parse(JSON.stringify(response)); this.getJsonPath(index).controls.forEach(jsonPath => { if (result) { result = result[jsonPath.value]; } }); setTimeout(() => { if (this.indicator.defaultId === null) { this.getJsonPath(index).enable(); if (dirty) { this.getJsonPath(index).markAsDirty(); } } indicatorPath.get('result').setErrors(null); if (typeof result === 'string' || typeof result === 'number') { result = Number(result); if (result !== Number.NaN) { indicatorPath.get('result').setValue(result); } else { indicatorPath.get('result').setValue(0); } } else { indicatorPath.get('result').setValue(0); } }, 500); }, error => { setTimeout(() => { if (this.indicator.defaultId === null) { this.getJsonPath(index).enable(); if (dirty) { this.getJsonPath(index).markAsDirty(); } } indicatorPath.get('result').setErrors(null); indicatorPath.get('result').setValue(0); }, 500); })); } public getJsonPath(index: number): FormArray { return this.numberIndicatorPaths.at(index).get('jsonPath') as FormArray; } public getCurrentJsonPath(index: number): string[] { return this.section.indicators[this.index].indicatorPaths[index].jsonPath; } public getParameters(index: number): FormArray { return this.chartIndicatorPaths.at(index).get('parameters') as FormArray; } public getParameter(index: number, key: string): FormControl { return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as FormControl; } private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) { return this.sanitizer.bypassSecurityTrustResourceUrl( this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath))); } private getUrlByStakeHolder(indicatorPath: IndicatorPath) { return this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)); } public addNumberIndicatorPath(url: string = '', parameters: FormArray = new FormArray([]), source: string = 'stats-tool', jsonPath: FormArray = new FormArray([])) { if (jsonPath.length === 0) { jsonPath.push(this.fb.control('', Validators.required)); } this.numberIndicatorPaths.push(this.fb.group({ url: this.fb.control(url, [Validators.required, StringUtils.urlValidator()]), jsonPath: jsonPath, result: this.fb.control(0, Validators.required), // parameters: parameters, source: this.fb.control(source, Validators.required) } )); let index = this.numberIndicatorPaths.length - 1; if (this.numberIndicatorPaths.at(index).get('url').valid) { this.validateJsonPath(index); this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value); } if (this.indicator.defaultId === null) { this.subscriptions.push(this.numberIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => { this.numberIndicatorPaths.at(index).get('result').setValue(null); if (this.numberIndicatorPaths.at(index).get('url').valid) { let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.statisticsService.getNumberSource(value), value, this.stakeholder, this.numberIndicatorPaths.at(index).get('jsonPath').value, this.statisticsService.numberSources.get(this.statisticsService.getNumberSource(value))); 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) || (!indicatorPath.chartObject && indicatorPath.url.indexOf("index_id") == -1 && indicatorPath.url.indexOf("index_name") == -1 && (indicatorPath.url).indexOf("index_shortName") == -1)) { // default profile if (this.stakeholder.defaultId == null) { this.urlParameterizedMessage = "This indicator couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly." } else { this.urlParameterizedMessage = "This indicator couldn't be generated properly. Please make sure chart data is for the current stakeholder." } } else { this.urlParameterizedMessage = null; } this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value); if (this.indicator.indicatorPaths[index]) { this.indicator.indicatorPaths[index] = indicatorPath; } else { this.indicator.indicatorPaths.push(indicatorPath); } if (indicatorPath.source) { this.numberIndicatorPaths.at(index).get('source').setValue(indicatorPath.source); } if (indicatorPath.jsonPath.length > 1 && this.getJsonPath(index).length == 1) { let paths = indicatorPath.jsonPath; for (let i = 0; i < paths.length; i++) { if (i == this.getJsonPath(index).length) { this.getJsonPath(index).push(this.fb.control('', Validators.required)); } } this.getJsonPath(index).setValue(paths) } } else { this.urlParameterizedMessage = null; } }) ); this.subscriptions.push(this.numberIndicatorPaths.at(index).get('jsonPath').valueChanges.subscribe(value => { if (this.indicator.indicatorPaths[index]) { this.indicator.indicatorPaths[index].jsonPath = value; } this.numberIndicatorPaths.at(index).get('result').setValue(null); }) ); this.subscriptions.push(this.numberIndicatorPaths.at(index).get('source').valueChanges.subscribe(value => { if (this.indicator.indicatorPaths[index]) { this.indicator.indicatorPaths[index].source = value; } }) ); } else { this.numberIndicatorPaths.at(index).get('url').disable(); this.numberIndicatorPaths.at(index).get('jsonPath').disable(); this.numberIndicatorPaths.at(index).get('source').disable(); } } public addChartIndicatorPath(value: string = '', parameters: FormArray = new FormArray([]), disableUrl: boolean = false, type: string = null) { this.chartIndicatorPaths.push(this.fb.group({ url: this.fb.control(value, [Validators.required, StringUtils.urlValidator()]), parameters: parameters, type: this.fb.control(type) } )); let index = this.chartIndicatorPaths.length - 1; if (disableUrl) { this.chartIndicatorPaths.at(index).get('url').disable(); } else { this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value); this.urlSubscriptions.push(this.chartIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => { if (this.chartIndicatorPaths.at(index).get('url').valid) { let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder); 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) { // default profile if (this.stakeholder.defaultId == null) { this.urlParameterizedMessage = "This chart couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly." } else { this.urlParameterizedMessage = "This chart couldn't be generated properly. Please make sure chart data is for the current stakeholder." } } else { this.urlParameterizedMessage = null; } this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value); (this.chartIndicatorPaths.at(index) as FormGroup).get('type').setValue(indicatorPath.type); let parameters = this.getParametersAsFormArray(indicatorPath); (this.chartIndicatorPaths.at(index) as FormGroup).setControl('parameters', parameters); if (!this.indicator.indicatorPaths[index]) { this.indicator.indicatorPaths[index] = indicatorPath; this.indicator.indicatorPaths[index].safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); } else { indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl; this.indicator.indicatorPaths[index] = indicatorPath; } } else { this.urlParameterizedMessage = null; } })); } } private getJsonPathAsFormArray(indicatorPath: IndicatorPath): FormArray { let jsonPath = this.fb.array([]); if (indicatorPath.jsonPath) { indicatorPath.jsonPath.forEach(path => { jsonPath.push(this.fb.control(path, Validators.required)); }); } return jsonPath; } private getParametersAsFormArray(indicatorPath: IndicatorPath): FormArray { let parameters = this.fb.array([]); if (indicatorPath.parameters) { Object.keys(indicatorPath.parameters).forEach(key => { if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) { if (this.indicatorUtils.parametersValidators.has(key)) { parameters.push(this.fb.group({ key: this.fb.control(key), value: this.fb.control(indicatorPath.parameters[key], this.indicatorUtils.parametersValidators.get(key)) })); } else { parameters.push(this.fb.group({ key: this.fb.control(key), value: this.fb.control(indicatorPath.parameters[key]) })); } } }); } return parameters; } public editNumberIndicatorOpen(section: Section, id = null) { this.urlParameterizedMessage = null; this.section = section; this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1; if (this.index !== -1) { this.indicator = HelperFunctions.copy(this.section.indicators[this.index]); this.numberIndicatorFb = this.fb.group({ _id: this.fb.control(this.indicator._id), name: this.fb.control(this.indicator.name, Validators.required), description: this.fb.control(this.indicator.description), creationDate: this.fb.control(this.indicator.creationDate), additionalDescription: this.fb.control(this.indicator.additionalDescription), visibility: this.fb.control(this.indicator.visibility), indicatorPaths: this.fb.array([], Validators.required), type: this.fb.control(this.indicator.type), width: this.fb.control(this.indicator.width), height: this.fb.control(this.indicator.height), defaultId: this.fb.control(this.indicator.defaultId) }); this.indicator.indicatorPaths.forEach(indicatorPath => { this.addNumberIndicatorPath(this.statisticsService.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)), indicatorPath.parameters, indicatorPath.source, this.getJsonPathAsFormArray(indicatorPath)); }); } else { this.indicator = new Indicator('', '', '', 'number', 'small', 'small', "PUBLIC", []); this.numberIndicatorFb = this.fb.group({ _id: this.fb.control(this.indicator._id), name: this.fb.control(this.indicator.name, Validators.required), description: this.fb.control(this.indicator.description), additionalDescription: this.fb.control(this.indicator.additionalDescription), visibility: this.fb.control(this.indicator.visibility), indicatorPaths: this.fb.array([], Validators.required), type: this.fb.control(this.indicator.type), width: this.fb.control(this.indicator.width), height: this.fb.control(this.indicator.height), defaultId: this.fb.control(this.indicator.defaultId) }); this.addNumberIndicatorPath(); } if (this.indicator.defaultId) { setTimeout(() => { this.numberIndicatorFb.get('description').disable(); }, 0); } this.editNumberModal.cancelButtonText = 'Cancel'; this.editNumberModal.okButtonLeft = false; this.editNumberModal.alertMessage = false; if (this.index === -1) { this.editNumberModal.alertTitle = 'Create a new number indicator'; this.editNumberModal.okButtonText = 'Save'; this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); this.editNumberNotify.reset(this.notification.message); } else { this.editNumberModal.alertTitle = 'Edit number indicator\'s information'; this.editNumberModal.okButtonText = 'Save Changes'; this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); this.editNumberNotify.reset(this.notification.message); } this.editNumberModal.open(); } public editChartIndicatorOpen(section: Section, id = null) { this.urlParameterizedMessage = null; this.urlSubscriptions.forEach(value => { if (value instanceof Subscriber) { value.unsubscribe(); } }); this.section = section; this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1; if (this.index !== -1) { this.indicator = HelperFunctions.copy(this.section.indicators[this.index]); this.chartIndicatorFb = this.fb.group({ _id: this.fb.control(this.indicator._id), name: this.fb.control(this.indicator.name), creationDate: this.fb.control(this.indicator.creationDate), description: this.fb.control(this.indicator.description), additionalDescription: this.fb.control(this.indicator.additionalDescription), visibility: this.fb.control(this.indicator.visibility), indicatorPaths: this.fb.array([]), width: this.fb.control(this.indicator.width), height: this.fb.control(this.indicator.height), defaultId: this.fb.control(this.indicator.defaultId) }); this.indicator.indicatorPaths.forEach(indicatorPath => { this.addChartIndicatorPath(this.getUrlByStakeHolder(indicatorPath), this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type); indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); }); } else { this.indicator = new Indicator('', '', '', 'chart', 'medium', 'medium', "PUBLIC", []); this.chartIndicatorFb = this.fb.group({ _id: this.fb.control(this.indicator._id), name: this.fb.control(this.indicator.name), description: this.fb.control(this.indicator.description), additionalDescription: this.fb.control(this.indicator.additionalDescription), visibility: this.fb.control(this.indicator.visibility), indicatorPaths: this.fb.array([]), width: this.fb.control(this.indicator.width, Validators.required), height: this.fb.control(this.indicator.height, Validators.required), defaultId: this.fb.control(this.indicator.defaultId) }); this.addChartIndicatorPath(); } if (this.indicator.defaultId) { setTimeout(() => { this.chartIndicatorFb.get('description').disable(); }, 0); } this.editChartModal.cancelButtonText = 'Cancel'; this.editChartModal.okButtonLeft = false; this.editChartModal.alertMessage = false; if (this.index === -1) { this.editChartModal.alertTitle = 'Create a new chart indicator'; this.editChartModal.okButtonText = 'Save'; this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); this.editChartNotify.reset(this.notification.message); } else { this.editChartModal.alertTitle = 'Edit chart indicator\'s information'; this.editChartModal.okButtonText = 'Save Changes'; this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);; this.editChartNotify.reset(this.notification.message); } this.editChartModal.open(); } saveIndicator() { this.editing = true; if (this.indicator.type === 'chart') { this.chartIndicatorFb.get('description').enable(); this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths, this.indicator.type, true); this.section = this.charts.find(section => section._id === this.section._id); } else { this.numberIndicatorFb.get('description').enable(); this.indicator = this.indicatorUtils.generateIndicatorByForm(this.numberIndicatorFb.value, this.indicator.indicatorPaths, this.indicator.type, false); this.section = this.numbers.find(section => section._id === this.section._id); } let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, this.section._id ]; this.subscriptions.push(this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.indicator, path).subscribe(indicator => { if (this.index !== -1) { this.section.indicators[this.index] = indicator; } else { this.section.indicators.push(indicator); } this.notification.entity = indicator._id; this.notification.stakeholder = this.stakeholder.alias; this.notification.stakeholderType = this.stakeholder.type; this.notification.groups = [Role.curator( this.stakeholder.type)]; if(this.stakeholder.defaultId) { this.notification.groups.push(Role.manager(this.stakeholder.type, this.stakeholder.alias)); if (this.indicator.type === "chart") { this.filterCharts(); this.chartIndicatorFb = null; this.editChartNotify.sendNotification(this.notification); } else { this.filterNumbers(); this.numberIndicatorFb = null; this.editNumberNotify.sendNotification(this.notification); } } else { this.stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL, null, this.stakeholder._id).subscribe(stakeholders => { stakeholders.forEach(value => { this.notification.groups.push(Role.manager(value.type, value.alias)) }); if (this.indicator.type === "chart") { this.filterCharts(); this.chartIndicatorFb = null; this.editChartNotify.sendNotification(this.notification); } else { this.filterNumbers(); this.numberIndicatorFb = null; this.editNumberNotify.sendNotification(this.notification); } }); } UIkit.notification('Indicator has been successfully saved', { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.editing = false; }, error => { this.chartIndicatorFb = null; UIkit.notification(error.error.message, { status: 'danger', timeout: 6000, pos: 'bottom-right' }); this.editing = false; })); } reorderIndicators(sectionId: string, type: IndicatorType, reorder: Reorder) { this.editing = true; let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, sectionId ]; this.subscriptions.push(this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, reorder, type).subscribe(indicators => { if (type === 'chart') { this.charts.find(section => section._id === sectionId).indicators = indicators; this.filterCharts(); } else { this.numbers.find(section => section._id === sectionId).indicators = indicators; this.filterNumbers(); } this.editing = false; })); } hasDifference(index: number): boolean { let hasDifference = false; this.chartIndicatorPaths.at(index).value.parameters.forEach((parameter) => { if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) { hasDifference = true; return; } }); return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !== this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString(); } public get isAdministrator(): boolean { return Session.isPortalAdministrator(this.user); } public get isCurator(): boolean { return this.isAdministrator || Session.isMonitorCurator(this.user); } refreshIndicator() { this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths, 'chart', true); this.indicator.indicatorPaths.forEach(indicatorPath => { indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); }); } deleteIndicatorOpen(section: Section, indicatorId: string, type: string, childrenAction: string = null) { this.indicatorChildrenActionOnDelete = null; if (childrenAction == "delete") { this.indicatorChildrenActionOnDelete = childrenAction; } else if (childrenAction == "disconnect") { this.indicatorChildrenActionOnDelete = childrenAction; } this.section = section; if (type === 'chart') { this.index = this.charts.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId); } else { this.index = this.numbers.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId); } this.indicator = section.indicators.find(value => value._id == indicatorId); this.deleteModal.alertTitle = 'Delete indicator'; this.deleteModal.cancelButtonText = 'No'; this.deleteModal.okButtonText = 'Yes'; this.notification = NotificationUtils.deleteIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); this.deleteNotify.reset(this.notification.message); this.deleteModal.open(); } deleteIndicator() { this.editing = true; let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, this.section._id, this.indicator._id ]; this.subscriptions.push(this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path, this.indicatorChildrenActionOnDelete).subscribe(() => { if (this.indicator.type === 'chart') { this.charts.find(section => section._id === this.section._id).indicators.splice(this.index, 1); this.filterCharts(); } else { this.numbers.find(section => section._id === this.section._id).indicators.splice(this.index, 1); this.filterNumbers(); } UIkit.notification('Indicator has been successfully deleted', { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.notification.entity = this.indicator._id; this.notification.stakeholder = this.stakeholder.alias; this.notification.stakeholderType = this.stakeholder.type; this.notification.groups = [Role.curator( this.stakeholder.type)]; if(this.stakeholder.defaultId) { this.notification.groups.push(Role.manager(this.stakeholder.type, this.stakeholder.alias)); this.deleteNotify.sendNotification(this.notification); } else { this.stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL, null, this.stakeholder._id).subscribe(stakeholders => { stakeholders.forEach(value => { this.notification.groups.push(Role.manager(value.type, value.alias)) }); this.deleteNotify.sendNotification(this.notification); }); } this.editing = false; }, error => { UIkit.notification(error.error.message, { status: 'danger', timeout: 6000, pos: 'bottom-right' }); this.editing = false; })); } changeIndicatorStatus(sectionId: string, indicator: Indicator, visibility: Visibility) { this.editing = true; let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, sectionId, indicator._id ]; this.subscriptions.push(this.stakeholderService.changeVisibility(this.properties.monitorServiceAPIURL, path, visibility).subscribe(visibility => { indicator.visibility = visibility; UIkit.notification('Indicator has been successfully changed to ' + indicator.visibility.toLowerCase(), { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.editing = false; }, error => { UIkit.notification('An error has been occurred. Try again later', { status: 'danger', timeout: 6000, pos: 'bottom-right' }); this.editing = false; })); } saveSection(section: Section, index: number, type: IndicatorType = "chart") { this.editing = true; let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id ]; this.subscriptions.push(this.stakeholderService.saveSection(this.properties.monitorServiceAPIURL, section, path, index).subscribe(section => { if (type === 'chart') { this.charts[index] = section; this.filterCharts(); } else { this.numbers[index] = section; this.filterNumbers(); } this.initReorder(); UIkit.notification('Section has been successfully saved', { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.editing = false; }, error => { UIkit.notification(error.error.message, { status: 'danger', timeout: 6000, pos: 'bottom-right' }); this.editing = false; })); } createSection(index = -1, type: IndicatorType = 'chart') { this.editing = true; this.section = new Section(type, null, null, this.stakeholder.alias); let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id ]; this.subscriptions.push(this.stakeholderService.saveSection(this.properties.monitorServiceAPIURL, this.section, path, index).subscribe(section => { if (type === 'chart') { if (index !== -1) { this.charts.splice(index, 0, section); } else { this.charts.push(section); } this.filterCharts(); } else { if (index !== -1) { this.numbers.splice(index, 0, section); } else { this.numbers.push(section); } this.filterNumbers(); } this.initReorder(); UIkit.notification('Section has been successfully created', { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.editing = false; }, error => { UIkit.notification(error.error.message, { status: 'danger', timeout: 6000, pos: 'bottom-right' }); this.editing = false; })); } // deleteNumberSectionOpen(section: Section, index: number) { // this.section = section; // this.index = index; // this.deleteNumberSectionModal.alertTitle = 'Delete Section'; // this.deleteNumberSectionModal.cancelButtonText = 'No'; // this.deleteNumberSectionModal.okButtonText = 'Yes'; // this.deleteNumberSectionModal.open(); // } // // deleteChartSectionOpen(section: Section, index: number) { // this.section = section; // this.index = index; // this.deleteChartSectionModal.alertTitle = 'Delete Section'; // this.deleteChartSectionModal.cancelButtonText = 'No'; // this.deleteChartSectionModal.okButtonText = 'Yes'; // this.deleteChartSectionModal.open(); // } deleteSectionOpen(section: Section, index: number, type: IndicatorType, childrenAction: string = null) { if (!this.editing && !section.defaultId) { this.sectionTypeToDelete = type; this.sectionChildrenActionOnDelete = null; if (childrenAction == "delete") { this.sectionChildrenActionOnDelete = childrenAction; } else if (childrenAction == "disconnect") { this.sectionChildrenActionOnDelete = childrenAction; } this.section = section; this.index = index; this.deleteSectionModal.alertTitle = 'Delete Section'; this.deleteSectionModal.cancelButtonText = 'No'; this.deleteSectionModal.okButtonText = 'Yes'; this.deleteSectionModal.open(); } } deleteSection() { this.editing = true; let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, this.section._id ]; this.subscriptions.push(this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path, this.sectionChildrenActionOnDelete).subscribe(() => { if (this.sectionTypeToDelete === "chart") { this.charts.splice(this.index, 1); this.filterCharts(); } else { this.numbers.splice(this.index, 1); this.filterNumbers(); } this.initReorder(); UIkit.notification('Section has been successfully deleted', { status: 'success', timeout: 6000, pos: 'bottom-right' }); this.editing = false; }, error => { UIkit.notification(error.error.message, { status: 'danger', timeout: 6000, pos: 'bottom-right' }); this.editing = false; })); } private checkForSchemaEnhancements(url:string){ //new schema this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url); } }