Merge branch 'DEVELOP' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.gridFailureInformation.frontend into SI-1947-BUG-Schnellfilter-qualifiziert-filtert-nicht-veroeffentlich
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 32808e9..0455f82 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
@@ -415,17 +415,17 @@
   });
 
   it('should return true for detailFieldVisibility in case no config is provided', () => {
-    component.visibilityConfiguration = null;
+    component.mapOptions.visibilityConfiguration = null;
     expect(component.determineDetailFieldVisibility('description')).toBeTruthy();
   });
 
   it('should return true for detailFieldVisibility if config provides "show" string for a specified form field', () => {
-    component.visibilityConfiguration = { fieldVisibility: { description: 'show' } as any } as any;
+    component.mapOptions.visibilityConfiguration = { fieldVisibility: { description: 'show' } as any } as any;
     expect(component.determineDetailFieldVisibility('description')).toBeTruthy();
   });
 
   it('should return false for detailFieldVisibility if config does not provides "show" string for a specified form field', () => {
-    component.visibilityConfiguration = { fieldVisibility: { description: 'hide' } as any } as any;
+    component.mapOptions.visibilityConfiguration = { fieldVisibility: { description: 'hide' } as any } as any;
     expect(component.determineDetailFieldVisibility('description')).toBeFalsy();
   });
 });
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.ts
index da6d6f8..164ac0a 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.ts
@@ -26,7 +26,6 @@
 import { take, skipWhile, takeUntil, find, map } from 'rxjs/operators';
 import { unboxProperties } from '@grid-failure-information-app/shared/utility/form-utils';
 import { unbox } from 'ngrx-forms';
