diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 21bde89..f313169 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectorRef, Component, OnDestroy, OnInit} from '@angular/core'; -import {ActivatedRoute, NavigationEnd, RouteConfigLoadEnd, Router} from '@angular/router'; +import {ActivatedRoute, NavigationEnd, Router} from '@angular/router'; import {EnvProperties} from './openaireLibrary/utils/properties/env-properties'; import {EnvironmentSpecificService} from './openaireLibrary/utils/properties/environment-specific.service'; diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 820196d..282a518 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -163,7 +163,13 @@ export class HomeComponent implements OnInit, OnDestroy { index_id: this.fb.control(this.stakeholder.index_id, Validators.required), index_shortName: this.fb.control(this.stakeholder.index_shortName, Validators.required), isDefaultProfile: this.fb.control(this.stakeholder.isDefaultProfile), - alias: this.fb.control(this.stakeholder.alias, Validators.required), + alias: this.fb.control(this.stakeholder.alias, + [ + Validators.required, + this.stakeholderUtils.aliasValidator( + (this.stakeholder.isDefaultProfile) ? this.defaultStakeholders : this.stakeholders + )] + ), isPublic: this.fb.control(this.stakeholder.isPublic), isActive: this.fb.control(this.stakeholder.isActive), type: this.fb.control(this.stakeholder.type, Validators.required), @@ -196,7 +202,7 @@ export class HomeComponent implements OnInit, OnDestroy { public saveStakeholder() { if (this.index === -1) { - if(!this.stakeholderFb.value.isDefaultProfile) { + if (!this.stakeholderFb.value.isDefaultProfile) { // this.stakeholderFb.setValue(this.stakeholderUtils. // createFunderFromDefaultProfile(this.stakeholderFb.value, // this.defaultStakeholders.find( value => value.type === this.stakeholderFb.value.type).topics)); diff --git a/src/app/library/sharedComponents/sidebar/layout.service.ts b/src/app/library/sharedComponents/sidebar/layout.service.ts index e1aa032..7ce2bfc 100644 --- a/src/app/library/sharedComponents/sidebar/layout.service.ts +++ b/src/app/library/sharedComponents/sidebar/layout.service.ts @@ -10,7 +10,7 @@ export class LayoutService { /** * Set this to true when sidebar items are ready. */ - private openSubject: BehaviorSubject = new BehaviorSubject(true); + private openSubject: BehaviorSubject = new BehaviorSubject(false); /** * Add hasSidebar: false on data of route config, if sidebar is not needed. diff --git a/src/app/library/sharedComponents/sidebar/sideBar.component.html b/src/app/library/sharedComponents/sidebar/sideBar.component.html index c25c0b2..ede2142 100644 --- a/src/app/library/sharedComponents/sidebar/sideBar.component.html +++ b/src/app/library/sharedComponents/sidebar/sideBar.component.html @@ -13,7 +13,7 @@ [class.act_section]="item.open" [title]="item.name" [class.submenu_trigger]="item.items.length > 1"> - + {{item.icon}} {{item.name}} diff --git a/src/app/library/sharedComponents/sidebar/sideBar.component.ts b/src/app/library/sharedComponents/sidebar/sideBar.component.ts index 10e7b8b..40cf37a 100644 --- a/src/app/library/sharedComponents/sidebar/sideBar.component.ts +++ b/src/app/library/sharedComponents/sidebar/sideBar.component.ts @@ -15,6 +15,7 @@ export class SideBarComponent implements OnInit { constructor() {} ngOnInit(): void { + console.log(this.items); } diff --git a/src/app/monitor/monitor.component.html b/src/app/monitor/monitor.component.html index 67b280d..c9d423a 100644 --- a/src/app/monitor/monitor.component.html +++ b/src/app/monitor/monitor.component.html @@ -1,175 +1,178 @@
-
-
-
-
- - -
settings
-
+ + +
settings
+
diff --git a/src/app/monitor/monitor.component.ts b/src/app/monitor/monitor.component.ts index 0ab31b1..f3c09cd 100644 --- a/src/app/monitor/monitor.component.ts +++ b/src/app/monitor/monitor.component.ts @@ -85,47 +85,47 @@ export class MonitorComponent implements OnInit, OnDestroy, IDeactivateComponent this.status = this.errorCodes.LOADING; this.numberResults = new Map(); this.chartsActiveType = new Map(); - // this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { - let stakeholder: Stakeholder = null; - if (params['stakeholder'] == "fwf") { - stakeholder = new Stakeholder(null, "funder", "fwf_________::FWF", "Austrian Science Fund (FWF)", "FWF", - false, "fwf", true, true, null); - stakeholder = this.stakeholderUtils.createFunderFromDefaultProfile(stakeholder, StakeholderCreator.createFunderDefaultProfile().topics); - stakeholder.logoUrl = "./assets/fwf.png"; - } else if (params['stakeholder'] == "arc") { - stakeholder = new Stakeholder(null, "funder", "arc_________::ARC", - "Australian Research Council (ARC)", "ARC", - false, null, true, true, null); - stakeholder = this.stakeholderUtils.createFunderFromDefaultProfile(stakeholder, StakeholderCreator.createFunderDefaultProfile().topics); - stakeholder.logoUrl = "./assets/arc1.gif"; - } else { - stakeholder = new Stakeholder(null, "funder", "ec__________::EC", - "European Commission", "EC", - false, "ec", true, true, null); - stakeholder = this.stakeholderUtils.createFunderFromDefaultProfile(stakeholder, StakeholderCreator.createFunderDefaultProfile().topics); - stakeholder.logoUrl = "./assets/ec.png"; - } - if (stakeholder) { - this.stakeholder = stakeholder; - this.seoService.createLinkForCanonicalURL(url, false); - this._meta.updateTag({content: url}, "property='og:url'"); - var description = "Monitor Dashboard | " + this.stakeholder.index_name; - var title = "Monitor Dashboard | " + this.stakeholder.index_shortName; - this._meta.updateTag({content: description}, "name='description'"); - this._meta.updateTag({content: description}, "property='og:description'"); - this._meta.updateTag({content: title}, "property='og:title'"); - this._title.setTitle(title); - if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) { - this.piwiksub = this._piwikService.trackView(this.properties, title, this.properties.piwikSiteId).subscribe(); + this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { + /*let stakeholder: Stakeholder = null; + if (params['stakeholder'] == "fwf") { + stakeholder = new Stakeholder(null, "funder", "fwf_________::FWF", "Austrian Science Fund (FWF)", "FWF", + false, "fwf", true, true, null); + stakeholder = this.stakeholderUtils.createFunderFromDefaultProfile(stakeholder, StakeholderCreator.createFunderDefaultProfile().topics); + stakeholder.logoUrl = "./assets/fwf.png"; + } else if (params['stakeholder'] == "arc") { + stakeholder = new Stakeholder(null, "funder", "arc_________::ARC", + "Australian Research Council (ARC)", "ARC", + false, null, true, true, null); + stakeholder = this.stakeholderUtils.createFunderFromDefaultProfile(stakeholder, StakeholderCreator.createFunderDefaultProfile().topics); + stakeholder.logoUrl = "./assets/arc1.gif"; + } else { + stakeholder = new Stakeholder(null, "funder", "ec__________::EC", + "European Commission", "EC", + false, "ec", true, true, null); + stakeholder = this.stakeholderUtils.createFunderFromDefaultProfile(stakeholder, StakeholderCreator.createFunderDefaultProfile().topics); + stakeholder.logoUrl = "./assets/ec.png"; + }*/ + if (stakeholder) { + this.stakeholder = stakeholder; + this.seoService.createLinkForCanonicalURL(url, false); + this._meta.updateTag({content: url}, "property='og:url'"); + var description = "Monitor Dashboard | " + this.stakeholder.index_name; + var title = "Monitor Dashboard | " + this.stakeholder.index_shortName; + this._meta.updateTag({content: description}, "name='description'"); + this._meta.updateTag({content: description}, "property='og:description'"); + this._meta.updateTag({content: title}, "property='og:title'"); + this._title.setTitle(title); + if (this.properties.enablePiwikTrack && (typeof document !== 'undefined')) { + this.piwiksub = this._piwikService.trackView(this.properties, title, this.properties.piwikSiteId).subscribe(); + } + //this.getDivContents(); + this.getPageContents(); + this.status = this.errorCodes.DONE; + this.setView(params); } - //this.getDivContents(); - this.getPageContents(); - this.status = this.errorCodes.DONE; - this.setView(params); - } - // }, error => { - // this.navigateToError(); - // }) + }, error => { + this.navigateToError(); + }) } else { this.setView(params); } @@ -172,25 +172,27 @@ export class MonitorComponent implements OnInit, OnDestroy, IDeactivateComponent } private setView(params: Params) { - if (params && params['topic']) { + if (params['topic']) { this.activeTopic = this.stakeholder.topics.find(topic => topic.alias === decodeURIComponent(params['topic']) && topic.isPublic && topic.isActive); if (this.activeTopic) { if (params['category']) { this.activeCategory = this.activeTopic.categories.find(category => (category.alias === params['category']) && category.isPublic && category.isActive); + if(!this.activeCategory) { + this.navigateToError(); + return; + } } else { this.activeCategory = this.activeTopic.categories.find(category => category.isPublic && category.isActive); if (this.activeCategory) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => subCategory.isPublic && subCategory.isActive); + this.setSideBar(); if (this.activeSubCategory) { - this.setSideBar(); this.setIndicators(); - } else { - this.navigateToError(); } } else { - this.navigateToError(); + this.setSideBar(); } return; } @@ -198,6 +200,10 @@ export class MonitorComponent implements OnInit, OnDestroy, IDeactivateComponent if (params['subCategory']) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => (subCategory.alias === params['subCategory'] && subCategory.isPublic && subCategory.isActive)); + if(!this.activeSubCategory) { + this.navigateToError(); + return; + } } else { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => subCategory.isPublic && subCategory.isActive); @@ -209,9 +215,13 @@ export class MonitorComponent implements OnInit, OnDestroy, IDeactivateComponent this.navigateToError(); } return; + } else { + this.activeSubCategory = null; } + } else { + this.navigateToError(); + return; } - this.navigateToError(); } else { this.activeTopic = this.stakeholder.topics.find(topic => topic.isPublic && topic.isActive); if (this.activeTopic) { @@ -254,6 +264,9 @@ export class MonitorComponent implements OnInit, OnDestroy, IDeactivateComponent subItems, null, open)); } }); + if(items.length === 0) { + items.push(new Item('noCategories', 'No categories available yet', null, [], null, false)); + } this.sideBar = new Sidebar(items, null); } diff --git a/src/app/stakeholder/stakeholder.component.ts b/src/app/stakeholder/stakeholder.component.ts index f8d4318..20fe5d8 100644 --- a/src/app/stakeholder/stakeholder.component.ts +++ b/src/app/stakeholder/stakeholder.component.ts @@ -12,177 +12,189 @@ import {AlertModal} from "../openaireLibrary/utils/modal/alert"; import {Subscriber} from "rxjs"; import {FormBuilder, FormGroup, Validators} from "@angular/forms"; import {LayoutService} from "../library/sharedComponents/sidebar/layout.service"; -import {IndicatorUtils} from "../utils/indicator-utils"; +import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils"; declare var UIkit; @Component({ - selector: 'stakeholder', - templateUrl: './stakeholder.component.html', + selector: 'stakeholder', + templateUrl: './stakeholder.component.html', }) export class StakeholderComponent implements OnInit, OnDestroy { - public subscriptions: any[] = []; - public loading: boolean = true; - public errorCodes: ErrorCodes; - public stakeholder: Stakeholder; - public analysisOpen: boolean = true; - private errorMessages: ErrorMessagesComponent; - public topicFb: FormGroup; - public indicatorUtils: IndicatorUtils = new IndicatorUtils(); - public element: any; - public index: number; - properties: EnvProperties; + public subscriptions: any[] = []; + public loading: boolean = true; + public errorCodes: ErrorCodes; + public stakeholder: Stakeholder; + public analysisOpen: boolean = true; + private errorMessages: ErrorMessagesComponent; + public topicFb: FormGroup; + public indicatorUtils: IndicatorUtils = new IndicatorUtils(); + public stakeholderUtils: StakeholderUtils = new StakeholderUtils(); + public element: any; + public index: number; + properties: EnvProperties; - @ViewChild('deleteTopicModal') deleteTopicModal: AlertModal; + @ViewChild('deleteTopicModal') deleteTopicModal: AlertModal; - constructor( - private route: ActivatedRoute, - private router: Router, - private title: Title, - private layoutService: LayoutService, - private fb: FormBuilder, - private stakeholderService: StakeholderService) { - this.errorCodes = new ErrorCodes(); - this.errorMessages = new ErrorMessagesComponent(); - } + constructor( + private route: ActivatedRoute, + private router: Router, + private title: Title, + private layoutService: LayoutService, + private fb: FormBuilder, + private stakeholderService: StakeholderService) { + this.errorCodes = new ErrorCodes(); + this.errorMessages = new ErrorMessagesComponent(); + } - public ngOnInit() { - this.route.data - .subscribe((data: { envSpecific: EnvProperties }) => { - this.properties = data.envSpecific; - this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { - if (stakeholder) { - this.stakeholder = HelperFunctions.copy(stakeholder); - this.topicFb = null; - this.title.setTitle(stakeholder.index_name); + public ngOnInit() { + this.route.data + .subscribe((data: { envSpecific: EnvProperties }) => { + this.properties = data.envSpecific; + this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { + if (stakeholder) { + this.stakeholder = HelperFunctions.copy(stakeholder); + this.topicFb = null; + this.title.setTitle(stakeholder.index_name); + } + })); + }); + } + + public ngOnDestroy() { + this.subscriptions.forEach(value => { + if (value instanceof Subscriber) { + value.unsubscribe(); + } + }); + } + + public show(element) { + UIkit.drop(element).show(); + } + + public hide(element) { + UIkit.drop(element).hide(); + } + + get open(): boolean { + return this.layoutService.open; + } + + public toggleOpen(event = null) { + if (!event) { + this.layoutService.setOpen(!this.open); + } else if (event && event['value'] === true) { + this.layoutService.setOpen(false); + } + } + + private buildTopic(topic: Topic) { + let topics = this.stakeholder.topics.filter(element => element._id !== topic._id); + this.topicFb = this.fb.group({ + _id: this.fb.control(topic._id), + name: this.fb.control(topic.name, Validators.required), + description: this.fb.control(topic.description), + alias: this.fb.control(topic.alias, [ + Validators.required, + this.stakeholderUtils.aliasValidator(topics) + ] + ), + isActive: this.fb.control(topic.isActive), + isPublic: this.fb.control(topic.isPublic), + isDefault: this.fb.control(topic.isDefault), + categories: this.fb.control(topic.categories) + }); + this.subscriptions.push(this.topicFb.get('name').valueChanges.subscribe(value => { + let i = 1; + value = this.stakeholderUtils.generateAlias(value); + this.topicFb.controls['alias'].setValue(value); + while (this.topicFb.get('alias').invalid) { + this.topicFb.controls['alias'].setValue(value + i); + i++; } })); - }); - } - - public ngOnDestroy() { - this.subscriptions.forEach(value => { - if (value instanceof Subscriber) { - value.unsubscribe(); - } - }); - } - - public show(element) { - UIkit.drop(element).show(); - } - - public hide(element) { - UIkit.drop(element).hide(); - } - - get open(): boolean { - return this.layoutService.open; - } - - public toggleOpen(event = null) { - if (!event) { - this.layoutService.setOpen(!this.open); - } else if (event && event['value'] === true) { - this.layoutService.setOpen(false); } - } - private buildTopic(topic: Topic) { - this.topicFb = this.fb.group({ - _id: this.fb.control(topic._id), - name: this.fb.control(topic.name, Validators.required), - description: this.fb.control(topic.description), - alias: this.fb.control(topic.alias), - isActive: this.fb.control(topic.isActive), - isPublic: this.fb.control(topic.isPublic), - isDefault: this.fb.control(topic.isDefault), - categories: this.fb.control(topic.categories) - }); - } - - public saveTopicOpen(element, index = -1) { - if (element.className.indexOf('uk-open') !== -1) { - this.hide(element); - } else { - if (index === -1) { - this.buildTopic(new Topic(null, null, null, true, true, false)); - } else { - this.buildTopic(this.stakeholder.topics[index]); - } - this.show(element); + public saveTopicOpen(element, index = -1) { + if (element.className.indexOf('uk-open') !== -1) { + this.hide(element); + } else { + if (index === -1) { + this.buildTopic(new Topic(null, null, null, true, true, false)); + } else { + this.buildTopic(this.stakeholder.topics[index]); + } + this.show(element); + } } - } - public saveTopic(element, index = -1) { - if (!this.topicFb.invalid) { - if (!this.topicFb.value.alias) { - this.topicFb.value.alias = this.topicFb.value.name.toLowerCase().trim(); - } - if (index === -1) { - this.save('Topic has been successfully created', element); - } else { - this.save('Topic has been successfully saved', element, index); - } + public saveTopic(element, index = -1) { + if (!this.topicFb.invalid) { + if (index === -1) { + this.save('Topic has been successfully created', element); + } else { + this.save('Topic has been successfully saved', element, index); + } + } } - } - public deleteTopicOpen(name: string, element, index: number) { - this.element = element; - this.index = index; - this.deleteTopicModal.alertTitle = 'Delete ' + name; - this.deleteTopicModal.cancelButtonText = 'No'; - this.deleteTopicModal.okButtonText = 'Yes'; - this.deleteTopicModal.message = 'This topic will permanently be deleted. Are you sure you want to proceed?'; - this.deleteTopicModal.open(); - } + public deleteTopicOpen(name: string, element, index: number) { + this.element = element; + this.index = index; + this.deleteTopicModal.alertTitle = 'Delete ' + name; + this.deleteTopicModal.cancelButtonText = 'No'; + this.deleteTopicModal.okButtonText = 'Yes'; + this.deleteTopicModal.message = 'This topic will permanently be deleted. Are you sure you want to proceed?'; + this.deleteTopicModal.open(); + } - private save(message: string, element, index: number = -1) { - let path = [this.stakeholder._id]; - this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.topicFb.value, path).subscribe(topic => { - if (index === -1) { - this.stakeholder.topics.push(topic); - } else { - this.stakeholder.topics[index] = topic; - } - this.stakeholderService.setStakeholder(this.stakeholder); - UIkit.notification(message, { - status: 'success', - timeout: 3000000, - pos: 'top-left' - }); - this.hide(element); - }, error => { - UIkit.notification(error.error.message, { - status: 'danger', - timeout: 3000, - pos: 'top-left' - }); - this.hide(element); - }); - } + private save(message: string, element, index: number = -1) { + let path = [this.stakeholder._id]; + this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.topicFb.value, path).subscribe(topic => { + if (index === -1) { + this.stakeholder.topics.push(topic); + } else { + this.stakeholder.topics[index] = topic; + } + this.stakeholderService.setStakeholder(this.stakeholder); + UIkit.notification(message, { + status: 'success', + timeout: 3000, + pos: 'top-left' + }); + this.hide(element); + }, error => { + UIkit.notification(error.error.message, { + status: 'danger', + timeout: 3000, + pos: 'top-left' + }); + this.hide(element); + }); + } - deleteTopic() { - let path = [ - this.stakeholder._id, - this.stakeholder.topics[this.index]._id - ]; - this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => { - this.stakeholder.topics.splice(this.index, 1); - this.stakeholderService.setStakeholder(this.stakeholder); - UIkit.notification('Topic has been successfully deleted', { - status: 'success', - timeout: 3000, - pos: 'top-left' - }); - this.hide(this.element); - }, error => { - UIkit.notification(error.error.message, { - status: 'danger', - timeout: 3000, - pos: 'top-left' - }); - this.hide(this.element); - }); - } + deleteTopic() { + let path = [ + this.stakeholder._id, + this.stakeholder.topics[this.index]._id + ]; + this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => { + this.stakeholder.topics.splice(this.index, 1); + this.stakeholderService.setStakeholder(this.stakeholder); + UIkit.notification('Topic has been successfully deleted', { + status: 'success', + timeout: 3000, + pos: 'top-left' + }); + this.hide(this.element); + }, error => { + UIkit.notification(error.error.message, { + status: 'danger', + timeout: 3000, + pos: 'top-left' + }); + this.hide(this.element); + }); + } } diff --git a/src/app/topic/indicators.component.html b/src/app/topic/indicators.component.html index 67a011d..9e647bc 100644 --- a/src/app/topic/indicators.component.html +++ b/src/app/topic/indicators.component.html @@ -76,7 +76,7 @@ more_vert @@ -142,7 +142,7 @@ more_vert diff --git a/src/app/topic/indicators.component.ts b/src/app/topic/indicators.component.ts index 41a1a82..aee6608 100644 --- a/src/app/topic/indicators.component.ts +++ b/src/app/topic/indicators.component.ts @@ -292,7 +292,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV this.editIndicatorModal.open(); } - public createIndicator() { + public createChartIndicator() { this.indicator = new Indicator( this.indicatorFb.value.name, this.indicatorFb.value.description, @@ -306,10 +306,10 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV this.indicator.indicatorPaths.push( this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(url), url)); }); - this.editIndicatorOpen(); + this.editChartIndicatorOpen(); } - public editIndicatorOpen(id = null) { + public editChartIndicatorOpen(id = null) { this.index = (id)?this.charts.findIndex(value => value._id === id):-1; if (this.index !== -1) { this.indicator = HelperFunctions.copy(this.charts[this.index]); @@ -341,12 +341,12 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV }); this.indicatorFb = this.fb.group({ id: this.fb.control(this.indicator._id), - name: this.fb.control(this.indicator.name, Validators.required), + name: this.fb.control(this.indicator.name/*, Validators.required*/), description: this.fb.control(this.indicator.description), isPublic: this.fb.control(this.indicator.isPublic), isActive: this.fb.control(this.indicator.isActive), indicatorPaths: indicatorPaths, - width: this.fb.control(this.indicator.width, Validators.required), + width: this.fb.control(this.indicator.width), }); if(this.index === -1) { this.editIndicatorModal.okButtonText = 'Save'; @@ -365,7 +365,9 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV saveIndicator() { if(this.indicator) { - this.indicator = this.indicatorUtils.generateIndicatorByForm(this.indicatorFb.value, this.indicator.indicatorPaths); + if(this.indicator.type === 'chart') { + this.indicator = this.indicatorUtils.generateIndicatorByForm(this.indicatorFb.value, this.indicator.indicatorPaths); + } let path = [ this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id, @@ -385,7 +387,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV this.indicatorFb = null; }); } else { - this.createIndicator(); + this.createChartIndicator(); } } diff --git a/src/app/topic/topic.component.ts b/src/app/topic/topic.component.ts index e055044..b2320e6 100644 --- a/src/app/topic/topic.component.ts +++ b/src/app/topic/topic.component.ts @@ -6,368 +6,402 @@ import {Category, Stakeholder, SubCategory, Topic} from "../utils/entities/stake import {StakeholderService} from "../services/stakeholder.service"; import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class"; import {AlertModal} from "../openaireLibrary/utils/modal/alert"; -import {Subscriber} from "rxjs"; +import {Subscriber, Subscription} from "rxjs"; import {FormBuilder, FormGroup, Validators} from "@angular/forms"; -import {IndicatorUtils} from "../utils/indicator-utils"; +import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils"; declare var UIkit; @Component({ - selector: 'topic', - templateUrl: './topic.component.html', + selector: 'topic', + templateUrl: './topic.component.html', }) export class TopicComponent implements OnInit, OnDestroy { - public subscriptions: any[] = []; - public properties: EnvProperties; - public indicatorUtils: IndicatorUtils = new IndicatorUtils(); - public loading: boolean = true; - public stakeholder: Stakeholder; - /** - * Current topic - **/ - public topicIndex: number = 0; - public topicFb: FormGroup; + public subscriptions: any[] = []; + public properties: EnvProperties; + public indicatorUtils: IndicatorUtils = new IndicatorUtils(); + public stakeholderUtils: StakeholderUtils = new StakeholderUtils(); + public loading: boolean = true; + public stakeholder: Stakeholder; + /** + * Current topic + **/ + public topicIndex: number = 0; + public topicFb: FormGroup; - /** - * categoryIndex: Current category to be edited, selectedCategoryIndex: selected on menu(opened) - */ - public categoryIndex: number = 0; - public selectedCategoryIndex: number = 0; - public categoryFb: FormGroup; - /** - * Current Subcategory to be edited - */ - public subCategoryIndex: number = 0; - public subcategoryFb: FormGroup; - /** - * Current drop element and index of topic, category or subcategory to be deleted. - */ - public element: any; - public index: number; - /** - * Check form validity - */ - public toggle: boolean = false; + /** + * categoryIndex: Current category to be edited, selectedCategoryIndex: selected on menu(opened) + */ + public categoryIndex: number = 0; + public selectedCategoryIndex: number = 0; + public categoryFb: FormGroup; + /** + * Current Subcategory to be edited + */ + public subCategoryIndex: number = 0; + public subcategoryFb: FormGroup; + /** + * Current drop element and index of topic, category or subcategory to be deleted. + */ + public element: any; + public index: number; + /** + * Check form validity + */ + public toggle: boolean = false; - @ViewChild('deleteTopicModal') deleteTopicModal: AlertModal; - @ViewChild('deleteCategoryModal') deleteCategoryModal: AlertModal; - @ViewChild('deleteSubcategoryModal') deleteSubcategoryModal: AlertModal; + @ViewChild('deleteTopicModal') deleteTopicModal: AlertModal; + @ViewChild('deleteCategoryModal') deleteCategoryModal: AlertModal; + @ViewChild('deleteSubcategoryModal') deleteSubcategoryModal: AlertModal; - constructor( - private route: ActivatedRoute, - private router: Router, - private title: Title, - private fb: FormBuilder, - private stakeholderService: StakeholderService) { - } + constructor( + private route: ActivatedRoute, + private router: Router, + private title: Title, + private fb: FormBuilder, + private stakeholderService: StakeholderService) { + } - public ngOnInit() { - this.route.data - .subscribe((data: { envSpecific: EnvProperties }) => { - this.properties = data.envSpecific; - this.route.params.subscribe( params => { - this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { - if (stakeholder) { - this.stakeholder = HelperFunctions.copy(stakeholder); - this.topicIndex = this.stakeholder.topics.findIndex(topic => topic.alias === params['topic']); - if(this.topicIndex === -1) { - this.navigateToError(); - } else { - this.title.setTitle(stakeholder.index_shortName + ' | ' + this.stakeholder.topics[this.topicIndex].name); - this.toggle = true; - } + public ngOnInit() { + this.route.data + .subscribe((data: { envSpecific: EnvProperties }) => { + this.properties = data.envSpecific; + let subscription: Subscription; + this.subscriptions.push(this.route.params.subscribe(params => { + if(subscription) { + subscription.unsubscribe(); + } + subscription = this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => { + if (stakeholder) { + this.stakeholder = HelperFunctions.copy(stakeholder); + this.topicIndex = this.stakeholder.topics.findIndex(topic => topic.alias === params['topic']); + if (this.topicIndex === -1) { + this.navigateToError(); + } else { + this.title.setTitle(stakeholder.index_shortName + ' | ' + this.stakeholder.topics[this.topicIndex].name); + this.toggle = true; + } + } + }); + })); + }); + } + + public ngOnDestroy() { + this.subscriptions.forEach(value => { + if (value instanceof Subscriber) { + value.unsubscribe(); } - })); }); - }); - } - - public ngOnDestroy() { - this.subscriptions.forEach( value => { - if(value instanceof Subscriber) { - value.unsubscribe(); - } - }); - } - - public hide(element) { - UIkit.drop(element).hide(); - } - - public show(element) { - UIkit.drop(element).show(); - } - - private buildTopic(topic: Topic) { - this.topicFb = this.fb.group({ - _id: this.fb.control(topic._id), - name: this.fb.control(topic.name, Validators.required), - description: this.fb.control(topic.description), - alias: this.fb.control(topic.alias), - isActive: this.fb.control(topic.isActive), - isPublic: this.fb.control(topic.isPublic), - isDefault: this.fb.control(topic.isDefault), - categories: this.fb.control(topic.categories) - }); - } - - public editTopicOpen(element) { - if(element.className.indexOf('uk-open') !== -1) { - this.hide(element); - } else { - this.buildTopic(this.stakeholder.topics[this.topicIndex]); - this.show(element); } - } - public saveTopic(element) { - if(!this.topicFb.invalid) { - if(!this.topicFb.value.alias) { - this.topicFb.value.alias = this.topicFb.value.name.toLowerCase().trim(); - } - let path = [this.stakeholder._id]; - let callback = (topic: Topic): void => { - this.stakeholder.topics[this.topicIndex] = topic; - this.stakeholderService.setStakeholder(this.stakeholder); - }; - this.save('Topic has been successfully saved', element, path, this.topicFb.value, callback,true); + public hide(element) { + UIkit.drop(element).hide(); } - } - public deleteTopicOpen(name: string, element) { - this.deleteOpen(name,'topic', this.deleteTopicModal, element, this.topicIndex); - } - - public deleteTopic() { - let path: string[] = [ - this.stakeholder._id, - this.stakeholder.topics[this.topicIndex]._id - ]; - let callback = (): void => { - this.stakeholder.topics.splice(this.topicIndex, 1); - this.stakeholderService.setStakeholder(this.stakeholder); - }; - this.delete('Topic has been successfully be deleted', path, callback, true); - } - - public toggleCategory(index: number) { - if(this.selectedCategoryIndex !== index) { - this.selectedCategoryIndex = index; - this.toggle = true; - } else { - this.toggle = !this.toggle; + public show(element) { + UIkit.drop(element).show(); } - } - private buildCategory(category: Category) { - this.categoryFb = this.fb.group({ - _id: this.fb.control(category._id), - name: this.fb.control(category.name, Validators.required), - description: this.fb.control(category.description), - alias: this.fb.control(category.alias), - isActive: this.fb.control(category.isActive), - isPublic: this.fb.control(category.isPublic), - isDefault: this.fb.control(category.isDefault), - subCategories: this.fb.control(category.subCategories) - }); - } - - public editCategoryOpen(element, index:number = -1) { - if(element.className.indexOf('uk-open') !== -1) { - this.hide(element); - } else { - if(index === -1) { - this.buildCategory(new Category(null, null, null, true, true)); - } else { - this.buildCategory(this.stakeholder.topics[this.topicIndex].categories[index]); - } - this.show(element); - } - } - - public saveCategory(element, index = -1) { - if(!this.categoryFb.invalid) { - if(!this.categoryFb.value.alias) { - this.categoryFb.value.alias = this.categoryFb.value.name.toLowerCase(); - } - let path = [this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id]; - let callback = (category: Category): void => { - if(index === -1) { - this.stakeholder.topics[this.topicIndex].categories.push(category); - } else { - this.stakeholder.topics[this.topicIndex].categories[index] = HelperFunctions.copy(category); - } - this.stakeholderService.setStakeholder(this.stakeholder); - }; - if(index === -1) { - this.save('Category has been successfully created', element, path, this.categoryFb.value, callback); - } else { - this.save('Category has been successfully saved', element, path, this.categoryFb.value, callback); - } - } - } - - public deleteCategoryOpen(name: string, element, index) { - this.deleteOpen(name,'category', this.deleteCategoryModal, element, index); - } - - public deleteCategory() { - let path: string[] = [ - this.stakeholder._id, - this.stakeholder.topics[this.topicIndex]._id, - this.stakeholder.topics[this.topicIndex].categories[this.index]._id - ]; - let callback = (): void => { - this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1); - this.stakeholderService.setStakeholder(this.stakeholder); - }; - this.delete('Category has been successfully be deleted', path, callback); - } - - private buildSubcategory(subCategory: SubCategory) { - this.subcategoryFb = this.fb.group({ - _id: this.fb.control(subCategory._id), - name: this.fb.control(subCategory.name, Validators.required), - description: this.fb.control(subCategory.description), - alias: this.fb.control(subCategory.alias), - isActive: this.fb.control(subCategory.isActive), - isPublic: this.fb.control(subCategory.isPublic), - isDefault: this.fb.control(subCategory.isDefault), - charts: this.fb.control(subCategory.charts), - numbers: this.fb.control(subCategory.numbers) - }); - } - - public editSubCategoryOpen(element, index:number = -1) { - if(element.className.indexOf('uk-open') !== -1) { - this.hide(element); - } else { - if(index === -1) { - this.buildSubcategory(new SubCategory(null, null, null, true, true)); - } else { - this.buildSubcategory(this.stakeholder.topics[this.topicIndex]. - categories[this.selectedCategoryIndex].subCategories[index]); - } - this.show(element); - } - } - - public saveSubCategory(element, index = -1) { - if(!this.subcategoryFb.invalid) { - if(!this.subcategoryFb.value.alias) { - this.subcategoryFb.value.alias = this.subcategoryFb.value.name.toLowerCase(); - } - let path: string[] = [ - this.stakeholder._id, - this.stakeholder.topics[this.topicIndex]._id, - this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex]._id, - ]; - let callback = (subCategory: SubCategory): void => { - if(index === -1) { - this.stakeholder.topics[this.topicIndex]. - categories[this.selectedCategoryIndex].subCategories.push(subCategory); - } else { - this.stakeholder.topics[this.topicIndex]. - categories[this.selectedCategoryIndex].subCategories[index] = subCategory; - } - this.stakeholderService.setStakeholder(this.stakeholder); - }; - if(index === -1) { - this.save('Subcategory has been successfully created', element, path, this.subcategoryFb.value, callback); - } else { - this.save('Subcategory has been successfully saved', element, path, this.subcategoryFb.value, callback); - } - this.hide(element); - } - } - - public deleteSubcategoryOpen(name: string, element, index) { - this.deleteOpen(name,'subcategory', this.deleteSubcategoryModal, element, index); - } - - public deleteSubcategory() { - let path: string[] = [ - this.stakeholder._id, - this.stakeholder.topics[this.topicIndex]._id, - this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex]._id, - this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories[this.index]._id - ]; - let callback = (): void => { - this.stakeholder.topics[this.topicIndex]. - categories[this.selectedCategoryIndex].subCategories.splice(this.index, 1); - this.stakeholderService.setStakeholder(this.stakeholder); - }; - this.delete('Subcategory has been successfully be deleted', path, callback); - } - - private navigateToError() { - this.router.navigate(['/error'], {queryParams: {'page': this.router.url}}); - } - - private deleteOpen(name: string, type: string, modal: AlertModal, element, index) { - this.element = element; - this.index = index; - modal.alertTitle = 'Delete ' + name; - modal.cancelButtonText = 'No'; - modal.okButtonText = 'Yes'; - modal.message = 'This ' + type + ' will permanently be deleted. Are you sure you want to proceed?'; - modal.open(); - } - - private save(message: string, element, path: string[], saveElement: any, callback: Function, redirect = false) { - this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, saveElement, path).subscribe(saveElement => { - callback(saveElement); - UIkit.notification(message, { - status: 'success', - timeout: 3000, - pos: 'top-left' - }); - if(redirect) { - this.router.navigate(['../' + saveElement.alias], { - relativeTo: this.route + private buildTopic(topic: Topic) { + let topics = this.stakeholder.topics.filter(element => element._id !== topic._id); + this.topicFb = this.fb.group({ + _id: this.fb.control(topic._id), + name: this.fb.control(topic.name, Validators.required), + description: this.fb.control(topic.description), + alias: this.fb.control(topic.alias, [ + Validators.required, + this.stakeholderUtils.aliasValidator(topics) + ] + ), + isActive: this.fb.control(topic.isActive), + isPublic: this.fb.control(topic.isPublic), + isDefault: this.fb.control(topic.isDefault), + categories: this.fb.control(topic.categories) }); - } - this.hide(element); - }, error => { - UIkit.notification(error.error.message, { - status: 'danger', - timeout: 3000, - pos: 'top-left' - }); - this.hide(element); - }); - } + this.subscriptions.push(this.topicFb.get('name').valueChanges.subscribe(value => { + let i = 1; + value = this.stakeholderUtils.generateAlias(value); + this.topicFb.controls['alias'].setValue(value); + while (this.topicFb.get('alias').invalid) { + this.topicFb.controls['alias'].setValue(value + i); + i++; + } + })); + } - private delete(message: string, path: string[], callback: Function, redirect = false) { - this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => { - callback(); - UIkit.notification(message, { - status: 'success', - timeout: 3000, - pos: 'top-left' - }); - if(redirect) { - this.back(); - } - this.hide(this.element); - }, error => { - UIkit.notification(error.error.message, { - status: 'danger', - timeout: 3000, - pos: 'top-left' - }); - this.hide(this.element); - }); - } + public editTopicOpen(element) { + if (element.className.indexOf('uk-open') !== -1) { + this.hide(element); + } else { + this.buildTopic(this.stakeholder.topics[this.topicIndex]); + this.show(element); + } + } - back() { - this.router.navigate(['../'], { - relativeTo: this.route - }); - } + public saveTopic(element) { + if (!this.topicFb.invalid) { + let path = [this.stakeholder._id]; + let callback = (topic: Topic): void => { + this.stakeholder.topics[this.topicIndex] = topic; + this.stakeholderService.setStakeholder(this.stakeholder); + }; + this.save('Topic has been successfully saved', element, path, this.topicFb.value, callback, true); + } + } - chooseSubcategory(categoryIndex: number, subcategoryIndex: number) { - this.categoryIndex = categoryIndex; - this.subCategoryIndex = subcategoryIndex; - } + public deleteTopicOpen(name: string, element) { + this.deleteOpen(name, 'topic', this.deleteTopicModal, element, this.topicIndex); + } + + public deleteTopic() { + let path: string[] = [ + this.stakeholder._id, + this.stakeholder.topics[this.topicIndex]._id + ]; + let callback = (): void => { + this.stakeholder.topics.splice(this.topicIndex, 1); + this.stakeholderService.setStakeholder(this.stakeholder); + }; + this.delete('Topic has been successfully be deleted', path, callback, true); + } + + public toggleCategory(index: number) { + if (this.selectedCategoryIndex !== index) { + this.selectedCategoryIndex = index; + this.toggle = true; + } else { + this.toggle = !this.toggle; + } + } + + private buildCategory(category: Category) { + let categories = this.stakeholder.topics[this.topicIndex].categories.filter(element => element._id !== category._id); + this.categoryFb = this.fb.group({ + _id: this.fb.control(category._id), + name: this.fb.control(category.name, Validators.required), + description: this.fb.control(category.description), + alias: this.fb.control(category.alias, [ + Validators.required, + this.stakeholderUtils.aliasValidator(categories) + ] + ), + isActive: this.fb.control(category.isActive), + isPublic: this.fb.control(category.isPublic), + isDefault: this.fb.control(category.isDefault), + subCategories: this.fb.control(category.subCategories) + }); + this.subscriptions.push(this.categoryFb.get('name').valueChanges.subscribe(value => { + let i = 1; + value = this.stakeholderUtils.generateAlias(value); + this.categoryFb.controls['alias'].setValue(value); + while (this.categoryFb.get('alias').invalid) { + this.categoryFb.controls['alias'].setValue(value + i); + i++; + } + })); + } + + public editCategoryOpen(element, index: number = -1) { + if (element.className.indexOf('uk-open') !== -1) { + this.hide(element); + } else { + if (index === -1) { + this.buildCategory(new Category(null, null, null, true, true)); + } else { + this.buildCategory(this.stakeholder.topics[this.topicIndex].categories[index]); + } + this.show(element); + } + } + + public saveCategory(element, index = -1) { + if (!this.categoryFb.invalid) { + let path = [this.stakeholder._id, this.stakeholder.topics[this.topicIndex]._id]; + let callback = (category: Category): void => { + if (index === -1) { + this.stakeholder.topics[this.topicIndex].categories.push(category); + } else { + this.stakeholder.topics[this.topicIndex].categories[index] = HelperFunctions.copy(category); + } + this.stakeholderService.setStakeholder(this.stakeholder); + }; + if (index === -1) { + this.save('Category has been successfully created', element, path, this.categoryFb.value, callback); + } else { + this.save('Category has been successfully saved', element, path, this.categoryFb.value, callback); + } + } + } + + public deleteCategoryOpen(name: string, element, index) { + this.deleteOpen(name, 'category', this.deleteCategoryModal, element, index); + } + + public deleteCategory() { + let path: string[] = [ + this.stakeholder._id, + this.stakeholder.topics[this.topicIndex]._id, + this.stakeholder.topics[this.topicIndex].categories[this.index]._id + ]; + let callback = (): void => { + this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1); + this.stakeholderService.setStakeholder(this.stakeholder); + }; + this.delete('Category has been successfully be deleted', path, callback); + } + + private buildSubcategory(subCategory: SubCategory) { + let subCategories = this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories.filter(element => element._id !== subCategory._id); + this.subcategoryFb = this.fb.group({ + _id: this.fb.control(subCategory._id), + name: this.fb.control(subCategory.name, Validators.required), + description: this.fb.control(subCategory.description), + alias: this.fb.control(subCategory.alias, [ + Validators.required, + this.stakeholderUtils.aliasValidator(subCategories) + ] + ), + isActive: this.fb.control(subCategory.isActive), + isPublic: this.fb.control(subCategory.isPublic), + isDefault: this.fb.control(subCategory.isDefault), + charts: this.fb.control(subCategory.charts), + numbers: this.fb.control(subCategory.numbers) + }); + this.subscriptions.push(this.subcategoryFb.get('name').valueChanges.subscribe(value => { + let i = 1; + value = this.stakeholderUtils.generateAlias(value); + this.subcategoryFb.controls['alias'].setValue(value); + while (this.subcategoryFb.get('alias').invalid) { + this.subcategoryFb.controls['alias'].setValue(value + i); + i++; + } + })); + } + + public editSubCategoryOpen(element, index: number = -1) { + if (element.className.indexOf('uk-open') !== -1) { + this.hide(element); + } else { + if (index === -1) { + this.buildSubcategory(new SubCategory(null, null, null, true, true)); + } else { + this.buildSubcategory(this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories[index]); + } + this.show(element); + } + } + + public saveSubCategory(element, index = -1) { + if (!this.subcategoryFb.invalid) { + let path: string[] = [ + this.stakeholder._id, + this.stakeholder.topics[this.topicIndex]._id, + this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex]._id, + ]; + let callback = (subCategory: SubCategory): void => { + if (index === -1) { + this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories.push(subCategory); + } else { + this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories[index] = subCategory; + } + this.stakeholderService.setStakeholder(this.stakeholder); + }; + if (index === -1) { + this.save('Subcategory has been successfully created', element, path, this.subcategoryFb.value, callback); + } else { + this.save('Subcategory has been successfully saved', element, path, this.subcategoryFb.value, callback); + } + this.hide(element); + } + } + + public deleteSubcategoryOpen(name: string, element, index) { + this.deleteOpen(name, 'subcategory', this.deleteSubcategoryModal, element, index); + } + + public deleteSubcategory() { + let path: string[] = [ + this.stakeholder._id, + this.stakeholder.topics[this.topicIndex]._id, + this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex]._id, + this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories[this.index]._id + ]; + let callback = (): void => { + this.stakeholder.topics[this.topicIndex].categories[this.selectedCategoryIndex].subCategories.splice(this.index, 1); + this.stakeholderService.setStakeholder(this.stakeholder); + }; + this.delete('Subcategory has been successfully be deleted', path, callback); + } + + private navigateToError() { + this.router.navigate(['/error'], {queryParams: {'page': this.router.url}}); + } + + private deleteOpen(name: string, type: string, modal: AlertModal, element, index) { + this.element = element; + this.index = index; + modal.alertTitle = 'Delete ' + name; + modal.cancelButtonText = 'No'; + modal.okButtonText = 'Yes'; + modal.message = 'This ' + type + ' will permanently be deleted. Are you sure you want to proceed?'; + modal.open(); + } + + private save(message: string, element, path: string[], saveElement: any, callback: Function, redirect = false) { + this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, saveElement, path).subscribe(saveElement => { + callback(saveElement); + UIkit.notification(message, { + status: 'success', + timeout: 3000, + pos: 'top-left' + }); + if (redirect) { + this.router.navigate(['../' + saveElement.alias], { + relativeTo: this.route + }); + } + this.hide(element); + }, error => { + UIkit.notification(error.error.message, { + status: 'danger', + timeout: 3000, + pos: 'top-left' + }); + this.hide(element); + }); + } + + private delete(message: string, path: string[], callback: Function, redirect = false) { + this.stakeholderService.deleteElement(this.properties.monitorServiceAPIURL, path).subscribe(() => { + callback(); + UIkit.notification(message, { + status: 'success', + timeout: 3000, + pos: 'top-left' + }); + if (redirect) { + this.back(); + } + this.hide(this.element); + }, error => { + UIkit.notification(error.error.message, { + status: 'danger', + timeout: 3000, + pos: 'top-left' + }); + this.hide(this.element); + }); + } + + back() { + this.router.navigate(['../'], { + relativeTo: this.route + }); + } + + chooseSubcategory(categoryIndex: number, subcategoryIndex: number) { + this.categoryIndex = categoryIndex; + this.subCategoryIndex = subcategoryIndex; + } } diff --git a/src/app/utils/indicator-utils.ts b/src/app/utils/indicator-utils.ts index 6801c84..e428a54 100644 --- a/src/app/utils/indicator-utils.ts +++ b/src/app/utils/indicator-utils.ts @@ -1,5 +1,5 @@ import {ChartHelper, Indicator, IndicatorPath, Stakeholder, SubCategory, Topic} from "./entities/stakeholder"; -import {Validators} from "@angular/forms"; +import {AbstractControl, ValidatorFn, Validators} from "@angular/forms"; export interface Option { icon?: string, @@ -84,6 +84,27 @@ export class StakeholderUtils { } return funder; } + + aliasValidator(elements: any[]): ValidatorFn { + return (control: AbstractControl): { [key: string]: boolean } | null => { + if(control.value && elements.find(element => + element.alias === control.value + )) { + return { 'alias': true }; + } + return null; + } + } + + // TODO need to be fixed + generateAlias(name: string): string { + let alias = name.toLowerCase(); + while (alias.includes(' / ') || alias.includes(' ')) { + alias = alias.replace(' / ', '-'); + alias = alias.replace(' ', '-'); + } + return alias; + } } export class IndicatorUtils {