This commit is contained in:
insanity 2018-05-26 18:08:40 +09:00
parent 67a924bcf1
commit 2149e32246
18 changed files with 241 additions and 130 deletions

View File

@ -69,6 +69,7 @@ import { TreeTableModule } from 'primeng/primeng';
import { CardModule } from 'primeng/card'; import { CardModule } from 'primeng/card';
import { DataViewModule } from 'primeng/dataview'; import { DataViewModule } from 'primeng/dataview';
import { SidebarModule } from 'primeng/sidebar'; import { SidebarModule } from 'primeng/sidebar';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
const PRIME_NG_MODULES: any[] = [ const PRIME_NG_MODULES: any[] = [
AccordionModule, AccordionModule,
@ -142,7 +143,8 @@ const PRIME_NG_MODULES: any[] = [
DataViewModule, DataViewModule,
SidebarModule, SidebarModule,
BlockUIModule, BlockUIModule,
InplaceModule InplaceModule,
ProgressSpinnerModule
]; ];
@NgModule({ @NgModule({

View File

@ -1,84 +1,97 @@
<div class="ui-g"> <p-blockUI [target]="content" [blocked]="pending">
<div class="ui-g-6 ui-nopad"> <i class="fa ui-icon-lock block-icon"></i>
<h1>Info</h1> </p-blockUI>
</div>
<!-- <p-messages [(value)]="msgs"></p-messages> -->
<div class="ui-g-6 nopad" dir="rtl" style="padding-top: 15px">
<button class="ui-button-width-fit" *ngIf="!editMode" pButton type="button" label="Edit" (click)="editMode = true"></button>
<button class="ui-button-width-fit" *ngIf="editMode" pButton type="button" label="Save" (click)="onEditSave()"></button>
</div>
</div>
<!-- Probe info --> <p-panel #content [showHeader]="false" class="block-panel">
<div class="ui-g ui-bottom-space-10">
<p-panel [showHeader]="false" class="nopad">
<div *ngIf="probeHost">
<div class="ui-g form-group">
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<div *ngIf="editMode" class="of-key-value-div">
<span>Name</span>
<span class="ng-star-inserted">
<input #input type="text" pInputText value="{{probeHost.probe.displayName}}" (keyup)="probeHost.probe.displayName = input.value">
</span>
</div>
<of-key-value *ngIf="!editMode" [key]="'Name'" [value]="probeHost.probe.displayName"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad"> <div class="ui-g">
<of-key-value [key]="'CIDR'" [value]="probeHost.probe.cidr"></of-key-value> <div class="ui-g-6 ui-nopad">
</div> <h1>Info</h1>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad"> </div>
<div *ngIf="editMode" class="of-key-value-div"> <div class="ui-g-6 nopad" dir="rtl" style="padding-top: 15px">
<span>Description</span> <button class="ui-button-width-fit" *ngIf="!editMode" pButton type="button" label="Edit" (click)="editMode = true"></button>
<span class="ng-star-inserted"> <button class="ui-button-width-fit" *ngIf="editMode" pButton type="button" label="Save" (click)="onEditSave()" [disabled]="displayNameErrMsg || descriptionErrMsg"></button>
<input *ngIf="editMode" #input type="text" pInputText value="{{probeHost.probe.description}}" (keyup)="probeHost.probe.description = input.value"> <button class="ui-button-width-fit" *ngIf="editMode" pButton type="button" label="Cancel" (click)="editMode = false"></button>
</span> </div>
</div>
<!-- Probe info -->
<div class="ui-g ui-bottom-space-10">
<p-panel [showHeader]="false" class="nopad">
<div *ngIf="probeHost">
<div class="ui-g form-group">
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<div *ngIf="editMode" class="of-key-value-div">
<span>Name</span>
<span class="ng-star-inserted">
<input #displayName type="text" pInputText value="{{probeHost.probe.displayName}}" (keyup)="onDisplayNameEditing(displayName.value)"/>
<div *ngIf="displayNameErrMsg" class="ui-message ui-messages-error ui-corner-all">{{displayNameErrMsg}}</div>
</span>
</div>
<of-key-value *ngIf="!editMode" [key]="'Name'" [value]="probeHost.probe.displayName"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'CIDR'" [value]="probeHost.probe.cidr"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<div *ngIf="editMode" class="of-key-value-div">
<span>Description</span>
<span class="ng-star-inserted">
<!-- <input *ngIf="editMode" #input type="text" pInputText value="{{probeHost.probe.description}}" (keyup)="probeHost.probe.description = input.value"> -->
<input #description type="text" pInputText value="{{probeHost.probe.description}}" (keyup)="onDescriptionEditing(description.value)"/>
<div *ngIf="descriptionErrMsg" class="ui-message ui-messages-error ui-corner-all">{{descriptionErrMsg}}</div>
</span>
</div>
<of-key-value *ngIf="!editMode" [key]="'Description'" [value]="probeHost.probe.description"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Key'" [value]="probeHost.probe.probeKey"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Authrozied at'" [value]="probeHost.probe.authorizeDate | date: 'dd/MM/yyyy'"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Authrozied by'" [value]="probeHost.probe.authorizeMember.name"></of-key-value>
</div> </div>
<of-key-value *ngIf="!editMode" [key]="'Description'" [value]="probeHost.probe.description"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Key'" [value]="probeHost.probe.probeKey"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Authrozied at'" [value]="probeHost.probe.authorizeDate | date: 'dd/MM/yyyy'"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Authrozied by'" [value]="probeHost.probe.authorizeMember.name"></of-key-value>
</div> </div>
</div> </div>
</div> </p-panel>
</p-panel>
<!-- Host info --> <!-- Host info -->
<p-panel [showHeader]="false" class="nopad"> <p-panel [showHeader]="false" class="nopad">
<div *ngIf="probeHost"> <div *ngIf="probeHost">
<div class="ui-g form-group"> <div class="ui-g form-group">
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'IPv4'" [value]="probeHost.host.ipv4"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'IPv6'" [value]="probeHost.host.ipv6"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Mac Address'" [value]="probeHost.host.mac"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'OS'" [value]="probeHost.host.os.vendor.name"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'IPv4'" [value]="probeHost.host.ipv4"></of-key-value>
</div> </div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'IPv6'" [value]="probeHost.host.ipv6"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'Mac Address'" [value]="probeHost.host.mac"></of-key-value>
</div>
<div class="ui-g-12 ui-md-6 ui-key-value ui-bottom-border-1 ui-nopad">
<of-key-value [key]="'OS'" [value]="probeHost.host.os.vendor.name"></of-key-value>
</div>
</div> </div>
</div> </p-panel>
</p-panel>
</div>
<div class="ui-g" dir="rtl">
<button class="ui-button-danger ui-button-width-fit" type="button" label="Remove this Probe" icon="ui-icon-close" pButton
(click)="onRemoveClick()"></button>
<button class="ui-button-width-fit" type="button" label="Discovery" icon="ui-icon-search" pButton (click)="onDiscoveryClick()"></button>
</div>
</p-panel>
</div>
<div class="ui-g" dir="rtl">
<button class="ui-button-danger ui-button-width-fit" type="button" label="Remove this Probe" icon="ui-icon-close" pButton
(click)="onRemoveClick()"></button>
<button class="ui-button-width-fit" type="button" label="Discovery" icon="ui-icon-search" pButton (click)="onDiscoveryClick()"></button>
</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> --> <p-growl [(value)]="msgs"></p-growl> -->

View File

@ -9,28 +9,43 @@ import { MessageService } from 'primeng/components/common/messageservice';
}) })
export class ProbeDetailComponent { export class ProbeDetailComponent {
@Input() pending: boolean;
@Input() probeHost: ProbeHost; @Input() probeHost: ProbeHost;
@Output() modify = new EventEmitter<ProbeHost>(); @Output() modify = new EventEmitter<ProbeHost>();
@Output() discovery = new EventEmitter<number>(); @Output() discovery = new EventEmitter<number>();
editMode = false; editMode = false;
displayNameErrMsg: string;
descriptionErrMsg: string;
displayName: string;
description: string;
constructor(private messageService: MessageService) { constructor(private messageService: MessageService) {
} }
onDisplayNameEditing(value: string) {
const msg: string = this.checkValidDisplayName(value);
if (msg !== null) {
this.displayNameErrMsg = msg;
} else {
this.displayNameErrMsg = null;
this.displayName = value;
}
}
onDescriptionEditing(value: string) {
const msg: string = this.checkValidDescription(value);
if (msg !== null) {
this.descriptionErrMsg = msg;
} else {
this.descriptionErrMsg = null;
this.description = value;
}
}
onEditSave() { onEditSave() {
const displayNameValidation = this.checkValidDisplayName(); this.probeHost.probe.displayName = this.displayName;
if (displayNameValidation) { this.probeHost.probe.description = this.description;
alert(displayNameValidation);
return;
}
const descriptionValidation = this.checkValidDescription();
if (descriptionValidation) {
alert(descriptionValidation);
return;
}
this.modify.emit(this.probeHost); this.modify.emit(this.probeHost);
this.editMode = false; this.editMode = false;
} }
@ -39,25 +54,23 @@ export class ProbeDetailComponent {
this.discovery.emit(this.probeHost.id); this.discovery.emit(this.probeHost.id);
} }
checkValidDisplayName(): string { checkValidDisplayName(value: string): string | null {
const displayName = this.probeHost.probe.displayName; if (value.length <= 2 || value.length > 20) {
if (displayName.length <= 2 || displayName.length > 20) {
return 'displayname length : 3 ~ 20'; return 'displayname length : 3 ~ 20';
} }
const regex = /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi; const regex = /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi;
if (displayName.match(regex)) { if (value.match(regex)) {
return 'Cannot use special characters.'; return 'Cannot use special characters.';
} }
return null; return null;
} }
checkValidDescription(): string { checkValidDescription(value: string): string | null {
const description = this.probeHost.probe.description; if (value.length > 50) {
if (description.length > 50) {
return 'description length : 0 ~ 50'; return 'description length : 0 ~ 50';
} }
const regex = /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi; const regex = /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi;
if (description.match(regex)) { if (value.match(regex)) {
return 'Cannot use special characters.'; return 'Cannot use special characters.';
} }
return null; return null;

View File

@ -1,27 +1,32 @@
<h1>Probes</h1> <h1>Probes</h1>
<p-table [value]="probeHosts" selectionMode="single" (onRowSelect)="onRowSelect($event)" [resizableColumns]="true"> <p-blockUI [target]="content" [blocked]="pending">
<ng-template pTemplate="header"> <i class="fa ui-icon-lock block-icon"></i>
<tr> </p-blockUI>
<th>Probe Name</th> <p-panel #content [showHeader]="false" class="block-panel">
<th>Uptime</th> <p-table [value]="probeHosts" selectionMode="single" (onRowSelect)="onRowSelect($event)" [resizableColumns]="true">
<th style="width:10em">IP</th> <ng-template pTemplate="header">
<th style="width:8em">OS</th> <tr>
<th style="width:10em">CIDR</th> <th>Probe Name</th>
<th pResizableColumn>Targets</th> <th>Uptime</th>
<th style="width:8em">Authroized at</th> <th style="width:10em">IP</th>
<th style="width:9em">Authroized by</th> <th style="width:8em">OS</th>
</tr> <th style="width:10em">CIDR</th>
</ng-template> <th pResizableColumn>Targets</th>
<ng-template pTemplate="body" let-probeHost> <th style="width:8em">Authroized at</th>
<tr [pSelectableRow]="probeHost"> <th style="width:9em">Authroized by</th>
<td>{{probeHost.probe.displayName}}</td> </tr>
<td>{{getUptime(probeHost.probe)}}</td> </ng-template>
<td>{{probeHost.host.ipv4}}</td> <ng-template pTemplate="body" let-probeHost>
<td>{{probeHost.host.os.vendor.name}}</td> <tr [pSelectableRow]="probeHost">
<td>{{probeHost.probe.cidr}}</td> <td>{{probeHost.probe.displayName}}</td>
<td>{{probeHost.probe.targetCount}}</td> <td>{{getUptime(probeHost.probe)}}</td>
<td>{{probeHost.probe.authorizeDate | date: 'dd.MM.yyyy'}}</td> <td>{{probeHost.host.ipv4}}</td>
<td>{{probeHost.probe.authorizeMember.name}}</td> <td>{{probeHost.host.os.vendor.name}}</td>
</tr> <td>{{probeHost.probe.cidr}}</td>
</ng-template> <td>{{probeHost.probe.targetCount}}</td>
</p-table> <td>{{probeHost.probe.authorizeDate | date: 'dd.MM.yyyy'}}</td>
<td>{{probeHost.probe.authorizeMember.name}}</td>
</tr>
</ng-template>
</p-table>
</p-panel>

View File

@ -7,6 +7,7 @@ import { ProbeHost, Probe } from '@overflow/commons-typescript/model/probe';
}) })
export class ProbeListComponent { export class ProbeListComponent {
@Output() select = new EventEmitter<ProbeHost>(); @Output() select = new EventEmitter<ProbeHost>();
@Input() pending;
@Input() probeHosts: ProbeHost[]; @Input() probeHosts: ProbeHost[];
constructor() { constructor() {

View File

@ -1 +1,2 @@
<of-probe-detail [probeHost]="(probeHost$ | async)" (modify)="onModify($event)" (discovery)="onDiscovery($event)"></of-probe-detail> <div *ngIf="error">An error has occurred.</div>
<of-probe-detail [pending]="pending$ |async" [probeHost]="probeHost$ | async" (modify)="onModify($event)" (discovery)="onDiscovery($event)"></of-probe-detail>

View File

@ -3,9 +3,8 @@ import { Observable } from 'rxjs';
import { ProbeHost, Probe } from '@overflow/commons-typescript/model/probe'; import { ProbeHost, Probe } from '@overflow/commons-typescript/model/probe';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
import * as ProbeStore from '../store/entity/probe'; import * as ProbeStore from '../store/entity/probe';
import { ProbeSelector } from '../store'; import { ProbeSelector, ProbeDetailContainerSelector } from '../store';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { RPCClientError } from '@loafer/ng-rpc';
@Component({ @Component({
selector: 'of-probe-detail-container', selector: 'of-probe-detail-container',
@ -16,12 +15,15 @@ export class ProbeDetailContainerComponent implements OnInit {
@Input() probeHostID: number; @Input() probeHostID: number;
@Output() discovery = new EventEmitter<number>(); @Output() discovery = new EventEmitter<number>();
probeHost$: Observable<ProbeHost>; probeHost$: Observable<ProbeHost>;
error$: Observable<RPCClientError>; pending$: Observable<boolean>;
error$: Observable<any>;
constructor( constructor(
private store: Store<ProbeStore.State>, private store: Store<ProbeStore.State>,
private route: ActivatedRoute, private route: ActivatedRoute,
) { ) {
this.pending$ = this.store.pipe(select(ProbeDetailContainerSelector.selectPending));
this.error$ = this.store.pipe(select(ProbeSelector.selectError));
} }
ngOnInit() { ngOnInit() {

View File

@ -1 +1 @@
<of-probe-list (select)="onSelect($event)" [probeHosts]="probeHosts$ | async"></of-probe-list> <of-probe-list [pending]="pending$ | async" (select)="onSelect($event)" [probeHosts]="probeHosts$ | async"></of-probe-list>

View File

@ -3,7 +3,7 @@ import { ProbeHost } from '@overflow/commons-typescript/model/probe';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
import * as ProbeStore from '../store/entity/probe'; import * as ProbeStore from '../store/entity/probe';
import { ProbeSelector } from '../store'; import { ProbeSelector, ProbeListContainerSelector } from '../store';
import { AuthSelector } from '@overflow/member/store'; import { AuthSelector } from '@overflow/member/store';
import { Domain } from '@overflow/commons-typescript/model/domain'; import { Domain } from '@overflow/commons-typescript/model/domain';
@ -14,10 +14,12 @@ import { Domain } from '@overflow/commons-typescript/model/domain';
export class ProbeListContainerComponent implements OnInit { export class ProbeListContainerComponent implements OnInit {
probeHosts$: Observable<ProbeHost[]>; probeHosts$: Observable<ProbeHost[]>;
pending$: Observable<boolean>;
@Output() select = new EventEmitter(); @Output() select = new EventEmitter();
constructor(private store: Store<ProbeStore.State>) { constructor(private store: Store<ProbeStore.State>) {
this.probeHosts$ = store.pipe(select(ProbeSelector.selectAll)); this.probeHosts$ = store.pipe(select(ProbeSelector.selectAll));
this.pending$ = store.pipe(select(ProbeListContainerSelector.selectPending));
} }
ngOnInit() { ngOnInit() {

View File

@ -0,0 +1,2 @@
export * from './probe-detail.reducer';
export * from './probe-detail.state';

View File

@ -0,0 +1,36 @@
import { ActionType, Actions } from '../../entity/probe';
import {
State,
initialState,
} from './probe-detail.state';
import { Probe } from '@overflow/commons-typescript/model/probe';
export function reducer(state = initialState, action: Actions): State {
switch (action.type) {
case ActionType.Read: {
return {
...state,
pending: true,
};
}
case ActionType.ReadSuccess: {
return {
...state,
pending: false,
};
}
case ActionType.ReadFailure: {
return {
...state,
pending: true,
};
}
default: {
return state;
}
}
}

View File

@ -0,0 +1,15 @@
import { Selector, createSelector } from '@ngrx/store';
import { createEntityAdapter, EntityState } from '@loafer/ng-entity';
export interface State {
pending: boolean;
}
export const initialState: State = {
pending: false,
};
export function getSelectors<S>(selector: Selector<any, State>) {
return {
selectPending: createSelector(selector, (state: State) => state.pending),
};
}

View File

@ -64,7 +64,7 @@ export class Effects {
return new ReadSuccess(probeHost); return new ReadSuccess(probeHost);
}) })
.catch((error: RPCClientError) => { .catch((error: RPCClientError) => {
return of(new ReadAllByDomainIDFailure(error)); return of(new ReadFailure(error));
}); });
@Effect() @Effect()

View File

@ -10,15 +10,18 @@ import { MODULE } from '../probe.constant';
import * as ProbeEntityStore from './entity/probe'; import * as ProbeEntityStore from './entity/probe';
import * as ProbeListContainerStore from './container/probe-list'; import * as ProbeListContainerStore from './container/probe-list';
import * as ProbeDetailContainerStore from './container/probe-detail';
export interface State { export interface State {
probes: ProbeEntityStore.State; probes: ProbeEntityStore.State;
probe_list_container: ProbeListContainerStore.State; probe_list_container: ProbeListContainerStore.State;
probe_detail_container: ProbeDetailContainerStore.State;
} }
export const REDUCERS = { export const REDUCERS = {
probes: ProbeEntityStore.reducer, probes: ProbeEntityStore.reducer,
probe_list_container: ProbeListContainerStore.reducer, probe_list_container: ProbeListContainerStore.reducer,
probe_detail_container: ProbeDetailContainerStore.reducer
}; };
export const EFFECTS = [ export const EFFECTS = [
@ -36,3 +39,8 @@ export const ProbeListContainerSelector = ProbeListContainerStore.getSelectors(c
selectState, selectState,
(state: State) => state.probe_list_container (state: State) => state.probe_list_container
)); ));
export const ProbeDetailContainerSelector = ProbeDetailContainerStore.getSelectors(createSelector(
selectState,
(state: State) => state.probe_detail_container
));

View File

@ -20,7 +20,8 @@
<div class="layout-main"> <div class="layout-main">
<of-breadcrumb></of-breadcrumb> <of-breadcrumb></of-breadcrumb>
<div class="layout-content" [@routerAnim]="getRouterOutletState(o)"> <!-- <div class="layout-content" [@routerAnim]="getRouterOutletState(o)"> -->
<div class="layout-content">
<router-outlet #o="outlet"></router-outlet> <router-outlet #o="outlet"></router-outlet>
</div> </div>

View File

@ -15,7 +15,7 @@ enum MenuOrientation {
selector: 'of-pages', selector: 'of-pages',
templateUrl: './pages.component.html', templateUrl: './pages.component.html',
styleUrls: ['./pages.component.scss'], styleUrls: ['./pages.component.scss'],
animations: [ slide ], // animations: [ fade ],
}) })
export class PagesComponent implements AfterViewInit, OnDestroy, OnInit { export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
layoutCompact = true; layoutCompact = true;

View File

@ -11,8 +11,8 @@ import { BreadcrumbService } from '@app/commons/service/breadcrumb.service';
}) })
export class ProbePageComponent { export class ProbePageComponent {
private isDetail: boolean; isDetail: boolean;
private probeHostID: string; probeHostID: string;
constructor( constructor(
private router: Router, private router: Router,

View File

@ -404,4 +404,14 @@ body .ui-progressbar .ui-progressbar-value {
} }
.footer { .footer {
height: 50px; height: 50px;
}
.block-icon {
position: absolute;
top: 40%;
left: 45%;
font-size: 50px;
color: #ffffff !important;
}
.ui-panel {
border: none !important;
} }