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

Signed-off-by: Peter Buschmann <peter.buschmann@pta.de>
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 6c42a93..e0a5032 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
@@ -221,6 +221,12 @@
     return null;
   }
 
+  @GET('/grid-failure-informations/{gridFailureId}/channels')
+  @Adapter(GridFailureService.publicationChannelListAdapter)
+  public getGridFailurePublicationChannels(@Path('gridFailureId') gridFailureId: string): Observable<PublicationChannel[]> {
+    return null;
+  }
+
   @POST('/grid-failure-informations/{gridFailureId}/channels')
   @Adapter(GridFailureService.publicationChannelAdapter)
   public postPublicationChannelAssignment(
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 0ea8a36..3530425 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
@@ -543,10 +543,7 @@
                     type="checkbox"
                     class="custom-control-input"
                     id="{{ 'channel' + i }}"
-                    [checked]="
-                      gridFailureDetailsSandbox.currentFormState.value.publicationChannels['value'] &&
-                      gridFailureDetailsSandbox.currentFormState.value.publicationChannels['value'].includes(channel)
-                    "
+                    [checked]="gridFailureDetailsSandbox.selectedPublicationChannels && gridFailureDetailsSandbox.selectedPublicationChannels.includes(channel)"
                     (change)="gridFailureDetailsSandbox.setPublicationChannels(channel, $event.target.checked)"
                   />
                   <label class="custom-control-label" for="{{ 'channel' + i }}">{{ channel }} </label>
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 09aacd5..e6e5cd0 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
@@ -141,4 +141,10 @@
     component.clearSearchInput();
     expect(component.searchInput.nativeElement.value).toBeFalsy();
   });
+
+  it('should disable unnecessary required properties when setLocation was called', () => {
+    const spy = spyOn(gridFailureSandbox, 'disableUnnecessaryRequiredProperties');
+    component.setLocation();
+    expect(spy).toHaveBeenCalled();
+  });
 });
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 168b70c..e6761a1 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
@@ -14,7 +14,14 @@
 import { Router } from '@angular/router';
 import { GridFailureDetailsSandbox } from '@grid-failure-information-app/pages/grid-failure/grid-failure-details/grid-failure-details.sandbox';
 import { StateEnum } from '@grid-failure-information-app/shared/constants/enums';
-import { FailureBranch, FailureHousenumber, FailureStation, GridFailure, DistributionGroup } from '@grid-failure-information-app/shared/models';
+import {
+  FailureBranch,
+  FailureHousenumber,
+  FailureStation,
+  GridFailure,
+  DistributionGroup,
+  PublicationChannel,
+} from '@grid-failure-information-app/shared/models';
 import { State } from '@grid-failure-information-app/shared/store';
 import * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action';
 import { UtilService } from '@grid-failure-information-app/shared/utility/utility.service';
@@ -51,6 +58,7 @@
     service.gridFailureDetailsFormState$ = of((INITIAL_STATE.value.branchId = '00' as any));
     service.noBranchId = '123';
     service.addressPostCodes$ = of(['test', 'test1', 'test2', 'hello']);
+    service.gridFailurePublicationChannels$ = of([new PublicationChannel()]);
   }));
 
   it('should create GridFailureDetailsSandbox service', () => {
@@ -655,6 +663,11 @@
     expect(appState.dispatch).toHaveBeenCalledWith(distributionGroupActions.loadDistributionGroups());
   });
 
