diff --git a/dashboard/menu/menu.component.ts b/dashboard/menu/menu.component.ts index d756a77f..9f89224b 100644 --- a/dashboard/menu/menu.component.ts +++ b/dashboard/menu/menu.component.ts @@ -372,10 +372,8 @@ export class MenuComponent implements OnInit { } public valueChange() { - this.elements.disable(); this.cdr.detectChanges(); this.elements.init(); - this.elements.enable(); } public get displayMenuItems() { diff --git a/monitor-admin/topic/indicators.component.html b/monitor-admin/topic/indicators.component.html index b9bce2df..2b0a57c3 100644 --- a/monitor-admin/topic/indicators.component.html +++ b/monitor-admin/topic/indicators.component.html @@ -1,470 +1,657 @@
-
-
Number Indicators
-
-
-
-
- -
-
-
-
-
- -
-
-
- - - - -
- +
+ +
+ -
-
{{indicator.name}}
-
- - -- -
-
- -
- +
+ +
-
-
- -
-
-
-
Chart Indicators
-
-
-
-
- -
-
-
-
-
- -
-
-
- - - - -
- +
+
-
-
-
- {{indicator.name}} +
+
+
+
+
+ Create a custom indicator +
+
+ Use our advance tool to create a custom Indicator that suit the needs of your + funding + KPI's. +
+
+ +
+
+
+
- -
- -
-
- -
-
-
-
-
-
-
-
-
-
- Create a custom indicator -
-
- Use our advance tool to create a custom Indicator that suit the needs of your funding - KPI's. -
-
- -
-
-
-
+
+ +
-
-
- -
-
+ [large]="true" classTitle="uk-background-primary uk-light" + (alertOutput)="saveIndicator()" + [okDisabled]="numberIndicatorFb && (numberIndicatorFb.invalid || numberIndicatorFb.pristine)">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{urlParameterizedMessage}}
-
-
- -
-
-
-
- There are schema enhancements that can be applied in this query.Apply - now -
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
- JSON Path -
-
-
- This JSON path is not valid or the result has not been calculated yet. - Please press calculate on box below to see the result. -
-
-
-
-
- - - - - - -
-
- -
-
+
-
- +
+
+
+
+
+
+ +
+
+
+
+
+
+
{{ urlParameterizedMessage }}
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JSON Path +
+
+
+ This JSON path is not valid or the result has not been calculated yet. + Please press calculate on box below to see the result. +
+
+
+
+
+ + + + + + +
+
+ +
+
+
+ +
+
-
-
+
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{urlParameterizedMessage}}
+ [okDisabled]="chartIndicatorFb && (chartIndicatorFb.invalid || chartIndicatorFb.pristine)"> +
+ +
+
+
+
+
-
- +
-
-
-
- There are schema enhancements that can be applied in this query. Apply - now +
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
- +
-
-
- -
-
- + +
+
+ +
+ You are about to delete + "{{ indicator.name ? indicator.name : (indicator.indicatorPaths[0]?.parameters?.title ? indicator.indicatorPaths[0].parameters.title : '') }} + " indicator permanently. +
+ Indicators of all profiles based on this default indicator, will be deleted as well. +
+ Are you sure you want to proceed? +
- You are about to delete - "{{indicator.name ? indicator.name : (indicator.indicatorPaths[0]?.parameters?.title?indicator.indicatorPaths[0].parameters.title:'')}}" indicator permanently. -
- Indicators of all profiles based on this default indicator, will be deleted as well. -
- Are you sure you want to proceed? -
-
- -
-
- + +
+
+ +
+ You are about to delete this section and its indicators permanently. +
+ Sections of all profiles based on this default section and their contents, will be deleted as well. +
+ Are you sure you want to proceed?
- You are about to delete this section and its indicators permanently. -
- Sections of all profiles based on this default section and their contents, will be deleted as well. -
- Are you sure you want to proceed? -
-
-
- +
+
+ +
-
diff --git a/monitor-admin/topic/indicators.component.ts b/monitor-admin/topic/indicators.component.ts index 46119354..42e85ddc 100644 --- a/monitor-admin/topic/indicators.component.ts +++ b/monitor-admin/topic/indicators.component.ts @@ -20,7 +20,7 @@ import { Visibility } from "../../monitor/entities/stakeholder"; import { - AbstractControl, + AbstractControl, FormArray, FormGroup, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, @@ -31,8 +31,8 @@ import {AlertModal} from "../../utils/modal/alert"; import {StatisticsService} from "../utils/services/statistics.service"; import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; -import {Reorder, StakeholderService} from "../../monitor/services/stakeholder.service"; -import {Observable, Subscriber} from "rxjs"; +import {MoveIndicator, SectionInfo, StakeholderService} from "../../monitor/services/stakeholder.service"; +import {BehaviorSubject, Observable, Subscriber} from "rxjs"; import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service"; import {Router} from "@angular/router"; import {Role, Session, User} from "../../login/utils/helper.class"; @@ -45,6 +45,7 @@ import {NotificationHandler} from "../../utils/notification-handler"; import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component"; import {properties} from "../../../../environments/environment"; import {StatsProfilesService} from "../utils/services/stats-profiles.service"; +import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component"; declare var UIkit; declare var copy; @@ -82,6 +83,8 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple public index: number = -1; public editing: boolean = false; public dragging: boolean = false; + /* Reorder indicators */ + public to: BehaviorSubject = new BehaviorSubject(null); /** Caches */ public safeUrls: Map = new Map([]); public numberResponses: Map = new Map(); @@ -94,12 +97,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple public sectionTypeToDelete: string; public sectionChildrenActionOnDelete: string; public indicatorChildrenActionOnDelete: string; - urlParameterizedMessage = null; - showCheckForSchemaEnhancements: boolean = false; + public urlParameterizedMessage = null; private notification: Notification; @ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent; @ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent; @ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent; + /* Transition Groups */ + @ViewChild('transitionGroup') transitionGroup: TransitionGroupComponent; public isFullscreen: boolean = false; @@ -124,7 +128,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple private notificationService: NotificationService, private fb: UntypedFormBuilder, protected _router: Router, - private cdr: ChangeDetectorRef, private sanitizer: DomSanitizer) { super() this.filesToUpload = []; @@ -186,7 +189,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } }); if (document !== undefined) { - let callback = (list, type: IndicatorType, action: 'moved' | 'added' | 'removed'): void => { + let callback = (list): string[] => { let items: HTMLCollection = list.current.children; let reordered = []; for (let i = 0; i < items.length; i++) { @@ -194,12 +197,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple 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); + return reordered; }; this.numbers.forEach((section) => { this.subscriptions.push(UIkit.util.on(document, 'start', '#number-' + section._id, (): void => { @@ -209,24 +207,32 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.dragging = false; })); this.subscriptions.push(UIkit.util.on(document, 'moved', '#number-' + section._id, (list): void => { - callback(list, "number", 'moved'); + this.reorderIndicators(section._id, 'number', callback(list)); })); this.subscriptions.push(UIkit.util.on(document, 'added', '#number-' + section._id, (list): void => { - callback(list, "number", 'added'); + this.to.next({id: section._id, indicators: callback(list)}); })); this.subscriptions.push(UIkit.util.on(document, 'removed', '#number-' + section._id, (list): void => { - callback(list, "number", 'removed'); + let sub = this.to.asObservable().subscribe(to => { + if(to) { + let from: SectionInfo = {id: section._id, indicators: callback(list)}; + this.moveIndicator({target: list.detail[1].id, from: from, to: to}); + setTimeout(() => { + sub.unsubscribe(); + }) + } + }) })); }); this.charts.forEach((section) => { this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => { - callback(list, "chart", 'moved'); + this.reorderIndicators(section._id, 'chart', callback(list)); })); this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => { - callback(list, "chart", 'added'); + //callback(list, "chart", 'added'); })); this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => { - callback(list, "chart", 'removed'); + // callback(list, "chart", 'removed'); })); }); } @@ -263,7 +269,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple setNumbers() { this.numberSections = this.fb.array([]); this.numberResults.clear(); - let urls: Map = new Map(); + let urls: Map = new Map(); this.numbers.forEach((section, i) => { this.numberSections.push(this.fb.group({ _id: this.fb.control(section._id), @@ -275,11 +281,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple indicators: this.fb.control(section.indicators) })); section.indicators.forEach((number, j) => { - let url = this.indicatorUtils.getFullUrl(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); + number.indicatorPaths.forEach((indicatorPath, k) => { + let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath); + const pair = JSON.stringify([indicatorPath.source, url]); + const indexes = urls.get(pair) ? urls.get(pair) : []; + indexes.push([i, j, k]); + urls.set(pair, indexes); + }); }); }); this.numberSubscription.forEach(value => { @@ -301,10 +309,10 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple }); } - private calculateResults(response: any, indexes: [number, number][]) { - indexes.forEach(([i, j]) => { + private calculateResults(response: any, indexes: [number, number, number][]) { + indexes.forEach(([i, j, k]) => { let result = JSON.parse(JSON.stringify(response)); - this.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { + this.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => { if (result) { result = result[jsonPath]; } @@ -317,7 +325,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } else { result = 0; } - this.numberResults.set(i + '-' + j, result); + this.numberResults.set(i + '-' + j + '-' + k, result); }); } @@ -364,6 +372,14 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple return this.chartIndicatorFb.get('indicatorPaths') as UntypedFormArray; } + public getActiveIndicatorPath(indicator: Indicator) { + if(indicator.activePath) { + return indicator.indicatorPaths[indicator.activePath]; + } else { + return indicator.indicatorPaths[0]; + } + } + public getNumberClassBySize(size: IndicatorSize) { if (size === 'small') { return 'uk-width-medium@m uk-width-1-1'; @@ -496,14 +512,12 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple 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.indicatorUtils.getNumberSource(value), value, this.stakeholder, this.numberIndicatorPaths.at(index).get('jsonPath').value, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(value))); - this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value); if (this.indicator.indicatorPaths[index]) { this.indicator.indicatorPaths[index] = indicatorPath; } else { @@ -559,11 +573,9 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple 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.indicatorUtils.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder); - this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value); (this.chartIndicatorPaths.at(index) as UntypedFormGroup).get('type').setValue(indicatorPath.type); (this.chartIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath)); if (!this.indicator.indicatorPaths[index]) { @@ -580,6 +592,65 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } } + public removeNumberIndicatorPath(index: number) { + this.numberIndicatorPaths.removeAt(index); + this.indicator.indicatorPaths.splice(index, 1); + this.transitionGroup.init(); + if(this.indicator.activePath === index) { + this.activeNumberIndicatorPath(Math.max(0, index - 1)); + } else if(this.indicator.activePath > index) { + this.activeNumberIndicatorPath(this.indicator.activePath - 1); + } + this.numberIndicatorFb.markAsDirty(); + } + + public removeChartIndicatorPath(index: number) { + this.chartIndicatorPaths.removeAt(index); + this.indicator.indicatorPaths.splice(index, 1); + this.transitionGroup.init(); + if(this.indicator.activePath === index) { + this.activeChartIndicatorPath(Math.max(0, index - 1)); + } else if(this.indicator.activePath > index) { + this.activeChartIndicatorPath(this.indicator.activePath - 1); + } + this.chartIndicatorFb.markAsDirty(); + } + + public moveIndicatorPath(form: FormGroup, + indicatorPaths: FormArray, index: number, + newIndex: number = index - 1) { + this.transitionGroup.init(); + let a = indicatorPaths.at(index); + let b = indicatorPaths.at(newIndex); + indicatorPaths.setControl(index , b); + indicatorPaths.setControl(newIndex , a); + HelperFunctions.swap(this.indicator.indicatorPaths, index , newIndex); + if(this.indicator.activePath === index) { + this.indicator.activePath = newIndex; + } else if(this.indicator.activePath === newIndex) { + this.indicator.activePath = index; + } + form.markAsDirty(); + } + + public activeNumberIndicatorPath(index: number) { + let paths = this.numberIndicatorPaths; + if(index == paths.length) { + this.addNumberIndicatorPath(); + this.transitionGroup.init(); + } + this.indicator.activePath = index; + } + + public activeChartIndicatorPath(index: number) { + let paths = this.chartIndicatorPaths; + if(index == paths.length) { + this.addChartIndicatorPath(); + this.transitionGroup.init(); + } + this.indicator.activePath = index; + } + private getJsonPathAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray { let jsonPath = this.fb.array([]); if (indicatorPath.jsonPath) { @@ -889,7 +960,23 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.loading = false; } - reorderIndicators(sectionId: string, type: IndicatorType, reorder: Reorder) { + moveIndicator(moveIndicator: MoveIndicator) { + 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.moveIndicator(this.properties.monitorServiceAPIURL, path, moveIndicator).subscribe(subCategory => { + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex] = subCategory; + this.setCharts(); + this.setNumbers(); + this.editing = false; + })); + } + + reorderIndicators(sectionId: string, type: IndicatorType, indicators: string[]) { this.editing = true; let path = [ this.stakeholder._id, @@ -898,7 +985,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple 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 => { + this.subscriptions.push(this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicators).subscribe(indicators => { if (type === 'chart') { this.charts.find(section => section._id === sectionId).indicators = indicators; this.setCharts(); @@ -1191,10 +1278,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple })); } - private checkForSchemaEnhancements(url: string) { - this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url) && this.properties.dashboard != 'irish'; - } - migrateFromOldImportJsonFile(charts) { // first section contains numbers // second contains charts @@ -1262,25 +1345,29 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple if (chart.type == "chart") { indicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(chart.url), chart.url, chart.type, stakeholder); - for (let section of this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts) { - for (let chart of section.indicators) { - if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) { - duplicates++; - exists = true; - } - } - } + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts.forEach((section: Section) => { + section.indicators.forEach(indicator => { + indicator.indicatorPaths.forEach(path => { + if (JSON.stringify(path.chartObject) == JSON.stringify(indicatorPath.chartObject)) { + duplicates++; + exists = true; + } + }); + }); + }); } else if (chart.type == "number") { indicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(chart.url), chart.url, stakeholder, chart.jsonPath, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(chart.url))); - for (let section of this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers) { - for (let chart of section.indicators) { - if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) { - duplicates++; - exists = true; - } - } - } + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers.forEach((section: Section) => { + section.indicators.forEach(indicator => { + indicator.indicatorPaths.forEach(path => { + if (JSON.stringify(path.chartObject) == JSON.stringify(indicatorPath.chartObject)) { + duplicates++; + exists = true; + } + }); + }); + }); } if (!exists) { let i: Indicator = new Indicator(chart.name, chart.description, chart.additionalDescription, chart.type, chart.width, chart.height, this.showVisibility?"RESTRICTED":this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities), [indicatorPath]); diff --git a/monitor-admin/topic/topic.component.ts b/monitor-admin/topic/topic.component.ts index b178eb46..40d128d8 100644 --- a/monitor-admin/topic/topic.component.ts +++ b/monitor-admin/topic/topic.component.ts @@ -242,30 +242,18 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, } topicChanged(callback: Function, save: boolean = false) { - if(this.topics && save) { - this.topics.disable(); - } - if(this.categories) { - this.categories.disable(); - } - if(this.subCategories) { - this.subCategories.disable(); - } if(callback) { callback(); } this.cdr.detectChanges(); if(this.topics && save) { this.topics.init(); - this.topics.enable(); } if(this.categories) { this.categories.init(); - this.categories.enable(); } if(this.subCategories) { this.subCategories.init(); - this.subCategories.enable(); } } @@ -359,6 +347,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, this.stakeholder.topics.splice(this.index, 1); if(this.topicIndex === this.index) { this.chooseTopic(Math.max(0, this.index - 1)); + } else if(this.topicIndex > this.index) { + this.chooseTopic(this.topicIndex - 1); } }, true); }; @@ -388,23 +378,15 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, } categoryChanged(callback: Function, save: boolean = false) { - if(this.categories && save) { - this.categories.disable(); - } - if(this.subCategories) { - this.subCategories.disable(); - } if(callback) { callback(); } this.cdr.detectChanges(); if(this.categories && save) { this.categories.init(); - this.categories.enable(); } if(this.subCategories) { this.subCategories.init(); - this.subCategories.enable(); } } @@ -500,6 +482,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1); if(this.categoryIndex === this.index) { this.chooseCategory(Math.max(0, this.index - 1)); + } else if(this.categoryIndex > this.index) { + this.chooseCategory(this.categoryIndex - 1); } }, true); }; @@ -528,16 +512,12 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, } subCategoryChanged(callback: Function, save: boolean = false) { - if(this.subCategories && save) { - this.subCategories.disable(); - } if(callback) { callback(); } this.cdr.detectChanges(); if(this.subCategories && save) { this.subCategories.init(); - this.subCategories.enable(); } } @@ -640,6 +620,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories.splice(this.index, 1); if(this.subCategoryIndex === this.index) { this.chooseSubcategory(Math.max(0, this.index - 1)); + } else if(this.subCategoryIndex > this.index) { + this.chooseSubcategory(this.subCategoryIndex - 1); } }, true); }; diff --git a/monitor-admin/topic/topic.module.ts b/monitor-admin/topic/topic.module.ts index 71e9b9d9..4c887228 100644 --- a/monitor-admin/topic/topic.module.ts +++ b/monitor-admin/topic/topic.module.ts @@ -20,11 +20,12 @@ import {TransitionGroupModule} from "../../utils/transition-group/transition-gro import {NumberRoundModule} from "../../utils/pipes/number-round.module"; import {SideBarModule} from "../../dashboard/sharedComponents/sidebar/sideBar.module"; import {SidebarMobileToggleModule} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module"; +import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module"; @NgModule({ imports: [ CommonModule, TopicRoutingModule, ClickModule, RouterModule, FormsModule, AlertModalModule, - ReactiveFormsModule, InputModule, IconsModule, PageContentModule, LoadingModule, NotifyFormModule, LogoUrlPipeModule, TransitionGroupModule, NumberRoundModule, SideBarModule, SidebarMobileToggleModule + ReactiveFormsModule, InputModule, IconsModule, PageContentModule, LoadingModule, NotifyFormModule, LogoUrlPipeModule, TransitionGroupModule, NumberRoundModule, SideBarModule, SidebarMobileToggleModule, SliderTabsModule ], declarations: [ TopicComponent, IndicatorsComponent diff --git a/monitor-admin/utils/indicator-utils.ts b/monitor-admin/utils/indicator-utils.ts index 9360c228..832b4894 100644 --- a/monitor-admin/utils/indicator-utils.ts +++ b/monitor-admin/utils/indicator-utils.ts @@ -55,6 +55,8 @@ export class StakeholderConfiguration { {icon: 'incognito', value: "PRIVATE", label: 'Private'}, ]; public static CACHE_INDICATORS: boolean = true; + public static NUMBER_MULTI_INDICATOR_PATHS = false; + public static CHART_MULTI_INDICATOR_PATHS = true; } export class StakeholderUtils { @@ -82,6 +84,14 @@ export class StakeholderUtils { return StakeholderConfiguration.CACHE_INDICATORS; } + get hasMultiNumberIndicatorPaths() { + return StakeholderConfiguration.NUMBER_MULTI_INDICATOR_PATHS; + } + + get hasMultiChartIndicatorPaths() { + return StakeholderConfiguration.CHART_MULTI_INDICATOR_PATHS; + } + visibilityIcon: Map = new Map(this.visibilities.map(option => [option.value, option.icon])); defaultValue(options: Option[]) { diff --git a/monitor/entities/stakeholder.ts b/monitor/entities/stakeholder.ts index 49c8e755..a33506ac 100644 --- a/monitor/entities/stakeholder.ts +++ b/monitor/entities/stakeholder.ts @@ -183,6 +183,7 @@ export class Indicator { visibility: Visibility; defaultId: string; indicatorPaths: IndicatorPath[]; + activePath: number = 0; overlay: Overlay = false; constructor(name: string, description: string, additionalDescription:string, type: IndicatorType, width: IndicatorSize,height: IndicatorSize, visibility: Visibility, indicatorPaths: IndicatorPath[], defaultId: string = null) { diff --git a/monitor/monitor-indicator-stakeholder-base.component.ts b/monitor/monitor-indicator-stakeholder-base.component.ts index 4573dee4..8838d202 100644 --- a/monitor/monitor-indicator-stakeholder-base.component.ts +++ b/monitor/monitor-indicator-stakeholder-base.component.ts @@ -214,15 +214,17 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator (this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : ""); //clear numbers when filters change this.numberResults.clear(); - let urls: Map = new Map(); + let urls: Map = new Map(); this.activeSubCategory.numbers.forEach((section, i) => { section.indicators.forEach((number, j) => { if (this.hasPermission(number.visibility)) { - let url = this.getFullUrl(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); + number.indicatorPaths.forEach((indicatorPath, k) => { + let url = this.getFullUrl(indicatorPath); + const pair = JSON.stringify([indicatorPath.source, url]); + const indexes = urls.get(pair) ? urls.get(pair) : []; + indexes.push([i, j, k]); + urls.set(pair, indexes); + }) } }); }); @@ -231,10 +233,10 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator let activeSubcategory = this.activeSubCategory._id; this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => { if(activeSubcategory === this.activeSubCategory._id) { - indexes.forEach(([i, j]) => { + indexes.forEach(([i, j, k]) => { if( this.activeSubCategory?.numbers[i]?.indicators[j]) { let result = JSON.parse(JSON.stringify(response)); - this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { + this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => { if (result) { result = result[jsonPath]; } @@ -247,7 +249,7 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator } else { result = 0; } - this.numberResults.set(i + '-' + j, result); + this.numberResults.set(i + '-' + j + '-' + k, result); } }); } @@ -255,10 +257,10 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator }); this.activeSubCategory.charts.forEach((section, i) => { section.indicators.forEach((indicator, j) => { - if (indicator.indicatorPaths.length > 0) { - indicator.indicatorPaths[0].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[0]); - this.chartsActiveType.set(i + '-' + j, indicator.indicatorPaths[0]); - } + indicator.indicatorPaths.forEach((indicatorPath, k) => { + indicator.indicatorPaths[k].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[k]); + this.chartsActiveType.set(i + '-' + j + '-' + k, indicator.indicatorPaths[k]); + }); }); }); if (this.cdr && !(this.cdr as ViewRef).destroyed) { diff --git a/monitor/services/stakeholder.service.ts b/monitor/services/stakeholder.service.ts index 3f0f3a11..d8b8bf30 100644 --- a/monitor/services/stakeholder.service.ts +++ b/monitor/services/stakeholder.service.ts @@ -1,16 +1,21 @@ import {Injectable} from "@angular/core"; import {HttpClient} from "@angular/common/http"; import {BehaviorSubject, from, Observable, Subscriber} from "rxjs"; -import {Indicator, Section, Stakeholder, StakeholderInfo, Visibility} from "../entities/stakeholder"; +import {Indicator, Section, Stakeholder, StakeholderInfo, SubCategory, Visibility} from "../entities/stakeholder"; import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {map} from "rxjs/operators"; import {properties} from "../../../../environments/environment"; import {CustomOptions} from "../../services/servicesUtils/customOptions.class"; -export interface Reorder { - action: 'moved' | 'added' | 'removed', - target: string, - ids: string[]; +export interface SectionInfo { + id: string; + indicators: string[]; +} + +export interface MoveIndicator { + target: string; + from: SectionInfo; + to: SectionInfo; } @Injectable({ @@ -128,7 +133,6 @@ export class StakeholderService { if (element.alias && element.alias.startsWith('/')) { element.alias = element.alias.slice(1); } - path = HelperFunctions.encodeArray(path); return this.http.post(url + ((path.length > 0) ? '/' : '') + path.join('/') + '/save', element, CustomOptions.registryOptions()).pipe(map(element => { if (path.length === 0) { @@ -140,7 +144,6 @@ export class StakeholderService { } saveBulkElements(url: string, indicators, path: string[] = []): Observable { - path = HelperFunctions.encodeArray(path); return this.http.post(url + ((path.length > 0) ? '/' : '') + path.join('/') + '/save-bulk', indicators, CustomOptions.registryOptions()).pipe(map(element => { if (path.length === 0) { @@ -152,7 +155,6 @@ export class StakeholderService { } saveSection(url: string, element: any, path: string[] = [], index: number = -1): Observable
{ - path = HelperFunctions.encodeArray(path); return this.http.post
(url + ((path.length > 0) ? '/' : '') + path.join('/') + '/save/' + index, element, CustomOptions.registryOptions()).pipe(map(element => { return HelperFunctions.copy(element); @@ -160,7 +162,6 @@ export class StakeholderService { } deleteElement(url: string, path: string[], childrenAction: string = null): Observable { - path = HelperFunctions.encodeArray(path); let params: string = ""; if (childrenAction) { params = "?children=" + childrenAction; @@ -169,17 +170,21 @@ export class StakeholderService { } reorderElements(url: string, path: string[], ids: string[]): Observable { - path = HelperFunctions.encodeArray(path); return this.http.post(url + '/' + path.join('/') + '/reorder', ids, CustomOptions.registryOptions()); } - reorderIndicators(url: string, path: string[], reorder: Reorder, type: string = 'chart'): Observable { - path = HelperFunctions.encodeArray(path); - return this.http.post(url + '/' + path.join('/') + '/' + type + '/reorder', reorder, CustomOptions.registryOptions()).pipe(map(indicators => { + reorderIndicators(url: string, path: string[], indicators: string[]): Observable { + return this.http.post(url + '/' + path.join('/') + '/reorder', indicators, CustomOptions.registryOptions()).pipe(map(indicators => { return HelperFunctions.copy(indicators); })); } + moveIndicator(url: string, path: string[], moveIndicator: MoveIndicator): Observable { + return this.http.post(url + '/' + path.join('/') + '/moveIndicator', moveIndicator, CustomOptions.registryOptions()).pipe(map(subCategory => { + return HelperFunctions.copy(subCategory); + })); + } + getStakeholderAsObservable(): Observable { return this.stakeholderSubject.asObservable(); } diff --git a/utils/transition-group/transition-group.component.ts b/utils/transition-group/transition-group.component.ts index 53530868..8cea910d 100644 --- a/utils/transition-group/transition-group.component.ts +++ b/utils/transition-group/transition-group.component.ts @@ -1,6 +1,6 @@ import {TransitionGroupItemDirective} from "./transition-group-item.directive"; import { - AfterViewInit, + AfterViewInit, ChangeDetectorRef, Component, ContentChildren, ElementRef, Input, @@ -29,15 +29,14 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy { @ContentChildren(TransitionGroupItemDirective) items: QueryList; @Input() public id: string; - private disabled: boolean = false; + public size: number; private subscription: Subscription; constructor(public element: ElementRef) {} ngAfterViewInit() { - this.init(); this.subscription = this.items.changes.subscribe(items => { - if(!this.disabled) { + if(items.length === this.size) { items.forEach(item => item.prevPos = item.newPos || item.prevPos); items.forEach(this.runCallback); this.refreshPosition('newPos'); @@ -80,6 +79,7 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy { init() { this.refreshPosition('prevPos'); this.refreshPosition('newPos'); + this.size = this.items.length; } runCallback(item: TransitionGroupItemDirective) { @@ -126,17 +126,17 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy { /** * Enable transition - * + * @deprecated * */ enable() { - this.disabled = false; + console.debug('Deprecated') } /** * Disable transition - * + * @deprecated * */ disable() { - this.disabled = true; + console.debug('Deprecated') } }