TSK-1316: Replaced local progress bars by global one

TSK-1316: Replaced local progress bars by global one in workplace
TSK-1316: Rework of progress-bar component


TSK-1316: Renamed progress-bar component


TSK-1316: Changed progress-bar mode
TSK-1316: Updated tests
This commit is contained in:
Sofie Hofmann 2020-11-23 11:56:14 +01:00
parent 4ffeacdfe8
commit 4dd426e060
36 changed files with 241 additions and 241 deletions

View File

@ -60,11 +60,6 @@ describe('AccessItemsManagementComponent', () => {
let store: Store; let store: Store;
let actions$: Observable<any>; let actions$: Observable<any>;
@Component({ selector: 'taskana-shared-spinner', template: '' })
class TaskanaSharedSpinnerStub {
@Input() isRunning: boolean;
}
@Component({ selector: 'taskana-shared-sort', template: '' }) @Component({ selector: 'taskana-shared-sort', template: '' })
class TaskanaSharedSortStub { class TaskanaSharedSortStub {
@Input() sortingFields: Map<string, string>; @Input() sortingFields: Map<string, string>;
@ -95,12 +90,7 @@ describe('AccessItemsManagementComponent', () => {
MatListModule, MatListModule,
MatExpansionModule MatExpansionModule
], ],
declarations: [ declarations: [AccessItemsManagementComponent, TypeAheadComponent, TaskanaSharedSortStub],
AccessItemsManagementComponent,
TypeAheadComponent,
TaskanaSharedSortStub,
TaskanaSharedSpinnerStub
],
providers: [ providers: [
{ provide: FormsValidatorService, useClass: formValidatorServiceSpy }, { provide: FormsValidatorService, useClass: formValidatorServiceSpy },
{ provide: NotificationService, useClass: notificationServiceSpy }, { provide: NotificationService, useClass: notificationServiceSpy },

View File

@ -1,7 +1,6 @@
<div class="classification-details"> <div class="classification-details">
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
<div class="classification-details__wrapper" id="classification-details" *ngIf="classification && !spinnerIsRunning"> <div class="classification-details__wrapper" id="classification-details" *ngIf="classification && !requestInProgress">
<!-- TITLE + ACTION BUTTONS --> <!-- TITLE + ACTION BUTTONS -->
<section class="classification-details__action-toolbar"> <section class="classification-details__action-toolbar">

View File

@ -32,11 +32,6 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning;
}
@Component({ selector: 'taskana-shared-field-error-display', template: '' }) @Component({ selector: 'taskana-shared-field-error-display', template: '' })
class FieldErrorDisplayStub { class FieldErrorDisplayStub {
@Input() displayError; @Input() displayError;
@ -87,7 +82,8 @@ const importExportServiceSpy = jest.fn().mockImplementation(
const requestInProgressServiceSpy = jest.fn().mockImplementation( const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({ (): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of()) setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
}) })
); );
@ -133,14 +129,7 @@ describe('ClassificationDetailsComponent', () => {
MatMenuModule, MatMenuModule,
BrowserAnimationsModule BrowserAnimationsModule
], ],
declarations: [ declarations: [ClassificationDetailsComponent, InputStub, FieldErrorDisplayStub, SvgIconStub, TextareaStub],
ClassificationDetailsComponent,
SpinnerStub,
InputStub,
FieldErrorDisplayStub,
SvgIconStub,
TextareaStub
],
providers: [ providers: [
{ provide: ClassificationsService, useClass: classificationServiceSpy }, { provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy }, { provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
@ -254,7 +243,7 @@ describe('ClassificationDetailsComponent', () => {
/* HTML */ /* HTML */
it('should not show details when spinner is running', () => { it('should not show details when spinner is running', () => {
component.spinnerIsRunning = true; component.requestInProgress = true;
component.classification = {}; component.classification = {};
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeFalsy(); expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeFalsy();
@ -262,7 +251,7 @@ describe('ClassificationDetailsComponent', () => {
}); });
it('should not show details when classification does not exist', () => { it('should not show details when classification does not exist', () => {
component.spinnerIsRunning = false; component.requestInProgress = false;
component.classification = null; component.classification = null;
fixture.detectChanges(); fixture.detectChanges();
expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeFalsy(); expect(debugElement.nativeElement.querySelector('.classification-details__action-toolbar')).toBeFalsy();

View File

@ -20,7 +20,6 @@ import { NotificationService } from '../../../shared/services/notifications/noti
import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../shared/models/customisation'; import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../shared/models/customisation';
import { Classification } from '../../../shared/models/classification'; import { Classification } from '../../../shared/models/classification';
import { customFieldCount } from '../../../shared/models/classification-summary'; import { customFieldCount } from '../../../shared/models/classification-summary';
import { CategoriesResponse } from '../../../shared/services/classification-categories/classification-categories.service';
import { import {
SaveCreatedClassification, SaveCreatedClassification,
@ -40,19 +39,18 @@ import {
}) })
export class ClassificationDetailsComponent implements OnInit, OnDestroy { export class ClassificationDetailsComponent implements OnInit, OnDestroy {
classification: Classification; classification: Classification;
requestInProgress = false;
@Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>; @Select(ClassificationSelectors.selectCategories) categories$: Observable<string[]>;
@Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>; @Select(EngineConfigurationSelectors.selectCategoryIcons) categoryIcons$: Observable<ClassificationCategoryImages>;
@Select(ClassificationSelectors.selectedClassificationType) selectedClassificationType$: Observable<string>; @Select(ClassificationSelectors.selectedClassificationType) selectedClassificationType$: Observable<string>;
@Select(ClassificationSelectors.selectedClassification) selectedClassification$: Observable<Classification>; @Select(ClassificationSelectors.selectedClassification) selectedClassification$: Observable<Classification>;
@Select(ClassificationSelectors.getBadgeMessage) badgeMessage$: Observable<string>; @Select(ClassificationSelectors.getBadgeMessage) badgeMessage$: Observable<string>;
spinnerIsRunning = false;
customFields$: Observable<CustomField[]>; customFields$: Observable<CustomField[]>;
isCreatingNewClassification: boolean = false; isCreatingNewClassification: boolean = false;
readonly lengthError = 'You have reached the maximum length for this field'; readonly lengthError = 'You have reached the maximum length for this field';
inputOverflowMap = new Map<string, boolean>(); inputOverflowMap = new Map<string, boolean>();
validateInputOverflow: Function; validateInputOverflow: Function;
requestInProgress: boolean;
@ViewChild('ClassificationForm') classificationForm: NgForm; @ViewChild('ClassificationForm') classificationForm: NgForm;
toggleValidationMap = new Map<string, boolean>(); toggleValidationMap = new Map<string, boolean>();
@ -86,6 +84,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.store.dispatch(new SelectClassification(this.classification.classificationId)); this.store.dispatch(new SelectClassification(this.classification.classificationId));
}); });
this.requestInProgressService
.getRequestInProgress()
.pipe(takeUntil(this.destroy$))
.subscribe((value) => {
this.requestInProgress = value;
});
this.formsValidatorService.inputOverflowObservable.pipe(takeUntil(this.destroy$)).subscribe((inputOverflowMap) => { this.formsValidatorService.inputOverflowObservable.pipe(takeUntil(this.destroy$)).subscribe((inputOverflowMap) => {
this.inputOverflowMap = inputOverflowMap; this.inputOverflowMap = inputOverflowMap;
}); });
@ -141,10 +146,6 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
); );
} }
spinnerRunning(value) {
this.spinnerIsRunning = value;
}
validChanged(): void { validChanged(): void {
this.classification.isValidInDomain = !this.classification.isValidInDomain; this.classification.isValidInDomain = !this.classification.isValidInDomain;
} }

View File

@ -61,11 +61,9 @@
<!-- CLASSIFICATION TREE --> <!-- CLASSIFICATION TREE -->
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
<taskana-administration-tree *ngIf="(classifications && classifications.length) else empty_classifications" <taskana-administration-tree *ngIf="(classifications && classifications.length) else empty_classifications"
[filterText]="inputValue" [filterIcon]="selectedCategory" [filterText]="inputValue" [filterIcon]="selectedCategory"
(switchTaskanaSpinnerEmit)="requestInProgress=$event"></taskana-administration-tree> (switchTaskanaSpinnerEmit)="setRequestInProgress($event)"></taskana-administration-tree>
<ng-template #empty_classifications> <ng-template #empty_classifications>
<div *ngIf="!requestInProgress" class="classification-list__no-items"> <div *ngIf="!requestInProgress" class="classification-list__no-items">
<h3 class="grey">There are no classifications</h3> <h3 class="grey">There are no classifications</h3>

View File

@ -19,6 +19,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ selector: 'taskana-administration-import-export', template: '' }) @Component({ selector: 'taskana-administration-import-export', template: '' })
class ImportExportStub { class ImportExportStub {
@ -29,11 +30,6 @@ class ImportExportStub {
@Component({ selector: 'taskana-administration-classification-types-selector', template: '' }) @Component({ selector: 'taskana-administration-classification-types-selector', template: '' })
class ClassificationTypesSelectorStub {} class ClassificationTypesSelectorStub {}
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning;
}
@Component({ selector: 'taskana-administration-tree', template: '' }) @Component({ selector: 'taskana-administration-tree', template: '' })
class TreeStub { class TreeStub {
@Input() filterText; @Input() filterText;
@ -75,6 +71,13 @@ const importExportServiceSpy = jest.fn().mockImplementation(
}) })
); );
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
})
);
describe('ClassificationListComponent', () => { describe('ClassificationListComponent', () => {
let fixture: ComponentFixture<ClassificationListComponent>; let fixture: ComponentFixture<ClassificationListComponent>;
let debugElement: DebugElement; let debugElement: DebugElement;
@ -96,7 +99,6 @@ describe('ClassificationListComponent', () => {
declarations: [ declarations: [
ClassificationListComponent, ClassificationListComponent,
ClassificationTypesSelectorStub, ClassificationTypesSelectorStub,
SpinnerStub,
TreeStub, TreeStub,
SvgIconStub, SvgIconStub,
ImportExportStub, ImportExportStub,
@ -106,7 +108,8 @@ describe('ClassificationListComponent', () => {
{ provide: ClassificationsService, useClass: classificationServiceSpy }, { provide: ClassificationsService, useClass: classificationServiceSpy },
{ provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy }, { provide: ClassificationCategoriesService, useClass: classificationCategoriesServiceSpy },
{ provide: DomainService, useClass: domainServiceSpy }, { provide: DomainService, useClass: domainServiceSpy },
{ provide: ImportExportService, useClass: importExportServiceSpy } { provide: ImportExportService, useClass: importExportServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy }
] ]
}).compileComponents(); }).compileComponents();

View File

@ -18,6 +18,7 @@ import {
} from '../../../shared/store/classification-store/classification.actions'; } from '../../../shared/store/classification-store/classification.actions';
import { DomainService } from '../../../shared/services/domain/domain.service'; import { DomainService } from '../../../shared/services/domain/domain.service';
import { ClassificationSummary } from '../../../shared/models/classification-summary'; import { ClassificationSummary } from '../../../shared/models/classification-summary';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-administration-classification-list', selector: 'taskana-administration-classification-list',
@ -43,15 +44,16 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
constructor( constructor(
private location: Location, private location: Location,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private domainService: DomainService,
private requestInProgressService: RequestInProgressService,
private store: Store, private store: Store,
private ngxsActions$: Actions, private ngxsActions$: Actions
private domainService: DomainService
) { ) {
this.ngxsActions$.pipe(ofActionDispatched(GetClassifications), takeUntil(this.destroy$)).subscribe(() => { this.ngxsActions$.pipe(ofActionDispatched(GetClassifications), takeUntil(this.destroy$)).subscribe(() => {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
}); });
this.ngxsActions$.pipe(ofActionCompleted(GetClassifications), takeUntil(this.destroy$)).subscribe(() => { this.ngxsActions$.pipe(ofActionCompleted(GetClassifications), takeUntil(this.destroy$)).subscribe(() => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
}); });
} }
@ -79,6 +81,13 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
.subscribe((domain) => { .subscribe((domain) => {
this.store.dispatch(GetClassifications); this.store.dispatch(GetClassifications);
}); });
this.requestInProgressService
.getRequestInProgress()
.pipe(takeUntil(this.destroy$))
.subscribe((value) => {
this.requestInProgress = value;
});
} }
addClassification() { addClassification() {
@ -107,6 +116,10 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
this.showFilter = !this.showFilter; this.showFilter = !this.showFilter;
} }
setRequestInProgress(value: boolean) {
this.requestInProgressService.setRequestInProgress(value);
}
ngOnDestroy() { ngOnDestroy() {
this.destroy$.next(); this.destroy$.next();
this.destroy$.complete(); this.destroy$.complete();

View File

@ -1,4 +1,3 @@
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
<div *ngIf="workbasket" id="wb-information"> <div *ngIf="workbasket" id="wb-information">
<!-- ACCESS ITEMS --> <!-- ACCESS ITEMS -->

View File

@ -1,6 +1,6 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { WorkbasketAccessItemsComponent } from './workbasket-access-items.component'; import { WorkbasketAccessItemsComponent } from './workbasket-access-items.component';
import { Component, DebugElement, Input } from '@angular/core'; import { DebugElement } from '@angular/core';
import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store'; import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@ -32,19 +32,12 @@ import {
} from '../../../shared/store/workbasket-store/workbasket.actions'; } from '../../../shared/store/workbasket-store/workbasket.actions';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ACTION } from '../../../shared/models/action'; import { ACTION } from '../../../shared/models/action';
import { WorkbasketAccessItems } from '../../../shared/models/workbasket-access-items';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning: boolean;
@Input() positionClass: string;
}
const savingWorkbasketServiceSpy = jest.fn().mockImplementation( const savingWorkbasketServiceSpy = jest.fn().mockImplementation(
(): Partial<SavingWorkbasketService> => ({ (): Partial<SavingWorkbasketService> => ({
triggeredAccessItemsSaving: jest.fn().mockReturnValue(of(true)) triggeredAccessItemsSaving: jest.fn().mockReturnValue(of(true))
@ -100,7 +93,7 @@ describe('WorkbasketAccessItemsComponent', () => {
MatAutocompleteModule, MatAutocompleteModule,
MatProgressBarModule MatProgressBarModule
], ],
declarations: [WorkbasketAccessItemsComponent, TypeAheadComponent, SpinnerStub], declarations: [WorkbasketAccessItemsComponent, TypeAheadComponent],
providers: [ providers: [
{ provide: SavingWorkbasketService, useClass: savingWorkbasketServiceSpy }, { provide: SavingWorkbasketService, useClass: savingWorkbasketServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy }, { provide: RequestInProgressService, useClass: requestInProgressServiceSpy },

View File

@ -61,7 +61,6 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
accessItemsRepresentation: WorkbasketAccessItemsRepresentation; accessItemsRepresentation: WorkbasketAccessItemsRepresentation;
accessItemsClone: Array<WorkbasketAccessItems>; accessItemsClone: Array<WorkbasketAccessItems>;
accessItemsResetClone: Array<WorkbasketAccessItems>; accessItemsResetClone: Array<WorkbasketAccessItems>;
requestInProgress = false;
AccessItemsForm = this.formBuilder.group({ AccessItemsForm = this.formBuilder.group({
accessItemsGroups: this.formBuilder.array([]) accessItemsGroups: this.formBuilder.array([])
}); });
@ -148,9 +147,9 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
if (!this.workbasket._links.accessItems) { if (!this.workbasket._links.accessItems) {
return; return;
} }
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.store.dispatch(new GetWorkbasketAccessItems(this.workbasket._links.accessItems.href)).subscribe(() => { this.store.dispatch(new GetWorkbasketAccessItems(this.workbasket._links.accessItems.href)).subscribe(() => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
}); });
this.savingWorkbaskets this.savingWorkbaskets

View File

@ -48,6 +48,5 @@
<taskana-administration-workbasket-distribution-targets [workbasket]="workbasket" [action]="action"></taskana-administration-workbasket-distribution-targets> <taskana-administration-workbasket-distribution-targets [workbasket]="workbasket" [action]="action"></taskana-administration-workbasket-distribution-targets>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
</div> </div>

View File

@ -28,11 +28,6 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CreateWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions'; import { CreateWorkbasket } from '../../../shared/store/workbasket-store/workbasket.actions';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning: boolean;
}
@Component({ selector: 'taskana-administration-workbasket-information', template: '<div>i</div>' }) @Component({ selector: 'taskana-administration-workbasket-information', template: '<div>i</div>' })
class WorkbasketInformationStub { class WorkbasketInformationStub {
@Input() workbasket: Workbasket; @Input() workbasket: Workbasket;
@ -91,7 +86,6 @@ describe('WorkbasketDetailsComponent', () => {
], ],
declarations: [ declarations: [
WorkbasketDetailsComponent, WorkbasketDetailsComponent,
SpinnerStub,
WorkbasketAccessItemsStub, WorkbasketAccessItemsStub,
WorkbasketDistributionTargetsStub, WorkbasketDistributionTargetsStub,
WorkbasketInformationStub WorkbasketInformationStub
@ -126,7 +120,6 @@ describe('WorkbasketDetailsComponent', () => {
it('should render information component when workbasket details is opened', () => { it('should render information component when workbasket details is opened', () => {
component.workbasket = { workbasketId: '1' }; component.workbasket = { workbasketId: '1' };
component.requestInProgress = false;
fixture.detectChanges(); fixture.detectChanges();
const information = debugElement.nativeElement.querySelector('taskana-administration-workbasket-information'); const information = debugElement.nativeElement.querySelector('taskana-administration-workbasket-information');
expect(information).toBeTruthy(); expect(information).toBeTruthy();

View File

@ -17,6 +17,7 @@ import {
SelectComponent SelectComponent
} from '../../../shared/store/workbasket-store/workbasket.actions'; } from '../../../shared/store/workbasket-store/workbasket.actions';
import { ButtonAction } from '../../models/button-action'; import { ButtonAction } from '../../models/button-action';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
import { WorkbasketComponent } from '../../models/workbasket-component'; import { WorkbasketComponent } from '../../models/workbasket-component';
@Component({ @Component({
@ -28,7 +29,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges
workbasket: Workbasket; workbasket: Workbasket;
workbasketCopy: Workbasket; workbasketCopy: Workbasket;
selectedId: string; selectedId: string;
requestInProgress = false;
action: ACTION; action: ACTION;
badgeMessage = ''; badgeMessage = '';
@ -52,6 +52,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges
private router: Router, private router: Router,
private domainService: DomainService, private domainService: DomainService,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private requestInProgressService: RequestInProgressService,
private store: Store private store: Store
) {} ) {}
@ -108,7 +109,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges
if (selectedWorkbasket) { if (selectedWorkbasket) {
workbasketIdSelected = selectedWorkbasket.workbasketId; workbasketIdSelected = selectedWorkbasket.workbasketId;
} }
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
if (!workbasketIdSelected && this.action === ACTION.CREATE) { if (!workbasketIdSelected && this.action === ACTION.CREATE) {
// CREATE // CREATE
this.workbasket = {}; this.workbasket = {};
@ -118,16 +119,16 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy, OnChanges
.subscribe((domain) => { .subscribe((domain) => {
this.workbasket.domain = domain; this.workbasket.domain = domain;
}); });
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
} else if (!workbasketIdSelected && this.action === ACTION.COPY) { } else if (!workbasketIdSelected && this.action === ACTION.COPY) {
// COPY // COPY
this.workbasket = { ...this.workbasketCopy }; this.workbasket = { ...this.workbasketCopy };
delete this.workbasket.workbasketId; delete this.workbasket.workbasketId;
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
} }
if (workbasketIdSelected) { if (workbasketIdSelected) {
this.workbasket = selectedWorkbasket; this.workbasket = selectedWorkbasket;
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.checkDomainAndRedirect(); this.checkDomainAndRedirect();
} }
} }

View File

@ -1,4 +1,3 @@
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
<div *ngIf="workbasket" id="wb-information"> <div *ngIf="workbasket" id="wb-information">
<!-- <!--
<div class="panel-heading"> <div class="panel-heading">

View File

@ -41,11 +41,6 @@ import { MatSelectModule } from '@angular/material/select';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning: boolean;
}
@Component({ selector: 'taskana-shared-field-error-display', template: '' }) @Component({ selector: 'taskana-shared-field-error-display', template: '' })
class FieldErrorDisplayStub { class FieldErrorDisplayStub {
@Input() displayError: boolean; @Input() displayError: boolean;
@ -120,7 +115,6 @@ describe('WorkbasketInformationComponent', () => {
], ],
declarations: [ declarations: [
WorkbasketInformationComponent, WorkbasketInformationComponent,
SpinnerStub,
FieldErrorDisplayStub, FieldErrorDisplayStub,
IconTypeStub, IconTypeStub,
TypeAheadComponent, TypeAheadComponent,

View File

@ -43,7 +43,6 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
workbasketClone: Workbasket; workbasketClone: Workbasket;
allTypes: Map<string, string>; allTypes: Map<string, string>;
requestInProgress = false;
badgeMessage = ''; badgeMessage = '';
toggleValidationMap = new Map<string, boolean>(); toggleValidationMap = new Map<string, boolean>();
lookupField = false; lookupField = false;

View File

@ -4,7 +4,6 @@
<taskana-administration-workbasket-list-toolbar [workbaskets]="workbasketsSummary$ | async" (performFilter)="performFilter($event)" <taskana-administration-workbasket-list-toolbar [workbaskets]="workbasketsSummary$ | async" (performFilter)="performFilter($event)"
(performSorting)="performSorting($event)" [workbasketDefaultSortBy]="workbasketDefaultSortBy"> (performSorting)="performSorting($event)" [workbasketDefaultSortBy]="workbasketDefaultSortBy">
</taskana-administration-workbasket-list-toolbar> </taskana-administration-workbasket-list-toolbar>
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
</section> </section>
<!-- WORKBASKET LIST --> <!-- WORKBASKET LIST -->
@ -43,7 +42,7 @@
<!-- SPINNER and EMPTY WORKBASKET LIST --> <!-- SPINNER and EMPTY WORKBASKET LIST -->
<ng-template #empty_workbaskets> <ng-template #empty_workbaskets>
<div *ngIf="!requestInProgress" class="workbasket-list__no-items"> <div *ngIf="!requestInProgress && !requestInProgressLocal" class="workbasket-list__no-items">
<h3 class="grey">There are no workbaskets</h3> <h3 class="grey">There are no workbaskets</h3>
</div> </div>
</ng-template> </ng-template>

View File

@ -17,12 +17,12 @@ import { Filter } from '../../../shared/models/filter';
import { ICONTYPES } from '../../../shared/models/icon-types'; import { ICONTYPES } from '../../../shared/models/icon-types';
import { Page } from '../../../shared/models/page'; import { Page } from '../../../shared/models/page';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { MatListModule, MatSelectionList } from '@angular/material/list'; import { MatListModule } from '@angular/material/list';
import { DomainService } from '../../../shared/services/domain/domain.service'; import { DomainService } from '../../../shared/services/domain/domain.service';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
const workbasketSavedTriggeredFn = jest.fn().mockReturnValue(of(1)); const workbasketSavedTriggeredFn = jest.fn().mockReturnValue(of(1));
const workbasketSummaryFn = jest.fn().mockReturnValue(of({})); const workbasketSummaryFn = jest.fn().mockReturnValue(of({}));
@ -59,6 +59,13 @@ const domainServiceSpy = jest.fn().mockImplementation(
}) })
); );
const requestInProgressServiceSpy = jest.fn().mockImplementation(
(): Partial<RequestInProgressService> => ({
setRequestInProgress: jest.fn().mockReturnValue(of()),
getRequestInProgress: jest.fn().mockReturnValue(of(false))
})
);
@Component({ selector: 'taskana-administration-workbasket-list-toolbar', template: '' }) @Component({ selector: 'taskana-administration-workbasket-list-toolbar', template: '' })
class WorkbasketListToolbarStub { class WorkbasketListToolbarStub {
@Input() workbaskets: Array<WorkbasketSummary>; @Input() workbaskets: Array<WorkbasketSummary>;
@ -73,11 +80,6 @@ class IconTypeStub {
@Input() selected = false; @Input() selected = false;
} }
@Component({ selector: 'taskana-shared-spinner', template: '' })
class SpinnerStub {
@Input() isRunning: boolean;
}
@Component({ selector: 'taskana-shared-pagination', template: '' }) @Component({ selector: 'taskana-shared-pagination', template: '' })
class PaginationStub { class PaginationStub {
@Input() page: Page; @Input() page: Page;
@ -108,19 +110,13 @@ describe('WorkbasketListComponent', () => {
MatSelectModule, MatSelectModule,
MatListModule MatListModule
], ],
declarations: [ declarations: [WorkbasketListComponent, WorkbasketListToolbarStub, IconTypeStub, PaginationStub, SvgIconStub],
WorkbasketListComponent,
WorkbasketListToolbarStub,
IconTypeStub,
SpinnerStub,
PaginationStub,
SvgIconStub
],
providers: [ providers: [
{ provide: WorkbasketService, useClass: workbasketServiceMock }, { provide: WorkbasketService, useClass: workbasketServiceMock },
{ provide: OrientationService, useClass: orientationServiceMock }, { provide: OrientationService, useClass: orientationServiceMock },
{ provide: ImportExportService, useClass: importExportServiceMock }, { provide: ImportExportService, useClass: importExportServiceMock },
{ provide: DomainService, useClass: domainServiceSpy } { provide: DomainService, useClass: domainServiceSpy },
{ provide: RequestInProgressService, useClass: requestInProgressServiceSpy }
] ]
}).compileComponents(); }).compileComponents();

View File

@ -22,6 +22,7 @@ import { WorkbasketSelectors } from '../../../shared/store/workbasket-store/work
import { Workbasket } from '../../../shared/models/workbasket'; import { Workbasket } from '../../../shared/models/workbasket';
import { MatSelectionList } from '@angular/material/list'; import { MatSelectionList } from '@angular/material/list';
import { DomainService } from '../../../shared/services/domain/domain.service'; import { DomainService } from '../../../shared/services/domain/domain.service';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-administration-workbasket-list', selector: 'taskana-administration-workbasket-list',
@ -30,7 +31,6 @@ import { DomainService } from '../../../shared/services/domain/domain.service';
}) })
export class WorkbasketListComponent implements OnInit, OnDestroy { export class WorkbasketListComponent implements OnInit, OnDestroy {
selectedId = ''; selectedId = '';
requestInProgress = false;
pageSelected = 1; pageSelected = 1;
pageSize = 9; pageSize = 9;
type = 'workbaskets'; type = 'workbaskets';
@ -38,6 +38,8 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
workbasketDefaultSortBy: string = 'name'; workbasketDefaultSortBy: string = 'name';
sort: Sorting = new Sorting(this.workbasketDefaultSortBy); sort: Sorting = new Sorting(this.workbasketDefaultSortBy);
filterBy: Filter = new Filter({ name: '', owner: '', type: '', description: '', key: '' }); filterBy: Filter = new Filter({ name: '', owner: '', type: '', description: '', key: '' });
requestInProgress: boolean;
requestInProgressLocal = false;
@ViewChild('wbToolbar', { static: true }) @ViewChild('wbToolbar', { static: true })
private toolbarElement: ElementRef; private toolbarElement: ElementRef;
@ -61,18 +63,21 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
private orientationService: OrientationService, private orientationService: OrientationService,
private importExportService: ImportExportService, private importExportService: ImportExportService,
private domainService: DomainService, private domainService: DomainService,
private requestInProgressService: RequestInProgressService,
private ngxsActions$: Actions private ngxsActions$: Actions
) { ) {
this.ngxsActions$.pipe(ofActionDispatched(GetWorkbasketsSummary), takeUntil(this.destroy$)).subscribe(() => { this.ngxsActions$.pipe(ofActionDispatched(GetWorkbasketsSummary), takeUntil(this.destroy$)).subscribe(() => {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.requestInProgressLocal = true;
}); });
this.ngxsActions$.pipe(ofActionCompleted(GetWorkbasketsSummary), takeUntil(this.destroy$)).subscribe(() => { this.ngxsActions$.pipe(ofActionCompleted(GetWorkbasketsSummary), takeUntil(this.destroy$)).subscribe(() => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.requestInProgressLocal = false;
}); });
} }
ngOnInit() { ngOnInit() {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.selectedWorkbasket$.pipe(takeUntil(this.destroy$)).subscribe((selectedWorkbasket) => { this.selectedWorkbasket$.pipe(takeUntil(this.destroy$)).subscribe((selectedWorkbasket) => {
if (typeof selectedWorkbasket !== 'undefined') { if (typeof selectedWorkbasket !== 'undefined') {
@ -117,11 +122,18 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
.getWorkbasketActionToolbarExpansion() .getWorkbasketActionToolbarExpansion()
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe((value) => { .subscribe((value) => {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
setTimeout(() => { setTimeout(() => {
this.refreshWorkbasketList(); this.refreshWorkbasketList();
}, 1); }, 1);
}); });
this.requestInProgressService
.getRequestInProgress()
.pipe(takeUntil(this.destroy$))
.subscribe((value) => {
this.requestInProgress = value;
});
} }
selectWorkbasket(id: string) { selectWorkbasket(id: string) {
@ -176,7 +188,7 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
) )
) )
.subscribe(() => { .subscribe(() => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
}); });
TaskanaQueryParameters.pageSize = this.cards; TaskanaQueryParameters.pageSize = this.cards;
} }

View File

@ -21,12 +21,15 @@
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content> <mat-sidenav-content>
<taskana-shared-nav-bar></taskana-shared-nav-bar> <taskana-shared-nav-bar></taskana-shared-nav-bar>
<mat-progress-bar mode="query" *ngIf="requestInProgress"></mat-progress-bar>
<div (window:resize)="onResize()"> <div (window:resize)="onResize()">
<div class="taskana-main"> <div class="taskana-main">
<div class="taskana-main__progress-bar">
<mat-progress-bar [hidden]="!requestInProgress" mode="indeterminate"></mat-progress-bar>
</div>
<router-outlet></router-outlet> <router-outlet></router-outlet>
<taskana-shared-progress-bar [hidden]="currentProgressValue === 0" currentValue={{currentProgressValue}}> <taskana-shared-progress-spinner
</taskana-shared-progress-bar> [hidden]="currentProgressValue === 0" currentValue={{currentProgressValue}}>
</taskana-shared-progress-spinner>
</div> </div>
</div> </div>
</mat-sidenav-content> </mat-sidenav-content>

View File

@ -1,4 +1,5 @@
@import '../theme/variables'; @import '../theme/variables';
@import 'src/theme/_colors.scss';
.sidenav { .sidenav {
position: absolute; position: absolute;
@ -6,7 +7,7 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
margin-top: 0px; margin-top: 0;
} }
.sidenav__drawer { .sidenav__drawer {
@ -56,9 +57,11 @@
outline: none; outline: none;
} }
mat-sidenav-content { .taskana-main__progress-bar {
height: unset; height: 4px;
background-color: $light-grey;
} }
::ng-deep .mat-drawer-inner-container { ::ng-deep .mat-drawer-inner-container {
overflow: visible !important; overflow: visible !important;
} }

View File

@ -1,6 +1,6 @@
import { Component, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Component, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NavigationStart, Router } from '@angular/router'; import { NavigationStart, Router } from '@angular/router';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service'; import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { SidenavService } from './shared/services/sidenav/sidenav.service'; import { SidenavService } from './shared/services/sidenav/sidenav.service';
import { RequestInProgressService } from './shared/services/request-in-progress/request-in-progress.service'; import { RequestInProgressService } from './shared/services/request-in-progress/request-in-progress.service';
@ -12,6 +12,7 @@ import { TaskanaEngineService } from './shared/services/taskana-engine/taskana-e
import { WindowRefService } from 'app/shared/services/window/window.service'; import { WindowRefService } from 'app/shared/services/window/window.service';
import { environment } from 'environments/environment'; import { environment } from 'environments/environment';
import { MatSidenav } from '@angular/material/sidenav'; import { MatSidenav } from '@angular/material/sidenav';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'taskana-root', selector: 'taskana-root',
@ -25,14 +26,12 @@ export class AppComponent implements OnInit, OnDestroy {
requestInProgress = false; requestInProgress = false;
currentProgressValue = 0; currentProgressValue = 0;
requestInProgressSubscription: Subscription;
selectedRouteSubscription: Subscription;
routerSubscription: Subscription;
uploadingFileSubscription: Subscription;
error: ErrorModel; error: ErrorModel;
version: string; version: string;
toggle: boolean = false; toggle: boolean = false;
destroy$ = new Subject<void>();
constructor( constructor(
private router: Router, private router: Router,
private requestInProgressService: RequestInProgressService, private requestInProgressService: RequestInProgressService,
@ -53,31 +52,41 @@ export class AppComponent implements OnInit, OnDestroy {
@ViewChild('sidenav') public sidenav: MatSidenav; @ViewChild('sidenav') public sidenav: MatSidenav;
ngOnInit() { ngOnInit() {
this.routerSubscription = this.router.events.subscribe((event) => { this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event) => {
if (event instanceof NavigationStart) { if (event instanceof NavigationStart) {
this.selectedRouteService.selectRoute(event); this.selectedRouteService.selectRoute(event);
this.formsValidatorService.formSubmitAttempt = false; this.formsValidatorService.formSubmitAttempt = false;
} }
}); });
this.requestInProgressSubscription = this.requestInProgressService this.requestInProgressService
.getRequestInProgress() .getRequestInProgress()
.pipe(takeUntil(this.destroy$))
.subscribe((value: boolean) => { .subscribe((value: boolean) => {
this.requestInProgress = value; this.requestInProgress = value;
}); });
this.selectedRouteSubscription = this.selectedRouteService.getSelectedRoute().subscribe((value: string) => { this.selectedRouteService
.getSelectedRoute()
.pipe(takeUntil(this.destroy$))
.subscribe((value: string) => {
if (value.indexOf('classifications') !== -1) { if (value.indexOf('classifications') !== -1) {
this.workbasketsRoute = false; this.workbasketsRoute = false;
} }
this.selectedRoute = value; this.selectedRoute = value;
}); });
this.uploadingFileSubscription = this.uploadService.getCurrentProgressObservable().subscribe((value) => { this.uploadService
.getCurrentProgressObservable()
.pipe(takeUntil(this.destroy$))
.subscribe((value) => {
this.currentProgressValue = value; this.currentProgressValue = value;
}); });
this.taskanaEngineService.getVersion().subscribe((restVersion) => { this.taskanaEngineService
.getVersion()
.pipe(takeUntil(this.destroy$))
.subscribe((restVersion) => {
this.version = restVersion.version; this.version = restVersion.version;
}); });
} }
@ -97,17 +106,7 @@ export class AppComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.routerSubscription) { this.destroy$.next();
this.routerSubscription.unsubscribe(); this.destroy$.complete();
}
if (this.requestInProgressSubscription) {
this.requestInProgressSubscription.unsubscribe();
}
if (this.selectedRouteSubscription) {
this.selectedRouteSubscription.unsubscribe();
}
if (this.uploadingFileSubscription) {
this.uploadingFileSubscription.unsubscribe();
}
} }
} }

View File

@ -60,6 +60,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar'; import { MatToolbarModule } from '@angular/material/toolbar';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
const MODULES = [ const MODULES = [
TabsModule.forRoot(), TabsModule.forRoot(),
@ -92,7 +93,7 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
@NgModule({ @NgModule({
declarations: DECLARATIONS, declarations: DECLARATIONS,
imports: [MODULES, MatSidenavModule, MatIconModule, MatToolbarModule, MatProgressBarModule], imports: [MODULES, MatSidenavModule, MatIconModule, MatToolbarModule, MatProgressBarModule, MatProgressSpinnerModule],
providers: [ providers: [
WindowRefService, WindowRefService,
DomainService, DomainService,

View File

@ -1,7 +0,0 @@
<div class="upload-file-container col-xs-12 col-md-4">
<div class="item progress-{{currentValue}}">
<div class="radial-inner-bg"><h1 class="blue"> {{currentValue}}%</h1></div>
</div>
<h4 class="blue">Uploading file</h4>
</div>
<div *ngIf="currentValue" class="mask"></div>

View File

@ -1,11 +0,0 @@
.upload-file-container {
z-index: 3000;
width: 170px;
position: absolute;
left: 50%;
top: 33%;
margin-left: -85px;
> .item {
margin-left: 10px;
}
}

View File

@ -1,24 +0,0 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProgressBarComponent } from './progress-bar.component';
describe('ProgressBarComponent', () => {
let component: ProgressBarComponent;
let fixture: ComponentFixture<ProgressBarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProgressBarComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProgressBarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,29 +0,0 @@
import { Component, OnInit, Input, SimpleChanges, OnChanges } from '@angular/core';
@Component({
selector: 'taskana-shared-progress-bar',
templateUrl: './progress-bar.component.html',
styleUrls: ['./progress-bar.component.scss']
})
export class ProgressBarComponent implements OnInit, OnChanges {
@Input()
currentValue = 0;
@Input()
min = 0;
@Input()
max = 100;
inProgress = false;
ngOnInit() {}
ngOnChanges(changes: SimpleChanges) {
if (!this.inProgress && changes.currentValue.currentValue > this.min) {
this.inProgress = true;
}
if (this.inProgress && changes.currentValue.currentValue >= this.max) {
this.inProgress = false;
}
}
}

View File

@ -0,0 +1,7 @@
<div class="progress-spinner-component">
<div class="progress-spinner-component__spinner-wrapper">
<mat-progress-spinner [value]="currentValue"></mat-progress-spinner>
</div>
<h4 class="progress-spinner-component__text">Uploading file</h4>
</div>
<div *ngIf="currentValue" class="mask"></div>

View File

@ -0,0 +1,30 @@
@import 'src/theme/_colors.scss';
.progress-spinner-component {
z-index: 3000;
width: 170px;
height: 160px;
position: absolute;
left: 50%;
top: 33%;
margin-left: -85px;
> .item {
margin-left: 10px;
}
display: flex;
flex-direction: column;
justify-content: space-between;
}
.progress-spinner-component__spinner-wrapper {
display: flex;
justify-content: center;
}
.progress-spinner-component__text {
color: $aquamarine;
text-align: center;
}
//TODO: Change color of spinner

View File

@ -0,0 +1,26 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProgressSpinnerComponent } from './progress-spinner.component';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
describe('ProgressSpinnerComponent', () => {
let component: ProgressSpinnerComponent;
let fixture: ComponentFixture<ProgressSpinnerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProgressSpinnerComponent],
imports: [MatProgressSpinnerModule]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProgressSpinnerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create component', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,11 @@
import { Component, Input } from '@angular/core';
@Component({
selector: 'taskana-shared-progress-spinner',
templateUrl: './progress-spinner.component.html',
styleUrls: ['./progress-spinner.component.scss']
})
export class ProgressSpinnerComponent {
@Input()
currentValue = 0;
}

View File

@ -29,7 +29,7 @@ import { MatRadioModule } from '@angular/material/radio';
import { SortComponent } from './components/sort/sort.component'; import { SortComponent } from './components/sort/sort.component';
import { PaginationComponent } from './components/pagination/pagination.component'; import { PaginationComponent } from './components/pagination/pagination.component';
import { NumberPickerComponent } from './components/number-picker/number-picker.component'; import { NumberPickerComponent } from './components/number-picker/number-picker.component';
import { ProgressBarComponent } from './components/progress-bar/progress-bar.component'; import { ProgressSpinnerComponent } from './components/progress-spinner/progress-spinner.component';
import { DatePickerComponent } from './components/date-picker/date-picker.component'; import { DatePickerComponent } from './components/date-picker/date-picker.component';
import { DropdownComponent } from './components/dropdown/dropdown.component'; import { DropdownComponent } from './components/dropdown/dropdown.component';
@ -60,6 +60,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
const MODULES = [ const MODULES = [
CommonModule, CommonModule,
@ -97,7 +98,7 @@ const DECLARATIONS = [
FieldErrorDisplayComponent, FieldErrorDisplayComponent,
PaginationComponent, PaginationComponent,
NumberPickerComponent, NumberPickerComponent,
ProgressBarComponent, ProgressSpinnerComponent,
DatePickerComponent, DatePickerComponent,
DropdownComponent, DropdownComponent,
ToastComponent, ToastComponent,
@ -116,7 +117,8 @@ const DECLARATIONS = [
MatTooltipModule, MatTooltipModule,
MatPaginatorModule, MatPaginatorModule,
MatSelectModule, MatSelectModule,
ReactiveFormsModule ReactiveFormsModule,
MatProgressSpinnerModule
], ],
exports: DECLARATIONS, exports: DECLARATIONS,
providers: [ providers: [

View File

@ -1,4 +1,3 @@
<taskana-shared-spinner [isRunning]="requestInProgress"></taskana-shared-spinner>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="pull-right"> <div class="pull-right">

View File

@ -8,6 +8,7 @@ import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.ser
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service'; import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@Component({ @Component({
selector: 'taskana-task', selector: 'taskana-task',
@ -16,7 +17,6 @@ import { take } from 'rxjs/operators';
}) })
export class TaskComponent implements OnInit, OnDestroy { export class TaskComponent implements OnInit, OnDestroy {
routeSubscription: Subscription; routeSubscription: Subscription;
requestInProgress = false;
regex = /\${(.*?)}/g; regex = /\${(.*?)}/g;
address = 'https://bing.com/'; address = 'https://bing.com/';
@ -29,6 +29,7 @@ export class TaskComponent implements OnInit, OnDestroy {
private taskService: TaskService, private taskService: TaskService,
private workbasketService: WorkbasketService, private workbasketService: WorkbasketService,
private classificationService: ClassificationsService, private classificationService: ClassificationsService,
private requestInProgressService: RequestInProgressService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private sanitizer: DomSanitizer private sanitizer: DomSanitizer
@ -39,20 +40,20 @@ export class TaskComponent implements OnInit, OnDestroy {
const { id } = params; const { id } = params;
this.getTask(id); this.getTask(id);
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.taskService this.taskService
.claimTask(id) .claimTask(id)
.pipe(take(1)) .pipe(take(1))
.subscribe((task) => { .subscribe((task) => {
this.task = task; this.task = task;
this.taskService.publishUpdatedTask(task); this.taskService.publishUpdatedTask(task);
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
}); });
}); });
} }
async getTask(id: string) { async getTask(id: string) {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.task = await this.taskService.getTask(id).toPromise(); this.task = await this.taskService.getTask(id).toPromise();
this.taskService.selectTask(this.task); this.taskService.selectTask(this.task);
const classification = await this.classificationService const classification = await this.classificationService
@ -61,13 +62,13 @@ export class TaskComponent implements OnInit, OnDestroy {
this.address = this.extractUrl(classification.applicationEntryPoint) || `${this.address}/?q=${this.task.name}`; this.address = this.extractUrl(classification.applicationEntryPoint) || `${this.address}/?q=${this.task.name}`;
this.link = this.sanitizer.bypassSecurityTrustResourceUrl(this.address); this.link = this.sanitizer.bypassSecurityTrustResourceUrl(this.address);
this.getWorkbaskets(); this.getWorkbaskets();
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
} }
getWorkbaskets() { getWorkbaskets() {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.workbasketService.getAllWorkBaskets().subscribe((workbaskets) => { this.workbasketService.getAllWorkBaskets().subscribe((workbaskets) => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.workbaskets = workbaskets.workbaskets; this.workbaskets = workbaskets.workbaskets;
const index = this.workbaskets.findIndex((workbasket) => workbasket.name === this.task.workbasketSummary.name); const index = this.workbaskets.findIndex((workbasket) => workbasket.name === this.task.workbasketSummary.name);
@ -78,18 +79,18 @@ export class TaskComponent implements OnInit, OnDestroy {
} }
transferTask(workbasket: Workbasket) { transferTask(workbasket: Workbasket) {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.taskService.transferTask(this.task.taskId, workbasket.workbasketId).subscribe((task) => { this.taskService.transferTask(this.task.taskId, workbasket.workbasketId).subscribe((task) => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.task = task; this.task = task;
}); });
this.navigateBack(); this.navigateBack();
} }
completeTask() { completeTask() {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.taskService.completeTask(this.task.taskId).subscribe((task) => { this.taskService.completeTask(this.task.taskId).subscribe((task) => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.task = task; this.task = task;
this.taskService.publishUpdatedTask(task); this.taskService.publishUpdatedTask(task);
this.navigateBack(); this.navigateBack();
@ -97,14 +98,14 @@ export class TaskComponent implements OnInit, OnDestroy {
} }
cancelClaimTask() { cancelClaimTask() {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
this.taskService this.taskService
.cancelClaimTask(this.task.taskId) .cancelClaimTask(this.task.taskId)
.pipe(take(1)) .pipe(take(1))
.subscribe((task) => { .subscribe((task) => {
this.task = task; this.task = task;
this.taskService.publishUpdatedTask(task); this.taskService.publishUpdatedTask(task);
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
}); });
this.navigateBack(); this.navigateBack();
} }

View File

@ -1,4 +1,3 @@
<taskana-shared-spinner [isRunning]="requestInProgress"></taskana-shared-spinner>
<div class="panel panel-default" *ngIf="task && !requestInProgress"> <div class="panel panel-default" *ngIf="task && !requestInProgress">
<!--Buttonbar--> <!--Buttonbar-->
<div class="panel-heading"> <div class="panel-heading">

View File

@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { TaskService } from 'app/workplace/services/task.service'; import { TaskService } from 'app/workplace/services/task.service';
@ -12,6 +12,7 @@ import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service'; import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications'; import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'taskana-task-details', selector: 'taskana-task-details',
@ -26,6 +27,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
currentWorkbasket: Workbasket; currentWorkbasket: Workbasket;
currentId: string; currentId: string;
showDetail = false; showDetail = false;
destroy$ = new Subject<void>();
private routeSubscription: Subscription; private routeSubscription: Subscription;
private workbasketSubscription: Subscription; private workbasketSubscription: Subscription;
@ -47,6 +49,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.workbasketSubscription = this.workplaceService.getSelectedWorkbasket().subscribe((workbasket) => { this.workbasketSubscription = this.workplaceService.getSelectedWorkbasket().subscribe((workbasket) => {
this.currentWorkbasket = workbasket; this.currentWorkbasket = workbasket;
}); });
this.routeSubscription = this.route.params.subscribe((params) => { this.routeSubscription = this.route.params.subscribe((params) => {
this.currentId = params.id; this.currentId = params.id;
// redirect if user enters through a deep-link // redirect if user enters through a deep-link
@ -55,9 +58,17 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
} }
this.getTask(); this.getTask();
}); });
this.masterAndDetailSubscription = this.masterAndDetailService.getShowDetail().subscribe((showDetail) => { this.masterAndDetailSubscription = this.masterAndDetailService.getShowDetail().subscribe((showDetail) => {
this.showDetail = showDetail; this.showDetail = showDetail;
}); });
this.requestInProgressService
.getRequestInProgress()
.pipe(takeUntil(this.destroy$))
.subscribe((value) => {
this.requestInProgress = value;
});
} }
resetTask(): void { resetTask(): void {
@ -69,14 +80,14 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
} }
getTask(): void { getTask(): void {
this.requestInProgress = true; this.requestInProgressService.setRequestInProgress(true);
if (this.currentId === 'new-task') { if (this.currentId === 'new-task') {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.task = new Task('', new ObjectReference(), this.currentWorkbasket); this.task = new Task('', new ObjectReference(), this.currentWorkbasket);
} else { } else {
this.taskService.getTask(this.currentId).subscribe( this.taskService.getTask(this.currentId).subscribe(
(task) => { (task) => {
this.requestInProgress = false; this.requestInProgressService.setRequestInProgress(false);
this.task = task; this.task = task;
this.cloneTask(); this.cloneTask();
this.taskService.selectTask(task); this.taskService.selectTask(task);
@ -139,6 +150,9 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
if (this.deleteTaskSubscription) { if (this.deleteTaskSubscription) {
this.deleteTaskSubscription.unsubscribe(); this.deleteTaskSubscription.unsubscribe();
} }
this.destroy$.next();
this.destroy$.complete();
} }
private onSave() { private onSave() {