Merge branch 'SI-1386-Markierung-bei-Vorversion-entfernen' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.gridFailureInformation.frontend into DEVELOP
diff --git a/package.json b/package.json
index 38f0438..ff5723d 100644
--- a/package.json
+++ b/package.json
@@ -59,8 +59,8 @@
     "@ngrx/store-devtools": "8.6.0",
     "@ngx-translate/core": "11.0.1",
     "@ngx-translate/http-loader": "4.0.0",
-    "ag-grid-angular": "21.2.2",
-    "ag-grid-community": "21.2.2",
+    "ag-grid-angular": "23.2.1",
+    "ag-grid-community": "23.2.1",
     "angular-font-awesome": "3.1.2",
     "angular2-notifications": "2.0.0",
     "bootstrap": "4.4.1",
diff --git a/projects/grid-failure-information-app/src/app/app-config.service.spec.ts b/projects/grid-failure-information-app/src/app/app-config.service.spec.ts
index 088f839..d9f8031 100644
--- a/projects/grid-failure-information-app/src/app/app-config.service.spec.ts
+++ b/projects/grid-failure-information-app/src/app/app-config.service.spec.ts
@@ -1,3 +1,4 @@
+import { getExportChannels } from './shared/store/index';
 /********************************************************************************
  * Copyright (c) 2020 Contributors to the Eclipse Foundation
  *
@@ -60,4 +61,10 @@
     component.load();
     expect((component as any).config).toBeDefined();
   });
+
+  it('should transform config response', () => {
+    const response: any = { exportChannels: ['X'] };
+    const item = ConfigService.configAdapter(response);
+    expect(item.exportChannels).toBe(response.exportChannels);
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.spec.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.spec.ts
index e6e5cd0..b099e56 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.spec.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.spec.ts
@@ -1,5 +1,3 @@
-import { INITIAL_STATE } from './../../../shared/store/reducers/grid-failures/grid-failure-details-form.reducer';
-import { logging } from 'protractor';
 /********************************************************************************
  * Copyright (c) 2020 Contributors to the Eclipse Foundation
  *
@@ -18,6 +16,8 @@
 import { State } from '@grid-failure-information-app/shared/store';
 import { async } from '@angular/core/testing';
 import { Globals } from '@grid-failure-information-app/shared/constants/globals';
+import { INITIAL_STATE } from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer';
+import * as models from '@grid-failure-information-app/shared/models';
 
 describe('GridFailureDetailsComponent', () => {
   let component: GridFailureDetailsComponent;
@@ -47,7 +47,9 @@
       resetStationId() {},
       resetPostCode() {},
       disableUnnecessaryRequiredProperties() {},
+      setSelectedStation() {},
       gridFailureDetailsFormState$: of(gridFailureDetailsFormResponse as any),
+      disableStationAttributes: false,
     } as any;
     component = new GridFailureDetailsComponent(gridFailureSandbox, appState);
   });
@@ -104,6 +106,7 @@
     (component as any)._initialFailureLocationState();
     expect(component.mapInteractionMode).toBeFalsy();
   }));
+
   it('checks if _initialFailureLocationState works fine for NS', async(() => {
     component.failureLocationView === Globals.FAILURE_LOCATION_MAP;
 
@@ -120,6 +123,7 @@
     (component as any)._initialFailureLocationState();
     expect(component.mapInteractionMode).toBeFalsy();
   }));
+
   it('checks if _initialFailureLocationState works fine for MS', async(() => {
     component.failureLocationView === Globals.FAILURE_LOCATION_MAP;
     //MS
@@ -147,4 +151,37 @@
     component.setLocation();
     expect(spy).toHaveBeenCalled();
   });
+
+  it('should reset selected station if no value exists', () => {
+    const spy = spyOn(gridFailureSandbox, 'setSelectedStation');
+    component.resetSelectedStation(null);
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('should resize map via forceResize$.next(true)', () => {
+    const spy = spyOn(component.mapOptions.forceResize$, 'next');
+    component.resizeSetMap();
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('should change to currentVersionMode in response to disableStationAttributes=false', () => {
+    const spy = spyOn(component.events$, 'next');
+    gridFailureSandbox.gridFailureStations$ = of([new models.FailureStation()]);
+    component.changeMode();
+    expect(spy).toHaveBeenCalledWith({ eventType: component['_modeEnum'].currentVersionMode });
+  });
+
+  it('should change to oldVersionMode in response to disableStationAttributes=false', () => {
+    const spy = spyOn(component.events$, 'next');
+    gridFailureSandbox.disableStationAttributes = true;
+    gridFailureSandbox.gridFailureStations$ = of([new models.FailureStation()]);
+    component.changeMode();
+    expect(spy).toHaveBeenCalledWith({ eventType: component['_modeEnum'].oldVersionMode });
+  });
+
+  it('should determine mapInteractionMode correctly', () => {
+    component.failureLocationView = Globals.FAILURE_LOCATION_MAP;
+    gridFailureSandbox.disableStationAttributes = false;
+    expect(component.mapInteractionMode).toBeTruthy();
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.ts
index fc95f52..1cc83c6 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.ts
@@ -794,6 +794,7 @@
         this.showUpdateButton = true;
         this.showPublishButton = true;
         this.showCompleteButton = true;
+        this.showStornoButton = true;
         break;
       default:
         break;
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts
index 56e49ea..62ff9c2 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts
@@ -98,6 +98,8 @@
     filterParams: {
       comparator: dateTimeComparator,
       browserDatePicker: true,
+      buttons: ['apply', 'reset'],
+      closeOnApply: false,
     },
     cellRendererFramework: DateTimeCellRendererComponent,
   },
@@ -111,6 +113,8 @@
     filterParams: {
       comparator: dateTimeComparator,
       browserDatePicker: true,
+      buttons: ['apply', 'reset'],
+      closeOnApply: false,
     },
     cellRendererFramework: DateTimeCellRendererComponent,
   },
@@ -124,6 +128,8 @@
     filterParams: {
       comparator: dateTimeComparator,
       browserDatePicker: true,
+      buttons: ['apply', 'reset'],
+      closeOnApply: false,
     },
     cellRendererFramework: DateTimeCellRendererComponent,
   },
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
index 48afa16..23853ca 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
@@ -216,9 +216,18 @@
           this._router.navigate(['/grid-failures', event.data.id]);
           break;
         case this._eventTypeEnum.Add:
-          if ((this.sandbox.condensationList.length == 0 || event.data.branch === this.sandbox.condensationList[0].branch) && !event.data.condensed) {
+          const newCondensList: boolean = this.sandbox.condensationList.length === 0 && !this.sandbox.condenseId;
+          const editEmptyCondensList: boolean = (newCondensList || this.sandbox.condensationList.length === 0) && !!this.sandbox.condenseId;
+          const editCondensList: boolean = !newCondensList && !editEmptyCondensList && !this.sandbox.condenseId;
+          const gridFailureAlreadyCondensed = event.data.condensed;
+          const canAdd: boolean =
+            (newCondensList ||
+              (editCondensList && this.sandbox.condensationList[0].branch === event.data.branch) ||
+              (editEmptyCondensList && this.sandbox.condenseBranch === event.data.branch)) &&
+            !gridFailureAlreadyCondensed;
+          if (canAdd) {
             this.sandbox.addItemToCondensationList(event.data);
-          } else if (event.data.condensed) {
+          } else if (gridFailureAlreadyCondensed) {
             break;
           } else {
             this._utilService.displayNotification('DifferentBranchesWarning', 'alert');
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure.sandbox.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure.sandbox.ts
index a44b273..b44b3c6 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure.sandbox.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure.sandbox.ts
@@ -45,6 +45,7 @@
   public qualifierFilterIsActive: boolean = false;
   public condensationList: GridFailure[] = new Array();
   public condenseId: string = null;
+  public condenseBranch: string = null;
   public StateEnum = StateEnum;
   public RolesEnum = RolesEnum;
   public isReminderActive$: Observable<boolean> = this.appState$.select(store.getGridFailureReminderData);
@@ -71,6 +72,7 @@
 
   public clearGridFailureCondensation(): void {
     this.condenseId = null;
+    this.condenseBranch = null;
     this.condensationList = [];
     this.loadGridFailures();
   }
@@ -118,6 +120,7 @@
       )
       .subscribe((condensedGridFailures: GridFailure[]) => {
         this.condensationList = condensedGridFailures;
+        this.condenseBranch = condensedGridFailures && condensedGridFailures.length > 0 ? condensedGridFailures[0].branch : null;
       });
 
     combineLatest(
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.spec.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.spec.ts
index dac1c66..da1755b 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.spec.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.spec.ts
@@ -112,9 +112,20 @@
     expect(item.id).toBe(response.id);
   });
 
+  it('should transform  publication channel list response', () => {
+    const response: any = [{ id: 'X' }];
+    expect(GridFailureService.publicationChannelListAdapter(response)[0].id).toBe('X');
+  });
+
   it('should transform publication channel response', () => {
     const response: any = { id: 'X' };
     const item = GridFailureService.publicationChannelAdapter(response);
     expect(item.id).toBe(response.id);
   });
+
+  it('should not transform reminder response', () => {
+    const response: any = true;
+    const test = GridFailureService.reminderAdapter(response);
+    expect(test).toBe(response);
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/constants/globals.ts b/projects/grid-failure-information-app/src/app/shared/constants/globals.ts
index 69e5ee9..ff90549 100644
--- a/projects/grid-failure-information-app/src/app/shared/constants/globals.ts
+++ b/projects/grid-failure-information-app/src/app/shared/constants/globals.ts
@@ -32,6 +32,8 @@
     inRange: 'ist zwischen',
     andCondition: 'und',
     orCondition: 'oder',
+    resetFilter: 'Filter löschen',
+    applyFilter: 'Filter anwenden',
   };
   public static PROPERTIES_TO_BOX: string[] = ['addressPolygonPoints', '__formBranch', 'distributionGroupUuids', 'stationIds', 'publicationChannels'];
 
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/date-time-picker-view-adapter.directive.spec.ts b/projects/grid-failure-information-app/src/app/shared/directives/date-time-picker-view-adapter.directive.spec.ts
index 2d86709..4e6bc9f 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/date-time-picker-view-adapter.directive.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/date-time-picker-view-adapter.directive.spec.ts
@@ -1,8 +1,67 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
 import { DateTimePickerViewAdapterDirective } from '@grid-failure-information-app/shared/directives/date-time-picker-view-adapter.directive';
+import { DateTimePickerComponent } from '@grid-failure-information-app/shared/components/date-time-picker/date-time-picker.component';
+import { NgbPopoverConfig } from '@ng-bootstrap/ng-bootstrap';
+import { DateTimeModel } from '@grid-failure-information-app/shared/models/date-time.model';
+import { dateTimePickerValueConverter } from '@grid-failure-information-app/shared/utility';
+import { FormControlState } from 'ngrx-forms';
 
 describe('DateTimePickerViewAdapaterDirective', () => {
+  let config: NgbPopoverConfig;
+  let component: DateTimePickerComponent;
+  let directive: DateTimePickerViewAdapterDirective;
+
+  beforeEach(() => {
+    config = new NgbPopoverConfig();
+    component = new DateTimePickerComponent(config);
+    directive = new DateTimePickerViewAdapterDirective(component);
+  });
+
   it('should create an instance', () => {
-    const directive = new DateTimePickerViewAdapterDirective({} as any);
     expect(directive).toBeTruthy();
   });
+
+  it('should set dateTimeViewValue to null', () => {
+    directive.setViewValue(null);
+    expect(directive['_dateTimePickerComponent'].dateTimeViewValue).toBeNull;
+  });
+
+  it('should set dateTimeViewValue to model', () => {
+    directive.setViewValue('20200618');
+    directive['dateTimeModel'] = DateTimeModel.fromLocalString('20200618');
+    expect(directive['_dateTimePickerComponent'].dateTimeViewValue).toBe(dateTimePickerValueConverter.convertStateToViewValue(directive['dateTimeModel']));
+  });
+
+  it('should set onChangeCallback', () => {
+    let onChangeCallback = value => {};
+    directive.setOnChangeCallback(onChangeCallback);
+    expect(directive['_dateTimePickerComponent'].onValueChangeCallBack).toBeDefined();
+  });
+
+  it('should set markTouchedCallBack', () => {
+    directive.setOnTouchedCallback(() => {});
+    expect(directive['_dateTimePickerComponent'].markTouched).toBeDefined();
+  });
+
+  it('should set isDisabled', () => {
+    directive.setIsDisabled(true);
+    expect(directive['_dateTimePickerComponent'].isDisabled).toBeTruthy();
+  });
+
+  it('should set isValid property', () => {
+    let state: FormControlState<any> = { isValid: true } as any;
+    directive.ngrxFormControlState = state;
+    expect(directive['_dateTimePickerComponent'].isValid).toBeTruthy();
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts b/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts
index 7c4d223..445d934 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/form-disable.directive.spec.ts
@@ -13,10 +13,15 @@
 import { FormDisableDirective } from '@grid-failure-information-app/shared/directives/form-disable.directive';
 import { async } from '@angular/core/testing';
 import { of } from 'rxjs/observable/of';
+import { FormState } from 'ngrx-forms';
+import { PermissionsModel } from '@grid-failure-information-app/shared/models/permissions.model';
+import { RolesEnum } from '@grid-failure-information-app/shared/constants/enums';
 
 describe('FormDisableDirective', () => {
+  let directive: FormDisableDirective;
   let viewContainerRef: any;
   let appState: any;
+
   beforeEach(async(() => {
     viewContainerRef = {
       createEmbeddedView: () => {},
@@ -30,10 +35,26 @@
       select: () => of({ roles: ['grid-failure-reader'] }),
       map: () => of({ reader: true }),
     };
+    directive = new FormDisableDirective(appState as any);
   }));
 
   it('should create an instance', () => {
-    const directive = new FormDisableDirective(appState as any);
     expect(directive).toBeTruthy();
   });
+
+  it('should not dispatch action if formState is disabled', () => {
+    let state: FormState<any> = { isDisabled: true } as any;
+    let dispatchSpy = spyOn(directive['_appState$'], 'dispatch');
+    directive.ngrxFormState = state;
+    expect(dispatchSpy).toHaveBeenCalledTimes(0);
+  });
+
+  it('should dispatch action if formState is not disabled', () => {
+    let permission: PermissionsModel = new PermissionsModel([RolesEnum.READER]);
+    directive['_permissions$'] = of(permission);
+    let state: FormState<any> = { isDisabled: false } as any;
+    let dispatchSpy = spyOn(directive['_appState$'], 'dispatch');
+    directive.ngrxFormState = state;
+    expect(dispatchSpy).toHaveBeenCalled();
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/form-validator.directive.spec.ts b/projects/grid-failure-information-app/src/app/shared/directives/form-validator.directive.spec.ts
index 6c48822..7b531d5 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/form-validator.directive.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/form-validator.directive.spec.ts
@@ -13,8 +13,25 @@
 import { FormValidatorDirective } from '@grid-failure-information-app/shared/directives/form-validator.directive';
 
 describe('FormValidator.DirectiveDirective', () => {
+  let directive: FormValidatorDirective;
+
+  beforeEach(() => {
+    directive = new FormValidatorDirective();
+  });
+
   it('should create an instance', () => {
-    const directive = new FormValidatorDirective();
     expect(directive).toBeTruthy();
   });
+
+  it('should set invalid property correctly', () => {
+    directive.required = true;
+    directive.ngrxFormControlState = { isDisabled: true, value: null } as any;
+    expect(directive.invalid).toBeTruthy();
+  });
+
+  it('should set valid property correctly', () => {
+    directive.required = true;
+    directive.ngrxFormControlState = { isDisabled: true, value: 'x' } as any;
+    expect(directive.valid).toBeTruthy();
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.spec.ts b/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.spec.ts
index c4af3ca..e21d9ef 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.spec.ts
@@ -1,8 +1,57 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
 import { FormControlVisibilityDirective } from './form-control-ui-state.directive';
+import { of } from 'rxjs/observable/of';
+import { State } from '@grid-failure-information-app/shared/store';
+import { Store } from '@ngrx/store';
+import { DisableAction, EnableAction, ResetAction, SetValueAction, NgrxFormControlDirective } from 'ngrx-forms';
 
-describe('FormControlUiStateDirective', () => {
+describe('FormControlVisibilityDirective ', () => {
+  let directive: FormControlVisibilityDirective;
+  let appState: Store<State>;
+
+  beforeEach(() => {
+    appState = of({
+      pipe: () => {},
+      dispatch: () => {},
+      select: () => {},
+      map: () => {},
+    }) as any;
+    directive = new FormControlVisibilityDirective(appState as any);
+  });
+
   it('should create an instance', () => {
-    // const directive = new FormControlUiStateDirective();
-    // expect(directive).toBeTruthy();
+    expect(directive).toBeTruthy();
+  });
+
+  it('should set isVisible property', () => {
+    directive.visibleByDependentField = true;
+    expect(directive['_isVisible']).toBeTruthy();
+  });
+
+  it('should dispatch EnableAction if isVisible = true', () => {
+    directive = new FormControlVisibilityDirective({ dispatch: () => null } as any);
+    let dispatchSpy = spyOn(directive['_appState$'], 'dispatch');
+    directive.ngrxFormControl = { state: { id: 'x' } } as any;
+    directive.visibleByDependentField = true;
+    expect(dispatchSpy).toHaveBeenCalledWith(new EnableAction(directive.ngrxFormControl.state.id));
+  });
+
+  it('should dispatch ResetAction if isVisible = false', () => {
+    directive = new FormControlVisibilityDirective({ dispatch: () => null } as any);
+    let dispatchSpy = spyOn(directive['_appState$'], 'dispatch');
+    directive.ngrxFormControl = { state: { id: 'x' } } as any;
+    directive.visibleByDependentField = false;
+    expect(dispatchSpy).toHaveBeenCalledWith(new ResetAction(directive.ngrxFormControl.state.id));
   });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.ts b/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.ts
index beee708..3cd9687 100644
--- a/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.ts
+++ b/projects/grid-failure-information-app/src/app/shared/directives/forms/form-control-ui-state.directive.ts
@@ -1,3 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
 import { Directive, Input, HostBinding, ContentChild } from '@angular/core';
 import * as store from '@grid-failure-information-app/shared/store';
 import { Store } from '@ngrx/store';