Production release May 2024 [EXPLORE] #40

Merged
konstantina.galouni merged 81 commits from develop into master 2024-05-23 18:26:50 +02:00
9 changed files with 758 additions and 487 deletions
Showing only changes of commit b71bdfa559 - Show all commits

View File

@ -372,10 +372,8 @@ export class MenuComponent implements OnInit {
} }
public valueChange() { public valueChange() {
this.elements.disable();
this.cdr.detectChanges(); this.cdr.detectChanges();
this.elements.init(); this.elements.init();
this.elements.enable();
} }
public get displayMenuItems() { public get displayMenuItems() {

View File

@ -21,7 +21,8 @@
(focusEmitter)="saveSection($event, numberSections.at(i), i, 'number')" (focusEmitter)="saveSection($event, numberSections.at(i), i, 'number')"
class="uk-width-1-3@m uk-width-1-1" placeholder="Title" inputClass="border-bottom"></div> class="uk-width-1-3@m uk-width-1-1" placeholder="Title" inputClass="border-bottom"></div>
</div> </div>
<div [id]="'number-' + number._id" class="uk-grid uk-grid-small uk-grid-match" uk-sortable="group: number" uk-grid> <div [id]="'number-' + number._id" class="uk-grid uk-grid-small uk-grid-match"
uk-sortable="group: number" uk-grid>
<ng-template ngFor [ngForOf]="number.indicators" let-indicator let-j="index"> <ng-template ngFor [ngForOf]="number.indicators" let-indicator let-j="index">
<div *ngIf="indicator" [id]="indicator._id" <div *ngIf="indicator" [id]="indicator._id"
[ngClass]="getNumberClassBySize(indicator.width)"> [ngClass]="getNumberClassBySize(indicator.width)">
@ -29,13 +30,18 @@
<div *ngIf="!dragging" <div *ngIf="!dragging"
class="uk-position-top-right uk-margin-small-right uk-margin-small-top"> class="uk-position-top-right uk-margin-small-right uk-margin-small-top">
<a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing"> <a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing">
<icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)" ratio="0.6"></icon> <icon *ngIf="showVisibility" [flex]="true"
[name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)"
ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0"> <div #element class="uk-dropdown"
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
<li><a (click)="editNumberIndicatorOpen(number, indicator._id); hide(element)">Edit</a></li> <li>
<a (click)="editNumberIndicatorOpen(number, indicator._id); hide(element)">Edit</a>
</li>
</ng-container> </ng-container>
<ng-container *ngIf="showVisibility"> <ng-container *ngIf="showVisibility">
<li *ngIf="isCurator" class="uk-nav-divider"></li> <li *ngIf="isCurator" class="uk-nav-divider"></li>
@ -43,9 +49,12 @@
<li> <li>
<a (click)="changeIndicatorStatus(number._id, indicator, v.value);hide(element)"> <a (click)="changeIndicatorStatus(number._id, indicator, v.value);hide(element)">
<div class="uk-flex uk-flex-middle"> <div class="uk-flex uk-flex-middle">
<icon [flex]="true" [name]="v.icon" ratio="0.6"></icon> <icon [flex]="true" [name]="v.icon"
<span class="uk-margin-small-left uk-width-expand">{{v.label}}</span> ratio="0.6"></icon>
<icon *ngIf="indicator.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon> <span class="uk-margin-small-left uk-width-expand">{{ v.label }}</span>
<icon *ngIf="indicator.visibility === v.value"
[flex]="true" name="done"
class="uk-text-secondary" ratio="0.8"></icon>
</div> </div>
</a> </a>
</li> </li>
@ -53,15 +62,18 @@
</ng-container> </ng-container>
<ng-container *ngIf="!indicator.defaultId && !editing && isCurator"> <ng-container *ngIf="!indicator.defaultId && !editing && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li><a (click)="deleteIndicatorOpen(number, indicator._id, 'number', 'delete');hide(element)">Delete</a></li> <li>
<a (click)="deleteIndicatorOpen(number, indicator._id, 'number', 'delete');hide(element)">Delete</a>
</li>
</ng-container> </ng-container>
</ul> </ul>
</div> </div>
</div> </div>
<div class="uk-text-small uk-text-truncate uk-margin-xsmall-bottom uk-margin-right">{{indicator.name}}</div> <div class="uk-text-small uk-text-truncate uk-margin-xsmall-bottom uk-margin-right">{{ indicator.name }}</div>
<div class="number uk-text-small uk-text-bold"> <div class="number uk-text-small uk-text-bold">
<span *ngIf="numberResults.get(i + '-' + j)" [innerHTML]="(indicator.indicatorPaths[0].format == 'NUMBER'?(numberResults.get(i + '-' + j) | numberRound: 2:1:stakeholder.locale):(numberResults.get(i + '-' + j) | numberPercentage: stakeholder.locale))"></span> <span *ngIf="numberResults.get(i + '-' + j + '-' + 0)"
<span *ngIf="!numberResults.get(i + '-' + j)">--</span> [innerHTML]="(indicator.indicatorPaths[0].format == 'NUMBER'?(numberResults.get(i + '-' + j + '-' + 0) | numberRound: 2:1:stakeholder.locale):(numberResults.get(i + '-' + j + '-' + 0) | numberPercentage: stakeholder.locale))"></span>
<span *ngIf="!numberResults.get(i + '-' + j + '-' + 0)">--</span>
</div> </div>
</div> </div>
</div> </div>
@ -70,7 +82,8 @@
<div *ngIf="isCurator" class="uk-margin-top"> <div *ngIf="isCurator" class="uk-margin-top">
<div class="uk-grid uk-grid-small" uk-grid> <div class="uk-grid uk-grid-small" uk-grid>
<div [ngClass]="getNumberClassBySize('small')"> <div [ngClass]="getNumberClassBySize('small')">
<a class="uk-card uk-card-default number-card uk-padding-small uk-flex uk-flex-middle uk-link-reset" (click)="editNumberIndicatorOpen(number)"> <a class="uk-card uk-card-default number-card uk-padding-small uk-flex uk-flex-middle uk-link-reset"
(click)="editNumberIndicatorOpen(number)">
<div class="uk-text-background uk-margin-right"> <div class="uk-text-background uk-margin-right">
<icon name="add" [flex]="true" ratio="1.5"></icon> <icon name="add" [flex]="true" ratio="1.5"></icon>
</div> </div>
@ -111,20 +124,27 @@
(focusEmitter)="saveSection($event, chartSections.at(i), i)" (focusEmitter)="saveSection($event, chartSections.at(i), i)"
class="uk-width-1-3@m uk-width-1-1" placeholder="Title" inputClass="border-bottom"></div> class="uk-width-1-3@m uk-width-1-1" placeholder="Title" inputClass="border-bottom"></div>
</div> </div>
<div [id]="'chart-' + chart._id" class="uk-grid uk-grid-small uk-grid-match" uk-sortable="group: chart" uk-grid> <div [id]="'chart-' + chart._id" class="uk-grid uk-grid-small uk-grid-match"
uk-sortable="group: chart" uk-grid>
<ng-template ngFor [ngForOf]="chart.indicators" let-indicator let-j="index"> <ng-template ngFor [ngForOf]="chart.indicators" let-indicator let-j="index">
<div *ngIf="indicator" [id]="indicator._id" [ngClass]="getChartClassBySize(indicator.width)"> <div *ngIf="indicator" [id]="indicator._id"
[ngClass]="getChartClassBySize(indicator.width)">
<div class="uk-card uk-card-default uk-card-body uk-position-relative"> <div class="uk-card uk-card-default uk-card-body uk-position-relative">
<div *ngIf="!dragging" <div *ngIf="!dragging"
class="uk-position-top-right uk-margin-small-right uk-margin-small-top"> class="uk-position-top-right uk-margin-small-right uk-margin-small-top">
<a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing"> <a class="uk-link-reset uk-flex uk-flex-middle" [class.uk-disabled]="editing">
<icon *ngIf="showVisibility" [flex]="true" [name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)" ratio="0.6"></icon> <icon *ngIf="showVisibility" [flex]="true"
[name]="stakeholderUtils.visibilityIcon.get(indicator.visibility)"
ratio="0.6"></icon>
<icon [flex]="true" name="more_vert"></icon> <icon [flex]="true" name="more_vert"></icon>
</a> </a>
<div #element class="uk-dropdown" uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0"> <div #element class="uk-dropdown"
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0">
<ul class="uk-nav uk-dropdown-nav"> <ul class="uk-nav uk-dropdown-nav">
<ng-container *ngIf="isCurator"> <ng-container *ngIf="isCurator">
<li><a (click)="editChartIndicatorOpen(chart, indicator._id); hide(element)">Edit</a></li> <li>
<a (click)="editChartIndicatorOpen(chart, indicator._id); hide(element)">Edit</a>
</li>
</ng-container> </ng-container>
<ng-container *ngIf="showVisibility"> <ng-container *ngIf="showVisibility">
<li *ngIf="isCurator" class="uk-nav-divider"></li> <li *ngIf="isCurator" class="uk-nav-divider"></li>
@ -132,9 +152,12 @@
<li> <li>
<a (click)="changeIndicatorStatus(chart._id, indicator, v.value);"> <a (click)="changeIndicatorStatus(chart._id, indicator, v.value);">
<div class="uk-flex uk-flex-middle"> <div class="uk-flex uk-flex-middle">
<icon [flex]="true" [name]="v.icon" ratio="0.6"></icon> <icon [flex]="true" [name]="v.icon"
<span class="uk-margin-small-left uk-width-expand">{{v.label}}</span> ratio="0.6"></icon>
<icon *ngIf="indicator.visibility === v.value" [flex]="true" name="done" class="uk-text-secondary" ratio="0.8"></icon> <span class="uk-margin-small-left uk-width-expand">{{ v.label }}</span>
<icon *ngIf="indicator.visibility === v.value"
[flex]="true" name="done"
class="uk-text-secondary" ratio="0.8"></icon>
</div> </div>
</a> </a>
</li> </li>
@ -142,30 +165,49 @@
</ng-container> </ng-container>
<ng-container *ngIf="!indicator.defaultId && !editing && isCurator"> <ng-container *ngIf="!indicator.defaultId && !editing && isCurator">
<li class="uk-nav-divider"> <li class="uk-nav-divider">
<li><a (click)="deleteIndicatorOpen(chart, indicator._id, 'chart', 'delete');hide(element)">Delete</a></li> <li>
<a (click)="deleteIndicatorOpen(chart, indicator._id, 'chart', 'delete');hide(element)">Delete</a>
</li>
</ng-container> </ng-container>
</ul> </ul>
</div> </div>
</div> </div>
<div> <div>
<div *ngIf="indicator.name" class="uk-text-center uk-text-bold uk-margin-small-bottom"> <div *ngIf="indicator.name"
{{indicator.name}} class="uk-text-center uk-text-bold uk-margin-small-bottom">
{{ indicator.name }}
</div> </div>
<iframe *ngIf="!properties.disableFrameLoad && indicator.indicatorPaths[0] && indicator.indicatorPaths[0].source !=='image' && <div *ngIf="indicator.indicatorPaths.length > 1" class="uk-margin-medium-bottom">
safeUrls.get(indicatorUtils.getFullUrl(stakeholder, indicator.indicatorPaths[0]))" <ul class="uk-subnav uk-subnav-pill uk-subnav-small">
allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" <li *ngFor="let indicatorPath of indicator.indicatorPaths; let i=index"
[src]="safeUrls.get(indicatorUtils.getFullUrl(stakeholder, indicator.indicatorPaths[0]))" class="uk-flex uk-margin-small-top"
class="uk-width-1-1" [ngClass]="'uk-height-' + (indicator.height?indicator.height.toLowerCase():'medium')" [class.uk-active]="(!indicator.activePath && i == 0) || indicator.activePath === i">
<a (click)="indicator.activePath = i">
<span>
{{ indicatorPath.parameters.title ? indicatorPath.parameters.title : '--' }}
</span>
</a>
</li>
</ul>
</div>
<iframe *ngIf="!properties.disableFrameLoad && getActiveIndicatorPath(indicator) && getActiveIndicatorPath(indicator).source !=='image' &&
safeUrls.get(indicatorUtils.getFullUrl(stakeholder, getActiveIndicatorPath(indicator)))"
allowfullscreen="true" mozallowfullscreen="true"
webkitallowfullscreen="true"
[src]="safeUrls.get(indicatorUtils.getFullUrl(stakeholder, getActiveIndicatorPath(indicator)))"
class="uk-width-1-1"
[ngClass]="'uk-height-' + (indicator.height?indicator.height.toLowerCase():'medium')"
[class.uk-blend-multiply]="!isFullscreen"></iframe> [class.uk-blend-multiply]="!isFullscreen"></iframe>
<div *ngIf="properties.disableFrameLoad && indicator.indicatorPaths && <div *ngIf="properties.disableFrameLoad && indicator.indicatorPaths &&
indicator.indicatorPaths.length > 0 && indicator.indicatorPaths[0].source !=='image'"> indicator.indicatorPaths.length > 0 && getActiveIndicatorPath(indicator).source !=='image'">
<img class="uk-width-1-1 uk-blend-multiply" [ngClass]="'uk-height-' + (indicator.height?indicator.height.toLowerCase():'medium')" <img class="uk-width-1-1 uk-blend-multiply"
[ngClass]="'uk-height-' + (indicator.height?indicator.height.toLowerCase():'medium')"
src="assets/chart-placeholder.png"> src="assets/chart-placeholder.png">
</div> </div>
<div *ngIf="indicator.indicatorPaths && indicator.indicatorPaths[0] && <div *ngIf="indicator.indicatorPaths && getActiveIndicatorPath(indicator) && getActiveIndicatorPath(indicator).source === 'image'">
indicator.indicatorPaths[0].source === 'image'"> <img class="uk-width-1-1 uk-blend-multiply"
<img class="uk-width-1-1 uk-blend-multiply" [ngClass]="'uk-height-' + (indicator.height?indicator.height.toLowerCase():'medium')" [ngClass]="'uk-height-' + (indicator.height?indicator.height.toLowerCase():'medium')"
[src]="indicator.indicatorPaths[0].url"> [src]="getActiveIndicatorPath(indicator).url">
</div> </div>
</div> </div>
</div> </div>
@ -175,12 +217,14 @@
<div *ngIf="isCurator" class="uk-margin-top"> <div *ngIf="isCurator" class="uk-margin-top">
<div class="uk-grid uk-grid-small uk-grid-match" uk-grid> <div class="uk-grid uk-grid-small uk-grid-match" uk-grid>
<div [ngClass]="getChartClassBySize('small')"> <div [ngClass]="getChartClassBySize('small')">
<div class=" uk-card uk-card-default uk-card-body clickable" (click)="editChartIndicatorOpen(chart)"> <div class=" uk-card uk-card-default uk-card-body clickable"
(click)="editChartIndicatorOpen(chart)">
<h6 class="uk-text-bold uk-text-center"> <h6 class="uk-text-bold uk-text-center">
Create a custom indicator Create a custom indicator
</h6> </h6>
<div class="uk-text-muted uk-text-small"> <div class="uk-text-muted uk-text-small">
Use our advance tool to create a custom Indicator that suit the needs of your funding Use our advance tool to create a custom Indicator that suit the needs of your
funding
KPI's. KPI's.
</div> </div>
<div class="uk-flex uk-flex-center uk-text-background uk-margin-medium-top"> <div class="uk-flex uk-flex-center uk-text-background uk-margin-medium-top">
@ -212,9 +256,11 @@
<div *ngIf="numberIndicatorFb" class="uk-grid" [formGroup]="numberIndicatorFb" uk-grid> <div *ngIf="numberIndicatorFb" class="uk-grid" [formGroup]="numberIndicatorFb" uk-grid>
<div input class="uk-width-1-1" [formInput]="numberIndicatorFb.get('name')" placeholder="Title"></div> <div input class="uk-width-1-1" [formInput]="numberIndicatorFb.get('name')" placeholder="Title"></div>
<div *ngIf="stakeholder.defaultId != '-1' && ( (indicator.description && indicator.description.length > 0) || !stakeholder.defaultId)" <div *ngIf="stakeholder.defaultId != '-1' && ( (indicator.description && indicator.description.length > 0) || !stakeholder.defaultId)"
input class="uk-width-1-1" [formInput]="numberIndicatorFb.get('description')" placeholder="Profile description" type="textarea"> input class="uk-width-1-1" [formInput]="numberIndicatorFb.get('description')"
placeholder="Profile description" type="textarea">
</div> </div>
<div input class="uk-width-1-1" *ngIf="stakeholder.defaultId" [formInput]="numberIndicatorFb.get('additionalDescription')" <div input class="uk-width-1-1" *ngIf="stakeholder.defaultId"
[formInput]="numberIndicatorFb.get('additionalDescription')"
placeholder="Description" type="textarea"> placeholder="Description" type="textarea">
</div> </div>
<div *ngIf="showVisibility" input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('visibility')" <div *ngIf="showVisibility" input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('visibility')"
@ -223,22 +269,89 @@
<div input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('width')" <div input class="uk-width-1-2@m" [formInput]="numberIndicatorFb.get('width')"
placeholder="Number Size" [options]="indicatorUtils.indicatorSizes" type="select"> placeholder="Number Size" [options]="indicatorUtils.indicatorSizes" type="select">
</div> </div>
<hr class="uk-width-1-1">
<div *ngIf="numberIndicatorPaths" formArrayName="indicatorPaths"> <div *ngIf="numberIndicatorPaths" formArrayName="indicatorPaths">
<div *ngIf="stakeholderUtils.hasMultiNumberIndicatorPaths" class="uk-margin-medium-bottom">
<ul #transitionGroup class="uk-subnav uk-subnav-pill uk-subnav-small" transition-group>
<li *ngFor="let indicatorPath of numberIndicatorPaths.controls; let i=index"
class="uk-visible-toggle uk-flex uk-margin-small-top" transition-group-item
[class.uk-active]="(!indicator.activePath && i == 0) || indicator.activePath === i">
<a (click)="activeNumberIndicatorPath(i)">
<span *ngIf="indicatorPath.get('result').valid && indicatorPath.get('result').value !== 0"
[innerHTML]="(indicatorPath.get('format').value == 'NUMBER'?(indicatorPath.get('result').value | numberRound: 2:1:stakeholder.locale):(indicatorPath.get('result').value | numberPercentage: stakeholder.locale))">
</span>
<span *ngIf="!indicatorPath.get('result').valid || indicatorPath.get('result').value === 0">
--
</span>
</a>
<span *ngIf="!indicator.defaultId && numberIndicatorPaths.length > 1"
class="uk-flex uk-flex-column uk-flex-center uk-margin-small-left"
[class.uk-invisible-hover]="indicator.activePath !== i"
(click)="$event.stopPropagation();$event.preventDefault()">
<a class="uk-link-reset uk-flex uk-flex-middle">
<icon [flex]="true" name="more_vert"></icon>
</a>
<div #element
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; container: .uk-modal-body">
<ul class="uk-nav uk-dropdown-nav">
<li *ngIf="i > 0">
<a (click)="hide(element);moveIndicatorPath(numberIndicatorFb, numberIndicatorPaths, i)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="west" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Move Left</span>
</div>
</a>
</li>
<li *ngIf="i < numberIndicatorPaths.length - 1">
<a (click)="hide(element);moveIndicatorPath(numberIndicatorFb, numberIndicatorPaths, i, i + 1)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="east" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Move Right</span>
</div>
</a>
</li>
<li>
<a (click)="removeNumberIndicatorPath(i); hide(element)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="delete" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Delete</span>
</div>
</a>
</li>
</ul>
</div>
</span>
</li>
<li class="uk-margin-small-top">
<a (click)="activeNumberIndicatorPath(numberIndicatorPaths.length); $event.preventDefault()"
class="uk-flex uk-flex-middle">
<icon name="add" [flex]="true"></icon>
<span class="uk-text-uppercase">Add</span>
</a>
</li>
</ul>
</div>
<div *ngFor="let indicatorPath of numberIndicatorPaths.controls; let i=index" [formGroupName]="i"> <div *ngFor="let indicatorPath of numberIndicatorPaths.controls; let i=index" [formGroupName]="i">
<div class="uk-grid" uk-grid> <div *ngIf="(!indicator.activePath && i == 0) || indicator.activePath === i" class="uk-grid"
uk-grid>
<div class="uk-width-1-1"> <div class="uk-width-1-1">
<div class="uk-grid" uk-grid> <div class="uk-grid" uk-grid>
<div class="uk-width-1-1 uk-flex uk-flex-middle"> <div class="uk-width-1-1 uk-flex uk-flex-middle">
<div input class="uk-width-expand" [formInput]="indicatorPath.get('url')" placeholder="Number URL"> <div input class="uk-width-expand" [formInput]="indicatorPath.get('url')"
<div *ngIf="urlParameterizedMessage" warning>{{urlParameterizedMessage}}</div> placeholder="Number URL">
<div *ngIf="urlParameterizedMessage" warning>{{ urlParameterizedMessage }}</div>
</div> </div>
<div class='uk-padding-small'> <div class='uk-padding-small'>
<a class="uk-link-reset" (click)="copyToClipboard(indicatorPath.get('url').value)"><icon [flex]="true" name="content_copy"></icon></a> <a class="uk-link-reset"
(click)="copyToClipboard(indicatorPath.get('url').value)">
<icon [flex]="true" name="content_copy"></icon>
</a>
</div> </div>
</div> </div>
<div class="uk-width-1-2@m"> <div class="uk-width-1-2@m">
<div input [formInput]="indicatorPath.get('source')" placeholder="Source" <div input [formInput]="indicatorPath.get('source')" placeholder="Source"
[options]="isAdministrator?indicatorUtils.allSourceTypes:indicatorUtils.sourceTypes" type="select"> [options]="isAdministrator?indicatorUtils.allSourceTypes:indicatorUtils.sourceTypes"
type="select">
</div> </div>
</div> </div>
<div class="uk-width-1-2@m"> <div class="uk-width-1-2@m">
@ -247,7 +360,8 @@
</div> </div>
</div> </div>
<div class="uk-width-1-2@m" formArrayName="parameters"> <div class="uk-width-1-2@m" formArrayName="parameters">
<div *ngIf="getParameter(i, 'statsProfile', 'number') && statsProfiles" input [formInput]="getParameter(i, 'statsProfile', 'number').get('value')" <div *ngIf="getParameter(i, 'statsProfile', 'number') && statsProfiles" input
[formInput]="getParameter(i, 'statsProfile', 'number').get('value')"
[type]="'select'" [type]="'select'"
[options]="statsProfiles" [options]="statsProfiles"
placeholder="Stats Profile"></div> placeholder="Stats Profile"></div>
@ -258,22 +372,26 @@
<h6 class="uk-text-bold uk-margin-remove-bottom"> <h6 class="uk-text-bold uk-margin-remove-bottom">
<span>JSON Path</span> <span>JSON Path</span>
</h6> </h6>
<div *ngIf="numberIndicatorPaths.at(i).get('result').invalid && numberIndicatorPaths.at(i).get('result').errors.required"> <div *ngIf="indicatorPath.get('result').invalid && indicatorPath.get('result').errors.required">
<div class="uk-text-danger uk-text-small"> <div class="uk-text-danger uk-text-small">
This JSON path is not valid or the result has not been calculated yet. This JSON path is not valid or the result has not been calculated yet.
Please press calculate on box below to see the result. Please press calculate on box below to see the result.
</div> </div>
</div> </div>
<div class="uk-grid uk-child-width-1-3@m uk-child-width-1-1 uk-margin-top uk-flex-middle" uk-grid> <div class="uk-grid uk-child-width-1-3@m uk-child-width-1-1 uk-margin-top uk-flex-middle"
<div *ngFor="let jsonPath of getJsonPath(i).controls; let j=index" class="uk-flex uk-flex-middle"> uk-grid>
<div input class="uk-width-1-1" [formInput]="jsonPath" [placeholder]="'Level ' + +(j + 1)"></div> <div *ngFor="let jsonPath of getJsonPath(i).controls; let j=index"
class="uk-flex uk-flex-middle">
<div input class="uk-width-1-1" [formInput]="jsonPath"
[placeholder]="'Level ' + +(j + 1)"></div>
<a [class.uk-invisible]="getJsonPath(i).length === 1 || numberIndicatorFb.get('defaultId').value" <a [class.uk-invisible]="getJsonPath(i).length === 1 || numberIndicatorFb.get('defaultId').value"
class="uk-margin-small-left uk-text-danger" class="uk-margin-small-left uk-text-danger"
[class.uk-disabled]="getJsonPath(i).disabled" [class.uk-disabled]="getJsonPath(i).disabled"
(click)="removeJsonPath(i, j)"> (click)="removeJsonPath(i, j)">
<icon name="close"></icon> <icon name="close"></icon>
</a> </a>
<span [class.uk-invisible]="getJsonPath(i).disabled || j === (getJsonPath(i).controls.length - 1)" class="uk-text-center uk-margin-small-left"> <span [class.uk-invisible]="getJsonPath(i).disabled || j === (getJsonPath(i).controls.length - 1)"
class="uk-text-center uk-margin-small-left">
<icon name="east"></icon> <icon name="east"></icon>
</span> </span>
</div> </div>
@ -287,24 +405,24 @@
<div class="uk-width-1-1 uk-flex uk-flex-center"> <div class="uk-width-1-1 uk-flex uk-flex-center">
<div class="uk-flex uk-position-relative"> <div class="uk-flex uk-position-relative">
<span class="uk-padding number number-preview uk-flex uk-flex-column uk-flex-center uk-text-center"> <span class="uk-padding number number-preview uk-flex uk-flex-column uk-flex-center uk-text-center">
<span *ngIf="numberIndicatorPaths.at(i).get('result').valid && numberIndicatorPaths.at(i).get('result').value !== 0" <span *ngIf="indicatorPath.get('result').valid && indicatorPath.get('result').value !== 0"
[innerHTML]="(numberIndicatorPaths.at(i).get('format').value == 'NUMBER'?(numberIndicatorPaths.at(i).get('result').value | numberRound: 2:1:stakeholder.locale):(numberIndicatorPaths.at(i).get('result').value | numberPercentage: stakeholder.locale))"> [innerHTML]="(indicatorPath.get('format').value == 'NUMBER'?(indicatorPath.get('result').value | numberRound: 2:1:stakeholder.locale):(indicatorPath.get('result').value | numberPercentage: stakeholder.locale))">
</span> </span>
<span *ngIf="numberIndicatorPaths.at(i).get('result').valid && numberIndicatorPaths.at(i).get('result').value === 0"> <span *ngIf="indicatorPath.get('result').valid && indicatorPath.get('result').value === 0">
-- --
</span> </span>
</span> </span>
<div *ngIf="numberIndicatorPaths.at(i).get('result').invalid" <div *ngIf="indicatorPath.get('result').invalid"
class="uk-width-1-1 uk-height-1-1 refresh-indicator"> class="uk-width-1-1 uk-height-1-1 refresh-indicator">
<div class="uk-position-relative uk-height-1-1"> <div class="uk-position-relative uk-height-1-1">
<a class="uk-position-center uk-text-center uk-text-small uk-link-reset" <a class="uk-position-center uk-text-center uk-text-small uk-link-reset"
[class.uk-disabled]="numberIndicatorPaths.at(i).get('url').invalid" [class.uk-disabled]="indicatorPath.get('url').invalid"
(click)="validateJsonPath(i, true)"> (click)="validateJsonPath(i, true)">
<div> <div>
<icon name="refresh"></icon> <icon name="refresh"></icon>
</div> </div>
<span *ngIf="numberIndicatorPaths.at(i).get('result').errors.required">Calculate</span> <span *ngIf="indicatorPath.get('result').errors.required">Calculate</span>
<span *ngIf="numberIndicatorPaths.at(i).get('result').errors.validating">Calculating...</span> <span *ngIf="indicatorPath.get('result').errors.validating">Calculating...</span>
</a> </a>
</div> </div>
</div> </div>
@ -312,13 +430,13 @@
class="uk-width-1-1 uk-height-1-1 refresh-indicator"> class="uk-width-1-1 uk-height-1-1 refresh-indicator">
<div class="uk-position-relative uk-height-1-1"> <div class="uk-position-relative uk-height-1-1">
<a class="uk-position-center uk-text-center uk-text-small uk-link-reset" <a class="uk-position-center uk-text-center uk-text-small uk-link-reset"
[class.uk-disabled]="numberIndicatorPaths.at(i).get('url').invalid" [class.uk-disabled]="indicatorPath.get('url').invalid"
(click)="refreshIndicator('number')"> (click)="refreshIndicator('number')">
<div> <div>
<icon name="refresh"></icon> <icon name="refresh"></icon>
</div> </div>
<span>Calculate</span> <span>Calculate</span>
<span *ngIf="numberIndicatorPaths.at(i).get('result').errors?.validating">Calculating...</span> <span *ngIf="indicatorPath.get('result').errors?.validating">Calculating...</span>
</a> </a>
</div> </div>
</div> </div>
@ -340,9 +458,11 @@
<div *ngIf="chartIndicatorFb" [formGroup]="chartIndicatorFb" class="uk-grid" uk-grid> <div *ngIf="chartIndicatorFb" [formGroup]="chartIndicatorFb" class="uk-grid" uk-grid>
<div input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('name')" placeholder="Title"></div> <div input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('name')" placeholder="Title"></div>
<div *ngIf="stakeholder.defaultId != '-1' && ((indicator.description && indicator.description.length > 0) || !stakeholder.defaultId)" <div *ngIf="stakeholder.defaultId != '-1' && ((indicator.description && indicator.description.length > 0) || !stakeholder.defaultId)"
input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('description')" placeholder="Default Description" type="textarea"> input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('description')"
placeholder="Default Description" type="textarea">
</div> </div>
<div *ngIf="stakeholder.defaultId" input class="uk-width-1-1" [formInput]="chartIndicatorFb.get('additionalDescription')" <div *ngIf="stakeholder.defaultId" input class="uk-width-1-1"
[formInput]="chartIndicatorFb.get('additionalDescription')"
placeholder="Description" type="textarea"> placeholder="Description" type="textarea">
</div> </div>
<div *ngIf="showVisibility" input class="uk-width-1-2@m" [formInput]="chartIndicatorFb.get('visibility')" <div *ngIf="showVisibility" input class="uk-width-1-2@m" [formInput]="chartIndicatorFb.get('visibility')"
@ -355,40 +475,113 @@
[options]="indicatorUtils.indicatorSizes" type="select"> [options]="indicatorUtils.indicatorSizes" type="select">
</div> </div>
<div *ngIf="chartIndicatorPaths" formArrayName="indicatorPaths" class="uk-width-1-1"> <div *ngIf="chartIndicatorPaths" formArrayName="indicatorPaths" class="uk-width-1-1">
<div *ngIf="stakeholderUtils.hasMultiChartIndicatorPaths" class="uk-margin-medium-bottom">
<ul #transitionGroup class="uk-subnav uk-subnav-pill uk-subnav-small" transition-group>
<li *ngFor="let indicatorPath of chartIndicatorPaths.controls; let i=index"
class="uk-visible-toggle uk-flex uk-margin-small-top" transition-group-item
[class.uk-active]="(!indicator.activePath && i == 0) || indicator.activePath === i">
<a (click)="activeChartIndicatorPath(i)">
<span>{{ getParameter(i, 'title')?.get('value')?.value ? getParameter(i, 'title').get('value').value : 'No title yet' }}</span>
</a>
<span *ngIf="!indicator.defaultId && chartIndicatorPaths.length > 1"
class="uk-flex uk-flex-column uk-flex-center uk-margin-small-left"
[class.uk-invisible-hover]="indicator.activePath !== i"
(click)="$event.stopPropagation();$event.preventDefault()">
<a class="uk-link-reset uk-flex uk-flex-middle">
<icon [flex]="true" name="more_vert"></icon>
</a>
<div #element
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; container: .uk-modal-body">
<ul class="uk-nav uk-dropdown-nav">
<li *ngIf="i > 0">
<a (click)="hide(element);moveIndicatorPath(chartIndicatorFb, chartIndicatorPaths, i)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="west" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Move Left</span>
</div>
</a>
</li>
<li *ngIf="i < chartIndicatorPaths.length - 1">
<a (click)="hide(element);moveIndicatorPath(chartIndicatorFb, chartIndicatorPaths, i, i + 1)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="east" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Move Right</span>
</div>
</a>
</li>
<li>
<a (click)="removeChartIndicatorPath(i); hide(element)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="delete" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Delete</span>
</div>
</a>
</li>
</ul>
</div>
</span>
</li>
<li class="uk-margin-small-top">
<a (click)="activeChartIndicatorPath(chartIndicatorPaths.length); $event.preventDefault()"
class="uk-flex uk-flex-middle">
<icon name="add" [flex]="true"></icon>
<span class="uk-text-uppercase">Add</span>
</a>
</li>
</ul>
</div>
<div *ngFor="let indicatorPath of chartIndicatorPaths.controls; let i=index;" <div *ngFor="let indicatorPath of chartIndicatorPaths.controls; let i=index;"
[formGroupName]="i" class="uk-grid" uk-grid> [formGroupName]="i">
<div *ngIf="(!indicator.activePath && i == 0) || indicator.activePath === i" class="uk-grid"
uk-grid>
<div class="uk-width-1-1 uk-flex uk-flex-middle"> <div class="uk-width-1-1 uk-flex uk-flex-middle">
<div input class="uk-width-expand" [title]="indicatorPath.get('url').disabled?'Default chart URLs cannot change':''" <div input class="uk-width-expand"
[title]="indicatorPath.get('url').disabled?'Default chart URLs cannot change':''"
[formInput]="indicatorPath.get('url')" placeholder="Chart URL"> [formInput]="indicatorPath.get('url')" placeholder="Chart URL">
<div *ngIf="urlParameterizedMessage" warning>{{urlParameterizedMessage}}</div> <div *ngIf="urlParameterizedMessage" warning>{{ urlParameterizedMessage }}</div>
</div> </div>
<div class='uk-padding-small'> <div class='uk-padding-small'>
<a class="uk-link-reset" (click)="copyToClipboard(indicatorPath.get('url').value)"><icon [flex]="true" name="content_copy"></icon></a> <a class="uk-link-reset" (click)="copyToClipboard(indicatorPath.get('url').value)">
<icon [flex]="true" name="content_copy"></icon>
</a>
</div> </div>
</div> </div>
<div class="uk-width-1-1" formArrayName="parameters"> <div class="uk-width-1-1" formArrayName="parameters">
<div class="uk-grid" uk-grid> <div class="uk-grid" uk-grid>
<div *ngIf="getParameter(i, 'title')" input class="uk-width-1-1" [formInput]="getParameter(i, 'title').get('value')" <div *ngIf="getParameter(i, 'title')" input class="uk-width-1-1"
[formInput]="getParameter(i, 'title').get('value')"
placeholder="Chart Title"></div> placeholder="Chart Title"></div>
<div *ngIf="getParameter(i, 'subtitle')" input class="uk-width-1-1" placeholder="Chart Subtitle" [formInput]="getParameter(i, 'subtitle').get('value')" label="Chart Subtitle"></div> <div *ngIf="getParameter(i, 'subtitle')" input class="uk-width-1-1"
<div *ngIf="!getParameter(i, 'type')" input class="uk-width-1-3@s" [formInput]="indicatorPath.get('type')" placeholder="Chart Type" placeholder="Chart Subtitle" [formInput]="getParameter(i, 'subtitle').get('value')"
label="Chart Subtitle"></div>
<div *ngIf="!getParameter(i, 'type')" input class="uk-width-1-3@s"
[formInput]="indicatorPath.get('type')" placeholder="Chart Type"
[options]="(indicatorPath.get('type').value == 'table' && getParameter(i, 'data_title_0'))?indicatorUtils.getChartTypes(indicatorPath.get('type').value):indicatorUtils.allChartTypes" [options]="(indicatorPath.get('type').value == 'table' && getParameter(i, 'data_title_0'))?indicatorUtils.getChartTypes(indicatorPath.get('type').value):indicatorUtils.allChartTypes"
type="select"></div> type="select"></div>
<div *ngIf="getParameter(i, 'type')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'type').get('value')" placeholder="Chart Type" <div *ngIf="getParameter(i, 'type')" input class="uk-width-1-3@s"
[options]="indicatorUtils.getChartTypes(getParameter(i, 'type').get('value').value)" type="select"></div> [formInput]="getParameter(i, 'type').get('value')" placeholder="Chart Type"
<div *ngIf="getParameter(i, 'xAxisTitle')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'xAxisTitle').get('value')" [options]="indicatorUtils.getChartTypes(getParameter(i, 'type').get('value').value)"
type="select"></div>
<div *ngIf="getParameter(i, 'xAxisTitle')" input class="uk-width-1-3@s"
[formInput]="getParameter(i, 'xAxisTitle').get('value')"
placeholder="X-Axis Title"></div> placeholder="X-Axis Title"></div>
<div *ngIf="getParameter(i, 'yAxisTitle')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'yAxisTitle').get('value')" <div *ngIf="getParameter(i, 'yAxisTitle')" input class="uk-width-1-3@s"
[formInput]="getParameter(i, 'yAxisTitle').get('value')"
placeholder="Y-Axis Title"></div> placeholder="Y-Axis Title"></div>
<div *ngIf="getParameter(i, 'data_title_0')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'data_title_0').get('value')" <div *ngIf="getParameter(i, 'data_title_0')" input class="uk-width-1-3@s"
[formInput]="getParameter(i, 'data_title_0').get('value')"
placeholder="Data Title"></div> placeholder="Data Title"></div>
<div *ngIf="getParameter(i, 'data_title_1')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'data_title_1').get('value')" <div *ngIf="getParameter(i, 'data_title_1')" input class="uk-width-1-3@s"
[formInput]="getParameter(i, 'data_title_1').get('value')"
placeholder="Data Title"></div> placeholder="Data Title"></div>
<div *ngIf="getParameter(i, 'start_year')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'start_year').get('value')" <div *ngIf="getParameter(i, 'start_year')" input class="uk-width-1-3@s"
[formInput]="getParameter(i, 'start_year').get('value')"
placeholder="Year (From)"></div> placeholder="Year (From)"></div>
<div *ngIf="getParameter(i, 'end_year')" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'end_year').get('value')" <div *ngIf="getParameter(i, 'end_year')" input class="uk-width-1-3@s"
[formInput]="getParameter(i, 'end_year').get('value')"
placeholder="Year (To)"></div> placeholder="Year (To)"></div>
<div *ngIf="getParameter(i, 'statsProfile') && statsProfiles" input class="uk-width-1-3@s" [formInput]="getParameter(i, 'statsProfile').get('value')" <div *ngIf="getParameter(i, 'statsProfile') && statsProfiles" input
class="uk-width-1-3@s" [formInput]="getParameter(i, 'statsProfile').get('value')"
[type]="'select'" [options]="statsProfiles" placeholder="Stats Profile"></div> [type]="'select'" [options]="statsProfiles" placeholder="Stats Profile"></div>
</div> </div>
</div> </div>
@ -397,7 +590,8 @@
<div *ngIf="(hasDifference(i)) && !indicatorPath.invalid" <div *ngIf="(hasDifference(i)) && !indicatorPath.invalid"
class="uk-width-1-1 uk-height-large refresh-indicator"> class="uk-width-1-1 uk-height-large refresh-indicator">
<div class="uk-position-relative uk-height-1-1"> <div class="uk-position-relative uk-height-1-1">
<a class="uk-position-center uk-text-center uk-link-reset" (click)="refreshIndicator()"> <a class="uk-position-center uk-text-center uk-link-reset"
(click)="refreshIndicator()">
<div> <div>
<icon name="refresh"></icon> <icon name="refresh"></icon>
</div> </div>
@ -405,11 +599,15 @@
</a> </a>
</div> </div>
</div> </div>
<iframe *ngIf="indicator.indicatorPaths[i].source !== 'image'" [class.uk-blend-multiply]="!isFullscreen" <iframe *ngIf="indicator.indicatorPaths[i].source !== 'image'"
[src]="indicator.indicatorPaths[i].safeResourceUrl" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" [class.uk-blend-multiply]="!isFullscreen"
[src]="indicator.indicatorPaths[i].safeResourceUrl" allowfullscreen="true"
mozallowfullscreen="true" webkitallowfullscreen="true"
class="uk-width-1-1 uk-height-large"></iframe> class="uk-width-1-1 uk-height-large"></iframe>
<div *ngIf="indicator.indicatorPaths[i].source === 'image'"> <div *ngIf="indicator.indicatorPaths[i].source === 'image'">
<img class="uk-width-1-1 uk-height-large uk-blend-multiply" [src]="indicator.indicatorPaths[i].url"> <img class="uk-width-1-1 uk-height-large uk-blend-multiply"
[src]="indicator.indicatorPaths[i].url">
</div>
</div> </div>
</div> </div>
</div> </div>
@ -418,13 +616,15 @@
<div #editChartNotify notify-form class="uk-width-1-1 uk-margin-medium-top"></div> <div #editChartNotify notify-form class="uk-width-1-1 uk-margin-medium-top"></div>
</div> </div>
</modal-alert> </modal-alert>
<modal-alert #deleteModal (alertOutput)="deleteIndicator()" [overflowBody]="false" classTitle="uk-background-primary uk-light"> <modal-alert #deleteModal (alertOutput)="deleteIndicator()" [overflowBody]="false"
classTitle="uk-background-primary uk-light">
<div [class.uk-invisible]="editing" class="uk-position-relative"> <div [class.uk-invisible]="editing" class="uk-position-relative">
<div *ngIf="editing"> <div *ngIf="editing">
<loading class="uk-position-center"></loading> <loading class="uk-position-center"></loading>
</div> </div>
You are about to delete <span class="uk-text-bold" *ngIf="indicator && index !== -1"> You are about to delete <span class="uk-text-bold" *ngIf="indicator && index !== -1">
"{{indicator.name ? indicator.name : (indicator.indicatorPaths[0]?.parameters?.title?indicator.indicatorPaths[0].parameters.title:'')}}"</span> indicator permanently. "{{ indicator.name ? indicator.name : (indicator.indicatorPaths[0]?.parameters?.title ? indicator.indicatorPaths[0].parameters.title : '') }}
"</span> indicator permanently.
<div *ngIf="indicatorChildrenActionOnDelete == 'delete'" class="uk-text-bold"> <div *ngIf="indicatorChildrenActionOnDelete == 'delete'" class="uk-text-bold">
Indicators of all profiles based on this default indicator, will be deleted as well. Indicators of all profiles based on this default indicator, will be deleted as well.
</div> </div>
@ -432,7 +632,8 @@
<div #deleteNotify notify-form class="uk-width-1-1 uk-margin-medium-top"></div> <div #deleteNotify notify-form class="uk-width-1-1 uk-margin-medium-top"></div>
</div> </div>
</modal-alert> </modal-alert>
<modal-alert #deleteSectionModal (alertOutput)="deleteSection()" [overflowBody]="false" classTitle="uk-background-primary uk-light"> <modal-alert #deleteSectionModal (alertOutput)="deleteSection()" [overflowBody]="false"
classTitle="uk-background-primary uk-light">
<div [class.uk-invisible]="editing" class="uk-position-relative"> <div [class.uk-invisible]="editing" class="uk-position-relative">
<div *ngIf="editing"> <div *ngIf="editing">
<loading class="uk-position-center"></loading> <loading class="uk-position-center"></loading>

