TSK-1805: Made loading more obvious

Loading bar is now a more intense color and is larger
Also made sure the loading bar is shown when loading components
This commit is contained in:
Tristan 2022-02-15 15:56:15 +01:00 committed by Tristan2357
parent f1ae2afccd
commit df40c6dad9
22 changed files with 167 additions and 69 deletions

View File

@ -31,6 +31,7 @@ import {
} from '../../../shared/store/classification-store/classification.actions'; } from '../../../shared/store/classification-store/classification.actions';
import { ClassificationTreeService } from '../../services/classification-tree.service'; import { ClassificationTreeService } from '../../services/classification-tree.service';
import { Pair } from '../../../shared/models/pair'; import { Pair } from '../../../shared/models/pair';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-administration-tree', selector: 'taskana-administration-tree',
@ -83,7 +84,8 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
private location: Location, private location: Location,
private store: Store, private store: Store,
private notificationsService: NotificationService, private notificationsService: NotificationService,
private classificationTreeService: ClassificationTreeService private classificationTreeService: ClassificationTreeService,
private requestInProgressService: RequestInProgressService
) {} ) {}
@HostListener('document:click', ['$event']) @HostListener('document:click', ['$event'])
@ -104,6 +106,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
.subscribe(([selectedClassificationId, treeNodes]) => { .subscribe(([selectedClassificationId, treeNodes]) => {
this.treeNodes = treeNodes; this.treeNodes = treeNodes;
this.selectNodeId = typeof selectedClassificationId !== 'undefined' ? selectedClassificationId : undefined; this.selectNodeId = typeof selectedClassificationId !== 'undefined' ? selectedClassificationId : undefined;
this.requestInProgressService.setRequestInProgress(false);
if (typeof this.tree.treeModel.getActiveNode() !== 'undefined') { if (typeof this.tree.treeModel.getActiveNode() !== 'undefined') {
if (this.tree.treeModel.getActiveNode().data.classificationId !== this.selectNodeId) { if (this.tree.treeModel.getActiveNode().data.classificationId !== this.selectNodeId) {
// wait for angular's two-way binding to convert the treeNodes to the internal tree structure. // wait for angular's two-way binding to convert the treeNodes to the internal tree structure.
@ -146,6 +149,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
onActivate(treeNode: any) { onActivate(treeNode: any) {
const id = treeNode.node.data.classificationId; const id = treeNode.node.data.classificationId;
this.selectNodeId = id; this.selectNodeId = id;
this.requestInProgressService.setRequestInProgress(true);
this.store.dispatch(new SelectClassification(id)); this.store.dispatch(new SelectClassification(id));
this.location.go(this.location.path().replace(/(classifications).*/g, `classifications/(detail:${id})`)); this.location.go(this.location.path().replace(/(classifications).*/g, `classifications/(detail:${id})`));
} }

View File

@ -34,7 +34,8 @@
isExpanded="true"></taskana-shared-workbasket-filter> isExpanded="true"></taskana-shared-workbasket-filter>
<!-- EMPTY LIST --> <!-- EMPTY LIST -->
<div *ngIf="distributionTargets?.length == 0" class="distribution-targets-list__empty-list"> <div *ngIf="distributionTargets?.length == 0 && requestInProgress < 0"
class="distribution-targets-list__empty-list">
<!-- AVAILABLE SIDE --> <!-- AVAILABLE SIDE -->
<div *ngIf="side === 0" style="padding: 0 16px;"> <div *ngIf="side === 0" style="padding: 0 16px;">
@ -48,14 +49,17 @@
</div> </div>
<!-- SPINNER -->
<taskana-shared-spinner [isRunning]="requestInProgress >= 0"></taskana-shared-spinner>
<!-- WORKBASKET LIST --> <!-- WORKBASKET LIST -->
<mat-selection-list #workbasket [multiple]="true"> <mat-selection-list #workbasket [multiple]="true">
<cdk-virtual-scroll-viewport #scroller <cdk-virtual-scroll-viewport #scroller
class="{{toolbarState? 'distribution-targets-list__list--with-filter' : 'distribution-targets-list__list--no-filter'}}" class="{{toolbarState? 'distribution-targets-list__list--with-filter' : 'distribution-targets-list__list--no-filter'}}"
itemSize="90"> itemSize="90">
<mat-list-option <mat-list-option
*cdkVirtualFor="let workbasket of distributionTargets| orderBy: ['name']; templateCacheSize: 0"
(click)="updateSelectAll(!workbasket.selected) && (workbasket.selected = !workbasket.selected)" (click)="updateSelectAll(!workbasket.selected) && (workbasket.selected = !workbasket.selected)"
*cdkVirtualFor="let workbasket of distributionTargets| orderBy: ['name']; templateCacheSize: 0"
[selected]="workbasket.selected" [selected]="workbasket.selected"
[value]="workbasket.workbasketId" [value]="workbasket.workbasketId"
class="workbasket-distribution-targets__workbaskets-item"> class="workbasket-distribution-targets__workbaskets-item">

View File

@ -62,6 +62,7 @@ export class WorkbasketDistributionTargetsListComponent
@ViewChild('workbasket') distributionTargetsList: MatSelectionList; @ViewChild('workbasket') distributionTargetsList: MatSelectionList;
@ViewChild('scroller') workbasketList: CdkVirtualScrollViewport; @ViewChild('scroller') workbasketList: CdkVirtualScrollViewport;
requestInProgress: number;
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
private filter: WorkbasketQueryFilterParameter; private filter: WorkbasketQueryFilterParameter;
private allSelectedDiff = 0; private allSelectedDiff = 0;
@ -69,6 +70,7 @@ export class WorkbasketDistributionTargetsListComponent
constructor(private changeDetector: ChangeDetectorRef, private store: Store) {} constructor(private changeDetector: ChangeDetectorRef, private store: Store) {}
ngOnInit(): void { ngOnInit(): void {
this.requestInProgress = 2;
if (this.side === Side.AVAILABLE) { if (this.side === Side.AVAILABLE) {
this.availableDistributionTargets$.pipe(takeUntil(this.destroy$)).subscribe((wbs) => this.assignWbs(wbs)); this.availableDistributionTargets$.pipe(takeUntil(this.destroy$)).subscribe((wbs) => this.assignWbs(wbs));
this.availableDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => { this.availableDistributionTargetsFilter$.pipe(takeUntil(this.destroy$)).subscribe((filter) => {
@ -79,6 +81,7 @@ export class WorkbasketDistributionTargetsListComponent
this.filter = filter; this.filter = filter;
this.store.dispatch(new FetchAvailableDistributionTargets(true, this.filter)); this.store.dispatch(new FetchAvailableDistributionTargets(true, this.filter));
this.selectAll(false); this.selectAll(false);
this.requestInProgress--;
}); });
} else { } else {
this.workbasketDistributionTargets$.pipe().subscribe((wbs) => this.assignWbs(wbs)); this.workbasketDistributionTargets$.pipe().subscribe((wbs) => this.assignWbs(wbs));
@ -90,6 +93,7 @@ export class WorkbasketDistributionTargetsListComponent
this.filter = filter; this.filter = filter;
this.applyFilter(); this.applyFilter();
this.selectAll(false); this.selectAll(false);
this.requestInProgress--;
}); });
} }
this.transferDistributionTargetObservable.subscribe((targetSide) => { this.transferDistributionTargetObservable.subscribe((targetSide) => {
@ -164,8 +168,11 @@ export class WorkbasketDistributionTargetsListComponent
} }
private assignWbs(wbs: WorkbasketSummary[]) { private assignWbs(wbs: WorkbasketSummary[]) {
this.distributionTargets = wbs.map((wb) => ({ ...wb, selected: this.allSelected })); this.distributionTargets = wbs.map((wb) => {
return { ...wb, selected: this.allSelected };
});
this.distributionTargetsClone = this.distributionTargets; this.distributionTargetsClone = this.distributionTargets;
this.requestInProgress--;
} }
private applyFilter() { private applyFilter() {

View File

@ -1,19 +1,21 @@
<mat-sidenav-container class="sidenav"> <mat-sidenav-container class="sidenav">
<mat-sidenav #sidenav mode="over" class="sidenav__drawer" [autoFocus]="false"> <mat-sidenav #sidenav [autoFocus]="false" class="sidenav__drawer" mode="over">
<div class="sidenav__drawer__container"> <div class="sidenav__drawer__container">
<div class="sidenav__drawer__container-menu"> <div class="sidenav__drawer__container-menu">
<button mat-icon-button class="navbar_button-toggle" (click)="toggleSidenav()"> <button (click)="toggleSidenav()" class="navbar_button-toggle" mat-icon-button>
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>
</div> </div>
<div class="sidenav__drawer__container-logout"> <div class="sidenav__drawer__container-logout">
<button mat-icon-button data-toggle="tooltip" title="Logout" (click)="logout()" aria-expanded="true" <button (click)="logout()" aria-controls="logout" aria-expanded="true" data-toggle="tooltip"
aria-controls="logout"> mat-icon-button
title="Logout">
<mat-icon>exit_to_app</mat-icon> <mat-icon>exit_to_app</mat-icon>
</button> </button>
</div> </div>
</div> </div>
<taskana-shared-user-information class="sidenav__drawer-user-info"></taskana-shared-user-information> <taskana-shared-user-information
class="sidenav__drawer-user-info"></taskana-shared-user-information>
<taskana-sidenav-list></taskana-sidenav-list> <taskana-sidenav-list></taskana-sidenav-list>
<div class="sidenav__drawer-version"> <div class="sidenav__drawer-version">
<p> Taskana version: {{version}} </p> <p> Taskana version: {{version}} </p>
@ -24,7 +26,10 @@
<div (window:resize)="onResize()"> <div (window:resize)="onResize()">
<div class="taskana-main"> <div class="taskana-main">
<div class="taskana-main__progress-bar"> <div class="taskana-main__progress-bar">
<mat-progress-bar *ngIf="requestInProgress" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="requestInProgress" color="accent"
mode="indeterminate"></mat-progress-bar>
<mat-progress-bar *ngIf="requestInProgress" color="accent"
mode="indeterminate"></mat-progress-bar>
</div> </div>
<router-outlet></router-outlet> <router-outlet></router-outlet>
</div> </div>

View File

@ -17,9 +17,11 @@
width: 350px; width: 350px;
background-color: $dark-green; background-color: $dark-green;
} }
.mat-drawer-content { .mat-drawer-content {
overflow: hidden !important; overflow: hidden !important;
} }
.sidenav__drawer-list-item { .sidenav__drawer-list-item {
margin-left: 30px; margin-left: 30px;
} }
@ -60,8 +62,9 @@
} }
.taskana-main__progress-bar { .taskana-main__progress-bar {
height: 4px; height: 8px;
background-color: $light-grey; background-color: $light-grey;
margin-bottom: 2px;
} }
::ng-deep .mat-drawer-inner-container { ::ng-deep .mat-drawer-inner-container {
@ -75,3 +78,7 @@
::ng-deep mat-tooltip-component { ::ng-deep mat-tooltip-component {
word-break: break-word; word-break: break-word;
} }
mat-progress-bar {
height: 3px;
}

View File

@ -3,6 +3,7 @@ import { MonitorService } from 'app/monitor/services/monitor.service';
import { ChartData } from 'app/monitor/models/chart-data'; import { ChartData } from 'app/monitor/models/chart-data';
import { ReportData } from '../../models/report-data'; import { ReportData } from '../../models/report-data';
import { ChartColorsDefinition } from '../../models/chart-colors'; import { ChartColorsDefinition } from '../../models/chart-colors';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-monitor-classification-report', selector: 'taskana-monitor-classification-report',
@ -22,12 +23,19 @@ export class ClassificationReportComponent implements OnInit {
lineChartColors = ChartColorsDefinition.getColors(); lineChartColors = ChartColorsDefinition.getColors();
constructor(private restConnectorService: MonitorService) {} constructor(
private restConnectorService: MonitorService,
private requestInProgressService: RequestInProgressService
) {}
async ngOnInit() { ngOnInit() {
this.reportData = await this.restConnectorService.getClassificationTasksReport().toPromise(); this.requestInProgressService.setRequestInProgress(true);
this.restConnectorService.getClassificationTasksReport().subscribe((report) => {
this.reportData = report;
this.lineChartData = this.restConnectorService.getChartData(this.reportData); this.lineChartData = this.restConnectorService.getChartData(this.reportData);
this.lineChartLabels = this.reportData.meta.header; this.lineChartLabels = this.reportData.meta.header;
this.requestInProgressService.setRequestInProgress(false);
});
} }
getTitle(): string { getTitle(): string {

View File

@ -9,10 +9,6 @@ import { Router } from '@angular/router';
export class MonitorComponent implements OnInit { export class MonitorComponent implements OnInit {
selectedTab = ''; selectedTab = '';
constructor(public router: Router) {
this.router.navigate(['/taskana/monitor/tasks-priority']);
}
ngOnInit(): void { ngOnInit(): void {
this.selectedTab = 'tasks-priority'; this.selectedTab = 'tasks-priority';
} }

View File

@ -11,6 +11,7 @@ import { settingsStateMock } from '../../../shared/store/mock-data/mock-store';
import { SettingsState } from '../../../shared/store/settings-store/settings.state'; import { SettingsState } from '../../../shared/store/settings-store/settings.state';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { MatDividerModule } from '@angular/material/divider'; import { MatDividerModule } from '@angular/material/divider';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Pipe({ name: 'germanTimeFormat' }) @Pipe({ name: 'germanTimeFormat' })
class GermanTimeFormatPipe implements PipeTransform { class GermanTimeFormatPipe implements PipeTransform {
@ -48,6 +49,7 @@ describe('TaskPriorityReportComponent', () => {
imports: [NgxsModule.forRoot([SettingsState]), MatTableModule, HttpClientTestingModule, MatDividerModule], imports: [NgxsModule.forRoot([SettingsState]), MatTableModule, HttpClientTestingModule, MatDividerModule],
declarations: [TaskPriorityReportComponent, GermanTimeFormatPipe, CanvasStub, TaskPriorityReportFilterStub], declarations: [TaskPriorityReportComponent, GermanTimeFormatPipe, CanvasStub, TaskPriorityReportFilterStub],
providers: [ providers: [
RequestInProgressService,
{ provide: MonitorService, useValue: monitorServiceSpy }, { provide: MonitorService, useValue: monitorServiceSpy },
{ provide: NotificationService, useValue: notificationServiceSpy } { provide: NotificationService, useValue: notificationServiceSpy }
] ]

View File

@ -1,7 +1,6 @@
import { AfterViewChecked, Component, OnDestroy, OnInit } from '@angular/core'; import { AfterViewChecked, Component, OnDestroy, OnInit } from '@angular/core';
import { ReportData } from '../../models/report-data'; import { ReportData } from '../../models/report-data';
import { MonitorService } from '../../services/monitor.service'; import { MonitorService } from '../../services/monitor.service';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { WorkbasketType } from '../../../shared/models/workbasket-type'; import { WorkbasketType } from '../../../shared/models/workbasket-type';
import { Select } from '@ngxs/store'; import { Select } from '@ngxs/store';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
@ -9,6 +8,7 @@ import { SettingsSelectors } from '../../../shared/store/settings-store/settings
import { Settings } from '../../../settings/models/settings'; import { Settings } from '../../../settings/models/settings';
import { mergeMap, take, takeUntil } from 'rxjs/operators'; import { mergeMap, take, takeUntil } from 'rxjs/operators';
import { SettingMembers } from '../../../settings/components/Settings/expected-members'; import { SettingMembers } from '../../../settings/components/Settings/expected-members';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-monitor-task-priority-report', selector: 'taskana-monitor-task-priority-report',
@ -34,9 +34,10 @@ export class TaskPriorityReportComponent implements OnInit, AfterViewChecked, On
@Select(SettingsSelectors.getSettings) @Select(SettingsSelectors.getSettings)
settings$: Observable<Settings>; settings$: Observable<Settings>;
constructor(private monitorService: MonitorService, private notificationService: NotificationService) {} constructor(private monitorService: MonitorService, private requestInProgressService: RequestInProgressService) {}
ngOnInit() { ngOnInit() {
this.requestInProgressService.setRequestInProgress(true);
this.settings$ this.settings$
.pipe( .pipe(
takeUntil(this.destroy$), takeUntil(this.destroy$),
@ -53,6 +54,7 @@ export class TaskPriorityReportComponent implements OnInit, AfterViewChecked, On
) )
.subscribe((reportData) => { .subscribe((reportData) => {
this.setValuesFromReportData(reportData); this.setValuesFromReportData(reportData);
this.requestInProgressService.setRequestInProgress(false);
}); });
} }
@ -114,13 +116,14 @@ export class TaskPriorityReportComponent implements OnInit, AfterViewChecked, On
} }
applyFilter(filter: {}) { applyFilter(filter: {}) {
this.requestInProgressService.setRequestInProgress(true);
this.monitorService this.monitorService
.getTasksByPriorityReport([WorkbasketType.TOPIC], this.priority, filter) .getTasksByPriorityReport([WorkbasketType.TOPIC], this.priority, filter)
.pipe(take(1)) .pipe(take(1))
.subscribe((reportData) => { .subscribe((reportData) => {
this.colorShouldChange = true; this.colorShouldChange = true;
this.setValuesFromReportData(reportData); this.setValuesFromReportData(reportData);
return; this.requestInProgressService.setRequestInProgress(false);
}); });
} }

View File

@ -1,6 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ReportData } from 'app/monitor/models/report-data'; import { ReportData } from 'app/monitor/models/report-data';
import { MonitorService } from '../../services/monitor.service'; import { MonitorService } from '../../services/monitor.service';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-monitor-task-report', selector: 'taskana-monitor-task-report',
@ -12,14 +15,22 @@ export class TaskReportComponent implements OnInit {
pieChartData: number[] = []; pieChartData: number[] = [];
pieChartType = 'pie'; pieChartType = 'pie';
reportData: ReportData; reportData: ReportData;
private destroy$ = new Subject<void>();
constructor(private restConnectorService: MonitorService) {} constructor(private monitorService: MonitorService, private requestInProgressService: RequestInProgressService) {}
async ngOnInit() { ngOnInit() {
this.reportData = await this.restConnectorService.getTaskStatusReport().toPromise(); this.requestInProgressService.setRequestInProgress(true);
this.monitorService
.getTaskStatusReport()
.pipe(takeUntil(this.destroy$))
.subscribe((report) => {
this.reportData = report;
this.pieChartLabels = this.reportData.meta.header; this.pieChartLabels = this.reportData.meta.header;
this.reportData.sumRow[0].cells.forEach((c) => { this.reportData.sumRow[0].cells.forEach((cell) => {
this.pieChartData.push(c); this.pieChartData.push(cell);
});
this.requestInProgressService.setRequestInProgress(false);
}); });
} }

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ReportData } from '../../models/report-data'; import { ReportData } from '../../models/report-data';
import { MonitorService } from '../../services/monitor.service'; import { MonitorService } from '../../services/monitor.service';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-monitor-timestamp-report', selector: 'taskana-monitor-timestamp-report',
@ -10,11 +11,16 @@ import { MonitorService } from '../../services/monitor.service';
export class TimestampReportComponent implements OnInit { export class TimestampReportComponent implements OnInit {
reportData: ReportData; reportData: ReportData;
constructor(private restConnectorService: MonitorService) {} constructor(
private restConnectorService: MonitorService,
private requestInProgressService: RequestInProgressService
) {}
ngOnInit() { ngOnInit() {
this.requestInProgressService.setRequestInProgress(true);
this.restConnectorService.getDailyEntryExitReport().subscribe((data: ReportData) => { this.restConnectorService.getDailyEntryExitReport().subscribe((data: ReportData) => {
this.reportData = data; this.reportData = data;
this.requestInProgressService.setRequestInProgress(false);
}); });
} }
} }

View File

@ -4,6 +4,7 @@ import { ChartData } from '../../models/chart-data';
import { ChartColorsDefinition } from '../../models/chart-colors'; import { ChartColorsDefinition } from '../../models/chart-colors';
import { MonitorService } from '../../services/monitor.service'; import { MonitorService } from '../../services/monitor.service';
import { MetaInfoData } from '../../models/meta-info-data'; import { MetaInfoData } from '../../models/meta-info-data';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-monitor-workbasket-report-due-date', selector: 'taskana-monitor-workbasket-report-due-date',
@ -26,12 +27,19 @@ export class WorkbasketReportDueDateComponent implements OnInit {
lineChartColors = ChartColorsDefinition.getColors(); lineChartColors = ChartColorsDefinition.getColors();
constructor(private restConnectorService: MonitorService) {} constructor(
private restConnectorService: MonitorService,
private requestInProgressService: RequestInProgressService
) {}
async ngOnInit() { async ngOnInit() {
this.reportData = await this.restConnectorService.getWorkbasketStatisticsQueryingByDueDate().toPromise(); this.requestInProgressService.setRequestInProgress(true);
this.restConnectorService.getWorkbasketStatisticsQueryingByDueDate().subscribe((report) => {
this.reportData = report;
this.metaInformation.emit(this.reportData.meta); this.metaInformation.emit(this.reportData.meta);
this.lineChartLabels = this.reportData.meta.header; this.lineChartLabels = this.reportData.meta.header;
this.lineChartData = this.restConnectorService.getChartData(this.reportData); this.lineChartData = this.restConnectorService.getChartData(this.reportData);
this.requestInProgressService.setRequestInProgress(false);
});
} }
} }

View File

@ -4,6 +4,7 @@ import { ChartData } from '../../models/chart-data';
import { ChartColorsDefinition } from '../../models/chart-colors'; import { ChartColorsDefinition } from '../../models/chart-colors';
import { MonitorService } from '../../services/monitor.service'; import { MonitorService } from '../../services/monitor.service';
import { MetaInfoData } from '../../models/meta-info-data'; import { MetaInfoData } from '../../models/meta-info-data';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-monitor-workbasket-report-planned-date', selector: 'taskana-monitor-workbasket-report-planned-date',
@ -27,12 +28,19 @@ export class WorkbasketReportPlannedDateComponent implements OnInit {
lineChartColors = ChartColorsDefinition.getColors(); lineChartColors = ChartColorsDefinition.getColors();
constructor(private restConnectorService: MonitorService) {} constructor(
private restConnectorService: MonitorService,
private requestInProgressService: RequestInProgressService
) {}
async ngOnInit() { ngOnInit() {
this.reportData = await this.restConnectorService.getWorkbasketStatisticsQueryingByPlannedDate().toPromise(); this.requestInProgressService.setRequestInProgress(true);
this.restConnectorService.getWorkbasketStatisticsQueryingByPlannedDate().subscribe((report) => {
this.reportData = report;
this.metaInformation.emit(this.reportData.meta); this.metaInformation.emit(this.reportData.meta);
this.lineChartLabels = this.reportData.meta.header; this.lineChartLabels = this.reportData.meta.header;
this.lineChartData = this.restConnectorService.getChartData(this.reportData); this.lineChartData = this.restConnectorService.getChartData(this.reportData);
this.requestInProgressService.setRequestInProgress(false);
});
} }
} }

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { MonitorComponent } from './components/monitor/monitor.component'; import { MonitorComponent } from './components/monitor/monitor.component';
import { TaskReportComponent } from './components/task-report/task-report.component'; import { TaskReportComponent } from './components/task-report/task-report.component';
import { WorkbasketReportComponent } from './components/workbasket-report/workbasket-report.component'; import { WorkbasketReportComponent } from './components/workbasket-report/workbasket-report.component';
@ -36,7 +36,7 @@ const routes: Routes = [
}, },
{ {
path: '', path: '',
redirectTo: '', redirectTo: 'tasks-priority',
pathMatch: 'full' pathMatch: 'full'
}, },
{ {

View File

@ -2,10 +2,10 @@
.settings { .settings {
padding: 8px 32px; padding: 8px 32px;
overflow-y: scroll;
&__content { &__content {
height: calc(100vh - 116px); height: calc(100vh - 116px);
overflow-y: scroll;
padding: 4px; padding: 4px;
} }

View File

@ -14,6 +14,7 @@ import { SettingsComponent } from './settings.component';
import { settingsStateMock } from '../../../shared/store/mock-data/mock-store'; import { settingsStateMock } from '../../../shared/store/mock-data/mock-store';
import { SetSettings } from '../../../shared/store/settings-store/settings.actions'; import { SetSettings } from '../../../shared/store/settings-store/settings.actions';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
const notificationServiceSpy: Partial<NotificationService> = { const notificationServiceSpy: Partial<NotificationService> = {
showError: jest.fn(), showError: jest.fn(),
@ -42,7 +43,13 @@ describe('SettingsComponent', () => {
BrowserAnimationsModule BrowserAnimationsModule
], ],
declarations: [SettingsComponent], declarations: [SettingsComponent],
providers: [{ provide: NotificationService, useValue: notificationServiceSpy }] providers: [
RequestInProgressService,
{
provide: NotificationService,
useValue: notificationServiceSpy
}
]
}).compileComponents(); }).compileComponents();
fixture = TestBed.createComponent(SettingsComponent); fixture = TestBed.createComponent(SettingsComponent);

View File

@ -7,6 +7,7 @@ import { SetSettings } from '../../../shared/store/settings-store/settings.actio
import { SettingsSelectors } from '../../../shared/store/settings-store/settings.selectors'; import { SettingsSelectors } from '../../../shared/store/settings-store/settings.selectors';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { validateSettings } from './settings.validators'; import { validateSettings } from './settings.validators';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-administration-settings', selector: 'taskana-administration-settings',
@ -22,10 +23,15 @@ export class SettingsComponent implements OnInit, OnDestroy {
@Select(SettingsSelectors.getSettings) settings$: Observable<Settings>; @Select(SettingsSelectors.getSettings) settings$: Observable<Settings>;
constructor(private store: Store, private notificationService: NotificationService) {} constructor(
private store: Store,
private notificationService: NotificationService,
private requestInProgressService: RequestInProgressService
) {}
ngOnInit() { ngOnInit() {
this.settings$.pipe(takeUntil(this.destroy$)).subscribe((settings) => { this.settings$.pipe(takeUntil(this.destroy$)).subscribe((settings) => {
this.requestInProgressService.setRequestInProgress(false);
this.settings = this.deepCopy(settings); this.settings = this.deepCopy(settings);
this.oldSettings = this.deepCopy(settings); this.oldSettings = this.deepCopy(settings);
}); });

View File

@ -1,40 +1,38 @@
<mat-nav-list class="navlist"> <mat-nav-list class="navlist">
<a (click)="toggleSidenav()" *ngIf="administrationAccess" [routerLinkActive]="['active']" <a (click)="toggleSidenav(administrationsUrl)" *ngIf="administrationAccess" [routerLinkActive]="['active']"
[routerLink]=[administrationsUrl] class="navlist__item navlist__admin" mat-list-item>Administration</a> [routerLink]=[administrationsUrl] class="navlist__item navlist__admin" mat-list-item>Administration</a>
<div class="navlist__admin-item"> <div class="navlist__admin-item">
<a (click)="toggleSidenav()" *ngIf="administrationAccess" [routerLinkActive]="['active__sub']" <a (click)="toggleSidenav(workbasketsUrl)" *ngIf="administrationAccess" [routerLinkActive]="['active__sub']"
[routerLink]=[workbasketsUrl] class="navlist__item navlist__admin-workbaskets" [routerLink]=[workbasketsUrl] class="navlist__item navlist__admin-workbaskets"
mat-list-item>Workbaskets</a> mat-list-item>Workbaskets</a>
<a (click)="toggleSidenav()" *ngIf="administrationAccess" [routerLinkActive]="['active__sub']" <a (click)="toggleSidenav(classificationUrl)" *ngIf="administrationAccess" [routerLinkActive]="['active__sub']"
[routerLink]=[classificationUrl] class="navlist__item navlist__admin-classifications" [routerLink]=[classificationUrl] class="navlist__item navlist__admin-classifications"
mat-list-item>Classifications</a> mat-list-item>Classifications</a>
<a (click)="toggleSidenav()" *ngIf="administrationAccess" [routerLinkActive]="['active__sub']" <a (click)="toggleSidenav(accessUrl)" *ngIf="administrationAccess" [routerLinkActive]="['active__sub']"
[routerLink]=[accessUrl] class="navlist__item navlist__admin-access-items" mat-list-item>Access [routerLink]=[accessUrl] class="navlist__item navlist__admin-access-items" mat-list-item>Access
Items</a> Items</a>
<a (click)="toggleSidenav()" *ngIf="(routingAccess)" [routerLinkActive]="['active__sub']" <a (click)="toggleSidenav(routingUrl)" *ngIf="(routingAccess)" [routerLinkActive]="['active__sub']"
[routerLink]=[routingUrl] class="navlist__item navlist__admin-task-routing" mat-list-item>Task [routerLink]=[routingUrl] class="navlist__item navlist__admin-task-routing" mat-list-item>Task
Routing</a> Routing</a>
</div> </div>
<a (click)="toggleSidenav()" *ngIf="monitorAccess" [routerLinkActive]="['active']" <a (click)="toggleSidenav(monitorUrl)" *ngIf="monitorAccess" [routerLinkActive]="['active']"
[routerLink]=[monitorUrl] [routerLink]=[monitorUrl]
class="navlist__item navlist__monitor" mat-list-item>Monitor</a> class="navlist__item navlist__monitor" mat-list-item>Monitor</a>
<a (click)="toggleSidenav()" *ngIf="workplaceAccess" [routerLinkActive]="['active']" <a (click)="toggleSidenav(workplaceUrl)" *ngIf="workplaceAccess" [routerLinkActive]="['active']"
[routerLink]=[workplaceUrl] class="navlist__item navlist__workplace" [routerLink]=[workplaceUrl] class="navlist__item navlist__workplace"
mat-list-item>Workplace</a> mat-list-item>Workplace</a>
<div class="navlist__admin-item"> <div class="navlist__admin-item">
<a (click)="toggleSidenav()" *ngIf="workplaceAccess" <a (click)="toggleSidenav(workplaceUrl)" *ngIf="workplaceAccess" [queryParams]="{component: 'workbaskets'}" [routerLinkActive]="['active__sub']"
[queryParams]="{component: 'workbaskets'}" [routerLinkActive]="['active__sub']"
[routerLink]=[workplaceUrl] class="navlist__item navlist__workplace--workbaskets" [routerLink]=[workplaceUrl] class="navlist__item navlist__workplace--workbaskets"
mat-list-item>Workbaskets</a> mat-list-item>Workbaskets</a>
<a (click)="toggleSidenav()" *ngIf="workplaceAccess" <a (click)="toggleSidenav(workplaceUrl)" *ngIf="workplaceAccess" [queryParams]="{component: 'task-search'}" [routerLinkActive]="['active__sub']"
[queryParams]="{component: 'task-search'}" [routerLinkActive]="['active__sub']"
[routerLink]=[workplaceUrl] class="navlist__item navlist__workplace--task-search" [routerLink]=[workplaceUrl] class="navlist__item navlist__workplace--task-search"
mat-list-item>Task Search</a> mat-list-item>Task Search</a>
</div> </div>
<a (click)="toggleSidenav()" *ngIf="historyAccess" [routerLinkActive]="['active']" <a (click)="toggleSidenav(historyUrl)" *ngIf="historyAccess" [routerLinkActive]="['active']"
[routerLink]=[historyUrl] [routerLink]=[historyUrl]
class="navlist__item navlist__history" mat-list-item>History</a> class="navlist__item navlist__history" mat-list-item>History</a>
<a (click)="toggleSidenav()" *ngIf="settingsAccess" [routerLinkActive]="['active']" <a (click)="toggleSidenav(settingsURL)" *ngIf="settingsAccess" [routerLinkActive]="['active']"
[routerLink]=[settingsURL] [routerLink]=[settingsURL]
class="navlist__item navlist__setting" mat-list-item>Settings</a> class="navlist__item navlist__setting" mat-list-item>Settings</a>
</mat-nav-list> </mat-nav-list>

View File

@ -16,6 +16,7 @@ import { MatGridListModule } from '@angular/material/grid-list';
import { MatListModule } from '@angular/material/list'; import { MatListModule } from '@angular/material/list';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { EMPTY } from 'rxjs'; import { EMPTY } from 'rxjs';
import { RequestInProgressService } from '../../services/request-in-progress/request-in-progress.service';
const SidenavServiceSpy: Partial<SidenavService> = { const SidenavServiceSpy: Partial<SidenavService> = {
toggleSidenav: jest.fn().mockReturnValue(EMPTY) toggleSidenav: jest.fn().mockReturnValue(EMPTY)
@ -48,6 +49,7 @@ describe('SidenavListComponent', () => {
HttpClientTestingModule HttpClientTestingModule
], ],
providers: [ providers: [
RequestInProgressService,
{ provide: SidenavService, useValue: SidenavServiceSpy }, { provide: SidenavService, useValue: SidenavServiceSpy },
{ provide: TaskanaEngineService, useValue: TaskanaEngineServiceSpy } { provide: TaskanaEngineService, useValue: TaskanaEngineServiceSpy }
] ]

View File

@ -4,6 +4,8 @@ import { MonitorGuard } from 'app/shared/guards/monitor.guard';
import { UserGuard } from 'app/shared/guards/user.guard'; import { UserGuard } from 'app/shared/guards/user.guard';
import { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service'; import { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service';
import { SidenavService } from '../../services/sidenav/sidenav.service'; import { SidenavService } from '../../services/sidenav/sidenav.service';
import { RequestInProgressService } from '../../services/request-in-progress/request-in-progress.service';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'taskana-sidenav-list', selector: 'taskana-sidenav-list',
@ -30,7 +32,12 @@ export class SidenavListComponent implements OnInit {
routingAccess = false; routingAccess = false;
settingsAccess = false; settingsAccess = false;
constructor(private taskanaEngineService: TaskanaEngineService, private sidenavService: SidenavService) {} constructor(
private taskanaEngineService: TaskanaEngineService,
private sidenavService: SidenavService,
private requestInProgressService: RequestInProgressService,
private router: Router
) {}
ngOnInit() { ngOnInit() {
this.administrationAccess = this.taskanaEngineService.hasRole(BusinessAdminGuard.roles); this.administrationAccess = this.taskanaEngineService.hasRole(BusinessAdminGuard.roles);
@ -45,7 +52,8 @@ export class SidenavListComponent implements OnInit {
this.settingsAccess = this.administrationAccess; this.settingsAccess = this.administrationAccess;
} }
toggleSidenav() { toggleSidenav(target: string) {
if (!this.router.url.includes(target)) this.requestInProgressService.setRequestInProgress(true);
this.toggle = !this.toggle; this.toggle = !this.toggle;
this.sidenavService.toggleSidenav(); this.sidenavService.toggleSidenav();
} }

View File

@ -15,6 +15,7 @@ import { Actions, ofActionCompleted, Select, Store } from '@ngxs/store';
import { ClearTaskFilter, SetTaskFilter } from '../../../shared/store/filter-store/filter.actions'; import { ClearTaskFilter, SetTaskFilter } from '../../../shared/store/filter-store/filter.actions';
import { WorkplaceSelectors } from '../../../shared/store/workplace-store/workplace.selectors'; import { WorkplaceSelectors } from '../../../shared/store/workplace-store/workplace.selectors';
import { SetFilterExpansion } from '../../../shared/store/workplace-store/workplace.actions'; import { SetFilterExpansion } from '../../../shared/store/workplace-store/workplace.actions';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
export enum Search { export enum Search {
byWorkbasket = 'workbasket', byWorkbasket = 'workbasket',
@ -62,7 +63,8 @@ export class TaskListToolbarComponent implements OnInit {
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private store: Store, private store: Store,
private ngxsActions$: Actions private ngxsActions$: Actions,
private requestInProgressService: RequestInProgressService
) {} ) {}
ngOnInit() { ngOnInit() {
@ -139,6 +141,7 @@ export class TaskListToolbarComponent implements OnInit {
onTabChange(search) { onTabChange(search) {
const tab = search.path[0].innerText; const tab = search.path[0].innerText;
this.requestInProgressService.setRequestInProgress(true);
if (tab === 'Workbaskets') { if (tab === 'Workbaskets') {
this.router.navigate(['taskana/workplace'], { queryParams: { component: 'workbaskets' } }); this.router.navigate(['taskana/workplace'], { queryParams: { component: 'workbaskets' } });
} }

View File

@ -16,6 +16,7 @@ import { Select, Store } from '@ngxs/store';
import { FilterSelectors } from '../../../shared/store/filter-store/filter.selectors'; import { FilterSelectors } from '../../../shared/store/filter-store/filter.selectors';
import { WorkplaceSelectors } from '../../../shared/store/workplace-store/workplace.selectors'; import { WorkplaceSelectors } from '../../../shared/store/workplace-store/workplace.selectors';
import { CalculateNumberOfCards } from '../../../shared/store/workplace-store/workplace.actions'; import { CalculateNumberOfCards } from '../../../shared/store/workplace-store/workplace.actions';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-task-master', selector: 'taskana-task-master',
@ -52,7 +53,8 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
private workplaceService: WorkplaceService, private workplaceService: WorkplaceService,
private notificationsService: NotificationService, private notificationsService: NotificationService,
private orientationService: OrientationService, private orientationService: OrientationService,
private store: Store private store: Store,
private requestInProgressService: RequestInProgressService
) {} ) {}
ngOnInit() { ngOnInit() {
@ -120,8 +122,14 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
this.getTasks(); this.getTasks();
} }
ngOnDestroy(): void {
this.destroy$.next(null);
this.destroy$.complete();
}
private getTasks(): void { private getTasks(): void {
this.requestInProgress = true; this.requestInProgress = true;
this.requestInProgressService.setRequestInProgress(true);
if (this.selectedSearchType === Search.byTypeAndValue) { if (this.selectedSearchType === Search.byTypeAndValue) {
delete this.currentBasket; delete this.currentBasket;
@ -131,6 +139,7 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
if (this.selectedSearchType === Search.byWorkbasket && !this.currentBasket) { if (this.selectedSearchType === Search.byWorkbasket && !this.currentBasket) {
this.requestInProgress = false; this.requestInProgress = false;
this.requestInProgressService.setRequestInProgress(false);
this.tasks = []; this.tasks = [];
} else { } else {
this.taskService this.taskService
@ -138,6 +147,7 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
.pipe(take(1)) .pipe(take(1))
.subscribe((taskResource) => { .subscribe((taskResource) => {
this.requestInProgress = false; this.requestInProgress = false;
this.requestInProgressService.setRequestInProgress(false);
if (taskResource.tasks && taskResource.tasks.length > 0) { if (taskResource.tasks && taskResource.tasks.length > 0) {
this.tasks = taskResource.tasks; this.tasks = taskResource.tasks;
} else { } else {
@ -150,9 +160,4 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
}); });
} }
} }
ngOnDestroy(): void {
this.destroy$.next(null);
this.destroy$.complete();
}
} }