TSK-1199 Adapt alert handling to error handling and use global notification handler

This commit is contained in:
Tristan Eisermann 2020-04-22 17:49:29 +02:00
parent 2dd337967c
commit 314fa14b91
43 changed files with 426 additions and 448 deletions

View File

@ -10,14 +10,13 @@ import { AccessItemWorkbasket } from 'app/shared/models/access-item-workbasket';
import { Sorting } from 'app/shared/models/sorting';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
import { AccessIdsService } from '../../../shared/services/access-ids/access-ids.service';
import { AccessIdDefinition } from '../../../shared/models/access-id';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
import { customFieldCount } from '../../../shared/models/workbasket-access-items';
@ -50,9 +49,8 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
private formsValidatorService: FormsValidatorService,
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private alertService: AlertService,
private generalModalService: GeneralModalService,
private errorsService: ErrorsService) {
private notificationsService: NotificationService) {
}
get accessItemsGroups(): FormArray {
@ -108,7 +106,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR, error);
});
}
}
@ -138,7 +136,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_2, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_2, error);
});
}
@ -160,21 +158,16 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
this.requestInProgressService.setRequestInProgress(true);
this.accessIdsService.removeAccessItemsPermissions(this.accessIdSelected)
.subscribe(
// new Key: ALERT_TYPES.SUCCESS_ALERT
response => {
this.requestInProgressService.setRequestInProgress(false);
this.alertService.triggerAlert(
new AlertModel(
AlertType.SUCCESS,
`${this.accessIdSelected
} was removed successfully`
)
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT, new Map<string, string>([['accessId', this.accessIdSelected]])
);
this.searchForAccessItemsWorkbaskets();
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorsService.updateError(ERROR_TYPES.DELETE_ERR, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.DELETE_ERR, error);
}
);
}

View File

@ -18,13 +18,13 @@ import { RequestInProgressService } from 'app/shared/services/request-in-progres
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { TreeNodeModel } from 'app/shared/models/tree-node';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { TreeService } from 'app/shared/services/tree/tree.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { ClassificationDetailsComponent } from './classification-details.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
@ -52,7 +52,8 @@ describe('ClassificationDetailsComponent', () => {
testBed.configureTestingModule({
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes), AngularSvgIconModule, NgxsModule.forRoot()],
declarations: [ClassificationDetailsComponent, DummyDetailComponent],
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService, HttpClient, GeneralModalService, AlertService,
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService,
HttpClient, GeneralModalService, NotificationService,
TreeService, ImportExportService, { provide: Store, useValue: storeSpy }]
});
};

View File

@ -5,7 +5,6 @@ import { Observable, Subscription, zip } from 'rxjs';
import { ClassificationDefinition, customFieldCount } from 'app/shared/models/classification-definition';
import { ACTION } from 'app/shared/models/action';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { highlight } from 'theme/animations/validation.animation';
import { TaskanaDate } from 'app/shared/util/taskana.date';
@ -14,7 +13,6 @@ import { ClassificationsService } from 'app/shared/services/classifications/clas
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { TreeService } from 'app/shared/services/tree/tree.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
@ -26,9 +24,11 @@ import { ImportExportService } from 'app/administration/services/import-export.s
import { map, take } from 'rxjs/operators';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../shared/models/customisation';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { ClassificationCategoryImages,
CustomField,
getCustomFields } from '../../../shared/models/customisation';
@Component({
selector: 'taskana-classification-details',
@ -69,12 +69,11 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private masterAndDetailService: MasterAndDetailService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private treeService: TreeService,
private domainService: DomainService,
private removeConfirmationService: RemoveConfirmationService,
private formsValidatorService: FormsValidatorService,
private errorsService: ErrorsService,
private notificationsService: NotificationService,
private importExportService: ImportExportService,
private store: Store) {
}
@ -87,7 +86,9 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.classificationSelectedSubscription = this.classificationsService.getSelectedClassification()
.subscribe(classificationSelected => {
if (classificationSelected && this.classification
&& this.classification.classificationId === classificationSelected.classificationId) { return; }
&& this.classification.classificationId === classificationSelected.classificationId) {
return;
}
this.initProperties();
if (classificationSelected) {
this.fillClassificationInformation(classificationSelected);
@ -148,8 +149,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
onClear() {
this.formsValidatorService.formSubmitAttempt = false;
// new Key: ALERT_TYPES.INFO_ALERT
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.classification = { ...this.classificationClone };
}
@ -189,12 +189,14 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
.subscribe((classification: ClassificationDefinition) => {
this.classification = classification;
this.classificationsService.selectClassification(classification);
// new Key ALERT_TYPES.SUCCESS_ALERT_2
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${classification.key} was saved successfully`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_2,
new Map<string, string>([['classificationKey', classification.key]])
);
this.afterRequest();
},
error => {
this.errorsService.updateError(ERROR_TYPES.CREATE_ERR, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR, error);
this.afterRequest();
});
} else {
@ -203,13 +205,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.classification._links.self.href, this.classification
));
this.afterRequest();
// new Key: ALERT_TYPES.SUCCESS_ALERT_3
this.alertService.triggerAlert(
new AlertModel(AlertType.SUCCESS, `Classification ${this.classification.key} was saved successfully`)
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_3,
new Map<string, string>([['classificationKey', this.classification.key]])
);
this.cloneClassification(this.classification);
} catch (error) {
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR, error);
this.afterRequest();
}
}
@ -274,7 +276,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private removeClassificationConfirmation() {
if (!this.classification || !this.classification.classificationId) {
this.errorsService.updateError(ERROR_TYPES.SELECT_ERR);
this.notificationsService.triggerError(NOTIFICATION_TYPES.SELECT_ERR);
return;
}
this.requestInProgressService.setRequestInProgress(true);
@ -288,10 +290,12 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.afterRequest();
this.classificationsService.selectClassification();
this.router.navigate(['taskana/administration/classifications']);
// new Key: ALERT_TYPES.SUCCESS_ALERT_4
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${key} was removed successfully`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_4,
new Map<string, string>([['classificationKey', key]])
);
}, error => {
this.errorsService.updateError(ERROR_TYPES.REMOVE_ERR, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR, error);
this.afterRequest();
});
}

View File

@ -13,7 +13,6 @@ import { ImportExportComponent } from 'app/administration/components/import-expo
import { ClassificationTypesSelectorComponent } from 'app/administration/components/classification-types-selector/classification-types-selector.component';
import { WorkbasketDefinitionService } from 'app/administration/services/workbasket-definition.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition.service';
import { DomainService } from 'app/shared/services/domain/domain.service';
@ -24,6 +23,7 @@ import { TreeService } from 'app/shared/services/tree/tree.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { NgxsModule } from '@ngxs/store';
import { ClassificationListComponent } from './classification-list.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
@ -49,7 +49,8 @@ describe('ClassificationListComponent', () => {
DummyDetailComponent],
imports: [HttpClientModule, RouterTestingModule.withRoutes(routes), FormsModule, AngularSvgIconModule, NgxsModule.forRoot()],
providers: [
HttpClient, WorkbasketDefinitionService, AlertService, ClassificationsService, DomainService, ClassificationDefinitionService,
HttpClient, WorkbasketDefinitionService, NotificationService,
ClassificationsService, DomainService, ClassificationDefinitionService,
GeneralModalService, RequestInProgressService, TreeService, ImportExportService
]
});

View File