View File

@ -20,7 +20,7 @@ import {
Visibility Visibility
} from "../../monitor/entities/stakeholder"; } from "../../monitor/entities/stakeholder";
import { import {
AbstractControl, AbstractControl, FormArray, FormGroup,
UntypedFormArray, UntypedFormArray,
UntypedFormBuilder, UntypedFormBuilder,
UntypedFormControl, UntypedFormControl,
@ -45,6 +45,7 @@ import {NotificationHandler} from "../../utils/notification-handler";
import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component"; import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component";
import {properties} from "../../../../environments/environment"; import {properties} from "../../../../environments/environment";
import {StatsProfilesService} from "../utils/services/stats-profiles.service"; import {StatsProfilesService} from "../utils/services/stats-profiles.service";
import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component";
declare var UIkit; declare var UIkit;
declare var copy; declare var copy;
@ -101,6 +102,8 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
@ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent; @ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent;
@ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent; @ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent;
@ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent; @ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent;
/* Transition Groups */
@ViewChild('transitionGroup') transitionGroup: TransitionGroupComponent;
public isFullscreen: boolean = false; public isFullscreen: boolean = false;
@ -266,7 +269,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
setNumbers() { setNumbers() {
this.numberSections = this.fb.array([]); this.numberSections = this.fb.array([]);
this.numberResults.clear(); this.numberResults.clear();
let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>(); let urls: Map<string, [number, number, number][]> = new Map<string, [number, number, number][]>();
this.numbers.forEach((section, i) => { this.numbers.forEach((section, i) => {
this.numberSections.push(this.fb.group({ this.numberSections.push(this.fb.group({
_id: this.fb.control(section._id), _id: this.fb.control(section._id),
@ -278,13 +281,15 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
indicators: this.fb.control(section.indicators) indicators: this.fb.control(section.indicators)
})); }));
section.indicators.forEach((number, j) => { section.indicators.forEach((number, j) => {
let url = this.indicatorUtils.getFullUrl(this.stakeholder, number.indicatorPaths[0]); number.indicatorPaths.forEach((indicatorPath, k) => {
const pair = JSON.stringify([number.indicatorPaths[0].source, url]); let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath);
const pair = JSON.stringify([indicatorPath.source, url]);
const indexes = urls.get(pair) ? urls.get(pair) : []; const indexes = urls.get(pair) ? urls.get(pair) : [];
indexes.push([i, j]); indexes.push([i, j, k]);
urls.set(pair, indexes); urls.set(pair, indexes);
}); });
}); });
});
this.numberSubscription.forEach(value => { this.numberSubscription.forEach(value => {
if (value instanceof Subscriber) { if (value instanceof Subscriber) {
value.unsubscribe(); value.unsubscribe();
@ -304,10 +309,10 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
}); });
} }
private calculateResults(response: any, indexes: [number, number][]) { private calculateResults(response: any, indexes: [number, number, number][]) {
indexes.forEach(([i, j]) => { indexes.forEach(([i, j, k]) => {
let result = JSON.parse(JSON.stringify(response)); 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) { if (result) {
result = result[jsonPath]; result = result[jsonPath];
} }
@ -320,7 +325,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
} else { } else {
result = 0; result = 0;
} }
this.numberResults.set(i + '-' + j, result); this.numberResults.set(i + '-' + j + '-' + k, result);
}); });
} }
@ -367,6 +372,14 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
return this.chartIndicatorFb.get('indicatorPaths') as UntypedFormArray; 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) { public getNumberClassBySize(size: IndicatorSize) {
if (size === 'small') { if (size === 'small') {
return 'uk-width-medium@m uk-width-1-1'; return 'uk-width-medium@m uk-width-1-1';
@ -579,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 { private getJsonPathAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray {
let jsonPath = this.fb.array([]); let jsonPath = this.fb.array([]);
if (indicatorPath.jsonPath) { if (indicatorPath.jsonPath) {
@ -1273,25 +1345,29 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple
if (chart.type == "chart") { if (chart.type == "chart") {
indicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(chart.url), chart.url, chart.type, stakeholder); 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) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts.forEach((section: Section) => {
for (let chart of section.indicators) { section.indicators.forEach(indicator => {
if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) { indicator.indicatorPaths.forEach(path => {
if (JSON.stringify(path.chartObject) == JSON.stringify(indicatorPath.chartObject)) {
duplicates++; duplicates++;
exists = true; exists = true;
} }
} });
} });
});
} else if (chart.type == "number") { } else if (chart.type == "number") {
indicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(chart.url), chart.url, stakeholder, indicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(chart.url), chart.url, stakeholder,
chart.jsonPath, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(chart.url))); 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) { this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers.forEach((section: Section) => {
for (let chart of section.indicators) { section.indicators.forEach(indicator => {
if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) { indicator.indicatorPaths.forEach(path => {
if (JSON.stringify(path.chartObject) == JSON.stringify(indicatorPath.chartObject)) {
duplicates++; duplicates++;
exists = true; exists = true;
} }
} });
} });
});
} }
if (!exists) { 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]); 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]);