+  it('should dispatch loadGridFailurePublicationChannels Action via loadGridFailurePublicationChannels()', () => {
+    service.loadGridFailurePublicationChannels('x');
+    expect(appState.dispatch).toHaveBeenCalledWith(gridFailureActions.loadGridFailurePublicationChannels({ payload: 'x' }));
+  });
+
   it('should compare maxVersionNumber vs. current versionNumber via checkForMaxVersion()', () => {
     service.maxVersionNumber = 1;
     service.currentFormState = { value: { versionNumber: 1 } as any } as any;
@@ -687,51 +700,25 @@
 
   it('should displayNotification when publishing is attempted without at least one selected channel', () => {
     const spy: any = spyOn(service['_utilService'], 'displayNotification');
-    const gfdetail = new GridFailure();
-    gfdetail.id = 'id';
-    gfdetail.publicationChannels = new Array();
-    gfdetail.publicationChannels['value'] = [];
-    service.currentFormState = INITIAL_STATE;
-    (service.currentFormState as any).isValid = true;
-    (service.currentFormState as any).value = gfdetail;
+    service.selectedPublicationChannels = [];
     service.setPublishedState();
     expect(spy).toHaveBeenCalled;
   });
 
   it('should call saveGridFailure() when publishing with at least one selected channel', () => {
     const spy: any = spyOn(service, 'saveGridFailure');
-    const gfdetail = new GridFailure();
-    gfdetail.id = 'id';
-    gfdetail.publicationChannels = new Array();
-    gfdetail.publicationChannels['value'] = ['SMS'];
-    service.currentFormState = INITIAL_STATE;
-    (service.currentFormState as any).isValid = true;
-    (service.currentFormState as any).value = gfdetail;
+    service.selectedPublicationChannels = ['MAIL'];
     service.setPublishedState();
     expect(spy).toHaveBeenCalled;
   });
 
   it('should dispatch createPublicationChannelAssignment action if a channel was checked', () => {
-    const gfdetail = new GridFailure();
-    gfdetail.id = 'id';
-    gfdetail.publicationChannels = new Array();
-    gfdetail.publicationChannels['value'] = ['SMS'];
-    service.currentFormState = INITIAL_STATE;
-    (service.currentFormState as any).isValid = true;
-    (service.currentFormState as any).value = gfdetail;
     service['_gridFailureId'] = 'x1';
     service.setPublicationChannels('SMS', true);
     expect(appState.dispatch).toHaveBeenCalledWith(gridFailureActions.createPublicationChannelAssignment({ gridFailureId: 'x1', channel: 'SMS' }));
   });
 
   it('should dispatch deletePublicationChannelAssignment action if a channel was unchecked', () => {
-    const gfdetail = new GridFailure();
-    gfdetail.id = 'id';
-    gfdetail.publicationChannels = new Array();
-    gfdetail.publicationChannels['value'] = ['SMS'];
-    service.currentFormState = INITIAL_STATE;
-    (service.currentFormState as any).isValid = true;
-    (service.currentFormState as any).value = gfdetail;
     service['_gridFailureId'] = 'x1';
     service.setPublicationChannels('SMS', false);
     expect(appState.dispatch).toHaveBeenCalledWith(gridFailureActions.deletePublicationChannelAssignment({ gridFailureId: 'x1', channel: 'SMS' }));
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 21d1936..ebecb34 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
@@ -1,4 +1,3 @@
-import { BranchNameEnum } from './../../../shared/constants/enums';
 /********************************************************************************
  * Copyright (c) 2020 Contributors to the Eclipse Foundation
  *
@@ -121,11 +120,14 @@
   public gridFailureDistributionGroupsLoading$: Observable<boolean> = this.appState$.select(store.getGridFailureDistributionGroupsLoading);
   public distributionGroups$: Observable<models.DistributionGroup[]> = this.appState$.select(store.getDistributionGroupsData);
   public exportChannels$: Observable<string[]> = this.appState$.select(store.getExportChannels);
+  public gridFailurePublicationChannels$: Observable<models.PublicationChannel[]> = this.appState$.select(store.getGridFailurePublicationChannelsData);
   public disablePublishButton: boolean;
   public disableStationAttributes = false;
+  public selectedPublicationChannels: Array<string>;
 
   private _gridFailureId: string;
   private _selectedStation: models.FailureStation;
+  private _stations: Array<models.FailureStation> = new Array<models.FailureStation>();
   private _assignedDistributionGroups: Array<models.DistributionGroup>;
   private _stations: Array<models.FailureStation> = new Array<models.FailureStation>();
 
@@ -219,9 +221,11 @@
     this.loadGridFailureBranches();
     this._setGridFailureStations();
   }
+
   public setGridFailureId(gridFailureId: string) {
     this._gridFailureId = gridFailureId;
   }
+
   public loadGridFailureDistributionGroups(gridFailureId: string): void {
     this.appState$.dispatch(gridFailureActions.loadGridFailureDistributionGroups({ payload: gridFailureId }));
   }
@@ -230,6 +234,10 @@
     this.appState$.dispatch(distributionGroupActions.loadDistributionGroups());
   }
 
+  public loadGridFailurePublicationChannels(gridFailureId: string): void {
+    this.appState$.dispatch(gridFailureActions.loadGridFailurePublicationChannels({ payload: gridFailureId }));
+  }
+
   public setState(newState: string): void {
     this.gridFailureStates$
       .pipe(
@@ -246,7 +254,7 @@
   }
 
   public setPublishedState(): void {
-    if (this.currentFormState.value.publicationChannels['value'].length === 0) {
+    if (this.selectedPublicationChannels.length === 0) {
       this._utilService.displayNotification('PublicationRequiresAtLeastOneChannel', 'alert');
     } else {
       this.saveGridFailure(true);
@@ -405,7 +413,6 @@
         ofType(gridFailureActions.loadGridFailureVersionsSuccess),
         takeUntil(this._endSubscriptions$),
         map(action => {
-          this.disablePublishButton = this.currentFormState.value.publicationStatus === enums.PublicationStatusEnum.VE;
           const gridFailures: models.GridFailure[] = action['payload'];
           return !!gridFailures && Math.max(...gridFailures.map(o => o.versionNumber));
         })
@@ -449,6 +456,11 @@
         this._assignedDistributionGroups = assignedGroups;
       });
 
+    this.gridFailurePublicationChannels$.pipe(takeUntil(this._endSubscriptions$)).subscribe((channels: Array<models.PublicationChannel>) => {
+      this.selectedPublicationChannels = channels.map(s => s.publicationChannel);
+      this.disablePublishButton = channels.length > 0 && !channels.find(channel => !channel.published);
+    });
+
     this.gridFailureDetailsFormState$.subscribe(gridFailureDetails => {
       let failureRadius: models.FailureRadius;
       if (!!gridFailureDetails.value.radiusId) {
@@ -587,28 +599,10 @@
   }
 
   public setPublicationChannels(channel: string, checked: boolean) {
-    let publicationChannels = this.currentFormState.value.publicationChannels['value'];
     if (checked) {
       this.appState$.dispatch(gridFailureActions.createPublicationChannelAssignment({ gridFailureId: this._gridFailureId, channel: channel }));
-      this.actionsSubject
-        .pipe(
-          ofType(gridFailureActions.createPublicationChannelAssignmentSuccess),
-          map(action => action.payload),
-          takeUntil(this._endSubscriptions$)
-        )
-        .subscribe((publicationChannel: models.PublicationChannel) => {
-          publicationChannels.push(publicationChannel.publicationChannel);
-          if (this.disablePublishButton && !publicationChannel.published) {
-            this.disablePublishButton = false;
-          }
-          this.appState$.dispatch(new SetValueAction(INITIAL_STATE.controls.publicationChannels.id, box(publicationChannels)));
-        });
     } else {
       this.appState$.dispatch(gridFailureActions.deletePublicationChannelAssignment({ gridFailureId: this._gridFailureId, channel: channel }));
-      this.actionsSubject.pipe(ofType(gridFailureActions.deletePublicationChannelAssignmentSuccess), takeUntil(this._endSubscriptions$)).subscribe(() => {
-        publicationChannels = publicationChannels.filter((x: string) => x !== channel);
-        this.appState$.dispatch(new SetValueAction(INITIAL_STATE.controls.publicationChannels.id, box(publicationChannels)));
-      });
     }
   }
 
@@ -741,14 +735,14 @@
   }
 
   private _setNoBranchId(branches: models.FailureBranch[]): void {
-    const noBranch: models.FailureBranch = branches.find(branch => branch.name === BranchNameEnum.NO_BRANCH);
+    const noBranch: models.FailureBranch = branches.find(branch => branch.name === enums.BranchNameEnum.NO_BRANCH);
     this.noBranchId = !!noBranch ? noBranch.id : null;
     this.appState$.dispatch(new SetUserDefinedPropertyAction(FORM_ID, NO_BRANCH_ID_KEY, this.noBranchId));
   }
 
   private _setGasBranchId(branches: models.FailureBranch[]): void {
     let gasBranchId: string;
-    const gasBranch: models.FailureBranch = branches.find(branch => branch.name === BranchNameEnum.GAS);
+    const gasBranch: models.FailureBranch = branches.find(branch => branch.name === enums.BranchNameEnum.GAS);
     gasBranchId = !!gasBranch ? gasBranch.id : null;
     this.appState$.dispatch(new SetUserDefinedPropertyAction(FORM_ID, GAS_BRANCH_ID_KEY, gasBranchId));
   }
@@ -761,6 +755,7 @@
     this._gridFailureId = null;
     this.maxVersionNumber = null;
     this._assignedDistributionGroups = null;
+    this.selectedPublicationChannels = null;
     navigateHome(this._router);
   }
 
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-distribution-groups/grid-failure-distribution-groups-column-definition.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-distribution-groups/grid-failure-distribution-groups-column-definition.ts
index 5b9c9ce..45e96db 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-distribution-groups/grid-failure-distribution-groups-column-definition.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-details/grid-failure-distribution-groups/grid-failure-distribution-groups-column-definition.ts
@@ -22,6 +22,7 @@
   {
     field: 'distributionText',
     headerName: 'DistributionGroup.Text',
+    maxWidth: 900,
     sortable: true,
     filter: 'setFilterComponent',
   },
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 17e134f..951b0df 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
@@ -35,6 +35,7 @@
       loadGridFailureStations() {},
       loadDistributionGroups() {},
       loadGridFailureDistributionGroups() {},
+      loadGridFailurePublicationChannels() {},
     } 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 513574d..d17b1ea 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
@@ -32,6 +32,8 @@
       this._detailSandbox.loadGridFailureVersions(gridFailureId);
       // load distribution group
       this._detailSandbox.loadGridFailureDistributionGroups(gridFailureId);
+      // load publication channels
+      this._detailSandbox.loadGridFailurePublicationChannels(gridFailureId);
     }
 
     this._detailSandbox.loadGridFailureBranches();
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 f37eadc..dac1c66 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
@@ -111,4 +111,10 @@
     const item = GridFailureService.distributionGroupAdapter(response);
     expect(item.id).toBe(response.id);
   });
+
+  it('should transform publication channel response', () => {
+    const response: any = { id: 'X' };
+    const item = GridFailureService.publicationChannelAdapter(response);
+    expect(item.id).toBe(response.id);
+  });
 });
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 33601d3..76f0ccf 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
@@ -88,6 +88,10 @@
     return new DistributionGroup(response);
   }
 
+  static publicationChannelListAdapter(response: any): Array<PublicationChannel> {
+    return response.map(responseItem => new PublicationChannel(responseItem));
+  }
+
   static publicationChannelAdapter(response: any): PublicationChannel {
     return new PublicationChannel(response);
   }
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 efb5962..82ce234 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
@@ -71,7 +71,6 @@
   public failureInformationCondensedId: string = null;
   public addressPolygonPoints: Array<[Number, Number]> | Boxed<Array<[Number, Number]>> = null;
   public description: string = null;
-  public publicationChannels: Array<string> = null;
 
   public constructor(data: any = null) {
     super(data);
diff --git a/projects/grid-failure-information-app/src/app/shared/models/publication-channel.model.ts b/projects/grid-failure-information-app/src/app/shared/models/publication-channel.model.ts
index 644ea42..6c0d6b4 100644
--- a/projects/grid-failure-information-app/src/app/shared/models/publication-channel.model.ts
+++ b/projects/grid-failure-information-app/src/app/shared/models/publication-channel.model.ts
@@ -11,9 +11,9 @@
  * SPDX-License-Identifier: EPL-2.0
  ********************************************************************************/
 export class PublicationChannel {
-  public failureInformationId: string = null;
+  public id: string = null;
   public publicationChannel: string = null;
-  public published: string = null;
+  public published: boolean = null;
 
   public constructor(data: any = null) {
     Object.keys(data || {})
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 7c478f3..728d34a 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,7 +23,6 @@
   FailureAddress,
   DistributionGroup,
   PublicationChannel,
-  Polygon,
 } from '@grid-failure-information-app/shared/models';
 
 export interface ILoadGridFailuresSuccess {
@@ -162,6 +161,10 @@
 export const deleteDistributionGroupAssignmentSuccess = createAction('[DistributionGroupAssignment] Delete Success');
 export const deleteDistributionGroupAssignmentFail = createAction('[DistributionGroupAssignment] Delete Fail', props<{ payload: string }>());
 
+export const loadGridFailurePublicationChannels = createAction('[PublicationChannels] Load', props<{ payload: string }>());
+export const loadGridFailurePublicationChannelsSuccess = createAction('[PublicationChannels] Load Success', props<{ payload: Array<PublicationChannel> }>());
+export const loadGridFailurePublicationChannelsFail = createAction('[PublicationChannels] Load Fail', props<{ payload: string }>());
+
 export const createPublicationChannelAssignment = createAction('[PublicationChannelAssignment] Create', props<{ gridFailureId: string; channel: string }>());
 export const createPublicationChannelAssignmentSuccess = createAction(
   '[PublicationChannelAssignment] Create Success',
@@ -169,7 +172,7 @@
 );
 export const createPublicationChannelAssignmentFail = createAction('[PublicationChannelAssignment] Create Fail', props<{ payload: string }>());
 
-export const deletePublicationChannelAssignment = createAction('[PublicationGroupAssignment] Delete', props<{ gridFailureId: string; channel: string }>());
+export const deletePublicationChannelAssignment = createAction('[PublicationChannelAssignment] Delete', props<{ gridFailureId: string; channel: string }>());
 export const deletePublicationChannelAssignmentSuccess = createAction('[PublicationChannelAssignment] Delete Success');
 export const deletePublicationChannelAssignmentFail = createAction('[PublicationChannelAssignment] Delete 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 332bf24..2cc6c7e 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
@@ -69,6 +69,7 @@
       deleteGridFailureStation() {},
       getGridFailurePolygon() {},
       getFailureReminder() {},
+      getGridFailurePublicationChannels() {},
     } as any;
     store = {
       dispatch() {},
@@ -623,6 +624,25 @@
     actions$.next(gridFailureActions.deleteDistributionGroupAssignment({ gridFailureId: '1', groupId: '2' }));
   });
 
+  it('should dispatch loadGridFailurePublicationChannelsSuccess action triggered by loadGridFailurePublicationChannels action', done => {
+    apiResponse = [new PublicationChannel({ id: '1' })];
+    spyOn(apiClient, 'getGridFailurePublicationChannels').and.returnValue(of(apiResponse));
+    effects.getGridFailurePublicationChannels$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadGridFailurePublicationChannelsSuccess({ payload: apiResponse }));
+    });
+    done();
+    actions$.next(gridFailureActions.loadGridFailurePublicationChannels({ payload: '1' }));
+  });
+
+  it('should dispatch loadGridFailurePublicationChannelsFail action triggered by loadGridFailurePublicationChannels action Error', done => {
+    spyOn(apiClient, 'getGridFailurePublicationChannels').and.returnValue(throwError('x'));
+    effects.getGridFailurePublicationChannels$.pipe(take(1)).subscribe(result => {
+      expect(result).toEqual(gridFailureActions.loadGridFailurePublicationChannelsFail({ payload: 'x' }));
+    });
+    done();
+    actions$.next(gridFailureActions.loadGridFailurePublicationChannels({ payload: '1' }));
+  });
+
   it('should dispatch createPublicationChannelAssignmentSuccess action triggered by createPublicationChannelAssignment action', done => {
     apiResponse = new PublicationChannel({ failureInformationId: '1' });
     spyOn(apiClient, 'postPublicationChannelAssignment').and.returnValue(of(apiResponse));
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 5af4a14..ef4d76a 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
@@ -30,6 +30,7 @@
   FailureHousenumber,
   FailureAddress,
   DistributionGroup,
+  PublicationChannel,
 } from '@grid-failure-information-app/shared/models';
 import { Store } from '@ngrx/store';
 
@@ -404,12 +405,25 @@
     )
   );
 
+  getGridFailurePublicationChannels$: any = createEffect(() =>
+    this._actions$.pipe(
+      ofType(gridFailureActions.loadGridFailurePublicationChannels),
+      switchMap(action => {
+        return this._apiClient
+          .getGridFailurePublicationChannels(action.payload)
+          .map((publicationChannels: PublicationChannel[]) => gridFailureActions.loadGridFailurePublicationChannelsSuccess({ payload: publicationChannels }))
+          .catch(error => of(gridFailureActions.loadGridFailurePublicationChannelsFail({ payload: error })));
+      })
+    )
+  );
+
   createPublicationChannelAssignment$: any = createEffect(() =>
     this._actions$.pipe(
       ofType(gridFailureActions.createPublicationChannelAssignment),
       switchMap(action => {
         return this._apiClient.postPublicationChannelAssignment(action.gridFailureId, action.channel).pipe(
           map(item => {
+            this._store.dispatch(gridFailureActions.loadGridFailurePublicationChannels({ payload: action.gridFailureId }));
             return gridFailureActions.createPublicationChannelAssignmentSuccess({ payload: item });
           }),
           catchError(error => of(gridFailureActions.createPublicationChannelAssignmentFail({ payload: error })))
@@ -424,6 +438,7 @@
       switchMap(action => {
         return this._apiClient.deletePublicationChannelAssignment(action.gridFailureId, action.channel).pipe(
           map(item => {
+            this._store.dispatch(gridFailureActions.loadGridFailurePublicationChannels({ payload: action.gridFailureId }));
             return gridFailureActions.deletePublicationChannelAssignmentSuccess();
           }),
           catchError(error => of(gridFailureActions.deletePublicationChannelAssignmentFail({ payload: error })))
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 f1d789b..1b89973 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
@@ -35,6 +35,8 @@
 import * as fromDistributionGroupsDetailForm from '@grid-failure-information-app/shared/store/reducers/distribution-groups/distribution-group-details-form.reducer';
 import * as fromDistributionGroupMembers from '@grid-failure-information-app/shared/store/reducers/distribution-groups/distribution-group-members.reducer';
 import * as fromGridFailureDistributionGroups from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-distribution-groups.reducer';
+import * as fromGridFailurePublicationChannels from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-publication-channels.reducer';
+
 import { createFeatureSelector } from '@ngrx/store';
 import { createSelector } from 'reselect';
 import { GridFailure, DistributionGroup } from '@grid-failure-information-app/shared/models';
@@ -62,6 +64,7 @@
   stations: fromStations.State;
   condensedGridFailures: fromCondensedGridFailures.State;
   gridFailureDistributionGroups: fromGridFailureDistributionGroups.State;
+  gridFailurePublicationChannels: fromGridFailurePublicationChannels.State;
   gridFailureReminder: fromGridFailureReminder.State;
 }
 
@@ -96,6 +99,7 @@
   stations: fromStations.reducer,
   condensedGridFailures: fromCondensedGridFailures.reducer,
   gridFailureDistributionGroups: fromGridFailureDistributionGroups.reducer,
+  gridFailurePublicationChannels: fromGridFailurePublicationChannels.reducer,
   gridFailureReminder: fromGridFailureReminder.reducer,
 };
 
@@ -222,6 +226,13 @@
 export const getGridFailureDistributionGroupsFailed = createSelector(selectGridFailureDistributionGroups, fromGridFailureDistributionGroups.getFailed);
 export const getGridFailureDistributionGroupsData = createSelector(selectGridFailureDistributionGroups, fromGridFailureDistributionGroups.getData);
 
+// GridFailurePublicationChannels
+export const selectGridFailurePublicationChannels = createSelector(selectGridFailuresState, (state: GridFailureState) => state.gridFailurePublicationChannels);
+export const getGridFailurePublicationChannelsLoaded = createSelector(selectGridFailurePublicationChannels, fromGridFailurePublicationChannels.getLoaded);
+export const getGridFailurePublicationChannelsLoading = createSelector(selectGridFailurePublicationChannels, fromGridFailurePublicationChannels.getLoading);
+export const getGridFailurePublicationChannelsFailed = createSelector(selectGridFailurePublicationChannels, fromGridFailurePublicationChannels.getFailed);
+export const getGridFailurePublicationChannelsData = createSelector(selectGridFailurePublicationChannels, fromGridFailurePublicationChannels.getData);
+
 /**
  * DistributionGroups store functions
  */
diff --git a/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-publication-channels.reducer.spec.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-publication-channels.reducer.spec.ts
new file mode 100644
index 0000000..9ee8911
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-publication-channels.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 {
+  GridFailurePublicationChannelsReducer,
+  INITIAL_STATE,
+  getData,
+  getLoading,
+  getLoaded,
+  getFailed,
+  reducer,
+} from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-publication-channels.reducer';
+import * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action';
+import { PublicationChannel } from '@grid-failure-information-app/shared/models';
+
+describe('GridFailurePublicationChannelsReducer reducer', () => {
+  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.loadGridFailurePublicationChannels({ payload: 'x' });
+    const result = GridFailurePublicationChannelsReducer(INITIAL_STATE, action);
+
+    expect(result).toEqual({
+      ...INITIAL_STATE,
+      loading: true,
+    });
+  });
+
+  it('should trigger loaded state', () => {
+    const items = { payload: [new PublicationChannel()] };
+    const action = gridFailureActions.loadGridFailurePublicationChannelsSuccess(items);
+    const result = GridFailurePublicationChannelsReducer(INITIAL_STATE, action);
+
+    expect(result.loaded).toBe(true);
+  });
+
+  it('should trigger failed state', () => {
+    const error = { payload: 'err_msg' };
+    const action = gridFailureActions.loadGridFailurePublicationChannelsFail(error);
+    const result = GridFailurePublicationChannelsReducer(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-publication-channels.reducer.ts b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-publication-channels.reducer.ts
new file mode 100644
index 0000000..a895a21
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/store/reducers/grid-failures/grid-failure-publication-channels.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 { PublicationChannel } from '@grid-failure-information-app/shared/models';
+import { createReducer, on } from '@ngrx/store';
+
+export interface State {
+  loading: boolean;
+  loaded: boolean;
+  failed: boolean;
+  data: Array<PublicationChannel>;
+}
+
+export const INITIAL_STATE: State = {
+  loading: false,
+  loaded: false,
+  failed: false,
+  data: [],
+};
+
+export const GridFailurePublicationChannelsReducer = createReducer(
+  INITIAL_STATE,
+  on(gridFailureActions.loadGridFailurePublicationChannels, (state: any, action: any) => {
+    return {
+      ...state,
+      loading: true,
+      loaded: false,
+      failed: false,
+      data: [],
+    };
+  }),
+  on(gridFailureActions.loadGridFailurePublicationChannelsSuccess, (state: any, action: any) => {
+    return {
+      ...state,
+      loading: false,
+      loaded: true,
+      failed: false,
+      data: action['payload'],
+    };
+  }),
+  on(gridFailureActions.loadGridFailurePublicationChannelsFail, (state: any, action: any) => {
+    return {
+      ...state,
+      loaded: false,
+      loading: false,
+      failed: true,
+      data: [],
+    };
+  })
+);
+
+export function reducer(state = INITIAL_STATE, action: any): State {
+  return GridFailurePublicationChannelsReducer(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;