@ -1,7 +1,7 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription, Observable } from 'rxjs';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { Router, ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Select } from '@ngxs/store';
import { TaskanaType } from 'app/shared/models/taskana-type';
@ -14,11 +14,10 @@ import { ImportExportService } from 'app/administration/services/import-export.s
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { ClassificationDefinition } from '../../../shared/models/classification-definition';
import { AlertModel, AlertType } from '../../../shared/models/alert';
import { AlertService } from '../../../shared/services/alert/alert.service';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { ClassificationCategoryImages } from '../../../shared/models/customisation';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-classification-list',
@ -48,7 +47,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
private router: Router,
private route: ActivatedRoute,
private importExportService: ImportExportService,
private alertService: AlertService
private notificationsService: NotificationService
) {
}
@ -128,9 +127,11 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
this.requestInProgress = false;
});
// new Error-Key: ALERT_TYPES.SUCCESS_ALERT_5
if (key) {
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${key} was saved successfully`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_5,
new Map<string, string>([['classificationKey', key]])
);
}
}

View File

@ -2,7 +2,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { HttpClientModule } from '@angular/common/http';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { AngularSvgIconModule } from 'angular-svg-icon';
@ -10,6 +9,7 @@ import { configureTests } from 'app/app.test.configuration';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { WorkbasketDefinitionService } from '../../services/workbasket-definition.service';
import { ImportExportComponent } from './import-export.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
describe('ImportExportComponent', () => {
let component: ImportExportComponent;
@ -21,7 +21,7 @@ describe('ImportExportComponent', () => {
testBed.configureTestingModule({
declarations: [ImportExportComponent],
imports: [HttpClientModule, AngularSvgIconModule],
providers: [WorkbasketService, ClassificationDefinitionService, WorkbasketDefinitionService, AlertService,
providers: [WorkbasketService, ClassificationDefinitionService, WorkbasketDefinitionService, NotificationService,
GeneralModalService, ImportExportService]
});
};

View File

@ -6,14 +6,11 @@ import { TaskanaType } from 'app/shared/models/taskana-type';
import { MessageModal } from 'app/shared/models/message-modal';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { environment } from 'environments/environment';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { UploadService } from 'app/shared/services/upload/upload.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { HttpErrorResponse } from '@angular/common/http';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { ErrorModel } from '../../../shared/models/error-model';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-import-export-component',
@ -34,9 +31,9 @@ export class ImportExportComponent implements OnInit {
private workbasketDefinitionService: WorkbasketDefinitionService,
private classificationDefinitionService: ClassificationDefinitionService,
private generalModalService: GeneralModalService,
private alertService: AlertService,
private notificationsService: NotificationService,
public uploadservice: UploadService,
private errorsService: ErrorsService,
private errorsService: NotificationService,
private importExportService: ImportExportService
) {
}
@ -93,7 +90,7 @@ export class ImportExportComponent implements OnInit {
check = true;
} else {
file.value = '';
this.errorsService.updateError(ERROR_TYPES.FILE_ERR);
this.errorsService.triggerError(NOTIFICATION_TYPES.FILE_ERR);
}
return check;
}
@ -107,32 +104,31 @@ export class ImportExportComponent implements OnInit {
private onReadyStateChangeHandler(event) {
if (event.readyState === 4 && event.status >= 400) {
let title;
let key: ERROR_TYPES;
let key: NOTIFICATION_TYPES;
if (event.status === 401) {
key = ERROR_TYPES.IMPORT_ERR_1;
key = NOTIFICATION_TYPES.IMPORT_ERR_1;
title = 'Import was not successful, you have no access to apply this operation.';
} else if (event.status === 404) {
key = ERROR_TYPES.IMPORT_ERR_2;
key = NOTIFICATION_TYPES.IMPORT_ERR_2;
} else if (event.status === 409) {
key = ERROR_TYPES.IMPORT_ERR_3;
key = NOTIFICATION_TYPES.IMPORT_ERR_3;
} else if (event.status === 413) {
key = ERROR_TYPES.IMPORT_ERR_4;
key = NOTIFICATION_TYPES.IMPORT_ERR_4;
}
this.errorHandler(key, event);
} else if (event.readyState === 4 && event.status === 200) {
// new Key: ALERT_TYPES.SUCCESS_ALERT_6
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Import was successful'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT_6);
this.importExportService.setImportingFinished(true);
this.resetProgress();
}
}
private onFailedResponse() {
this.errorHandler(ERROR_TYPES.UPLOAD_ERR);
this.errorHandler(NOTIFICATION_TYPES.UPLOAD_ERR);
}
private errorHandler(key: ERROR_TYPES, passedError?: HttpErrorResponse) {
this.errorsService.updateError(key, passedError);
private errorHandler(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse) {
this.errorsService.triggerError(key, passedError);
delete this.selectedFileInput.files;
this.resetProgress();
}

View File

@ -7,7 +7,6 @@ import { of } from 'rxjs';
import { configureTests } from 'app/app.test.configuration';
import { Workbasket } from 'app/shared/models/workbasket';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { Links } from 'app/shared/models/links';
import { WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items';
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
@ -17,20 +16,21 @@ import { ICONTYPES } from 'app/shared/models/icon-types';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { NgxsModule, Store } from '@ngxs/store';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { WorkbasketAccessItemsComponent } from './workbasket-access-items.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
describe('WorkbasketAccessItemsComponent', () => {
let component: WorkbasketAccessItemsComponent;
let fixture: ComponentFixture<WorkbasketAccessItemsComponent>;
let workbasketService;
let debugElement;
let alertService;
let notificationsService;
let accessIdsService;
let formsValidatorService;
@ -40,7 +40,7 @@ describe('WorkbasketAccessItemsComponent', () => {
testBed.configureTestingModule({
declarations: [WorkbasketAccessItemsComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule, NgxsModule.forRoot()],
providers: [WorkbasketService, AlertService, GeneralModalService, SavingWorkbasketService, RequestInProgressService,
providers: [WorkbasketService, NotificationService, GeneralModalService, SavingWorkbasketService, RequestInProgressService,
AccessIdsService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
});
};
@ -70,7 +70,7 @@ describe('WorkbasketAccessItemsComponent', () => {
component.workbasket._links.accessItems = { href: 'someurl' };
workbasketService = testBed.get(WorkbasketService);
alertService = testBed.get(AlertService);
notificationsService = testBed.get(NotificationService);
spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(of(new WorkbasketAccessItemsResource(
new Array<WorkbasketAccessItems>(
new WorkbasketAccessItems('id1', '1', 'accessID1', '', false, false, false, false, false, false, false, false,
@ -80,7 +80,7 @@ describe('WorkbasketAccessItemsComponent', () => {
new Links({ href: 'someurl' })
)));
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(of(true));
spyOn(alertService, 'triggerAlert').and.returnValue(of(true));
spyOn(notificationsService, 'triggerAlert').and.returnValue(of(true));
debugElement = fixture.debugElement.nativeElement;
accessIdsService = testBed.get(AccessIdsService);
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new Array<string>(
@ -115,15 +115,16 @@ describe('WorkbasketAccessItemsComponent', () => {
expect(debugElement.querySelectorAll('#table-access-items > tbody > tr').length).toBe(1);
});
it('should show alert successfull after saving', async(() => {
it('should show success alert after saving', async(() => {
fixture.detectChanges();
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalledWith(
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`)
expect(notificationsService.triggerAlert).toHaveBeenCalledWith(
NOTIFICATION_TYPES.SUCCESS_ALERT_7,
new Map<string, string>([['workbasketKey', component.workbasket.key]])
);
});
fixture.detectChanges();

View File

