TSK-1647: Implemented global frontend error handling using backend error keys
Co-authored-by: Tristan Eisermann<19949441+Tristan2357@users.noreply.github.com> Co-authored-by: Tim Gerversmann<72377965+tge20@users.noreply.github.com> Co-authored-by: Sofie Hofmann<29145005+sofie29@users.noreply.github.com>
This commit is contained in:
parent
34d2bbfa92
commit
8edb488bd3
|
|
@ -43,12 +43,13 @@ class ServiceLevelHandler {
|
||||||
ServiceLevelHandler(
|
ServiceLevelHandler(
|
||||||
InternalTaskanaEngine taskanaEngine,
|
InternalTaskanaEngine taskanaEngine,
|
||||||
TaskMapper taskMapper,
|
TaskMapper taskMapper,
|
||||||
AttachmentMapper attachmentMapper) {
|
AttachmentMapper attachmentMapper,
|
||||||
|
TaskServiceImpl taskServiceImpl) {
|
||||||
this.taskanaEngine = taskanaEngine;
|
this.taskanaEngine = taskanaEngine;
|
||||||
this.taskMapper = taskMapper;
|
this.taskMapper = taskMapper;
|
||||||
this.attachmentMapper = attachmentMapper;
|
this.attachmentMapper = attachmentMapper;
|
||||||
converter = taskanaEngine.getEngine().getWorkingDaysToDaysConverter();
|
converter = taskanaEngine.getEngine().getWorkingDaysToDaysConverter();
|
||||||
taskServiceImpl = (TaskServiceImpl) taskanaEngine.getEngine().getTaskService();
|
this.taskServiceImpl = taskServiceImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use the same algorithm as setPlannedPropertyOfTasksImpl to refresh
|
// use the same algorithm as setPlannedPropertyOfTasksImpl to refresh
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ public class TaskServiceImpl implements TaskService {
|
||||||
this.createTaskPreprocessorManager = taskanaEngine.getCreateTaskPreprocessorManager();
|
this.createTaskPreprocessorManager = taskanaEngine.getCreateTaskPreprocessorManager();
|
||||||
this.taskTransferrer = new TaskTransferrer(taskanaEngine, taskMapper, this);
|
this.taskTransferrer = new TaskTransferrer(taskanaEngine, taskMapper, this);
|
||||||
this.taskCommentService = new TaskCommentServiceImpl(taskanaEngine, taskCommentMapper, this);
|
this.taskCommentService = new TaskCommentServiceImpl(taskanaEngine, taskCommentMapper, this);
|
||||||
this.serviceLevelHandler = new ServiceLevelHandler(taskanaEngine, taskMapper, attachmentMapper);
|
this.serviceLevelHandler =
|
||||||
|
new ServiceLevelHandler(taskanaEngine, taskMapper, attachmentMapper, this);
|
||||||
this.attachmentHandler = new AttachmentHandler(attachmentMapper, classificationService);
|
this.attachmentHandler = new AttachmentHandler(attachmentMapper, classificationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ context('TASKANA Workbaskets', () => {
|
||||||
cy.wait(Cypress.env('dropdownWait'));
|
cy.wait(Cypress.env('dropdownWait'));
|
||||||
cy.get('mat-option').contains('Clearance').click();
|
cy.get('mat-option').contains('Clearance').click();
|
||||||
cy.saveWorkbaskets();
|
cy.saveWorkbaskets();
|
||||||
|
cy.wait(3050); //wait for toasts to disappear
|
||||||
|
|
||||||
// assure that its Clearance now
|
// assure that its Clearance now
|
||||||
cy.get('mat-form-field').contains('mat-form-field', 'Type').contains('Clearance').should('be.visible');
|
cy.get('mat-form-field').contains('mat-form-field', 'Type').contains('Clearance').should('be.visible');
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
"@circlon/angular-tree-component": "11.0.4",
|
"@circlon/angular-tree-component": "11.0.4",
|
||||||
"@ngxs/store": "3.7.2",
|
"@ngxs/store": "3.7.2",
|
||||||
"angular-svg-icon": "12.0.0",
|
"angular-svg-icon": "12.0.0",
|
||||||
|
"@ngneat/hot-toast": "3.1.0",
|
||||||
|
"@ngneat/overview": "2.0.2",
|
||||||
"chart.js": "2.9.4",
|
"chart.js": "2.9.4",
|
||||||
"core-js": "3.15.1",
|
"core-js": "3.15.1",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import { ClassificationCategoriesService } from '../../../shared/services/classi
|
||||||
import { AccessItemsManagementState } from '../../../shared/store/access-items-management-store/access-items-management.state';
|
import { AccessItemsManagementState } from '../../../shared/store/access-items-management-store/access-items-management.state';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { GetAccessItems } from '../../../shared/store/access-items-management-store/access-items-management.actions';
|
import { GetAccessItems } from '../../../shared/store/access-items-management-store/access-items-management.actions';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
|
import { TypeAheadComponent } from '../../../shared/components/type-ahead/type-ahead.component';
|
||||||
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
|
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
|
||||||
|
|
@ -78,7 +77,6 @@ describe('AccessItemsManagementComponent', () => {
|
||||||
NgxsModule.forRoot([EngineConfigurationState, AccessItemsManagementState]),
|
NgxsModule.forRoot([EngineConfigurationState, AccessItemsManagementState]),
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
TypeaheadModule.forRoot(),
|
TypeaheadModule.forRoot(),
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,8 @@ export class AccessItemsManagementComponent implements OnInit {
|
||||||
|
|
||||||
revokeAccess() {
|
revokeAccess() {
|
||||||
this.notificationService.showDialog(
|
this.notificationService.showDialog(
|
||||||
`You are going to delete all access related: ${this.accessId.accessId}. Can you confirm this action?`,
|
'ACCESS_ITEM_MANAGEMENT_REVOKE_ACCESS',
|
||||||
|
{ accessId: this.accessId.accessId },
|
||||||
() => {
|
() => {
|
||||||
this.store
|
this.store
|
||||||
.dispatch(new RemoveAccessItemsPermissions(this.accessId.accessId))
|
.dispatch(new RemoveAccessItemsPermissions(this.accessId.accessId))
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
<mat-icon class="action-toolbar__aquamarine-button">content_copy</mat-icon>
|
<mat-icon class="action-toolbar__aquamarine-button">content_copy</mat-icon>
|
||||||
<span>Copy</span>
|
<span>Copy</span>
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item class="action-toolbar__dropdown" matTooltip="Delete this classification" (click)="onRemoveClassification()">
|
<button *ngIf="this.classification?.classificationId" mat-menu-item class="action-toolbar__dropdown" matTooltip="Delete this classification" (click)="onRemoveClassification()">
|
||||||
<mat-icon class="action-toolbar__red-button">delete</mat-icon>
|
<mat-icon class="action-toolbar__red-button">delete</mat-icon>
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,9 @@ const formsValidatorServiceSpy: Partial<FormsValidatorService> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const notificationServiceSpy: Partial<NotificationService> = {
|
const notificationServiceSpy: Partial<NotificationService> = {
|
||||||
showToast: jest.fn().mockReturnValue(of()),
|
showWarning: jest.fn().mockReturnValue(of()),
|
||||||
showDialog: jest.fn().mockReturnValue(of()),
|
showSuccess: jest.fn().mockReturnValue(of()),
|
||||||
triggerError: jest.fn().mockReturnValue(of())
|
showDialog: jest.fn().mockReturnValue(of())
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('ClassificationDetailsComponent', () => {
|
describe('ClassificationDetailsComponent', () => {
|
||||||
|
|
@ -157,9 +157,9 @@ describe('ClassificationDetailsComponent', () => {
|
||||||
it('should show warning when onCopy() is called and isCreatingNewClassification is true', () => {
|
it('should show warning when onCopy() is called and isCreatingNewClassification is true', () => {
|
||||||
component.isCreatingNewClassification = true;
|
component.isCreatingNewClassification = true;
|
||||||
const notificationService = TestBed.inject(NotificationService);
|
const notificationService = TestBed.inject(NotificationService);
|
||||||
const showToastSpy = jest.spyOn(notificationService, 'showToast');
|
const showWarningSpy = jest.spyOn(notificationService, 'showWarning');
|
||||||
component.onCopy();
|
component.onCopy();
|
||||||
expect(showToastSpy).toHaveBeenCalled();
|
expect(showWarningSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dispatch action when onCopy() is called and isCreatingNewClassification is false', async () => {
|
it('should dispatch action when onCopy() is called and isCreatingNewClassification is false', async () => {
|
||||||
|
|
@ -203,22 +203,6 @@ describe('ClassificationDetailsComponent', () => {
|
||||||
expect(isActionDispatched).toBe(true);
|
expect(isActionDispatched).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger an error in removeClassificationConfirmation() when classification does not exist', () => {
|
|
||||||
component.classification = undefined;
|
|
||||||
const notificationService = TestBed.inject(NotificationService);
|
|
||||||
const triggerErrorSpy = jest.spyOn(notificationService, 'triggerError');
|
|
||||||
component.removeClassificationConfirmation();
|
|
||||||
expect(triggerErrorSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should trigger an error in removeClassificationConfirmation() when classificationId does not exist', () => {
|
|
||||||
component.classification = { key: 'Key01' };
|
|
||||||
const notificationService = TestBed.inject(NotificationService);
|
|
||||||
const triggerErrorSpy = jest.spyOn(notificationService, 'triggerError');
|
|
||||||
component.removeClassificationConfirmation();
|
|
||||||
expect(triggerErrorSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should dispatch action in removeClassificationConfirmation() when classification and classificationId exist', () => {
|
it('should dispatch action in removeClassificationConfirmation() when classification and classificationId exist', () => {
|
||||||
component.classification = { classificationId: 'ID01' };
|
component.classification = { classificationId: 'ID01' };
|
||||||
const requestInProgressService = TestBed.inject(RequestInProgressService);
|
const requestInProgressService = TestBed.inject(RequestInProgressService);
|
||||||
|
|
@ -298,6 +282,16 @@ describe('ClassificationDetailsComponent', () => {
|
||||||
expect(buttonsInDropdown.length).toEqual(3);
|
expect(buttonsInDropdown.length).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not show delete button when creating or copying a Classification', () => {
|
||||||
|
component.classification.classificationId = null;
|
||||||
|
const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
|
||||||
|
expect(button).toBeTruthy();
|
||||||
|
button.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
const buttonsInDropdown = debugElement.queryAll(By.css('.action-toolbar__dropdown'));
|
||||||
|
expect(buttonsInDropdown.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
it('should call onCopy() when button is clicked', () => {
|
it('should call onCopy() when button is clicked', () => {
|
||||||
const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
|
const button = debugElement.nativeElement.querySelector('#action-toolbar__more-buttons');
|
||||||
expect(button).toBeTruthy();
|
expect(button).toBeTruthy();
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import { map, take, takeUntil } from 'rxjs/operators';
|
||||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||||
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
|
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../shared/models/customisation';
|
import { ClassificationCategoryImages, CustomField, getCustomFields } from '../../../shared/models/customisation';
|
||||||
import { Classification } from '../../../shared/models/classification';
|
import { Classification } from '../../../shared/models/classification';
|
||||||
|
|
@ -121,13 +120,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
.dispatch(new RestoreSelectedClassification(this.classification.classificationId))
|
.dispatch(new RestoreSelectedClassification(this.classification.classificationId))
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
this.notificationsService.showSuccess('CLASSIFICATION_RESTORE');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCopy() {
|
onCopy() {
|
||||||
if (this.isCreatingNewClassification) {
|
if (this.isCreatingNewClassification) {
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.WARNING_CANT_COPY);
|
this.notificationsService.showWarning('CLASSIFICATION_COPY_NOT_CREATED');
|
||||||
} else {
|
} else {
|
||||||
this.store.dispatch(new CopyClassification());
|
this.store.dispatch(new CopyClassification());
|
||||||
}
|
}
|
||||||
|
|
@ -165,27 +164,20 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
this.store
|
this.store
|
||||||
.dispatch(new SaveCreatedClassification(this.classification))
|
.dispatch(new SaveCreatedClassification(this.classification))
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(
|
.subscribe((store) => {
|
||||||
(store) => {
|
this.notificationsService.showSuccess('CLASSIFICATION_CREATE', {
|
||||||
this.notificationsService.showToast(
|
classificationKey: store.classification.selectedClassification.key
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_2,
|
});
|
||||||
new Map<string, string>([['classificationKey', store.classification.selectedClassification.key]])
|
this.location.go(
|
||||||
);
|
this.location
|
||||||
this.location.go(
|
.path()
|
||||||
this.location
|
.replace(
|
||||||
.path()
|
/(classifications).*/g,
|
||||||
.replace(
|
`classifications/(detail:${store.classification.selectedClassification.classificationId})`
|
||||||
/(classifications).*/g,
|
)
|
||||||
`classifications/(detail:${store.classification.selectedClassification.classificationId})`
|
);
|
||||||
)
|
this.afterRequest();
|
||||||
);
|
});
|
||||||
this.afterRequest();
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR, error);
|
|
||||||
this.afterRequest();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
this.store
|
this.store
|
||||||
|
|
@ -193,13 +185,11 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.afterRequest();
|
this.afterRequest();
|
||||||
this.notificationsService.showToast(
|
this.notificationsService.showSuccess('CLASSIFICATION_UPDATE', {
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_3,
|
classificationKey: this.classification.key
|
||||||
new Map<string, string>([['classificationKey', this.classification.key]])
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR, error);
|
|
||||||
this.afterRequest();
|
this.afterRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -207,26 +197,20 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
onRemoveClassification() {
|
onRemoveClassification() {
|
||||||
this.notificationsService.showDialog(
|
this.notificationsService.showDialog(
|
||||||
`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`,
|
'CLASSIFICATION_DELETE',
|
||||||
|
{ classificationKey: this.classification.key },
|
||||||
this.removeClassificationConfirmation.bind(this)
|
this.removeClassificationConfirmation.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeClassificationConfirmation() {
|
removeClassificationConfirmation() {
|
||||||
if (!this.classification || !this.classification.classificationId) {
|
|
||||||
this.notificationsService.triggerError(NOTIFICATION_TYPES.SELECT_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.requestInProgressService.setRequestInProgress(true);
|
this.requestInProgressService.setRequestInProgress(true);
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.dispatch(new RemoveSelectedClassification())
|
.dispatch(new RemoveSelectedClassification())
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.notificationsService.showToast(
|
this.notificationsService.showSuccess('CLASSIFICATION_REMOVE', { classificationKey: this.classification.key });
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_4,
|
|
||||||
new Map<string, string>([['classificationKey', this.classification.key]])
|
|
||||||
);
|
|
||||||
this.afterRequest();
|
this.afterRequest();
|
||||||
});
|
});
|
||||||
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications'));
|
this.location.go(this.location.path().replace(/(classifications).*/g, 'classifications'));
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,7 @@ xdescribe('ImportExportComponent', () => {
|
||||||
const notificationServiceSpy = jest.fn().mockImplementation(
|
const notificationServiceSpy = jest.fn().mockImplementation(
|
||||||
(): Partial<NotificationService> => ({
|
(): Partial<NotificationService> => ({
|
||||||
showDialog: showDialogFn,
|
showDialog: showDialogFn,
|
||||||
showToast: showDialogFn,
|
showSuccess: showDialogFn
|
||||||
triggerError: showDialogFn
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@ import { TaskanaType } from 'app/shared/models/taskana-type';
|
||||||
import { environment } from 'environments/environment';
|
import { environment } from 'environments/environment';
|
||||||
import { UploadService } from 'app/shared/services/upload/upload.service';
|
import { UploadService } from 'app/shared/services/upload/upload.service';
|
||||||
import { ImportExportService } from 'app/administration/services/import-export.service';
|
import { ImportExportService } from 'app/administration/services/import-export.service';
|
||||||
import { HttpErrorResponse } from '@angular/common/http';
|
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
@ -23,15 +21,13 @@ export class ImportExportComponent implements OnInit {
|
||||||
selectedFileInput;
|
selectedFileInput;
|
||||||
|
|
||||||
domains: string[] = [];
|
domains: string[] = [];
|
||||||
errorWhileUploadingText: string;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private domainService: DomainService,
|
private domainService: DomainService,
|
||||||
private workbasketDefinitionService: WorkbasketDefinitionService,
|
private workbasketDefinitionService: WorkbasketDefinitionService,
|
||||||
private classificationDefinitionService: ClassificationDefinitionService,
|
private classificationDefinitionService: ClassificationDefinitionService,
|
||||||
private notificationsService: NotificationService,
|
|
||||||
public uploadService: UploadService,
|
public uploadService: UploadService,
|
||||||
private errorsService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
private importExportService: ImportExportService
|
private importExportService: ImportExportService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -85,7 +81,7 @@ export class ImportExportComponent implements OnInit {
|
||||||
check = true;
|
check = true;
|
||||||
} else {
|
} else {
|
||||||
file.value = '';
|
file.value = '';
|
||||||
this.errorsService.triggerError(NOTIFICATION_TYPES.FILE_ERR);
|
this.notificationService.showError('IMPORT_EXPORT_UPLOAD_FILE_FORMAT');
|
||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
|
@ -98,32 +94,32 @@ export class ImportExportComponent implements OnInit {
|
||||||
|
|
||||||
private onReadyStateChangeHandler(event) {
|
private onReadyStateChangeHandler(event) {
|
||||||
if (event.readyState === 4 && event.status >= 400) {
|
if (event.readyState === 4 && event.status >= 400) {
|
||||||
let title;
|
let key = 'FALLBACK';
|
||||||
let key: NOTIFICATION_TYPES;
|
|
||||||
if (event.status === 401) {
|
if (event.status === 401) {
|
||||||
key = NOTIFICATION_TYPES.IMPORT_ERR_1;
|
key = 'IMPORT_EXPORT_UPLOAD_FAILED_AUTH';
|
||||||
title = 'Import was not successful, you have no access to apply this operation.';
|
|
||||||
} else if (event.status === 404) {
|
} else if (event.status === 404) {
|
||||||
key = NOTIFICATION_TYPES.IMPORT_ERR_2;
|
key = 'IMPORT_EXPORT_UPLOAD_FAILED_NOT_FOUND';
|
||||||
} else if (event.status === 409) {
|
} else if (event.status === 409) {
|
||||||
key = NOTIFICATION_TYPES.IMPORT_ERR_3;
|
key = 'IMPORT_EXPORT_UPLOAD_FAILED_CONFLICTS';
|
||||||
} else if (event.status === 413) {
|
} else if (event.status === 413) {
|
||||||
key = NOTIFICATION_TYPES.IMPORT_ERR_4;
|
key = 'IMPORT_EXPORT_UPLOAD_FAILED_SIZE';
|
||||||
}
|
}
|
||||||
this.errorHandler(key, event);
|
this.errorHandler(key);
|
||||||
} else if (event.readyState === 4 && event.status === 200) {
|
} else if (event.readyState === 4 && event.status === 204) {
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_6);
|
const message = this.currentSelection === TaskanaType.WORKBASKETS ? 'WORKBASKET_IMPORT' : 'CLASSIFICATION_IMPORT';
|
||||||
|
this.notificationService.showSuccess(message);
|
||||||
this.importExportService.setImportingFinished(true);
|
this.importExportService.setImportingFinished(true);
|
||||||
this.resetProgress();
|
this.resetProgress();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onFailedResponse() {
|
private onFailedResponse() {
|
||||||
this.errorHandler(NOTIFICATION_TYPES.UPLOAD_ERR);
|
this.errorHandler('IMPORT_EXPORT_UPLOAD_FAILED');
|
||||||
}
|
}
|
||||||
|
|
||||||
private errorHandler(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse) {
|
private errorHandler(key: string) {
|
||||||
this.errorsService.triggerError(key, passedError);
|
this.notificationService.showError(key);
|
||||||
delete this.selectedFileInput.files;
|
delete this.selectedFileInput.files;
|
||||||
this.resetProgress();
|
this.resetProgress();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import { Select, Store } from '@ngxs/store';
|
||||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||||
|
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { NOTIFICATION_TYPES } from 'app/shared/models/notifications';
|
|
||||||
import { NotificationService } from 'app/shared/services/notifications/notification.service';
|
import { NotificationService } from 'app/shared/services/notifications/notification.service';
|
||||||
import { Classification } from '../../../shared/models/classification';
|
import { Classification } from '../../../shared/models/classification';
|
||||||
import { ClassificationsService } from '../../../shared/services/classifications/classifications.service';
|
import { ClassificationsService } from '../../../shared/services/classifications/classifications.service';
|
||||||
|
|
@ -246,10 +245,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy
|
||||||
|
|
||||||
private updateClassification(classification: Classification) {
|
private updateClassification(classification: Classification) {
|
||||||
this.store.dispatch(new UpdateClassification(classification)).subscribe(() => {
|
this.store.dispatch(new UpdateClassification(classification)).subscribe(() => {
|
||||||
this.notificationsService.showToast(
|
this.notificationsService.showSuccess('CLASSIFICATION_MOVE', { classificationKey: classification.key });
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_5,
|
|
||||||
new Map<string, string>([['classificationKey', classification.key]])
|
|
||||||
);
|
|
||||||
this.switchTaskanaSpinner(false);
|
this.switchTaskanaSpinner(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,7 @@ const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
|
||||||
|
|
||||||
const showDialogFn = jest.fn().mockReturnValue(true);
|
const showDialogFn = jest.fn().mockReturnValue(true);
|
||||||
const notificationServiceSpy: Partial<NotificationService> = {
|
const notificationServiceSpy: Partial<NotificationService> = {
|
||||||
triggerError: showDialogFn,
|
showSuccess: showDialogFn
|
||||||
showToast: showDialogFn
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
|
const validateFormInformationFn = jest.fn().mockImplementation((): Promise<any> => Promise.resolve(true));
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import { FormsValidatorService } from 'app/shared/services/forms-validator/forms
|
||||||
import { AccessIdDefinition } from 'app/shared/models/access-id';
|
import { AccessIdDefinition } from 'app/shared/models/access-id';
|
||||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||||
import { filter, take, takeUntil, tap } from 'rxjs/operators';
|
import { filter, take, takeUntil, tap } from 'rxjs/operators';
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
|
import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../../shared/models/customisation';
|
||||||
import {
|
import {
|
||||||
|
|
@ -272,7 +271,7 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
|
||||||
this.AccessItemsForm.reset();
|
this.AccessItemsForm.reset();
|
||||||
this.setAccessItemsGroups(this.accessItemsResetClone);
|
this.setAccessItemsGroups(this.accessItemsResetClone);
|
||||||
this.accessItemsClone = this.cloneAccessItems(this.accessItemsResetClone);
|
this.accessItemsClone = this.cloneAccessItems(this.accessItemsResetClone);
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
this.notificationsService.showSuccess('WORKBASKET_ACCESS_ITEM_RESTORE');
|
||||||
}
|
}
|
||||||
|
|
||||||
isFieldValid(field: string, index: number): boolean {
|
isFieldValid(field: string, index: number): boolean {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import { WorkbasketService } from '../../../shared/services/workbasket/workbaske
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
||||||
import { SelectedRouteService } from '../../../shared/services/selected-route/selected-route';
|
import { SelectedRouteService } from '../../../shared/services/selected-route/selected-route';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { selectedWorkbasketMock, workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store';
|
import { selectedWorkbasketMock, workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store';
|
||||||
import { StartupService } from '../../../shared/services/startup/startup.service';
|
import { StartupService } from '../../../shared/services/startup/startup.service';
|
||||||
|
|
@ -83,7 +82,6 @@ describe('WorkbasketDetailsComponent', () => {
|
||||||
NgxsModule.forRoot([WorkbasketState]),
|
NgxsModule.forRoot([WorkbasketState]),
|
||||||
HttpClientTestingModule,
|
HttpClientTestingModule,
|
||||||
RouterTestingModule.withRoutes([]),
|
RouterTestingModule.withRoutes([]),
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ const workbasketServiceSpy: Partial<WorkbasketService> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const notificationsServiceSpy: Partial<NotificationService> = {
|
const notificationsServiceSpy: Partial<NotificationService> = {
|
||||||
showToast: jest.fn().mockReturnValue(true)
|
showSuccess: jest.fn().mockReturnValue(true)
|
||||||
};
|
};
|
||||||
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
|
const requestInProgressServiceSpy: Partial<RequestInProgressService> = {
|
||||||
setRequestInProgress: jest.fn().mockReturnValue(of())
|
setRequestInProgress: jest.fn().mockReturnValue(of())
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import { WorkbasketDistributionTargets } from 'app/shared/models/workbasket-dist
|
||||||
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||||
import { Actions, ofActionCompleted, Select, Store } from '@ngxs/store';
|
import { Actions, ofActionCompleted, Select, Store } from '@ngxs/store';
|
||||||
import { filter, take, takeUntil } from 'rxjs/operators';
|
import { filter, take, takeUntil } from 'rxjs/operators';
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import {
|
import {
|
||||||
GetAvailableDistributionTargets,
|
GetAvailableDistributionTargets,
|
||||||
|
|
@ -294,7 +293,7 @@ export class WorkbasketDistributionTargetsComponent implements OnInit, OnDestroy
|
||||||
}
|
}
|
||||||
|
|
||||||
onClear() {
|
onClear() {
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
this.notificationsService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_RESTORE');
|
||||||
this.availableDistributionTargets = Object.assign([], this.availableDistributionTargetsUndoClone);
|
this.availableDistributionTargets = Object.assign([], this.availableDistributionTargetsUndoClone);
|
||||||
this.availableDistributionTargetsFilterClone = Object.assign([], this.availableDistributionTargetsUndoClone);
|
this.availableDistributionTargetsFilterClone = Object.assign([], this.availableDistributionTargetsUndoClone);
|
||||||
this.selectedDistributionTargets = Object.assign([], this.selectedDistributionTargetsUndoClone);
|
this.selectedDistributionTargets = Object.assign([], this.selectedDistributionTargetsUndoClone);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
||||||
import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service';
|
import { FormsValidatorService } from '../../../shared/services/forms-validator/forms-validator.service';
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
|
import { EngineConfigurationState } from '../../../shared/store/engine-configuration-store/engine-configuration.state';
|
||||||
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
||||||
|
|
@ -79,8 +78,7 @@ const formValidatorServiceMock: Partial<FormsValidatorService> = {
|
||||||
const showDialogFn = jest.fn().mockReturnValue(true);
|
const showDialogFn = jest.fn().mockReturnValue(true);
|
||||||
const notificationServiceMock: Partial<NotificationService> = {
|
const notificationServiceMock: Partial<NotificationService> = {
|
||||||
showDialog: showDialogFn,
|
showDialog: showDialogFn,
|
||||||
showToast: showDialogFn,
|
showSuccess: showDialogFn
|
||||||
triggerError: showDialogFn
|
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('WorkbasketInformationComponent', () => {
|
describe('WorkbasketInformationComponent', () => {
|
||||||
|
|
@ -95,7 +93,6 @@ describe('WorkbasketInformationComponent', () => {
|
||||||
imports: [
|
imports: [
|
||||||
FormsModule,
|
FormsModule,
|
||||||
HttpClientTestingModule,
|
HttpClientTestingModule,
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
NgxsModule.forRoot([EngineConfigurationState, WorkbasketState]),
|
NgxsModule.forRoot([EngineConfigurationState, WorkbasketState]),
|
||||||
TypeaheadModule.forRoot(),
|
TypeaheadModule.forRoot(),
|
||||||
|
|
@ -171,9 +168,9 @@ describe('WorkbasketInformationComponent', () => {
|
||||||
it('should reset workbasket information when onUndo is called', () => {
|
it('should reset workbasket information when onUndo is called', () => {
|
||||||
component.workbasketClone = selectedWorkbasketMock;
|
component.workbasketClone = selectedWorkbasketMock;
|
||||||
const notificationService = TestBed.inject(NotificationService);
|
const notificationService = TestBed.inject(NotificationService);
|
||||||
const toastSpy = jest.spyOn(notificationService, 'showToast');
|
const showSuccessSpy = jest.spyOn(notificationService, 'showSuccess');
|
||||||
component.onUndo();
|
component.onUndo();
|
||||||
expect(toastSpy).toHaveBeenCalled();
|
expect(showSuccessSpy).toHaveBeenCalled();
|
||||||
expect(component.workbasket).toMatchObject(component.workbasketClone);
|
expect(component.workbasket).toMatchObject(component.workbasketClone);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import { RequestInProgressService } from 'app/shared/services/request-in-progres
|
||||||
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
|
||||||
import { filter, map, takeUntil } from 'rxjs/operators';
|
import { filter, map, takeUntil } from 'rxjs/operators';
|
||||||
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import { CustomField, getCustomFields, WorkbasketsCustomisation } from '../../../shared/models/customisation';
|
import { CustomField, getCustomFields, WorkbasketsCustomisation } from '../../../shared/models/customisation';
|
||||||
import {
|
import {
|
||||||
|
|
@ -136,13 +135,14 @@ export class WorkbasketInformationComponent implements OnInit, OnChanges, OnDest
|
||||||
|
|
||||||
onUndo() {
|
onUndo() {
|
||||||
this.formsValidatorService.formSubmitAttempt = false;
|
this.formsValidatorService.formSubmitAttempt = false;
|
||||||
this.notificationService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
this.notificationService.showSuccess('WORKBASKET_RESTORE');
|
||||||
this.workbasket = { ...this.workbasketClone };
|
this.workbasket = { ...this.workbasketClone };
|
||||||
}
|
}
|
||||||
|
|
||||||
removeWorkbasket() {
|
removeWorkbasket() {
|
||||||
this.notificationService.showDialog(
|
this.notificationService.showDialog(
|
||||||
`You are going to delete workbasket: ${this.workbasket.key}. Can you confirm this action?`,
|
'WORKBASKET_DELETE',
|
||||||
|
{ workbasketKey: this.workbasket.key },
|
||||||
this.onRemoveConfirmed.bind(this)
|
this.onRemoveConfirmed.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import { Direction, Sorting, WorkbasketQuerySortParameter } from '../../../share
|
||||||
import { ACTION } from '../../../shared/models/action';
|
import { ACTION } from '../../../shared/models/action';
|
||||||
import { TaskanaType } from '../../../shared/models/taskana-type';
|
import { TaskanaType } from '../../../shared/models/taskana-type';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
|
||||||
|
|
@ -59,7 +58,6 @@ describe('WorkbasketListToolbarComponent', () => {
|
||||||
NgxsModule.forRoot([WorkbasketState]),
|
NgxsModule.forRoot([WorkbasketState]),
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule
|
MatDialogModule
|
||||||
],
|
],
|
||||||
declarations: [WorkbasketListToolbarComponent, ImportExportStub, SortStub, FilterStub],
|
declarations: [WorkbasketListToolbarComponent, ImportExportStub, SortStub, FilterStub],
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
||||||
import { WorkbasketService } from '../../../shared/services/workbasket/workbasket.service';
|
import { WorkbasketService } from '../../../shared/services/workbasket/workbasket.service';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { OrientationService } from '../../../shared/services/orientation/orientation.service';
|
import { OrientationService } from '../../../shared/services/orientation/orientation.service';
|
||||||
import { ImportExportService } from '../../services/import-export.service';
|
import { ImportExportService } from '../../services/import-export.service';
|
||||||
|
|
@ -95,7 +94,6 @@ describe('WorkbasketListComponent', () => {
|
||||||
imports: [
|
imports: [
|
||||||
NgxsModule.forRoot([WorkbasketState]),
|
NgxsModule.forRoot([WorkbasketState]),
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@ import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
const showDialogFn = jest.fn().mockReturnValue(true);
|
const showDialogFn = jest.fn().mockReturnValue(true);
|
||||||
const NotificationServiceSpy: Partial<NotificationService> = {
|
const NotificationServiceSpy: Partial<NotificationService> = {
|
||||||
triggerError: showDialogFn,
|
showSuccess: showDialogFn
|
||||||
showToast: showDialogFn
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const domainServiceSpy: Partial<DomainService> = {
|
const domainServiceSpy: Partial<DomainService> = {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import { RequestInProgressService } from './shared/services/request-in-progress/
|
||||||
import { OrientationService } from './shared/services/orientation/orientation.service';
|
import { OrientationService } from './shared/services/orientation/orientation.service';
|
||||||
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
|
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
|
||||||
import { UploadService } from './shared/services/upload/upload.service';
|
import { UploadService } from './shared/services/upload/upload.service';
|
||||||
import { ErrorModel } from './shared/models/error-model';
|
|
||||||
import { TaskanaEngineService } from './shared/services/taskana-engine/taskana-engine.service';
|
import { TaskanaEngineService } from './shared/services/taskana-engine/taskana-engine.service';
|
||||||
import { WindowRefService } from 'app/shared/services/window/window.service';
|
import { WindowRefService } from 'app/shared/services/window/window.service';
|
||||||
import { environment } from 'environments/environment';
|
import { environment } from 'environments/environment';
|
||||||
|
|
@ -26,7 +25,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||||
requestInProgress = false;
|
requestInProgress = false;
|
||||||
currentProgressValue = 0;
|
currentProgressValue = 0;
|
||||||
|
|
||||||
error: ErrorModel;
|
|
||||||
version: string;
|
version: string;
|
||||||
toggle: boolean = false;
|
toggle: boolean = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,7 @@
|
||||||
<h4 class="modal-title" mat-dialog-title id="errorModalLabel">{{title}}</h4>
|
<mat-dialog-content class="mat-typography">
|
||||||
<div mat-dialog-content class="modal-body">
|
<h4> {{message}} </h4>
|
||||||
<div class="alert alert-danger" role="alert">
|
</mat-dialog-content>
|
||||||
<span class="material-icons md-20" data-toggle="tooltip">error</span>
|
<mat-dialog-actions style="justify-content: flex-end">
|
||||||
<span *ngIf="!isDialog" class="sr-only">Error:</span>
|
<button mat-dialog-close mat-stroked-button> Cancel </button>
|
||||||
{{message}}
|
<button *ngIf="isDataSpecified" [mat-dialog-close]="callback" mat-raised-button color="primary"> Delete </button>
|
||||||
</div>
|
</mat-dialog-actions>
|
||||||
</div>
|
|
||||||
<div mat-dialog-actions align="end">
|
|
||||||
<button mat-dialog-close mat-stroked-button data-dismiss="modal" type="button">
|
|
||||||
<span data-toggle="tooltip" class="material-icons md-20 red">cancel</span>
|
|
||||||
</button>
|
|
||||||
<button *ngIf="isDialog" [mat-dialog-close]="callback" mat-raised-button color="primary"
|
|
||||||
data-dismiss="modal" type="button">
|
|
||||||
<span data-toggle="tooltip" class="material-icons md-20 white">done</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1 @@
|
||||||
.alert {
|
|
||||||
color: #a94442;
|
|
||||||
background-color: #f2dede;
|
|
||||||
padding: 15px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border: 1px solid #ebccd1;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
import { notifications } from '../../models/notifications';
|
import { ObtainMessageService } from '../../services/obtain-message/obtain-message.service';
|
||||||
|
import { messageTypes } from '../../services/obtain-message/message-types';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-shared-dialog-pop-up',
|
selector: 'taskana-shared-dialog-pop-up',
|
||||||
|
|
@ -8,43 +9,19 @@ import { notifications } from '../../models/notifications';
|
||||||
styleUrls: ['./dialog-pop-up.component.scss']
|
styleUrls: ['./dialog-pop-up.component.scss']
|
||||||
})
|
})
|
||||||
export class DialogPopUpComponent implements OnInit {
|
export class DialogPopUpComponent implements OnInit {
|
||||||
title: string;
|
|
||||||
message: string;
|
message: string;
|
||||||
isDialog: false;
|
|
||||||
callback: Function;
|
callback: Function;
|
||||||
|
isDataSpecified: boolean;
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) private data: any) {}
|
constructor(@Inject(MAT_DIALOG_DATA) private data: any, private obtainMessageService: ObtainMessageService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.data) {
|
this.isDataSpecified = this.data?.message && this.data?.callback;
|
||||||
this.isDialog = this.data.isDialog;
|
if (this.isDataSpecified) {
|
||||||
if (this.isDialog) {
|
this.message = this.data.message;
|
||||||
this.initDialog();
|
this.callback = this.data.callback;
|
||||||
} else {
|
|
||||||
this.initError();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.message = 'There was an error with this PopUp. \nPlease contact your administrator.';
|
this.message = this.obtainMessageService.getMessage('POPUP_CONFIGURATION', {}, messageTypes.DIALOG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initError() {
|
|
||||||
this.title = notifications.get(this.data.key).left || '';
|
|
||||||
this.message =
|
|
||||||
notifications.get(this.data.key).right || (this.data && this.data.passedError && this.data.passedError.error)
|
|
||||||
? this.data.passedError.error.message
|
|
||||||
: '';
|
|
||||||
if (this.data.additions) {
|
|
||||||
this.data.additions.forEach((value: string, replacementKey: string) => {
|
|
||||||
this.message = this.message.replace(`{${replacementKey}}`, value);
|
|
||||||
this.title = this.title.replace(`{${replacementKey}}`, value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initDialog() {
|
|
||||||
this.message = this.data.message;
|
|
||||||
this.title = 'Please confirm your action';
|
|
||||||
this.callback = this.data.callback;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Component, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
|
||||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
|
||||||
import { NotificationService } from '../../services/notifications/notification.service';
|
import { NotificationService } from '../../services/notifications/notification.service';
|
||||||
|
|
||||||
declare let $: any;
|
declare let $: any;
|
||||||
|
|
@ -29,7 +28,7 @@ export class SpinnerComponent implements OnDestroy {
|
||||||
@ViewChild('spinnerModal', { static: true })
|
@ViewChild('spinnerModal', { static: true })
|
||||||
private modal;
|
private modal;
|
||||||
|
|
||||||
constructor(private errorsService: NotificationService) {}
|
constructor(private notificationService: NotificationService) {}
|
||||||
|
|
||||||
set isDelayedRunning(value: boolean) {
|
set isDelayedRunning(value: boolean) {
|
||||||
this.showSpinner = value;
|
this.showSpinner = value;
|
||||||
|
|
@ -62,7 +61,7 @@ export class SpinnerComponent implements OnDestroy {
|
||||||
this.isDelayedRunning = value;
|
this.isDelayedRunning = value;
|
||||||
this.cancelTimeout();
|
this.cancelTimeout();
|
||||||
this.requestTimeout = setTimeout(() => {
|
this.requestTimeout = setTimeout(() => {
|
||||||
this.errorsService.triggerError(NOTIFICATION_TYPES.TIMEOUT_ERR);
|
this.notificationService.showError('SPINNER_TIMEOUT');
|
||||||
this.cancelTimeout();
|
this.cancelTimeout();
|
||||||
this.isRunning = false;
|
this.isRunning = false;
|
||||||
}, this.maxRequestTimeout);
|
}, this.maxRequestTimeout);
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
<span id="alert-icon" class="material-icons md-20">{{ type }}</span>
|
|
||||||
{{ message }}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { Component, Inject, Input, OnInit } from '@angular/core';
|
|
||||||
import { MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar';
|
|
||||||
import { NOTIFICATION_TYPES, notifications } from '../../models/notifications';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'taskana-shared-toast',
|
|
||||||
templateUrl: './toast.component.html',
|
|
||||||
styleUrls: ['./toast.component.scss']
|
|
||||||
})
|
|
||||||
export class ToastComponent implements OnInit {
|
|
||||||
message: string;
|
|
||||||
type: string = 'info';
|
|
||||||
|
|
||||||
constructor(@Inject(MAT_SNACK_BAR_DATA) private data: any) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
if (this.data) {
|
|
||||||
this.message = notifications.get(this.data.key).right;
|
|
||||||
if (this.data.additions) {
|
|
||||||
this.data.additions.forEach((value: string, replacementKey: string) => {
|
|
||||||
this.message = this.message.replace(`{${replacementKey}}`, value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.type = NOTIFICATION_TYPES[this.data.key].split('_')[0].toLowerCase();
|
|
||||||
if (this.type === 'danger') {
|
|
||||||
this.type = 'error';
|
|
||||||
}
|
|
||||||
if (this.type === 'success') {
|
|
||||||
this.type = 'done';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.message = 'There was an error with this toast. \nPlease contact your administrator.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,18 +3,15 @@ import { CanActivate } from '@angular/router';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { DomainService } from 'app/shared/services/domain/domain.service';
|
import { DomainService } from 'app/shared/services/domain/domain.service';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
import { NotificationService } from '../services/notifications/notification.service';
|
|
||||||
import { NOTIFICATION_TYPES } from '../models/notifications';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DomainGuard implements CanActivate {
|
export class DomainGuard implements CanActivate {
|
||||||
constructor(private domainService: DomainService, private errorsService: NotificationService) {}
|
constructor(private domainService: DomainService) {}
|
||||||
|
|
||||||
canActivate() {
|
canActivate() {
|
||||||
return this.domainService.getDomains().pipe(
|
return this.domainService.getDomains().pipe(
|
||||||
map((domain) => true),
|
map(() => true),
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_5);
|
|
||||||
return of(false);
|
return of(false);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,12 @@ import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana-engine.service';
|
import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana-engine.service';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
import { NOTIFICATION_TYPES } from '../models/notifications';
|
|
||||||
import { NotificationService } from '../services/notifications/notification.service';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class HistoryGuard implements CanActivate {
|
export class HistoryGuard implements CanActivate {
|
||||||
constructor(
|
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) {}
|
||||||
private taskanaEngineService: TaskanaEngineService,
|
|
||||||
public router: Router,
|
|
||||||
private errorsService: NotificationService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
canActivate(
|
canActivate(
|
||||||
next: ActivatedRouteSnapshot,
|
next: ActivatedRouteSnapshot,
|
||||||
|
|
@ -28,7 +22,6 @@ export class HistoryGuard implements CanActivate {
|
||||||
return this.navigateToWorkplace();
|
return this.navigateToWorkplace();
|
||||||
}),
|
}),
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_6);
|
|
||||||
return of(this.navigateToWorkplace());
|
return of(this.navigateToWorkplace());
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { HttpErrorResponse } from '@angular/common/http';
|
|
||||||
import { NOTIFICATION_TYPES, notifications } from './notifications';
|
|
||||||
|
|
||||||
export class ErrorModel {
|
|
||||||
public readonly errObj: HttpErrorResponse;
|
|
||||||
public readonly title: string;
|
|
||||||
public readonly message: string;
|
|
||||||
|
|
||||||
constructor(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>) {
|
|
||||||
this.title = notifications.get(key).left;
|
|
||||||
let messageTemp = notifications.get(key).right;
|
|
||||||
this.errObj = passedError;
|
|
||||||
if (addition) {
|
|
||||||
addition.forEach((value: string, replacementKey: string) => {
|
|
||||||
messageTemp = messageTemp.replace(`{${replacementKey}}`, value);
|
|
||||||
this.title.replace(`{${replacementKey}}`, value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.message = messageTemp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,252 +0,0 @@
|
||||||
import { Pair } from './pair';
|
|
||||||
|
|
||||||
export enum NOTIFICATION_TYPES {
|
|
||||||
// ERRORS
|
|
||||||
FETCH_ERR,
|
|
||||||
FETCH_ERR_2,
|
|
||||||
FETCH_ERR_3,
|
|
||||||
FETCH_ERR_4,
|
|
||||||
FETCH_ERR_5,
|
|
||||||
FETCH_ERR_6,
|
|
||||||
FETCH_ERR_7,
|
|
||||||
DELETE_ERR,
|
|
||||||
DELETE_ERR_2,
|
|
||||||
CREATE_ERR,
|
|
||||||
CREATE_ERR_2,
|
|
||||||
REMOVE_ERR,
|
|
||||||
REMOVE_ERR_2,
|
|
||||||
SAVE_ERR,
|
|
||||||
SAVE_ERR_2,
|
|
||||||
SAVE_ERR_3,
|
|
||||||
SAVE_ERR_4,
|
|
||||||
SELECT_ERR,
|
|
||||||
FILE_ERR,
|
|
||||||
IMPORT_ERR_1,
|
|
||||||
IMPORT_ERR_2,
|
|
||||||
IMPORT_ERR_3,
|
|
||||||
IMPORT_ERR_4,
|
|
||||||
UPLOAD_ERR,
|
|
||||||
TIMEOUT_ERR,
|
|
||||||
GENERAL_ERR,
|
|
||||||
ACCESS_ERR,
|
|
||||||
MARK_ERR,
|
|
||||||
|
|
||||||
// ALERTS
|
|
||||||
// currently their names are used as a way to determine the type of the alert
|
|
||||||
// e.g. we extract from 'SUCCESS_ALERT_2' in notification.service, that this is a success alert
|
|
||||||
// and should therefore have the color green, so please __keep this in mind when refactoring__
|
|
||||||
// usages of this undocumented sideffect: notification.service.ts and toast.component.ts
|
|
||||||
INFO_ALERT,
|
|
||||||
INFO_ALERT_2,
|
|
||||||
DANGER_ALERT,
|
|
||||||
DANGER_ALERT_2,
|
|
||||||
SUCCESS_ALERT,
|
|
||||||
SUCCESS_ALERT_2,
|
|
||||||
SUCCESS_ALERT_3,
|
|
||||||
SUCCESS_ALERT_4,
|
|
||||||
SUCCESS_ALERT_5,
|
|
||||||
SUCCESS_ALERT_6,
|
|
||||||
SUCCESS_ALERT_7,
|
|
||||||
SUCCESS_ALERT_8,
|
|
||||||
SUCCESS_ALERT_9,
|
|
||||||
SUCCESS_ALERT_10,
|
|
||||||
SUCCESS_ALERT_11,
|
|
||||||
SUCCESS_ALERT_12,
|
|
||||||
SUCCESS_ALERT_13,
|
|
||||||
SUCCESS_ALERT_14,
|
|
||||||
WARNING_ALERT,
|
|
||||||
WARNING_ALERT_2,
|
|
||||||
WARNING_CANT_COPY
|
|
||||||
}
|
|
||||||
|
|
||||||
export const notifications = new Map<NOTIFICATION_TYPES, Pair<string, string>>([
|
|
||||||
// access-items-management.component.ts
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.FETCH_ERR,
|
|
||||||
{ left: 'There was an error while retrieving your access ids with groups.', right: '' }
|
|
||||||
],
|
|
||||||
// access-items-management.component.ts
|
|
||||||
[NOTIFICATION_TYPES.FETCH_ERR_2, { left: 'There was an error while retrieving your access items ', right: '' }],
|
|
||||||
// access-items-management.component.ts
|
|
||||||
[NOTIFICATION_TYPES.DELETE_ERR, { left: "You can't delete a group", right: '' }],
|
|
||||||
// classification-details.component
|
|
||||||
[NOTIFICATION_TYPES.CREATE_ERR, { left: 'There was an error while creating this classification', right: '' }],
|
|
||||||
// classification-details.component
|
|
||||||
[NOTIFICATION_TYPES.REMOVE_ERR, { left: 'There was an error while removing your classification', right: '' }],
|
|
||||||
// classification-details.component
|
|
||||||
[NOTIFICATION_TYPES.SAVE_ERR, { left: 'There was an error while saving your classification', right: '' }],
|
|
||||||
// classification-details.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SELECT_ERR,
|
|
||||||
{ left: 'There is no classification selected', right: 'Please check if you are creating a classification' }
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.FILE_ERR,
|
|
||||||
{ left: 'Wrong format', right: 'This file format is not allowed! Please use a .json file.' }
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.IMPORT_ERR_1,
|
|
||||||
{
|
|
||||||
left: 'Import was not successful',
|
|
||||||
right: 'Import was not successful, you have no access to apply this operation.'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.IMPORT_ERR_2,
|
|
||||||
{ left: 'Import was not successful', right: 'Import was not successful, operation was not found.' }
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.IMPORT_ERR_3,
|
|
||||||
{ left: 'Import was not successful', right: 'Import was not successful, operation has some conflicts.' }
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.IMPORT_ERR_4,
|
|
||||||
{ left: 'Import was not successful', right: 'Import was not successful, maximum file size exceeded.' }
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.UPLOAD_ERR,
|
|
||||||
{
|
|
||||||
left: 'Upload failed',
|
|
||||||
right: `The upload didn't proceed sucessfully.
|
|
||||||
\n The uploaded file probably exceeded the maximum file size of 10 MB.`
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.FETCH_ERR_3, { left: '', right: 'An error occurred while fetching the task' }],
|
|
||||||
// workbasket-details.component
|
|
||||||
[NOTIFICATION_TYPES.FETCH_ERR_4, { left: '', right: 'An error occurred while fetching the workbasket' }],
|
|
||||||
// access-items.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SAVE_ERR_2,
|
|
||||||
{ left: "There was an error while saving your workbasket's access items", right: '' }
|
|
||||||
],
|
|
||||||
// workbaskets-distribution-targets.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SAVE_ERR_3,
|
|
||||||
{ left: "There was an error while saving your workbasket's distribution targets", right: '' }
|
|
||||||
],
|
|
||||||
// workbasket-information.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.REMOVE_ERR_2,
|
|
||||||
{ left: 'There was an error removing distribution target for {workbasketId}.', right: '' }
|
|
||||||
],
|
|
||||||
// workbasket-information.component
|
|
||||||
[NOTIFICATION_TYPES.SAVE_ERR_4, { left: 'There was an error while saving your workbasket', right: '' }],
|
|
||||||
// workbasket-information.component
|
|
||||||
[NOTIFICATION_TYPES.CREATE_ERR_2, { left: 'There was an error while creating this workbasket', right: '' }],
|
|
||||||
// workbasket-information.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.MARK_ERR,
|
|
||||||
{
|
|
||||||
left: 'Workbasket was marked for deletion.',
|
|
||||||
right:
|
|
||||||
'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 cleared from the database.'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// domain.guard
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.FETCH_ERR_5,
|
|
||||||
{ left: 'There was an error, please contact your administrator', right: 'There was an error getting Domains' }
|
|
||||||
],
|
|
||||||
// history.guard
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.FETCH_ERR_6,
|
|
||||||
{
|
|
||||||
left: 'There was an error, please contact your administrator',
|
|
||||||
right: 'There was an error getting history provider'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// http-client-interceptor.service
|
|
||||||
[NOTIFICATION_TYPES.ACCESS_ERR, { left: 'You have no access to this resource', right: '' }],
|
|
||||||
// http-client-interceptor.service
|
|
||||||
[NOTIFICATION_TYPES.GENERAL_ERR, { left: 'There was an error, please contact your administrator', right: '' }],
|
|
||||||
// spinner.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.TIMEOUT_ERR,
|
|
||||||
{
|
|
||||||
left: 'There was an error with your request, please make sure you have internet connection',
|
|
||||||
right: 'Request time exceeded'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.FETCH_ERR_7, { left: 'An error occurred while fetching the task', right: '' }],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.DELETE_ERR_2, { left: 'An error occurred while deleting the task', right: '' }],
|
|
||||||
|
|
||||||
// ALERTS
|
|
||||||
|
|
||||||
// access-items-management.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT, { left: '', right: '{accessId} was removed successfully' }],
|
|
||||||
// classification-details.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_2,
|
|
||||||
{ left: '', right: 'Classification {classificationKey} was created successfully' }
|
|
||||||
],
|
|
||||||
// classification-details.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_3,
|
|
||||||
{ left: '', right: 'Classification {classificationKey} was saved successfully' }
|
|
||||||
],
|
|
||||||
// classification-details.component
|
|
||||||
// access-items.component
|
|
||||||
// workbasket.distribution-targets.component
|
|
||||||
// workbasket-information.component
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.INFO_ALERT, { left: '', right: 'Information restored' }],
|
|
||||||
// classification-details.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_4,
|
|
||||||
{ left: '', right: 'Classification {classificationKey} was removed successfully' }
|
|
||||||
],
|
|
||||||
// classification-list.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_5,
|
|
||||||
{ left: '', right: 'Classification {classificationKey} was moved successfully' }
|
|
||||||
],
|
|
||||||
// import-export.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_6, { left: '', right: 'Import was successful' }],
|
|
||||||
// access-items.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_7,
|
|
||||||
{ left: '', right: 'Workbasket {workbasketKey} Access items were saved successfully' }
|
|
||||||
],
|
|
||||||
// workbasket.distribution-targets.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
|
|
||||||
{ left: '', right: 'Workbasket {workbasketName} Distribution targets were saved successfully' }
|
|
||||||
],
|
|
||||||
// workbasket-information.component
|
|
||||||
[
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_9,
|
|
||||||
{ left: '', right: 'DistributionTargets for workbasketID {workbasketId} was removed successfully' }
|
|
||||||
],
|
|
||||||
// workbasket-information.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_10, { left: '', right: 'Workbasket {workbasketKey} was saved successfully' }],
|
|
||||||
// workbasket-information.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_11, { left: '', right: 'Workbasket {workbasketKey} was created successfully' }],
|
|
||||||
// workbasket-information.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_12, { left: '', right: 'The Workbasket {workbasketId} has been deleted.' }],
|
|
||||||
// forms-validator.service
|
|
||||||
[NOTIFICATION_TYPES.WARNING_ALERT, { left: '', right: 'There are some empty fields which are required.' }],
|
|
||||||
// forms-validator.service x2
|
|
||||||
[NOTIFICATION_TYPES.WARNING_ALERT_2, { left: '', right: 'The {owner} introduced is not valid.' }],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.DANGER_ALERT, { left: '', right: 'There was an error while updating.' }],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_13, { left: '', right: 'Task {taskId} was created successfully.' }],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.SUCCESS_ALERT_14, { left: '', right: 'Updating was successful.' }],
|
|
||||||
// task-details.component
|
|
||||||
[NOTIFICATION_TYPES.DANGER_ALERT_2, { left: '', right: 'There was an error while creating a new task.' }],
|
|
||||||
// task-master.component
|
|
||||||
[NOTIFICATION_TYPES.INFO_ALERT_2, { left: '', right: 'The selected Workbasket is empty!' }],
|
|
||||||
[NOTIFICATION_TYPES.WARNING_CANT_COPY, { left: '', right: "Can't copy a not created classification" }]
|
|
||||||
]);
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { FormArray, NgForm, NgModel } from '@angular/forms';
|
import { FormArray, NgForm, NgModel } from '@angular/forms';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
|
||||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
|
||||||
import { NotificationService } from '../notifications/notification.service';
|
import { NotificationService } from '../notifications/notification.service';
|
||||||
import { Observable, Subject, Subscription, timer } from 'rxjs';
|
import { Observable, Subject, Subscription, timer } from 'rxjs';
|
||||||
|
|
||||||
|
|
@ -54,12 +53,9 @@ export class FormsValidatorService {
|
||||||
const responseOwner = new ResponseOwner(values[1]);
|
const responseOwner = new ResponseOwner(values[1]);
|
||||||
if (!(values[0] && responseOwner.valid)) {
|
if (!(values[0] && responseOwner.valid)) {
|
||||||
if (!responseOwner.valid) {
|
if (!responseOwner.valid) {
|
||||||
this.notificationsService.showToast(
|
this.notificationsService.showWarning('OWNER_NOT_VALID', { owner: responseOwner.field });
|
||||||
NOTIFICATION_TYPES.WARNING_ALERT_2,
|
|
||||||
new Map<string, string>([['owner', responseOwner.field]])
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.WARNING_ALERT);
|
this.notificationsService.showWarning('EMPTY_FIELDS');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values[0] && responseOwner.valid;
|
return values[0] && responseOwner.valid;
|
||||||
|
|
@ -88,10 +84,9 @@ export class FormsValidatorService {
|
||||||
result = result && responseOwner.valid;
|
result = result && responseOwner.valid;
|
||||||
});
|
});
|
||||||
if (!result) {
|
if (!result) {
|
||||||
this.notificationsService.showToast(
|
this.notificationsService.showWarning('OWNER_NOT_VALID', {
|
||||||
NOTIFICATION_TYPES.WARNING_ALERT_2,
|
owner: responseOwner ? responseOwner.field : 'owner'
|
||||||
new Map<string, string>([['owner', responseOwner ? responseOwner.field : 'owner']])
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,13 @@ import { RequestInProgressService } from 'app/shared/services/request-in-progres
|
||||||
import { environment } from 'environments/environment';
|
import { environment } from 'environments/environment';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
import { NotificationService } from '../notifications/notification.service';
|
import { NotificationService } from '../notifications/notification.service';
|
||||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HttpClientInterceptor implements HttpInterceptor {
|
export class HttpClientInterceptor implements HttpInterceptor {
|
||||||
constructor(
|
constructor(
|
||||||
private requestInProgressService: RequestInProgressService,
|
private requestInProgressService: RequestInProgressService,
|
||||||
private errorsService: NotificationService,
|
private tokenExtractor: HttpXsrfTokenExtractor,
|
||||||
private tokenExtractor: HttpXsrfTokenExtractor
|
private notificationService: NotificationService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
|
@ -36,22 +35,16 @@ export class HttpClientInterceptor implements HttpInterceptor {
|
||||||
() => {},
|
() => {},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 403)) {
|
if (
|
||||||
this.errorsService.triggerError(NOTIFICATION_TYPES.ACCESS_ERR, error);
|
error.status !== 404 ||
|
||||||
} else if (
|
!(error instanceof HttpErrorResponse) ||
|
||||||
error instanceof HttpErrorResponse &&
|
error.url.indexOf('environment-information.json') === -1
|
||||||
error.status === 404 &&
|
|
||||||
error.url.indexOf('environment-information.json')
|
|
||||||
) {
|
) {
|
||||||
// ignore this error
|
const { key, messageVariables } = error.error.error || {
|
||||||
} else if (
|
key: 'FALLBACK',
|
||||||
(error.status === 409 && error.error.exception.endsWith('WorkbasketAccessItemAlreadyExistException')) ||
|
messageVariables: {}
|
||||||
error.error.exception.endsWith('WorkbasketAlreadyExistException') ||
|
};
|
||||||
error.error.exception.endsWith('ClassificationAlreadyExistException')
|
this.notificationService.showError(key, messageVariables);
|
||||||
) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.errorsService.triggerError(NOTIFICATION_TYPES.GENERAL_ERR, error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,71 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { HttpErrorResponse } from '@angular/common/http';
|
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
|
||||||
import { ErrorModel } from '../../models/error-model';
|
|
||||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
|
||||||
import { ToastComponent } from '../../components/toast/toast.component';
|
|
||||||
import { DialogPopUpComponent } from '../../components/popup/dialog-pop-up.component';
|
import { DialogPopUpComponent } from '../../components/popup/dialog-pop-up.component';
|
||||||
|
import { HotToastService } from '@ngneat/hot-toast';
|
||||||
|
import { ObtainMessageService } from '../obtain-message/obtain-message.service';
|
||||||
|
import { messageTypes } from '../obtain-message/message-types';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class NotificationService {
|
export class NotificationService {
|
||||||
constructor(private matSnack: MatSnackBar, private popup: MatDialog) {}
|
constructor(
|
||||||
|
private popup: MatDialog,
|
||||||
|
private toastService: HotToastService,
|
||||||
|
private obtainMessageService: ObtainMessageService
|
||||||
|
) {}
|
||||||
|
|
||||||
triggerError(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, additions?: Map<String, String>): void {
|
generateToastId(errorKey: string, messageVariables: object): string {
|
||||||
this.popup.open(DialogPopUpComponent, {
|
let id = errorKey;
|
||||||
data: { key, passedError, additions, isDialog: false },
|
for (const [replacementKey, value] of Object.entries(messageVariables)) {
|
||||||
backdropClass: 'backdrop',
|
id = id.concat(replacementKey, value);
|
||||||
position: { top: '3em' },
|
}
|
||||||
autoFocus: true,
|
return id;
|
||||||
maxWidth: '50em'
|
}
|
||||||
|
|
||||||
|
showError(errorKey: string, messageVariables: object = {}) {
|
||||||
|
this.toastService.error(this.obtainMessageService.getMessage(errorKey, messageVariables, messageTypes.ERROR), {
|
||||||
|
dismissible: true,
|
||||||
|
autoClose: false,
|
||||||
|
id: this.generateToastId(errorKey, messageVariables)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showDialog(message: string, callback?: Function): MatDialogRef<DialogPopUpComponent> {
|
showSuccess(successKey: string, messageVariables: object = {}) {
|
||||||
|
this.toastService.success(
|
||||||
|
this.obtainMessageService.getMessage(successKey, messageVariables, messageTypes.SUCCESS),
|
||||||
|
{
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showWarning(warningKey: string, messageVariables: object = {}) {
|
||||||
|
this.toastService.warning(this.obtainMessageService.getMessage(warningKey, messageVariables, messageTypes.WARNING));
|
||||||
|
}
|
||||||
|
|
||||||
|
showInformation(informationKey: string, messageVariables: object = {}) {
|
||||||
|
this.toastService.show(
|
||||||
|
`
|
||||||
|
<span class="material-icons">info</span> ${this.obtainMessageService.getMessage(
|
||||||
|
informationKey,
|
||||||
|
messageVariables,
|
||||||
|
messageTypes.INFORMATION
|
||||||
|
)}
|
||||||
|
`,
|
||||||
|
// prevents duplicated toast because of double call in task-master
|
||||||
|
// TODO: delete while frontend refactoring
|
||||||
|
{ id: 'empty-workbasket' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showDialog(key: string, messageVariables: object = {}, callback: Function) {
|
||||||
|
const message = this.obtainMessageService.getMessage(key, messageVariables, messageTypes.DIALOG);
|
||||||
|
|
||||||
const ref = this.popup.open(DialogPopUpComponent, {
|
const ref = this.popup.open(DialogPopUpComponent, {
|
||||||
data: { isDialog: true, message, callback },
|
data: { message: message, callback },
|
||||||
backdropClass: 'backdrop',
|
backdropClass: 'backdrop',
|
||||||
position: { top: '3em' },
|
position: { top: '5em' },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
maxWidth: '50em'
|
maxWidth: '50em'
|
||||||
});
|
});
|
||||||
|
|
@ -39,30 +76,4 @@ export class NotificationService {
|
||||||
});
|
});
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast(key: NOTIFICATION_TYPES, additions?: Map<string, string>) {
|
|
||||||
let colorClass: string[];
|
|
||||||
const type = NOTIFICATION_TYPES[key].split('_')[0].toLowerCase();
|
|
||||||
switch (type) {
|
|
||||||
case 'danger':
|
|
||||||
colorClass = ['red', 'background-white'];
|
|
||||||
break;
|
|
||||||
case 'success':
|
|
||||||
colorClass = ['white', 'background-bluegreen'];
|
|
||||||
break;
|
|
||||||
case 'info':
|
|
||||||
colorClass = ['white', 'background-darkgreen'];
|
|
||||||
break;
|
|
||||||
case 'warning':
|
|
||||||
colorClass = ['brown', 'background-white'];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
colorClass = ['white', 'background-darkgreen'];
|
|
||||||
}
|
|
||||||
return this.matSnack.openFromComponent(ToastComponent, {
|
|
||||||
duration: 5000,
|
|
||||||
data: { key, additions },
|
|
||||||
panelClass: colorClass
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { messageTypes } from './message-types';
|
||||||
|
|
||||||
|
export const messageByErrorCode = {
|
||||||
|
[messageTypes.ERROR]: {
|
||||||
|
FALLBACK:
|
||||||
|
'An error occurred, but there is no error code. Please contact your administrator to specify the error code.',
|
||||||
|
CRITICAL_SYSTEM_ERROR: 'A system error occurred. Please contact your administrator.',
|
||||||
|
UNKNOWN_ERROR: 'An unknown error occurred. Please contact your administrator.',
|
||||||
|
|
||||||
|
ENTITY_NOT_UP_TO_DATE:
|
||||||
|
'Cannot be saved because there has been a modification while editing. Please reload to get the current version.',
|
||||||
|
DOMAIN_NOT_FOUND: 'Domain {domain} cannot be found',
|
||||||
|
ROLE_MISMATCHED: 'Current user {currentUserId} is not authorized. User must be member of role(s) {roles}.',
|
||||||
|
SPINNER_TIMEOUT: 'Request time exceeded. Please make sure you have internet connection.',
|
||||||
|
HISTORY_EVENT_NOT_FOUND: 'History Event with id {historyEventId} cannot be found',
|
||||||
|
PAYLOAD_TOO_LARGE: 'Maximum upload size was exceeded',
|
||||||
|
CLASSIFICATION_SERVICE_LEVEL_MALFORMED:
|
||||||
|
'Service level {serviceLevel} of Classification with key {classificationKey} and domain {domain} is invalid. ' +
|
||||||
|
'The service level has to be a positive ISO-8601 duration format and only whole days are supported. ' +
|
||||||
|
"The format must be 'PnD'.",
|
||||||
|
INVALID_ARGUMENT: 'A method was called with an invalid argument.',
|
||||||
|
|
||||||
|
CLASSIFICATION_IN_USE:
|
||||||
|
'Classification with key {classificationKey} in domain {domain} cannot be deleted since there are Tasks associated with this Classification.',
|
||||||
|
CLASSIFICATION_ALREADY_EXISTS:
|
||||||
|
'Classification with key {classificationKey} cannot be saved since a Classification with the same key already exists in domain {domain}',
|
||||||
|
CLASSIFICATION_WITH_ID_NOT_FOUND: 'Classification with id {classificationId} cannot be found',
|
||||||
|
|
||||||
|
WORKBASKET_WITH_ID_NOT_FOUND: 'Workbasket with id {workbasketId} cannot be found',
|
||||||
|
WORKBASKET_WITH_KEY_NOT_FOUND: 'Workbasket with key {workbasketKey} cannot be found in domain {domain}',
|
||||||
|
WORKBASKET_ALREADY_EXISTS:
|
||||||
|
'Workbasket with key {workbasketKey} cannot be saved since a Workbasket with the same key already exists in domain {domain}',
|
||||||
|
WORKBASKET_IN_USE: 'Workbasket with id {workbasketId} cannot be deleted since it contains non-completed Tasks',
|
||||||
|
WORKBASKET_ACCESS_ITEM_ALREADY_EXISTS:
|
||||||
|
'Workbasket Access Item with access id {accessId} for Workbasket with id {workbasketId} cannot be created since it already exists',
|
||||||
|
WORKBASKET_WITH_ID_MISMATCHED_PERMISSION:
|
||||||
|
'Current user {currentUserId} has no permission for Workbasket with id {workbasketId}. Required permission(s): {requiredPermissions}.',
|
||||||
|
WORKBASKET_WITH_KEY_MISMATCHED_PERMISSION:
|
||||||
|
'Current user {currentUserId} has no permission for Workbasket with key {workbasketKey}. Required permission(s): {requiredPermissions}.',
|
||||||
|
|
||||||
|
TASK_ALREADY_EXISTS:
|
||||||
|
'Task with external id {externalTaskId} cannot be created, because a Task with the same external id already exists.',
|
||||||
|
TASK_NOT_FOUND: 'Task with id {taskId} cannot be found',
|
||||||
|
TASK_INVALID_CALLBACK_STATE:
|
||||||
|
'Callback state {taskCallbackState} for Task with id {taskId} is invalid. Required callback states: {requiredCallbackStates}',
|
||||||
|
TASK_INVALID_OWNER: 'Current user {currentUserId} is not the owner of the Task with id {taskId}',
|
||||||
|
TASK_INVALID_STATE: 'Task with id {taskId} is in state {taskState}. Required state(s): {requiredTaskStates}.',
|
||||||
|
|
||||||
|
IMPORT_EXPORT_UPLOAD_FAILED: 'Upload failed. The uploaded file probably exceeded the maximum file size of 10 MB.',
|
||||||
|
IMPORT_EXPORT_UPLOAD_FAILED_AUTH: 'Upload failed because you have no access to apply this operation.',
|
||||||
|
IMPORT_EXPORT_UPLOAD_FAILED_NOT_FOUND: 'Upload failed because operation was not found',
|
||||||
|
IMPORT_EXPORT_UPLOAD_FAILED_CONFLICTS: 'Upload failed because operation has conflicts',
|
||||||
|
IMPORT_EXPORT_UPLOAD_FAILED_SIZE: 'Upload failed because maximum file size exceeded',
|
||||||
|
IMPORT_EXPORT_UPLOAD_FILE_FORMAT: 'File format is not allowed. Please use a .json file.'
|
||||||
|
},
|
||||||
|
|
||||||
|
[messageTypes.SUCCESS]: {
|
||||||
|
FALLBACK:
|
||||||
|
'Action was completed successfully, but this success message was not configured properly. ' +
|
||||||
|
'Please ask your administrator to configure this message.',
|
||||||
|
|
||||||
|
CLASSIFICATION_CREATE: 'Classification with key {classificationKey} was created',
|
||||||
|
CLASSIFICATION_UPDATE: 'Classification with key {classificationKey} was updated',
|
||||||
|
CLASSIFICATION_REMOVE: 'Classification with key {classificationKey} was removed',
|
||||||
|
CLASSIFICATION_MOVE: 'Classification with key {classificationKey} was moved',
|
||||||
|
CLASSIFICATION_RESTORE: 'Classification restored',
|
||||||
|
CLASSIFICATION_IMPORT: 'Classifications imported',
|
||||||
|
|
||||||
|
WORKBASKET_CREATE: 'Workbasket with key {workbasketKey} was created',
|
||||||
|
WORKBASKET_UPDATE: 'Workbasket with key {workbasketKey} was updated',
|
||||||
|
WORKBASKET_REMOVE: 'Workbasket with key {workbasketKey} was removed',
|
||||||
|
WORKBASKET_RESTORE: 'Workbasket restored',
|
||||||
|
WORKBASKET_IMPORT: 'Workbaskets imported',
|
||||||
|
WORKBASKET_ACCESS_ITEM_SAVE: 'Workbasket Access Items were saved',
|
||||||
|
WORKBASKET_ACCESS_ITEM_RESTORE: 'Workbasket Access Items restored',
|
||||||
|
WORKBASKET_DISTRIBUTION_TARGET_SAVE: 'Workbasket Distribution Targets were saved',
|
||||||
|
WORKBASKET_DISTRIBUTION_TARGET_RESTORE: 'Workbasket Distribution Targets restored',
|
||||||
|
WORKBASKET_DISTRIBUTION_TARGET_REMOVE:
|
||||||
|
'Workbasket with key {workbasketKey} was removed as Workbasket Distribution Target',
|
||||||
|
WORKBASKET_ACCESS_ITEM_REMOVE_PERMISSION: '{accessId} was removed',
|
||||||
|
|
||||||
|
TASK_CREATE: 'Task with name {taskName} was created',
|
||||||
|
TASK_UPDATE: 'Task with name {taskName} was updated',
|
||||||
|
TASK_DELETE: 'Task with name {taskName} was deleted',
|
||||||
|
TASK_RESTORE: 'Task restored'
|
||||||
|
},
|
||||||
|
|
||||||
|
[messageTypes.WARNING]: {
|
||||||
|
CLASSIFICATION_COPY_NOT_CREATED: 'Cannot copy a not created Classification',
|
||||||
|
EMPTY_FIELDS: 'There are empty fields which are required',
|
||||||
|
OWNER_NOT_VALID: 'The {owner} introduced is not valid'
|
||||||
|
},
|
||||||
|
|
||||||
|
[messageTypes.INFORMATION]: {
|
||||||
|
EMPTY_WORKBASKET: 'Selected Workbasket is empty'
|
||||||
|
},
|
||||||
|
|
||||||
|
[messageTypes.DIALOG]: {
|
||||||
|
POPUP_CONFIGURATION: 'This Popup was not configured properly for this request. Please contact your administrator.',
|
||||||
|
|
||||||
|
WORKBASKET_DELETE: 'Delete Workbasket with key {workbasketKey}?',
|
||||||
|
CLASSIFICATION_DELETE: 'Delete Classification with key {classificationKey}?',
|
||||||
|
TASK_DELETE: 'Delete Task with id {taskId}?',
|
||||||
|
ACCESS_ITEM_MANAGEMENT_REVOKE_ACCESS: 'Delete all access related to {accessId}?'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
export enum messageTypes {
|
||||||
|
ERROR,
|
||||||
|
SUCCESS,
|
||||||
|
WARNING,
|
||||||
|
INFORMATION,
|
||||||
|
DIALOG
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { messageByErrorCode } from './message-by-error-code';
|
||||||
|
import { messageTypes } from './message-types';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ObtainMessageService {
|
||||||
|
getMessage(key: string, messageVariables: object = {}, type: messageTypes): string {
|
||||||
|
let message =
|
||||||
|
messageByErrorCode[type][key] ||
|
||||||
|
messageByErrorCode[type]['FALLBACK'] ||
|
||||||
|
`The message with type '${type}' and key '${key}' is not configured`;
|
||||||
|
|
||||||
|
for (const [replacementKey, value] of Object.entries(messageVariables)) {
|
||||||
|
message = message.replace(`{${replacementKey}}`, `'${value}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import { TreeModule } from '@circlon/angular-tree-component';
|
||||||
import { AlertModule } from 'ngx-bootstrap/alert';
|
import { AlertModule } from 'ngx-bootstrap/alert';
|
||||||
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
|
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
|
||||||
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
||||||
|
import { HotToastModule } from '@ngneat/hot-toast';
|
||||||
import { AccordionModule } from 'ngx-bootstrap/accordion';
|
import { AccordionModule } from 'ngx-bootstrap/accordion';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -20,7 +20,6 @@ import { TaskanaTreeComponent } from 'app/administration/components/tree/tree.co
|
||||||
import { TypeAheadComponent } from 'app/shared/components/type-ahead/type-ahead.component';
|
import { TypeAheadComponent } from 'app/shared/components/type-ahead/type-ahead.component';
|
||||||
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
|
import { IconTypeComponent } from 'app/administration/components/type-icon/icon-type.component';
|
||||||
import { FieldErrorDisplayComponent } from 'app/shared/components/field-error-display/field-error-display.component';
|
import { FieldErrorDisplayComponent } from 'app/shared/components/field-error-display/field-error-display.component';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatRadioModule } from '@angular/material/radio';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
|
|
@ -43,7 +42,6 @@ import { DateTimeZonePipe } from './pipes/date-time-zone.pipe';
|
||||||
* Services
|
* Services
|
||||||
*/
|
*/
|
||||||
import { HttpClientInterceptor } from './services/http-client-interceptor/http-client-interceptor.service';
|
import { HttpClientInterceptor } from './services/http-client-interceptor/http-client-interceptor.service';
|
||||||
import { ToastComponent } from './components/toast/toast.component';
|
|
||||||
import { DialogPopUpComponent } from './components/popup/dialog-pop-up.component';
|
import { DialogPopUpComponent } from './components/popup/dialog-pop-up.component';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
|
@ -56,6 +54,10 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { WorkbasketFilterComponent } from './components/workbasket-filter/workbasket-filter.component';
|
import { WorkbasketFilterComponent } from './components/workbasket-filter/workbasket-filter.component';
|
||||||
import { TaskFilterComponent } from './components/task-filter/task-filter.component';
|
import { TaskFilterComponent } from './components/task-filter/task-filter.component';
|
||||||
|
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
|
||||||
|
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
|
||||||
|
import { ObtainMessageService } from './services/obtain-message/obtain-message.service';
|
||||||
|
import { AccessIdsService } from './services/access-ids/access-ids.service';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
|
@ -66,12 +68,16 @@ const MODULES = [
|
||||||
BsDatepickerModule.forRoot(),
|
BsDatepickerModule.forRoot(),
|
||||||
AngularSvgIconModule,
|
AngularSvgIconModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
TreeModule,
|
TreeModule,
|
||||||
MatAutocompleteModule
|
MatAutocompleteModule,
|
||||||
|
HotToastModule.forRoot({
|
||||||
|
style: {
|
||||||
|
'max-width': '520px'
|
||||||
|
}
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
|
|
@ -91,7 +97,6 @@ const DECLARATIONS = [
|
||||||
FieldErrorDisplayComponent,
|
FieldErrorDisplayComponent,
|
||||||
PaginationComponent,
|
PaginationComponent,
|
||||||
ProgressSpinnerComponent,
|
ProgressSpinnerComponent,
|
||||||
ToastComponent,
|
|
||||||
DialogPopUpComponent,
|
DialogPopUpComponent,
|
||||||
WorkbasketFilterComponent,
|
WorkbasketFilterComponent,
|
||||||
TaskFilterComponent
|
TaskFilterComponent
|
||||||
|
|
@ -118,8 +123,12 @@ const DECLARATIONS = [
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
useClass: HttpClientInterceptor,
|
useClass: HttpClientInterceptor,
|
||||||
multi: true
|
multi: true
|
||||||
}
|
},
|
||||||
|
AccessIdsService,
|
||||||
|
ClassificationsService,
|
||||||
|
WorkbasketService,
|
||||||
|
ObtainMessageService
|
||||||
],
|
],
|
||||||
entryComponents: [DialogPopUpComponent, ToastComponent]
|
entryComponents: [DialogPopUpComponent]
|
||||||
})
|
})
|
||||||
export class SharedModule {}
|
export class SharedModule {}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { Observable, of } from 'rxjs';
|
||||||
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
||||||
import { take, tap } from 'rxjs/operators';
|
import { take, tap } from 'rxjs/operators';
|
||||||
import { AccessIdDefinition } from '../../models/access-id';
|
import { AccessIdDefinition } from '../../models/access-id';
|
||||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
|
||||||
import { NotificationService } from '../../services/notifications/notification.service';
|
import { NotificationService } from '../../services/notifications/notification.service';
|
||||||
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
|
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
|
||||||
import { RequestInProgressService } from '../../services/request-in-progress/request-in-progress.service';
|
import { RequestInProgressService } from '../../services/request-in-progress/request-in-progress.service';
|
||||||
|
|
@ -50,9 +49,8 @@ export class AccessItemsManagementState implements NgxsAfterBootstrap {
|
||||||
groups
|
groups
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
(error) => {
|
() => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR, error);
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -72,9 +70,8 @@ export class AccessItemsManagementState implements NgxsAfterBootstrap {
|
||||||
accessItemsResource
|
accessItemsResource
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
(error) => {
|
() => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_2, error);
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -91,14 +88,12 @@ export class AccessItemsManagementState implements NgxsAfterBootstrap {
|
||||||
tap(
|
tap(
|
||||||
() => {
|
() => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.showToast(
|
this.notificationService.showSuccess('WORKBASKET_ACCESS_ITEM_REMOVE_PERMISSION', {
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT,
|
accessId: action.accessId
|
||||||
new Map<string, string>([['accessId', action.accessId]])
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
(error) => {
|
() => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.DELETE_ERR, error);
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import {
|
||||||
} from './workbasket.actions';
|
} from './workbasket.actions';
|
||||||
import { WorkbasketSummaryRepresentation } from '../../models/workbasket-summary-representation';
|
import { WorkbasketSummaryRepresentation } from '../../models/workbasket-summary-representation';
|
||||||
import { ACTION } from '../../models/action';
|
import { ACTION } from '../../models/action';
|
||||||
import { NOTIFICATION_TYPES } from '../../models/notifications';
|
|
||||||
import { NotificationService } from '../../services/notifications/notification.service';
|
import { NotificationService } from '../../services/notifications/notification.service';
|
||||||
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
|
import { WorkbasketAccessItemsRepresentation } from '../../models/workbasket-access-items-representation';
|
||||||
import { WorkbasketDistributionTargets } from '../../models/workbasket-distribution-targets';
|
import { WorkbasketDistributionTargets } from '../../models/workbasket-distribution-targets';
|
||||||
|
|
@ -195,19 +194,11 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
||||||
ctx.dispatch(new OnButtonPressed(undefined));
|
ctx.dispatch(new OnButtonPressed(undefined));
|
||||||
return this.workbasketService.createWorkbasket(action.workbasket).pipe(
|
return this.workbasketService.createWorkbasket(action.workbasket).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
tap(
|
tap((workbasketUpdated) => {
|
||||||
(workbasketUpdated) => {
|
this.notificationService.showSuccess('WORKBASKET_CREATE', { workbasketKey: workbasketUpdated.key });
|
||||||
this.notificationService.showToast(
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_11,
|
|
||||||
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
|
|
||||||
);
|
|
||||||
|
|
||||||
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets'));
|
this.location.go(this.location.path().replace(/(workbaskets).*/g, 'workbaskets'));
|
||||||
},
|
}),
|
||||||
(error) => {
|
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.CREATE_ERR_2, error);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
concatMap((workbasketUpdated) => ctx.dispatch(new SelectWorkbasket(workbasketUpdated.workbasketId)))
|
concatMap((workbasketUpdated) => ctx.dispatch(new SelectWorkbasket(workbasketUpdated.workbasketId)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -276,27 +267,19 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
||||||
ctx.dispatch(new OnButtonPressed(undefined));
|
ctx.dispatch(new OnButtonPressed(undefined));
|
||||||
return this.workbasketService.updateWorkbasket(action.url, action.workbasket).pipe(
|
return this.workbasketService.updateWorkbasket(action.url, action.workbasket).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
tap(
|
tap((updatedWorkbasket) => {
|
||||||
(updatedWorkbasket) => {
|
this.notificationService.showSuccess('WORKBASKET_UPDATE', { workbasketKey: updatedWorkbasket.key });
|
||||||
this.notificationService.showToast(
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_10,
|
|
||||||
new Map<string, string>([['workbasketKey', updatedWorkbasket.key]])
|
|
||||||
);
|
|
||||||
|
|
||||||
const paginatedWorkbasketSummary = { ...ctx.getState().paginatedWorkbasketsSummary };
|
const paginatedWorkbasketSummary = { ...ctx.getState().paginatedWorkbasketsSummary };
|
||||||
paginatedWorkbasketSummary.workbaskets = updateWorkbasketSummaryRepresentation(
|
paginatedWorkbasketSummary.workbaskets = updateWorkbasketSummaryRepresentation(
|
||||||
paginatedWorkbasketSummary.workbaskets,
|
paginatedWorkbasketSummary.workbaskets,
|
||||||
action.workbasket
|
action.workbasket
|
||||||
);
|
);
|
||||||
ctx.patchState({
|
ctx.patchState({
|
||||||
selectedWorkbasket: updatedWorkbasket,
|
selectedWorkbasket: updatedWorkbasket,
|
||||||
paginatedWorkbasketsSummary: paginatedWorkbasketSummary
|
paginatedWorkbasketsSummary: paginatedWorkbasketSummary
|
||||||
});
|
});
|
||||||
},
|
})
|
||||||
(error) => {
|
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_4, error);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,21 +288,11 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
||||||
ctx.dispatch(new OnButtonPressed(undefined));
|
ctx.dispatch(new OnButtonPressed(undefined));
|
||||||
return this.workbasketService.removeDistributionTarget(action.url).pipe(
|
return this.workbasketService.removeDistributionTarget(action.url).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
tap(
|
tap(() => {
|
||||||
() => {
|
this.notificationService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_REMOVE', {
|
||||||
this.notificationService.showToast(
|
workbasketKey: ctx.getState().selectedWorkbasket.key
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_9,
|
});
|
||||||
new Map<string, string>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]])
|
})
|
||||||
);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
this.notificationService.triggerError(
|
|
||||||
NOTIFICATION_TYPES.REMOVE_ERR_2,
|
|
||||||
error,
|
|
||||||
new Map<String, String>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,17 +302,10 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
||||||
return this.workbasketService.markWorkbasketForDeletion(action.url).pipe(
|
return this.workbasketService.markWorkbasketForDeletion(action.url).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
tap((response) => {
|
tap((response) => {
|
||||||
if (response.status === 202) {
|
if (response.status !== 202) {
|
||||||
this.notificationService.triggerError(
|
this.notificationService.showSuccess('WORKBASKET_REMOVE', {
|
||||||
NOTIFICATION_TYPES.MARK_ERR,
|
workbasketKey: ctx.getState().selectedWorkbasket.key
|
||||||
undefined,
|
});
|
||||||
new Map<String, String>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]])
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.notificationService.showToast(
|
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_12,
|
|
||||||
new Map<string, string>([['workbasketId', ctx.getState().selectedWorkbasket.workbasketId]])
|
|
||||||
);
|
|
||||||
|
|
||||||
ctx.dispatch(new DeselectWorkbasket());
|
ctx.dispatch(new DeselectWorkbasket());
|
||||||
}
|
}
|
||||||
|
|
@ -369,21 +335,15 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
||||||
.updateWorkBasketAccessItem(action.url, { accessItems: action.workbasketAccessItems })
|
.updateWorkBasketAccessItem(action.url, { accessItems: action.workbasketAccessItems })
|
||||||
.pipe(
|
.pipe(
|
||||||
take(1),
|
take(1),
|
||||||
tap(
|
tap((workbasketAccessItems) => {
|
||||||
(workbasketAccessItems) => {
|
ctx.patchState({
|
||||||
ctx.patchState({
|
workbasketAccessItems
|
||||||
workbasketAccessItems
|
});
|
||||||
});
|
this.notificationService.showSuccess('WORKBASKET_ACCESS_ITEM_SAVE', {
|
||||||
this.notificationService.showToast(
|
workbasketKey: ctx.getState().selectedWorkbasket.key
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_7,
|
});
|
||||||
new Map<string, string>([['workbasketKey', ctx.getState().selectedWorkbasket.key]])
|
return of(null);
|
||||||
);
|
})
|
||||||
return of(null);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_2, error);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -440,15 +400,13 @@ export class WorkbasketState implements NgxsAfterBootstrap {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.showToast(
|
this.notificationService.showSuccess('WORKBASKET_DISTRIBUTION_TARGET_SAVE', {
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
|
workbasketName: ctx.getState().selectedWorkbasket.name
|
||||||
new Map<string, string>([['workbasketName', ctx.getState().selectedWorkbasket.name]])
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return of(null);
|
return of(null);
|
||||||
},
|
},
|
||||||
(error) => {
|
() => {
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_3, error);
|
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,8 @@ import { ObjectReference } from 'app/workplace/models/object-reference';
|
||||||
import { Workbasket } from 'app/shared/models/workbasket';
|
import { Workbasket } from 'app/shared/models/workbasket';
|
||||||
import { WorkplaceService } from 'app/workplace/services/workplace.service';
|
import { WorkplaceService } from 'app/workplace/services/workplace.service';
|
||||||
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
|
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { take, takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-task-details',
|
selector: 'taskana-task-details',
|
||||||
|
|
@ -75,7 +74,7 @@ export class TaskDetailsComponent implements OnInit, OnDestroy {
|
||||||
this.task.customAttributes = this.taskClone.customAttributes.slice(0);
|
this.task.customAttributes = this.taskClone.customAttributes.slice(0);
|
||||||
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
|
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
|
||||||
this.task.primaryObjRef = { ...this.taskClone.primaryObjRef };
|
this.task.primaryObjRef = { ...this.taskClone.primaryObjRef };
|
||||||
this.notificationService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
|
this.notificationService.showSuccess('TASK_RESTORE');
|
||||||
}
|
}
|
||||||
|
|
||||||
getTask(): void {
|
getTask(): void {
|
||||||
|
|
@ -91,8 +90,8 @@ export class TaskDetailsComponent implements OnInit, OnDestroy {
|
||||||
this.cloneTask();
|
this.cloneTask();
|
||||||
this.taskService.selectTask(task);
|
this.taskService.selectTask(task);
|
||||||
},
|
},
|
||||||
(error) => {
|
() => {
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_7, error);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -111,22 +110,22 @@ export class TaskDetailsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
deleteTask(): void {
|
deleteTask(): void {
|
||||||
this.notificationService.showDialog(
|
this.notificationService.showDialog(
|
||||||
`You are going to delete Task: ${this.currentId}. Can you confirm this action?`,
|
'TASK_DELETE',
|
||||||
|
{ taskId: this.currentId },
|
||||||
this.deleteTaskConfirmation.bind(this)
|
this.deleteTaskConfirmation.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteTaskConfirmation(): void {
|
deleteTaskConfirmation(): void {
|
||||||
this.deleteTaskSubscription = this.taskService.deleteTask(this.task).subscribe(
|
this.deleteTaskSubscription = this.taskService
|
||||||
() => {
|
.deleteTask(this.task)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe(() => {
|
||||||
|
this.notificationService.showSuccess('TASK_DELETE', { taskName: this.task.name });
|
||||||
this.taskService.publishTaskDeletion();
|
this.taskService.publishTaskDeletion();
|
||||||
this.task = null;
|
this.task = null;
|
||||||
this.router.navigate(['taskana/workplace/tasks'], { queryParamsHandling: 'merge' });
|
this.router.navigate(['taskana/workplace/tasks'], { queryParamsHandling: 'merge' });
|
||||||
},
|
});
|
||||||
(error) => {
|
|
||||||
this.notificationService.triggerError(NOTIFICATION_TYPES.DELETE_ERR_2, error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectTab(tab: string): void {
|
selectTab(tab: string): void {
|
||||||
|
|
@ -169,11 +168,10 @@ export class TaskDetailsComponent implements OnInit, OnDestroy {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
this.cloneTask();
|
this.cloneTask();
|
||||||
this.taskService.publishUpdatedTask(task);
|
this.taskService.publishUpdatedTask(task);
|
||||||
this.notificationService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_14);
|
this.notificationService.showSuccess('TASK_UPDATE', { taskName: task.name });
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.showToast(NOTIFICATION_TYPES.DANGER_ALERT);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -184,10 +182,7 @@ export class TaskDetailsComponent implements OnInit, OnDestroy {
|
||||||
this.taskService.createTask(this.task).subscribe(
|
this.taskService.createTask(this.task).subscribe(
|
||||||
(task) => {
|
(task) => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.showToast(
|
this.notificationService.showSuccess('TASK_CREATE', { taskName: task.name });
|
||||||
NOTIFICATION_TYPES.SUCCESS_ALERT_13,
|
|
||||||
new Map<string, string>([['taskId', task.name]])
|
|
||||||
);
|
|
||||||
this.task = task;
|
this.task = task;
|
||||||
this.taskService.selectTask(this.task);
|
this.taskService.selectTask(this.task);
|
||||||
this.taskService.publishUpdatedTask(task);
|
this.taskService.publishUpdatedTask(task);
|
||||||
|
|
@ -195,7 +190,6 @@ export class TaskDetailsComponent implements OnInit, OnDestroy {
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.requestInProgressService.setRequestInProgress(false);
|
this.requestInProgressService.setRequestInProgress(false);
|
||||||
this.notificationService.showToast(NOTIFICATION_TYPES.DANGER_ALERT_2);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import { Page } from 'app/shared/models/page';
|
||||||
import { take, takeUntil } from 'rxjs/operators';
|
import { take, takeUntil } from 'rxjs/operators';
|
||||||
import { Search } from '../task-list-toolbar/task-list-toolbar.component';
|
import { Search } from '../task-list-toolbar/task-list-toolbar.component';
|
||||||
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
import { NotificationService } from '../../../shared/services/notifications/notification.service';
|
||||||
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
|
|
||||||
import { QueryPagingParameter } from '../../../shared/models/query-paging-parameter';
|
import { QueryPagingParameter } from '../../../shared/models/query-paging-parameter';
|
||||||
import { TaskQueryFilterParameter } from '../../../shared/models/task-query-filter-parameter';
|
import { TaskQueryFilterParameter } from '../../../shared/models/task-query-filter-parameter';
|
||||||
import { Select, Store } from '@ngxs/store';
|
import { Select, Store } from '@ngxs/store';
|
||||||
|
|
@ -144,7 +143,7 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
|
||||||
} else {
|
} else {
|
||||||
this.tasks = [];
|
this.tasks = [];
|
||||||
if (this.selectedSearchType === Search.byWorkbasket) {
|
if (this.selectedSearchType === Search.byWorkbasket) {
|
||||||
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT_2);
|
this.notificationsService.showInformation('EMPTY_WORKBASKET');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.tasksPageInformation = taskResource.page;
|
this.tasksPageInformation = taskResource.page;
|
||||||
|
|
|
||||||
|
|
@ -502,3 +502,7 @@ li.list-group-item:hover {
|
||||||
.mat-select-value-text {
|
.mat-select-value-text {
|
||||||
color: #4a5568 !important;
|
color: #4a5568 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hot-toast-icon {
|
||||||
|
align-self: center !important
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1502,6 +1502,20 @@
|
||||||
merge-source-map "^1.1.0"
|
merge-source-map "^1.1.0"
|
||||||
schema-utils "^2.7.0"
|
schema-utils "^2.7.0"
|
||||||
|
|
||||||
|
"@ngneat/hot-toast@3.1.0":
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ngneat/hot-toast/-/hot-toast-3.1.0.tgz#1338530c70d77643abf9fc344c1e6f600f2e8683"
|
||||||
|
integrity sha512-lbBEkPf2/I6L7yXFK3bssP/yNwT/uV5P/fuMgWeB8t4gHIPl9aTwF+j2DWhYEJGoDDlztvaXaimV6Yt2C8l0+Q==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@ngneat/overview@2.0.2":
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ngneat/overview/-/overview-2.0.2.tgz#557dbb801e8b3e42d3cda57f5feb79319ef2f120"
|
||||||
|
integrity sha512-BARS4lUrWW5BidZS6jKtZc3okV7ro+3QKxJKs1FgeDDSomNdNACEjB0BMITeulEQ+agE4n9U+sbGpF2guOXDQA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
"@ngtools/webpack@12.0.5":
|
"@ngtools/webpack@12.0.5":
|
||||||
version "12.0.5"
|
version "12.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.0.5.tgz#3d858c1df3a4f5a13450fb0cffe0d5db8e61d0e1"
|
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.0.5.tgz#3d858c1df3a4f5a13450fb0cffe0d5db8e61d0e1"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue