TSK-1205 Added new Toasts and DialogPopUps that replace the old infrastructure for alerting the user

This commit is contained in:
Tristan Eisermann 2020-05-12 08:26:36 +02:00
parent a888eebdc0
commit e64af885b3
71 changed files with 657 additions and 907 deletions

View File

@ -21,6 +21,7 @@
"src/environments/data-sources"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/theme/_main.scss"
],
"scripts": [
@ -80,6 +81,7 @@
"node_modules/bootstrap/dist/js/bootstrap.min.js"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/theme/_main.scss"
],
"assets": [
@ -116,4 +118,4 @@
"prefix": "app"
}
}
}
}

30
web/package-lock.json generated
View File

@ -297,6 +297,23 @@
"tslib": "^1.9.0"
}
},
"@angular/cdk": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz",
"integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==",
"requires": {
"parse5": "^5.0.0",
"tslib": "^1.7.1"
},
"dependencies": {
"parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
"optional": true
}
}
},
"@angular/cli": {
"version": "8.3.22",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.22.tgz",
@ -1442,6 +1459,14 @@
"tslib": "^1.9.0"
}
},
"@angular/material": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-8.2.3.tgz",
"integrity": "sha512-SOczkIaqes+r+9XF/UUiokidfFKBpHkOPIaFK857sFD0FBNPvPEpOr5oHKCG3feERRwAFqHS7Wo2ohVEWypb5A==",
"requires": {
"tslib": "^1.7.1"
}
},
"@angular/platform-browser": {
"version": "8.2.14",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-8.2.14.tgz",
@ -6992,6 +7017,11 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
},
"hammerjs": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
},
"handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",

View File

@ -15,9 +15,11 @@
"private": true,
"dependencies": {
"@angular/animations": "8.2.14",
"@angular/cdk": "8.2.3",
"@angular/common": "8.2.14",
"@angular/core": "8.2.14",
"@angular/forms": "8.2.14",
"@angular/material": "8.2.3",
"@angular/platform-browser": "8.2.14",
"@angular/platform-browser-dynamic": "8.2.14",
"@angular/router": "8.2.14",

View File

@ -8,8 +8,6 @@ import { FormsValidatorService } from 'app/shared/services/forms-validator/forms
import { AccessItemWorkbasketResource } from 'app/shared/models/access-item-workbasket-resource';
import { AccessItemWorkbasket } from 'app/shared/models/access-item-workbasket';
import { Sorting } from 'app/shared/models/sorting';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { RequestInProgressService } from '../../../shared/services/request-in-progress/request-in-progress.service';
@ -48,8 +46,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
private accessIdsService: AccessIdsService,
private formsValidatorService: FormsValidatorService,
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private generalModalService: GeneralModalService,
private notificationService: NotificationService,
private notificationsService: NotificationService) {
}
@ -141,11 +138,11 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
}
revokeAccess() {
this.removeConfirmationService.setRemoveConfirmation(
this.onRemoveConfirmed.bind(this),
this.notificationService.showDialog(
`You are going to delete all access related: ${
this.accessIdSelected
}. Can you confirm this action?`
}. Can you confirm this action?`,
this.onRemoveConfirmed.bind(this)
);
}
@ -160,7 +157,7 @@ export class AccessItemsManagementComponent implements OnInit, OnDestroy {
.subscribe(
response => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationsService.triggerAlert(
this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT, new Map<string, string>([['accessId', this.accessIdSelected]])
);
this.searchForAccessItemsWorkbaskets();

View File

@ -17,14 +17,15 @@ import { MasterAndDetailService } from 'app/shared/services/master-and-detail/ma
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { TreeNodeModel } from 'app/shared/models/tree-node';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { TreeService } from 'app/shared/services/tree/tree.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { ClassificationDetailsComponent } from './classification-details.component';
import { dispatchKeyboardEvent } from '@angular/cdk/testing';
import { TabDirective } from 'ngx-bootstrap';
import { KEYS } from 'angular-tree-component';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { ClassificationDetailsComponent } from './classification-details.component';
@Component({
@ -35,7 +36,7 @@ class DummyDetailComponent {
}
const routes: Routes = [
{ path: 'administration/classifications', component: DummyDetailComponent }
{ path: 'taskana/administration/classifications', component: DummyDetailComponent }
];
describe('ClassificationDetailsComponent', () => {
@ -45,7 +46,6 @@ describe('ClassificationDetailsComponent', () => {
let classificationsService;
let treeService;
let removeConfirmationService;
const storeSpy: jasmine.SpyObj<Store> = jasmine.createSpyObj('Store', ['select']);
const configure = (testBed: TestBed) => {
@ -53,7 +53,7 @@ describe('ClassificationDetailsComponent', () => {
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes), AngularSvgIconModule, NgxsModule.forRoot()],
declarations: [ClassificationDetailsComponent, DummyDetailComponent],
providers: [MasterAndDetailService, RequestInProgressService, ClassificationsService,
HttpClient, GeneralModalService, NotificationService,
HttpClient, NotificationService,
TreeService, ImportExportService, { provide: Store, useValue: storeSpy }]
});
};
@ -75,7 +75,6 @@ describe('ClassificationDetailsComponent', () => {
component = fixture.componentInstance;
classificationsService = testBed.get(ClassificationsService);
removeConfirmationService = testBed.get(RemoveConfirmationService);
spyOn(classificationsService, 'getClassifications').and.returnValue(of(treeNodes));
spyOn(classificationsService, 'deleteClassification').and.returnValue(of(true));
component.classification = new ClassificationDefinition('id1');
@ -91,10 +90,15 @@ describe('ClassificationDetailsComponent', () => {
expect(component).toBeTruthy();
});
it('should trigger treeService remove node id after removing a node', () => {
it('should trigger treeService remove node id after removing a node', done => {
const treeServiceSpy = spyOn(treeService, 'setRemovedNodeId');
component.removeClassification();
removeConfirmationService.runCallbackFunction();
expect(treeServiceSpy).toHaveBeenCalledWith('id1');
const ref = component.removeClassification();
ref.afterOpened().subscribe(() => {
ref.close(ref.componentInstance.callback);
});
ref.afterClosed().subscribe(() => {
expect(treeServiceSpy).toHaveBeenCalledWith('id1');
done();
});
});
});

View File

@ -11,10 +11,8 @@ import { TaskanaDate } from 'app/shared/util/taskana.date';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { TreeService } from 'app/shared/services/tree/tree.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { Pair } from 'app/shared/models/pair';
@ -24,11 +22,13 @@ import { ImportExportService } from 'app/administration/services/import-export.s
import { map, take } from 'rxjs/operators';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
import { ClassificationSelectors } from 'app/shared/store/classification-store/classification.selectors';
import { MatDialogRef } from '@angular/material/dialog';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
import { ClassificationCategoryImages,
CustomField,
getCustomFields } from '../../../shared/models/customisation';
import { DialogPopUpComponent } from '../../../shared/components/popup/dialog-pop-up.component';
@Component({
selector: 'taskana-classification-details',
@ -67,13 +67,11 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private router: Router,
private masterAndDetailService: MasterAndDetailService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private treeService: TreeService,
private domainService: DomainService,
private removeConfirmationService: RemoveConfirmationService,
private formsValidatorService: FormsValidatorService,
private notificationsService: NotificationService,
private notificationService: NotificationService,
private importExportService: ImportExportService,
private store: Store) {
}
@ -129,9 +127,11 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.router.navigate(['./'], { relativeTo: this.route.parent });
}
removeClassification() {
this.removeConfirmationService.setRemoveConfirmation(this.removeClassificationConfirmation.bind(this),
`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`);
removeClassification(): MatDialogRef<DialogPopUpComponent> {
return this.notificationService.showDialog(
`You are going to delete classification: ${this.classification.key}. Can you confirm this action?`,
this.removeClassificationConfirmation.bind(this)
);
}
isFieldValid(field: string): boolean {
@ -149,7 +149,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
onClear() {
this.formsValidatorService.formSubmitAttempt = false;
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.notificationService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
this.classification = { ...this.classificationClone };
}
@ -189,14 +189,14 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
.subscribe((classification: ClassificationDefinition) => {
this.classification = classification;
this.classificationsService.selectClassification(classification);
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_2,
new Map<string, string>([['classificationKey', classification.key]])
);
this.afterRequest();
},
error => {
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.CREATE_ERR, error);
this.afterRequest();
});
} else {
@ -205,13 +205,13 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.classification._links.self.href, this.classification
));
this.afterRequest();
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_3,
new Map<string, string>([['classificationKey', this.classification.key]])
);
this.cloneClassification(this.classification);
} catch (error) {
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR, error);
this.afterRequest();
}
}
@ -276,7 +276,7 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
private removeClassificationConfirmation() {
if (!this.classification || !this.classification.classificationId) {
this.notificationsService.triggerError(NOTIFICATION_TYPES.SELECT_ERR);
this.notificationService.triggerError(NOTIFICATION_TYPES.SELECT_ERR);
return;
}
this.requestInProgressService.setRequestInProgress(true);
@ -290,12 +290,12 @@ export class ClassificationDetailsComponent implements OnInit, OnDestroy {
this.afterRequest();
this.classificationsService.selectClassification();
this.router.navigate(['taskana/administration/classifications']);
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_4,
new Map<string, string>([['classificationKey', key]])
);
}, error => {
this.notificationsService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR, error);
this.afterRequest();
});
}

View File

@ -16,7 +16,6 @@ import { WorkbasketDefinitionService } from 'app/administration/services/workbas
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { ClassificationDefinitionService } from 'app/administration/services/classification-definition.service';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
import { TreeService } from 'app/shared/services/tree/tree.service';
@ -51,7 +50,7 @@ describe('ClassificationListComponent', () => {
providers: [
HttpClient, WorkbasketDefinitionService, NotificationService,
ClassificationsService, DomainService, ClassificationDefinitionService,
GeneralModalService, RequestInProgressService, TreeService, ImportExportService
RequestInProgressService, TreeService, ImportExportService
]
});
};

View File

@ -128,7 +128,7 @@ export class ClassificationListComponent implements OnInit, OnDestroy {
});
if (key) {
this.notificationsService.triggerAlert(
this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_5,
new Map<string, string>([['classificationKey', key]])
);

View File

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

View File

@ -3,8 +3,6 @@ import { ClassificationDefinitionService } from 'app/administration/services/cla
import { WorkbasketDefinitionService } from 'app/administration/services/workbasket-definition.service';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { TaskanaType } from 'app/shared/models/taskana-type';
import { MessageModal } from 'app/shared/models/message-modal';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { environment } from 'environments/environment';
import { UploadService } from 'app/shared/services/upload/upload.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
@ -30,7 +28,6 @@ export class ImportExportComponent implements OnInit {
private domainService: DomainService,
private workbasketDefinitionService: WorkbasketDefinitionService,
private classificationDefinitionService: ClassificationDefinitionService,
private generalModalService: GeneralModalService,
private notificationsService: NotificationService,
public uploadservice: UploadService,
private errorsService: NotificationService,
@ -117,7 +114,7 @@ export class ImportExportComponent implements OnInit {
}
this.errorHandler(key, event);
} else if (event.readyState === 4 && event.status === 200) {
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT_6);
this.notificationsService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_6);
this.importExportService.setImportingFinished(true);
this.resetProgress();
}

View File

@ -12,8 +12,6 @@ import { WorkbasketAccessItems } from 'app/shared/models/workbasket-access-items
import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-access-items-resource';
import { ICONTYPES } from 'app/shared/models/icon-types';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@ -40,7 +38,7 @@ describe('WorkbasketAccessItemsComponent', () => {
testBed.configureTestingModule({
declarations: [WorkbasketAccessItemsComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, ReactiveFormsModule, NgxsModule.forRoot()],
providers: [WorkbasketService, NotificationService, GeneralModalService, SavingWorkbasketService, RequestInProgressService,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, RequestInProgressService,
AccessIdsService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
});
};
@ -80,7 +78,7 @@ describe('WorkbasketAccessItemsComponent', () => {
new Links({ href: 'someurl' })
)));
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(of(true));
spyOn(notificationsService, 'triggerAlert').and.returnValue(of(true));
spyOn(notificationsService, 'showToast').and.returnValue(of(true));
debugElement = fixture.debugElement.nativeElement;
accessIdsService = testBed.get(AccessIdsService);
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new Array<string>(
@ -122,7 +120,7 @@ describe('WorkbasketAccessItemsComponent', () => {
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(notificationsService.triggerAlert).toHaveBeenCalledWith(
expect(notificationsService.showToast).toHaveBeenCalledWith(
NOTIFICATION_TYPES.SUCCESS_ALERT_7,
new Map<string, string>([['workbasketKey', component.workbasket.key]])
);

View File

@ -9,7 +9,6 @@ import { WorkbasketAccessItemsResource } from 'app/shared/models/workbasket-acce
import { ACTION } from 'app/shared/models/action';
import { SavingInformation, SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { highlight } from 'theme/animations/validation.animation';
@ -56,7 +55,6 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy {
constructor(
private workbasketService: WorkbasketService,
private generalModalService: GeneralModalService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private formBuilder: FormBuilder,
@ -106,7 +104,7 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy {
this.AccessItemsForm.reset();
this.setAccessItemsGroups(this.accessItemsResetClone);
this.accessItemsClone = this.cloneAccessItems(this.accessItemsResetClone);
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
}
remove(index: number) {
@ -183,7 +181,7 @@ export class WorkbasketAccessItemsComponent implements OnChanges, OnDestroy {
.subscribe(response => {
this.accessItemsClone = this.cloneAccessItems(this.AccessItemsForm.value.accessItemsGroups);
this.accessItemsResetClone = this.cloneAccessItems(this.AccessItemsForm.value.accessItemsGroups);
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT_7,
this.notificationsService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_7,
new Map<string, string>([['workbasketKey', this.workbasket.key]]));
this.requestInProgressService.setRequestInProgress(false);
}, error => {

View File

@ -19,7 +19,6 @@ import { LinksWorkbasketSummary } from 'app/shared/models/links-workbasket-summa
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
@ -61,7 +60,7 @@ describe('WorkbasketDetailsComponent', () => {
declarations: [WorkbasketDetailsComponent, WorkbasketInformationComponent,
WorkbasketAccessItemsComponent,
WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent, DummyDetailComponent],
providers: [WorkbasketService, MasterAndDetailService, GeneralModalService, RequestInProgressService,
providers: [WorkbasketService, MasterAndDetailService, RequestInProgressService,
NotificationService, SavingWorkbasketService, ImportExportService]
});
};

View File

@ -9,8 +9,6 @@ import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.ser
import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { ImportExportService } from 'app/administration/services/import-export.service';
import { GeneralModalService } from '../../../shared/services/general-modal/general-modal.service';
import { MessageModal } from '../../../shared/models/message-modal';
import { NOTIFICATION_TYPES } from '../../../shared/models/notifications';
import { NotificationService } from '../../../shared/services/notifications/notification.service';
@ -41,7 +39,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
private masterAndDetailService: MasterAndDetailService,
private domainService: DomainService,
private errorsService: NotificationService,
private generalModalService: GeneralModalService,
private importExportService: ImportExportService) { }

View File

@ -13,7 +13,6 @@ import { Workbasket } from 'app/shared/models/workbasket';
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@ -36,7 +35,7 @@ describe('WorkbasketDistributionTargetsComponent', () => {
testBed.configureTestingModule({
imports: [AngularSvgIconModule, HttpClientModule, InfiniteScrollModule],
declarations: [WorkbasketDistributionTargetsComponent, WorkbasketDualListComponent],
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, GeneralModalService, RequestInProgressService,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, RequestInProgressService,
]
});
};

View File

@ -11,12 +11,10 @@ import { Workbasket } from 'app/shared/models/workbasket';
import { WorkbasketSummary } from 'app/shared/models/workbasket-summary';
import { WorkbasketSummaryResource } from 'app/shared/models/workbasket-summary-resource';
import { WorkbasketDistributionTargetsResource } from 'app/shared/models/workbasket-distribution-targets-resource';
import { MessageModal } from 'app/shared/models/message-modal';
import { ACTION } from 'app/shared/models/action';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Page } from 'app/shared/models/page';
@ -76,7 +74,6 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
constructor(
private workbasketService: WorkbasketService,
private savingWorkbaskets: SavingWorkbasketService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService,
private notificationsService: NotificationService
@ -127,7 +124,7 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
this.distributionTargetsSelected = response.distributionTargets;
this.distributionTargetsSelectedClone = Object.assign([], this.distributionTargetsSelected);
this.distributionTargetsClone = Object.assign([], this.distributionTargetsLeft);
this.notificationsService.triggerAlert(
this.notificationsService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_8,
new Map<string, string>([['workbasketName', this.workbasket.name]])
);
@ -142,7 +139,7 @@ export class WorkbasketDistributionTargetsComponent implements OnChanges, OnDest
}
onClear() {
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
this.distributionTargetsLeft = Object.assign([], this.distributionTargetsClone);
this.distributionTargetsRight = Object.assign([], this.distributionTargetsSelectedClone);
this.distributionTargetsSelected = Object.assign([], this.distributionTargetsSelectedClone);

View File

@ -13,7 +13,6 @@ import { ICONTYPES } from 'app/shared/models/icon-types';
import { ACTION } from 'app/shared/models/action';
import { Links } from 'app/shared/models/links';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
@ -51,7 +50,7 @@ describe('WorkbasketInformationComponent', () => {
testBed.configureTestingModule({
declarations: [WorkbasketInformationComponent, DummyDetailComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, RouterTestingModule.withRoutes(routes), NgxsModule.forRoot()],
providers: [WorkbasketService, NotificationService, SavingWorkbasketService, GeneralModalService,
providers: [WorkbasketService, NotificationService, SavingWorkbasketService,
RequestInProgressService, FormsValidatorService, { provide: Store, useValue: storeSpy }]
});
@ -78,7 +77,7 @@ describe('WorkbasketInformationComponent', () => {
formsValidatorService = testBed.get(FormsValidatorService);
spyOn(alertService, 'triggerAlert');
spyOn(alertService, 'showToast');
fixture.detectChanges();
done();
});
@ -165,7 +164,7 @@ describe('WorkbasketInformationComponent', () => {
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalled();
expect(alertService.showToast).toHaveBeenCalled();
expect(component.workbasket.workbasketId).toBe('someNewId');
});
}));
@ -192,7 +191,7 @@ describe('WorkbasketInformationComponent', () => {
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalled();
expect(alertService.showToast).toHaveBeenCalled();
expect(component.workbasket.workbasketId).toBe('someNewId');
expect(savingWorkbasketService.triggerDistributionTargetSaving).toHaveBeenCalled();
expect(savingWorkbasketService.triggerAccessItemsSaving).toHaveBeenCalled();

View File

@ -15,11 +15,9 @@ import { ACTION } from 'app/shared/models/action';
import { customFieldCount, Workbasket } from 'app/shared/models/workbasket';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { SavingWorkbasketService, SavingInformation } from 'app/administration/services/saving-workbaskets.service';
import { WorkbasketService } from 'app/shared/services/workbasket/workbasket.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { map } from 'rxjs/operators';
import { EngineConfigurationSelectors } from 'app/shared/store/engine-configuration-store/engine-configuration.selectors';
@ -62,12 +60,10 @@ implements OnInit, OnChanges, OnDestroy {
private workbasketService: WorkbasketService,
private route: ActivatedRoute,
private router: Router,
private generalModalService: GeneralModalService,
private savingWorkbasket: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private removeConfirmationService: RemoveConfirmationService,
private formsValidatorService: FormsValidatorService,
private notificationsService: NotificationService
private notificationService: NotificationService
) {
}
@ -114,16 +110,14 @@ implements OnInit, OnChanges, OnDestroy {
onClear() {
this.formsValidatorService.formSubmitAttempt = false;
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.notificationService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
this.workbasket = { ...this.workbasketClone };
}
removeWorkbasket() {
this.removeConfirmationService.setRemoveConfirmation(
this.onRemoveConfirmed.bind(this),
`You are going to delete workbasket: ${
this.workbasket.key
}. Can you confirm this action?`
this.notificationService.showDialog(
`You are going to delete workbasket: ${this.workbasket.key}. Can you confirm this action?`,
this.onRemoveConfirmed.bind(this)
);
}
@ -142,13 +136,13 @@ implements OnInit, OnChanges, OnDestroy {
.subscribe(
reponse => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_9,
new Map<string, string>([['workbasketId', this.workbasket.workbasketId]])
);
},
error => {
this.notificationsService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR_2,
this.notificationService.triggerError(NOTIFICATION_TYPES.REMOVE_ERR_2,
error,
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
this.requestInProgressService.setRequestInProgress(false);
@ -170,14 +164,14 @@ implements OnInit, OnChanges, OnDestroy {
this.afterRequest();
this.workbasket = workbasketUpdated;
this.workbasketClone = { ...this.workbasket };
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_10,
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
);
},
error => {
this.afterRequest();
this.notificationsService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_4, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.SAVE_ERR_4, error);
}
);
}
@ -195,7 +189,7 @@ implements OnInit, OnChanges, OnDestroy {
this.addDateToWorkbasket();
this.workbasketService.createWorkbasket(this.workbasket).subscribe(
(workbasketUpdated: Workbasket) => {
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_11,
new Map<string, string>([['workbasketKey', workbasketUpdated.key]])
);
@ -222,7 +216,7 @@ implements OnInit, OnChanges, OnDestroy {
}
},
error => {
this.notificationsService.triggerError(NOTIFICATION_TYPES.CREATE_ERR_2, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.CREATE_ERR_2, error);
this.requestInProgressService.setRequestInProgress(false);
}
);
@ -243,12 +237,11 @@ implements OnInit, OnChanges, OnDestroy {
this.requestInProgressService.setRequestInProgress(false);
this.workbasketService.triggerWorkBasketSaved();
if (response.status === 202) {
this.notificationsService.triggerError(NOTIFICATION_TYPES.MARK_ERR,
this.notificationService.triggerError(NOTIFICATION_TYPES.MARK_ERR,
undefined,
new Map<String, String>([['workbasketId', this.workbasket.workbasketId]]));
} else {
// new Key ALERT_TYPES.SUCCESS_ALERT_12
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_12,
new Map<string, string>([['workbasketId', this.workbasket.workbasketId]])
);

View File

@ -2,12 +2,7 @@
<div (window:resize)="onResize()" class="container-fluid container-main">
<div class="row ">
<router-outlet></router-outlet>
<taskana-general-message-modal *ngIf="modalMessage" [(message)]="modalMessage" [title]="modalTitle"
[type]="modalType" error="true"></taskana-general-message-modal>
<error-modal></error-modal>
<taskana-spinner [isRunning]="requestInProgress" isModal=true></taskana-spinner>
<taskana-alert></taskana-alert>
<taskana-remove-confirmation></taskana-remove-confirmation>
<taskana-progress-bar [ngClass]="{hidden: currentProgressValue === 0}" currentValue={{currentProgressValue}}></taskana-progress-bar>
</div>
<taskana-type-ahead></taskana-type-ahead>

View File

@ -3,9 +3,7 @@ import { NavigationStart, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { FormsValidatorService } from 'app/shared/services/forms-validator/forms-validator.service';
import { MessageModal } from './shared/models/message-modal';
import { GeneralModalService } from './shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from './shared/services/request-in-progress/request-in-progress.service';
import { OrientationService } from './shared/services/orientation/orientation.service';
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
@ -21,15 +19,11 @@ import { NotificationService } from './shared/services/notifications/notificatio
export class AppComponent implements OnInit, OnDestroy {
workbasketsRoute = true;
modalMessage = '';
modalTitle = '';
modalType;
selectedRoute = '';
requestInProgress = false;
currentProgressValue = 0;
modalSubscription: Subscription;
requestInProgressSubscription: Subscription;
selectedRouteSubscription: Subscription;
routerSubscription: Subscription;
@ -38,7 +32,6 @@ export class AppComponent implements OnInit, OnDestroy {
constructor(
private router: Router,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private orientationService: OrientationService,
private selectedRouteService: SelectedRouteService,
@ -62,20 +55,6 @@ export class AppComponent implements OnInit, OnDestroy {
}
});
this.modalSubscription = this.generalModalService.getMessage().subscribe((messageModal: MessageModal) => {
if (typeof messageModal.message === 'string') {
this.modalMessage = messageModal.message;
} else if (messageModal.message.error instanceof ProgressEvent) {
this.modalMessage = messageModal.message.message;
} else {
this.modalMessage = messageModal.message.error
? (`${messageModal.message.error.error} ${messageModal.message.error.message}`)
: messageModal.message.message;
}
this.modalTitle = messageModal.title;
this.modalType = messageModal.type;
});
this.requestInProgressSubscription = this.requestInProgressService.getRequestInProgress().subscribe((value: boolean) => {
this.requestInProgress = value;
});
@ -95,9 +74,6 @@ export class AppComponent implements OnInit, OnDestroy {
if (this.routerSubscription) {
this.routerSubscription.unsubscribe();
}
if (this.modalSubscription) {
this.modalSubscription.unsubscribe();
}
if (this.requestInProgressSubscription) {
this.requestInProgressSubscription.unsubscribe();
}

View File

@ -17,7 +17,6 @@ import { SharedModule } from 'app/shared/shared.module';
/**
* Services
*/
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { OrientationService } from 'app/shared/services/orientation/orientation.service';
import { SelectedRouteService } from 'app/shared/services/selected-route/selected-route';
@ -30,7 +29,6 @@ import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana
import { NavBarComponent } from 'app/shared/components/nav-bar/nav-bar.component';
import { UserInformationComponent } from 'app/shared/components/user-information/user-information.component';
import { NoAccessComponent } from 'app/shared/components/no-access/no-access.component';
import { RemoveConfirmationService } from './shared/services/remove-confirmation/remove-confirmation.service';
import { FormsValidatorService } from './shared/services/forms-validator/forms-validator.service';
import { UploadService } from './shared/services/upload/upload.service';
import { NotificationService } from './shared/services/notifications/notification.service';
@ -52,6 +50,7 @@ import { UserGuard } from './shared/guards/user.guard';
import { ClassificationCategoriesService } from './shared/services/classification-categories/classification-categories.service';
import { environment } from '../environments/environment';
import { STATES } from './shared/store';
import { ToastComponent } from './shared/components/toast/toast.component';
const MODULES = [
TabsModule.forRoot(),
@ -87,7 +86,6 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
providers: [
WindowRefService,
DomainService,
GeneralModalService,
RequestInProgressService,
OrientationService,
SelectedRouteService,
@ -105,7 +103,6 @@ export function startupServiceFactory(startupService: StartupService): () => Pro
MasterAndDetailService,
TreeService,
TaskanaEngineService,
RemoveConfirmationService,
FormsValidatorService,
UploadService,
NotificationService,

View File

@ -3,7 +3,6 @@ import { getTestBed, TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
@ -12,7 +11,6 @@ import { TaskanaEngineServiceMock } from './shared/services/taskana-engine/taska
import { TaskanaEngineService } from './shared/services/taskana-engine/taskana-engine.service';
import { DomainService } from './shared/services/domain/domain.service';
import { DomainServiceMock } from './shared/services/domain/domain.service.mock';
import { GeneralModalService } from './shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from './shared/services/request-in-progress/request-in-progress.service';
import { OrientationService } from './shared/services/orientation/orientation.service';
import { SelectedRouteService } from './shared/services/selected-route/selected-route';
@ -34,8 +32,8 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
testBed.configureTestingModule({
imports: [BrowserAnimationsModule, SharedModule, FormsModule, ReactiveFormsModule, HttpClientModule, AngularSvgIconModule],
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
{ provide: DomainService, useClass: DomainServiceMock }, RemoveConfirmationService,
NotificationService, GeneralModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
{ provide: DomainService, useClass: DomainServiceMock }, NotificationService,
RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]
});
return testBed.compileComponents().then(() => testBed);

View File

@ -1,10 +1,10 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right btn-group">
<button class="btn btn-default" data-toggle="tooltip" title="Query" type="button">
<button class="btn btn-default" data-toggle="tooltip" title="Search" type="button">
<span (click)="search()" class="material-icons md-20 blue">search</span>
</button>
<button class="btn btn-default" data-toggle="tooltip" title="Query" type="button">
<button class="btn btn-default" data-toggle="tooltip" title="Clear" type="button">
<span (click)="clear()" class="material-icons md-20 blue">clear</span>
</button>
</div>
@ -16,42 +16,63 @@
<div class="table-header">
<div class="table-row">
<ng-container *ngFor="let taskHeader of taskQueryHeader | mapToIterable">
<div (click)="changeOrderBy(taskHeader.key); search();" *ngIf="filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)"
class="table-cell table-cell--bold table-cell--justify">
<div (click)="changeOrderBy(taskHeader.key); search();"
*ngIf="filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)"
class="table-cell table-cell--bold table-cell--justify">
<span class="icon-space">
{{getHeaderFieldDescription(taskHeader.key)}}
</span>
<span *ngIf="orderBy.sortBy === taskHeader.key" [ngClass]="{'flip': orderBy.sortDirection === 'desc'}" class="material-icons md-20 blue pull-right">sort</span>
<span *ngIf="orderBy.sortBy === taskHeader.key"
[ngClass]="{'flip': orderBy.sortDirection === 'desc'}"
class="material-icons md-20 blue pull-right">sort</span>
</div>
<div (click)="toggleExpand = !toggleExpand" *ngIf="taskHeader.key === 'custom1'"
[ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}" class="table-cell table-cell--bold table-cell--separator">
<span class="material-icons md-24 blue pull-right">{{toggleExpand? 'chevron_left' : 'chevron_right'}}</span>
[ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
class="table-cell table-cell--bold table-cell--separator">
<span class="material-icons md-24 blue pull-right">{{toggleExpand ? 'chevron_left'
: 'chevron_right'}}</span>
</div>
<div (click)="changeOrderBy(taskHeader.key); search();" *ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && toggleExpand"
class="table-cell table-cell--bold table-cell--justify">
<div (click)="changeOrderBy(taskHeader.key); search();"
*ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && toggleExpand"
class="table-cell table-cell--bold table-cell--justify">
<span class="icon-space">
{{getHeaderFieldDescription(taskHeader.key)}}
</span>
<span *ngIf="orderBy.sortBy === taskHeader.key && filterFieldsToAllowQuerying(taskHeader.key)" [ngClass]="{'flip': orderBy.sortDirection === 'desc'}"
class="material-icons md-20 blue pull-right">sort</span>
<span
*ngIf="orderBy.sortBy === taskHeader.key && filterFieldsToAllowQuerying(taskHeader.key)"
[ngClass]="{'flip': orderBy.sortDirection === 'desc'}"
class="material-icons md-20 blue pull-right">sort</span>
</div>
</ng-container>
</div>
<div class="table-row">
<ng-container *ngFor="let taskHeader of taskQueryHeader | mapToIterable">
<div *ngIf="isDate(taskHeader.key)" class="table-cell table-cell--bold table-cell--justify divDate">
<taskana-date-picker (dateOutput)="updateDate($event)" [id]="'created'" [name]="'this.created'" formControlName="{{taskHeader.key}}" placeholder="{{getHeaderFieldDescription(taskHeader.key)}}" type="text"></taskana-date-picker>
<div *ngIf="isDate(taskHeader.key)"
class="table-cell table-cell--bold table-cell--justify divDate">
<taskana-date-picker (dateOutput)="updateDate($event)" [id]="'created'"
[name]="'this.created'" formControlName="{{taskHeader.key}}"
placeholder="{{getHeaderFieldDescription(taskHeader.key)}}"
type="text"></taskana-date-picker>
</div>
<div *ngIf="!isDate(taskHeader.key) && filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)" class="table-cell table-cell--bold table-cell--justify">
<input (keyup.enter)="search()" class="form-control input-sm" formControlName="{{taskHeader.key}}" placeholder="{{getHeaderFieldDescription(taskHeader.key)}}"
type="text">
<div
*ngIf="!isDate(taskHeader.key) && filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)"
class="table-cell table-cell--bold table-cell--justify">
<input (keyup.enter)="search()" class="form-control input-sm"
formControlName="{{taskHeader.key}}"
placeholder="{{getHeaderFieldDescription(taskHeader.key)}}"
type="text">
</div>
<div (click)="toggleExpand = !toggleExpand" *ngIf="taskHeader.key === 'custom1'"
[ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}" class="table-cell table-cell--bold table-cell--separator">
[ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
class="table-cell table-cell--bold table-cell--separator">
</div>
<div *ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && toggleExpand" class="table-cell table-cell--bold table-cell--justify">
<input (keyup.enter)="search()" *ngIf="filterFieldsToAllowQuerying(taskHeader.key)" class="form-control input-sm"
formControlName="{{taskHeader.key}}" placeholder="{{getHeaderFieldDescription(taskHeader.key)}}" type="text">
<div
*ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && toggleExpand"
class="table-cell table-cell--bold table-cell--justify">
<input (keyup.enter)="search()" *ngIf="filterFieldsToAllowQuerying(taskHeader.key)"
class="form-control input-sm"
formControlName="{{taskHeader.key}}"
placeholder="{{getHeaderFieldDescription(taskHeader.key)}}" type="text">
</div>
</ng-container>
</div>
@ -62,19 +83,24 @@
<div *ngIf="isDate(taskHeader.key)" class="table-cell table-cell--justify">
{{task[taskHeader.key] | dateTimeZone:'yyyy-MM-dd'}}
</div>
<div *ngIf="!isDate(taskHeader.key) && filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)" class="table-cell table-cell--justify">
<div
*ngIf="!isDate(taskHeader.key) && filterFieldsToShow(taskHeader.key) && !filterExpandGroup(taskHeader.key)"
class="table-cell table-cell--justify">
{{task[taskHeader.key]}}
</div>
<div (click)="toggleExpand = !toggleExpand" *ngIf="taskHeader.key === 'custom1'" [ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
class="table-cell table-cell--separator">
<div (click)="toggleExpand = !toggleExpand" *ngIf="taskHeader.key === 'custom1'"
[ngClass]="{'zoom-in': !toggleExpand, 'zoom-out': toggleExpand}"
class="table-cell table-cell--separator">
</div>
<div *ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && filterFieldsToAllowQuerying(taskHeader.key) && toggleExpand" class="table-cell table-cell--justify">
<div
*ngIf="filterFieldsToShow(taskHeader.key) && filterExpandGroup(taskHeader.key) && filterFieldsToAllowQuerying(taskHeader.key) && toggleExpand"
class="table-cell table-cell--justify">
{{task[taskHeader.key]}}
</div>
<div *ngIf="!filterFieldsToAllowQuerying(taskHeader.key) && toggleExpand" class="table-cell table-cell--justify">
<button (click)="openDetails(taskHeader.key, task[taskHeader.key])" *ngIf="task[taskHeader.key]" class="btn btn-default btn-xs" type="button">
<span class="material-icons md-16 blue pull-right">open_in_new</span>
</button>
<div *ngIf="!filterFieldsToAllowQuerying(taskHeader.key) && toggleExpand"
class="table-cell table-cell--justify">
<div *ngIf="task[taskHeader.key]">{{task[taskHeader.key]}}
</div>
</div>
</ng-container>
</div>
@ -82,8 +108,9 @@
</form>
</div>
<div *ngIf="taskQueryResource" class="divTablePagination">
<taskana-pagination (changePage)="changePage($event)" [(page)]="taskQueryResource.page" [numberOfItems]="taskQuery.length"
type="Entries"></taskana-pagination>
<taskana-pagination (changePage)="changePage($event)" [(page)]="taskQueryResource.page"
[numberOfItems]="taskQuery.length"
type="Entries"></taskana-pagination>
</div>
</div>
</div>
</div>

View File

@ -4,8 +4,6 @@ import { OrientationService } from 'app/shared/services/orientation/orientation.
import { Subscription } from 'rxjs';
import { Orientation } from 'app/shared/models/orientation';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { MessageModal } from 'app/shared/models/message-modal';
import { FormControl, FormGroup } from '@angular/forms';
import { TaskHistoryEventResourceData } from 'app/shared/models/task-history-event-resource';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
@ -31,7 +29,6 @@ export class TaskQueryComponent implements OnInit {
constructor(
private taskQueryService: TaskQueryService,
private orientationService: OrientationService,
private generalModalService: GeneralModalService,
private requestInProgressService: RequestInProgressService,
private errorsService: NotificationService
) {
@ -145,17 +142,6 @@ export class TaskQueryComponent implements OnInit {
}
}
// TODO: Global?
openDetails(key: string, val: string) {
this.generalModalService.triggerMessage(
new MessageModal(
`These are the details of ${this.getHeaderFieldDescription(key)}`,
val,
'code'
)
);
}
getTaskValue(key: string, task: TaskHistoryEventData): string {
return task[key];
}

View File

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

View File

@ -1,9 +0,0 @@
.footer{
position: fixed;
bottom: 0;
width: 100%;
margin-bottom: 0px;
text-align: center;
z-index: 1050;
}

View File

@ -1,56 +0,0 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AlertComponent } from './alert.component';
import { NOTIFICATION_TYPES } from '../../models/notifications';
import { NotificationService } from '../../services/notifications/notification.service';
// TODO re-enable these tests when alert-component has been refactored and renamed (message component)
xdescribe('AlertComponent', () => {
let component: AlertComponent;
let fixture: ComponentFixture<AlertComponent>;
let debugElement;
let notificationsService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [BrowserAnimationsModule],
declarations: [AlertComponent],
providers: [NotificationService]
}).compileComponents();
}));
beforeEach(() => {
notificationsService = TestBed.get(NotificationService);
fixture = TestBed.createComponent(AlertComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement.nativeElement;
fixture.detectChanges();
});
afterEach(() => {
document.body.removeChild(debugElement);
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should show alert message', () => {
notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT);
fixture.detectChanges();
expect(debugElement.querySelector('#alert-icon').innerText).toBe('done');
expect(debugElement.querySelector('#alert-text').innerText).toBe('some custom text');
});
it('should have differents alert types', () => {
notificationsService.triggerAlert(NOTIFICATION_TYPES.WARNING_ALERT);
fixture.detectChanges();
expect(debugElement.querySelector('#alert-icon').innerText).toBe('warning');
notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT);
fixture.detectChanges();
expect(debugElement.querySelector('#alert-icon').innerText).toBe('warning');
expect(debugElement.querySelector('#alert-text').innerText).toBe('some custom text');
});
});

View File

@ -1,35 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { NotificationService } from 'app/shared/services/notifications/notification.service';
import { AlertModel } from '../../models/alert-model';
import { expandTop } from '../../../../theme/animations/expand.animation';
@Component({
selector: 'taskana-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.scss'],
animations: [expandTop]
})
export class AlertComponent implements OnInit {
alert: AlertModel;
private timeoutId: any; // NodeJS.Timer cannot be imported..
constructor(private notificationService: NotificationService) {
}
ngOnInit() {
this.notificationService.getAlert().subscribe((alert: AlertModel) => {
this.alert = alert;
if (alert.autoClosing) {
this.setTimeOutForClosing(alert.closingDelay);
}
});
}
setTimeOutForClosing(time: number) {
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
delete this.alert;
}, time);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,8 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
import { HttpClientModule } from '@angular/common/http';
import { configureTests } from 'app/app.test.configuration';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Overlay } from '@angular/cdk/overlay';
import { FilterComponent } from './filter.component';
describe('FilterComponent', () => {
@ -15,7 +17,7 @@ describe('FilterComponent', () => {
beforeEach(done => {
const configure = (testBed: TestBed) => {
testBed.configureTestingModule({
declarations: [],
providers: [MatSnackBar, Overlay],
imports: [AngularSvgIconModule, FormsModule, HttpClientModule]
});
};

View File

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

View File

@ -1,4 +0,0 @@
.word-break{word-break: break-word; }
.modal{
z-index: 1051;
}

View File

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

View File

@ -1,33 +0,0 @@
import { Component, Input, ViewChild, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
declare let $: any; // jquery
@Component({
selector: 'taskana-general-message-modal',
templateUrl: './general-message-modal.component.html',
styleUrls: ['./general-message-modal.component.scss']
})
export class GeneralMessageModalComponent implements OnChanges {
@Input() message: string;
@Output() messageChange = new EventEmitter<string>();
@Input()
title: string;
@Input()
type: string;
@ViewChild('generalModal', { static: true })
private modal;
ngOnChanges(changes: SimpleChanges) {
if (this.message) {
$(this.modal.nativeElement).modal('toggle');
}
}
removeMessage() {
this.message = '';
this.messageChange.emit(this.message);
}
}

View File

@ -11,10 +11,11 @@ import { SelectedRouteService } from 'app/shared/services/selected-route/selecte
import { BusinessAdminGuard } from 'app/shared/guards/business-admin.guard';
import { MonitorGuard } from 'app/shared/guards/monitor.guard';
import { WindowRefService } from 'app/shared/services/window/window.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { configureTests } from 'app/app.test.configuration';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Overlay } from '@angular/cdk/overlay';
import { NavBarComponent } from './nav-bar.component';
describe('NavBarComponent', () => {
@ -42,8 +43,9 @@ describe('NavBarComponent', () => {
BusinessAdminGuard,
MonitorGuard,
WindowRefService,
GeneralModalService,
RequestInProgressService]
RequestInProgressService,
MatSnackBar,
Overlay]
});
};
configureTests(configure).then(testBed => {

View File

@ -0,0 +1,17 @@
<h4 class="modal-title" mat-dialog-title id="errorModalLabel">{{title}}</h4>
<div mat-dialog-content class="modal-body">
<div class="alert alert-danger" role="alert">
<span class="material-icons md-20" data-toggle="tooltip">error</span>
<span *ngIf="!isDialog" class="sr-only">Error:</span>
{{message}}
</div>
</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>

View File

@ -0,0 +1,26 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MAT_DIALOG_SCROLL_STRATEGY, MatDialog } from '@angular/material/dialog';
import { DialogPopUpComponent } from './dialog-pop-up.component';
describe('PopupComponent', () => {
let component: DialogPopUpComponent;
let fixture: ComponentFixture<DialogPopUpComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DialogPopUpComponent],
providers: [MatDialog, { provide: MAT_DIALOG_SCROLL_STRATEGY }, { provide: MAT_DIALOG_DATA }]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DialogPopUpComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,50 @@
import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { HttpErrorResponse } from '@angular/common/http';
import { notifications } from '../../models/notifications';
@Component({
selector: 'app-popup',
templateUrl: './dialog-pop-up.component.html',
styleUrls: ['./dialog-pop-up.component.scss']
})
export class DialogPopUpComponent implements OnInit {
title: string;
message: string;
isDialog: false;
callback: Function;
constructor(@Inject(MAT_DIALOG_DATA) private data: any) {
}
ngOnInit() {
if (this.data) {
this.isDialog = this.data.isDialog;
if (this.isDialog) {
this.initDialog();
} else {
this.initError();
}
} else {
this.message = 'There was an error with this PopUp. \nPlease contact your administrator.';
}
}
initError() {
this.title = notifications.get(this.data.key).name;
this.message = notifications.get(this.data.key).text || 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;
}
}

View File

@ -1,24 +0,0 @@
<div #removeConfirmationModal class="modal fade" tabindex="-1" data-backdrop="static" data-keyboard="false" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content word-break">
<div class="modal-header">
<h4 class="modal-title" id="generalModalLabel">Delete confirmation</h4>
</div>
<div class="modal-body">
<div class="alert alert-danger" role="alert">
<span data-toggle="tooltip" class="material-icons md-20 red">error</span>
<span class="sr-only">Error:</span>
{{message}}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-danger" data-dismiss="modal" data-toggle="tooltip" title="Cancel">
<span data-toggle="tooltip" class="material-icons md-20 white">cancel</span>
</button>
<button type="button" class="btn btn-default btn-primary" data-dismiss="modal" data-toggle="tooltip" title="Confirm" (click)="confirmAction()">
<span data-toggle="tooltip" class="material-icons md-20 white">done</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -1,4 +0,0 @@
.word-break{word-break: break-word; }
.modal{
z-index: 1051;
}

View File

@ -1,29 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { configureTests } from 'app/app.test.configuration';
import { RemoveConfirmationComponent } from './remove-confirmation.component';
import { RemoveConfirmationService } from '../../services/remove-confirmation/remove-confirmation.service';
describe('RemoveConfirmationComponent', () => {
let component: RemoveConfirmationComponent;
let fixture: ComponentFixture<RemoveConfirmationComponent>;
beforeEach(done => {
const configure = (testBed: TestBed) => {
testBed.configureTestingModule({
declarations: [],
providers: []
});
};
configureTests(configure).then(testBed => {
fixture = TestBed.createComponent(RemoveConfirmationComponent);
component = fixture.componentInstance;
TestBed.get(RemoveConfirmationService);
fixture.detectChanges();
done();
});
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,31 +0,0 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
declare let $: any;
@Component({
selector: 'taskana-remove-confirmation',
templateUrl: './remove-confirmation.component.html',
styleUrls: ['./remove-confirmation.component.scss']
})
export class RemoveConfirmationComponent implements OnInit {
private confirmationCallback: Function;
message: string;
@ViewChild('removeConfirmationModal', { static: true })
private modal;
constructor(private removeConfirmationService: RemoveConfirmationService) { }
ngOnInit() {
this.removeConfirmationService.getRemoveConfirmation().subscribe(({ callback, message }) => {
this.confirmationCallback = callback;
this.message = message;
$(this.modal.nativeElement).modal('toggle');
});
}
confirmAction() {
this.confirmationCallback();
}
}

View File

@ -1,6 +1,8 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Overlay } from '@angular/cdk/overlay';
import { MAT_DIALOG_SCROLL_STRATEGY, MatDialog } from '@angular/material/dialog';
import { SpinnerComponent } from './spinner.component';
describe('SpinnerComponent', () => {
@ -10,7 +12,7 @@ describe('SpinnerComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SpinnerComponent],
providers: [GeneralModalService]
providers: [MatSnackBar, Overlay, MatDialog, { provide: MAT_DIALOG_SCROLL_STRATEGY }]
})
.compileComponents();
}));

View File

@ -0,0 +1,2 @@
<span id="alert-icon" class="material-icons md-20">{{ type }}</span>
{{ message }}

View File

@ -0,0 +1,26 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_SNACK_BAR_DATA, MatSnackBar } from '@angular/material/snack-bar';
import { ToastComponent } from './toast.component';
describe('ToastComponent', () => {
let component: ToastComponent;
let fixture: ComponentFixture<ToastComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ToastComponent],
providers: [{ provide: MAT_SNACK_BAR_DATA }]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ToastComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,37 @@
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: 'app-toast',
// template: '{{ message }}',
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).text;
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.';
}
}
}

View File

@ -3,6 +3,8 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
import { HttpClientModule } from '@angular/common/http';
import { configureTests } from 'app/app.test.configuration';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Overlay } from '@angular/cdk/overlay';
import { UserInformationComponent } from './user-information.component';
@ -18,6 +20,7 @@ describe('UserInformationComponent', () => {
imports: [AngularSvgIconModule,
HttpClientModule],
declarations: [UserInformationComponent],
providers: [MatSnackBar, Overlay]
});
};
configureTests(configure).then(testBed => {

View File

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

View File

@ -8,13 +8,14 @@ export class ErrorModel {
constructor(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>) {
this.title = notifications.get(key).name;
this.message = notifications.get(key).text;
let messageTemp = notifications.get(key).text;
this.errObj = passedError;
if (addition) {
addition.forEach((value: string, replacementKey: string) => {
this.message.replace(`{${replacementKey}}`, value);
messageTemp = messageTemp.replace(`{${replacementKey}}`, value);
this.title.replace(`{${replacementKey}}`, value);
});
}
this.message = messageTemp;
}
}

View File

@ -1,7 +0,0 @@
export class MessageModal {
constructor(
public title?: string,
public message?: any,
public type = 'error'
) { }
}

View File

@ -59,12 +59,12 @@ export enum NOTIFICATION_TYPES {
export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
// access-items-management.component.ts
[NOTIFICATION_TYPES.FETCH_ERR, new Pair(
'There was error while retrieving your access ids with groups.',
'There was an error while retrieving your access ids with groups.',
''
)],
// access-items-management.component.ts
[NOTIFICATION_TYPES.FETCH_ERR_2, new Pair(
'There was error while retrieving your access items ',
'There was an error while retrieving your access items ',
''
)],
// access-items-management.component.ts
@ -74,17 +74,17 @@ export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
)],
// classification-details.component
[NOTIFICATION_TYPES.CREATE_ERR, new Pair(
'There was an error creating a classification',
'There was an error while creating this classification',
'',
)],
// classification-details.component
[NOTIFICATION_TYPES.REMOVE_ERR, new Pair(
'There was error while removing your classification',
'There was an error while removing your classification',
''
)],
// classification-details.component
[NOTIFICATION_TYPES.SAVE_ERR, new Pair(
'There was error while saving your classification',
'There was an error while saving your classification',
''
)],
// classification-details.component
@ -121,7 +121,7 @@ export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
[NOTIFICATION_TYPES.UPLOAD_ERR, new Pair(
'Upload failed',
`The upload didn't proceed sucessfully.
\n Probably the uploaded file exceeded the maximum file size of 10 MB.`
\n The uploaded file probably exceeded the maximum file size of 10 MB.`
)],
// taskdetails.component
[NOTIFICATION_TYPES.FETCH_ERR_3, new Pair(
@ -130,17 +130,17 @@ export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
)],
// workbasket-details.component
[NOTIFICATION_TYPES.FETCH_ERR_4, new Pair(
'An error occurred while fetching the workbasket',
''
'',
'An error occurred while fetching the workbasket'
)],
// access-items.component
[NOTIFICATION_TYPES.SAVE_ERR_2, new Pair(
'There was error while saving your workbasket\'s access items',
'There was an error while saving your workbasket\'s access items',
''
)],
// workbaskets-distribution-targets.component
[NOTIFICATION_TYPES.SAVE_ERR_3, new Pair(
'There was error while saving your workbasket\'s distribution targets',
'There was an error while saving your workbasket\'s distribution targets',
'',
)],
// workbasket-information.component
@ -150,39 +150,39 @@ export const notifications = new Map<NOTIFICATION_TYPES, Pair>([
)],
// workbasket-information.component
[NOTIFICATION_TYPES.SAVE_ERR_4, new Pair(
'There was error while saving your workbasket',
'There was an error while saving your workbasket',
''
)],
// workbasket-information.component
[NOTIFICATION_TYPES.CREATE_ERR_2, new Pair(
'There was an error creating a workbasket',
'There was an error while creating this workbasket',
''
)],
// workbasket-information.component
[NOTIFICATION_TYPES.MARK_ERR, new Pair(
'Workbasket was marked for deletion.',
'The Workbasket {workbasketId} still contains completed tasks and could not be deleted.'
+ 'Instead is was marked for deletion and will be deleted automatically '
+ 'as soon as the completed tasks are deleted from the database.'
+ ' 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, new Pair(
'There was an error, please contact with your administrator',
'There was an error, please contact your administrator',
'There was an error getting Domains'
)],
// history.guard
[NOTIFICATION_TYPES.FETCH_ERR_6, new Pair(
'There was an error, please contact with your administrator',
'There was an error, please contact your administrator',
'There was an error getting history provider'
)],
// http-client-interceptor.service
[NOTIFICATION_TYPES.ACCESS_ERR, new Pair(
'You have no access to this resource ',
'You have no access to this resource',
''
)],
// http-client-interceptor.service
[NOTIFICATION_TYPES.GENERAL_ERR, new Pair(
'There was error, please contact with your administrator',
'There was an error, please contact your administrator',
''
)],
// spinner.component

