Merge branch 'DEVELOP' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.gridFailureInformation.frontend into SI-571-publication-channels

Signed-off-by: Peter Buschmann <peter.buschmann@pta.de>
diff --git a/i18n/general.de.json b/i18n/general.de.json
index a64f1d0..2977d28 100644
--- a/i18n/general.de.json
+++ b/i18n/general.de.json
@@ -50,6 +50,7 @@
   "DifferentBranchesWarning": "Es können nur Meldungen mit gleicher Sparte verdichtet werden.",
   "EmptyListWarning": "Die Liste ist leer. Zum Verdichten muss mindestens eine Meldung ausgewählt sein.",
   "SelectedContactAlreadyAssigned": "Der ausgewählte Kontakt ist der Verteilergruppe bereits zugeordnet.",
-  "NoContatctSelected": "Es wurde kein Kontakt ausgewählt oder es wurde keine entsprechender gefunden.",
-  "SelectedDistributionGroupAlreadyAssigned": "Die ausgewählte Verteilergruppe ist der Störinfo bereits zugeordnet."
+  "NoContactSelected": "Es wurde kein Kontakt ausgewählt oder es wurde keine entsprechender gefunden.",
+  "SelectedDistributionGroupAlreadyAssigned": "Die ausgewählte Verteilergruppe ist der Störinfo bereits zugeordnet.",
+  "SelectedStationAlreadyAssigned": "Die ausgewählte Station ist der Störungsmeldung bereits zugeordnet."
 }
diff --git a/i18n/grid-failure.de.json b/i18n/grid-failure.de.json
index a061fd8..9f9461d 100644
--- a/i18n/grid-failure.de.json
+++ b/i18n/grid-failure.de.json
@@ -52,6 +52,7 @@
     "AssignGroupBtn": "Verteilergruppe zuordnen",
     "PublicationChannels": "Veröffentlichungskanäle",
     "DistributionGroups": "Verteilergruppen",
-    "ChannelSaveBtn": "Kanäle speichern"
+    "ChannelSaveBtn": "Kanäle speichern",
+	"AddStation": "Station hinzufügen"
   }
 }
diff --git a/projects/grid-failure-information-app/src/app/pages/distribution-group/distribution-group.sandbox.ts b/projects/grid-failure-information-app/src/app/pages/distribution-group/distribution-group.sandbox.ts
index be483ef..f419727 100644
--- a/projects/grid-failure-information-app/src/app/pages/distribution-group/distribution-group.sandbox.ts
+++ b/projects/grid-failure-information-app/src/app/pages/distribution-group/distribution-group.sandbox.ts
@@ -186,7 +186,7 @@
 
   public assignContactToGroup(): void {
     if (!this._selectedContact) {
-      this._utilService.displayNotification('NoContatctSelected');
+      this._utilService.displayNotification('NoContactSelected');
       return;
     }
     let testMember: DistributionGroupMember = this._distributionGroupMembers.find(member => member.contactId === this._selectedContact.uuid);
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-api-client.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-api-client.ts
index 77f17fe..cf8a52d 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-api-client.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-api-client.ts
@@ -26,6 +26,7 @@
   FailureAddress,
   DistributionGroup,
   PublicationChannel,
+  Polygon,
 } from '@grid-failure-information-app/shared/models';
 
 @Injectable()
@@ -114,7 +115,34 @@
 
   @GET('/stations')
   @Adapter(GridFailureService.stationListAdapter)