View File

@ -242,30 +242,18 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
} }
topicChanged(callback: Function, save: boolean = false) { 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) { if(callback) {
callback(); callback();
} }
this.cdr.detectChanges(); this.cdr.detectChanges();
if(this.topics && save) { if(this.topics && save) {
this.topics.init(); this.topics.init();
this.topics.enable();
} }
if(this.categories) { if(this.categories) {
this.categories.init(); this.categories.init();
this.categories.enable();
} }
if(this.subCategories) { if(this.subCategories) {
this.subCategories.init(); this.subCategories.init();
this.subCategories.enable();
} }
} }
@ -359,6 +347,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
this.stakeholder.topics.splice(this.index, 1); this.stakeholder.topics.splice(this.index, 1);
if(this.topicIndex === this.index) { if(this.topicIndex === this.index) {
this.chooseTopic(Math.max(0, this.index - 1)); this.chooseTopic(Math.max(0, this.index - 1));
} else if(this.topicIndex > this.index) {
this.chooseTopic(this.topicIndex - 1);
} }
}, true); }, true);
}; };
@ -388,23 +378,15 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
} }
categoryChanged(callback: Function, save: boolean = false) { categoryChanged(callback: Function, save: boolean = false) {
if(this.categories && save) {
this.categories.disable();
}
if(this.subCategories) {
this.subCategories.disable();
}
if(callback) { if(callback) {
callback(); callback();
} }
this.cdr.detectChanges(); this.cdr.detectChanges();
if(this.categories && save) { if(this.categories && save) {
this.categories.init(); this.categories.init();
this.categories.enable();
} }
if(this.subCategories) { if(this.subCategories) {
this.subCategories.init(); 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); this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1);
if(this.categoryIndex === this.index) { if(this.categoryIndex === this.index) {
this.chooseCategory(Math.max(0, this.index - 1)); this.chooseCategory(Math.max(0, this.index - 1));
} else if(this.categoryIndex > this.index) {
this.chooseCategory(this.categoryIndex - 1);
} }
}, true); }, true);
}; };
@ -528,16 +512,12 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit,
} }
subCategoryChanged(callback: Function, save: boolean = false) { subCategoryChanged(callback: Function, save: boolean = false) {
if(this.subCategories && save) {
this.subCategories.disable();
}
if(callback) { if(callback) {
callback(); callback();
} }
this.cdr.detectChanges(); this.cdr.detectChanges();
if(this.subCategories && save) { if(this.subCategories && save) {
this.subCategories.init(); 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); this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories.splice(this.index, 1);
if(this.subCategoryIndex === this.index) { if(this.subCategoryIndex === this.index) {
this.chooseSubcategory(Math.max(0, this.index - 1)); this.chooseSubcategory(Math.max(0, this.index - 1));
} else if(this.subCategoryIndex > this.index) {
this.chooseSubcategory(this.subCategoryIndex - 1);
} }
}, true); }, true);
}; };