View File

@ -51,12 +51,12 @@ export class FormsValidatorService {
const responseOwner = new ResponseOwner(values[1]);
if (!(values[0] && responseOwner.valid)) {
if (!responseOwner.valid) {
this.notificationsService.triggerAlert(
this.notificationsService.showToast(
NOTIFICATION_TYPES.WARNING_ALERT_2,
new Map<string, string>([['owner', responseOwner.field]])
);
} else {
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.WARNING_ALERT);
this.notificationsService.showToast(NOTIFICATION_TYPES.WARNING_ALERT);
}
}
return values[0] && responseOwner.valid;
@ -83,7 +83,7 @@ export class FormsValidatorService {
result = result && responseOwner.valid;
});
if (!result) {
this.notificationsService.triggerAlert(
this.notificationsService.showToast(
NOTIFICATION_TYPES.WARNING_ALERT_2,
new Map<string, string>([['owner', responseOwner.field]])
);

View File

@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { MessageModal } from 'app/shared/models/message-modal';
@Injectable()
export class GeneralModalService {
private messageTriggered = new Subject<MessageModal>();
triggerMessage(message: MessageModal) {
this.messageTriggered.next(message);
}
getMessage(): Observable<MessageModal> {
return this.messageTriggered.asObservable();
}
}

View File

@ -1,15 +1,18 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Overlay } from '@angular/cdk/overlay';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { MAT_DIALOG_SCROLL_STRATEGY, MatDialog } from '@angular/material/dialog';
import { HttpClientInterceptor } from './http-client-interceptor.service';
import { NotificationService } from '../notifications/notification.service';
describe('HttpExtensionService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
providers: [HttpClientInterceptor, GeneralModalService, RequestInProgressService]
providers: [HttpClientInterceptor, RequestInProgressService, MatSnackBar, Overlay, MatDialog, { provide: MAT_DIALOG_SCROLL_STRATEGY }]
});
});