-import { VisibilityConfigurationInterface } from '@grid-failure-information-app/shared/interfaces/visibility-configuration.interface';
 import { determineDetailFieldVisibility } from '@grid-failure-information-app/shared/utility';
 
 @Component({
@@ -58,7 +57,6 @@
   }
   public stationsColumnDefinition: any = STATION_COLDEF;
   public frameworkComponents: any;
-  public visibilityConfiguration: VisibilityConfigurationInterface;
 
   private _subscription: Subscription;
   private _modeEnum = ModeEnum;
@@ -75,7 +73,6 @@
     this.appState$.select(store.getPreConfiguration).subscribe(preConfig => {
       if (preConfig) {
         this.mapOptions = new MapOptions(preConfig);
-        this.visibilityConfiguration = preConfig.visibilityConfiguration;
       }
     });
     this.gridFailureDetailsSandbox.gridFailureDetailsFormState$.subscribe(formState => {
@@ -189,7 +186,7 @@
   }
 
   public determineDetailFieldVisibility(field: string): boolean {
-    return determineDetailFieldVisibility(this.visibilityConfiguration, 'fieldVisibility', field);
+    return determineDetailFieldVisibility(this.mapOptions.visibilityConfiguration, 'fieldVisibility', field);
   }
 
   private _initialFailureLocationState() {
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 09180f0..ab364a7 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
@@ -198,8 +198,8 @@
     this.appState$.dispatch(gridFailureActions.loadAllAddressCommunities({ branch: null }));
   }
 
-  public loadGridFailureDistricts(community: string): void {
-    this.appState$.dispatch(gridFailureActions.loadAddressDistrictsOfCommunity({ branch: null, community: community }));
+  public loadGridFailureDistricts(community: string, branch: string): void {
+    this.appState$.dispatch(gridFailureActions.loadAddressDistrictsOfCommunity({ branch: branch, community: community }));
   }
 
   public dateValueConverter = NgrxValueConverters.objectToJSON;
@@ -891,7 +891,9 @@
         break;
 
       case formState.controls.city.id:
-        this.loadGridFailureDistricts(formState.value.city);
+        this.loadGridFailureDistricts(
+          formState.value.city,
+          formState.value.branch);
         break;
 
       case formState.controls.district.id:
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts
index 8fb8236..5da79e0 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.spec.ts
@@ -16,7 +16,8 @@
 import { GridFailureSandbox } from '@grid-failure-information-app/pages/grid-failure/grid-failure-list/grid-failure.sandbox';
 import { Subscription, of, Subject } from 'rxjs';
 import { UtilService } from '@grid-failure-information-app/shared/utility';
-import { RolesEnum } from '@grid-failure-information-app/shared/constants/enums';
+import { StateEnum } from '@grid-failure-information-app/shared/constants/enums';
+import { MapOptions } from '@openk-libs/grid-failure-information-map/shared/models/map-options.model';
 
 describe('GridFailureListComponent ', () => {
   let component: GridFailureListComponent;
@@ -29,6 +30,7 @@
   let _gridApi: any;
   let filterInstance: any;
   let preConfig$: any;
+  let mapOptions: MapOptions;
 
   beforeEach(() => {
     router = { navigate() {} } as any;
@@ -48,7 +50,8 @@
     utilService = {
       displayNotification() {},
     } as any;
-    appState$ = { dispatch: () => {}, pipe: () => of(true), select: () => of(true) } as any;
+    mapOptions = new MapOptions();
+    appState$ = { dispatch: () => {}, pipe: () => of(true), select: () => of() } as any;
     preConfig$ = of({ visibilityConfiguration: { fieldVisibility: {} } });
     subscription = { unsubscribe() {} } as any;
     _gridApi = { onFilterChanged() {}, setFilterModel(model: any) {} } as any;
@@ -66,11 +69,43 @@
     expect(component).toBeTruthy();
   });
 
-  it('should call appropriate functions for edit event', () => {
+  it('should call appropriate functions for edit event and ngOnInit', () => {
+    mapOptions.visibilityConfiguration = { fieldVisibility: { failureClassification: 'show' } } as any;
+    appState$ = { dispatch: () => {}, pipe: () => of(true), select: () => of(mapOptions as any) } as any;
+    component = new GridFailureListComponent(sandbox, appState$, router, utilService);
     const spy: any = spyOn(router, 'navigate');
     component.ngOnInit();
     component.gridOptions.context.eventSubject.next({ type: 'edit', data: new GridFailure() });
     expect(spy).toHaveBeenCalled();
+    expect(component.overviewColumnDefinition).toBeDefined();
+    expect(component.condensationColumnDefinition).toBeDefined();
+  });
+
+  it('should not define column definitions without configuration', () => {
+    mapOptions.visibilityConfiguration = null;
+    appState$ = { dispatch: () => {}, pipe: () => of(true), select: () => of(mapOptions as any) } as any;
+    component = new GridFailureListComponent(sandbox, appState$, router, utilService);
+
+    component.ngOnInit();
+    expect(component.overviewColumnDefinition).not.toBeDefined();
+    expect(component.condensationColumnDefinition).not.toBeDefined();
+  });
+
+  it('should pass external filter if the appropriate conditions are met (published)', () => {
+    let node: any = { data: { publicationStatus: StateEnum.PUBLISHED } };
+    component.sandbox.publisherFilterIsActive = true;
+    expect(component.doesExternalFilterPass(node)).toBeTruthy();
+  });
+
+  it('should pass external filter if the appropriate conditions are met (qualified)', () => {
+    let node: any = { data: { statusIntern: StateEnum.QUALIFIED } };
+    component.sandbox.publisherFilterIsActive = true;
+    expect(component.doesExternalFilterPass(node)).toBeTruthy();
+  });
+
+  it('should should not pass external filter if the appropriate conditions are not met', () => {
+    let node: any;
+    expect(component.doesExternalFilterPass(node)).toBeFalsy();
   });
 
   it('should call appropriate functions for add event', () => {
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 ea701c7..29f2f70 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
@@ -24,7 +24,7 @@
 import { Subject } from 'rxjs';
 import { takeUntil, take, delay } from 'rxjs/operators';
 import { Globals } from '@grid-failure-information-app/shared/constants/globals';
-import { RolesEnum } from '@grid-failure-information-app/shared/constants/enums';
+import { RolesEnum, VisibilityEnum } from '@grid-failure-information-app/shared/constants/enums';
 import { MapOptions } from '@openk-libs/grid-failure-information-map/shared/models/map-options.model';
 import * as store from '@grid-failure-information-app/shared/store';
 import { Store } from '@ngrx/store';
@@ -38,6 +38,7 @@
 export class GridFailureListComponent extends BaseList implements OnInit, OnDestroy {
   public Globals = Globals;
   public RolesEnum = RolesEnum;
+  public VisibilityEnum = VisibilityEnum;
   public overviewColumnDefinition: any;
   public condensationColumnDefinition: any;
   public mapOptions: MapOptions = new MapOptions();
@@ -62,25 +63,22 @@
   constructor(public sandbox: GridFailureSandbox, private appState$: Store<store.State>, private _router: Router, private _utilService: UtilService) {
     super();
     this.frameworkComponents = { setFilterComponent: SetFilterComponent, headerCellRendererComponent: HeaderCellRendererComponent };
-
-    this.preConfig$.pipe(takeUntil(this._endSubscriptions$)).subscribe(config => {
-      if (config && config.visibilityConfiguration) {
-        GRID_FAILURE_COLDEF.forEach((column: any) => {
-          column['hide'] = config.visibilityConfiguration.fieldVisibility[column['field']] === 'hide';
-        });
-        this.overviewColumnDefinition = GRID_FAILURE_COLDEF;
-        GRID_FAILURE_FOR_CONDENSATION_COLDEF.forEach((column: any) => {
-          column['hide'] = config.visibilityConfiguration.fieldVisibility[column['field']] === 'hide';
-        });
-        this.condensationColumnDefinition = GRID_FAILURE_FOR_CONDENSATION_COLDEF;
-      }
-    });
   }
 
   ngOnInit(): void {
     this._setInitialGridOptions();
     this.appState$.select(store.getPreConfiguration).subscribe(mapConfig => {
       this.mapOptions = new MapOptions(mapConfig);
+      if (mapConfig && mapConfig.visibilityConfiguration) {
+        GRID_FAILURE_COLDEF.forEach((column: any) => {
+          column['hide'] = mapConfig.visibilityConfiguration.fieldVisibility[column['field']] === VisibilityEnum.HIDE;
+        });
+        this.overviewColumnDefinition = GRID_FAILURE_COLDEF;
+        GRID_FAILURE_FOR_CONDENSATION_COLDEF.forEach((column: any) => {
+          column['hide'] = mapConfig.visibilityConfiguration.fieldVisibility[column['field']] === VisibilityEnum.HIDE;
+        });
+        this.condensationColumnDefinition = GRID_FAILURE_FOR_CONDENSATION_COLDEF;
+      }
     });
   }
 
diff --git a/projects/grid-failure-information-app/src/app/shared/constants/enums.ts b/projects/grid-failure-information-app/src/app/shared/constants/enums.ts
index e40107b..900f65a 100644
--- a/projects/grid-failure-information-app/src/app/shared/constants/enums.ts
+++ b/projects/grid-failure-information-app/src/app/shared/constants/enums.ts
@@ -30,10 +30,10 @@
   VE = 'veröffentlicht',
 }
 
-export enum DistributionPublicationStatusEnum{
-  PUBLISH ='publish',
-  COMPLETE ='complete',
-  UPDATE ='update',
+export enum DistributionPublicationStatusEnum {
+  PUBLISH = 'publish',
+  COMPLETE = 'complete',
+  UPDATE = 'update',
 }
 
 export enum RolesEnum {
@@ -83,3 +83,8 @@
   DISTRICT_HEATING = 'F',
   SECONDARY_TECHNIQUE = 'ST',
 }
+
+export enum VisibilityEnum {
+  SHOW = 'show',
+  HIDE = 'hide',
+}
diff --git a/projects/grid-failure-information-app/src/app/shared/interfaces/visibility-configuration.interface.ts b/projects/grid-failure-information-app/src/app/shared/interfaces/visibility-configuration.interface.ts
index 679e78d..f2dd988 100644
--- a/projects/grid-failure-information-app/src/app/shared/interfaces/visibility-configuration.interface.ts
+++ b/projects/grid-failure-information-app/src/app/shared/interfaces/visibility-configuration.interface.ts
@@ -17,6 +17,15 @@
     internalRemark: string;
     responsibility: string;
   };
+  mapExternTooltipVisibility: {
+    branch: string;
+    city: string;
+    district: string;
+    expectedReasonText: string;
+    failureBegin: string;
+    failureEndPlanned: string;
+    postcode: string;
+  };
   tableExternColumnVisibility: {
     branch: string;
     city: string;
diff --git a/projects/grid-failure-information-app/src/app/shared/utility/utilityHelpers.ts b/projects/grid-failure-information-app/src/app/shared/utility/utilityHelpers.ts
index 534b7a1..becb2c7 100644
--- a/projects/grid-failure-information-app/src/app/shared/utility/utilityHelpers.ts
+++ b/projects/grid-failure-information-app/src/app/shared/utility/utilityHelpers.ts
@@ -16,6 +16,7 @@
 import { NgrxValueConverter, NgrxValueConverters } from 'ngrx-forms';
 import { FailureHousenumber } from '@grid-failure-information-app/shared/models';
 import { VisibilityConfigurationInterface } from '@grid-failure-information-app/shared/interfaces/visibility-configuration.interface';
+import { VisibilityEnum } from '@grid-failure-information-app/shared/constants/enums';
 
 /**
  * Returns formated date based on given culture
@@ -146,7 +147,7 @@
 
 export function determineDetailFieldVisibility(config: VisibilityConfigurationInterface, config_prop: string, field: string): boolean {
   if (config && config[config_prop]) {
-    return config[config_prop][field] === 'show';
+    return config[config_prop][field] === VisibilityEnum.SHOW;
   } else {
     return true;
   }
diff --git a/projects/grid-failure-information-map-app/src/app/app-config.service.spec.ts b/projects/grid-failure-information-map-app/src/app/app-config.service.spec.ts
index defb76b..6434262 100644
--- a/projects/grid-failure-information-map-app/src/app/app-config.service.spec.ts
+++ b/projects/grid-failure-information-map-app/src/app/app-config.service.spec.ts
@@ -24,4 +24,10 @@
   it('should be created', () => {
     expect(service).toBeTruthy();
   });
+
+  it('should call http het via getConfig()', () => {
+    const spy: any = spyOn(service['http'], 'get');
+    service.getConfig();
+    expect(spy).toHaveBeenCalledWith('public-settings');
+  });
 });
diff --git a/projects/grid-failure-information-table-app/src/app/app-config.service.spec.ts b/projects/grid-failure-information-table-app/src/app/app-config.service.spec.ts
new file mode 100644
index 0000000..f7f1837
--- /dev/null
+++ b/projects/grid-failure-information-table-app/src/app/app-config.service.spec.ts
@@ -0,0 +1,33 @@
+/********************************************************************************
+ * 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 { AppConfigService } from '@grid-failure-information-table-app/app/app-config.service';
+
+describe('AppConfigService', () => {
+  let service: AppConfigService;
+  let mockHttpClient;
+
+  beforeEach(() => {
+    mockHttpClient = { get: () => {} };
+    service = new AppConfigService(mockHttpClient);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+
+  it('should call http het via getConfig()', () => {
+    const spy: any = spyOn(service['http'], 'get');
+    service.getConfig();
+    expect(spy).toHaveBeenCalledWith('public-settings');
+  });
+});
diff --git a/projects/grid-failure-information-table-app/src/app/app-config.service.ts b/projects/grid-failure-information-table-app/src/app/app-config.service.ts
new file mode 100644
index 0000000..96aea46
--- /dev/null
+++ b/projects/grid-failure-information-table-app/src/app/app-config.service.ts
@@ -0,0 +1,25 @@
+/********************************************************************************
+ * 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 { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class AppConfigService {
+  constructor(private http: HttpClient) {}
+
+  getConfig() {
+    return this.http.get('public-settings');
+  }
+}
diff --git a/projects/grid-failure-information-table-app/src/app/app.component.html b/projects/grid-failure-information-table-app/src/app/app.component.html
index d573aec..58d06c1 100644
--- a/projects/grid-failure-information-table-app/src/app/app.component.html
+++ b/projects/grid-failure-information-table-app/src/app/app.component.html
@@ -23,3 +23,4 @@
 >
 </ag-grid-angular>
 <app-spinner [isRunning]="!(gridFailures)"></app-spinner>
+<div id="grid-failure-information-table-app-lastChange">Letzte Änderung: {{lastModDate}}</div>
diff --git a/projects/grid-failure-information-table-app/src/app/app.component.spec.ts b/projects/grid-failure-information-table-app/src/app/app.component.spec.ts
index c0c0e99..4a119d2 100644
--- a/projects/grid-failure-information-table-app/src/app/app.component.spec.ts
+++ b/projects/grid-failure-information-table-app/src/app/app.component.spec.ts
@@ -12,20 +12,29 @@
  ********************************************************************************/
 import { TableComponent } from '@grid-failure-information-table-app/app/app.component';
 import { AppTableService } from '@grid-failure-information-table-app/app/app-table.service';
-import { GridFailure } from '@grid-failure-information-app/shared/models';
+import { AppConfigService } from '@grid-failure-information-table-app/app/app-config.service';
+import { GridFailure, Settings } from '@grid-failure-information-app/shared/models';
 import { of } from 'rxjs';
 
 describe('AppComponent', () => {
   let component: TableComponent;
   let service: AppTableService;
+  let configService: AppConfigService;
   let gridFailureMapListAll: GridFailure[] = [];
 
   beforeEach(() => {
     service = {
-      loadGridFailureData: () => of(true)
+      loadGridFailureData: () => of(true),
     } as any;
-    gridFailureMapListAll = [new GridFailure({ postcode: '007' }), new GridFailure({ postcode: '4711' }), new GridFailure({ postcode: '0815' })];
-    component = new TableComponent(service);
+    configService = {
+      getConfig: () => of(true),
+    } as any;
+    gridFailureMapListAll = [
+      new GridFailure({ postcode: '007', modDate: '2020-08-13T13:35:44.808Z' }),
+      new GridFailure({ postcode: '4711', modDate: '2020-08-14T13:35:44.808Z' }),
+      new GridFailure({ postcode: '0815', modDate: '2019-08-13T13:35:44.808Z' }),
+    ];
+    component = new TableComponent(service, configService, null);
     (component as any)._gridFailuresAll = gridFailureMapListAll;
     component.gridFailures = gridFailureMapListAll.map(i => Object.assign(i));
   });
@@ -44,6 +53,7 @@
     let sortModel;
     let params = { api: { setSortModel: sortModel = {} } };
     component['_gridApi'] = params.api;
+    component['_datePipe'] = { transform: () => '18.09.2020 / 10:17' } as any;
     const spy: any = spyOn(component['_gridApi'], 'setSortModel');
     component.onGridReady(params);
     expect(spy).toHaveBeenCalled();
@@ -51,6 +61,7 @@
 
   it('should assign all gridfailures to table', () => {
     component.postcode = '';
+    component['_datePipe'] = { transform: () => '18.09.2020 / 10:17' } as any;
     expect(component.gridFailures.length).toEqual(gridFailureMapListAll.length);
   });
 
@@ -59,4 +70,20 @@
     expect(component.gridFailures.length).toEqual(1);
     expect(component.gridFailures[0].postcode).toEqual('007');
   });
+
+  it('should get the last modDate of the GridFailure array after "_getLastModeDate"', () => {
+    const lastTimeStamp = (component as any)._getLastModeDate();
+    expect(lastTimeStamp).toEqual(1597412144808); // == '2020-08-14T13:35:44.808Z'
+  });
+
+  it('should define columnDefs in case config is provided', () => {
+    let config = new Settings();
+    config.visibilityConfiguration = { tableExternColumnVisibility: { failureClassification: 'show' } } as any;
+    configService = {
+      getConfig: () => of(config),
+    } as any;
+    component = new TableComponent(service, configService, null);
+    component.ngOnInit();
+    expect(component.columnDefs).toBeDefined();
+  });
 });
diff --git a/projects/grid-failure-information-table-app/src/app/app.component.ts b/projects/grid-failure-information-table-app/src/app/app.component.ts
index 927f011..36ff684 100644
--- a/projects/grid-failure-information-table-app/src/app/app.component.ts
+++ b/projects/grid-failure-information-table-app/src/app/app.component.ts
@@ -12,11 +12,15 @@
  ********************************************************************************/
 import { Component, Input, OnInit, OnDestroy } from '@angular/core';
 import { AppTableService } from '@grid-failure-information-table-app/app/app-table.service';
-import { GridFailure } from '@grid-failure-information-app/shared/models';
+import { GridFailure, Settings } from '@grid-failure-information-app/shared/models';
 import { APP_TABLE_COLDEF } from '@grid-failure-information-table-app/app/app-table-column-definition';
 import { GridOptions } from 'ag-grid-community';
 import { Globals } from '@grid-failure-information-app/shared/constants/globals';
 import { Subscription } from 'rxjs';
+import { DatePipe } from '@angular/common';
+import { AppConfigService } from '@grid-failure-information-table-app/app/app-config.service';
+import { take } from 'rxjs/operators';
+import { VisibilityEnum } from '@grid-failure-information-app/shared/constants/enums';
 
 @Component({
   selector: 'app-root',
@@ -25,17 +29,19 @@
 })
 export class TableComponent implements OnInit, OnDestroy {
   public Globals = Globals;
-  public columnDefs: any = APP_TABLE_COLDEF;
+  public VisibilityEnum = VisibilityEnum;
+  public columnDefs: any;
   public defaultColDef: any;
   public gridOptions: GridOptions;
   public noRowsTemplate: string;
   public gridFailures: GridFailure[];
+  public lastModDate: string;
 
   private _gridApi;
   private _gridFailuresAll: GridFailure[];
-  private _subscription: Subscription;
+  private _subscription: Subscription = new Subscription();
 
-  constructor(private _appTableService: AppTableService) {
+  constructor(private _appTableService: AppTableService, private _configService: AppConfigService, private _datePipe: DatePipe) {
     this.defaultColDef = {
       sortable: true,
       suppressMovable: true,
@@ -49,10 +55,29 @@
   }
 
   ngOnInit() {
-    this._subscription = this._appTableService.loadGridFailureData().subscribe((data: GridFailure[]) => {
-      this.gridFailures = data;
-      this._gridFailuresAll = data;
-    });
+    this._subscription.add(
+      this._configService
+        .getConfig()
+        .pipe(take(1))
+        .subscribe((config: Settings) => {
+          if (config && config.visibilityConfiguration) {
+            APP_TABLE_COLDEF.forEach((column: any) => {
+              column['hide'] = config.visibilityConfiguration.tableExternColumnVisibility[column['field']] === VisibilityEnum.HIDE;
+            });
+            this.columnDefs = APP_TABLE_COLDEF;
+          }
+        })
+    );
+    this._subscription.add(
+      this._appTableService
+        .loadGridFailureData()
+        .pipe(take(1))
+        .subscribe((data: GridFailure[]) => {
+          this.gridFailures = data;
+          this._gridFailuresAll = data;
+          this.lastModDate = this._datePipe.transform(this._getLastModeDate(), Globals.DATE_TIME_FORMAT);
+        })
+    );
     this.gridOptions = {
       localeText: Globals.LOCALE_TEXT,
     };
@@ -67,4 +92,10 @@
   ngOnDestroy(): void {
     this._subscription.unsubscribe();
   }
+
+  private _getLastModeDate(): number {
+    let modeDates: number[] = this._gridFailuresAll.map(gf => Date.parse(gf.modDate));
+    modeDates = modeDates.sort((a, b) => b - a); // sort timestamps descending
+    return modeDates[0];
+  }
 }
diff --git a/projects/grid-failure-information-table-app/src/app/app.module.ts b/projects/grid-failure-information-table-app/src/app/app.module.ts
index e2c2e1f..8965120 100644
--- a/projects/grid-failure-information-table-app/src/app/app.module.ts
+++ b/projects/grid-failure-information-table-app/src/app/app.module.ts
@@ -18,8 +18,10 @@
 import { HttpClientModule } from '@angular/common/http';
 import { AgGridModule } from 'ag-grid-angular';
 import { PublicApiModule } from '@grid-failure-information-app/app/public-api.module';
+import { AppConfigService } from '@grid-failure-information-table-app/app/app-config.service';
+import { DatePipe } from '@angular/common';
 
-const providers =[AppTableService];
+const providers =[AppTableService, AppConfigService, DatePipe];
 
 @NgModule({
   declarations: [TableComponent],
@@ -43,7 +45,7 @@
   static forRoot(): ModuleWithProviders {
     return {
       ngModule: AppModule,
-      providers: providers
+      providers: providers,
     };
   }
 }
diff --git a/projects/grid-failure-information-table-app/src/app/utilityHelpers.spec.ts b/projects/grid-failure-information-table-app/src/app/utilityHelpers.spec.ts
index b28aa07..6922310 100644
--- a/projects/grid-failure-information-table-app/src/app/utilityHelpers.spec.ts
+++ b/projects/grid-failure-information-table-app/src/app/utilityHelpers.spec.ts
@@ -42,4 +42,14 @@
     let testValue = utilityHelpers.dateTimeComparator(filterLocalDateAtMidnight, null);
     expect(testValue).toBe(-1);
   });
+
+  it('should compare two strings via stringInsensitiveComparator', () => {
+    let testValue = utilityHelpers.stringInsensitiveComparator('A', 'b');
+    expect(testValue).toBe(-1);
+  });
+
+  it('should handle null values in stringInsensitiveComparator ', () => {
+    let testValue = utilityHelpers.stringInsensitiveComparator(null, null);
+    expect(testValue).toBe(0);
+  });
 });
diff --git a/projects/openk/grid-failure-information-map/src/constants/enums.ts b/projects/openk/grid-failure-information-map/src/constants/enums.ts
new file mode 100644
index 0000000..4a2096d
--- /dev/null
+++ b/projects/openk/grid-failure-information-map/src/constants/enums.ts
@@ -0,0 +1,16 @@
+/********************************************************************************
+ * 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
+ ********************************************************************************/
+export enum VisibilityEnum {
+  SHOW = 'show',
+  HIDE = 'hide',
+}
diff --git a/projects/openk/grid-failure-information-map/src/lib/grid-failure-information-map.component.ts b/projects/openk/grid-failure-information-map/src/lib/grid-failure-information-map.component.ts
index c29252b..8401de8 100644
--- a/projects/openk/grid-failure-information-map/src/lib/grid-failure-information-map.component.ts
+++ b/projects/openk/grid-failure-information-map/src/lib/grid-failure-information-map.component.ts
@@ -16,6 +16,7 @@
 import { GridFailureMapInformation } from '@openk-libs/grid-failure-information-map/shared/models/grid-failure-coordinates.model';
 import { convertISOToLocalDateTime } from '@openk-libs/grid-failure-information-map/shared/utility/utilityHelpers';
 import { MapOptions } from '@openk-libs/grid-failure-information-map/shared/models/map-options.model';
+import { determineDetailFieldVisibility } from '@openk-libs/grid-failure-information-map/shared/utility/utilityHelpers';
 
 @Component({
   selector: 'openk-grid-failure-information-map',
@@ -110,31 +111,67 @@
   }
 
   private _setMultipleMarkers(): void {
-    if (!!this._map && !!this._mapData) {
+    if (!!this._map && !!this._mapData && this._mapOptions) {
       this._mapData.forEach(gridFailure => {
         if (gridFailure.latitude && gridFailure.longitude) {
           const currentMarker = L.marker([gridFailure.latitude, gridFailure.longitude], { icon: this._icon })
             .addTo(this._map)
             .on('click', () => this.gridFailureId.emit(gridFailure.id));
-          let tooltipContent = `${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_BEGIN}${Globals.STRONG_END_TAG} ${convertISOToLocalDateTime(
-            gridFailure.failureBegin
-          )}${Globals.BREAK_TAG}
-            ${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_END_PLANNED}${Globals.STRONG_END_TAG} ${convertISOToLocalDateTime(
-            gridFailure.failureEndPlanned
-          )} ${Globals.BREAK_TAG}
-            ${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_EXPECTED_REASON}${Globals.STRONG_END_TAG} ${gridFailure.expectedReasonText} ${Globals.BREAK_TAG}
-            ${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_BRANCH}${Globals.STRONG_END_TAG} ${gridFailure.branchDescription}`;
-          if (!!this._mapOptions.extendMarkerInformation) {
-            tooltipContent += `
-            ${Globals.BREAK_TAG}${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_ZIP}${Globals.STRONG_END_TAG} ${
-              !!gridFailure.postcode ? gridFailure.postcode : ''
-            }
-            ${Globals.BREAK_TAG}${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_CITY}${Globals.STRONG_END_TAG} ${!!gridFailure.city ? gridFailure.city : ''}
-            ${Globals.BREAK_TAG}${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_DISTRICT}${Globals.STRONG_END_TAG} ${
-              !!gridFailure.district ? gridFailure.district : ''
-            }
-             `;
-          }
+          let failureBeginVisibility =
+            !this._mapOptions.extendMarkerInformation ||
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'failureBegin');
+          let failureBeginString = failureBeginVisibility
+            ? `${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_BEGIN}${Globals.STRONG_END_TAG} ${convertISOToLocalDateTime(gridFailure.failureBegin)}${
+                Globals.BREAK_TAG
+              }`
+            : '';
+          let failureEndPlannedVisibility =
+            !this._mapOptions.extendMarkerInformation ||
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'failureEndPlanned');
+          let failureEndPlannedString = failureEndPlannedVisibility
+            ? ` ${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_END_PLANNED}${Globals.STRONG_END_TAG} ${convertISOToLocalDateTime(
+                gridFailure.failureEndPlanned
+              )} ${Globals.BREAK_TAG}`
+            : '';
+          let expectedReasonVisibility =
+            !this._mapOptions.extendMarkerInformation ||
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'expectedReasonText');
+          let expectedReasonString = expectedReasonVisibility
+            ? `  ${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_EXPECTED_REASON}${Globals.STRONG_END_TAG} ${gridFailure.expectedReasonText} ${Globals.BREAK_TAG}`
+            : '';
+          let branchVisibility =
+            !this._mapOptions.extendMarkerInformation ||
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'branch');
+          let branchString = branchVisibility
+            ? `  ${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_BRANCH}${Globals.STRONG_END_TAG} ${gridFailure.branchDescription}`
+            : '';
+          /* adress fields: only if extendMarkerInformation is true */
+          let postcodeVisibility =
+            this._mapOptions.extendMarkerInformation &&
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'postcode');
+          let postcodeString = postcodeVisibility
+            ? `  ${Globals.BREAK_TAG}${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_ZIP}${Globals.STRONG_END_TAG} ${
+                !!gridFailure.postcode ? gridFailure.postcode : ''
+              }`
+            : '';
+          let cityVisibility =
+            this._mapOptions.extendMarkerInformation &&
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'city');
+          let cityString = cityVisibility
+            ? ` ${Globals.BREAK_TAG}${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_CITY}${Globals.STRONG_END_TAG} ${
+                !!gridFailure.city ? gridFailure.city : ''
+              }`
+            : '';
+          let districtVisibility =
+            this._mapOptions.extendMarkerInformation &&
+            determineDetailFieldVisibility(this._mapOptions.visibilityConfiguration, 'mapExternTooltipVisibility', 'district');
+          let districtString = districtVisibility
+            ? `  ${Globals.BREAK_TAG}${Globals.STRONG_BEGIN_TAG}${Globals.GRID_FAILURE_DISTRICT}${Globals.STRONG_END_TAG} ${
+                !!gridFailure.district ? gridFailure.district : ''
+              }`
+            : '';
+          /* tooltip assembly */
+          let tooltipContent = `${failureBeginString}${failureEndPlannedString}${expectedReasonString}${branchString}${postcodeString}${cityString}${districtString}`;
           currentMarker.bindTooltip(tooltipContent);
           this._drawPolygonOrCircle(gridFailure);
         }
diff --git a/projects/openk/grid-failure-information-map/src/shared/models/map-options.model.ts b/projects/openk/grid-failure-information-map/src/shared/models/map-options.model.ts
index c0244b6..031f129 100644
--- a/projects/openk/grid-failure-information-map/src/shared/models/map-options.model.ts
+++ b/projects/openk/grid-failure-information-map/src/shared/models/map-options.model.ts
@@ -11,6 +11,7 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 import { Subject } from 'rxjs';
+import { VisibilityConfigurationInterface } from '@openk-libs/grid-failure-information-map/shared/models/visibility-configuration.interface';
 
 export class MapOptions {
   public forceResize$: Subject<any> = new Subject<any>();
@@ -19,6 +20,7 @@
   public extendMarkerInformation: boolean = false;
   public overviewMapInitialLatitude: string = null;
   public overviewMapInitialLongitude: string = null;
+  public visibilityConfiguration: VisibilityConfigurationInterface = null;
 
   public constructor(data: any = null) {
     Object.keys(data || {})
diff --git a/projects/openk/grid-failure-information-map/src/shared/models/visibility-configuration.interface.ts b/projects/openk/grid-failure-information-map/src/shared/models/visibility-configuration.interface.ts
new file mode 100644
index 0000000..f2dd988
--- /dev/null
+++ b/projects/openk/grid-failure-information-map/src/shared/models/visibility-configuration.interface.ts
@@ -0,0 +1,64 @@
+/********************************************************************************
+ * 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
+ ********************************************************************************/
+export interface VisibilityConfigurationInterface {
+  fieldVisibility: {
+    description: string;
+    failureClassification: string;
+    internalRemark: string;
+    responsibility: string;
+  };
+  mapExternTooltipVisibility: {
+    branch: string;
+    city: string;
+    district: string;
+    expectedReasonText: string;
+    failureBegin: string;
+    failureEndPlanned: string;
+    postcode: string;
+  };
+  tableExternColumnVisibility: {
+    branch: string;
+    city: string;
+    description: string;
+    district: string;
+    expectedReasonText: string;
+    failureBegin: string;
+    failureClassification: string;
+    failureEndPlanned: string;
+    postcode: string;
+    street: string;
+  };
+  tableInternColumnVisibility: {
+    branch: string;
+    city: string;
+    description: string;
+    district: string;
+    expectedReasonText: string;
+    failureBegin: string;
+    failureClassification: string;
+    failureEndPlanned: string;
+    failureEndResupplied: string;
+    housenumber: string;
+    internalRemark: string;
+    postcode: string;
+    pressureLevel: string;
+    publicationStatus: string;
+    radius: string;
+    responsibility: string;
+    stationIds: string;
+    statusExtern: string;
+    statusIntern: string;
+    street: string;
+    voltageLevel: string;
+  };
+}
diff --git a/projects/openk/grid-failure-information-map/src/shared/utility/utilityHelpers.ts b/projects/openk/grid-failure-information-map/src/shared/utility/utilityHelpers.ts
index 391c94c..0047680 100644
--- a/projects/openk/grid-failure-information-map/src/shared/utility/utilityHelpers.ts
+++ b/projects/openk/grid-failure-information-map/src/shared/utility/utilityHelpers.ts
@@ -10,6 +10,8 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
+import { VisibilityConfigurationInterface } from '@openk-libs/grid-failure-information-map/shared/models/visibility-configuration.interface';
+import { VisibilityEnum } from '@openk-libs/grid-failure-information-map/constants/enums';
 
 // Convert datetime from ISO to local string
 export function convertISOToLocalDateTime(value: string): string {
@@ -47,3 +49,11 @@
 export function toInteger(value: any): number {
   return parseInt(`${value}`, 10);
 }
+
+export function determineDetailFieldVisibility(config: VisibilityConfigurationInterface, config_prop: string, field: string): boolean {
+  if (config && config[config_prop]) {
+    return config[config_prop][field] === VisibilityEnum.SHOW;
+  } else {
+    return true;
+  }
+}