unsubscribe test
This commit is contained in:
		
							parent
							
								
									7bd56800ea
								
							
						
					
					
						commit
						28ef8e0545
					
				| @ -9,10 +9,10 @@ | |||||||
| 
 | 
 | ||||||
|       <div class="ui-inputgroup"> |       <div class="ui-inputgroup"> | ||||||
|         <span class="md-inputfield"> |         <span class="md-inputfield"> | ||||||
|           <input #input type="text" pInputText value="{{probe.displayName}}"> |           <input #input type="text" pInputText value="{{probe.displayName}}" (keypress)="onDisplayNameChangeKeypress($event, input.value)"> | ||||||
|           <label></label> |           <label></label> | ||||||
|         </span> |         </span> | ||||||
|         <button pButton type="button" icon="ui-icon-search" (click)="onDisplayNameChange(input.value)"></button> |         <button pButton label="Save" type="button" (click)="onDisplayNameChange(input.value)"></button> | ||||||
|       </div> |       </div> | ||||||
| 
 | 
 | ||||||
|       <div class="ui-g form-group"> |       <div class="ui-g form-group"> | ||||||
| @ -44,3 +44,4 @@ | |||||||
|   <button class="ui-button-width-fit" type="button" label="Discovery" icon="ui-icon-search" pButton (click)="onDiscoveryClick()"></button> |   <button class="ui-button-width-fit" type="button" label="Discovery" icon="ui-icon-search" pButton (click)="onDiscoveryClick()"></button> | ||||||
| </div> | </div> | ||||||
| <p-confirmDialog header="Confirmation" icon="fa ui-icon-warning" width="425"></p-confirmDialog> | <p-confirmDialog header="Confirmation" icon="fa ui-icon-warning" width="425"></p-confirmDialog> | ||||||
|  | <p-growl [(value)]="msgs"></p-growl> | ||||||
| @ -6,33 +6,35 @@ import * as DetailStore from '../../store/detail'; | |||||||
| import * as ModifyStore from '../../store/modify'; | import * as ModifyStore from '../../store/modify'; | ||||||
| import { DetailSelector, ModifySelector } from '../../store'; | import { DetailSelector, ModifySelector } from '../../store'; | ||||||
| import { Probe } from '../../model'; | import { Probe } from '../../model'; | ||||||
| import { ConfirmationService } from 'primeng/primeng'; | import { ConfirmationService, Message } from 'primeng/primeng'; | ||||||
| import * as CIDR from 'ip-cidr'; | import * as CIDR from 'ip-cidr'; | ||||||
| import { Subscription } from 'rxjs/Subscription'; | import { Subscription } from 'rxjs/Subscription'; | ||||||
|  | import { MessageService } from 'primeng/components/common/messageservice'; | ||||||
| // import { SettingComponent as DiscoverySettingComponent } from 'packages/discovery/component/setting/setting.component';
 | // import { SettingComponent as DiscoverySettingComponent } from 'packages/discovery/component/setting/setting.component';
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'of-probe-detail', |   selector: 'of-probe-detail', | ||||||
|   templateUrl: './detail.component.html', |   templateUrl: './detail.component.html', | ||||||
|   providers: [ConfirmationService] |   providers: [ConfirmationService, MessageService] | ||||||
| }) | }) | ||||||
| export class DetailComponent implements OnInit, AfterContentInit, OnDestroy { | export class DetailComponent implements OnInit, AfterContentInit, OnDestroy { | ||||||
| 
 | 
 | ||||||
|   probeSubscription$: Subscription; |   probeSubscription$: Subscription; | ||||||
|   modifySuccessSubscription$: Subscription; |  | ||||||
|   probe$ = this.detailStore.pipe(select(DetailSelector.select('probe'))); |   probe$ = this.detailStore.pipe(select(DetailSelector.select('probe'))); | ||||||
|   modifySuccess$ = this.modifyStore.pipe(select(ModifySelector.select('probe'))); |   modifySuccess$ = this.modifyStore.pipe(select(ModifySelector.select('modifiedProbe'))); | ||||||
|   probe: Probe = null; |   probe: Probe = null; | ||||||
|   IPRange: string; |   IPRange: string; | ||||||
|   display = false; |   display = false; | ||||||
|  |   msgs: Message[] = []; | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     private route: ActivatedRoute, |     private route: ActivatedRoute, | ||||||
|     private router: Router, |     private router: Router, | ||||||
|     private detailStore: Store<DetailStore.State>, |     private detailStore: Store<DetailStore.State>, | ||||||
|     private modifyStore: Store<ModifyStore.State>, |     private modifyStore: Store<ModifyStore.State>, | ||||||
|     private confirmationService: ConfirmationService |     private confirmationService: ConfirmationService, | ||||||
|  |     private messageService: MessageService | ||||||
|   ) { } |   ) { } | ||||||
| 
 | 
 | ||||||