View File

@ -3,7 +3,7 @@ import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse
import { Observable } from 'rxjs';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { environment } from 'environments/environment';
import { tap } from 'rxjs/operators';
import { map, tap } from 'rxjs/operators';
import { NotificationService } from '../notifications/notification.service';
import { NOTIFICATION_TYPES } from '../../models/notifications';

View File

@ -1,37 +1,51 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
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 { AlertModel } from '../../models/alert-model';
import { ToastComponent } from '../../components/toast/toast.component';
import { DialogPopUpComponent } from '../../components/popup/dialog-pop-up.component';
@Injectable({
providedIn: 'root'
})
export class NotificationService {
errorSubject$: Subject<ErrorModel> = new Subject<ErrorModel>();
alertSubject$: Subject<AlertModel> = new Subject<AlertModel>();
public triggerError(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, addition?: Map<String, String>): void {
const errorModel = new ErrorModel(key, passedError, addition);
this.updateErrorSubject(errorModel);
constructor(private matSnack: MatSnackBar, private popup: MatDialog) {
}
getError(): Observable<ErrorModel> {
return this.errorSubject$.asObservable();
triggerError(key: NOTIFICATION_TYPES, passedError?: HttpErrorResponse, additions?: Map<String, String>): void {
this.popup.open(DialogPopUpComponent, {
data: { key, passedError, additions, isDialog: false },
backdropClass: 'backdrop',
position: { top: '3em' },
autoFocus: true,
maxWidth: '50em',
});
}
protected updateErrorSubject(errorToShow: ErrorModel) {
this.errorSubject$.next(errorToShow);
showDialog(message: string, callback?: Function): MatDialogRef<DialogPopUpComponent> {
const ref = this.popup.open(DialogPopUpComponent, {
data: { isDialog: true, message, callback },
backdropClass: 'backdrop',
position: { top: '3em' },
autoFocus: true,
maxWidth: '50em',
});
ref.beforeClosed().subscribe(call => {
if (typeof call === 'function') {
call();
}
});
return ref;
}
triggerAlert(key: NOTIFICATION_TYPES, additions?: Map<string, string>) {
const alert: AlertModel = new AlertModel(key, additions);
this.alertSubject$.next(alert);
}
getAlert(): Observable<AlertModel> {
return this.alertSubject$.asObservable();
showToast(key: NOTIFICATION_TYPES, additions?: Map<string, string>) {
this.matSnack.openFromComponent(ToastComponent, {
duration: 2000,
data: { key, additions },
panelClass: ['white', 'background-darkgreen']
});
}
}

View File

@ -1,11 +1,14 @@
import { inject, TestBed } from '@angular/core/testing';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Overlay } from '@angular/cdk/overlay';
import { MAT_DIALOG_SCROLL_STRATEGY, MatDialog } from '@angular/material/dialog';
import { NotificationService } from './notification.service';
describe('ErrorsService', () => {
describe('NotificationService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [NotificationService]
providers: [NotificationService, MatSnackBar, Overlay, MatDialog, { provide: MAT_DIALOG_SCROLL_STRATEGY }],
});
});

View File

@ -1,21 +0,0 @@
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
@Injectable()
export class RemoveConfirmationService {
private removeConfirmationCallbackSubject = new Subject<{ callback: Function, message: string }>();
private removeConfirmationCallback: Function;
setRemoveConfirmation(callback: Function, message: string) {
this.removeConfirmationCallback = callback;
this.removeConfirmationCallbackSubject.next({ callback, message });
}
getRemoveConfirmation(): Observable<{ callback: Function, message: string }> {
return this.removeConfirmationCallbackSubject.asObservable();
}
runCallbackFunction() {
this.removeConfirmationCallback();
}
}

View File

@ -14,17 +14,16 @@ import { ClassificationsService } from 'app/shared/services/classifications/clas
/**
* Components
*/
import { GeneralMessageModalComponent } from 'app/shared/components/general-message-modal/general-message-modal.component';
import { SpinnerComponent } from 'app/shared/components/spinner/spinner.component';
import { AlertComponent } from 'app/shared/components/alert/alert.component';
import { MasterAndDetailComponent } from 'app/shared/components/master-and-detail/master-and-detail.component';
import { TaskanaTreeComponent } from 'app/shared/components/tree/tree.component';
import { TypeAheadComponent } from 'app/shared/components/type-ahead/type-ahead.component';
import { RemoveConfirmationComponent } from 'app/shared/components/remove-confirmation/remove-confirmation.component';
import { FilterComponent } from 'app/shared/components/filter/filter.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 { ErrorModalComponent } from './components/error-message-modal/error-modal.component';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { SortComponent } from './components/sort/sort.component';
import { PaginationComponent } from './components/pagination/pagination.component';
import { NumberPickerComponent } from './components/number-picker/number-picker.component';
@ -50,6 +49,8 @@ import { DateTimeZonePipe } from './pipes/date-time-zone.pipe';
*/
import { HttpClientInterceptor } from './services/http-client-interceptor/http-client-interceptor.service';
import { AccessIdsService } from './services/access-ids/access-ids.service';
import { ToastComponent } from './components/toast/toast.component';
import { DialogPopUpComponent } from './components/popup/dialog-pop-up.component';
const MODULES = [
CommonModule,
@ -60,15 +61,15 @@ const MODULES = [
BsDatepickerModule.forRoot(),
AngularSvgIconModule,
HttpClientModule,
MatSnackBarModule,
MatDialogModule,
MatButtonModule,
RouterModule,
TreeModule.forRoot()
];
const DECLARATIONS = [
GeneralMessageModalComponent,
ErrorModalComponent,
SpinnerComponent,
AlertComponent,
MasterAndDetailComponent,
TaskanaTreeComponent,
TypeAheadComponent,
@ -83,18 +84,21 @@ const DECLARATIONS = [
SortComponent,
FilterComponent,
IconTypeComponent,
RemoveConfirmationComponent,
FieldErrorDisplayComponent,
PaginationComponent,
NumberPickerComponent,
ProgressBarComponent,
DatePickerComponent,
DropdownComponent
DropdownComponent,
ToastComponent,
DialogPopUpComponent
];
@NgModule({
declarations: DECLARATIONS,
imports: MODULES,
imports: [
MODULES
],
exports: DECLARATIONS,
providers: [
{
@ -105,7 +109,8 @@ const DECLARATIONS = [
AccessIdsService,
ClassificationsService,
WorkbasketService
]
],
entryComponents: [ToastComponent, DialogPopUpComponent]
})
export class SharedModule {
}

View File

@ -152,7 +152,7 @@ export class TaskMasterComponent implements OnInit, OnDestroy {
this.tasks = taskResource.tasks;
} else {
this.tasks = [];
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT_2);
this.notificationsService.showToast(NOTIFICATION_TYPES.INFO_ALERT_2);
}
this.tasksPageInformation = taskResource.page;
});

View File

@ -10,7 +10,6 @@ import { Component } from '@angular/core';
import { DomainService } from 'app/shared/services/domain/domain.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { SelectedRouteService } from 'app/shared/services/selected-route/selected-route';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { ClassificationsService } from 'app/shared/services/classifications/classifications.service';
import { TaskService } from '../../services/task.service';
import { TaskComponent } from './task.component';
@ -36,7 +35,7 @@ xdescribe('TaskComponent', () => {
imports: [FormsModule, HttpClientModule, RouterTestingModule.withRoutes(routes)],
declarations: [TaskComponent, SpinnerComponent, DummyDetailComponent],
providers: [TaskService, HttpClient, WorkbasketService, DomainService, RequestInProgressService,
SelectedRouteService, GeneralModalService, ClassificationsService]
SelectedRouteService, ClassificationsService]
}).compileComponents();
}));