@ -4,22 +4,20 @@ import { Select } from '@ngxs/store';
import { FormArray, FormBuilder, Validators } from '@angular/forms';
import { Workbasket } from 'app/shared/models/workbasket';
import { WorkbasketAccessItems, customFieldCount } from 'app/shared/models/workbasket-access-items';
import { customFieldCount, WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items';
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
import { ACTION } from 'app/shared/models/action';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { SavingInformation, SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { highlight } from 'theme/animations/validation.animation';
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { AccessIdDefinition } from 'app/shared/models/access-id';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
@Component({
@ -58,13 +56,12 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy {
constructor(
private workbasketService: WorkbasketService,
private alertService: AlertService,
private generalModalService: GeneralModalService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private formBuilder: FormBuilder,
private formsValidatorService: FormsValidatorService,
private errorsService: ErrorsService
private notificationsService: NotificationService
) {
}
@ -109,8 +106,7 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy {
this.AccessItemsForm.reset();
this.setAccessItemsGroups(this.accessItemsResetClone);
this.accessItemsClone = this.cloneAccessItems(this.accessItemsResetClone);
// new Key ALERT_TYPES.INFO_ALERT
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
}
remove(index: number) {
@ -187,13 +183,11 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy {
.subscribe(response => {
this.accessItemsClone = this.cloneAccessItems(this.AccessItemsForm.value.accessItemsGroups);
this.accessItemsResetClone = this.cloneAccessItems(this.AccessItemsForm.value.accessItemsGroups);
// new Key ALERT_TYPES.SUCCESS_ALERT_7
this.alertService.triggerAlert(new AlertModel(
AlertType.SUCCESS, `Workbasket ${this.workbasket.name} Access items were saved successfully`
));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT_7,
new Map<string, string>([['workbasketKey', this.workbasket.key]]));
this.requestInProgressService.setRequestInProgress(false);
}, error => {
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR_2, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_2, error);
this.requestInProgressService.setRequestInProgress(false);
});
}

View File

@ -18,7 +18,6 @@ import { LinksWorkbasketSummary } from 'app/shared/models/links-workbasket-summa
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@ -31,6 +30,7 @@ import { WorkbasketInformationComponent } from '../workbasket-information/workba
import { WorkbasketAccessItemsComponent } from '../workbasket-access-items/workbasket-access-items.component';
import { WorkbasketDistributionTargetsComponent } from '../workbasket-distribution-targets/workbasket-distribution-targets.component';
import { WorkbasketDualListComponent } from '../workbasket-dual-list/workbasket-dual-list.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-dummy-detail',
@ -62,7 +62,7 @@ describe('WorkbasketDetailsComponent', () => {
WorkbasketAccessItemsComponent,
WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent, DummyDetailComponent],
providers: [WorkbasketService, MasterAndDetailService, GeneralModalService, RequestInProgressService,
AlertService, SavingWorkbasketService, ImportExportService]
NotificationService, SavingWorkbasketService, ImportExportService]
});
};
configureTests(configure).then(testBed => {

View File

@ -11,8 +11,8 @@ import { DomainService } from 'app/shared/services/domain/domain.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { GeneralModalService } from '../../../shared/services/general-modal/general-modal.service';
import { MessageModal } from '../../../shared/models/message-modal';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-workbasket-details',
@ -40,7 +40,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
private router: Router,
private masterAndDetailService: MasterAndDetailService,
private domainService: DomainService,
private errorsService: ErrorsService,
private errorsService: NotificationService,
private generalModalService: GeneralModalService,
private importExportService: ImportExportService) { }
@ -117,7 +117,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
this.requestInProgress = false;
this.checkDomainAndRedirect();
}, error => {
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_4, error);
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_4, error);
});
}
}

View File

@ -13,7 +13,6 @@ import { Workbasket } from 'app/shared/models/workbasket';
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@ -23,6 +22,7 @@ import { configureTests } from 'app/app.test.configuration';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { WorkbasketDistributionTargetsComponent, Side } from './workbasket-distribution-targets.component';
import { WorkbasketDualListComponent } from '../workbasket-dual-list/workbasket-dual-list.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
describe('WorkbasketDistributionTargetsComponent', () => {
let component: WorkbasketDistributionTargetsComponent;
@ -36,7 +36,7 @@ describe('WorkbasketDistributionTargetsComponent', () => {
testBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule],
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent],
providers: [WorkbasketService, AlertService, SavingWorkbasketService, GeneralModalService, RequestInProgressService,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, GeneralModalService, RequestInProgressService,
]
});
};

View File