|   ngOnInit() { |   ngOnInit() { | ||||||
| @ -47,23 +49,12 @@ export class DetailComponent implements OnInit, AfterContentInit, OnDestroy { | |||||||
|         console.log(error.response.message); |         console.log(error.response.message); | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|     this.modifySuccessSubscription$ = this.modifySuccess$.subscribe( |  | ||||||
|       (probe: Probe) => { |  | ||||||
|         if (probe) { |  | ||||||
|           console.log('modify success'); |  | ||||||
|         } else { |  | ||||||
|           console.log('modify fail'); |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       (error: RPCClientError) => { |  | ||||||
|         console.log(error.response.message); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnDestroy() { |   ngOnDestroy() { | ||||||
|  |     if (this.probeSubscription$) { | ||||||
|       this.probeSubscription$.unsubscribe(); |       this.probeSubscription$.unsubscribe(); | ||||||
|     this.modifySuccessSubscription$.unsubscribe(); |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngAfterContentInit() { |   ngAfterContentInit() { | ||||||
| @ -105,10 +96,34 @@ export class DetailComponent implements OnInit, AfterContentInit, OnDestroy { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onDisplayNameChange(value: string) { |   onDisplayNameChange(value: string) { | ||||||
|  |     if (value === this.probe.displayName) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     this.probe.displayName = value; |     this.probe.displayName = value; | ||||||
|     this.modifyStore.dispatch( |     this.modifyStore.dispatch( | ||||||
|       new ModifyStore.Modify(this.probe) |       new ModifyStore.Modify(this.probe) | ||||||
|     ); |     ); | ||||||
|  | 
 | ||||||
|  |     const modifySuccessSubscription$: Subscription = this.modifySuccess$.subscribe( | ||||||
|  |       (probe: Probe) => { | ||||||
|  |         if (probe) { | ||||||
|  |           this.msgs = []; | ||||||
|  |           this.msgs.push({ severity: 'success', summary: 'Succeed', detail: 'Probe name has changed.' }); | ||||||
|  |         } | ||||||
|  |         if (modifySuccessSubscription$) { | ||||||
|  |           modifySuccessSubscription$.unsubscribe(); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       (error: RPCClientError) => { | ||||||
|  |         console.log(error.response.message); | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onDisplayNameChangeKeypress(event, value) { | ||||||
|  |     if (event.key === 'Enter') { | ||||||
|  |       this.onDisplayNameChange(value); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ | |||||||
|       <td>{{probeHost.host.ipv4}}</td> |       <td>{{probeHost.host.ipv4}}</td> | ||||||
|       <td>{{probeHost.host.os.vendor.name}}</td> |       <td>{{probeHost.host.os.vendor.name}}</td> | ||||||
|       <td>{{probeHost.probe.cidr}}</td> |       <td>{{probeHost.probe.cidr}}</td> | ||||||
|       <td>반정규화 필요</td> |       <td>{{probeHost.probe.targetCount}}</td> | ||||||
|       <td>{{probeHost.probe.authorizeDate | date: 'dd.MM.yyyy'}}</td> |       <td>{{probeHost.probe.authorizeDate | date: 'dd.MM.yyyy'}}</td> | ||||||
|       <td>{{probeHost.probe.authorizeMember.name}}</td> |       <td>{{probeHost.probe.authorizeMember.name}}</td> | ||||||
|     </tr> |     </tr> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { Component, OnInit, AfterViewInit, AfterContentInit, ViewChild } from '@angular/core'; | import { Component, OnInit, AfterViewInit, AfterContentInit, ViewChild, OnDestroy } from '@angular/core'; | ||||||
| import { Router } from '@angular/router'; | import { Router } from '@angular/router'; | ||||||
| 
 | 
 | ||||||
| import { Store, select } from '@ngrx/store'; | import { Store, select } from '@ngrx/store'; | ||||||
| @ -10,12 +10,14 @@ import { AuthSelector } from 'packages/member/store'; | |||||||
| import { Probe, ProbeHost } from '../../model'; | import { Probe, ProbeHost } from '../../model'; | ||||||
| import * as ListStore from '../../store/probe-host-list'; | import * as ListStore from '../../store/probe-host-list'; | ||||||
| import { ProbeHostListSelector } from '../../store'; | import { ProbeHostListSelector } from '../../store'; | ||||||
|  | import { Subscription } from 'rxjs/Subscription'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'of-probe-list', |   selector: 'of-probe-list', | ||||||
|   templateUrl: './list.component.html', |   templateUrl: './list.component.html', | ||||||
| }) | }) | ||||||
| export class ListComponent implements OnInit, AfterContentInit { | export class ListComponent implements OnInit, AfterContentInit, OnDestroy { | ||||||
|  |   probeHostsSubscription$: Subscription; | ||||||
|   probeHosts$ = this.store.pipe(select(ProbeHostListSelector.select('probeHosts'))); |   probeHosts$ = this.store.pipe(select(ProbeHostListSelector.select('probeHosts'))); | ||||||
|   probeHosts: ProbeHost[]; |   probeHosts: ProbeHost[]; | ||||||
| 
 | 
 | ||||||
| @ -26,7 +28,7 @@ export class ListComponent implements OnInit, AfterContentInit { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnInit() { |   ngOnInit() { | ||||||
|     this.probeHosts$.subscribe( |     this.probeHostsSubscription$ = this.probeHosts$.subscribe( | ||||||
|       (probeHosts: ProbeHost[]) => { |       (probeHosts: ProbeHost[]) => { | ||||||
|         console.log(probeHosts); |         console.log(probeHosts); | ||||||
|         this.probeHosts = probeHosts; |         this.probeHosts = probeHosts; | ||||||
| @ -46,7 +48,12 @@ export class ListComponent implements OnInit, AfterContentInit { | |||||||
|         console.log(error); |         console.log(error); | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|  |   ngOnDestroy() { | ||||||
|  |     if (this.probeHostsSubscription$) { | ||||||
|  |       this.probeHostsSubscription$.unsubscribe(); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onRowSelect(event) { |   onRowSelect(event) { | ||||||
|  | |||||||
| @ -31,4 +31,8 @@ export class ProbeService { | |||||||
|     return this.rpcService.call<Probe>('ProbeService.modify', probe); |     return this.rpcService.call<Probe>('ProbeService.modify', probe); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public remove(id: string): Observable<boolean> { | ||||||
|  |     return this.rpcService.call<boolean>('ProbeService.remove', id); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,9 +9,6 @@ export enum ActionType { | |||||||
|   Read = '[probe.detail] Read', |   Read = '[probe.detail] Read', | ||||||
|   ReadSuccess = '[probe.detail] ReadSuccess', |   ReadSuccess = '[probe.detail] ReadSuccess', | ||||||
|   ReadFailure = '[probe.detail] ReadFailure', |   ReadFailure = '[probe.detail] ReadFailure', | ||||||
|   Modify = '[probe.detail] Modify', |  | ||||||
|   ModifySuccess = '[probe.detail] ModifySuccess', |  | ||||||
|   ModifyFailure = '[probe.detail] ModifyFailure', |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class Read implements Action { | export class Read implements Action { | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ export function reducer(state = initialState, action: Actions): State { | |||||||
|         ...state, |         ...state, | ||||||
|         error: null, |         error: null, | ||||||
|         isPending: false, |         isPending: false, | ||||||
|         probe: action.payload, |         modifiedProbe: action.payload, | ||||||
|       }; |       }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -35,7 +35,7 @@ export function reducer(state = initialState, action: Actions): State { | |||||||
|         ...state, |         ...state, | ||||||
|         error: action.payload, |         error: action.payload, | ||||||
|         isPending: false, |         isPending: false, | ||||||
|         probe: null, |         modifiedProbe: null, | ||||||
|       }; |       }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,12 +7,12 @@ import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; | |||||||
| export interface State extends EntityState<Probe> { | export interface State extends EntityState<Probe> { | ||||||
|   error: RPCClientError | null; |   error: RPCClientError | null; | ||||||
|   isPending: boolean; |   isPending: boolean; | ||||||
|   probe: Probe | null; |   modifiedProbe: Probe | null; | ||||||
| } | } | ||||||
| export const adapter: EntityAdapter<Probe> = createEntityAdapter<Probe>(); | export const adapter: EntityAdapter<Probe> = createEntityAdapter<Probe>(); | ||||||
| export const initialState: State = adapter.getInitialState({ | export const initialState: State = adapter.getInitialState({ | ||||||
|   error: null, |   error: null, | ||||||
|   isPending: false, |   isPending: false, | ||||||
|   probe: null, |   modifiedProbe: null, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								src/packages/probe/store/remove/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/packages/probe/store/remove/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | export * from './remove.action'; | ||||||
|  | export * from './remove.effect'; | ||||||
|  | export * from './remove.reducer'; | ||||||
|  | export * from './remove.state'; | ||||||
							
								
								
									
										37
									
								
								src/packages/probe/store/remove/remove.action.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/packages/probe/store/remove/remove.action.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | import { Action } from '@ngrx/store'; | ||||||
|  | 
 | ||||||
|  | import { RPCClientError } from '@loafer/ng-rpc/protocol'; | ||||||
|  | 
 | ||||||
|  | import { Probe } from '../../model'; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export enum ActionType { | ||||||
|  |   Remove = '[probe.remove] Remove', | ||||||
|  |   RemoveSuccess = '[probe.detail] RemoveSuccess', | ||||||
|  |   RemoveFailure = '[probe.detail] RemoveFailure', | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class Remove implements Action { | ||||||
|  |   readonly type = ActionType.Remove; | ||||||
|  | 
 | ||||||
|  |   constructor(public payload: {id: string}) {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class RemoveSuccess implements Action { | ||||||
|  |   readonly type = ActionType.RemoveSuccess; | ||||||
|  | 
 | ||||||
|  |   constructor(public payload: boolean) {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class RemoveFailure implements Action { | ||||||
|  |   readonly type = ActionType.RemoveFailure; | ||||||
|  | 
 | ||||||
|  |   constructor(public payload: RPCClientError) {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export type Actions = | ||||||
|  |   | Remove | ||||||
|  |   | RemoveSuccess | ||||||
|  |   | RemoveFailure | ||||||
|  | ; | ||||||
							
								
								
									
										15
									
								
								src/packages/probe/store/remove/remove.effect.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/packages/probe/store/remove/remove.effect.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | import { TestBed, inject } from '@angular/core/testing'; | ||||||
|  | 
 | ||||||
|  | import { Effects } from './remove.effect'; | ||||||
|  | 
 | ||||||
|  | describe('ProbeDetail.Effects', () => { | ||||||
|  |   beforeEach(() => { | ||||||
|  |     TestBed.configureTestingModule({ | ||||||
|  |       providers: [Effects] | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('should be created', inject([Effects], (effects: Effects) => { | ||||||
|  |     expect(effects).toBeTruthy(); | ||||||
|  |   })); | ||||||
|  | }); | ||||||
							
								
								
									
										49
									
								
								src/packages/probe/store/remove/remove.effect.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/packages/probe/store/remove/remove.effect.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | import { Injectable } from '@angular/core'; | ||||||
|  | import { Router } from '@angular/router'; | ||||||
|  | 
 | ||||||
|  | import { Effect, Actions, ofType } from '@ngrx/effects'; | ||||||
|  | import { Action } from '@ngrx/store'; | ||||||
|  | 
 | ||||||
|  | import { Observable } from 'rxjs/Observable'; | ||||||
|  | import { of } from 'rxjs/observable/of'; | ||||||
|  | 
 | ||||||
|  | import 'rxjs/add/operator/catch'; | ||||||
|  | import 'rxjs/add/operator/do'; | ||||||
|  | import 'rxjs/add/operator/exhaustMap'; | ||||||
|  | import 'rxjs/add/operator/switchMap'; | ||||||
|  | import 'rxjs/add/operator/map'; | ||||||
|  | import 'rxjs/add/operator/take'; | ||||||
|  | 
 | ||||||
|  | import { RPCClientError } from '@loafer/ng-rpc/protocol'; | ||||||
|  | 
 | ||||||
|  | import { Probe } from '../../model'; | ||||||
|  | import { ProbeService } from '../../service/probe.service'; | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   Remove, | ||||||
|  |   RemoveSuccess, | ||||||
|  |   RemoveFailure, | ||||||
|  |   ActionType | ||||||
|  | } from './remove.action'; | ||||||
|  | 
 | ||||||
|  | @Injectable() | ||||||
|  | export class Effects { | ||||||
|  | 
 | ||||||
|  |   constructor( | ||||||
|  |     private actions$: Actions, | ||||||
|  |     private probeService: ProbeService, | ||||||
|  |     private router: Router | ||||||
|  |   ) { } | ||||||
|  | 
 | ||||||
|  |   @Effect() | ||||||
|  |   remove$: Observable<Action> = this.actions$ | ||||||
|  |     .ofType(ActionType.Remove) | ||||||
|  |     .map((action: Remove) => action.payload) | ||||||
|  |     .switchMap(payload => this.probeService.remove(payload.id)) | ||||||
|  |     .map(result => { | ||||||
|  |       return new RemoveSuccess(result); | ||||||
|  |     }) | ||||||
|  |     .catch((error: RPCClientError) => { | ||||||
|  |       return of(new RemoveFailure(error)); | ||||||
|  |     }); | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								src/packages/probe/store/remove/remove.reducer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/packages/probe/store/remove/remove.reducer.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | import { | ||||||
|  |   Remove, | ||||||
|  |   RemoveFailure, | ||||||
|  |   RemoveSuccess, | ||||||
|  |   ActionType, | ||||||
|  |   Actions, | ||||||
|  | } from './remove.action'; | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   State, | ||||||
|  |   initialState, | ||||||
|  | } from './remove.state'; | ||||||
|  | 
 | ||||||
|  | import { Probe } from '../../model'; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export function reducer(state = initialState, action: Actions): State { | ||||||
|  |   switch (action.type) { | ||||||
|  |     case ActionType.Remove: { | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         error: null, | ||||||
|  |         isPending: true, | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     case ActionType.RemoveSuccess: { | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         error: null, | ||||||
|  |         isPending: false, | ||||||
|  |         succeed: action.payload, | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     case ActionType.RemoveFailure: { | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         error: action.payload, | ||||||
|  |         isPending: false, | ||||||
|  |         succeed: false, | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     default: { | ||||||
|  |       return state; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								src/packages/probe/store/remove/remove.state.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/packages/probe/store/remove/remove.state.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | import { RPCClientError } from '@loafer/ng-rpc/protocol'; | ||||||
|  | import { Probe } from '../../model'; | ||||||
|  | 
 | ||||||
|  | export interface State  { | ||||||
|  |   error: RPCClientError | null; | ||||||
|  |   isPending: boolean; | ||||||
|  |   succeed: boolean | null; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const initialState: State = { | ||||||
|  |   error: null, | ||||||
|  |   isPending: false, | ||||||
|  |   succeed: null, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user