View File

@ -20,11 +20,12 @@ import {TransitionGroupModule} from "../../utils/transition-group/transition-gro
import {NumberRoundModule} from "../../utils/pipes/number-round.module"; import {NumberRoundModule} from "../../utils/pipes/number-round.module";
import {SideBarModule} from "../../dashboard/sharedComponents/sidebar/sideBar.module"; import {SideBarModule} from "../../dashboard/sharedComponents/sidebar/sideBar.module";
import {SidebarMobileToggleModule} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module"; import {SidebarMobileToggleModule} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module";
import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module";
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, TopicRoutingModule, ClickModule, RouterModule, FormsModule, AlertModalModule, 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: [ declarations: [
TopicComponent, IndicatorsComponent TopicComponent, IndicatorsComponent

View File

@ -55,6 +55,8 @@ export class StakeholderConfiguration {
{icon: 'incognito', value: "PRIVATE", label: 'Private'}, {icon: 'incognito', value: "PRIVATE", label: 'Private'},
]; ];
public static CACHE_INDICATORS: boolean = true; public static CACHE_INDICATORS: boolean = true;
public static NUMBER_MULTI_INDICATOR_PATHS = false;
public static CHART_MULTI_INDICATOR_PATHS = true;
} }
export class StakeholderUtils { export class StakeholderUtils {
@ -82,6 +84,14 @@ export class StakeholderUtils {
return StakeholderConfiguration.CACHE_INDICATORS; return StakeholderConfiguration.CACHE_INDICATORS;
} }
get hasMultiNumberIndicatorPaths() {
return StakeholderConfiguration.NUMBER_MULTI_INDICATOR_PATHS;
}
get hasMultiChartIndicatorPaths() {
return StakeholderConfiguration.CHART_MULTI_INDICATOR_PATHS;
}
visibilityIcon: Map<Visibility, string> = new Map<Visibility, string>(this.visibilities.map(option => [option.value, option.icon])); visibilityIcon: Map<Visibility, string> = new Map<Visibility, string>(this.visibilities.map(option => [option.value, option.icon]));
defaultValue(options: Option[]) { defaultValue(options: Option[]) {

View File

@ -183,6 +183,7 @@ export class Indicator {
visibility: Visibility; visibility: Visibility;
defaultId: string; defaultId: string;
indicatorPaths: IndicatorPath[]; indicatorPaths: IndicatorPath[];
activePath: number = 0;
overlay: Overlay = false; overlay: Overlay = false;
constructor(name: string, description: string, additionalDescription:string, type: IndicatorType, width: IndicatorSize,height: IndicatorSize, visibility: Visibility, indicatorPaths: IndicatorPath[], defaultId: string = null) { constructor(name: string, description: string, additionalDescription:string, type: IndicatorType, width: IndicatorSize,height: IndicatorSize, visibility: Visibility, indicatorPaths: IndicatorPath[], defaultId: string = null) {

View File

@ -214,15 +214,17 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
(this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : ""); (this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : "");
//clear numbers when filters change //clear numbers when filters change
this.numberResults.clear(); this.numberResults.clear();
let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>(); let urls: Map<string, [number, number, number][]> = new Map<string, [number, number, number][]>();
this.activeSubCategory.numbers.forEach((section, i) => { this.activeSubCategory.numbers.forEach((section, i) => {
section.indicators.forEach((number, j) => { section.indicators.forEach((number, j) => {
if (this.hasPermission(number.visibility)) { if (this.hasPermission(number.visibility)) {
let url = this.getFullUrl(number.indicatorPaths[0]); number.indicatorPaths.forEach((indicatorPath, k) => {
const pair = JSON.stringify([number.indicatorPaths[0].source, url]); let url = this.getFullUrl(indicatorPath);
const pair = JSON.stringify([indicatorPath.source, url]);
const indexes = urls.get(pair) ? urls.get(pair) : []; const indexes = urls.get(pair) ? urls.get(pair) : [];
indexes.push([i, j]); indexes.push([i, j, k]);
urls.set(pair, indexes); urls.set(pair, indexes);
})
} }
}); });
}); });
@ -231,10 +233,10 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
let activeSubcategory = this.activeSubCategory._id; let activeSubcategory = this.activeSubCategory._id;
this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => { this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => {
if(activeSubcategory === this.activeSubCategory._id) { if(activeSubcategory === this.activeSubCategory._id) {
indexes.forEach(([i, j]) => { indexes.forEach(([i, j, k]) => {
if( this.activeSubCategory?.numbers[i]?.indicators[j]) { if( this.activeSubCategory?.numbers[i]?.indicators[j]) {
let result = JSON.parse(JSON.stringify(response)); 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) { if (result) {
result = result[jsonPath]; result = result[jsonPath];
} }
@ -247,7 +249,7 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator
} else { } else {
result = 0; 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) => { this.activeSubCategory.charts.forEach((section, i) => {
section.indicators.forEach((indicator, j) => { section.indicators.forEach((indicator, j) => {
if (indicator.indicatorPaths.length > 0) { indicator.indicatorPaths.forEach((indicatorPath, k) => {
indicator.indicatorPaths[0].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[0]); indicator.indicatorPaths[k].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[k]);
this.chartsActiveType.set(i + '-' + j, indicator.indicatorPaths[0]); this.chartsActiveType.set(i + '-' + j + '-' + k, indicator.indicatorPaths[k]);
} });
}); });
}); });
if (this.cdr && !(this.cdr as ViewRef).destroyed) { if (this.cdr && !(this.cdr as ViewRef).destroyed) {

View File

@ -1,6 +1,6 @@
import {TransitionGroupItemDirective} from "./transition-group-item.directive"; import {TransitionGroupItemDirective} from "./transition-group-item.directive";
import { import {
AfterViewInit, AfterViewInit, ChangeDetectorRef,
Component, Component,
ContentChildren, ContentChildren,
ElementRef, Input, ElementRef, Input,
@ -29,15 +29,14 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy {
@ContentChildren(TransitionGroupItemDirective) items: QueryList<TransitionGroupItemDirective>; @ContentChildren(TransitionGroupItemDirective) items: QueryList<TransitionGroupItemDirective>;
@Input() @Input()
public id: string; public id: string;
private disabled: boolean = false; public size: number;
private subscription: Subscription; private subscription: Subscription;
constructor(public element: ElementRef) {} constructor(public element: ElementRef) {}
ngAfterViewInit() { ngAfterViewInit() {
this.init();
this.subscription = this.items.changes.subscribe(items => { 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(item => item.prevPos = item.newPos || item.prevPos);
items.forEach(this.runCallback); items.forEach(this.runCallback);
this.refreshPosition('newPos'); this.refreshPosition('newPos');
@ -80,6 +79,7 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy {
init() { init() {
this.refreshPosition('prevPos'); this.refreshPosition('prevPos');
this.refreshPosition('newPos'); this.refreshPosition('newPos');
this.size = this.items.length;
} }
runCallback(item: TransitionGroupItemDirective) { runCallback(item: TransitionGroupItemDirective) {
@ -126,17 +126,17 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy {
/** /**
* Enable transition * Enable transition
* * @deprecated
* */ * */
enable() { enable() {
this.disabled = false; console.debug('Deprecated')
} }
/** /**
* Disable transition * Disable transition
* * @deprecated
* */ * */
disable() { disable() {
this.disabled = true; console.debug('Deprecated')
} }
} }