TSK-1163: implemented error modal and replaced dangling error messages

since TSK-931 introduced a new error model with a corresponding service I removed all dangling error messages and replaced then with the corresponding error key
This commit is contained in:
Mustapha Zorgati 2020-03-17 10:50:44 +01:00
parent 7eab4d5f2e
commit 76c59ed3f7
32 changed files with 9397 additions and 632 deletions

8816
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormBuilder, FormArray, Validators, FormGroup, FormControl } from '@angular/forms';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { Subscription } from 'rxjs';
@ -16,7 +16,8 @@ import { AlertService } from 'app/services/alert/alert.service';
import { RequestInProgressService } from '../../services/requestInProgress/request-in-progress.service';
import { AccessIdsService } from '../../shared/services/access-ids/access-ids.service';
import { AccessIdDefinition } from '../../models/access-id';
import { ERROR_TYPES } from '../../services/general-modal/errors';
import { ErrorsService } from "../../services/errors/errors.service";
import { ERROR_TYPES } from "../../models/errors";
@Component({
selector: 'taskana-access-items-management',
@ -53,6 +54,27 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
custom11Field = this.customFieldsService.getCustomField('Custom 11', 'workbaskets.access-items.custom11');
custom12Field = this.customFieldsService.getCustomField('Custom 12', 'workbaskets.access-items.custom12');
constructor(private formBuilder: FormBuilder,
private customFieldsService: CustomFieldsService,
private accessIdsService: AccessIdsService,
private formsValidatorService: FormsValidatorService,
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private alertService: AlertService,
private generalModalService: GeneralModalService,
private errorsService: ErrorsService) {
}
get accessItemsGroups(): FormArray {
return this.AccessItemsForm ? this.AccessItemsForm.get('accessItemsGroups') as FormArray : null;
}
private static unSubscribe(subscription: Subscription): void {
if (subscription) {
subscription.unsubscribe();
}
}
setAccessItemsGroups(accessItems: Array<AccessItemWorkbasket>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
AccessItemsFormGroups.forEach(accessItemGroup => {
@ -62,24 +84,17 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
});
});
const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormGroups);
if (!this.AccessItemsForm) { this.AccessItemsForm = this.formBuilder.group({}); }
if (!this.AccessItemsForm) {
this.AccessItemsForm = this.formBuilder.group({});
}
this.AccessItemsForm.setControl('accessItemsGroups', AccessItemsFormArray);
if (!this.AccessItemsForm.value.workbasketKeyFilter) { this.AccessItemsForm.addControl('workbasketKeyFilter', new FormControl()); }
if (!this.AccessItemsForm.value.accessIdFilter) { this.AccessItemsForm.addControl('accessIdFilter', new FormControl()); }
if (!this.AccessItemsForm.value.workbasketKeyFilter) {
this.AccessItemsForm.addControl('workbasketKeyFilter', new FormControl());
}
if (!this.AccessItemsForm.value.accessIdFilter) {
this.AccessItemsForm.addControl('accessIdFilter', new FormControl());
}
get accessItemsGroups(): FormArray {
return this.AccessItemsForm ? this.AccessItemsForm.get('accessItemsGroups') as FormArray : null;
}
constructor(private formBuilder: FormBuilder,
private customFieldsService: CustomFieldsService,
private accessIdsService: AccessIdsService,
private formsValidatorService: FormsValidatorService,
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private alertService: AlertService,
private generalModalService: GeneralModalService) { }
ngOnInit() {
}
@ -93,7 +108,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
this.accessIdPrevious = selected.accessId;
this.isGroup = selected.accessId.includes(this.groupsKey);
this.unSubscribe(this.accessItemInformationsubscription);
AccessItemsManagementComponent.unSubscribe(this.accessItemInformationsubscription);
this.accessItemInformationsubscription = this.accessIdsService.getAccessItemsInformation(selected.accessId, true)
.subscribe((accessIdsWithGroups: Array<AccessIdDefinition>) => {
this.accessIdsWithGroups = accessIdsWithGroups;
@ -103,12 +118,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
// new Key: ERROR_TYPES.FETCH_ERR
error => {
this.requestInProgressService.setRequestInProgress(false);
this.generalModalService.triggerMessage(
new MessageModal(
'There was error while retrieving your access ids with groups',
error
)
);
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR, error);
});
}
}
@ -124,7 +134,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
searchForAccessItemsWorkbaskets() {
this.requestInProgressService.setRequestInProgress(true);
this.unSubscribe(this.accessItemPermissionsSubscription);
AccessItemsManagementComponent.unSubscribe(this.accessItemPermissionsSubscription);
this.accessItemPermissionsSubscription = this.accessIdsService.getAccessItemsPermissions(
this.accessIdsWithGroups,
this.AccessItemsForm ? this.AccessItemsForm.value.accessIdFilter : undefined,
@ -136,15 +146,9 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
this.setAccessItemsGroups(accessItemsResource ? accessItemsResource.accessItems : []);
this.requestInProgressService.setRequestInProgress(false);
},
// new Key: ERROR_TYPES.FETCH_ERR_2
error => {
this.requestInProgressService.setRequestInProgress(false);
this.generalModalService.triggerMessage(
new MessageModal(
'There was error while retrieving your access items',
error
)
);
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_2, error);
});
}
@ -157,6 +161,11 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
);
}
ngOnDestroy(): void {
AccessItemsManagementComponent.unSubscribe(this.accessItemPermissionsSubscription);
AccessItemsManagementComponent.unSubscribe(this.accessItemInformationsubscription);
}
private onRemoveConfirmed() {
this.requestInProgressService.setRequestInProgress(true);
this.accessIdsService.removeAccessItemsPermissions(this.accessIdSelected)
@ -173,25 +182,10 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
);
this.searchForAccessItemsWorkbaskets();
},
// new Key: ERROR_TYPES.DELETE_ERR
error => {
this.requestInProgressService.setRequestInProgress(false);
this.generalModalService.triggerMessage(
new MessageModal(
'You can\'t delete a group',
error
)
);
this.errorsService.updateError(ERROR_TYPES.DELETE_ERR, error);
}
);
}
private unSubscribe(subscription: Subscription): void {
if (subscription) { subscription.unsubscribe(); }
}
ngOnDestroy(): void {
this.unSubscribe(this.accessItemPermissionsSubscription);
this.unSubscribe(this.accessItemInformationsubscription);
}
}

View File