View File

@ -6,9 +6,7 @@ import { Routes } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { Component } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { WorkplaceService } from '../../services/workplace.service';
import { TaskService } from '../../services/task.service';
import { TaskdetailsAttributeComponent } from '../taskdetails-attribute/attribute.component';
@ -39,8 +37,8 @@ xdescribe('TaskdetailsComponent', () => {
TaskdetailsGeneralFieldsComponent, TaskdetailsCustomFieldsComponent,
TaskdetailsAttributeComponent, DummyDetailComponent],
imports: [FormsModule, RouterTestingModule.withRoutes(routes), HttpClientModule],
providers: [TaskService, HttpClient, WorkplaceService, RemoveConfirmationService,
RequestInProgressService, NotificationService, GeneralModalService]
providers:
[TaskService, HttpClient, WorkplaceService, RequestInProgressService, NotificationService]
})
.compileComponents();
}));

View File

@ -3,10 +3,7 @@ import { Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { TaskService } from 'app/workplace/services/task.service';
import { RemoveConfirmationService } from 'app/shared/services/remove-confirmation/remove-confirmation.service';
import { Task } from 'app/workplace/models/task';
import { GeneralModalService } from 'app/shared/services/general-modal/general-modal.service';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { TaskanaDate } from 'app/shared/util/taskana.date';
import { ObjectReference } from 'app/workplace/models/object-reference';
@ -39,11 +36,8 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
private taskService: TaskService,
private workplaceService: WorkplaceService,
private router: Router,
private removeConfirmationService: RemoveConfirmationService,
private requestInProgressService: RequestInProgressService,
private notificationsService: NotificationService,
private generalModalService: GeneralModalService,
private errorsService: NotificationService,
private notificationService: NotificationService,
private masterAndDetailService: MasterAndDetailService) {
}
@ -70,7 +64,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task.customAttributes = this.taskClone.customAttributes.slice(0);
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
this.task.primaryObjRef = { ...this.taskClone.primaryObjRef };
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.INFO_ALERT);
this.notificationService.showToast(NOTIFICATION_TYPES.INFO_ALERT);
}
getTask(): void {
@ -85,7 +79,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.cloneTask();
this.taskService.selectTask(task);
}, error => {
this.errorsService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_7, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.FETCH_ERR_7, error);
});
}
}
@ -103,8 +97,10 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
}
deleteTask(): void {
this.removeConfirmationService.setRemoveConfirmation(this.deleteTaskConfirmation.bind(this),
`You are going to delete Task: ${this.currentId}. Can you confirm this action?`);
this.notificationService.showDialog(
`You are going to delete Task: ${this.currentId}. Can you confirm this action?`,
this.deleteTaskConfirmation.bind(this)
);
}
deleteTaskConfirmation(): void {
@ -113,7 +109,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task = null;
this.router.navigate(['taskana/workplace/tasks']);
}, error => {
this.errorsService.triggerError(NOTIFICATION_TYPES.DELETE_ERR_2, error);
this.notificationService.triggerError(NOTIFICATION_TYPES.DELETE_ERR_2, error);
});
}
@ -153,10 +149,10 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.task = task;
this.cloneTask();
this.taskService.publishUpdatedTask(task);
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.SUCCESS_ALERT_14);
this.notificationService.showToast(NOTIFICATION_TYPES.SUCCESS_ALERT_14);
}, () => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.DANGER_ALERT);
this.notificationService.showToast(NOTIFICATION_TYPES.DANGER_ALERT);
});
}
@ -165,7 +161,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.addDateToTask();
this.taskService.createTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationsService.triggerAlert(
this.notificationService.showToast(
NOTIFICATION_TYPES.SUCCESS_ALERT_13,
new Map<string, string>([['taskId', task.name]])
);
@ -175,7 +171,7 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.router.navigate([`../${task.taskId}`], { relativeTo: this.route });
}, () => {
this.requestInProgressService.setRequestInProgress(false);
this.notificationsService.triggerAlert(NOTIFICATION_TYPES.DANGER_ALERT_2);
this.notificationService.showToast(NOTIFICATION_TYPES.DANGER_ALERT_2);
});
}