-  public getGridFailureStations(): Observable<FailureStation[]> {
+  public getStations(): Observable<FailureStation[]> {
+    return null;
+  }
+
+  @POST('/stations/polygon-coordinates')
+  @Adapter(GridFailureService.polygonAdapter)
+  public getGridFailurePolygon(@Body() stationIds: string[]): Observable<Array<[number, number]>> {
+    return null;
+  }
+
+  @GET('/grid-failure-informations/{gridFailureId}/stations')
+  @Adapter(GridFailureService.stationListAdapter)
+  public getGridFailureStations(@Path('gridFailureId') gridFailureId: string): Observable<FailureStation[]> {
+    return null;
+  }
+
+  @POST('/grid-failure-informations/{gridFailureDetailId}/stations')
+  @Adapter(GridFailureService.stationListAdapter)
+  public postGridFailureStation(@Path('gridFailureDetailId') gridFailureDetailId: string, @Body() station: FailureStation): Observable<FailureStation[]> {
+    return null;
+  }
+
+  @DELETE('/grid-failure-informations/{gridFailureId}/stations/{gridFailureStationId}')
+  @Adapter(GridFailureService.stationAdapter)
+  public deleteGridFailureStation(
+    @Path('gridFailureId') gridFailureDetailId: string,
+    @Path('gridFailureStationId') gridFailureStationId: string
+  ): Observable<void> {
     return null;
   }
 
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html
index e28ce10..dac06e1 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.html
@@ -450,39 +450,60 @@
                     </select>
                   </div>
                 </div>
+
+                <!-- radius -->
+                <div class="form-group row">
+                  <label for="radius" class="col-sm-5 col-form-label">{{ 'GridFailure.RadiusInMeter' | translate }}</label>
+                  <div class="col-sm-6">
+                    <select
+                      [required]="gridFailureDetailsSandbox.isFieldRequiredDependingOnBranchId"
+                      type="text"
+                      class="form-control"
+                      [ngrxFormControlState]="formState.controls['radiusId']"
+                    >
+                      <option [value]="null" selected disabled>{{ 'SelectOption' | translate }}</option>
+                      <option *ngFor="let item of gridFailureDetailsSandbox.gridFailureRadii$ | async" [value]="item.id">{{ item.radius }}</option>
+                    </select>
+                  </div>
+                </div>
               </div>
 
               <div class="MS-fields" *ngIf="failureLocationView === Globals.FAILURE_LOCATION_MS">
                 <!-- stationDescription -->
                 <div class="form-group row">
-                  <label for="stationDescription" class="col-sm-5 col-form-label">{{ 'GridFailure.StationDescription' | translate }}</label>
                   <div class="col-sm-6">
                     <input
                       [required]="gridFailureDetailsSandbox.isFieldRequiredDependingOnBranchId"
+                      #searchInput
+                      placeholder="{{ 'GridFailure.StationDescription' | translate }}"
                       type="text"
                       maxlength="255"
                       id="stationDescription"
                       class="form-control"
                       autocomplete="off"
-                      (input)="resetCoords($event.target.value)"
-                      (selectItem)="gridFailureDetailsSandbox.latLonMapping($event.item); gridFailureDetailsSandbox.setStationId($event.item.stationId)"
+                      (input)="resetSelectedStation($event.target.value)"
+                      (selectItem)="gridFailureDetailsSandbox.setStationId($event.item.stationId); gridFailureDetailsSandbox.setSelectedStation($event.item)"
                       [ngbTypeahead]="gridFailureDetailsSandbox.searchForStation"
-                      [ngrxValueConverter]="gridFailureDetailsSandbox.stationValueConverter"
-                      [ngrxFormControlState]="formState.controls['stationDescription']"
                       [resultFormatter]="gridFailureDetailsSandbox.formatter"
                       [inputFormatter]="gridFailureDetailsSandbox.formatter"
                     />
                   </div>
+                  <button type="button" class="btn btn-primary btn-sm" (click)="gridFailureDetailsSandbox.postSelectedStation(); clearSearchInput()">
+                    {{ 'GridFailure.AddStation' | translate }}
+                  </button>
                 </div>
-                <!-- radius -->
-                <div class="form-group row">
-                  <label for="radius" class="col-sm-5 col-form-label">{{ 'GridFailure.RadiusInMeter' | translate }}</label>
-                  <div class="col-sm-6">
-                    <select required type="text" class="form-control" [ngrxFormControlState]="formState.controls['radiusId']">
-                      <option [value]="null" selected disabled>{{ 'SelectOption' | translate }}</option>
-                      <option *ngFor="let item of gridFailureDetailsSandbox.gridFailureRadii$ | async" [value]="item.id">{{ item.radius }}</option>
-                    </select>
-                  </div>
+                <div class="stationList">
+                  <ag-grid-angular
+                    autoResizeColumns
+                    class="ag-theme-balham"
+                    [gridOptions]="gridOptions"
+                    [columnDefs]="stationsColumnDefinition"
+                    [rowSelection]="'single'"
+                    [frameworkComponents]="frameworkComponents"
+                    [rowData]="gridFailureDetailsSandbox.gridFailureStations"
+                    [overlayNoRowsTemplate]="noRowsTemplate"
+                  >
+                  </ag-grid-angular>
                 </div>
               </div>
               <div class="map-detail-view">
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.scss b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.scss
index 50adc44..b0cb7b5 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.scss
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.component.scss
@@ -100,7 +100,7 @@
 
 .NS-fields,
 .MS-fields {
-  min-width: 530px;
+  min-width: 480px;
 }
 
 .non-outline {
@@ -117,3 +117,12 @@
   background-color: #337ab7;
   cursor: default;
 }
+.row {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+}
+.stationList {
+  width: 378px;
+  height: 378px;
+}
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 635f363..09aacd5 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
@@ -39,6 +39,7 @@
   beforeEach(() => {
     appState = { dispatch: () => {}, pipe: () => of(true), select: () => of(true) } as any;
     gridFailureSandbox = {
+      init() {},
       clearGridFailureData() {},
       registerEvents() {},
       endSubscriptions() {},
@@ -71,15 +72,12 @@
 
   it('checks if resetCoords(value: string) works fine', async(() => {
     let spy1 = spyOn(gridFailureSandbox, 'resetCoords');
-    let spy2 = spyOn(gridFailureSandbox, 'resetStationId');
 
     component.resetCoords('1');
     expect(spy1).not.toHaveBeenCalled();
-    expect(spy2).not.toHaveBeenCalled();
 
     component.resetCoords(null);
     expect(spy1).toHaveBeenCalled();
-    expect(spy2).toHaveBeenCalled();
   }));
 
   it('checks if disableUnnecessaryRequiredProperties works fine', async(() => {
@@ -137,4 +135,10 @@
     (component as any)._initialFailureLocationState();
     expect(component.mapInteractionMode).toBeFalsy();
   }));
+
+  it('should clear search input', () => {
+    component.searchInput = { nativeElement: { value: 'x' } };
+    component.clearSearchInput();
+    expect(component.searchInput.nativeElement.value).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 4d9343e..5874a40 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
@@ -10,23 +10,28 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
-import { take, skip } from 'rxjs/operators';
-import { Component, OnInit } from '@angular/core';
+import { combineLatest } from 'rxjs';
+import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
 import { GridFailureDetailsSandbox } from '@grid-failure-information-app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox';
 import { RolesEnum, StateEnum, VoltageLevelEnum } from '@grid-failure-information-app/shared/constants/enums';
 import { Globals } from '@grid-failure-information-app/shared/constants/globals';
 import { GridFailure } from '@grid-failure-information-app/shared/models/grid-failure.model';
 import * as store from '@grid-failure-information-app/shared/store';
 import { Store } from '@ngrx/store';
-import { Observable } from 'rxjs';
+import { Observable, Subscription } from 'rxjs';
 import { MapOptions } from '@openk-libs/grid-failure-information-map/shared/models/map-options.model';
+import { BaseList } from '@grid-failure-information-app/shared/components/base-components/base.list';
+import { STATION_COLDEF } from './station-list-column-definition';
+import { SetFilterComponent } from '@grid-failure-information-app/shared/filters/ag-grid/set-filter/set-filter.component';
+import { take, skip, skipWhile } from 'rxjs/operators';
 
 @Component({
   selector: 'app-grid-failure-details',
   templateUrl: './grid-failure-details.component.html',
   styleUrls: ['./grid-failure-details.component.scss'],
 })
-export class GridFailureDetailsComponent implements OnInit {
+export class GridFailureDetailsComponent extends BaseList implements OnInit {
+  @ViewChild('searchInput', { static: false }) searchInput: ElementRef;
   public Globals = Globals;
   public RolesEnum = RolesEnum;
   public StateEnum = StateEnum;
@@ -38,15 +43,32 @@
   public get mapInteractionMode(): boolean {
     return this.failureLocationView === Globals.FAILURE_LOCATION_MAP;
   }
+  public stationsColumnDefinition: any = STATION_COLDEF;
+  public frameworkComponents: any;
 
-  constructor(public gridFailureDetailsSandbox: GridFailureDetailsSandbox, protected appState$: Store<store.State>) {}
+  private _subscription: Subscription;
+
+  constructor(public gridFailureDetailsSandbox: GridFailureDetailsSandbox, protected appState$: Store<store.State>) {
+    super();
+    this.frameworkComponents = { setFilterComponent: SetFilterComponent };
+  }
 
   ngOnInit() {
+    this.gridFailureDetailsSandbox.init();
     this.gridFailureDetailsSandbox.registerEvents();
     this._initialFailureLocationState();
     this.appState$.select(store.getPreConfiguration).subscribe(preConfig => {
       this.mapOptions = new MapOptions(preConfig);
     });
+    this.gridOptions.context = {
+      ...this.gridOptions.context,
+      icons: { delete: true },
+    };
+    this._subscription = this.gridOptions.context.eventSubject.subscribe(event => {
+      if (event.type === 'delete') {
+        this.gridFailureDetailsSandbox.deleteGridFailureStation(event.data.id);
+      }
+    });
   }
   public setLocation() {
     this.gridFailureDetailsSandbox.gridFailureDetailsFormState$.pipe(take(1)).subscribe(currentFormState => {
@@ -67,31 +89,42 @@
   public resetCoords(value: string): void {
     if (!value) {
       this.gridFailureDetailsSandbox.resetCoords();
-      this.gridFailureDetailsSandbox.resetStationId();
     }
   }
+
+  public resetSelectedStation(value: string): void {
+    if (!value) {
+      this.gridFailureDetailsSandbox.setSelectedStation(null);
+    }
+  }
+
   public resizeSetMap() {
     this.mapOptions.forceResize$.next(true);
   }
+
   public disableUnnecessaryRequiredProperties() {
     this.gridFailureDetailsSandbox.disableUnnecessaryRequiredProperties(this.failureLocationView);
   }
 
+  public clearSearchInput() {
+    this.searchInput.nativeElement.value = '';
+  }
+
   private _initialFailureLocationState() {
-    this.gridFailureDetailsSandbox.gridFailureDetailsFormState$
+    combineLatest(this.gridFailureDetailsSandbox.gridFailureDetailsFormState$, this.gridFailureDetailsSandbox.gridFailureStations$)
       .pipe(
         //Skip ngrx-form specific initialization
-        skip(1),
+        skipWhile(([currentFormState, stationsList]) => !stationsList && stationsList.length === 0),
         take(1)
       )
-      .subscribe(currentFormState => {
+      .subscribe(([currentFormState, stationsList]) => {
         if (!!currentFormState && !!currentFormState.controls) {
           const coordinatesExsist = !!currentFormState.controls.latitude.value && !!currentFormState.controls.longitude.value;
           //The user is forced to set other address data before he can edity the hosuenumber
           //and housenumber is the last to edit value, we can assume that coordinates have been set correctly
           const nsDataExist = !!currentFormState.controls.housenumber.value && coordinatesExsist;
           //Radius is the only required field,  we can assume that coordinates have been set correctly
-          const msDataExist = (!!currentFormState.controls.radius.value || currentFormState.controls.radius.value == 0) && coordinatesExsist;
+          const msDataExist = !!stationsList && !!stationsList.length && coordinatesExsist;
           if (nsDataExist) {
             this.failureLocationView = Globals.FAILURE_LOCATION_NS;
           } else if (msDataExist) {
@@ -99,13 +132,13 @@
           } else if (coordinatesExsist && !nsDataExist && !msDataExist) {
             this.failureLocationView = Globals.FAILURE_LOCATION_MAP;
           }
-
           this.gridFailureDetailsSandbox.disableUnnecessaryRequiredProperties(this.failureLocationView);
         }
       });
   }
 
   ngOnDestroy() {
+    this.gridFailureDetailsSandbox.gridFailureStations = [];
     this.gridFailureDetailsSandbox.endSubscriptions();
   }
 }
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.spec.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.spec.ts
index 376c3de..09dac39 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.spec.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox.spec.ts
@@ -379,8 +379,8 @@
   });
 
   it('should load GridFailureStations', () => {
-    service.loadGridFailureStations();
-    expect(dispatchSpy).toHaveBeenCalledWith(Object({ type: gridFailureActions.loadGridFailureStations.type }));
+    service.loadStations();
+    expect(dispatchSpy).toHaveBeenCalledWith(Object({ type: gridFailureActions.loadStations.type }));
   });
 
   it('should map lon and lat values', () => {
@@ -489,7 +489,7 @@
   it('should trigger searchForStation  and check if the right value was returned', () => {
     const failureStation: FailureStation = new FailureStation();
     failureStation.stationName = 'hello';
-    (service as any)._gridFailureStations = [new FailureStation(), new FailureStation(), failureStation];
+    (service as any)._stations = [new FailureStation(), new FailureStation(), failureStation];
     const text$ = of('hello');
     const result = service.searchForStation(text$);
 
@@ -501,7 +501,7 @@
   it('should trigger searchForStation  and check if the right value was returned if length is under 2', () => {
     const failureStation: FailureStation = new FailureStation();
     failureStation.stationName = 'hello';
-    (service as any)._gridFailureStations = [new FailureStation(), new FailureStation(), failureStation];
+    (service as any)._stations = [new FailureStation(), new FailureStation(), failureStation];
     const text$ = of('h');
     const result = service.searchForStation(text$);
 
@@ -585,12 +585,10 @@
     let part: string = 'NS';
     service.disableUnnecessaryRequiredProperties(part);
     expect(appState.dispatch).toHaveBeenCalledWith(new EnableAction(INITIAL_STATE.controls.postcode.id));
-    expect(appState.dispatch).toHaveBeenCalledWith(new DisableAction(INITIAL_STATE.controls.radiusId.id));
+    expect(appState.dispatch).toHaveBeenCalledWith(new EnableAction(INITIAL_STATE.controls.radiusId.id));
 
     part = 'MS';
     service.disableUnnecessaryRequiredProperties(part);
-    expect(appState.dispatch).toHaveBeenCalledWith(new EnableAction(INITIAL_STATE.controls.postcode.id));
-    expect(appState.dispatch).toHaveBeenCalledWith(new DisableAction(INITIAL_STATE.controls.radiusId.id));
 
     part = 'map';
     service.disableUnnecessaryRequiredProperties(part);
@@ -598,6 +596,57 @@
     expect(appState.dispatch).toHaveBeenCalledWith(new DisableAction(INITIAL_STATE.controls.radiusId.id));
   });
 
+  it('should delete gridFailure station', () => {
+    let station = new FailureStation();
+    station.id = 'xx';
+    station.latitude = 5;
+    station.longitude = 5;
+    service.gridFailureStations = [station];
+
+    service.deleteGridFailureStation('xx');
+
+    expect(service.gridFailureStations).toEqual([]);
+  });
+
+  it('should load gridFailure stations', () => {
+    service.loadGridFailureStations('xx');
+    service.loadGridFailureStations(null);
+
+    expect(appState.dispatch).toHaveBeenCalledWith(gridFailureActions.loadGridFailureStations({ payload: 'xx' }));
+  });
+
+  it('should set GridFailureId', () => {
+    service.setGridFailureId('xx');
+
+    expect((service as any)._gridFailureId).toBe('xx');
+  });
+
+  it('should set selected Station', () => {
+    const station = new FailureStation();
+    service.setSelectedStation(station);
+
+    expect((service as any)._selectedStation).toBe(station);
+  });
+
+  it('should post selected Station', () => {
+    const station = new FailureStation();
+    station.id = 'xx';
+    (service as any)._selectedStation = station;
+    (service as any)._gridFailureDetailId = 'x';
+    service.postSelectedStation();
+    expect(appState.dispatch).toHaveBeenCalled();
+    expect((service as any)._selectedStation).toBe(null);
+  });
+
+  // it('should delete station', () => {
+  //   const stationId = 'xx';
+  //   (service as any)._gridFailureDetailId = 'x';
+  //   service.deleteGridFailureStation(stationId);
+  //   expect(appState.dispatch).toHaveBeenCalledWith(
+  //     gridFailureActions.deleteGridFailureStation({ gridFailureDetailId: (service as any)._gridFailureDetailId, stationId: stationId })
+  //   );
+  // });
+
   it('should dispatch loadGridFailureDistributionGroups Action via loadGridFailureDistributionGroups(id)', () => {
     service.loadGridFailureDistributionGroups('id');
     expect(appState.dispatch).toHaveBeenCalledWith(gridFailureActions.loadGridFailureDistributionGroups({ payload: 'id' }));
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 07b4ef8..a2b9bd7 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
@@ -44,9 +44,12 @@
   SetUserDefinedPropertyAction,
   SetValueAction,
   box,
+  MarkAsTouchedAction,
+  MarkAsDirtyAction,
 } from 'ngrx-forms';
 import { combineLatest, Observable } from 'rxjs';
 import { debounceTime, distinctUntilChanged, map, skipWhile, take, takeUntil, tap } from 'rxjs/operators';
+import { FailureStation } from '@grid-failure-information-app/shared/models';
 
 @Injectable()
 export class GridFailureDetailsSandbox extends BaseFormSandbox<models.GridFailure> {
@@ -57,6 +60,12 @@
   public currentFormState: FormGroupState<models.GridFailure>;
   public gridFailureClassifications$: Observable<models.FailureClassification[]> = this.appState$.select(store.getGridFailureClassificationsData);
   public gridFailureBranches$: Observable<models.FailureBranch[]> = this.appState$.select(store.getGridFailureBranchesData);
+  public stations$: Observable<models.FailureStation[]> = this.appState$.select(store.getStationsData);
+  public gridFailureStations$: Observable<models.FailureStation[]> = this.actionsSubject.pipe(
+    ofType(gridFailureActions.loadGridFailureStationsSuccess.type),
+    map(action => action['payload'])
+  );
+  public gridFailurePolygon$: Observable<Array<[number, number]>> = this.appState$.select(store.getGridFailurePolygonData);
   public gridFailureActions = gridFailureActions;
   public gridFailureStates$: Observable<models.FailureState[]> = this.appState$.select(store.getGridFailureStatesData);
   public gridFailureRadii$: Observable<models.FailureRadius[]> = this.appState$.select(store.getGridFailureRadiiData);
@@ -66,7 +75,7 @@
   public pressureLevelEnum = enums.PressureLevelEnum;
   public publicationStatusEnum = enums.PublicationStatusEnum;
   public maxVersionNumber: number;
-  public currentGridFailureDetailsCoords: models.FailureCoords = new models.FailureCoords();
+  public currentGridFailureDetailsCoords: models.FailureCoordsInformation = new models.FailureCoordsInformation();
   public noBranchId: string;
   public isFieldRequiredDependingOnBranchId: boolean = false;
 
@@ -105,6 +114,7 @@
   public showUpdateButton: boolean = false;
   public showPublishButton: boolean = false;
   public gridFailureAddress: models.FailureAddress;
+  private _stations: Array<models.FailureStation> = new Array<models.FailureStation>();
 
   public gridFailureDistributionGroups$: Observable<models.DistributionGroup[]> = this.appState$.select(store.getGridFailureDistributionGroupsData);
   public gridFailureDistributionGroupsLoading$: Observable<boolean> = this.appState$.select(store.getGridFailureDistributionGroupsLoading);
@@ -114,6 +124,8 @@
 
   private _gridFailureStations: Array<models.FailureStation> = new Array<models.FailureStation>();
   private _gridFailureId: string;
+  private _selectedStation: models.FailureStation;
+  public gridFailureStations: FailureStation[] = [];
   private _assignedDistributionGroups: Array<models.DistributionGroup>;
 
   constructor(
@@ -124,11 +136,20 @@
     private _modalService: NgbModal
   ) {
     super(appState$);
-    this.init();
   }
 
   public init() {
     this._setBranchIds();
+
+    this.gridFailureStations$.pipe(take(1), takeUntil(this._endSubscriptions$)).subscribe(stations => {
+      this.gridFailureStations = stations;
+      // set coords if first element was inserted
+      !!stations.length && this.latLonMapping({ longitude: stations[0].longitude, latitude: stations[0].latitude });
+
+      this._calculatePolygon(stations);
+    });
+
+    this.loadGridFailureStations(this._gridFailureId);
   }
 
   public loadGridFailure(gridFailureId: string): void {
@@ -172,12 +193,11 @@
       });
   }
 
-  public loadGridFailureStations(): void {
-    this.appState$.dispatch(gridFailureActions.loadGridFailureStations());
+  public loadStations(): void {
+    this.appState$.dispatch(gridFailureActions.loadStations());
   }
 
   public loadGridFailureVersions(gridFailureId: string): void {
-    this._gridFailureId = gridFailureId;
     this.appState$.dispatch(gridFailureActions.loadGridFailureVersions({ payload: gridFailureId }));
   }
 
@@ -195,7 +215,9 @@
       this.appState$.dispatch(new EnableAction(FORM_ID));
     }
   }
-
+  public setGridFailureId(gridFailureId: string) {
+    this._gridFailureId = gridFailureId;
+  }
   public loadGridFailureDistributionGroups(gridFailureId: string): void {
     this.appState$.dispatch(gridFailureActions.loadGridFailureDistributionGroups({ payload: gridFailureId }));
   }
@@ -256,7 +278,7 @@
 
       this.appState$.dispatch(
         gridFailureActions.saveGridFailure({
-          payload: { gridFailure: gridFailure, saveForPublish: saveForPublish },
+          payload: { gridFailure: unboxProperties<models.GridFailure>(this.currentFormState.value), saveForPublish: saveForPublish },
         })
       );
       this.actionsSubject.pipe(ofType(gridFailureActions.saveGridFailureSuccess), take(1), takeUntil(this._endSubscriptions$)).subscribe(() => {
@@ -388,12 +410,12 @@
 
     this.actionsSubject
       .pipe(
-        ofType(gridFailureActions.loadGridFailureStationsSuccess),
+        ofType(gridFailureActions.loadStationsSuccess),
         map(action => action.payload),
         takeUntil(this._endSubscriptions$)
       )
       .subscribe((stations: Array<models.FailureStation>) => {
-        this._gridFailureStations = stations;
+        this._stations = stations;
       });
 
     this.actionsSubject
@@ -408,6 +430,11 @@
         this.latLonMapping(event);
       });
 
+    this.gridFailurePolygon$.subscribe((polygon: Array<[number, number]>) => {
+      this.currentFormState.value.addressPolygonPoints = !!polygon ? box(polygon) : null;
+      this.currentGridFailureDetailsCoords = new models.FailureCoordsInformation(this.currentFormState.value);
+    });
+
     this.actionsSubject
       .pipe(
         ofType(gridFailureActions.loadGridFailureDistributionGroupsSuccess),
@@ -419,11 +446,22 @@
       });
 
     this.gridFailureDetailsFormState$.subscribe(gridFailureDetails => {
+      let failureRadius: models.FailureRadius;
+      if (!!gridFailureDetails.value.radiusId) {
+        this.gridFailureRadii$.subscribe(radiusIds => {
+          if (radiusIds.length !== 0) {
+            failureRadius = radiusIds.find(item => item.id === gridFailureDetails.value.radiusId);
+            gridFailureDetails.value.radius = failureRadius.radius;
+          }
+        });
+      }
+
       if (
         this.currentGridFailureDetailsCoords.latitude !== gridFailureDetails.value.latitude ||
-        this.currentGridFailureDetailsCoords.longitude !== gridFailureDetails.value.longitude
+        this.currentGridFailureDetailsCoords.longitude !== gridFailureDetails.value.longitude ||
+        this.currentGridFailureDetailsCoords.radius !== gridFailureDetails.value.radius
       ) {
-        this.currentGridFailureDetailsCoords = new models.FailureCoords(gridFailureDetails.value);
+        this.currentGridFailureDetailsCoords = new models.FailureCoordsInformation(gridFailureDetails.value);
       }
     });
   }
@@ -432,7 +470,7 @@
     text$.pipe(
       debounceTime(200),
       distinctUntilChanged(),
-      map(term => (term.length < 2 ? [] : this._gridFailureStations.filter(s => s.failureStationSearchString.toLowerCase().indexOf(term.toLowerCase()) > -1)))
+      map(term => (term.length < 2 ? [] : this._stations.filter(s => s.failureStationSearchString.toLowerCase().indexOf(term.toLowerCase()) > -1)))
     );
 
   public formatter = (s: models.FailureStation | string) => {
@@ -442,6 +480,14 @@
 
   public stationValueConverter: NgrxValueConverter<any | null, string | null> = stationToStationDescriptionConverter;
 
+  private _calculatePolygon(stations: models.FailureStation[]) {
+    let stationIds: string[] = [];
+    stations.forEach(station => {
+      stationIds.push(station.id);
+    });
+    this.appState$.dispatch(gridFailureActions.loadGridFailurePolygon({ payload: stationIds }));
+  }
+
   public latLonMapping(data: { longitude: number; latitude: number }): void {
     !!data &&
       this.appState$.dispatch(
@@ -504,6 +550,8 @@
         ...this.currentFormState.value,
         stationDescription: null,
         stationId: null,
+        stationIds: [],
+        addressPolygonPoints: null,
         latitude: null,
         longitude: null,
         postcode: null,
@@ -515,22 +563,20 @@
         radiusId: null,
       })
     );
+    this.gridFailureStations = [];
   }
 
   public disableUnnecessaryRequiredProperties(part: string): void {
     switch (part) {
       case Globals.FAILURE_LOCATION_NS:
         this.appState$.dispatch(new EnableAction(INITIAL_STATE.controls.postcode.id));
-        this._disableStationControls();
+        this.appState$.dispatch(new EnableAction(INITIAL_STATE.controls.radiusId.id));
 
         break;
       case Globals.FAILURE_LOCATION_MS:
         this._disableAddressControls();
-        this.appState$.dispatch(new EnableAction(INITIAL_STATE.controls.radiusId.id));
-        this.appState$.dispatch(new EnableAction(INITIAL_STATE.controls.stationDescription.id));
         break;
       case Globals.FAILURE_LOCATION_MAP:
-        this._disableStationControls();
         this._disableAddressControls();
         break;
       default:
@@ -564,9 +610,55 @@
     }
   }
 
-  private _disableStationControls(): void {
-    this.appState$.dispatch(new DisableAction(INITIAL_STATE.controls.radiusId.id));
-    this.appState$.dispatch(new DisableAction(INITIAL_STATE.controls.stationDescription.id));
+  public setSelectedStation(selectedStation: models.FailureStation) {
+    this._selectedStation = selectedStation;
+  }
+
+  public postSelectedStation() {
+    if (!this._selectedStation) {
+      return;
+    }
+    if (this.currentFormState.value.stationIds && this.currentFormState.value.stationIds.some(id => id === this._selectedStation.id)) {
+      this._utilService.displayNotification('SelectedStationAlreadyAssigned', 'alert');
+      return;
+    }
+
+    this.gridFailureStations = [...this.gridFailureStations, this._selectedStation];
+    !!this.gridFailureStations.length &&
+      this.latLonMapping({ longitude: this.gridFailureStations[0].longitude, latitude: this.gridFailureStations[0].latitude });
+
+    this._calculatePolygon(this.gridFailureStations);
+    this.appState$.dispatch(
+      new SetValueAction(
+        this.currentFormState.controls.stationIds.id,
+        this.gridFailureStations.map(station => station.id)
+      )
+    );
+    this.appState$.dispatch(new MarkAsDirtyAction(this.currentFormState.id));
+
+    this.latLonMapping({ longitude: this.gridFailureStations[0].longitude, latitude: this.gridFailureStations[0].latitude });
+
+    this._selectedStation = null;
+  }
+
+  public deleteGridFailureStation(stationId: string) {
+    // reset coords if stations are empty after whole transaction
+    if (this.gridFailureStations.length === 1) {
+      this.resetCoords();
+    }
+    this.gridFailureStations = this.gridFailureStations.filter(station => station.id != stationId);
+    this.appState$.dispatch(
+      new SetValueAction(
+        this.currentFormState.controls.stationIds.id,
+        this.gridFailureStations.map(station => station.id)
+      )
+    );
+
+    this.appState$.dispatch(new MarkAsDirtyAction(this.currentFormState.id));
+
+    !!this.gridFailureStations.length &&
+      this.latLonMapping({ longitude: this.gridFailureStations[0].longitude, latitude: this.gridFailureStations[0].latitude });
+    this._calculatePolygon(this.gridFailureStations);
   }
 
   private _disableAddressControls(): void {
@@ -575,6 +667,7 @@
     this.appState$.dispatch(new DisableAction(INITIAL_STATE.controls.district.id));
     this.appState$.dispatch(new DisableAction(INITIAL_STATE.controls.street.id));
     this.appState$.dispatch(new DisableAction(INITIAL_STATE.controls.housenumber.id));
+    this.appState$.dispatch(new DisableAction(INITIAL_STATE.controls.radiusId.id));
   }
 
   public loadInitialAddressData(formState: FormGroupState<models.GridFailure>) {
@@ -610,6 +703,13 @@
     this.appState$.dispatch(gridFailureActions.loadAddressPostalcodes({ branch: !!this.currentFormState ? this.currentFormState.value.branch : null }));
   }
 
+  public loadGridFailureStations(gridFailureId: string) {
+    if (!gridFailureId) {
+      return;
+    }
+    this.appState$.dispatch(gridFailureActions.loadGridFailureStations({ payload: gridFailureId }));
+  }
+
   public checkForMaxVersion(): boolean {
     return this.currentFormState.value.versionNumber === this.maxVersionNumber;
   }
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/station-list-column-definition.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/station-list-column-definition.ts
new file mode 100644
index 0000000..abd6b5d
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/station-list-column-definition.ts
@@ -0,0 +1,37 @@
+/********************************************************************************
+ * 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 { IconCellRendererComponent } from '@grid-failure-information-app/shared/components/cell-renderer/icon-cell-renderer/icon-cell-renderer.component';
+
+export const STATION_COLDEF = [
+  {
+    field: 'stationName',
+    colId: 'stationName',
+    headerName: 'GridFailure.StationDescription',
+    sortable: true,
+    filter: 'setFilterComponent',
+    valueGetter: params => params.data.failureStationSearchString,
+  },
+  {
+    field: 'tools',
+    headerName: ' ',
+    pinned: 'right',
+    maxWidth: 70,
+    minWidth: 70,
+    lockPosition: true,
+    sortable: false,
+    filter: false,
+    suppressMenu: true,
+    suppressSizeToFit: true,
+    cellRendererFramework: IconCellRendererComponent,
+  },
+];
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.spec.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.spec.ts
index 381b206..17e134f 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.spec.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.spec.ts
@@ -23,14 +23,16 @@
       loadGridFailures() {},
     } as any;
     detailSandbox = {
+      setGridFailureId(id: string) {},
       loadGridFailure() {},
       loadGridFailureVersions() {},
       loadGridFailureBranches() {},
       loadGridFailureClassifications() {},
       loadGridFailureStates() {},
       loadGridFailureRadii() {},
-      loadGridFailureStations() {},
+      loadStations() {},
       loadAddressPostalcodes() {},
+      loadGridFailureStations() {},
       loadDistributionGroups() {},
       loadGridFailureDistributionGroups() {},
     } as any;
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.ts
index f8c2286..513574d 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.resolver.ts
@@ -22,8 +22,10 @@
   public resolve(route: ActivatedRouteSnapshot): void {
     const gridFailureId: string = route.params['gridFailureId'];
     if (!gridFailureId) {
+      this._detailSandbox.setGridFailureId(null);
       this._sandbox.loadGridFailures();
     } else if (gridFailureId && gridFailureId !== 'new') {
+      this._detailSandbox.setGridFailureId(gridFailureId);
       // load current version
       this._detailSandbox.loadGridFailure(gridFailureId);
       // load history
@@ -36,7 +38,7 @@
     this._detailSandbox.loadGridFailureClassifications();
     this._detailSandbox.loadGridFailureStates();
     this._detailSandbox.loadGridFailureRadii();
-    this._detailSandbox.loadGridFailureStations();
+    this._detailSandbox.loadStations();
     this._detailSandbox.loadAddressPostalcodes();
     this._detailSandbox.loadDistributionGroups();
   }
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 f3feb0c..f37eadc 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
@@ -89,6 +89,18 @@
     expect(GridFailureService.housenumberListAdapter(response)[0].uuid).toBe('X');
   });
 
+  it('should transform station list response', () => {
+    const response: any = [{ id: 'X' }];
+    expect(GridFailureService.stationListAdapter(response)[0].id).toBe('X');
+  });
+
+  it('should transform station item response', () => {
+    const response: any = { id: 'X' };
+    const item = GridFailureService.stationAdapter(response);
+
+    expect(item.id).toBe(response.id);
+  });
+
   it('should transform distribution group list response', () => {
     const response: any = [{ id: 'X' }];
     expect(GridFailureService.distributionGroupListAdapter(response)[0].id).toBe('X');
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.ts
index ba06482..f428f45 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.service.ts
@@ -23,6 +23,7 @@
   FailureAddress,
   DistributionGroup,
   PublicationChannel,
+  Polygon,
 } from '@grid-failure-information-app/shared/models';
 
 @Injectable()
@@ -55,10 +56,18 @@
     return response.map(responseItem => new FailureExpectedReason(responseItem));
   }
 
+  static stationAdapter(response: any): FailureStation {
+    return new FailureStation(response);
+  }
+
   static stationListAdapter(response: any): Array<FailureStation> {
     return response.map(responseItem => new FailureStation(responseItem));
   }
 
+  static polygonAdapter(response: any): Array<[number, number]> {
+    return response;
+  }
+
   static housenumberListAdapter(response: any): Array<FailureHousenumber> {
     return response.map(responseItem => new FailureHousenumber(responseItem));
   }
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 946164b..31e6c4e 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
@@ -31,7 +31,7 @@
     andCondition: 'und',
     orCondition: 'oder',
   };
-  public static PROPERTIES_TO_BOX: string[] = ['addressPolygonPoints', '__formBranch', 'distributionGroupUuids', 'publicationChannels'];
+  public static PROPERTIES_TO_BOX: string[] = ['addressPolygonPoints', '__formBranch', 'distributionGroupUuids', 'stationIds', 'publicationChannels'];
 
   public static BUSINESS_RULE_FIELDS: any = {
     branch: { power: 'S', gas: 'G', telecommunication: 'TK' },
diff --git a/projects/grid-failure-information-app/src/app/shared/models/failure-coords.model.ts b/projects/grid-failure-information-app/src/app/shared/models/failure-coords.model.ts
index de6290b..504ab74 100644
--- a/projects/grid-failure-information-app/src/app/shared/models/failure-coords.model.ts
+++ b/projects/grid-failure-information-app/src/app/shared/models/failure-coords.model.ts
@@ -13,9 +13,11 @@
 import { Boxed, box } from 'ngrx-forms';
 import { Globals } from '@grid-failure-information-app/shared/constants/globals';
 
-export class FailureCoords {
+export class FailureCoordsInformation {
   public longitude: number = null;
   public latitude: number = null;
+  public radius: number = null;
+  public addressPolygonPoints: Array<[Number, Number]> = null;
 
   public constructor(data: any = null) {
     Object.keys(data || {})
diff --git a/projects/grid-failure-information-app/src/app/shared/models/grid-failure.model.ts b/projects/grid-failure-information-app/src/app/shared/models/grid-failure.model.ts
index fb45602..109f517 100644
--- a/projects/grid-failure-information-app/src/app/shared/models/grid-failure.model.ts
+++ b/projects/grid-failure-information-app/src/app/shared/models/grid-failure.model.ts
@@ -33,7 +33,7 @@
   public condensedCount: number = null;
   public city: string = null;
   public district: string = null;
-  public distributionGroupUuids: string[] = null;
+  public distributionGroupUuids: Array<string> = null;
   public failureBegin: string = null;
   public failureClassification: string = null;
   public failureClassificationId: string = null;
@@ -49,6 +49,7 @@
   public responsibility: string = null;
   public stationId: string = null;
   public stationDescription: string = null;
+  public stationIds: Array<string> = null;
   public statusExtern: string = null;
   public statusExternId: string = null;
   public statusIntern: string = null;
diff --git a/projects/grid-failure-information-app/src/app/shared/models/index.ts b/projects/grid-failure-information-app/src/app/shared/models/index.ts
index 6f9b245..225ae0b 100644
--- a/projects/grid-failure-information-app/src/app/shared/models/index.ts
+++ b/projects/grid-failure-information-app/src/app/shared/models/index.ts
@@ -27,3 +27,4 @@
 export * from './settings.model';
 export * from './distribution-group-text-placeholder.model';
 export * from './publication-channel.model';
+export * from './polygon.model';
diff --git a/projects/grid-failure-information-app/src/app/shared/models/polygon.model.ts b/projects/grid-failure-information-app/src/app/shared/models/polygon.model.ts
new file mode 100644
index 0000000..40eea76
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/models/polygon.model.ts
@@ -0,0 +1,30 @@
+/********************************************************************************
+ * 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 { Boxed, box } from 'ngrx-forms';
+import { Globals } from '@grid-failure-information-app/shared/constants/globals';
+
+export class Polygon {
+  public addressPolygonPoints: Array<[Number, Number]> = null;
+
+  public constructor(data: any = null) {
+    Object.keys(data || {})
+      .filter(property => this.hasOwnProperty(property))
+      .forEach(property => {
+        if (Globals.PROPERTIES_TO_BOX.includes(property)) {
+          this[property] = box(data[property]);
+        } else {
+          this[property] = data[property];
+        }
+      });
+  }
+}
diff --git a/projects/grid-failure-information-app/src/app/shared/store/actions/grid-failures.action.ts b/projects/grid-failure-information-app/src/app/shared/store/actions/grid-failures.action.ts
index 0bf88b6..4bd4dbc 100644
--- a/projects/grid-failure-information-app/src/app/shared/store/actions/grid-failures.action.ts
+++ b/projects/grid-failure-information-app/src/app/shared/store/actions/grid-failures.action.ts
@@ -23,6 +23,7 @@
   FailureAddress,
   DistributionGroup,
   PublicationChannel,
+  Polygon,
 } from '@grid-failure-information-app/shared/models';
 
 export interface ILoadGridFailuresSuccess {
@@ -96,10 +97,26 @@
 export const putGridFailuresCondensationSuccess = createAction('[CondensedGridFailures] Put Success', props<{ payload: GridFailure[] }>());
 export const putGridFailuresCondensationFail = createAction('[CondensedGridFailures] Put Fail', props<{ payload: string }>());
 
-export const loadGridFailureStations = createAction('[GridFailureStations] Load');
+export const loadStations = createAction('[Stations] Load');
+export const loadStationsSuccess = createAction('[Stations] Load Success', props<{ payload: Array<FailureStation> }>());
+export const loadStationsFail = createAction('[Stations] Load Fail', props<{ payload: string }>());
+
+export const loadGridFailureStations = createAction('[GridFailureStations] Load', props<{ payload: string }>());
 export const loadGridFailureStationsSuccess = createAction('[GridFailureStations] Load Success', props<{ payload: Array<FailureStation> }>());
 export const loadGridFailureStationsFail = createAction('[GridFailureStations] Load Fail', props<{ payload: string }>());
 
+export const postGridFailureStation = createAction('[GridFailureStation] Post', props<{ gridFailureDetailId: string; station: FailureStation }>());
+export const postGridFailureStationSuccess = createAction('[GridFailureStation] Post Success');
+export const postGridFailureStationFail = createAction('[GridFailureStation] Post Fail', props<{ payload: string }>());
+
+export const loadGridFailurePolygon = createAction('[loadGridFailurePolygon] Load', props<{ payload: string[] }>());
+export const loadGridFailurePolygonSuccess = createAction('[loadGridFailurePolygon] Load Success', props<{ payload: Array<[number, number]> }>());
+export const loadGridFailurePolygonFail = createAction('[loadGridFailurePolygon] Load Fail', props<{ payload: string }>());
+
+export const deleteGridFailureStation = createAction('[GridFailureStation] Delete', props<{ gridFailureDetailId: string; stationId: string }>());
+export const deleteGridFailureStationSuccess = createAction('[GridFailureStation] Delete Success');
+export const deleteGridFailureStationFail = createAction('[GridFailureStation] Delete Fail', props<{ payload: string }>());
+
 export const loadAddressPostalcodes = createAction('[AddressPostalcodes] Load', props<{ branch: string }>());
 export const loadAddressPostalcodesSuccess = createAction('[AddressPostalcodes] Load Success', props<{ payload: Array<string> }>());
 export const loadAddressPostalcodesFail = createAction('[AddressPostalcodes] Load Fail', props<{ payload: string }>());
diff --git a/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.spec.ts b/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.spec.ts
index 1300be4..71f575f 100644
--- a/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.spec.ts
@@ -52,7 +52,7 @@
       postGridFailuresCondensation() {},
       putGridFailuresCondensation() {},
       getCondensedGridFailures() {},
-      getGridFailureStations() {},
+      getStations() {},
       getAddressPostalcodes() {},
       getAddressCommunities() {},
       getAddressDistricts() {},
@@ -64,6 +64,10 @@
       deleteDistributionGroupAssignment() {},
       postPublicationChannelAssignment() {},
       deletePublicationChannelAssignment() {},
+      getGridFailureStations() {},
+      postGridFailureStation() {},
+      deleteGridFailureStation() {},
+      getGridFailurePolygon() {},
     } as any;
     store = {
       dispatch() {},
@@ -326,23 +330,23 @@
     actions$.next(gridFailureActions.putGridFailuresCondensation({ gridFailureId: id, payload: apiResponse }));
   });
 
-  it('should equal getGridFailureStationsSuccess after getGridFailureStations', done => {
+  it('should equal getStationsSuccess after getStations', done => {
     apiResponse = [new FailureStation({ id: '1' })];
-    spyOn(apiClient, 'getGridFailureStations').and.returnValue(of(apiResponse));
-    effects.getGridFailureStations$.pipe(take(1)).subscribe(result => {
-      expect(result).toEqual(gridFailureActions.loadGridFailureStationsSuccess({ payload: apiResponse }));
+    spyOn(apiClient, 'getStations').and.returnValue(of(apiResponse));
+    effects.getStations$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadStationsSuccess({ payload: apiResponse }));
     });
     done();
-    actions$.next(gridFailureActions.loadGridFailureStations());
+    actions$.next(gridFailureActions.loadStations());
   });
 
-  it('should equal getGridFailureStationsFail in response to getGridFailureStations Error', done => {
-    spyOn(apiClient, 'getGridFailureStations').and.returnValue(throwError('x'));
-    effects.getGridFailureStations$.pipe(take(1)).subscribe(result => {
-      expect(result).toEqual(gridFailureActions.loadGridFailureStationsFail({ payload: 'x' }));
+  it('should equal getStationsFail in response to getStations Error', done => {
+    spyOn(apiClient, 'getStations').and.returnValue(throwError('x'));
+    effects.getStations$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadStationsFail({ payload: 'x' }));
     });
     done();
-    actions$.next(gridFailureActions.loadGridFailureStations());
+    actions$.next(gridFailureActions.loadStations());
   });
 
   it('should equal loadAddressPostalcodes after getAddressPostalcodes', done => {
@@ -499,6 +503,69 @@
     actions$.next(gridFailureActions.loadGridFailureAddress({ payload: '1' }));
   });
 
+  it('should equal loadGridFailureStations in response to getGridFailureStations', done => {
+    apiResponse = new FailureStation({ id: '1' });
+    spyOn(apiClient, 'getGridFailureStations').and.returnValue(of(apiResponse));
+    effects.getGridFailureStations$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadGridFailureStationsSuccess({ payload: apiResponse }));
+    });
+    done();
+    actions$.next(gridFailureActions.loadGridFailureStations({ payload: '1' }));
+  });
+
+  it('should equal loadGridFailureStations Fail after getGridFailureStations Error', done => {
+    spyOn(apiClient, 'getGridFailureStations').and.returnValue(throwError('x'));
+    effects.getGridFailureStations$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadGridFailureStationsFail({ payload: 'x' }));
+    });
+    done();
+    actions$.next(gridFailureActions.loadGridFailureStations({ payload: '1' }));
+  });
+
+  it('should equal postGridFailureStationSuccess in response to postGridFailureStation', done => {
+    apiResponse = new FailureStation({ id: '1' });
+    const gridFailureId = 'x';
+    spyOn(apiClient, 'postGridFailureStation').and.returnValue(of(apiResponse));
+    effects.postGridFailureStation$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.postGridFailureStationSuccess());
+    });
+    done();
+    actions$.next(gridFailureActions.postGridFailureStation({ gridFailureDetailId: gridFailureId, station: apiResponse }));
+  });
+
+  it('should equal postGridFailureStationFail in response to postGridFailureStation Error', done => {
+    apiResponse = new FailureStation({ id: '1' });
+    const gridFailureId = 'x';
+    spyOn(apiClient, 'postGridFailureStation').and.returnValue(throwError('x'));
+    effects.postGridFailureStation$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.postGridFailureStationFail({ payload: 'x' }));
+    });
+    done();
+    actions$.next(gridFailureActions.postGridFailureStation({ gridFailureDetailId: gridFailureId, station: apiResponse }));
+  });
+
+  it('should equal deleteGridFailureStationSuccess after deleteGridFailureStation', done => {
+    apiResponse = new FailureStation({ id: '1' });
+    const gridFailureId = 'x';
+    spyOn(apiClient, 'deleteGridFailureStation').and.returnValue(of(null));
+    effects.deleteGridFailureStation$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.deleteGridFailureStationSuccess());
+    });
+    done();
+    actions$.next(gridFailureActions.deleteGridFailureStation({ gridFailureDetailId: gridFailureId, stationId: apiResponse }));
+  });
+
+  it('should equal deleteGridFailureStationFail after deleteGridFailureStation Error', done => {
+    apiResponse = new FailureStation({ id: '1' });
+    const gridFailureId = 'x';
+    spyOn(apiClient, 'deleteGridFailureStation').and.returnValue(throwError('x'));
+    effects.deleteGridFailureStation$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.deleteGridFailureStationFail({ payload: 'x' }));
+    });
+    done();
+    actions$.next(gridFailureActions.deleteGridFailureStation({ gridFailureDetailId: gridFailureId, stationId: apiResponse }));
+  });
+
   it('should dispatch loadGridFailureDistributionGroupsSuccess action triggered by loadGridFailureDistributionGroups action', done => {
     apiResponse = [new DistributionGroup({ id: '1' })];
     spyOn(apiClient, 'getGridFailureDistributionGroups').and.returnValue(of(apiResponse));
@@ -591,4 +658,26 @@
     done();
     actions$.next(gridFailureActions.deletePublicationChannelAssignment({ gridFailureId: '1', channel: 'SMS' }));
   });
+
+  it('should equal loadGridFailurePolygon in response to getGridFailurePolygon', done => {
+    apiResponse = [
+      [1, 1],
+      [5, 5],
+    ];
+    spyOn(apiClient, 'getGridFailurePolygon').and.returnValue(of(apiResponse));
+    effects.getGridFailurePolygon$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadGridFailurePolygonSuccess({ payload: apiResponse }));
+    });
+    done();
+    actions$.next(gridFailureActions.loadGridFailurePolygon({ payload: ['xx', 'xx'] }));
+  });
+
+  it('should equal loadGridFailurePolygon Fail after loadGridFailurePolygon Error', done => {
+    spyOn(apiClient, 'getGridFailurePolygon').and.returnValue(throwError('x'));
+    effects.getGridFailurePolygon$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadGridFailurePolygonFail({ payload: 'x' }));
+    });
+    done();
+    actions$.next(gridFailureActions.loadGridFailurePolygon({ payload: ['xx', 'xx'] }));
+  });
 });
diff --git a/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.ts b/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.ts
index 4a796c0..15e1c52 100644
--- a/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.ts
+++ b/projects/grid-failure-information-app/src/app/shared/store/effects/grid-failures.effect.ts
@@ -205,18 +205,76 @@
     )
   );
 
+  getStations$: any = createEffect(() =>
+    this._actions$.pipe(
+      ofType(gridFailureActions.loadStations),
+      switchMap(action => {
+        return this._apiClient
+          .getStations()
+          .map((response: FailureStation[]) => gridFailureActions.loadStationsSuccess({ payload: response }))
+          .catch(error => of(gridFailureActions.loadStationsFail({ payload: error })));
+      })
+    )
+  );
+
+  getGridFailurePolygon$: any = createEffect(() =>
+    this._actions$.pipe(
+      ofType(gridFailureActions.loadGridFailurePolygon),
+      switchMap(action => {
+        return this._apiClient
+          .getGridFailurePolygon(action.payload)
+          .map((gridFailurePolygon: Array<[number, number]>) => gridFailureActions.loadGridFailurePolygonSuccess({ payload: gridFailurePolygon }))
+          .catch(error => of(gridFailureActions.loadGridFailurePolygonFail({ payload: error })));
+      })
+    )
+  );
+
   getGridFailureStations$: any = createEffect(() =>
     this._actions$.pipe(
       ofType(gridFailureActions.loadGridFailureStations),
       switchMap(action => {
         return this._apiClient
-          .getGridFailureStations()
+          .getGridFailureStations(action.payload)
           .map((response: FailureStation[]) => gridFailureActions.loadGridFailureStationsSuccess({ payload: response }))
           .catch(error => of(gridFailureActions.loadGridFailureStationsFail({ payload: error })));
       })
     )
   );
 
+  postGridFailureStation$: any = createEffect(() => {
+    let gridFailureId: string = '';
+    return this._actions$.pipe(
+      ofType(gridFailureActions.postGridFailureStation),
+      switchMap(action => {
+        gridFailureId = action.gridFailureDetailId;
+        return this._apiClient.postGridFailureStation(action.gridFailureDetailId, action.station).pipe(
+          map(() => {
+            this._store.dispatch(gridFailureActions.loadGridFailureStations({ payload: gridFailureId }));
+            return gridFailureActions.postGridFailureStationSuccess();
+          }),
+          catchError(error => of(gridFailureActions.postGridFailureStationFail({ payload: error })))
+        );
+      })
+    );
+  });
+
+  deleteGridFailureStation$: any = createEffect(() => {
+    let gridFailureId: string = '';
+    return this._actions$.pipe(
+      ofType(gridFailureActions.deleteGridFailureStation),
+      switchMap(action => {
+        gridFailureId = action.gridFailureDetailId;
+        return this._apiClient.deleteGridFailureStation(action.gridFailureDetailId, action.stationId).pipe(
+          map(() => {
+            this._store.dispatch(gridFailureActions.loadGridFailureStations({ payload: gridFailureId }));
+            return gridFailureActions.deleteGridFailureStationSuccess();
+          }),
+          catchError(error => of(gridFailureActions.deleteGridFailureStationFail({ payload: error })))
+        );
+      })
+    );
+  });
+
   getAddressPostalcodes$: any = createEffect(() =>
     this._actions$.pipe(
       ofType(gridFailureActions.loadAddressPostalcodes),
diff --git a/projects/grid-failure-information-app/src/app/shared/store/index.ts b/projects/grid-failure-information-app/src/app/shared/store/index.ts
index b3ee3bc..eb9b659 100644
--- a/projects/grid-failure-information-app/src/app/shared/store/index.ts
+++ b/projects/grid-failure-information-app/src/app/shared/store/index.ts
@@ -25,6 +25,8 @@
 import * as fromGridFailureStates from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-states.reducer';
 import * as fromGridFailureRadii from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-radii.reducer';
 import * as fromGridFailureExpectedReasons from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-expected-reasons.reducer';
+import * as fromStations from '@grid-failure-information-app/shared/store/reducers/grid-failures/stations.reducer';
+import * as fromGridFailurePolygon from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer';
 import * as fromGridFailureStations from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-stations.reducer';
 import * as fromGridFailuresDetailForm from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer';
 import * as fromCondensedGridFailures from '@grid-failure-information-app/shared/store/reducers/grid-failures/condensed-grid-failures.reducer';
@@ -55,6 +57,8 @@
   gridFailureRadii: fromGridFailureRadii.State;
   gridFailureExpectedReasons: fromGridFailureExpectedReasons.State;
   gridFailureStations: fromGridFailureStations.State;
+  gridFailurePolygon: fromGridFailurePolygon.State;
+  stations: fromStations.State;
   condensedGridFailures: fromCondensedGridFailures.State;
   gridFailureDistributionGroups: fromGridFailureDistributionGroups.State;
 }
@@ -86,6 +90,8 @@
   gridFailureRadii: fromGridFailureRadii.reducer,
   gridFailureExpectedReasons: fromGridFailureExpectedReasons.reducer,
   gridFailureStations: fromGridFailureStations.reducer,
+  gridFailurePolygon: fromGridFailurePolygon.reducer,
+  stations: fromStations.reducer,
   condensedGridFailures: fromCondensedGridFailures.reducer,
   gridFailureDistributionGroups: fromGridFailureDistributionGroups.reducer,
 };
@@ -171,6 +177,13 @@
 export const getGridFailureExpectedReasonsFailed = createSelector(selectGridFailureExpectedReasons, fromGridFailureExpectedReasons.getFailed);
 export const getGridFailureExpectedReasonsData = createSelector(selectGridFailureExpectedReasons, fromGridFailureExpectedReasons.getData);
 
+// Stations
+export const selectStations = createSelector(selectGridFailuresState, (state: GridFailureState) => state.stations);
+export const getStationsLoaded = createSelector(selectStations, fromStations.getLoaded);
+export const getStationsLoading = createSelector(selectStations, fromStations.getLoading);
+export const getStationsFailed = createSelector(selectStations, fromStations.getFailed);
+export const getStationsData = createSelector(selectStations, fromStations.getData);
+
 // GridFailure stations
 export const selectGridFailureStations = createSelector(selectGridFailuresState, (state: GridFailureState) => state.gridFailureStations);
 export const getGridFailureStationsLoaded = createSelector(selectGridFailureStations, fromGridFailureStations.getLoaded);
@@ -178,6 +191,13 @@
 export const getGridFailureStationsFailed = createSelector(selectGridFailureStations, fromGridFailureStations.getFailed);
 export const getGridFailureStationsData = createSelector(selectGridFailureStations, fromGridFailureStations.getData);
 
+// GridFailure polygon
+export const selectGridFailurePolygon = createSelector(selectGridFailuresState, (state: GridFailureState) => state.gridFailurePolygon);
+export const getGridFailurePolygonLoaded = createSelector(selectGridFailurePolygon, fromGridFailurePolygon.getLoaded);
+export const getGridFailurePolygonLoading = createSelector(selectGridFailurePolygon, fromGridFailurePolygon.getLoading);
+export const getGridFailurePolygonFailed = createSelector(selectGridFailurePolygon, fromGridFailurePolygon.getFailed);
+export const getGridFailurePolygonData = createSelector(selectGridFailurePolygon, fromGridFailurePolygon.getData);
+
 // CondensedGridFailures
 export const selectCondensedGridFailures = createSelector(selectGridFailuresState, (state: GridFailureState) => state.condensedGridFailures);
 export const getCondensedGridFailuresLoaded = createSelector(selectCondensedGridFailures, fromCondensedGridFailures.getLoaded);
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer.ts
index 972d42d..c4b8aa4 100644
--- a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer.ts
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer.ts
@@ -191,6 +191,9 @@
       housenumber: (propState, formState): any => {
         return requiredIf(propState, formState, formState.controls.branchId.id, NO_BRANCH_ID_KEY);
       },
+      radiusId: (propState, formState): any => {
+        return requiredIf(propState, formState, formState.controls.branchId.id, NO_BRANCH_ID_KEY);
+      },
       voltageLevel: (propState, formState): any => {
         return requiredIf(propState, formState, formState.controls.branchId.id, GAS_BRANCH_ID_KEY);
       },
@@ -204,7 +207,6 @@
       branchId: validate(required),
       failureBegin: validate(required),
       expectedReasonId: validate(required),
-      radiusId: validate(required),
       longitude: validate(required),
       latitude: validate(required),
       __formBranch: validate(required),
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer.spec.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer.spec.ts
new file mode 100644
index 0000000..130a676
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer.spec.ts
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * 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 {
+  GridFailurePolygonReducer,
+  INITIAL_STATE,
+  getData,
+  getLoading,
+  getLoaded,
+  getFailed,
+  reducer,
+} from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer';
+import * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action';
+
+describe('GridFailurePolygonReducer', () => {
+  it('should return the initial state', () => {
+    const action = { type: 'NOOP' } as any;
+    const result = reducer(undefined, action);
+
+    expect(result).toBe(INITIAL_STATE);
+  });
+
+  it('should trigger loading state', () => {
+    const action = gridFailureActions.loadGridFailurePolygon({ payload: ['xx'] });
+    const result = GridFailurePolygonReducer(INITIAL_STATE, action);
+
+    expect(result).toEqual({
+      ...INITIAL_STATE,
+      loading: true,
+    });
+  });
+
+  it('should trigger loaded state', () => {
+    const action = gridFailureActions.loadGridFailurePolygonSuccess({ payload: [[1, 1]] });
+    const result = GridFailurePolygonReducer(INITIAL_STATE, action);
+
+    expect(result.loaded).toBe(true);
+  });
+
+  it('should trigger failed state', () => {
+    const error = { payload: 'err_msg' };
+    const action = gridFailureActions.loadGridFailurePolygonFail(error);
+    const result = GridFailurePolygonReducer(INITIAL_STATE, action);
+
+    expect(result).toEqual({
+      ...INITIAL_STATE,
+      failed: true,
+    });
+  });
+
+  it('getData return state.data', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getData(state);
+    expect(result).toBe(state.data);
+  });
+
+  it('getLoading return state.loading', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getLoading(state);
+    expect(result).toBe(state.loading);
+  });
+
+  it('getLoaded return state.loaded', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getLoaded(state);
+    expect(result).toBe(state.loaded);
+  });
+
+  it('getFailed return state.failed', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getFailed(state);
+    expect(result).toBe(state.failed);
+  });
+});
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer.ts
new file mode 100644
index 0000000..93d86e4
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-polygon.reducer.ts
@@ -0,0 +1,69 @@
+/********************************************************************************
+ * 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 * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action';
+import { Polygon } from '@grid-failure-information-app/shared/models';
+import { createReducer, on } from '@ngrx/store';
+
+export interface State {
+  loading: boolean;
+  loaded: boolean;
+  failed: boolean;
+  data: Array<[number, number]>;
+}
+
+export const INITIAL_STATE: State = {
+  loading: false,
+  loaded: false,
+  failed: false,
+  data: [],
+};
+
+export const GridFailurePolygonReducer = createReducer(
+  INITIAL_STATE,
+  on(gridFailureActions.loadGridFailurePolygon, (state: any, action: any) => {
+    return {
+      ...state,
+      loading: true,
+      loaded: false,
+      failed: false,
+      data: [],
+    };
+  }),
+  on(gridFailureActions.loadGridFailurePolygonSuccess, (state: any, action: any) => {
+    return {
+      ...state,
+      loading: false,
+      loaded: true,
+      failed: false,
+      data: action['payload'],
+    };
+  }),
+  on(gridFailureActions.loadGridFailurePolygonFail, (state: any, action: any) => {
+    return {
+      ...state,
+      loaded: false,
+      loading: false,
+      failed: true,
+      data: [],
+    };
+  })
+);
+
+export function reducer(state = INITIAL_STATE, action: any): State {
+  return GridFailurePolygonReducer(state, action);
+}
+
+export const getData = (state: State) => state.data;
+export const getLoading = (state: State) => state.loading;
+export const getLoaded = (state: State) => state.loaded;
+export const getFailed = (state: State) => state.failed;
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-stations.reducer.spec.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-stations.reducer.spec.ts
index fb4271c..916d34f 100644
--- a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-stations.reducer.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-stations.reducer.spec.ts
@@ -30,15 +30,15 @@
     expect(result).toBe(INITIAL_STATE);
   });
 
-  it('should trigger loading state', () => {
-    const action = gridFailureActions.loadGridFailureStations();
-    const result = GridFailureStationsReducer(INITIAL_STATE, action);
+  // it('should trigger loading state', () => {
+  //   const action = gridFailureActions.loadPolygonStationInformation({ payload: 'xx' });
+  //   const result = GridFailureStationsReducer(INITIAL_STATE, action);
 
-    expect(result).toEqual({
-      ...INITIAL_STATE,
-      loading: true,
-    });
-  });
+  //   expect(result).toEqual({
+  //     ...INITIAL_STATE,
+  //     loading: true,
+  //   });
+  // });
 
   it('should trigger loaded state', () => {
     const items = { payload: [new FailureStation()] };
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/stations.reducer.spec.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/stations.reducer.spec.ts
new file mode 100644
index 0000000..af7a91b
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/stations.reducer.spec.ts
@@ -0,0 +1,85 @@
+/********************************************************************************
+ * 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 {
+  StationsReducer,
+  INITIAL_STATE,
+  getData,
+  getLoading,
+  getLoaded,
+  getFailed,
+  reducer,
+} from '@grid-failure-information-app/shared/store/reducers/grid-failures/stations.reducer';
+import * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action';
+import { FailureStation } from '@grid-failure-information-app/shared/models';
+
+describe('StationsReducer', () => {
+  it('should return the initial state', () => {
+    const action = { type: 'NOOP' } as any;
+    const result = reducer(undefined, action);
+
+    expect(result).toBe(INITIAL_STATE);
+  });
+
+  it('should trigger loading state', () => {
+    const action = gridFailureActions.loadStations();
+    const result = StationsReducer(INITIAL_STATE, action);
+
+    expect(result).toEqual({
+      ...INITIAL_STATE,
+      loading: true,
+    });
+  });
+
+  it('should trigger loaded state', () => {
+    const items = { payload: [new FailureStation()] };
+    const action = gridFailureActions.loadStationsSuccess(items);
+    const result = StationsReducer(INITIAL_STATE, action);
+
+    expect(result.loaded).toBe(true);
+  });
+
+  it('should trigger failed state', () => {
+    const error = { payload: 'err_msg' };
+    const action = gridFailureActions.loadStationsFail(error);
+    const result = StationsReducer(INITIAL_STATE, action);
+
+    expect(result).toEqual({
+      ...INITIAL_STATE,
+      failed: true,
+    });
+  });
+
+  it('getData return state.data', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getData(state);
+    expect(result).toBe(state.data);
+  });
+
+  it('getLoading return state.loading', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getLoading(state);
+    expect(result).toBe(state.loading);
+  });
+
+  it('getLoaded return state.loaded', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getLoaded(state);
+    expect(result).toBe(state.loaded);
+  });
+
+  it('getFailed return state.failed', () => {
+    const state = { ...INITIAL_STATE };
+    const result = getFailed(state);
+    expect(result).toBe(state.failed);
+  });
+});
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/stations.reducer.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/stations.reducer.ts
new file mode 100644
index 0000000..48a332a
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/stations.reducer.ts
@@ -0,0 +1,69 @@
+/********************************************************************************
+ * 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 * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action';
+import { FailureStation } from '@grid-failure-information-app/shared/models';
+import { createReducer, on } from '@ngrx/store';
+
+export interface State {
+  loading: boolean;
+  loaded: boolean;
+  failed: boolean;
+  data: Array<FailureStation>;
+}
+
+export const INITIAL_STATE: State = {
+  loading: false,
+  loaded: false,
+  failed: false,
+  data: [],
+};
+
+export const StationsReducer = createReducer(
+  INITIAL_STATE,
+  on(gridFailureActions.loadStations, (state: any, action: any) => {
+    return {
+      ...state,
+      loading: true,
+      loaded: false,
+      failed: false,
+      data: [],
+    };
+  }),
+  on(gridFailureActions.loadStationsSuccess, (state: any, action: any) => {
+    return {
+      ...state,
+      loading: false,
+      loaded: true,
+      failed: false,
+      data: action['payload'],
+    };
+  }),
+  on(gridFailureActions.loadStationsFail, (state: any, action: any) => {
+    return {
+      ...state,
+      loaded: false,
+      loading: false,
+      failed: true,
+      data: [],
+    };
+  })
+);
+
+export function reducer(state = INITIAL_STATE, action: any): State {
+  return StationsReducer(state, action);
+}
+
+export const getData = (state: State) => state.data;
+export const getLoading = (state: State) => state.loading;
+export const getLoaded = (state: State) => state.loaded;
+export const getFailed = (state: State) => state.failed;
diff --git a/projects/grid-failure-information-app/src/app/shared/utility/form-utils.ts b/projects/grid-failure-information-app/src/app/shared/utility/form-utils.ts
index 775bc96..058aaeb 100644
--- a/projects/grid-failure-information-app/src/app/shared/utility/form-utils.ts
+++ b/projects/grid-failure-information-app/src/app/shared/utility/form-utils.ts
@@ -16,7 +16,7 @@
  * Unboxes all boxed elements of the passed object.
  * Properties to unbox are identified by the '__boxed' property.
  */
-export function unboxProperties(obj: any): object {
+export function unboxProperties<T>(obj: any): T {
   Object.keys(obj || {})
     .filter(property => obj.hasOwnProperty(property))
     .forEach(property => {
@@ -25,5 +25,5 @@
       }
     });
 
-  return obj;
+  return obj as T;
 }
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 5fd1d2d..975140d 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
@@ -130,13 +130,14 @@
     if (!!this._map && !!this._mapDetailData) {
       if (this._mapDetailData.latitude && this._mapDetailData.longitude) {
         L.marker([this._mapDetailData.latitude, this._mapDetailData.longitude], { icon: this._icon }).addTo(this._map);
+        this._drawPolygonOrCircle(this._mapDetailData);
       }
     }
   }
 
   // Draw whether polygon, circle or nothing; graded according to priority
   private _drawPolygonOrCircle(gridFailure: GridFailureMapInformation): void {
-    if (gridFailure.addressPolygonPoints && !!gridFailure.addressPolygonPoints['value']) {
+    if (!!gridFailure.addressPolygonPoints && !!gridFailure.addressPolygonPoints['value'] && !!gridFailure.addressPolygonPoints['value'].length) {
       L.polygon(gridFailure.addressPolygonPoints['value'], {
         color: Globals.RADIUS_BORDER_COLOR,
         fillColor: Globals.RADIUS_FILL_COLOR,