@ -25,7 +25,8 @@ import { NgForm } from '@angular/forms';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
import { CustomFieldsService } from '../../../services/custom-fields/custom-fields.service';
import { ERROR_TYPES } from '../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../models/errors';
import { ErrorsService } from "../../../services/errors/errors.service";
@Component({
selector: 'taskana-classification-details',
@ -81,6 +82,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private customFieldsService: CustomFieldsService,
private removeConfirmationService: RemoveConfirmationService,
private formsValidatorService: FormsValidatorService,
private errorsService: ErrorsService,
private importExportService: ImportExportService) {
}
@ -180,9 +182,8 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${classification.key} was saved successfully`));
this.afterRequest();
},
// new Key: ERROR_TYPES.CREATE_ERR
error => {
this.generalModalService.triggerMessage(new MessageModal('There was an error creating a classification', error));
this.errorsService.updateError(ERROR_TYPES.CREATE_ERR, error);
this.afterRequest();
});
} else {
@ -197,8 +198,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
);
this.cloneClassification(this.classification);
} catch (error) {
// new Key: ERROR_TYPES.SAVE_ERR
this.generalModalService.triggerMessage(new MessageModal('There was error while saving your classification', error));
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR, error);
this.afterRequest();
}
}
@ -280,10 +280,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private removeClassificationConfirmation() {
if (!this.classification || !this.classification.classificationId) {
this.generalModalService.triggerMessage(
// new Key ERROR_TYPES.SELECT_ERR
new MessageModal('There is no classification selected', 'Please check if you are creating a classification')
);
this.errorsService.updateError(ERROR_TYPES.SELECT_ERR);
return;
}
this.requestInProgressService.setRequestInProgress(true);
@ -300,8 +297,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
// new Key: ALERT_TYPES.SUCCESS_ALERT_4
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Classification ${key} was removed successfully`));
}, error => {
// new Key: ERROR_TYPES.REMOVE_ERR
this.generalModalService.triggerMessage(new MessageModal('There was error while removing your classification', error));
this.errorsService.updateError(ERROR_TYPES.REMOVE_ERR, error);
this.afterRequest();
});
}

View File