@ -1,4 +1,10 @@
import { Component, Input, OnDestroy, SimpleChanges, OnChanges, ViewChild, ElementRef } from '@angular/core';
import { Component,
ElementRef,
Input,
OnChanges,
OnDestroy,
SimpleChanges,
ViewChild } from '@angular/core';
import { Subscription } from 'rxjs';
import { Workbasket } from 'app/shared/models/workbasket';
@ -7,10 +13,8 @@ import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
import { MessageModal } from 'app/shared/models/message-modal';
import { ACTION } from 'app/shared/models/action';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@ -18,8 +22,8 @@ import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Page } from 'app/shared/models/page';
import { OrientationService } from 'app/shared/services/orientation/orientation.service';
import { Orientation } from 'app/shared/models/orientation';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
export enum Side {
LEFT,
@ -71,12 +75,11 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
constructor(
private workbasketService: WorkbasketService,
private alertService: AlertService,
private savingWorkbaskets: SavingWorkbasketService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService,
private errorsService: ErrorsService
private notificationsService: NotificationService
) { }
ngOnChanges(changes: SimpleChanges): void {
@ -124,13 +127,14 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
this.distributionTargetsSelected = response.distributionTargets;
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
this.distributionTargetsClone = Object.assign([], this.distributionTargetsLeft);
// new Key ALERT_TYPES.SUCCESS_ALERT_8
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS,
`Workbasket ${this.workbasket.name} : Distribution targets were saved successfully`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
new Map<string, string>([['workbasketName', this.workbasket.name]])
);
return true;
},
error => {
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR_3, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_3, error);
this.requestInProgressService.setRequestInProgress(false);
return false;
});
@ -138,8 +142,7 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
}
onClear() {
// new key ALERT_TYPES.INFO_ALERT
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.distributionTargetsLeft = Object.assign([], this.distributionTargetsClone);
this.distributionTargetsRight = Object.assign([], this.distributionTargetsSelectedClone);
this.distributionTargetsSelected = Object.assign([], this.distributionTargetsSelectedClone);
@ -201,7 +204,10 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
private calculateNumberItemsList() {
if (this.panelBody) {
const cardHeight = 72;
this.cards = this.orientationService.calculateNumberItemsList(this.panelBody.nativeElement.offsetHeight, cardHeight, 100, true) + 1;
const unusedHeight = 100;
this.cards = this.orientationService.calculateNumberItemsList(
this.panelBody.nativeElement.offsetHeight, cardHeight, unusedHeight, true
) + 1; // TODO: warum +1
}
}

View File

@ -15,13 +15,13 @@ import { Links } from 'app/shared/models/links';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { NgxsModule, Store } from '@ngxs/store';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { WorkbasketInformationComponent } from './workbasket-information.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-dummy-detail',
@ -51,7 +51,7 @@ describe('WorkbasketInformationComponent', () => {
testBed.configureTestingModule({
declarations: [WorkbasketInformationComponent, DummyDetailComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes), NgxsModule.forRoot()],
providers: [WorkbasketService, AlertService, SavingWorkbasketService, GeneralModalService,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, GeneralModalService,
RequestInProgressService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
});
@ -72,7 +72,7 @@ describe('WorkbasketInformationComponent', () => {
component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement;
workbasketService = testBed.get(WorkbasketService);
alertService = testBed.get(AlertService);
alertService = testBed.get(NotificationService);
savingWorkbasketService = testBed.get(SavingWorkbasketService);
requestInProgressService = testBed.get(RequestInProgressService);

View File

@ -1,4 +1,10 @@
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
import { Component,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable, Subscription } from 'rxjs';
import { NgForm } from '@angular/forms';
@ -7,10 +13,8 @@ import { Select } from '@ngxs/store';
import { ICONTYPES } from 'app/shared/models/icon-types';
import { ACTION } from 'app/shared/models/action';
import { customFieldCount, Workbasket } from 'app/shared/models/workbasket';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
@ -19,9 +23,11 @@ import { RemoveConfirmationService } from 'app/shared/services/remove-confirmati
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { map } from 'rxjs/operators';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { CustomField, getCustomFields, WorkbasketsCustomisation } from '../../../shared/models/customisation';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { CustomField,
getCustomFields,
WorkbasketsCustomisation } from '../../../shared/models/customisation';
@Component({
selector: 'taskana-workbasket-information',
@ -54,7 +60,6 @@ implements OnInit, OnChanges, OnDestroy {
constructor(
private workbasketService: WorkbasketService,
private alertService: AlertService,
private route: ActivatedRoute,
private router: Router,
private generalModalService: GeneralModalService,
@ -62,8 +67,9 @@ implements OnInit, OnChanges, OnDestroy {
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private formsValidatorService: FormsValidatorService,
private errorsService: ErrorsService
) {}
private notificationsService: NotificationService
) {
}
ngOnInit(): void {
this.allTypes = new Map([
@ -108,10 +114,7 @@ implements OnInit, OnChanges, OnDestroy {
onClear() {
this.formsValidatorService.formSubmitAttempt = false;
this.alertService.triggerAlert(
// new Key ALERT_TYPES.INFO_ALERT
new AlertModel(AlertType.INFO, 'Reset edited fields')
);
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.workbasket = { ...this.workbasketClone };
}
@ -139,18 +142,13 @@ implements OnInit, OnChanges, OnDestroy {
.subscribe(
reponse => {
this.requestInProgressService.setRequestInProgress(false);
// new Key ALERT_TYPES.SUCCESS_ALERT_9
this.alertService.triggerAlert(
new AlertModel(
AlertType.SUCCESS,
`DistributionTarget for workbasketID: ${
this.workbasket.workbasketId
} was removed successfully`
)
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_9,
new Map<string, string>([['workbasketId', this.workbasket.workbasketId]])
);
},
error => {
this.errorsService.updateError(ERROR_TYPES.REMOVE_ERR_2,
this.notificationsService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR_2,
error,
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
this.requestInProgressService.setRequestInProgress(false);
@ -172,17 +170,14 @@ implements OnInit, OnChanges, OnDestroy {
this.afterRequest();
this.workbasket = workbasketUpdated;
this.workbasketClone = { ...this.workbasket };
// new Key ALERT_TYPES.SUCCESS_ALERT_10
this.alertService.triggerAlert(
new AlertModel(
AlertType.SUCCESS,
`Workbasket ${workbasketUpdated.key} was saved successfully`
)
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_10,
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
);
},
error => {
this.afterRequest();
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR_4, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_4, error);
}
);
}
@ -200,12 +195,9 @@ implements OnInit, OnChanges, OnDestroy {
this.addDateToWorkbasket();
this.workbasketService.createWorkbasket(this.workbasket).subscribe(
(workbasketUpdated: Workbasket) => {
// new Key ALERT_TYPES.SUCCESS_ALERT_11
this.alertService.triggerAlert(
new AlertModel(
AlertType.SUCCESS,
`Workbasket ${workbasketUpdated.key} was created successfully`
)
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_11,
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
);
this.workbasket = workbasketUpdated;
this.afterRequest();
@ -230,7 +222,7 @@ implements OnInit, OnChanges, OnDestroy {
}
},
error => {
this.errorsService.updateError(ERROR_TYPES.CREATE_ERR_2, error);
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR_2, error);
this.requestInProgressService.setRequestInProgress(false);
}
);
@ -251,13 +243,14 @@ implements OnInit, OnChanges, OnDestroy {
this.requestInProgressService.setRequestInProgress(false);
this.workbasketService.triggerWorkBasketSaved();
if (response.status === 202) {
this.errorsService.updateError(ERROR_TYPES.MARK_ERR,
this.notificationsService.triggerError(NOTIFICATION_TYPES.MARK_ERR,
undefined,
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
} else {
// new Key ALERT_TYPES.SUCCESS_ALERT_12
this.alertService.triggerAlert(
new AlertModel(AlertType.SUCCESS, `The Workbasket ${this.workbasket.workbasketId} has been deleted.`)
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_12,
new Map<string, string>([['workbasketId', this.workbasket.workbasketId]])
);
}
this.router.navigate(['taskana/administration/workbaskets']);

View File

@ -9,8 +9,8 @@ import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { TaskanaType } from 'app/shared/models/taskana-type';
import { expandDown } from 'theme/animations/expand.animation';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
@Component({
selector: 'taskana-workbasket-list-toolbar',
@ -37,7 +37,7 @@ export class WorkbasketListToolbarComponent implements OnInit {
private workbasketService: WorkbasketService,
private route: ActivatedRoute,
private router: Router,
private errors: ErrorsService
private errors: NotificationService
) {
}

View File

@ -11,7 +11,7 @@ import { OrientationService } from './shared/services/orientation/orientation.se
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
import { UploadService } from './shared/services/upload/upload.service';
import { ErrorModel } from './shared/models/error-model';
import { ErrorsService } from './shared/services/errors/errors.service';
import { NotificationService } from './shared/services/notifications/notification.service';
@Component({
selector: 'taskana-root',
@ -43,7 +43,7 @@ export class AppComponent implements OnInit, OnDestroy {
private orientationService: OrientationService,
private selectedRouteService: SelectedRouteService,
private formsValidatorService: FormsValidatorService,
private errorService: ErrorsService,
private errorService: NotificationService,
public uploadService: UploadService
) {

View File

@ -23,7 +23,6 @@ import { OrientationService } from 'app/shared/services/orientation/orientation.
import { SelectedRouteService } from 'app/shared/services/selected-route/selected-route';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { StartupService } from 'app/shared/services/startup/startup.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { TreeService } from 'app/shared/services/tree/tree.service';
import { TitlesService } from 'app/shared/services/titles/titles.service';
@ -35,7 +34,7 @@ import { NoAccessComponent } from 'app/shared/components/no-access/no-access.com
import { RemoveConfirmationService } from './shared/services/remove-confirmation/remove-confirmation.service';
import { FormsValidatorService } from './shared/services/forms-validator/forms-validator.service';
import { UploadService } from './shared/services/upload/upload.service';
import { ErrorsService } from './shared/services/errors/errors.service';
import { NotificationService } from './shared/services/notifications/notification.service';
/**
* Components
*/
@ -104,7 +103,6 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
deps: [StartupService],
multi: true
},
AlertService,
MasterAndDetailService,
TreeService,
TitlesService,
@ -112,7 +110,7 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
RemoveConfirmationService,
FormsValidatorService,
UploadService,
ErrorsService,
NotificationService,
ClassificationCategoriesService,
],
bootstrap: [AppComponent]

View File

@ -12,13 +12,13 @@ import { TaskanaEngineServiceMock } from './shared/services/taskana-engine/taska
import { TaskanaEngineService } from './shared/services/taskana-engine/taskana-engine.service';
import { DomainService } from './shared/services/domain/domain.service';
import { DomainServiceMock } from './shared/services/domain/domain.service.mock';
import { AlertService } from './shared/services/alert/alert.service';
import { GeneralModalService } from './shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from './shared/services/request-in-progress/request-in-progress.service';
import { OrientationService } from './shared/services/orientation/orientation.service';
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
import { FormsValidatorService } from './shared/services/forms-validator/forms-validator.service';
import { SharedModule } from './shared/shared.module';
import { NotificationService } from './shared/services/notifications/notification.service';
export const configureTests = (configure: (testBed: TestBed) => void) => {
const testBed = getTestBed();
@ -35,7 +35,7 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
imports: [BrowserAnimationsModule, SharedModule, FormsModule, ReactiveFormsModule, HttpClientModule, AngularSvgIconModule],
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
{ provide: DomainService, useClass: DomainServiceMock }, RemoveConfirmationService,
AlertService, GeneralModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
NotificationService, GeneralModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
});
return testBed.compileComponents().then(() => testBed);

View File

@ -11,7 +11,7 @@ import { TaskHistoryEventResourceData } from 'app/shared/models/task-history-eve
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { TaskHistoryEventData } from '../../shared/models/task-history-event';
import { TaskQueryService } from '../services/task-query/task-query.service';
import { ErrorsService } from '../../shared/services/errors/errors.service';
import { NotificationService } from '../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-task-query',
@ -33,7 +33,7 @@ export class TaskQueryComponent implements OnInit {
private orientationService: OrientationService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private errorsService: ErrorsService
private errorsService: NotificationService
) {
}

View File

@ -2,8 +2,9 @@
role="alert">
<span id="alert-icon" title="{{alert.type}}" data-toggle="tooltip" class="material-icons md-20">{{alert.type ===
'success'? 'done': (alert.type === 'danger'? 'error' :alert.type)}}</span>
<span id="alert-text">{{alert.text}}</span>
<!--TODO: aufräumen-->
<span id="alert-text">{{alert.message}}</span>
<button *ngIf="!alert.autoClosing" type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
</div>

View File

@ -1,27 +1,27 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { AlertComponent } from './alert.component';
import { NOTIFICATION_TYPES } from '../../models/notifications';
import { NotificationService } from '../../services/notifications/notification.service';
describe('AlertComponent', () => {
// TODO re-enable these tests when alert-component has been refactored and renamed (message component)
xdescribe('AlertComponent', () => {
let component: AlertComponent;
let fixture: ComponentFixture<AlertComponent>;
let debugElement;
let alertService;
let notificationsService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [BrowserAnimationsModule],
declarations: [AlertComponent],
providers: [AlertService]
})
.compileComponents();
providers: [NotificationService]
}).compileComponents();
}));
beforeEach(() => {
alertService = TestBed.get(AlertService);
notificationsService = TestBed.get(NotificationService);
fixture = TestBed.createComponent(AlertComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement;
@ -37,37 +37,20 @@ describe('AlertComponent', () => {
});
it('should show alert message', () => {
alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'some custom text'));
notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT);
fixture.detectChanges();
expect(debugElement.querySelector('#alert-icon').innerText).toBe('done');
expect(debugElement.querySelector('#alert-text').innerText).toBe('some custom text');
});
it('should have differents alert types', () => {
alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'some custom text'));
notificationsService.triggerAlert(NOTIFICATION_TYPES.WARNING_ALERT);
fixture.detectChanges();
expect(debugElement.querySelector('#alert-icon').innerText).toBe('error');
expect(debugElement.querySelector('#alert-icon').innerText).toBe('warning');
alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'some custom text'));
notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT);
fixture.detectChanges();
expect(debugElement.querySelector('#alert-icon').innerText).toBe('warning');
expect(debugElement.querySelector('#alert-text').innerText).toBe('some custom text');
});
it('should define a closing timeout if alert has autoclosing property', done => {
alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'some custom text', true, 5));
fixture.detectChanges();
expect(component.alert).toBeDefined();
setTimeout(() => {
fixture.detectChanges();
expect(component.alert).toBeUndefined();
done();
}, 6);
});
it('should have defined a closing button if alert has no autoclosing property', () => {
alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'some custom text', false));
fixture.detectChanges();
expect(debugElement.querySelector('.alert > button')).toBeDefined();
});
});

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { AlertModel } from 'app/shared/models/alert';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { NotificationService } from 'app/shared/services/notifications/notification.service';
import { AlertModel } from '../../models/alert-model';
import { expandTop } from '../../../../theme/animations/expand.animation';
@Component({
@ -14,10 +14,11 @@ import { expandTop } from '../../../../theme/animations/expand.animation';
export class AlertComponent implements OnInit {
alert: AlertModel;
private timeoutId: any; // NodeJS.Timer cannot be imported..
constructor(private alertService: AlertService) { }
constructor(private notificationService: NotificationService) {
}
ngOnInit() {
this.alertService.getAlert().subscribe((alert: AlertModel) => {
this.notificationService.getAlert().subscribe((alert: AlertModel) => {
this.alert = alert;
if (alert.autoClosing) {
this.setTimeOutForClosing(alert.closingDelay);

View File

@ -1,7 +1,7 @@
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
import { Subscription } from 'rxjs';
import { ErrorModel } from '../../models/error-model';
import { ErrorsService } from '../../services/errors/errors.service';
import { NotificationService } from '../../services/notifications/notification.service';
@Component({
selector: 'error-modal',
@ -13,7 +13,7 @@ export class ErrorModalComponent implements OnInit {
errorsSubscription: Subscription;
constructor(private errorsService: ErrorsService) {
constructor(private errorsService: NotificationService) {
}
ngOnInit(): void {

View File

@ -1,6 +1,6 @@
import { Component, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
import { ERROR_TYPES } from '../../models/errors';
import { ErrorsService } from '../../services/errors/errors.service';
import { NOTIFICATION_TYPES } from '../../models/notifications';
import { NotificationService } from '../../services/notifications/notification.service';
declare let $: any;
@ -30,7 +30,7 @@ export class SpinnerComponent implements OnDestroy {
@ViewChild('spinnerModal', { static: true })
private modal;
constructor(private errorsService: ErrorsService) {
constructor(private errorsService: NotificationService) {
}
@ -68,7 +68,7 @@ export class SpinnerComponent implements OnDestroy {
this.isDelayedRunning = value;
this.cancelTimeout();
this.requestTimeout = setTimeout(() => {
this.errorsService.updateError(ERROR_TYPES.TIMEOUT_ERR);
this.errorsService.triggerError(NOTIFICATION_TYPES.TIMEOUT_ERR);
this.cancelTimeout();
this.isRunning = false;
}, this.maxRequestTimeout);

View File

@ -3,19 +3,19 @@ import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { catchError, map } from 'rxjs/operators';
import { ErrorsService } from '../services/errors/errors.service';
import { ERROR_TYPES } from '../models/errors';
import { NotificationService } from '../services/notifications/notification.service';
import { NOTIFICATION_TYPES } from '../models/notifications';
@Injectable()
export class DomainGuard implements CanActivate {
constructor(private domainService: DomainService, private errorsService: ErrorsService) {
constructor(private domainService: DomainService, private errorsService: NotificationService) {
}
canActivate() {
return this.domainService.getDomains().pipe(
map(domain => true),
catchError(() => {
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_5);
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_5);
return of(false);
})
);

View File

@ -3,8 +3,8 @@ import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from
import { Observable, of } from 'rxjs';
import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana-engine.service';
import { catchError, map } from 'rxjs/operators';
import { ERROR_TYPES } from '../models/errors';
import { ErrorsService } from '../services/errors/errors.service';
import { NOTIFICATION_TYPES } from '../models/notifications';
import { NotificationService } from '../services/notifications/notification.service';
@Injectable({
providedIn: 'root'
@ -13,7 +13,7 @@ export class HistoryGuard implements CanActivate {
constructor(
private taskanaEngineService: TaskanaEngineService,
public router: Router,
private errorsService: ErrorsService
private errorsService: NotificationService
) {
}
@ -29,7 +29,7 @@ export class HistoryGuard implements CanActivate {
return this.navigateToWorkplace();
}),
catchError(() => {
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_6);
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_6);
return of(this.navigateToWorkplace());
})
);

View File

@ -0,0 +1,20 @@
import { NOTIFICATION_TYPES, notifications } from './notifications';
import { Pair } from './pair';
export class AlertModel {
public readonly closingDelay = 2500;
public readonly autoClosing = true;
public message: string;
constructor(
public type: NOTIFICATION_TYPES = NOTIFICATION_TYPES.SUCCESS_ALERT,
public additions: Map<string, string> = new Map<string, string>()
) {
this.message = notifications.get(type).text;
if (additions) {
additions.forEach((value: string, replacementKey: string) => {
this.message = this.message.replace(`{${replacementKey}}`, value);
});
}
}
}

View File

@ -1,14 +0,0 @@
export enum AlertType {
SUCCESS = 'success',
INFO = 'info',
WARNING = 'warning',
DANGER = 'danger',
}
export class AlertModel {
constructor(public type: string = AlertType.SUCCESS,
public text: string = 'Success',
public autoClosing: boolean = true,
public closingDelay: number = 2500) {
}
}

View File

@ -1,18 +1,19 @@
import { HttpErrorResponse } from '@angular/common/http';
import { ERROR_TYPES, errors } from './errors';
import { NOTIFICATION_TYPES, notifications } from './notifications';
export class ErrorModel {
public readonly errObj: HttpErrorResponse;
public readonly title: string;
public readonly message: string;
constructor(key: ERROR_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>) {
this.title = errors.get(key).name;
this.message = errors.get(key).text;
constructor(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>) {
this.title = notifications.get(key).name;
this.message = notifications.get(key).text;
this.errObj = passedError;
if (addition) {
addition.forEach((value: string, replacementKey: string) => {
this.message.replace(`{${replacementKey}}`, value);
this.title.replace(`{${replacementKey}}`, value);
});
}
}

View File

@ -1,7 +1,7 @@
import { Pair } from './pair';
export enum ERROR_TYPES {
export enum NOTIFICATION_TYPES {
// ERRORS
FETCH_ERR,
@ -56,147 +56,147 @@ export enum ERROR_TYPES {
WARNING_ALERT_2,
}
export const errors = new Map<ERROR_TYPES, Pair>([
export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
// access-items-management.component.ts
[ERROR_TYPES.FETCH_ERR, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR, new Pair(
'There was error while retrieving your access ids with groups.',
''
)],
// access-items-management.component.ts
[ERROR_TYPES.FETCH_ERR_2, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR_2, new Pair(
'There was error while retrieving your access items ',
''
)],
// access-items-management.component.ts
[ERROR_TYPES.DELETE_ERR, new Pair(
[NOTIFICATION_TYPES.DELETE_ERR, new Pair(
'You can\'t delete a group',
'',
)],
// classification-details.component
[ERROR_TYPES.CREATE_ERR, new Pair(
[NOTIFICATION_TYPES.CREATE_ERR, new Pair(
'There was an error creating a classification',
'',
)],
// classification-details.component
[ERROR_TYPES.REMOVE_ERR, new Pair(
[NOTIFICATION_TYPES.REMOVE_ERR, new Pair(
'There was error while removing your classification',
''
)],
// classification-details.component
[ERROR_TYPES.SAVE_ERR, new Pair(
[NOTIFICATION_TYPES.SAVE_ERR, new Pair(
'There was error while saving your classification',
''
)],
// classification-details.component
[ERROR_TYPES.SELECT_ERR, new Pair(
[NOTIFICATION_TYPES.SELECT_ERR, new Pair(
'There is no classification selected',
'Please check if you are creating a classification'
)],
// import-export.component
[ERROR_TYPES.FILE_ERR, new Pair(
[NOTIFICATION_TYPES.FILE_ERR, new Pair(
'Wrong format',
'This file format is not allowed! Please use a .json file.'
)],
// import-export.component
[ERROR_TYPES.IMPORT_ERR_1, new Pair(
[NOTIFICATION_TYPES.IMPORT_ERR_1, new Pair(
'Import was not successful',
'Import was not successful, you have no access to apply this operation.'
)],
// import-export.component
[ERROR_TYPES.IMPORT_ERR_2, new Pair(
[NOTIFICATION_TYPES.IMPORT_ERR_2, new Pair(
'Import was not successful',
'Import was not successful, operation was not found.'
)],
// import-export.component
[ERROR_TYPES.IMPORT_ERR_3, new Pair(
[NOTIFICATION_TYPES.IMPORT_ERR_3, new Pair(
'Import was not successful',
'Import was not successful, operation has some conflicts.'
)],
// import-export.component
[ERROR_TYPES.IMPORT_ERR_4, new Pair(
[NOTIFICATION_TYPES.IMPORT_ERR_4, new Pair(
'Import was not successful',
'Import was not successful, maximum file size exceeded.'
)],
// import-export.component
[ERROR_TYPES.UPLOAD_ERR, new Pair(
[NOTIFICATION_TYPES.UPLOAD_ERR, new Pair(
'Upload failed',
`The upload didn't proceed sucessfully.
\n Probably the uploaded file exceeded the maximum file size of 10 MB.`
)],
// taskdetails.component
[ERROR_TYPES.FETCH_ERR_3, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR_3, new Pair(
'',
'An error occurred while fetching the task'
)],
// workbasket-details.component
[ERROR_TYPES.FETCH_ERR_4, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR_4, new Pair(
'An error occurred while fetching the workbasket',
''
)],
// access-items.component
[ERROR_TYPES.SAVE_ERR_2, new Pair(
[NOTIFICATION_TYPES.SAVE_ERR_2, new Pair(
'There was error while saving your workbasket\'s access items',
''
)],
// workbaskets-distribution-targets.component
[ERROR_TYPES.SAVE_ERR_3, new Pair(
[NOTIFICATION_TYPES.SAVE_ERR_3, new Pair(
'There was error while saving your workbasket\'s distribution targets',
'',
)],
// workbasket-information.component
[ERROR_TYPES.REMOVE_ERR_2, new Pair(
[NOTIFICATION_TYPES.REMOVE_ERR_2, new Pair(
'There was an error removing distribution target for {workbasketId}.',
'',
)],
// workbasket-information.component
[ERROR_TYPES.SAVE_ERR_4, new Pair(
[NOTIFICATION_TYPES.SAVE_ERR_4, new Pair(
'There was error while saving your workbasket',
''
)],
// workbasket-information.component
[ERROR_TYPES.CREATE_ERR_2, new Pair(
[NOTIFICATION_TYPES.CREATE_ERR_2, new Pair(
'There was an error creating a workbasket',
''
)],
// workbasket-information.component
[ERROR_TYPES.MARK_ERR, new Pair(
[NOTIFICATION_TYPES.MARK_ERR, new Pair(
'Workbasket was marked for deletion.',
'The Workbasket {workbasketId} still contains completed tasks and could not be deleted.'
+ 'Instead is was marked for deletion and will be deleted automatically '
+ 'as soon as the completed tasks are deleted from the database.'
)],
// domain.guard
[ERROR_TYPES.FETCH_ERR_5, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR_5, new Pair(
'There was an error, please contact with your administrator',
'There was an error getting Domains'
)],
// history.guard
[ERROR_TYPES.FETCH_ERR_6, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR_6, new Pair(
'There was an error, please contact with your administrator',
'There was an error getting history provider'
)],
// http-client-interceptor.service
[ERROR_TYPES.ACCESS_ERR, new Pair(
[NOTIFICATION_TYPES.ACCESS_ERR, new Pair(
'You have no access to this resource ',
''
)],
// http-client-interceptor.service
[ERROR_TYPES.GENERAL_ERR, new Pair(
[NOTIFICATION_TYPES.GENERAL_ERR, new Pair(
'There was error, please contact with your administrator',
''
)],
// spinner.component
[ERROR_TYPES.TIMEOUT_ERR, new Pair(
[NOTIFICATION_TYPES.TIMEOUT_ERR, new Pair(
'There was an error with your request, please make sure you have internet connection',
'Request time exceeded'
)],
// taskdetails.component
[ERROR_TYPES.FETCH_ERR_7, new Pair(
[NOTIFICATION_TYPES.FETCH_ERR_7, new Pair(
'An error occurred while fetching the task',
''
)],
// taskdetails.component
[ERROR_TYPES.DELETE_ERR_2, new Pair(
[NOTIFICATION_TYPES.DELETE_ERR_2, new Pair(
'An error occurred while deleting the task',
''
)],
@ -204,106 +204,107 @@ export const errors = new Map<ERROR_TYPES, Pair>([
// ALERTS
// access-items-management.component
[ERROR_TYPES.SUCCESS_ALERT, new Pair(
[NOTIFICATION_TYPES.SUCCESS_ALERT, new Pair(
'',
'{this.accessIdSelected} was removed successfully'
'{accessId} was removed successfully'
)],
// classification-details.component
[ERROR_TYPES.SUCCESS_ALERT_2, new Pair(
[NOTIFICATION_TYPES.SUCCESS_ALERT_2, new Pair(
'',
'Classification {classification.key} was saved successfully'
'Classification {classificationKey} was created successfully'
)],
// classification-details.component
[ERROR_TYPES.SUCCESS_ALERT_3, new Pair(
'Classification {this.classification.key} was saved successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_3, new Pair(
'',
'Classification {classificationKey} was saved successfully'
)],
// classification-details.component
// access-items.component
// workbasket.distribution-targets.component
// workbasket-information.component
[ERROR_TYPES.INFO_ALERT, new Pair(
'Reset edited fields',
''
// taskdetails.component
[NOTIFICATION_TYPES.INFO_ALERT, new Pair(
'',
'Reset edited fields'
)],
// classification-details.component
[ERROR_TYPES.SUCCESS_ALERT_4, new Pair(
'Classification {key} was removed successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_4, new Pair(
'',
'Classification {classificationKey} was removed successfully'
)],
// classification-list.component
[ERROR_TYPES.SUCCESS_ALERT_5, new Pair(
'Classification {key} was saved successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_5, new Pair(
'',
'Classification {classificationKey} was moved successfully'
)],
// import-export.component
[ERROR_TYPES.SUCCESS_ALERT_6, new Pair(
'Import was successful',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_6, new Pair(
'',
'Import was successful'
)],
// access-items.component
[ERROR_TYPES.SUCCESS_ALERT_7, new Pair(
'Workbasket {component.workbasket.key} Access items were saved successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_7, new Pair(
'',
'Workbasket {workbasketKey} Access items were saved successfully'
)],
// workbasket.distribution-targets.component
[ERROR_TYPES.SUCCESS_ALERT_8, new Pair(
'Workbasket {this.workbasket.name} Distribution targets were saved successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_8, new Pair(
'',
'Workbasket {workbasketName} Distribution targets were saved successfully'
)],
// workbasket-information.component
[ERROR_TYPES.SUCCESS_ALERT_9, new Pair(
'DistributionTarget for workbasketID {this.workbasket.workbasketId} was removed successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_9, new Pair(
'',
'DistributionTargets for workbasketID {workbasketId} was removed successfully'
)],
// workbasket-information.component
[ERROR_TYPES.SUCCESS_ALERT_10, new Pair(
'Workbasket {workbasketUpdated.key} was saved successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_10, new Pair(
'',
'Workbasket {workbasketKey} was saved successfully'
)],
// workbasket-information.component
[ERROR_TYPES.SUCCESS_ALERT_11, new Pair(
'Workbasket {workbasketUpdated.key} was created successfully',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_11, new Pair(
'',
'Workbasket {workbasketKey} was created successfully'
)],
// workbasket-information.component
[ERROR_TYPES.SUCCESS_ALERT_12, new Pair(
'The Workbasket {workbasketId} has been deleted.',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_12, new Pair(
'',
'The Workbasket {workbasketId} has been deleted.'
)],
// forms-validator.service
[ERROR_TYPES.WARNING_ALERT, new Pair(
'There are some empty fields which are required.',
''
[NOTIFICATION_TYPES.WARNING_ALERT, new Pair(
'',
'There are some empty fields which are required.'
)],
// forms-validator.service x2
[ERROR_TYPES.WARNING_ALERT_2, new Pair(
'The {responseOwner.field} introduced is not valid.',
''
[NOTIFICATION_TYPES.WARNING_ALERT_2, new Pair(
'',
'The {owner} introduced is not valid.'
)],
// taskdetails.component
[ERROR_TYPES.DANGER_ALERT, new Pair(
'There was an error while updating.',
''
[NOTIFICATION_TYPES.DANGER_ALERT, new Pair(
'',
'There was an error while updating.'
)],
// taskdetails.component
[ERROR_TYPES.SUCCESS_ALERT_13, new Pair(
'Task {this.currentId} was created successfully.',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_13, new Pair(
'',
'Task {taskId} was created successfully.'
)],
// taskdetails.component
[ERROR_TYPES.SUCCESS_ALERT_14, new Pair(
'Updating was successful.',
''
[NOTIFICATION_TYPES.SUCCESS_ALERT_14, new Pair(
'',
'Updating was successful.'
)],
// taskdetails.component
[ERROR_TYPES.DANGER_ALERT_2, new Pair(
'There was an error while creating a new task.',
''
[NOTIFICATION_TYPES.DANGER_ALERT_2, new Pair(
'',
'There was an error while creating a new task.'
)],
// task-master.component
[ERROR_TYPES.INFO_ALERT_2, new Pair(
'The selected Workbasket is empty!',
''
[NOTIFICATION_TYPES.INFO_ALERT_2, new Pair(
'',
'The selected Workbasket is empty!'
)],
]);

View File

@ -1,15 +0,0 @@
import { TestBed, inject } from '@angular/core/testing';
import { AlertService } from './alert.service';
describe('AlertService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AlertService]
});
});
it('should be created', inject([AlertService], (service: AlertService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
import { AlertModel } from 'app/shared/models/alert';
@Injectable()
export class AlertService {
public alertTriggered = new Subject<AlertModel>();
triggerAlert(alert: AlertModel) {
this.alertTriggered.next(alert);
}
getAlert(): Observable<AlertModel> {
return this.alertTriggered.asObservable();
}
}

View File

@ -1,12 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { ErrorsService } from './errors.service';
describe('ErrorsService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ErrorsService = TestBed.get(ErrorsService);
expect(service).toBeTruthy();
});
});

View File

@ -1,25 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
import { ErrorModel } from '../../models/error-model';
import { ERROR_TYPES } from '../../models/errors';
@Injectable({
providedIn: 'root'
})
export class ErrorsService {
errorSubject$: Subject<ErrorModel> = new Subject<ErrorModel>();
public updateError(key: ERROR_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>): void {
const errorModel = new ErrorModel(key, passedError, addition);
this.updateErrorSubject(errorModel);
}
getError(): Observable<ErrorModel> {
return this.errorSubject$.asObservable();
}
private updateErrorSubject(errorToShow: ErrorModel) {
this.errorSubject$.next(errorToShow);
}
}

View File

@ -1,9 +1,8 @@
import { NgForm, FormArray } from '@angular/forms';
import { FormArray, NgForm } from '@angular/forms';
import { Injectable } from '@angular/core';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
import { ERROR_TYPES } from '../../models/errors';
import { NOTIFICATION_TYPES } from '../../models/notifications';
import { NotificationService } from '../notifications/notification.service';
@Injectable()
export class FormsValidatorService {
@ -11,7 +10,7 @@ export class FormsValidatorService {
private workbasketOwner = 'workbasket.owner';
constructor(
private alertService: AlertService,
private notificationsService: NotificationService,
private accessIdsService: AccessIdsService
) {
}
@ -52,11 +51,12 @@ export class FormsValidatorService {
const responseOwner = new ResponseOwner(values[1]);
if (!(values[0] && responseOwner.valid)) {
if (!responseOwner.valid) {
// new Key ALERT_TYPES.WARNING_ALERT_2
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, `The ${responseOwner.field} introduced is not valid.`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.WARNING_ALERT_2,
new Map<string, string>([['owner', responseOwner.field]])
);
} else {
// new Key ALERT_TYPES.WARNING_ALERT
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'There are some empty fields which are required.'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.WARNING_ALERT);
}
}
return values[0] && responseOwner.valid;
@ -83,8 +83,10 @@ export class FormsValidatorService {
result = result && responseOwner.valid;
});
if (!result) {
// new key ALERT_TYPES.WARNING_ALERT_2
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, `The ${responseOwner.field} introduced is not valid.`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.WARNING_ALERT_2,
new Map<string, string>([['owner', responseOwner.field]])
);
}
return result;
}
@ -97,7 +99,7 @@ export class FormsValidatorService {
return true;
}
return (this.formSubmitAttempt && ngForm.form.controls[field].valid)
|| (ngForm.form.controls[field].touched && ngForm.form.controls[field].valid);
|| (ngForm.form.controls[field].touched && ngForm.form.controls[field].valid);
}
}

View File

@ -4,14 +4,14 @@ import { Observable } from 'rxjs';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { environment } from 'environments/environment';
import { tap } from 'rxjs/operators';
import { ErrorsService } from '../errors/errors.service';
import { ERROR_TYPES } from '../../models/errors';
import { NotificationService } from '../notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../models/notifications';
@Injectable()
export class HttpClientInterceptor implements HttpInterceptor {
constructor(
private requestInProgressService: RequestInProgressService,
private errorsService: ErrorsService
private errorsService: NotificationService
) {
}
@ -25,11 +25,11 @@ export class HttpClientInterceptor implements HttpInterceptor {
}, error => {
this.requestInProgressService.setRequestInProgress(false);
if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 403)) {
this.errorsService.updateError(ERROR_TYPES.ACCESS_ERR, error);
this.errorsService.triggerError(NOTIFICATION_TYPES.ACCESS_ERR, error);
} else if (error instanceof HttpErrorResponse && (error.status === 404) && error.url.indexOf('environment-information.json')) {
// ignore this error
} else {
this.errorsService.updateError(ERROR_TYPES.GENERAL_ERR, error);
this.errorsService.triggerError(NOTIFICATION_TYPES.GENERAL_ERR, error);
}
}));
}

View File

@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
import { ErrorModel } from '../../models/error-model';
import { NOTIFICATION_TYPES } from '../../models/notifications';
import { AlertModel } from '../../models/alert-model';
@Injectable({
providedIn: 'root'
})
export class NotificationService {
errorSubject$: Subject<ErrorModel> = new Subject<ErrorModel>();
alertSubject$: Subject<AlertModel> = new Subject<AlertModel>();
public triggerError(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>): void {
const errorModel = new ErrorModel(key, passedError, addition);
this.updateErrorSubject(errorModel);
}
getError(): Observable<ErrorModel> {
return this.errorSubject$.asObservable();
}
protected updateErrorSubject(errorToShow: ErrorModel) {
this.errorSubject$.next(errorToShow);
}
triggerAlert(key: NOTIFICATION_TYPES, additions?: Map<string, string>) {
const alert: AlertModel = new AlertModel(key, additions);
this.alertSubject$.next(alert);
}
getAlert(): Observable<AlertModel> {
return this.alertSubject$.asObservable();
}
}

View File

@ -0,0 +1,15 @@
import { inject, TestBed } from '@angular/core/testing';
import { NotificationService } from './notification.service';
describe('ErrorsService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [NotificationService]
});
});
it('should be created', inject([NotificationService], (service: NotificationService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -11,7 +11,6 @@ import { MapValuesPipe } from 'app/shared/pipes/map-values.pipe';
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
import { Component } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { OrientationService } from 'app/shared/services/orientation/orientation.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { DomainService } from 'app/shared/services/domain/domain.service';
@ -22,6 +21,7 @@ import { WorkplaceService } from '../../services/workplace.service';
import { TaskService } from '../../services/task.service';
import { TaskListToolbarComponent } from '../task-list-toolbar/task-list-toolbar.component';
import { TaskMasterComponent } from './task-master.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-dummy-detail',
@ -43,7 +43,7 @@ xdescribe('TaskMasterComponent', () => {
declarations: [TaskMasterComponent, TaskListToolbarComponent, SvgIconComponent,
PaginationComponent, SortComponent, FilterComponent,
SpreadNumberPipe, MapValuesPipe, IconTypeComponent, DummyDetailComponent],
providers: [TaskService, HttpClient, WorkplaceService, AlertService, OrientationService,
providers: [TaskService, HttpClient, WorkplaceService, NotificationService, OrientationService,
WorkbasketService, DomainService, RequestInProgressService, SelectedRouteService,
ComponentLoaderFactory, PositioningService, SvgIconRegistryService]
})

View File

@ -1,19 +1,20 @@
import { Component, OnDestroy, OnInit, ViewChild, ElementRef } from '@angular/core';
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Task } from 'app/workplace/models/task';
import { TaskService } from 'app/workplace/services/task.service';
import { Subscription } from 'rxjs';
import { Sorting } from 'app/shared/models/sorting';
import { Workbasket } from 'app/shared/models/workbasket';
import { Filter } from 'app/shared/models/filter';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { OrientationService } from 'app/shared/services/orientation/orientation.service';
import { Orientation } from 'app/shared/models/orientation';
import { Page } from 'app/shared/models/page';
import { map } from 'rxjs/operators';
import { ObjectReference } from '../../models/object-reference';
import { Search } from '../task-list-toolbar/task-list-toolbar.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
@Component({
selector: 'taskana-task-master',
@ -51,10 +52,11 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
private workbasketChangeSubscription: Subscription;
private orientationSubscription: Subscription;
private objectReferenceSubscription: Subscription;
constructor(
private taskService: TaskService,
private workplaceService: WorkplaceService,
private alertService: AlertService,
private notificationsService: NotificationService,
private orientationService: OrientationService
) {
this.taskChangeSubscription = this.taskService.taskChangedStream.subscribe(task => {
@ -144,25 +146,37 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
this.sort.sortBy, this.sort.sortDirection, this.filterBy.filterParams.name, this.filterBy.filterParams.owner,
this.filterBy.filterParams.priority, this.filterBy.filterParams.state, this.objectReference ? this.objectReference.type : '',
this.objectReference ? this.objectReference.value : '')
.subscribe(tasks => {
.subscribe(taskResource => {
this.requestInProgress = false;
if (tasks.tasks) {
this.tasks = tasks.tasks;
if (taskResource.tasks && taskResource.tasks.length > 1) {
this.tasks = taskResource.tasks;
} else {
this.tasks = [];
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'The selected Workbasket is empty!'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT_2);
}
this.tasksPageInformation = tasks.page;
this.tasksPageInformation = taskResource.page;
});
}
}
ngOnDestroy(): void {
if (this.taskChangeSubscription) { this.taskChangeSubscription.unsubscribe(); }
if (this.taskDeletedSubscription) { this.taskDeletedSubscription.unsubscribe(); }
if (this.workbasketChangeSubscription) { this.workbasketChangeSubscription.unsubscribe(); }
if (this.taskAddedSubscription) { this.taskAddedSubscription.unsubscribe(); }
if (this.orientationSubscription) { this.orientationSubscription.unsubscribe(); }
if (this.objectReferenceSubscription) { this.objectReferenceSubscription.unsubscribe(); }
if (this.taskChangeSubscription) {
this.taskChangeSubscription.unsubscribe();
}
if (this.taskDeletedSubscription) {
this.taskDeletedSubscription.unsubscribe();
}
if (this.workbasketChangeSubscription) {
this.workbasketChangeSubscription.unsubscribe();
}
if (this.taskAddedSubscription) {
this.taskAddedSubscription.unsubscribe();
}
if (this.orientationSubscription) {
this.orientationSubscription.unsubscribe();
}
if (this.objectReferenceSubscription) {
this.objectReferenceSubscription.unsubscribe();
}
}
}

View File

@ -8,7 +8,6 @@ import { Component } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { WorkplaceService } from '../../services/workplace.service';
import { TaskService } from '../../services/task.service';
@ -16,6 +15,7 @@ import { TaskdetailsAttributeComponent } from '../taskdetails-attribute/attribut
import { TaskdetailsCustomFieldsComponent } from '../taskdetails-custom-fields/custom-fields.component';
import { TaskdetailsGeneralFieldsComponent } from '../taskdetails-general/general-fields.component';
import { TaskdetailsComponent } from './taskdetails.component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-dummy-detail',
@ -40,7 +40,7 @@ xdescribe('TaskdetailsComponent', () => {
TaskdetailsAttributeComponent, DummyDetailComponent],
imports: [FormsModule, RouterTestingModule.withRoutes(routes), HttpClientModule],
providers: [TaskService, HttpClient, WorkplaceService, RemoveConfirmationService,
RequestInProgressService, AlertService, GeneralModalService]
RequestInProgressService, NotificationService, GeneralModalService]
})
.compileComponents();
}));

View File

@ -8,15 +8,13 @@ import { RemoveConfirmationService } from 'app/shared/services/remove-confirmati
import { Task } from 'app/workplace/models/task';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { AlertService } from 'app/shared/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/shared/models/alert';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { ObjectReference } from 'app/workplace/models/object-reference';
import { Workbasket } from 'app/shared/models/workbasket';
import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { ERROR_TYPES } from '../../../shared/models/errors';
import { ErrorsService } from '../../../shared/services/errors/errors.service';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@Component({
selector: 'taskana-task-details',
@ -43,9 +41,9 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
private router: Router,
private removeConfirmationService: RemoveConfirmationService,
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private notificationsService: NotificationService,
private generalModalService: GeneralModalService,
private errorsService: ErrorsService,
private errorsService: NotificationService,
private masterAndDetailService: MasterAndDetailService) {
}
@ -72,7 +70,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task.customAttributes = this.taskClone.customAttributes.slice(0);
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
this.task.primaryObjRef = { ...this.taskClone.primaryObjRef };
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
}
getTask(): void {
@ -87,7 +85,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.cloneTask();
this.taskService.selectTask(task);
}, error => {
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_7, error);
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_7, error);
});
}
}
@ -115,7 +113,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task = null;
this.router.navigate(['taskana/workplace/tasks']);
}, error => {
this.errorsService.updateError(ERROR_TYPES.DELETE_ERR_2, error);
this.errorsService.triggerError(NOTIFICATION_TYPES.DELETE_ERR_2, error);
});
}
@ -155,12 +153,10 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task = task;
this.cloneTask();
this.taskService.publishUpdatedTask(task);
// new Key ALERT_TYPES.SUCCESS_ALERT_14
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Updating was successful.'));
}, err => {
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT_14);
}, () => {
this.requestInProgressService.setRequestInProgress(false);
// new Key ALERT_TYPES.DANGER_ALERT
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'There was an error while updating.'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.DANGER_ALERT);
});
}
@ -169,16 +165,17 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.addDateToTask();
this.taskService.createTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
// new Key ALERT_TYPES.SUCCESS_ALERT_13
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Task ${this.currentId} was created successfully.`));
this.notificationsService.triggerAlert(
NOTIFICATION_TYPES.SUCCESS_ALERT_13,
new Map<string, string>([['taskId', task.name]])
);
this.task = task;
this.taskService.selectTask(this.task);
this.taskService.publishUpdatedTask(task);
this.router.navigate([`../${task.taskId}`], { relativeTo: this.route });
}, err => {
}, () => {
this.requestInProgressService.setRequestInProgress(false);
// new Key ALERT_TYPES.DANGER_ALERT_2
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'There was an error while creating a new task.'));
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.DANGER_ALERT_2);
});
}