View File

@ -7,6 +7,8 @@
<base href="./">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="assets/icons/taskana.png">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<taskana-root></taskana-root>

View File

@ -24,12 +24,12 @@ getTestBed().initTestEnvironment(
);
// Then we find all the tests.
const contextAdministration = require.context('./app/administration', true, /\.spec\.ts$/);
const contextWorplace = require.context('./app/workplace', true, /\.spec\.ts$/);
const contextWorkplace = require.context('./app/workplace', true, /\.spec\.ts$/);
// const contextMonitor = require.context('./app/monitor', true, /\.spec\.ts$/);
const contextShared = require.context('./app/shared', true, /\.spec\.ts$/);
// And load the modules.
contextAdministration.keys().map(contextAdministration);
contextWorplace.keys().map(contextWorplace);
contextWorkplace.keys().map(contextWorkplace);
// contextMonitor.keys().map(contextMonitor);
contextShared.keys().map(contextShared);
// Finally, start Karma to run the tests.

View File

@ -1,19 +1,19 @@
.placeholder img {
display: inline-block;
border-radius: 50%;
display: inline-block;
border-radius: 50%;
}
.no-margin {
margin: 0px;
margin: 0px;
}
.content-margin {
margin: 0px 10px 0px 10px;
margin: 0px 10px 0px 10px;
}
.no-border-radius {
border-radius: 0px;
border-radius: 0px;
}
/*
@ -22,139 +22,139 @@
/* Move down content because we have a fixed navbar that is 55px tall */
.container-main {
margin-top: 55px;
overflow-y: hidden;
/*Min mobile view size*/
min-width: 420px;
margin-top: 55px;
overflow-y: hidden;
/*Min mobile view size*/
min-width: 420px;
}
.container-scrollable {
max-height: calc(100vh - 55px);
height: calc(100vh - 55px);
overflow: hidden;
max-height: calc(100vh - 55px);
height: calc(100vh - 55px);
overflow: hidden;
}
.vertical-center {
/* Make it a flex container */
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
/* Make it a flex container */
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
/* In legacy web browsers such as Firefox 9
we need to specify the width of the flex container */
width: 100%;
/* In legacy web browsers such as Firefox 9
we need to specify the width of the flex container */
width: 100%;
/* Also 'margin: 0 auto' doesn't have any effect on flex items in such web browsers
hence the bootstrap's container won't be aligned to the center anymore.
Therefore, we should use the following declarations to get it centered again */
-webkit-box-pack: center;
-moz-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
/* Also 'margin: 0 auto' doesn't have any effect on flex items in such web browsers
hence the bootstrap's container won't be aligned to the center anymore.
Therefore, we should use the following declarations to get it centered again */
-webkit-box-pack: center;
-moz-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
/*
Colors
*/
.white {
color: white;
color: white;
& svg {
fill: white;
}
& svg {
fill: white;
}
}
.blue {
color: $blue;
color: $blue;
& svg {
fill: $blue;
}
& svg {
fill: $blue;
}
}
.blue-green {
color: $blue-green;
color: $blue-green;
& svg {
fill: $blue-green;
}
& svg {
fill: $blue-green;
}
}
.green {
color: $green;
color: $green;
& svg {
fill: $green;
}
& svg {
fill: $green;
}
}
.dark-green {
color: $dark-green;
color: $dark-green;
& svg {
fill: $dark-green;
}
& svg {
fill: $dark-green;
}
}
.grey {
color: $grey;
color: $grey;
& svg {
fill: $grey;
}
& svg {
fill: $grey;
}
}
.brown {
color: $brown;
color: $brown;
& svg {
fill: $brown;
}
& svg {
fill: $brown;
}
}
.red {
color: $invalid;
color: $invalid;
& svg {
fill: $invalid;
}
& svg {
fill: $invalid;
}
}
.green-blue {
color: $blue-green;
color: $blue-green;
& svg {
fill: $blue-green;
}
& svg {
fill: $blue-green;
}
}
.aquamarine {
color: $aquamarine;
color: $aquamarine;
& svg {
fill: $aquamarine;
}
& svg {
fill: $aquamarine;
}
}
svg-icon.fa-fw > svg {
text-align: center;
width: 1.25em;
text-align: center;
width: 1.25em;
}
svg-icon {
position: relative;
top: 4px;
position: relative;
top: 4px;
}
.panel-default > .panel-heading .badge.warning {
background-color: $brown;
background-color: $brown;
}
.badge.priority {
background-color: #e1e1e1;
background-color: #e1e1e1;
}
@ -162,297 +162,307 @@ svg-icon {
*Remove bootstrap cols padding for master and detail component
*/
.no-gutter > taskana-master-and-detail > [class*='col-'] {
padding-right: 0;
padding-left: 0;
padding-right: 0;
padding-left: 0;
}
.small {
width: 16px;
height: 16px;
width: 16px;
height: 16px;
}
.dropdown-menu.action {
min-width: 0px;
min-width: 0px;
}
.footer-space-pagination-list {
max-height: calc(100vh - 130px);
height: calc(100vh - 130px);
overflow-y: auto;
overflow-x: hidden;
max-height: calc(100vh - 130px);
height: calc(100vh - 130px);
overflow-y: auto;
overflow-x: hidden;
}
.margin-right {
margin-right: 2px;
margin-right: 2px;
}
.no-border-bottom {
border-bottom: none;
border-bottom: none;
}
.selected {
z-index: 2;
background-color: #f5f5f5;
border-color: #f5f5f5;
z-index: 2;
background-color: #f5f5f5;
border-color: #f5f5f5;
}
.form-group.required .control-label:after {
content: " *";
color: red;
content: " *";
color: red;
}
.user-select {
margin-left: 2px;
margin-left: 2px;
}
.dropdown-menu-users {
min-width: 0px;
min-width: 0px;
}
.no-gutter > [class*='col-'] {
padding-right: 0;
padding-left: 0;
padding-right: 0;
padding-left: 0;
}
.table-center > thead > tr > th {
text-align: center;
vertical-align: middle;
text-align: center;
vertical-align: middle;
}
body {
overflow-y: hidden;
overflow-y: hidden;
}
.table-center > tbody > tr > td {
text-align: center;
vertical-align: middle;
text-align: center;
vertical-align: middle;
}
.table-center > tbody > tr > td.text-align {
text-align: left;
text-align: left;
}
.table-center > thead > tr > th.text-align {
text-align: left;
text-align: left;
}
.dropdown-menu-users > li {
margin-bottom: 5px;
margin-bottom: 5px;
}
.toolbar {
padding: 13px 15px;
padding: 13px 15px;
}
.open > .dropdown-menu {
opacity: 1;
visibility: visible;
opacity: 1;
visibility: visible;
}
.dropdown-menu {
display: block;
opacity: 0;
visibility: hidden;
-webkit-transition: opacity 300ms ease, visibility 300ms ease;
-moz-transition: opacity 300ms ease, visibility 300ms ease;
-o-transition: opacity 300ms ease, visibility 300ms ease;
transition: opacity 300ms ease, visibility 300ms ease;
display: block;
opacity: 0;
visibility: hidden;
-webkit-transition: opacity 300ms ease, visibility 300ms ease;
-moz-transition: opacity 300ms ease, visibility 300ms ease;
-o-transition: opacity 300ms ease, visibility 300ms ease;
transition: opacity 300ms ease, visibility 300ms ease;
}
/* buttons and icons vertical align */
.vertical-align {
vertical-align: top;
vertical-align: top;
}
.btn > svg-icon > svg {
vertical-align: middle;
vertical-align: middle;
}
a > svg-icon > svg {
vertical-align: text-top;
vertical-align: text-top;
}
/*end buttons and icons vertical align */
span.flip {
transform: rotateX(180deg);
transform: rotateX(180deg);
}
.panel-heading {
padding: 8px 15px 4px 15px;
padding: 8px 15px 4px 15px;
}
.panel {
border-radius: 0px;
border-radius: 0px;
}
.centered-spinner {
margin-top: 30px;
margin-bottom: 30px;
margin-top: 30px;
margin-bottom: 30px;
}
.centered-spinner-whole-screen {
position: absolute !important;
top: 20vh;
left: 42%;
position: absolute !important;
top: 20vh;
left: 42%;
}
.list-group-item {
padding: 5px 15px;
padding: 5px 15px;
}
.dual-list > taskana-filter > .list-group-search {
margin-top: 4px;
margin-top: 4px;
}
.container {
@media (min-width: 1200px) {
width: 100%;
}
@media (min-width: 1200px) {
width: 100%;
}
}
taskana-workbasket-information, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets, taskana-workbasket-details, taskana-monitor-tasks,
taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-monitor-timestamp {
& .panel {
border: none;
box-shadow: none;
margin-bottom: 0px;
& .panel {
border: none;
box-shadow: none;
margin-bottom: 0px;
& > .panel-body {
height: calc(100vh - 155px);
max-height: calc(100vh - 155px);
overflow-y: auto;
}
}
& > .panel-body {
height: calc(100vh - 155px);
max-height: calc(100vh - 155px);
overflow-y: auto;
}
}
}
taskana-task-details, taskana-classification-details, taskana-access-items-management, taskana-task, taskana-task-query {
& .panel {
border: none;
box-shadow: none;
margin-bottom: 0px;
& .panel {
border: none;
box-shadow: none;
margin-bottom: 0px;
& > .panel-body {
height: calc(100vh - 100px);
max-height: calc(100vh - 100px);
overflow-y: auto;
}
}
& > .panel-body {
height: calc(100vh - 100px);
max-height: calc(100vh - 100px);
overflow-y: auto;
}
}
}
taskana-task-query {
& .panel {
& > .panel-body {
height: calc(100vh - 105px);
max-height: calc(100vh - 105px);
}
}
& .panel {
& > .panel-body {
height: calc(100vh - 105px);
max-height: calc(100vh - 105px);
}
}
}
taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management {
& .panel {
& > .panel-heading {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}
}
& .panel {
& > .panel-heading {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}
}
}
li.list-group-item.active:hover {
color: #fff;
background-color: $green;
border-color: $green;
color: #fff;
background-color: $green;
border-color: $green;
}
.list-group-item.active {
background-color: $green;
background-color: $green;
}
li.list-group-item:hover {
color: #555;
text-decoration: none;
background-color: #f5f5f5;
color: #555;
text-decoration: none;
background-color: #f5f5f5;
}
.vertical-right-divider {
border-right: 1px solid #ccc;
height: calc(100vh - 55px);
border-right: 1px solid #ccc;
height: calc(100vh - 55px);
}
.horizontal-bottom-divider {
border-bottom: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.center-block > span.empty-icon, .empty-icon {
display: block;
width: 150px;
height: 150px;
fill: grey;
color: grey;
margin: 20px auto;
font-size: 100px;
display: block;
width: 150px;
height: 150px;
fill: grey;
color: grey;
margin: 20px auto;
font-size: 100px;
}
.btn.no-style {
border: none;
background-color: transparent;
border: none;
background-color: transparent;
}
.align-header {
margin-top: 3px;
margin-top: 3px;
}
.container-no-items {
top: 20vh;
height: 40vh;
top: 20vh;
height: 40vh;
}
.center-block {
text-align: center;
text-align: center;
}
.align-center {
text-align: center;
text-align: center;
}
.btn.rounded {
border-radius: 50%;
background-color: transparent;
border-radius: 50%;
background-color: transparent;
&:focus, &:active:focus {
outline: none;
}
&:focus, &:active:focus {
outline: none;
}
}
.modal-backdrop.show {
background-color: $transparent-grey;
background-color: $transparent-grey;
}
.padding-right.pull-right {
padding-right: 15px;
padding-right: 15px;
}
.backdrop {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 990;
background-color: white;
opacity: 0.8;
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 990;
background-color: rgba(180,180,180,0.7);
opacity: 0.8;
}
.mask {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 2000;
background-color: white;
opacity: 0.8;
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: 2000;
background-color: white;
opacity: 0.8;
}
.background-darkgreen {
background-color: $dark-green;
}
/* our header has a z-index of 1031 and the default z-index of the
mat-dialog is just 1000 which leads to undesirable overlap*/
.cdk-overlay-container {
z-index: 1337;
}