@ -13,7 +13,7 @@ import { ImportExportService } from 'app/administration/services/import-export/i
import { ClassificationDefinition } from '../../../../models/classification-definition';
import { AlertModel, AlertType } from '../../../../models/alert';
import { AlertService } from '../../../../services/alert/alert.service';
import { ERROR_TYPES } from '../../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../../models/errors';
@Component({
selector: 'taskana-classification-list',

View File

@ -10,7 +10,10 @@ import { AlertService } from 'app/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/models/alert';
import { UploadService } from 'app/shared/services/upload/upload.service';
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
import { ERROR_TYPES } from '../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../models/errors';
import { ErrorsService } from "../../../services/errors/errors.service";
import { ErrorModel } from "../../../models/error-model";
import { HttpErrorResponse } from "@angular/common/http";
@Component({
selector: 'taskana-import-export-component',
@ -20,7 +23,7 @@ import { ERROR_TYPES } from '../../../services/general-modal/errors';
export class ImportExportComponent implements OnInit {
@Input() currentSelection: TaskanaType;
@ViewChild('selectedFile', { static: true })
@ViewChild('selectedFile', {static: true})
selectedFileInput;
domains: string[] = [];
@ -33,13 +36,16 @@ export class ImportExportComponent implements OnInit {
private generalModalService: GeneralModalService,
private alertService: AlertService,
public uploadservice: UploadService,
private errorsService: ErrorsService,
private importExportService: ImportExportService
) {
}
ngOnInit() {
this.domainService.getDomains().subscribe(
data => { this.domains = data; }
data => {
this.domains = data;
}
);
}
@ -83,15 +89,11 @@ export class ImportExportComponent implements OnInit {
private checkFormatFile(file): boolean {
const ending = file.name.match(/\.([^.]+)$/)[1];
let check = false;
switch (ending) {
case 'json':
if (ending === 'json') {
check = true;
break;
default:
} else {
file.value = '';
// new Key: ERROR_TYPES.FILE_ERR
this.generalModalService.triggerMessage(new MessageModal('Wrong format',
'This file format is not allowed! Please use a .json file.'));
this.errorsService.updateError(ERROR_TYPES.FILE_ERR);
}
return check;
}
@ -105,20 +107,18 @@ export class ImportExportComponent implements OnInit {
private onReadyStateChangeHandler(event) {
if (event.readyState === 4 && event.status >= 400) {
let title;
let key: ERROR_TYPES;
if (event.status === 401) {
// new Key ERROR_TYPES.IMPORT_ERR_1
key = ERROR_TYPES.IMPORT_ERR_1;
title = 'Import was not successful, you have no access to apply this operation.';
} else if (event.status === 404) {
// new Key ERROR_TYPES.IMPORT_ERR_2
title = 'Import was not successful, operation was not found.';
key = ERROR_TYPES.IMPORT_ERR_2;
} else if (event.status === 409) {
// new Key ERROR_TYPES.IMPORT_ERR_3
title = 'Import was not successful, operation has some conflicts.';
key = ERROR_TYPES.IMPORT_ERR_3;
} else if (event.status === 413) {
// new Key ERROR_TYPES.IMPORT_ERR_4
title = 'Import was not successful, maximum file size exceeded.';
key = ERROR_TYPES.IMPORT_ERR_4;
}
this.errorHandler(title, JSON.parse(event.responseText).message);
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'));
@ -127,19 +127,12 @@ export class ImportExportComponent implements OnInit {
}
}
private onFailedResponse(event) {
// new Key ERROR_TYPES.UPLOAD_ERR
this.errorHandler('Upload failed', 'The upload didn\'t proceed sucessfully. \n'
+ 'Probably the uploaded file exceeded the maximum file size of 10 MB');
private onFailedResponse() {
this.errorHandler(ERROR_TYPES.UPLOAD_ERR);
}
private errorHandler(title = 'Import was not successful', message) {
this.generalModalService.triggerMessage(
new MessageModal(
title,
message
)
);
private errorHandler(key: ERROR_TYPES, passedError?: HttpErrorResponse) {
this.errorsService.updateError(key, passedError);
delete this.selectedFileInput.files;
this.resetProgress();
}

View File

@ -1,15 +1,17 @@
import { Component, Input, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
import { Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
import { Subscription } from 'rxjs';
import { FormBuilder, Validators, FormArray } from '@angular/forms';
import { FormArray, FormBuilder, Validators } from '@angular/forms';
import { Workbasket } from 'app/models/workbasket';
import { WorkbasketAccessItems } from 'app/models/workbasket-access-items';
import { WorkbasketAccessItemsResource } from 'app/models/workbasket-access-items-resource';
import { MessageModal } from 'app/models/message-modal';
import { ACTION } from 'app/models/action';
import { AlertModel, AlertType } from 'app/models/alert';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import {
SavingInformation,
SavingWorkbasketService
} from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { AlertService } from 'app/services/alert/alert.service';
@ -18,7 +20,8 @@ import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.se
import { highlight } from 'app/shared/animations/validation.animation';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { AccessIdDefinition } from 'app/models/access-id';
import { ERROR_TYPES } from '../../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../../models/errors';
import { ErrorsService } from "../../../../services/errors/errors.service";
@Component({
selector: 'taskana-workbasket-access-items',
@ -61,13 +64,29 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
accessItemsubscription: Subscription;
savingAccessItemsSubscription: Subscription;
AccessItemsForm = this.formBuilder.group({
accessItemsGroups: this.formBuilder.array([
])
accessItemsGroups: this.formBuilder.array([])
});
toogleValidationAccessIdMap = new Map<number, boolean>();
private initialized = false;
constructor(
private workbasketService: WorkbasketService,
private alertService: AlertService,
private generalModalService: GeneralModalService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private customFieldsService: CustomFieldsService,
private formBuilder: FormBuilder,
private formsValidatorService: FormsValidatorService,
private errorsService: ErrorsService
) {
}
get accessItemsGroups(): FormArray {
return this.AccessItemsForm.get('accessItemsGroups') as FormArray;
}
setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
AccessItemsFormGroups.forEach(accessItemGroup => {
@ -77,22 +96,6 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
this.AccessItemsForm.setControl('accessItemsGroups', AccessItemsFormArray);
}
get accessItemsGroups(): FormArray {
return this.AccessItemsForm.get('accessItemsGroups') as FormArray;
}
constructor(
private workbasketService: WorkbasketService,
private alertService: AlertService,
private generalModalService: GeneralModalService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private customFieldsService: CustomFieldsService,
private formBuilder: FormBuilder,
private formsValidatorService: FormsValidatorService
) {
}
ngOnChanges(changes: SimpleChanges): void {
if (!this.initialized && changes.active && changes.active.currentValue === 'accessItems') {
this.init();
@ -102,30 +105,6 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
}
}
private init() {
this.initialized = true;
if (!this.workbasket._links.accessItems) {
return;
}
this.requestInProgress = true;
this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href)
.subscribe((accessItemsResource: WorkbasketAccessItemsResource) => {
this.accessItemsResource = accessItemsResource;
this.setAccessItemsGroups(accessItemsResource.accessItems);
this.accessItemsClone = this.cloneAccessItems(accessItemsResource.accessItems);
this.accessItemsResetClone = this.cloneAccessItems(accessItemsResource.accessItems);
this.requestInProgress = false;
});
this.savingAccessItemsSubscription = this.savingWorkbaskets.triggeredAccessItemsSaving()
.subscribe((savingInformation: SavingInformation) => {
if (this.action === ACTION.COPY) {
this.accessItemsResource._links.self.href = savingInformation.url;
this.setWorkbasketIdForCopy(savingInformation.workbasketId);
this.onSave();
}
});
}
addAccessItem() {
const workbasketAccessItems = new WorkbasketAccessItems();
workbasketAccessItems.workbasketId = this.workbasket.workbasketId;
@ -178,6 +157,39 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
this.accessItemsGroups.controls[row].get('accessName').setValue(accessItem.name);
}
ngOnDestroy(): void {
if (this.accessItemsubscription) {
this.accessItemsubscription.unsubscribe();
}
if (this.savingAccessItemsSubscription) {
this.savingAccessItemsSubscription.unsubscribe();
}
}
private init() {
this.initialized = true;
if (!this.workbasket._links.accessItems) {
return;
}
this.requestInProgress = true;
this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket._links.accessItems.href)
.subscribe((accessItemsResource: WorkbasketAccessItemsResource) => {
this.accessItemsResource = accessItemsResource;
this.setAccessItemsGroups(accessItemsResource.accessItems);
this.accessItemsClone = this.cloneAccessItems(accessItemsResource.accessItems);
this.accessItemsResetClone = this.cloneAccessItems(accessItemsResource.accessItems);
this.requestInProgress = false;
});
this.savingAccessItemsSubscription = this.savingWorkbaskets.triggeredAccessItemsSaving()
.subscribe((savingInformation: SavingInformation) => {
if (this.action === ACTION.COPY) {
this.accessItemsResource._links.self.href = savingInformation.url;
this.setWorkbasketIdForCopy(savingInformation.workbasketId);
this.onSave();
}
});
}
private onSave() {
this.requestInProgressService.setRequestInProgress(true);
this.workbasketService.updateWorkBasketAccessItem(
@ -192,8 +204,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
));
this.requestInProgressService.setRequestInProgress(false);
}, error => {
// new Key ERROR_TYPES.SAVE_ERR_2
this.generalModalService.triggerMessage(new MessageModal('There was error while saving your workbasket\'s access items', error));
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR_2, error);
this.requestInProgressService.setRequestInProgress(false);
});
}
@ -206,7 +217,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
private cloneAccessItems(inputaccessItem): Array<WorkbasketAccessItems> {
return this.AccessItemsForm.value.accessItemsGroups.map(
(accessItems: WorkbasketAccessItems) => ({ ...accessItems })
(accessItems: WorkbasketAccessItems) => ({...accessItems})
);
}
@ -216,9 +227,4 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
element.workbasketId = workbasketId;
});
}
ngOnDestroy(): void {
if (this.accessItemsubscription) { this.accessItemsubscription.unsubscribe(); }
if (this.savingAccessItemsSubscription) { this.savingAccessItemsSubscription.unsubscribe(); }
}
}

View File

@ -18,7 +18,8 @@ import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Page } from 'app/models/page';
import { OrientationService } from 'app/services/orientation/orientation.service';
import { Orientation } from 'app/models/orientation';
import { ERROR_TYPES } from '../../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../../models/errors';
import { ErrorsService } from "../../../../services/errors/errors.service";
export enum Side {
LEFT,
@ -74,7 +75,8 @@ export class DistributionTargetsComponent implements OnChanges, OnDestroy {
private savingWorkbaskets: SavingWorkbasketService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService
private orientationService: OrientationService,
private errorsService: ErrorsService
) { }
ngOnChanges(changes: SimpleChanges): void {
@ -128,10 +130,7 @@ export class DistributionTargetsComponent implements OnChanges, OnDestroy {
return true;
},
error => {
// new Key ERROR_TYPES.SAVE_ERR_3
this.generalModalService.triggerMessage(
new MessageModal('There was error while saving your workbasket\'s distribution targets', error)
);
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR_3, error);
this.requestInProgressService.setRequestInProgress(false);
return false;
});

View File

@ -89,9 +89,9 @@ describe('WorkbasketInformationComponent', () => {
fixture.detectChanges();
expect(debugElement.querySelector('#wb-information')).toBeDefined();
expect(debugElement.querySelector('#wb-information > .panel-heading > h4').textContent.trim()).toBe('name');
expect(debugElement.querySelectorAll('#wb-information > .panel-body > form').length).toBe(1);
expect(debugElement.querySelectorAll('#wb-information > .panel-message > form').length).toBe(1);
fixture.whenStable().then(() => {
expect(debugElement.querySelector('#wb-information > .panel-body > form > div > div > input ').value).toBe('keyModified');
expect(debugElement.querySelector('#wb-information > .panel-message > form > div > div > input ').value).toBe('keyModified');
});
}));

View File

@ -18,7 +18,8 @@ import { RequestInProgressService } from 'app/services/requestInProgress/request
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { ERROR_TYPES } from '../../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../../models/errors';
import { ErrorsService } from "../../../../services/errors/errors.service";
@Component({
selector: 'taskana-workbasket-information',
@ -81,7 +82,8 @@ implements OnInit, OnChanges, OnDestroy {
private requestInProgressService: RequestInProgressService,
private customFieldsService: CustomFieldsService,
private removeConfirmationService: RemoveConfirmationService,
private formsValidatorService: FormsValidatorService
private formsValidatorService: FormsValidatorService,
private errorsService: ErrorsService
) {
this.allTypes = new Map([
['PERSONAL', 'Personal'],
@ -165,14 +167,9 @@ implements OnInit, OnChanges, OnDestroy {
);
},
error => {
// new Key ERROR_TYPES.REMOVE_ERR_2
this.generalModalService.triggerMessage(
new MessageModal(
`There was an error removing distribution target for ${
this.workbasket.workbasketId
}.`,
error
)
this.errorsService.updateError(ERROR_TYPES.REMOVE_ERR_2,
error,
new Map<String,String>([["workbasketId", this.workbasket.workbasketId]])
);
this.requestInProgressService.setRequestInProgress(false);
}
@ -203,13 +200,7 @@ implements OnInit, OnChanges, OnDestroy {
},
error => {
this.afterRequest();
// new Key ERROR_TYPES.SAVE_ERR_4
this.generalModalService.triggerMessage(
new MessageModal(
'There was error while saving your workbasket',
error
)
);
this.errorsService.updateError(ERROR_TYPES.SAVE_ERR_4, error);
}
);
}
@ -258,9 +249,7 @@ implements OnInit, OnChanges, OnDestroy {
},
error => {
// new Key ERROR_TYPES.CREATE_ERR_2
this.generalModalService.triggerMessage(
new MessageModal('There was an error creating a workbasket', error)
);
this.errorsService.updateError(ERROR_TYPES.CREATE_ERR_2, error);
this.requestInProgressService.setRequestInProgress(false);
}
);
@ -281,17 +270,11 @@ implements OnInit, OnChanges, OnDestroy {
this.requestInProgressService.setRequestInProgress(false);
this.workbasketService.triggerWorkBasketSaved();
if (response.status === 202) {
// new Key ERROR_TYPES.MARK_ERR
// TODO: message changed
this.generalModalService.triggerMessage(
new MessageModal('Workbasket was marked for deletion.',
`The Workbasket ${this.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.')
);
this.errorsService.updateError(ERROR_TYPES.MARK_ERR,
undefined,
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
} else {
// new Key ALERT_TYPES.SUCCESS_ALERT_12
// TODO: message changed
this.alertService.triggerAlert(
new AlertModel(AlertType.SUCCESS, `The Workbasket ${this.workbasket.workbasketId} has been deleted.`)
);

View File

@ -11,7 +11,8 @@ import { DomainService } from 'app/services/domain/domain.service';
import { ImportExportService } from 'app/administration/services/import-export/import-export.service';
import { GeneralModalService } from '../../../services/general-modal/general-modal.service';
import { MessageModal } from '../../../models/message-modal';
import { ERROR_TYPES } from '../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../models/errors';
import { ErrorsService } from "../../../services/errors/errors.service";
@Component({
selector: 'taskana-workbasket-details',
@ -39,6 +40,7 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
private router: Router,
private masterAndDetailService: MasterAndDetailService,
private domainService: DomainService,
private errorsService: ErrorsService,
private generalModalService: GeneralModalService,
private importExportService: ImportExportService) { }
@ -114,11 +116,8 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
this.workbasket = workbasket;
this.requestInProgress = false;
this.checkDomainAndRedirect();
}, err => {
// new Key ERROR_TYPES.FETCH_ERR_4
this.generalModalService.triggerMessage(
new MessageModal('An error occurred while fetching the workbasket', err)
);
}, error => {
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_4, error);
});
}
}

View File

@ -9,8 +9,8 @@ import { WorkbasketSummary } from 'app/models/workbasket-summary';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { TaskanaType } from 'app/models/taskana-type';
import { expandDown } from 'app/shared/animations/expand.animation';
import { ErrorsService } from '../../../../shared/services/errors/errors.service';
import { ERROR_TYPES } from '../../../../services/general-modal/errors';
import { ErrorsService } from '../../../../services/errors/errors.service';
import { ERROR_TYPES } from '../../../../models/errors';
@Component({
selector: 'taskana-workbasket-list-toolbar',

View File

@ -1,9 +1,10 @@
<taskana-nav-bar></taskana-nav-bar>
<div class="container-fluid container-main" (window:resize)="onResize($event)">
<div (window:resize)="onResize()" class="container-fluid container-main">
<div class="row ">
<router-outlet></router-outlet>
<taskana-general-message-modal *ngIf="modalMessage" [(message)]="modalMessage" [title]="modalTitle"
[type]="modalType" error="true"></taskana-general-message-modal>
<error-modal></error-modal>
<taskana-spinner [isRunning]="requestInProgress" isModal=true></taskana-spinner>
<taskana-alert></taskana-alert>
<taskana-remove-confirmation></taskana-remove-confirmation>

View File

@ -1,15 +1,17 @@
import { Component, OnInit, HostListener, OnDestroy } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { Subscription } from 'rxjs';
import {Component, HostListener, OnDestroy, OnInit} from '@angular/core';
import {NavigationStart, Router} from '@angular/router';
import {Subscription} from 'rxjs';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { MessageModal } from './models/message-modal';
import {FormsValidatorService} from 'app/shared/services/forms/forms-validator.service';
import {MessageModal} from './models/message-modal';
import { GeneralModalService } from './services/general-modal/general-modal.service';
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
import { OrientationService } from './services/orientation/orientation.service';
import { SelectedRouteService } from './services/selected-route/selected-route';
import { UploadService } from './shared/services/upload/upload.service';
import {GeneralModalService} from './services/general-modal/general-modal.service';
import {RequestInProgressService} from './services/requestInProgress/request-in-progress.service';
import {OrientationService} from './services/orientation/orientation.service';
import {SelectedRouteService} from './services/selected-route/selected-route';
import {UploadService} from './shared/services/upload/upload.service';
import {ErrorModel} from "./models/error-model";
import {ErrorsService} from "./services/errors/errors.service";
@Component({
selector: 'taskana-root',
@ -32,11 +34,7 @@ export class AppComponent implements OnInit, OnDestroy {
selectedRouteSubscription: Subscription;
routerSubscription: Subscription;
uploadingFileSubscription: Subscription;
@HostListener('window:resize', ['$event'])
onResize(event) {
this.orientationService.onResize();
}
error: ErrorModel;
constructor(
private router: Router,
@ -45,10 +43,16 @@ export class AppComponent implements OnInit, OnDestroy {
private orientationService: OrientationService,
private selectedRouteService: SelectedRouteService,
private formsValidatorService: FormsValidatorService,
private errorService: ErrorsService,
public uploadService: UploadService
) {
}
@HostListener('window:resize', ['$event'])
onResize() {
this.orientationService.onResize();
}
ngOnInit() {
this.routerSubscription = this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
@ -87,10 +91,20 @@ export class AppComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
if (this.routerSubscription) { this.routerSubscription.unsubscribe(); }
if (this.modalSubscription) { this.modalSubscription.unsubscribe(); }
if (this.requestInProgressSubscription) { this.requestInProgressSubscription.unsubscribe(); }
if (this.selectedRouteSubscription) { this.selectedRouteSubscription.unsubscribe(); }
if (this.uploadingFileSubscription) { this.uploadingFileSubscription.unsubscribe(); }
if (this.routerSubscription) {
this.routerSubscription.unsubscribe();
}
if (this.modalSubscription) {
this.modalSubscription.unsubscribe();
}
if (this.requestInProgressSubscription) {
this.requestInProgressSubscription.unsubscribe();
}
if (this.selectedRouteSubscription) {
this.selectedRouteSubscription.unsubscribe();
}
if (this.uploadingFileSubscription) {
this.uploadingFileSubscription.unsubscribe();
}
}
}

View File

@ -35,7 +35,7 @@ import { NoAccessComponent } from 'app/components/no-access/no-access.component'
import { RemoveConfirmationService } from './services/remove-confirmation/remove-confirmation.service';
import { FormsValidatorService } from './shared/services/forms/forms-validator.service';
import { UploadService } from './shared/services/upload/upload.service';
import { ErrorsService } from './shared/services/errors/errors.service';
import { ErrorsService } from './services/errors/errors.service';
/**

View File

@ -2,23 +2,20 @@ import { of } from 'rxjs';
import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { DomainService } from 'app/services/domain/domain.service';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { map, catchError } from 'rxjs/operators';
import { ERROR_TYPES } from '../services/general-modal/errors';
import { catchError, map } from 'rxjs/operators';
import { ErrorsService } from "../services/errors/errors.service";
import { ERROR_TYPES } from "../models/errors";
@Injectable()
export class DomainGuard implements CanActivate {
constructor(private domainService: DomainService, private generalModalService: GeneralModalService) { }
constructor(private domainService: DomainService, private errorsService: ErrorsService) {
}
canActivate() {
return this.domainService.getDomains().pipe(
map(domain => true),
catchError(() => {
// new Key ERROR_TYPES.FETCH_ERR_5
this.generalModalService.triggerMessage(new MessageModal(
'There was an error, please contact with your administrator', 'There was an error getting Domains'
));
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_5);
return of(false);
})
);

View File

@ -1,11 +1,10 @@
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
import { map, catchError } from 'rxjs/operators';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { ERROR_TYPES } from '../services/general-modal/errors';
import { catchError, map } from 'rxjs/operators';
import { ERROR_TYPES } from '../models/errors';
import { ErrorsService } from "../services/errors/errors.service";
@Injectable({
providedIn: 'root'
@ -14,8 +13,9 @@ export class HistoryGuard implements CanActivate {
constructor(
private taskanaEngineService: TaskanaEngineService,
public router: Router,
public generalModalService: GeneralModalService
) { }
private errorsService: ErrorsService
) {
}
canActivate(
next: ActivatedRouteSnapshot,
@ -29,10 +29,7 @@ export class HistoryGuard implements CanActivate {
return this.navigateToWorkplace();
}),
catchError(() => {
// new Key ERROR_TYPES.FETCH_ERR_6
this.generalModalService.triggerMessage(new MessageModal(
'There was an error, please contact with your administrator', 'There was an error getting history provider'
));
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_6)
return of(this.navigateToWorkplace());
})
);

View File

@ -1,16 +1,17 @@
import { Component, OnInit } from '@angular/core';
import { SortingModel, Direction } from 'app/models/sorting';
import { Direction, SortingModel } from 'app/models/sorting';
import { OrientationService } from 'app/services/orientation/orientation.service';
import { Subscription } from 'rxjs';
import { Orientation } from 'app/models/orientation';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { MessageModal } from 'app/models/message-modal';
import { FormGroup, FormControl } from '@angular/forms';
import { FormControl, FormGroup } from '@angular/forms';
import { TaskHistoryEventResourceData } from 'app/models/task-history-event-resource';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { TaskHistoryEventData } from '../../models/task-history-event';
import { TaskQueryService } from '../services/task-query/task-query.service';
import { ErrorsService } from "../../services/errors/errors.service";
@Component({
selector: 'taskana-task-query',
@ -25,15 +26,16 @@ export class TaskQueryComponent implements OnInit {
orientationSubscription: Subscription;
taskQuerySubscription: Subscription;
taskQueryForm = new FormGroup({
});
taskQueryForm = new FormGroup({});
constructor(
private taskQueryService: TaskQueryService,
private orientationService: OrientationService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService
) { }
private requestInProgressService: RequestInProgressService,
private errorsService: ErrorsService
) {
}
ngOnInit() {
this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => {
@ -168,6 +170,20 @@ export class TaskQueryComponent implements OnInit {
this.performRequest();
}
updateDate($event: string) {
this.taskQueryForm.get('created').setValue($event.substring(0, 10));
this.performRequest();
}
ngOnDestroy() {
if (this.orientationSubscription) {
this.orientationSubscription.unsubscribe();
}
if (this.taskQuerySubscription) {
this.taskQuerySubscription.unsubscribe();
}
}
private toggleSortDirection(sortDirection: string): Direction {
if (sortDirection === Direction.ASC) {
return Direction.DESC;
@ -205,14 +221,4 @@ export class TaskQueryComponent implements OnInit {
TaskanaQueryParameters.page = TaskanaQueryParameters.page ? TaskanaQueryParameters.page : 1;
TaskanaQueryParameters.pageSize = cards > 0 ? cards : 1;
}
updateDate($event: string) {
this.taskQueryForm.get('created').setValue($event.substring(0, 10));
this.performRequest();
}
onDestroy() {
if (this.orientationSubscription) { this.orientationSubscription.unsubscribe(); }
if (this.taskQuerySubscription) { this.taskQuerySubscription.unsubscribe(); }
}
}

View File

@ -1,17 +1,19 @@
import { ErrorHandler } from '@angular/core';
import { ERROR_TYPES, errors } from '../services/general-modal/errors';
import { ERROR_TYPES, errors } from './errors';
import { HttpErrorResponse } from "@angular/common/http";
export class ErrorModel {
head: string;
body: string;
errObj?: ErrorHandler;
public readonly errObj: HttpErrorResponse;
public readonly title: string;
public readonly message: string;
constructor(key: ERROR_TYPES, passedError?: ErrorHandler, addition?: string) {
this.head = errors.get(key).name;
this.body = errors.get(key).text;
if (addition) {
this.body.replace('{rep}', addition);
}
constructor(key: ERROR_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>) {
this.title = errors.get(key).name;
this.message = errors.get(key).text;
this.errObj = passedError;
if (addition) {
addition.forEach((value: string, key: string) => {
this.message.replace(`{${key}}`, value);
});
}
}
}

View File

@ -1,4 +1,4 @@
import { Pair } from '../../models/pair';
import { Pair } from './pair';
export enum ERROR_TYPES {
@ -60,33 +60,33 @@ export enum ERROR_TYPES {
export const errors = new Map<ERROR_TYPES, Pair>([
// access-items-management.component.ts
[ERROR_TYPES.FETCH_ERR, new Pair(
'',
'There was error while retrieving your access ids with groups.'
'There was error while retrieving your access ids with groups.',
''
)],
// access-items-management.component.ts
[ERROR_TYPES.FETCH_ERR_2, new Pair(
'',
'There was error while retrieving your access items '
'There was error while retrieving your access items ',
''
)],
// access-items-management.component.ts
[ERROR_TYPES.DELETE_ERR, new Pair(
'You can\'t delete a group',
'',
'You can\'t delete a group'
)],
// classification-details.component
[ERROR_TYPES.CREATE_ERR, new Pair(
'There was an error creating a classification',
'',
'There was an error creating a classification'
)],
// classification-details.component
[ERROR_TYPES.REMOVE_ERR, new Pair(
'',
'There was error while removing your classification'
'There was error while removing your classification',
''
)],
// classification-details.component
[ERROR_TYPES.SAVE_ERR, new Pair(
'',
'There was error while saving your classification'
'There was error while saving your classification',
''
)],
// classification-details.component
[ERROR_TYPES.SELECT_ERR, new Pair(
@ -95,7 +95,7 @@ export const errors = new Map<ERROR_TYPES, Pair>([
)],
// import-export.component
[ERROR_TYPES.FILE_ERR, new Pair(
'',
'Wrong format',
'This file format is not allowed! Please use a .json file.'
)],
// import-export.component
@ -131,38 +131,40 @@ export const errors = new Map<ERROR_TYPES, Pair>([
)],
// workbasket-details.component
[ERROR_TYPES.FETCH_ERR_4, new Pair(
'',
'An error occurred while fetching the workbasket'
'An error occurred while fetching the workbasket',
''
)],
// access-items.component
[ERROR_TYPES.SAVE_ERR_2, new Pair(
'',
'There was error while saving your workbasket\'s access items'
'There was error while saving your workbasket\'s access items',
''
)],
// workbaskets-distribution-targets.component
[ERROR_TYPES.SAVE_ERR_3, new Pair(
'There was error while saving your workbasket\'s distribution targets',
'',
'There was error while saving your workbasket\'s distribution targets'
)],
// workbasket-information.component
[ERROR_TYPES.REMOVE_ERR_2, new Pair(
'There was an error removing distribution target for {workbasketId}.',
'',
'There was an error removing distribution target for {this.workbasket.workbasketId}.'
)],
// workbasket-information.component
[ERROR_TYPES.SAVE_ERR_4, new Pair(
'',
'There was error while saving your workbasket'
'There was error while saving your workbasket',
''
)],
// workbasket-information.component
[ERROR_TYPES.CREATE_ERR_2, new Pair(
'',
'There was an error creating a workbasket'
'There was an error creating a workbasket',
''
)],
// workbasket-information.component
[ERROR_TYPES.MARK_ERR, new Pair(
'There was an error marking workbasket for deletion',
'It not possible to mark the workbasket for deletion, It has been deleted.'
'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(
@ -184,25 +186,20 @@ export const errors = new Map<ERROR_TYPES, Pair>([
'There was error, please contact with your administrator',
''
)],
// http-client-interceptor.service
[ERROR_TYPES.NONE, new Pair(
'',
'Error wird ignoriert, keine Message geworfen'
)],
// spinner.component
[ERROR_TYPES.TIMEOUT_ERR, new Pair(
'Request time exceeded',
'There was an error with your request, please make sure you have internet connection'
'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(
'',
'An error occurred while fetching the task'
'An error occurred while fetching the task',
''
)],
// taskdetails.component
[ERROR_TYPES.DELETE_ERR_2, new Pair(
'',
'An error occurred while deleting the task'
'An error occurred while deleting the task',
''
)],
// ALERTS
@ -272,7 +269,7 @@ export const errors = new Map<ERROR_TYPES, Pair>([
)],
// workbasket-information.component
[ERROR_TYPES.SUCCESS_ALERT_12, new Pair(
'The Workbasket {this.workbasket.workbasketId} has been marked for deletion',
'The Workbasket {workbasketId} has been deleted.',
''
)],
// forms-validator.service

View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { ErrorModel } from '../../models/error-model';
import { ERROR_TYPES } from '../../models/errors';
import { HttpErrorResponse } from "@angular/common/http";
@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,7 @@
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { MessageModal } from 'app/models/message-modal';
import { ERROR_TYPES, errors as ERRORS } from './errors';
@Injectable()
export class GeneralModalService {
private messageTriggered = new Subject<MessageModal>();

View File

@ -0,0 +1,28 @@
<div *ngIf="error">
<div class="modal-backdrop show"></div>
<div aria-labelledby="errorModalLabel"
class="modal show"
data-backdrop="static"
data-keyboard="false" role="dialog"
tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content word-break">
<div class="modal-header">
<h4 class="modal-title" id="errorModalLabel">{{error.title}}</h4>
</div>
<div class="modal-body">
<div class="alert alert-danger" role="alert">
<span class="material-icons md-20" data-toggle="tooltip">error</span>
<span class="sr-only">Error:</span>
{{error.message ? error.message : error.errObj.error.message}}
</div>
</div>
<div class="modal-footer">
<button (click)="removeMessage()" class="btn btn-default btn-danger" data-dismiss="modal"
type="button">Close
</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
.word-break {
word-break: break-word;
}

View File

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

View File

@ -0,0 +1,34 @@
import {Component, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
import {ErrorModel} from "../../models/error-model";
import {Subscription} from "rxjs";
import {ErrorsService} from "../../services/errors/errors.service";
@Component({
selector: 'error-modal',
templateUrl: './error-modal.component.html',
styleUrls: ['./error-modal.component.scss']
})
export class ErrorModalComponent implements OnInit {
error: ErrorModel;
errorsSubscription: Subscription;
constructor(private errorsService: ErrorsService) {
}
ngOnInit(): void {
this.errorsSubscription = this.errorsService.getError().subscribe((error: ErrorModel) => {
this.error = error;
});
}
removeMessage() {
delete this.error;
}
ngOnDestroy() {
if (this.errorsSubscription) {
this.errorsSubscription.unsubscribe();
}
}
}

View File

@ -1,20 +0,0 @@
import { ErrorHandler, Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { ErrorModel } from '../../../models/error-model';
import { ERROR_TYPES } from '../../../services/general-modal/errors';
@Injectable({
providedIn: 'root'
})
export class ErrorsService {
errorSubject$: Subject<ErrorModel>;
private updateErrorSubject(errorToShow: ErrorModel) {
this.errorSubject$.next(errorToShow);
}
public updateError(key: ERROR_TYPES, passedError?: ErrorHandler, addition?: string): void {
const errorModel = new ErrorModel(key, passedError, addition);
this.updateErrorSubject(errorModel);
}
}

View File

@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
import { AlertService } from 'app/services/alert/alert.service';
import { AlertModel, AlertType } from 'app/models/alert';
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
import { ERROR_TYPES } from '../../../services/general-modal/errors';
import { ERROR_TYPES } from '../../../models/errors';
@Injectable()
export class FormsValidatorService {

View File

@ -1,43 +1,35 @@
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { MessageModal } from 'app/models/message-modal';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { environment } from 'environments/environment';
import { tap } from 'rxjs/operators';
import { ERROR_TYPES } from '../../../services/general-modal/errors';
import { ErrorsService } from "../../../services/errors/errors.service";
import { ERROR_TYPES } from "../../../models/errors";
@Injectable()
export class HttpClientInterceptor implements HttpInterceptor {
constructor(
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService
private requestInProgressService: RequestInProgressService,
private errorsService: ErrorsService
) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let req = request.clone({ headers: request.headers.set('Content-Type', 'application/hal+json') });
let req = request.clone({headers: request.headers.set('Content-Type', 'application/hal+json')});
if (!environment.production) {
req = req.clone({ headers: req.headers.set('Authorization', 'Basic YWRtaW46YWRtaW4=') });
req = req.clone({headers: req.headers.set('Authorization', 'Basic YWRtaW46YWRtaW4=')});
}
return next.handle(req).pipe(tap(() => { }, error => {
return next.handle(req).pipe(tap(() => {
}, error => {
this.requestInProgressService.setRequestInProgress(false);
if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 403)) {
// new Key ERROR_TYPES.ACCESS_ERR
this.generalModalService.triggerMessage(
new MessageModal('You have no access to this resource ', error)
);
this.errorsService.updateError(ERROR_TYPES.ACCESS_ERR, error);
} else if (error instanceof HttpErrorResponse && (error.status === 404) && error.url.indexOf('environment-information.json')) {
// ignore this error message Key ERROR_TYPES.NONE
// ignore this error
} else {
// new Key ERROR_TYPES.GENERAL_ERR
this.generalModalService.triggerMessage(
new MessageModal('There was error, please contact with your administrator ', error)
);
this.errorsService.updateError(ERROR_TYPES.GENERAL_ERR, error);
}
}));
}

View File

@ -15,6 +15,7 @@ import { ClassificationsService } from 'app/shared/services/classifications/clas
* Components
*/
import { GeneralMessageModalComponent } from 'app/shared/general-message-modal/general-message-modal.component';
import { ErrorModalComponent } from "./error-message-modal/error-modal.component";
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
import { AlertComponent } from 'app/shared/alert/alert.component';
import { MasterAndDetailComponent } from 'app/shared/master-and-detail/master-and-detail.component';
@ -65,6 +66,7 @@ const MODULES = [
const DECLARATIONS = [
GeneralMessageModalComponent,
ErrorModalComponent,
SpinnerComponent,
AlertComponent,
MasterAndDetailComponent,

View File

@ -1,10 +1,6 @@
import { Component, Input, Output, EventEmitter, OnDestroy, ViewChild } from '@angular/core';
import { MessageModal } from 'app/models/message-modal';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { ERROR_TYPES } from '../../services/general-modal/errors';
import { Component, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
import { ERROR_TYPES } from '../../models/errors';
import { ErrorsService } from "../../services/errors/errors.service";
declare let $: any;
@ -15,25 +11,37 @@ declare let $: any;
styleUrls: ['./spinner.component.scss']
})
export class SpinnerComponent implements OnDestroy {
showSpinner: boolean;
@Input()
delay = 250;
@Input()
isModal = false;
@Input()
positionClass: string;
@Output()
spinnerIsRunning = new EventEmitter<boolean>();
private currentTimeout: any;
private requestTimeout: any;
private maxRequestTimeout = 10000;
@ViewChild('spinnerModal', {static: true})
private modal;
constructor(private errorsService: ErrorsService) {
}
set isDelayedRunning(value: boolean) {
this.showSpinner = value;
this.spinnerIsRunning.next(value);
}
showSpinner: boolean;
@Input()
delay = 250;
@Input()
set isRunning(value: boolean) {
if (!value) {
this.cancelTimeout();
if (this.isModal) { this.closeModal(); }
if (this.isModal) {
this.closeModal();
}
this.isDelayedRunning = false;
return;
}
@ -44,33 +52,19 @@ export class SpinnerComponent implements OnDestroy {
this.runSpinner(value);
}
@Input()
isModal = false;
@Input()
positionClass: string;
@Output()
spinnerIsRunning = new EventEmitter<boolean>();
@ViewChild('spinnerModal', { static: true })
private modal;
constructor(private generalModalService: GeneralModalService) {
ngOnDestroy(): any {
this.cancelTimeout();
}
private runSpinner(value) {
this.currentTimeout = setTimeout(() => {
if (this.isModal) { $(this.modal.nativeElement).modal('show'); }
if (this.isModal) {
$(this.modal.nativeElement).modal('show');
}
this.isDelayedRunning = value;
this.cancelTimeout();
this.requestTimeout = setTimeout(() => {
// new Key ERROR_TYPES.TIMEOUT_ERR
this.generalModalService.triggerMessage(
new MessageModal('There was an error with your request, please make sure you have internet connection',
'Request time execeed')
);
this.errorsService.updateError(ERROR_TYPES.TIMEOUT_ERR);
this.cancelTimeout();
this.isRunning = false;
}, this.maxRequestTimeout);
@ -83,15 +77,10 @@ export class SpinnerComponent implements OnDestroy {
}
}
private cancelTimeout(): void {
clearTimeout(this.currentTimeout);
clearTimeout(this.requestTimeout);
delete this.currentTimeout; // do we need this?
delete this.requestTimeout;
}
ngOnDestroy(): any {
this.cancelTimeout();
}
}

View File

@ -6,7 +6,6 @@ import { TaskService } from 'app/workplace/services/task.service';
import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import { Task } from 'app/workplace/models/task';
import { MessageModal } from 'app/models/message-modal';
import { GeneralModalService } from 'app/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { AlertService } from 'app/services/alert/alert.service';
@ -16,7 +15,8 @@ import { ObjectReference } from 'app/workplace/models/object-reference';
import { Workbasket } from 'app/models/workbasket';
import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
import { ERROR_TYPES } from '../../services/general-modal/errors';
import { ERROR_TYPES } from '../../models/errors';
import { ErrorsService } from "../../services/errors/errors.service";
@Component({
selector: 'taskana-task-details',
@ -45,6 +45,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
private requestInProgressService: RequestInProgressService,
private alertService: AlertService,
private generalModalService: GeneralModalService,
private errorsService: ErrorsService,
private masterAndDetailService: MasterAndDetailService) {
}
@ -67,10 +68,10 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
}
resetTask(): void {
this.task = { ...this.taskClone };
this.task = {...this.taskClone};
this.task.customAttributes = this.taskClone.customAttributes.slice(0);
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
this.task.primaryObjRef = { ...this.taskClone.primaryObjRef };
this.task.primaryObjRef = {...this.taskClone.primaryObjRef};
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
}
@ -85,11 +86,8 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task = task;
this.cloneTask();
this.taskService.selectTask(task);
}, err => {
// new Key ERROR_TYPES.FETCH_ERR_7
this.generalModalService.triggerMessage(
new MessageModal('An error occurred while fetching the task', err)
);
}, error => {
this.errorsService.updateError(ERROR_TYPES.FETCH_ERR_7, error);
});
}
}
@ -99,7 +97,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
}
openTask() {
this.router.navigate([{ outlets: { detail: `task/${this.currentId}` } }], { relativeTo: this.route.parent });
this.router.navigate([{outlets: {detail: `task/${this.currentId}`}}], {relativeTo: this.route.parent});
}
workOnTaskDisabled(): boolean {
@ -116,11 +114,8 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.taskService.publishUpdatedTask();
this.task = null;
this.router.navigate(['taskana/workplace/tasks']);
}, err => {
// new Key ERROR_TYPES.DELETE_ERR_2
this.generalModalService.triggerMessage(
new MessageModal('An error occurred while deleting the task ', err)
);
}, error => {
this.errorsService.updateError(ERROR_TYPES.DELETE_ERR_2, error);
});
}
@ -131,7 +126,22 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
backClicked(): void {
delete this.task;
this.taskService.selectTask(this.task);
this.router.navigate(['./'], { relativeTo: this.route.parent });
this.router.navigate(['./'], {relativeTo: this.route.parent});
}
ngOnDestroy(): void {
if (this.routeSubscription) {
this.routeSubscription.unsubscribe();
}
if (this.workbasketSubscription) {
this.workbasketSubscription.unsubscribe();
}
if (this.masterAndDetailSubscription) {
this.masterAndDetailSubscription.unsubscribe();
}
if (this.deleteTaskSubscription) {
this.deleteTaskSubscription.unsubscribe();
}
}
private onSave() {
@ -164,7 +174,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task = task;
this.taskService.selectTask(this.task);
this.taskService.publishUpdatedTask(task);
this.router.navigate([`../${task.taskId}`], { relativeTo: this.route });
this.router.navigate([`../${task.taskId}`], {relativeTo: this.route});
}, err => {
this.requestInProgressService.setRequestInProgress(false);
// new Key ALERT_TYPES.DANGER_ALERT_2
@ -179,24 +189,9 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
}
private cloneTask() {
this.taskClone = { ...this.task };
this.taskClone = {...this.task};
this.taskClone.customAttributes = this.task.customAttributes.slice(0);
this.taskClone.callbackInfo = this.task.callbackInfo.slice(0);
this.taskClone.primaryObjRef = { ...this.task.primaryObjRef };
}
ngOnDestroy(): void {
if (this.routeSubscription) {
this.routeSubscription.unsubscribe();
}
if (this.workbasketSubscription) {
this.workbasketSubscription.unsubscribe();
}
if (this.masterAndDetailSubscription) {
this.masterAndDetailSubscription.unsubscribe();
}
if (this.deleteTaskSubscription) {
this.deleteTaskSubscription.unsubscribe();
}
this.taskClone.primaryObjRef = {...this.task.primaryObjRef};
}
}