ing
This commit is contained in:
parent
1be35047cf
commit
a8422cad14
|
@ -98,7 +98,7 @@ export class PopupPanelComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
onOverlayAnimationDone(event: AnimationEvent) {
|
||||
console.log('onOverlayAnimationDone');
|
||||
|
||||
}
|
||||
|
||||
appendOverlay() {
|
||||
|
|
|
@ -30,10 +30,6 @@ export class AutoHeightDirective implements OnInit, OnDestroy, AfterViewInit {
|
|||
ngOnDestroy(): void {
|
||||
}
|
||||
|
||||
onVisible(event) {
|
||||
console.log('visibilitychange');
|
||||
}
|
||||
|
||||
/**
|
||||
* forceCalculate
|
||||
*/
|
||||
|
@ -51,7 +47,6 @@ export class AutoHeightDirective implements OnInit, OnDestroy, AfterViewInit {
|
|||
const footerElementMargin = this.getfooterElementMargin();
|
||||
|
||||
this.elementRef.nativeElement.style.height = windowHeight - footerElementMargin - elementOffsetTop + 'px';
|
||||
console.log([windowHeight, elementOffsetTop, elementMarginBottom, footerElementMargin, this.elementRef.nativeElement.style.height]);
|
||||
}
|
||||
|
||||
private getElementOffsetTop() {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
export * from './discovery';
|
||||
|
||||
export * from './DiscoverHost';
|
||||
export * from './DiscoverPort';
|
||||
export * from './DiscoverService';
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { PagesComponent } from './pages/pages.component';
|
||||
import { HomePageComponent } from './pages/home/home-page.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', loadChildren: './pages/pages.module#PagesModule' },
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
{
|
||||
path: '',
|
||||
component: PagesComponent,
|
||||
children: [
|
||||
{ path: 'home', component: HomePageComponent },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
imports: [RouterModule.forRoot(routes, { useHash: true })],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
|
|
|
@ -8,14 +8,14 @@ import { EffectsModule } from '@ngrx/effects';
|
|||
|
||||
|
||||
import { environment } from '../environments/environment';
|
||||
import { reducers, metaReducers, effects } from '../commons/store';
|
||||
import { REDUCERS, META_REDUCERS, EFFECTS } from './store';
|
||||
|
||||
@NgModule({
|
||||
exports: [
|
||||
StoreModule,
|
||||
],
|
||||
imports: [
|
||||
StoreModule.forRoot(reducers, { metaReducers }),
|
||||
StoreModule.forRoot(REDUCERS, { metaReducers: META_REDUCERS }),
|
||||
/**
|
||||
* @ngrx/router-store keeps router state up-to-date in the store.
|
||||
*/
|
||||
|
@ -41,7 +41,7 @@ import { reducers, metaReducers, effects } from '../commons/store';
|
|||
maxAge: 50,
|
||||
logOnly: environment.production,
|
||||
}),
|
||||
EffectsModule.forRoot(effects),
|
||||
EffectsModule.forRoot(EFFECTS),
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef, AfterContentInit, AfterViewInit } from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { of, Subscription } from 'rxjs';
|
||||
import { map, catchError, take } from 'rxjs/operators';
|
||||
|
||||
import { ElectronProxyService } from '../commons/service/electron-proxy.service';
|
||||
import { ProbeService } from '../commons/service/probe.service';
|
||||
import { ElectronProxyService } from './service/electron-proxy.service';
|
||||
import { MenuEvent } from '../commons/type';
|
||||
import * as AppStore from './store/app';
|
||||
import * as UserStore from './store/environment/user';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit, OnDestroy {
|
||||
export class AppComponent implements OnInit, AfterContentInit, AfterViewInit, OnDestroy {
|
||||
title = 'scanner-app';
|
||||
showTitleBar: boolean;
|
||||
block: boolean;
|
||||
|
@ -25,6 +28,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
|
||||
public constructor(
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
private store: Store<any>,
|
||||
private electronProxyService: ElectronProxyService,
|
||||
) {
|
||||
// this.showTitleBar = !__LINUX__;
|
||||
|
@ -33,6 +37,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.dispatch(new AppStore.AppInit());
|
||||
this.store.dispatch(new UserStore.SetMemberID({ memberID: 'scannerUser' }));
|
||||
// this.probeService.connect();
|
||||
this.electronProxyService.sendReady(performance.now());
|
||||
this.menuSubscription = this.electronProxyService.menuObservable()
|
||||
|
@ -64,7 +70,19 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
this.store.dispatch(new AppStore.AppAfterContentInit());
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.store.dispatch(new AppStore.AppAfterViewInit());
|
||||
}
|
||||
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.store.dispatch(new AppStore.AppDestroy());
|
||||
|
||||
this.menuSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,30 +4,50 @@ import { NgModule } from '@angular/core';
|
|||
|
||||
import { CommonsUIModule } from '@overflow/commons/ui/commons-ui.module';
|
||||
|
||||
import {
|
||||
PerfectScrollbarModule,
|
||||
PERFECT_SCROLLBAR_CONFIG,
|
||||
PerfectScrollbarConfigInterface,
|
||||
} from 'ngx-perfect-scrollbar';
|
||||
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppStoreModule } from './app-store.module';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { COMPONENTS } from './component';
|
||||
import { PAGES } from './pages';
|
||||
|
||||
import { SERVICES } from './service';
|
||||
|
||||
const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
|
||||
suppressScrollX: true
|
||||
};
|
||||
|
||||
import { CommonsModule } from '../commons/commons.module';
|
||||
import { SERVICES } from '../commons/service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
|
||||
PerfectScrollbarModule,
|
||||
|
||||
CommonsUIModule,
|
||||
CommonsModule,
|
||||
|
||||
AppRoutingModule,
|
||||
AppStoreModule,
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
...COMPONENTS,
|
||||
...PAGES,
|
||||
],
|
||||
providers: [
|
||||
...SERVICES,
|
||||
{
|
||||
provide: PERFECT_SCROLLBAR_CONFIG,
|
||||
useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG
|
||||
}
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
18
src/app/component/index.ts
Normal file
18
src/app/component/index.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import {
|
||||
COMPONENTS as LAYOUT_COMPONENTS
|
||||
} from './layout';
|
||||
|
||||
import {
|
||||
COMPONENTS as MENU_COMPONENTS
|
||||
} from './menu';
|
||||
|
||||
import {
|
||||
COMPONENTS as TARGET_COMPONENTS
|
||||
} from './target';
|
||||
|
||||
|
||||
export const COMPONENTS = [
|
||||
...LAYOUT_COMPONENTS,
|
||||
...MENU_COMPONENTS,
|
||||
...TARGET_COMPONENTS,
|
||||
];
|
8
src/app/component/layout/index.ts
Normal file
8
src/app/component/layout/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import {
|
||||
COMPONENTS as TOOLBAR_COMPONENTS
|
||||
} from './toolbar';
|
||||
|
||||
|
||||
export const COMPONENTS = [
|
||||
...TOOLBAR_COMPONENTS,
|
||||
];
|
7
src/app/component/layout/toolbar/index.ts
Normal file
7
src/app/component/layout/toolbar/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { NicDropdownComponent } from './nic-dropdown.component';
|
||||
import { ScannerSettingDropdownComponent } from './scanner-setting-dropdown.component';
|
||||
|
||||
export const COMPONENTS = [
|
||||
NicDropdownComponent,
|
||||
ScannerSettingDropdownComponent,
|
||||
];
|
|
@ -4,11 +4,11 @@
|
|||
<!-- <svg _ngcontent-c1="" aria-hidden="true" class="octicon icon" version="1.1" viewBox="0 0 10 16" width="16px" height="16px">
|
||||
<path _ngcontent-c1="" d="M8 1a1.993 1.993 0 0 0-1 3.72V6L5 8 3 6V4.72A1.993 1.993 0 0 0 2 1a1.993 1.993 0 0 0-1 3.72V6.5l3 3v1.78A1.993 1.993 0 0 0 5 15a1.993 1.993 0 0 0 1-3.72V9.5l3-3V4.72A1.993 1.993 0 0 0 8 1zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3 10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3-10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path>
|
||||
</svg> -->
|
||||
<div _ngcontent-c1="" class="text" *ngIf="selected else loading">
|
||||
<div _ngcontent-c1="" class="text" *ngIf="selected">
|
||||
<div _ngcontent-c1="" class="description">{{selected.network || ''}}</div>
|
||||
<div _ngcontent-c1="" class="title">{{selected.friendlyName || ''}}</div>
|
||||
</div>
|
||||
<ng-template #loading>
|
||||
<ng-template *ngIf="pending$ | async">
|
||||
Loading...
|
||||
</ng-template>
|
||||
<svg _ngcontent-c1="" aria-hidden="true" class="octicon dropdownArrow" version="1.1" viewBox="0 0 12 16" width="16px"
|
136
src/app/component/layout/toolbar/nic-dropdown.component.ts
Normal file
136
src/app/component/layout/toolbar/nic-dropdown.component.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
OnDestroy,
|
||||
ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { Observable, of, Subscription } from 'rxjs';
|
||||
import { catchError, map, tap, exhaustMap } from 'rxjs/operators';
|
||||
|
||||
import { SelectItem } from 'primeng/primeng';
|
||||
|
||||
import { Interface } from '@overflow/model/net/nic';
|
||||
import { Zone } from '@overflow/model/discovery';
|
||||
import { toMetaIPType, MetaIPType, MetaIPTypeEnum } from '@overflow/model/meta';
|
||||
import { DropdownPanelComponent } from '@overflow/commons/ui/component/primeng';
|
||||
|
||||
import * as AppStore from '../../../store';
|
||||
import * as DiscoveryConfigStore from '../../../store/discovery/config';
|
||||
|
||||
class NICInfo {
|
||||
iface: string;
|
||||
friendlyName: string;
|
||||
metaIPType: MetaIPType;
|
||||
mac: string;
|
||||
address: string;
|
||||
network: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-toolbar-nic-dropdown',
|
||||
templateUrl: './nic-dropdown.component.html',
|
||||
styleUrls: ['./nic-dropdown.component.scss']
|
||||
})
|
||||
export class NicDropdownComponent implements OnInit, OnDestroy {
|
||||
|
||||
@Input()
|
||||
blockTarget: any;
|
||||
|
||||
@ViewChild('panel')
|
||||
panel: DropdownPanelComponent;
|
||||
|
||||
pending$: Observable<boolean>;
|
||||
error$: Observable<any>;
|
||||
|
||||
interfacesSubscription: Subscription | null;
|
||||
|
||||
nics: SelectItem[] | null;
|
||||
selected: NICInfo;
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
const __this = this;
|
||||
this.interfacesSubscription = this.store.pipe(
|
||||
tap(() => {
|
||||
__this.pending$ = of(true);
|
||||
}),
|
||||
select(AppStore.EnvironmentSelector.InterfacesSelector.selectInterfaces),
|
||||
map((ifaces: Interface[]) => {
|
||||
if (null === ifaces) {
|
||||
return;
|
||||
}
|
||||
__this.nics = [];
|
||||
ifaces.forEach(iface => {
|
||||
if (undefined === iface.addresses) {
|
||||
return;
|
||||
}
|
||||
iface.addresses.forEach(address => {
|
||||
if (
|
||||
address.metaIPType.key !== toMetaIPType(MetaIPTypeEnum.V4).key
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const nicInfo = {
|
||||
iface: iface.iface,
|
||||
friendlyName: iface.friendlyName,
|
||||
metaIPType: address.metaIPType,
|
||||
mac: iface.mac,
|
||||
address: address.address,
|
||||
network: address.network
|
||||
};
|
||||
__this.nics.push({
|
||||
label: iface.friendlyName + ' (' + address.network + ')',
|
||||
value: nicInfo,
|
||||
disabled:
|
||||
address.metaIPType.key !== toMetaIPType(MetaIPTypeEnum.V4).key
|
||||
? true
|
||||
: false
|
||||
});
|
||||
if (address.gateway !== undefined && address.gateway.length > 0) {
|
||||
__this.nicSelected(nicInfo);
|
||||
}
|
||||
});
|
||||
});
|
||||
this.changeDetector.detectChanges();
|
||||
}),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
return of();
|
||||
}),
|
||||
tap(() => {
|
||||
__this.pending$ = of(false);
|
||||
}),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (null !== this.interfacesSubscription) {
|
||||
this.interfacesSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
nicSelected(nic: NICInfo) {
|
||||
this.selected = nic;
|
||||
|
||||
const zone: Zone = {
|
||||
network: this.selected.network,
|
||||
iface: this.selected.iface,
|
||||
metaIPType: toMetaIPType(MetaIPTypeEnum.V4),
|
||||
address: this.selected.address,
|
||||
mac: this.selected.mac
|
||||
};
|
||||
|
||||
this.store.dispatch(new DiscoveryConfigStore.ChangeZone(zone));
|
||||
|
||||
this.panel.hide();
|
||||
}
|
||||
}
|
|
@ -1,21 +1,27 @@
|
|||
import { Component, Input, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
|
||||
import { Component, Input, OnInit, ViewChild, Output, EventEmitter, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
|
||||
import { Observable, of, Subscription } from 'rxjs';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { DropdownPanelComponent } from '@overflow/commons/ui/component/primeng';
|
||||
import { DiscoverHost, Zone } from '@overflow/model/discovery';
|
||||
import { toMetaIPType, MetaIPTypeEnum, MetaPortTypeEnum } from '@overflow/model/meta';
|
||||
import { DiscoveryConfigService } from '../../service/discovery-config.service';
|
||||
|
||||
import * as AppStore from '../../../store';
|
||||
import * as DiscoveryConfigStore from '../../../store/discovery/config';
|
||||
|
||||
const IPCIDR = require('ip-cidr');
|
||||
|
||||
@Component({
|
||||
selector: 'app-scanner-setting-dropdown',
|
||||
selector: 'app-layout-toolbar-scanner-setting-dropdown',
|
||||
templateUrl: './scanner-setting-dropdown.component.html',
|
||||
styleUrls: ['./scanner-setting-dropdown.component.scss'],
|
||||
})
|
||||
|
||||
export class ScannerSettingDropdownComponent implements OnInit {
|
||||
export class ScannerSettingDropdownComponent implements OnInit, OnDestroy {
|
||||
|
||||
@Input() blockTarget: any;
|
||||
@Output() ready = new EventEmitter<DiscoverHost>();
|
||||
@ViewChild('panel') panel: DropdownPanelComponent;
|
||||
|
||||
valid: boolean;
|
||||
|
@ -35,17 +41,36 @@ export class ScannerSettingDropdownComponent implements OnInit {
|
|||
|
||||
validIPArray: string[];
|
||||
|
||||
zoneSubscription: Subscription | null;
|
||||
|
||||
constructor(
|
||||
private discoveryConfigService: DiscoveryConfigService
|
||||
private store: Store<any>,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.discoveryConfigService.zone.subscribe(res => {
|
||||
this.zone = res as Zone;
|
||||
this.setDefault();
|
||||
});
|
||||
this.zoneSubscription = this.store.pipe(
|
||||
select(AppStore.DiscoverySelector.ConfigSelector.selectZone),
|
||||
map((zone: Zone) => {
|
||||
if (null === zone) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.zone = zone;
|
||||
this.setDefault();
|
||||
}),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
return of();
|
||||
}),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (null !== this.zoneSubscription) {
|
||||
this.zoneSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
setDefault(): void {
|
||||
|
@ -66,6 +91,8 @@ export class ScannerSettingDropdownComponent implements OnInit {
|
|||
this.portErrMsg = '';
|
||||
|
||||
this.setSummary();
|
||||
|
||||
this.changeDetector.detectChanges();
|
||||
}
|
||||
|
||||
validateIP(value: string, idx: number) {
|
||||
|
@ -212,9 +239,9 @@ export class ScannerSettingDropdownComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
};
|
||||
this.ready.emit(discoverHost);
|
||||
}
|
||||
|
||||
this.store.dispatch(new DiscoveryConfigStore.ChangeDiscoverHost(discoverHost));
|
||||
}
|
||||
}
|
||||
|
||||
class Condition {
|
11
src/app/component/menu/index.ts
Normal file
11
src/app/component/menu/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { AboutComponent } from './about.component';
|
||||
import { ExportCSVComponent } from './export-csv.component';
|
||||
import { PreferencesComponent } from './preferences.component';
|
||||
import { PrintComponent } from './print.component';
|
||||
|
||||
export const COMPONENTS = [
|
||||
AboutComponent,
|
||||
ExportCSVComponent,
|
||||
PreferencesComponent,
|
||||
PrintComponent,
|
||||
];
|
|
@ -6,16 +6,16 @@ import { map, catchError, take } from 'rxjs/operators';
|
|||
import { Host } from '@overflow/model/discovery';
|
||||
import { PingResult } from '@overflow/model/ping';
|
||||
|
||||
import { ProbeService } from '../../service/probe.service';
|
||||
import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.directive';
|
||||
|
||||
import { PingService } from '../../../service/ping.service';
|
||||
import { PingOption } from '@overflow/model/config/ping';
|
||||
|
||||
@Component({
|
||||
selector: 'app-host-detail',
|
||||
templateUrl: './host-detail.component.html',
|
||||
styleUrls: ['./host-detail.component.scss'],
|
||||
selector: 'app-target-detail-host',
|
||||
templateUrl: './host.component.html',
|
||||
styleUrls: ['./host.component.scss'],
|
||||
})
|
||||
export class HostDetailComponent implements OnChanges {
|
||||
export class HostComponent implements OnChanges {
|
||||
@Input() host: Host;
|
||||
|
||||
@ViewChildren(AutoHeightDirective) autoHeightDirectives: QueryList<AutoHeightDirective>;
|
||||
|
@ -32,7 +32,7 @@ export class HostDetailComponent implements OnChanges {
|
|||
|
||||
|
||||
constructor(
|
||||
private probeService: ProbeService,
|
||||
private pingService: PingService,
|
||||
) {
|
||||
this.pingWaiting = false;
|
||||
this.count = 5;
|
||||
|
@ -48,14 +48,13 @@ export class HostDetailComponent implements OnChanges {
|
|||
doPing() {
|
||||
this.pingWaiting = true;
|
||||
|
||||
const option = {
|
||||
Count: this.count,
|
||||
Interval: this.interval,
|
||||
Deadline: this.deadline,
|
||||
const option: PingOption = {
|
||||
count: this.count,
|
||||
interval: this.interval,
|
||||
deadline: this.deadline,
|
||||
};
|
||||
|
||||
this.probeService
|
||||
.call<PingResult>('PingService.PingHost', this.host, option)
|
||||
this.pingService.pingHost(this.host, option)
|
||||
.pipe(
|
||||
map((pingResult: PingResult) => {
|
||||
if (pingResult) {
|
11
src/app/component/target/detail/index.ts
Normal file
11
src/app/component/target/detail/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { HostComponent } from './host.component';
|
||||
import { NodeComponent } from './node.component';
|
||||
import { ServiceComponent } from './service.component';
|
||||
import { ZoneComponent } from './zone.component';
|
||||
|
||||
export const COMPONENTS = [
|
||||
NodeComponent,
|
||||
ZoneComponent,
|
||||
HostComponent,
|
||||
ServiceComponent,
|
||||
];
|
26
src/app/component/target/detail/node.component.html
Normal file
26
src/app/component/target/detail/node.component.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<div class="ui-g">
|
||||
|
||||
<div class="ui-g-12">
|
||||
|
||||
|
||||
<ng-container [ngSwitch]="selectedTarget.group">
|
||||
|
||||
<ng-container *ngSwitchCase="'zone'">
|
||||
<app-target-detail-zone [zone]="selectedTarget.target" (otherHostSelect)="otherHostSelected($event)"></app-target-detail-zone>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'host'">
|
||||
<app-target-detail-host [host]="selectedTarget.target" (ping)="ping.emit($event)"></app-target-detail-host>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'service'">
|
||||
<app-target-detail-service [service]="selectedTarget.target" (ping)="ping.emit($event)"></app-target-detail-service>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchDefault>
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
</div>
|
26
src/app/component/target/detail/node.component.ts
Normal file
26
src/app/component/target/detail/node.component.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { PingResult } from '@overflow/model/ping';
|
||||
import { Host, Port, Service } from '@overflow/model/discovery';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-target-detail-node',
|
||||
templateUrl: './node.component.html',
|
||||
styleUrls: ['./node.component.scss'],
|
||||
})
|
||||
export class NodeComponent {
|
||||
|
||||
@Input() selectedTarget: { group: string, target: Host | Port | Service } | null;
|
||||
@Output() otherHostSelect = new EventEmitter<Host>();
|
||||
@Output() ping = new EventEmitter<PingResult>();
|
||||
|
||||
constructor(
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
otherHostSelected(host: Host) {
|
||||
this.otherHostSelect.emit(host);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,21 @@
|
|||
import { Component, Input, OnChanges, SimpleChanges, ViewChildren, QueryList } from '@angular/core';
|
||||
import { Service } from '@overflow/model/discovery';
|
||||
import { PingResult } from '@overflow/model/ping';
|
||||
import { ProbeService } from '../../service/probe.service';
|
||||
import { map, catchError, take } from 'rxjs/operators';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { map, catchError, take } from 'rxjs/operators';
|
||||
|
||||
import { Service } from '@overflow/model/discovery';
|
||||
import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.directive';
|
||||
import { PingResult } from '@overflow/model/ping';
|
||||
|
||||
import { PingService } from '../../../service/ping.service';
|
||||
import { PingOption } from '@overflow/model/config/ping';
|
||||
|
||||
@Component({
|
||||
selector: 'app-service-detail',
|
||||
templateUrl: './service-detail.component.html',
|
||||
styleUrls: ['./service-detail.component.scss'],
|
||||
selector: 'app-target-detail-service',
|
||||
templateUrl: './service.component.html',
|
||||
styleUrls: ['./service.component.scss'],
|
||||
})
|
||||
export class ServiceDetailComponent implements OnChanges {
|
||||
export class ServiceComponent implements OnChanges {
|
||||
|
||||
@Input() service: Service;
|
||||
|
||||
|
@ -28,7 +32,7 @@ export class ServiceDetailComponent implements OnChanges {
|
|||
|
||||
|
||||
constructor(
|
||||
private probeService: ProbeService
|
||||
private pingService: PingService
|
||||
) {
|
||||
this.pingWaiting = false;
|
||||
this.count = 5;
|
||||
|
@ -44,14 +48,13 @@ export class ServiceDetailComponent implements OnChanges {
|
|||
doPing() {
|
||||
this.pingWaiting = true;
|
||||
|
||||
const option = {
|
||||
Count: this.count,
|
||||
Interval: this.interval,
|
||||
Deadline: this.deadline,
|
||||
const option: PingOption = {
|
||||
count: this.count,
|
||||
interval: this.interval,
|
||||
deadline: this.deadline,
|
||||
};
|
||||
|
||||
this.probeService
|
||||
.call<PingResult>('PingService.PingService', this.service, option)
|
||||
this.pingService.pingService(this.service, option)
|
||||
.pipe(
|
||||
map((pingResult: PingResult) => {
|
||||
console.log(pingResult);
|
|
@ -5,11 +5,11 @@ import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.
|
|||
const IPCIDR = require('ip-cidr');
|
||||
|
||||
@Component({
|
||||
selector: 'app-zone-detail',
|
||||
templateUrl: './zone-detail.component.html',
|
||||
styleUrls: ['./zone-detail.component.scss'],
|
||||
selector: 'app-target-detail-zone',
|
||||
templateUrl: './zone.component.html',
|
||||
styleUrls: ['./zone.component.scss'],
|
||||
})
|
||||
export class ZoneDetailComponent implements OnInit {
|
||||
export class ZoneComponent implements OnInit {
|
||||
|
||||
@Input() zone: Zone;
|
||||
@Output() otherHostSelect = new EventEmitter<Host>();
|
18
src/app/component/target/display/display.component.html
Normal file
18
src/app/component/target/display/display.component.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div>
|
||||
<ng-container [ngSwitch]="(targetDisplayType$ | async)">
|
||||
<app-target-display-map *ngSwitchCase="'MAP'"></app-target-display-map>
|
||||
<app-target-display-grid *ngSwitchCase="'GRID'"></app-target-display-grid>
|
||||
<app-target-display-tree *ngSwitchCase="'TREE'"></app-target-display-tree>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<div #detailSidebar style="position: inherit; top: 0; left: 0; height: 100%;"></div>
|
||||
|
||||
<p-sidebar [(visible)]="displaySidebar" [modal]="false" [appendTo]="detailSidebar" styleClass="ui-sidebar-md"
|
||||
position="right" (onHide)="onHideDetail()" [style]="{position:'absolute'}">
|
||||
<div *ngIf="selectedTarget">
|
||||
<app-target-detail-node [selectedTarget]="selectedTarget" (otherHostSelect)="otherHostSelected($event)"></app-target-detail-node>
|
||||
</div>
|
||||
</p-sidebar>
|
||||
|
||||
</div>
|
21
src/app/component/target/display/display.component.scss
Normal file
21
src/app/component/target/display/display.component.scss
Normal file
|
@ -0,0 +1,21 @@
|
|||
/deep/ .target-display {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
margin: -0.6em -0.9em -0.7em -0.9em; //-0.5em -0.75em;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 400px; //text-align: center;
|
||||
}
|
||||
|
||||
.detail-sidebar {
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/deep/ .ui-panel .ui-panel-content {
|
||||
padding: .6em .75em;
|
||||
}
|
74
src/app/component/target/display/display.component.ts
Normal file
74
src/app/component/target/display/display.component.ts
Normal file
|
@ -0,0 +1,74 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
AfterContentInit,
|
||||
ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { map, catchError, take, tap } from 'rxjs/operators';
|
||||
|
||||
import { Port, Service, Host } from '@overflow/model/discovery';
|
||||
|
||||
import { TargetDisplayType } from '../../../core/type';
|
||||
import * as AppStore from '../../../store';
|
||||
import * as TargetStore from '../../../store/target/target';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-target-display',
|
||||
templateUrl: './display.component.html',
|
||||
styleUrls: ['./display.component.scss']
|
||||
})
|
||||
export class DisplayComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
private targetDisplayType$: Observable<TargetDisplayType>;
|
||||
|
||||
displaySidebar = false;
|
||||
selectedTargetSubscription: Subscription | null;
|
||||
selectedTarget: { group: string, target: Host | Port | Service } | null;
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
const __this = this;
|
||||
|
||||
this.targetDisplayType$ = this.store.pipe(select(AppStore.TargetSelector.TargetSelector.selectTargetDisplayType));
|
||||
|
||||
this.selectedTargetSubscription = this.store.pipe(
|
||||
select(AppStore.TargetSelector.TargetSelector.selectSelectedTarget)
|
||||
).pipe(
|
||||
map((_selectedTarget) => {
|
||||
if (null === _selectedTarget) {
|
||||
__this.displaySidebar = false;
|
||||
__this.selectedTarget = null;
|
||||
} else {
|
||||
__this.displaySidebar = true;
|
||||
__this.selectedTarget = _selectedTarget;
|
||||
}
|
||||
__this.changeDetector.detectChanges();
|
||||
}),
|
||||
).subscribe();
|
||||
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (null !== this.selectedTargetSubscription) {
|
||||
this.selectedTargetSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
onHideDetail() {
|
||||
this.store.dispatch(new TargetStore.ChangeSelectedTarget(null));
|
||||
}
|
||||
|
||||
}
|
3
src/app/component/target/display/grid.component.html
Normal file
3
src/app/component/target/display/grid.component.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
Grid
|
||||
</div>
|
31
src/app/component/target/display/grid.component.ts
Normal file
31
src/app/component/target/display/grid.component.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
AfterContentInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@Component({
|
||||
selector: 'app-target-display-grid',
|
||||
templateUrl: './grid.component.html',
|
||||
styleUrls: ['./grid.component.scss']
|
||||
})
|
||||
export class GridComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
}
|
||||
|
||||
}
|
11
src/app/component/target/display/index.ts
Normal file
11
src/app/component/target/display/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { DisplayComponent } from './display.component';
|
||||
import { GridComponent } from './grid.component';
|
||||
import { MapComponent } from './map.component';
|
||||
import { TreeComponent } from './tree.component';
|
||||
|
||||
export const COMPONENTS = [
|
||||
DisplayComponent,
|
||||
GridComponent,
|
||||
MapComponent,
|
||||
TreeComponent,
|
||||
];
|
|
@ -1,5 +1,5 @@
|
|||
<div>
|
||||
<svg #discoveryTarget width="100%" height="100%">
|
||||
<div class="target-display">
|
||||
<svg #displayTarget width="100%" height="100%">
|
||||
<g>
|
||||
<g *ngFor="let link of links">
|
||||
<g class="link-container" [ngClass]="'link-'+link.target.group" [attr.sourceId]="link.source.id"
|
||||
|
@ -51,15 +51,18 @@
|
|||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<p-card class="ui-map-info" *ngIf="discoveryResult">
|
||||
<p-card class="ui-map-info" *ngIf="displaySummary">
|
||||
<div class="ui-map-info-row ui-border-bottom">
|
||||
<div>Total Hosts: </div>{{discoveryResult.totalHosts}}
|
||||
<div>Total Hosts: </div>{{displaySummary.totalHosts}}
|
||||
</div>
|
||||
<div class="ui-map-info-row ui-border-bottom">
|
||||
<div>Total Services: </div>{{discoveryResult.totalServices}}
|
||||
<div>Total Ports: </div>{{displaySummary.totalPorts}}
|
||||
</div>
|
||||
<div class="ui-map-info-row ui-border-bottom">
|
||||
<div>Total Services: </div>{{displaySummary.totalServices}}
|
||||
</div>
|
||||
<div class="ui-map-info-row">
|
||||
<div>Elapsed: </div>{{discoveryResult.elapsedTime}}
|
||||
<div>Elapsed: </div>{{displaySummary.elapsedTime}}
|
||||
</div>
|
||||
</p-card>
|
||||
</div>
|
83
src/app/component/target/display/map.component.scss
Normal file
83
src/app/component/target/display/map.component.scss
Normal file
|
@ -0,0 +1,83 @@
|
|||
.link {
|
||||
stroke: #999;
|
||||
stroke-opacity: 0.6;
|
||||
}
|
||||
|
||||
.textClass {
|
||||
stroke: #323232;
|
||||
font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
|
||||
font-weight: normal;
|
||||
stroke-width: .5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.linkTextClass {
|
||||
stroke: #b6b4b4;
|
||||
font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
|
||||
font-weight: normal;
|
||||
stroke-width: .3;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.focused {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.semi-focused {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
|
||||
.semi-unfocused {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.unfocused {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.semi-unselected {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.unselected {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.ui-map-info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
.ui-map-info-row {
|
||||
//display: inline;
|
||||
font-size: 0.8em;
|
||||
line-height: 2em;
|
||||
width: 120px;
|
||||
font-weight: bold;
|
||||
user-select: text;
|
||||
div {
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
padding-left: 5px;
|
||||
width: 75px;
|
||||
user-select: text;
|
||||
}
|
||||
}
|
||||
.ui-border-bottom {
|
||||
border-bottom: 1px solid #d6d6d6;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ui-card-body {
|
||||
padding: 0.5em;
|
||||
border: 1px solid #d6d6d6;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
// /deep/ .ui-blockui {
|
||||
// opacity: 0.1;
|
||||
// }
|
||||
/deep/ .ui-widget-overlay {
|
||||
background-color: #666666;
|
||||
opacity: .20;
|
||||
filter: Alpha(Opacity=50);
|
||||
}
|
820
src/app/component/target/display/map.component.ts
Normal file
820
src/app/component/target/display/map.component.ts
Normal file
|
@ -0,0 +1,820 @@
|
|||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
EventEmitter,
|
||||
Output,
|
||||
ViewChild,
|
||||
OnDestroy,
|
||||
ElementRef,
|
||||
AfterContentInit,
|
||||
ChangeDetectorRef,
|
||||
HostListener
|
||||
} from '@angular/core';
|
||||
|
||||
import { Observable, of, Subscription, combineLatest } from 'rxjs';
|
||||
import { catchError, map, tap, exhaustMap, take, filter } from 'rxjs/operators';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import * as d3 from 'd3';
|
||||
|
||||
import { Zone, Host, Service, Port } from '@overflow/model/discovery';
|
||||
import { Link } from '../../../core/model/link';
|
||||
import { Node } from '../../../core/model/node';
|
||||
|
||||
import * as AppStore from '../../../store';
|
||||
import * as DiscoveryConfigStore from '../../../store/discovery/config';
|
||||
import * as TargetStore from '../../../store/target/target';
|
||||
import * as UILayoutStore from '../../../store/ui/layout';
|
||||
import { DiscoverySession } from '../../../core/discovery/discovery-session';
|
||||
import { DiscoveryMessageType } from 'src/app/core/type';
|
||||
|
||||
export class DisplaySummary {
|
||||
totalHosts: number;
|
||||
totalPorts: number;
|
||||
totalServices: number;
|
||||
elapsedTime: string;
|
||||
|
||||
startDate: Date;
|
||||
|
||||
hTimer: any;
|
||||
|
||||
constructor() {
|
||||
this.totalHosts = 0;
|
||||
this.totalPorts = 0;
|
||||
this.totalServices = 0;
|
||||
this.elapsedTime = '00:00:00';
|
||||
}
|
||||
|
||||
start(startDate: Date) {
|
||||
this.startDate = startDate;
|
||||
const __this = this;
|
||||
const _startDate = new Date();
|
||||
this.hTimer = setInterval(function () {
|
||||
// Get todays date and time
|
||||
const now = new Date().getTime();
|
||||
__this.setElapsedTime(_startDate, new Date());
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
setElapsedTime(startDate: Date, now: Date) {
|
||||
const distance = now.getTime() - startDate.getTime();
|
||||
|
||||
// Time calculations for days, hours, minutes and seconds
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
this.elapsedTime = String(hours).padStart(2, '0') + ':' + String(minutes).padStart(2, '0') + ':' + String(seconds).padStart(2, '0');
|
||||
}
|
||||
|
||||
stop(stopDate: Date) {
|
||||
clearInterval(this.hTimer);
|
||||
this.setElapsedTime(this.startDate, stopDate);
|
||||
}
|
||||
|
||||
increaseHost() {
|
||||
this.totalHosts++;
|
||||
}
|
||||
|
||||
increasePort() {
|
||||
this.totalPorts++;
|
||||
}
|
||||
|
||||
increaseService() {
|
||||
this.totalServices++;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-target-display-map',
|
||||
templateUrl: './map.component.html',
|
||||
styleUrls: ['./map.component.scss']
|
||||
})
|
||||
export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
|
||||
zone: Zone | null = null;
|
||||
hosts: Map<string, Host>;
|
||||
ports: Map<string, Map<number, Port>>;
|
||||
services: Map<string, Map<number, Map<string, Service>>>;
|
||||
|
||||
zoneNode: Node | null = null;
|
||||
nodes: Node[];
|
||||
links: Link[];
|
||||
|
||||
selectedNode: Node | null = null;
|
||||
|
||||
@ViewChild('displayTarget') set displayTarget(content: ElementRef) {
|
||||
this.displayTargetRef = content;
|
||||
}
|
||||
|
||||
private displayTargetRef: ElementRef;
|
||||
public simulation: d3.Simulation<Node, Link> | undefined;
|
||||
private zoomBehavior: d3.ZoomBehavior<Element, {}>;
|
||||
private displayTargetWidth: number;
|
||||
private displayTargetHeight: number;
|
||||
private readonly maxScale: number;
|
||||
private readonly minScale: number;
|
||||
|
||||
displaySummary: DisplaySummary | null = null;
|
||||
|
||||
discoverySessionSubscription: Subscription | null = null;
|
||||
refreshTargetDisplaySubscription: Subscription | null = null;
|
||||
targetSubscription: Subscription | null = null;
|
||||
targetObservable: Observable<void>;
|
||||
selectedTargetSubscription: Subscription | null = null;
|
||||
|
||||
discoverySubscription: Subscription | null = null;
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
) {
|
||||
this.maxScale = 1;
|
||||
this.minScale = 0.7;
|
||||
|
||||
const __this = this;
|
||||
this.targetObservable = this.store.pipe(
|
||||
take(1),
|
||||
select((state) => {
|
||||
const zone = AppStore.DiscoverySelector.ConfigSelector.selectZone(state);
|
||||
const hosts = AppStore.TargetSelector.TargetSelector.selectHosts(state);
|
||||
const ports = AppStore.TargetSelector.TargetSelector.selectPorts(state);
|
||||
const services = AppStore.TargetSelector.TargetSelector.selectServices(state);
|
||||
|
||||
__this.initMapDisplay(zone, hosts, ports, services);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event) {
|
||||
if (undefined !== this.displayTargetRef) {
|
||||
this.displayTargetWidth = this.displayTargetRef.nativeElement.clientWidth;
|
||||
this.displayTargetHeight = this.displayTargetRef.nativeElement.clientHeight;
|
||||
|
||||
this.zoneNode.fx = this.displayTargetWidth / 2;
|
||||
this.zoneNode.fy = this.displayTargetHeight / 2;
|
||||
|
||||
this.simulationRestart(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
const __this = this;
|
||||
this.discoverySessionSubscription = this.store.pipe(
|
||||
select(AppStore.DiscoverySelector.RequestSelector.selectDiscoverySession),
|
||||
map((discoverySession: DiscoverySession) => {
|
||||
if (null === discoverySession) {
|
||||
if (null !== __this.discoverySubscription) {
|
||||
__this.discoverySubscription.unsubscribe();
|
||||
__this.discoverySubscription = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
__this.discoverySubscription = discoverySession.discoveryObservable().pipe(
|
||||
map((discoveryMessage: { messageType: DiscoveryMessageType, params: any[] }) => {
|
||||
switch (discoveryMessage.messageType) {
|
||||
case DiscoveryMessageType.Queueing:
|
||||
break;
|
||||
case DiscoveryMessageType.QueueingFailed:
|
||||
break;
|
||||
case DiscoveryMessageType.QueueingTimeout:
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveryStart: {
|
||||
__this.store.dispatch(new UILayoutStore.ChangeBlockPagesContent({ blockPagesContent: true }));
|
||||
__this.initMapDisplay(__this.zone, null, null, null);
|
||||
__this.displaySummary.start(discoveryMessage.params[0]);
|
||||
}
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveryStop: {
|
||||
__this.simulationRestart(true);
|
||||
__this.zoomToFit(0.95, 500);
|
||||
|
||||
__this.displaySummary.stop(discoveryMessage.params[0]);
|
||||
__this.store.dispatch(new UILayoutStore.ChangeBlockPagesContent({ blockPagesContent: false }));
|
||||
}
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveryMode:
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveryError:
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveredHost:
|
||||
|
||||
__this.addHost(discoveryMessage.params[0], true);
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveredPort:
|
||||
__this.addPort(discoveryMessage.params[0], false);
|
||||
break;
|
||||
case DiscoveryMessageType.DiscoveredService:
|
||||
__this.addService(discoveryMessage.params[0], true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}),
|
||||
).subscribe();
|
||||
}),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
return of();
|
||||
}),
|
||||
).subscribe();
|
||||
|
||||
this.refreshTargetDisplaySubscription = this.store.pipe(
|
||||
select(AppStore.TargetSelector.TargetSelector.selectRefreshTargetDisplay),
|
||||
filter(v => !!v),
|
||||
map((refreshTargetDisplay: boolean) => {
|
||||
if (!refreshTargetDisplay) {
|
||||
return;
|
||||
}
|
||||
__this.targetObservable.subscribe();
|
||||
}),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
return of();
|
||||
}),
|
||||
).subscribe();
|
||||
|
||||
this.selectedTargetSubscription = this.store.pipe(
|
||||
select(AppStore.TargetSelector.TargetSelector.selectSelectedTarget)
|
||||
).pipe(
|
||||
map((selectedTarget) => {
|
||||
if (null === selectedTarget) {
|
||||
__this.onHideDetail();
|
||||
return;
|
||||
} else {
|
||||
|
||||
}
|
||||
}),
|
||||
).subscribe();
|
||||
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
this.displayTargetWidth = this.displayTargetRef.nativeElement.clientWidth;
|
||||
this.displayTargetHeight = this.displayTargetRef.nativeElement.clientHeight;
|
||||
|
||||
this.targetObservable.subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (null !== this.targetSubscription) {
|
||||
this.targetSubscription.unsubscribe();
|
||||
}
|
||||
if (null !== this.refreshTargetDisplaySubscription) {
|
||||
this.refreshTargetDisplaySubscription.unsubscribe();
|
||||
}
|
||||
if (null !== this.discoverySessionSubscription) {
|
||||
this.discoverySessionSubscription.unsubscribe();
|
||||
}
|
||||
if (null !== this.selectedTargetSubscription) {
|
||||
this.selectedTargetSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
initMapDisplay(zone: Zone, hosts: Host[], ports: Port[], services: Service[]) {
|
||||
if (null === zone) {
|
||||
return;
|
||||
}
|
||||
this.nodes = [];
|
||||
this.links = [];
|
||||
this.hosts = new Map();
|
||||
this.ports = new Map();
|
||||
this.services = new Map();
|
||||
this.displaySummary = new DisplaySummary();
|
||||
|
||||
this.simulationInit();
|
||||
|
||||
this.setZone(zone);
|
||||
|
||||
if (null !== hosts) {
|
||||
hosts.forEach((host) => {
|
||||
this.addHost(host);
|
||||
});
|
||||
}
|
||||
|
||||
if (null !== ports) {
|
||||
ports.forEach((port) => {
|
||||
this.addPort(port);
|
||||
});
|
||||
}
|
||||
|
||||
if (null !== services) {
|
||||
services.forEach((service) => {
|
||||
this.addService(service);
|
||||
});
|
||||
}
|
||||
|
||||
this.simulationRestart(true);
|
||||
}
|
||||
|
||||
simulationInit() {
|
||||
if (undefined !== this.simulation) {
|
||||
return;
|
||||
}
|
||||
|
||||
const svg = d3.select(this.displayTargetRef.nativeElement);
|
||||
|
||||
this.zoomBehavior = d3.zoom()
|
||||
.scaleExtent([0.2, 4])
|
||||
.on('zoom', () => {
|
||||
const transform = d3.event.transform;
|
||||
svg.select('g').attr('transform', 'translate(' + transform.x + ',' + transform.y + ') scale(' + transform.k + ')');
|
||||
});
|
||||
svg.call(this.zoomBehavior);
|
||||
|
||||
const __this = this;
|
||||
this.simulation = d3
|
||||
.forceSimulation<Node, Link>()
|
||||
.nodes(this.nodes)
|
||||
.force('charge', d3.forceManyBody().strength(-200))
|
||||
.force('link', d3.forceLink(this.links).distance(150))
|
||||
.force('center', d3.forceCenter(this.displayTargetWidth / 2, this.displayTargetHeight / 2))
|
||||
.force('collision', d3.forceCollide().radius(function (node: Node) {
|
||||
return node.r * 1.2;
|
||||
}))
|
||||
.on('tick', () => {
|
||||
__this.changeDetector.markForCheck();
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
simulationRestart(attachEvent: boolean = false) {
|
||||
// Update and restart the simulation.
|
||||
this.simulation
|
||||
.nodes(this.nodes)
|
||||
.force('link', d3.forceLink(this.links).distance(150))
|
||||
.force('center', d3.forceCenter(this.displayTargetWidth / 2, this.displayTargetHeight / 2))
|
||||
.alpha(1)
|
||||
.restart()
|
||||
;
|
||||
this.changeDetector.detectChanges();
|
||||
|
||||
if (attachEvent) {
|
||||
const __this = this;
|
||||
|
||||
const nodeElements = d3.select(this.displayTargetRef.nativeElement).selectAll('.node-container');
|
||||
const linkElements = d3.select(this.displayTargetRef.nativeElement).selectAll('.link-container');
|
||||
|
||||
function getNodeFromElement(element: Element): Node | null {
|
||||
const container = d3.select(element);
|
||||
const nodeId = container.attr('nodeId');
|
||||
return __this.getNode(nodeId);
|
||||
}
|
||||
|
||||
// drag
|
||||
nodeElements.call(
|
||||
d3.drag()
|
||||
.on('start', function () {
|
||||
const node = getNodeFromElement(this);
|
||||
if (null === node || 'zone' === node.group) {
|
||||
return;
|
||||
}
|
||||
|
||||
d3.event.sourceEvent.stopPropagation();
|
||||
|
||||
if (!d3.event.active) {
|
||||
__this.simulation.alphaTarget(0.3).restart();
|
||||
}
|
||||
|
||||
d3.event.on('drag', dragged).on('end', ended);
|
||||
|
||||
function dragged(d, i) {
|
||||
node.fx = d3.event.x;
|
||||
node.fy = d3.event.y;
|
||||
}
|
||||
|
||||
function ended() {
|
||||
if (!d3.event.active) {
|
||||
__this.simulation.alphaTarget(0);
|
||||
}
|
||||
|
||||
node.fx = null;
|
||||
node.fy = null;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
enum ConnectedNode {
|
||||
TARGET = 1,
|
||||
CONNECTED,
|
||||
NOT_CONNECTED,
|
||||
}
|
||||
|
||||
function isConnectedNode(node: Node, element: Element): ConnectedNode {
|
||||
const _node = getNodeFromElement(element);
|
||||
if (node === _node) {
|
||||
return ConnectedNode.TARGET;
|
||||
}
|
||||
for (let i = 0; i < node.links.length; i++) {
|
||||
const link = node.links[i];
|
||||
if (node === _node || link.source === _node || link.target === _node) {
|
||||
return ConnectedNode.CONNECTED;
|
||||
}
|
||||
}
|
||||
return ConnectedNode.NOT_CONNECTED;
|
||||
}
|
||||
|
||||
function isConnectedLink(node: Node, element: Element) {
|
||||
const _linkElement = d3.select(element);
|
||||
const sourceId = _linkElement.attr('sourceId');
|
||||
const targetId = _linkElement.attr('targetId');
|
||||
|
||||
if (sourceId === node.id || targetId === node.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nodeElements.on('click', function () {
|
||||
d3.event.stopPropagation();
|
||||
|
||||
const nodeElement = this as Element;
|
||||
const node = getNodeFromElement(nodeElement);
|
||||
if (null === node || 'zone' === node.group) {
|
||||
__this.onTargetClick(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === __this.selectedNode) {
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unfocused', false);
|
||||
d3.select(_thisElement).classed('unfocused', false);
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unfocused', false);
|
||||
d3.select(_thisElement).classed('unfocused', false);
|
||||
});
|
||||
} else {
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unselected', false);
|
||||
d3.select(_thisElement).classed('unselected', false);
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unselected', false);
|
||||
d3.select(_thisElement).classed('unselected', false);
|
||||
});
|
||||
}
|
||||
|
||||
__this.selectedNode = node;
|
||||
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
switch (isConnectedNode(node, _thisElement)) {
|
||||
case ConnectedNode.CONNECTED:
|
||||
d3.select(_thisElement).classed('semi-unselected', true);
|
||||
break;
|
||||
case ConnectedNode.NOT_CONNECTED:
|
||||
d3.select(_thisElement).classed('unselected', true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
if (isConnectedLink(node, _thisElement)) {
|
||||
d3.select(_thisElement).classed('semi-unselected', true);
|
||||
} else {
|
||||
d3.select(_thisElement).classed('unselected', true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
__this.onTargetClick(node);
|
||||
});
|
||||
|
||||
// Highlight
|
||||
const displayTarget = d3.select(this.displayTargetRef.nativeElement);
|
||||
displayTarget.on('click', function () {
|
||||
__this.selectedNode = null;
|
||||
__this.store.dispatch(new TargetStore.ChangeSelectedTarget(null));
|
||||
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unselected', false);
|
||||
d3.select(_thisElement).classed('unselected', false);
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unselected', false);
|
||||
d3.select(_thisElement).classed('unselected', false);
|
||||
});
|
||||
});
|
||||
|
||||
nodeElements
|
||||
.on('mouseover', function () {
|
||||
const node = getNodeFromElement(this as Element);
|
||||
if ('zone' === node.group) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === __this.selectedNode) {
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
switch (isConnectedNode(node, _thisElement)) {
|
||||
case ConnectedNode.CONNECTED:
|
||||
d3.select(_thisElement).classed('semi-unfocused', true);
|
||||
break;
|
||||
case ConnectedNode.NOT_CONNECTED:
|
||||
d3.select(_thisElement).classed('unfocused', true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
if (isConnectedLink(node, _thisElement)) {
|
||||
d3.select(_thisElement).classed('semi-unfocused', true);
|
||||
} else {
|
||||
d3.select(_thisElement).classed('unfocused', true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
switch (isConnectedNode(node, _thisElement)) {
|
||||
case ConnectedNode.TARGET:
|
||||
d3.select(_thisElement).classed('focused', true);
|
||||
break;
|
||||
case ConnectedNode.CONNECTED:
|
||||
d3.select(_thisElement).classed('semi-focused', true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
if (isConnectedLink(node, _thisElement)) {
|
||||
d3.select(_thisElement).classed('semi-focused', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
.on('mouseout', function () {
|
||||
const node = getNodeFromElement(this as Element);
|
||||
|
||||
if (null === __this.selectedNode) {
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unfocused', false);
|
||||
d3.select(_thisElement).classed('unfocused', false);
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unfocused', false);
|
||||
d3.select(_thisElement).classed('unfocused', false);
|
||||
});
|
||||
|
||||
} else {
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-focused', false);
|
||||
d3.select(_thisElement).classed('focused', false);
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-focused', false);
|
||||
d3.select(_thisElement).classed('focused', false);
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
zoomToFit(paddingPercent, transitionDuration) {
|
||||
const root = d3.select(this.displayTargetRef.nativeElement);
|
||||
const bounds = root.node().getBBox();
|
||||
|
||||
const fullWidth = this.displayTargetWidth;
|
||||
const fullHeight = this.displayTargetHeight;
|
||||
|
||||
const width = bounds.width;
|
||||
const height = bounds.height;
|
||||
|
||||
const midX = bounds.x + width / 2;
|
||||
const midY = bounds.y + height / 2;
|
||||
|
||||
if (width === 0 || height === 0) { return; } // nothing to fit
|
||||
|
||||
let scale = (paddingPercent || 0.75) / Math.max(width / fullWidth, height / fullHeight);
|
||||
console.log(`scale: ${scale}`);
|
||||
|
||||
if (this.maxScale < scale) {
|
||||
scale = this.maxScale;
|
||||
}
|
||||
if (this.minScale > scale) {
|
||||
scale = this.minScale;
|
||||
}
|
||||
|
||||
const translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
|
||||
|
||||
root
|
||||
.transition()
|
||||
.duration(transitionDuration || 0) // milliseconds
|
||||
.call(this.zoomBehavior.transform, d3.zoomIdentity.translate(translate[0], translate[1]).scale(scale));
|
||||
}
|
||||
|
||||
onTargetClick(node: Node) {
|
||||
console.log(node);
|
||||
|
||||
switch (node.group) {
|
||||
case 'zone':
|
||||
const zone: Zone = node.target;
|
||||
zone.hostList = [];
|
||||
|
||||
this.hosts.forEach(_host => {
|
||||
if (_host.zone.network === zone.network) {
|
||||
zone.hostList.push(_host);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case 'host':
|
||||
const host: Host = node.target;
|
||||
host.portList = [];
|
||||
if (this.ports.has(host.address)) {
|
||||
this.ports.get(host.address).forEach(port => {
|
||||
host.portList.push(port);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.store.dispatch(new TargetStore.ChangeSelectedTarget({
|
||||
group: node.group,
|
||||
target: node.target,
|
||||
}));
|
||||
|
||||
this.selectedNode = node;
|
||||
}
|
||||
|
||||
onHideDetail() {
|
||||
const __this = this;
|
||||
|
||||
const nodeElements = d3.select(this.displayTargetRef.nativeElement).selectAll('.node-container');
|
||||
const linkElements = d3.select(this.displayTargetRef.nativeElement).selectAll('.link-container');
|
||||
|
||||
__this.selectedNode = null;
|
||||
|
||||
nodeElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unselected', false);
|
||||
d3.select(_thisElement).classed('unselected', false);
|
||||
});
|
||||
|
||||
linkElements.each(function () {
|
||||
const _thisElement = this as Element;
|
||||
d3.select(_thisElement).classed('semi-unselected', false);
|
||||
d3.select(_thisElement).classed('unselected', false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private getNode(id: string): Node | null {
|
||||
let _n: Node = null;
|
||||
this.nodes.some((node): boolean => {
|
||||
if (node.id === id) {
|
||||
_n = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return _n;
|
||||
}
|
||||
|
||||
|
||||
refreshTargetDisplay(zone: Zone, hosts: Host[], services: Service[]) {
|
||||
|
||||
}
|
||||
|
||||
setZone(zone: Zone, requireRefresh: boolean = false) {
|
||||
if (null === zone) {
|
||||
return;
|
||||
}
|
||||
this.zone = zone;
|
||||
this.zoneNode = new Node(zone.network);
|
||||
this.zoneNode.group = 'zone';
|
||||
this.zoneNode.target = zone;
|
||||
this.zoneNode.fx = this.displayTargetWidth / 2;
|
||||
this.zoneNode.fy = this.displayTargetHeight / 2;
|
||||
this.zoneNode.r = 60;
|
||||
|
||||
this.nodes.push(
|
||||
this.zoneNode,
|
||||
);
|
||||
|
||||
if (requireRefresh) {
|
||||
this.simulationRestart();
|
||||
}
|
||||
}
|
||||
|
||||
addHost(host: Host, requireRefresh: boolean = false) {
|
||||
if (null === host) {
|
||||
return;
|
||||
}
|
||||
this.hosts.set(host.address, host);
|
||||
|
||||
const hostId = `${host.address}`;
|
||||
|
||||
let hostNode = this.getNode(hostId);
|
||||
if (null !== hostNode) {
|
||||
hostNode.target = host;
|
||||
} else {
|
||||
hostNode = new Node(hostId);
|
||||
hostNode.target = host;
|
||||
hostNode.group = 'host';
|
||||
hostNode.r = 40;
|
||||
hostNode.x = this.zoneNode.x;
|
||||
hostNode.y = this.zoneNode.y;
|
||||
|
||||
this.nodes.push(hostNode);
|
||||
this.links.push(new Link(this.zoneNode, hostNode));
|
||||
|
||||
this.displaySummary.increaseHost();
|
||||
|
||||
if (requireRefresh) {
|
||||
this.simulationRestart();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addPort(port: Port, requireRefresh: boolean = false) {
|
||||
if (null === port) {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ports: Map<number, Port>;
|
||||
if (!this.ports.has(port.host.address)) {
|
||||
_ports = new Map();
|
||||
this.ports.set(port.host.address, _ports);
|
||||
} else {
|
||||
_ports = this.ports.get(port.host.address);
|
||||
}
|
||||
|
||||
if (!_ports.has(port.portNumber)) {
|
||||
this.displaySummary.increasePort();
|
||||
}
|
||||
|
||||
_ports.set(port.portNumber, port);
|
||||
|
||||
if (requireRefresh) {
|
||||
this.simulationRestart();
|
||||
}
|
||||
}
|
||||
|
||||
addService(service: Service, requireRefresh: boolean = false) {
|
||||
if (null === service) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hostId = `${service.port.host.address}`;
|
||||
const serviceId = `${service.port.host.address}-${service.port.portNumber}-${service.port.metaPortType.key}`;
|
||||
|
||||
const hostNode = this.getNode(hostId);
|
||||
let serviceNode = this.getNode(serviceId);
|
||||
if (null !== serviceNode) {
|
||||
serviceNode.target = service;
|
||||
} else {
|
||||
serviceNode = new Node(serviceId);
|
||||
serviceNode.target = service;
|
||||
serviceNode.group = 'service';
|
||||
serviceNode.r = 30;
|
||||
serviceNode.x = hostNode.x;
|
||||
serviceNode.y = hostNode.y;
|
||||
|
||||
this.nodes.push(serviceNode);
|
||||
this.links.push(new Link(hostNode, serviceNode));
|
||||
|
||||
this.displaySummary.increaseService();
|
||||
|
||||
if (requireRefresh) {
|
||||
this.simulationRestart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
src/app/component/target/display/tree.component.html
Normal file
3
src/app/component/target/display/tree.component.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
Tree
|
||||
</div>
|
31
src/app/component/target/display/tree.component.ts
Normal file
31
src/app/component/target/display/tree.component.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
AfterContentInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@Component({
|
||||
selector: 'app-target-display-tree',
|
||||
templateUrl: './tree.component.html',
|
||||
styleUrls: ['./tree.component.scss']
|
||||
})
|
||||
export class TreeComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
}
|
||||
|
||||
}
|
13
src/app/component/target/index.ts
Normal file
13
src/app/component/target/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import {
|
||||
COMPONENTS as DETAIL_COMPONENTS
|
||||
} from './detail';
|
||||
|
||||
import {
|
||||
COMPONENTS as DISPLAY_COMPONENTS
|
||||
} from './display';
|
||||
|
||||
|
||||
export const COMPONENTS = [
|
||||
...DETAIL_COMPONENTS,
|
||||
...DISPLAY_COMPONENTS,
|
||||
];
|
230
src/app/core/discovery/discovery-session.ts
Normal file
230
src/app/core/discovery/discovery-session.ts
Normal file
|
@ -0,0 +1,230 @@
|
|||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { Host, Port, DiscoveryModeType, Service } from '@overflow/model/discovery';
|
||||
import { RPCSubscriber } from '@overflow/commons/ui/decorator/RPCSubscriber';
|
||||
import { RPCError } from '@overflow/rpc-js';
|
||||
|
||||
import { ProbeService } from '../../service/probe.service';
|
||||
import { DiscoverRequestInfo } from '../model';
|
||||
|
||||
import * as AppStore from '../../store';
|
||||
import * as DiscoveryRequestStore from '../../store/discovery/request';
|
||||
import * as UserStore from '../../store/environment/user';
|
||||
import * as TargetTargetStore from '../../store/target/target';
|
||||
import { take, map } from 'rxjs/operators';
|
||||
import { DiscoveryMessageType, TargetDisplayType, DiscoveryStatusType } from '../type';
|
||||
import { Subject, Observable } from 'rxjs';
|
||||
|
||||
export class DiscoverySession {
|
||||
|
||||
private _discoverRequestInfo: DiscoverRequestInfo | null;
|
||||
private _requestID: string | null;
|
||||
private startDate: Date | null;
|
||||
private discoverySubject: Subject<{ messageType: DiscoveryMessageType, params: any[] }> | null;
|
||||
|
||||
private constructor(
|
||||
private store: Store<any>,
|
||||
private probeService: ProbeService,
|
||||
) {
|
||||
}
|
||||
|
||||
public static requestDiscover(store: Store<any>, probeService: ProbeService): void {
|
||||
store.pipe(
|
||||
take(1),
|
||||
select((state) => {
|
||||
const memberID = AppStore.EnvironmentSelector.UserSelector.selectMemberID(state);
|
||||
const zone = AppStore.DiscoverySelector.ConfigSelector.selectZone(state);
|
||||
const host = AppStore.DiscoverySelector.ConfigSelector.selectHost(state);
|
||||
const port = AppStore.DiscoverySelector.ConfigSelector.selectPort(state);
|
||||
const discoverHost = AppStore.DiscoverySelector.ConfigSelector.selectDiscoverHost(state);
|
||||
const discoverPort = AppStore.DiscoverySelector.ConfigSelector.selectDiscoverPort(state);
|
||||
const discoverService = AppStore.DiscoverySelector.ConfigSelector.selectDiscoverService(state);
|
||||
const discoverySession = AppStore.DiscoverySelector.RequestSelector.selectDiscoverySession(state);
|
||||
|
||||
if (null !== discoverySession) {
|
||||
return null;
|
||||
}
|
||||
const discoverRequestInfo = {
|
||||
requesterID: memberID,
|
||||
zone,
|
||||
host,
|
||||
port,
|
||||
discoverHost,
|
||||
discoverPort,
|
||||
discoverService,
|
||||
};
|
||||
const _discoverySession = new DiscoverySession(store, probeService);
|
||||
_discoverySession.init(discoverRequestInfo);
|
||||
|
||||
return _discoverySession;
|
||||
}),
|
||||
).pipe(
|
||||
map((discoverySession) => {
|
||||
if (null === discoverySession) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(new UserStore.ChangeShowWelcomPage({ showWelcomPage: false }));
|
||||
store.dispatch(new TargetTargetStore.ChangeTargetDisplayType({ targetDisplayType: TargetDisplayType.MAP }));
|
||||
|
||||
store.dispatch(new DiscoveryRequestStore.RequestDiscover({ discoverySession }));
|
||||
// store.dispatch(new UserStore.ChangeShowWelcomPage({ showWelcomPage: false }));
|
||||
// store.dispatch(new TargetTargetStore.ChangeTargetDisplayType({ targetDisplayType: TargetDisplayType.MAP }));
|
||||
}),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
public static requestDiscoverStop(store: Store<any>): void {
|
||||
store.pipe(
|
||||
take(1),
|
||||
select((state) => {
|
||||
const discoverySession = AppStore.DiscoverySelector.RequestSelector.selectDiscoverySession(state);
|
||||
|
||||
if (null === discoverySession) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return discoverySession;
|
||||
}),
|
||||
).pipe(
|
||||
map((discoverySession) => {
|
||||
if (null === discoverySession) {
|
||||
return;
|
||||
}
|
||||
store.dispatch(new DiscoveryRequestStore.RequestDiscoverStop({ discoverySession }));
|
||||
}),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
init(discoverRequestInfo: DiscoverRequestInfo) {
|
||||
this._discoverRequestInfo = discoverRequestInfo;
|
||||
this.discoverySubject = new Subject();
|
||||
this.probeService.subscribeNotification(this);
|
||||
}
|
||||
|
||||
destroy(requireDispatch: boolean = true) {
|
||||
this.probeService.unsubscribeNotification(this);
|
||||
|
||||
if (requireDispatch) {
|
||||
this.store.dispatch(new DiscoveryRequestStore.DiscoveryComplete());
|
||||
}
|
||||
|
||||
this._requestID = null;
|
||||
this.startDate = null;
|
||||
|
||||
this._discoverRequestInfo = null;
|
||||
this.discoverySubject = null;
|
||||
}
|
||||
|
||||
public get requestID(): string {
|
||||
return this._requestID;
|
||||
}
|
||||
|
||||
public get discoverRequestInfo(): DiscoverRequestInfo {
|
||||
return this._discoverRequestInfo;
|
||||
}
|
||||
|
||||
public discoveryObservable(): Observable<{ messageType: DiscoveryMessageType, params: any[] }> {
|
||||
return this.discoverySubject.asObservable();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DiscoveryQueueing
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.Queueing' })
|
||||
public DiscoveryQueueing(requestID: string, queueingDate: Date) {
|
||||
this._requestID = requestID;
|
||||
|
||||
this.store.dispatch(new DiscoveryRequestStore.ChangeDiscoveryStatus({ discoveryStatus: DiscoveryStatusType.Queueing }));
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.Queueing, params: [requestID, queueingDate] });
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveryQueueingFailed
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.QueueingFailed' })
|
||||
public DiscoveryQueueingFailed(queueingFailedDate: Date) {
|
||||
this.store.dispatch(new DiscoveryRequestStore.ChangeDiscoveryStatus({ discoveryStatus: DiscoveryStatusType.Stopped }));
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.QueueingFailed, params: [queueingFailedDate] });
|
||||
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveryQueueingTimeout
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.QueueingTimeout' })
|
||||
public DiscoveryQueueingTimeout(queueingTimeoutDate: Date) {
|
||||
this._requestID = null;
|
||||
|
||||
this.store.dispatch(new DiscoveryRequestStore.ChangeDiscoveryStatus({ discoveryStatus: DiscoveryStatusType.Stopped }));
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.QueueingTimeout, params: [queueingTimeoutDate] });
|
||||
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveryStart
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveryStart' })
|
||||
public DiscoveryStart(startDate: Date) {
|
||||
this.startDate = startDate;
|
||||
|
||||
this.store.dispatch(new DiscoveryRequestStore.ChangeDiscoveryStatus({ discoveryStatus: DiscoveryStatusType.Started }));
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveryStart, params: [startDate] });
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveryStop
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveryStop' })
|
||||
public DiscoveryStop(stopDate: Date) {
|
||||
this.store.dispatch(new DiscoveryRequestStore.ChangeDiscoveryStatus({ discoveryStatus: DiscoveryStatusType.Stopped }));
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveryStop, params: [stopDate] });
|
||||
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveryMode
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveryMode' })
|
||||
public DiscoveryMode(discoveryMode: DiscoveryModeType) {
|
||||
this.store.dispatch(new DiscoveryRequestStore.ChangeDiscoveryMode({ discoveryMode: discoveryMode }));
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveryMode, params: [discoveryMode] });
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveryError
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveryError' })
|
||||
public DiscoveryError(err: RPCError) {
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveryError, params: [err] });
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveredHost
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveredHost' })
|
||||
public DiscoveredHost(host: Host) {
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveredHost, params: [host] });
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveredPort
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveredPort' })
|
||||
public DiscoveredPort(port: Port) {
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveredPort, params: [port] });
|
||||
}
|
||||
|
||||
/**
|
||||
* DiscoveredService
|
||||
*/
|
||||
@RPCSubscriber({ method: 'DiscoveryService.DiscoveredService' })
|
||||
public DiscoveredService(service: Service) {
|
||||
this.discoverySubject.next({ messageType: DiscoveryMessageType.DiscoveredService, params: [service] });
|
||||
}
|
||||
|
||||
}
|
11
src/app/core/model/discover-request-info.ts
Normal file
11
src/app/core/model/discover-request-info.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Zone, Host, Port, DiscoverHost, DiscoverPort, DiscoverService } from '@overflow/model/discovery';
|
||||
|
||||
export interface DiscoverRequestInfo {
|
||||
requesterID: string;
|
||||
zone: Zone | null;
|
||||
host: Host | null;
|
||||
port: Port | null;
|
||||
discoverHost: DiscoverHost | null;
|
||||
discoverPort: DiscoverPort | null;
|
||||
discoverService: DiscoverService | null;
|
||||
}
|
3
src/app/core/model/index.ts
Normal file
3
src/app/core/model/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './link';
|
||||
export * from './node';
|
||||
export * from './discover-request-info';
|
13
src/app/core/type/discovery-message.ts
Normal file
13
src/app/core/type/discovery-message.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
export enum DiscoveryMessageType {
|
||||
Queueing = 'Queueing',
|
||||
QueueingFailed = 'QueueingFailed',
|
||||
QueueingTimeout = 'QueueingTimeout',
|
||||
DiscoveryStart = 'DiscoveryStart',
|
||||
DiscoveryStop = 'DiscoveryStop',
|
||||
DiscoveryMode = 'DiscoveryMode',
|
||||
DiscoveryError = 'DiscoveryError',
|
||||
DiscoveredHost = 'DiscoveredHost',
|
||||
DiscoveredPort = 'DiscoveredPort',
|
||||
DiscoveredService = 'DiscoveredService',
|
||||
}
|
7
src/app/core/type/discovery-status.ts
Normal file
7
src/app/core/type/discovery-status.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export enum DiscoveryStatusType {
|
||||
Requested = 'Requested',
|
||||
Queueing = 'Queueing',
|
||||
Started = 'Started',
|
||||
Stopping = 'Stopping',
|
||||
Stopped = 'Stopped'
|
||||
}
|
3
src/app/core/type/index.ts
Normal file
3
src/app/core/type/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './discovery-message';
|
||||
export * from './discovery-status';
|
||||
export * from './target-display';
|
7
src/app/core/type/target-display.ts
Normal file
7
src/app/core/type/target-display.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
export enum TargetDisplayType {
|
||||
NONE = 'NONE',
|
||||
MAP = 'MAP',
|
||||
GRID = 'GRID',
|
||||
TREE = 'TREE',
|
||||
}
|
48
src/app/core/util/discovery.util.ts
Normal file
48
src/app/core/util/discovery.util.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { DiscoverHost, DiscoverPort, DiscoverService, Zone, Host, Port } from '@overflow/model/discovery';
|
||||
|
||||
import * as AppStore from '../../store';
|
||||
import { DiscoverRequestInfo } from '../model';
|
||||
import { DiscoverySession } from '../discovery/discovery-session';
|
||||
|
||||
export class DiscoveryUtil {
|
||||
/**
|
||||
* name
|
||||
*/
|
||||
public static getRequestInfo(store: Store<any>): Observable<DiscoverRequestInfo> {
|
||||
return combineLatest(
|
||||
store.select(AppStore.EnvironmentSelector.UserSelector.selectMemberID),
|
||||
store.select(AppStore.DiscoverySelector.ConfigSelector.selectZone),
|
||||
store.select(AppStore.DiscoverySelector.ConfigSelector.selectHost),
|
||||
store.select(AppStore.DiscoverySelector.ConfigSelector.selectPort),
|
||||
store.select(AppStore.DiscoverySelector.ConfigSelector.selectDiscoverHost),
|
||||
store.select(AppStore.DiscoverySelector.ConfigSelector.selectDiscoverPort),
|
||||
store.select(AppStore.DiscoverySelector.ConfigSelector.selectDiscoverService),
|
||||
(
|
||||
memberID: string,
|
||||
zone: Zone, host: Host, port: Port,
|
||||
discoverHost: DiscoverHost, discoverPort: DiscoverPort, discoverService: DiscoverService) => {
|
||||
return {
|
||||
requesterID: memberID,
|
||||
zone,
|
||||
host,
|
||||
port,
|
||||
discoverHost,
|
||||
discoverPort,
|
||||
discoverService,
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static getDiscoverySession(store: Store<any>): Observable<DiscoverySession> {
|
||||
return combineLatest(
|
||||
store.select(AppStore.DiscoverySelector.RequestSelector.selectDiscoverySession),
|
||||
(discoverySession: DiscoverySession) => {
|
||||
return discoverySession;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { HomePageComponent } from './home-page.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: HomePageComponent,
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class HomePageRoutingModule { }
|
|
@ -1,6 +1,6 @@
|
|||
<of-p-div #discoveryContainer>
|
||||
<div *ngIf="showIntro" class="home-start">
|
||||
<div class="start-button" (click)="discoveryConfigService.setDiscoveryStatus('Started')">
|
||||
<of-p-div>
|
||||
<div *ngIf="(showWelcomPage$ | async)" class="home-start">
|
||||
<div class="start-button" (click)="requestDiscover()">
|
||||
<svg version="1.1" viewBox="0 0 200 210">
|
||||
<path d="M8.3,193.5c0.1,2.4,0.8,4.9,2.1,7.1c4.5,7.7,14.3,10.4,22.1,5.9l152.1-87.8c2-1.3,3.8-3.1,5.1-5.4
|
||||
c4.5-7.7,1.8-17.6-5.9-22.1L31.6,3.4c-2.2-1.1-4.6-1.7-7.2-1.7c-8.9,0-16.2,7.2-16.2,16.2V193.5z" />
|
||||
|
@ -10,127 +10,19 @@
|
|||
<img src="assets/image/logo/overFlow_CI_white_90.png">
|
||||
<h1>Network Scanner </h1>
|
||||
<br>
|
||||
<b>를 이용해 주셔서 감사합니다.</b>
|
||||
<b>이용해 주셔서 감사합니다.</b>
|
||||
<br> 좌측의 버튼을 클릭 하시면 기본 설정으로 스캐닝이 시작 됩니다. 설정의 변경을 원하시면 상단의 설정 영역을 클릭하여 변경이 가능합니다.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!showIntro" class="discovery-container">
|
||||
<svg #discoveryTarget width="100%" height="100%">
|
||||
<g>
|
||||
<g *ngFor="let link of links">
|
||||
<g class="link-container" [ngClass]="'link-'+link.target.group" [attr.sourceId]="link.source.id"
|
||||
[attr.targetId]="link.target.id">
|
||||
<line class="link" [attr.x1]="link.source.x" [attr.y1]="link.source.y" [attr.x2]="link.target.x" [attr.y2]="link.target.y"></line>
|
||||
<text *ngIf="link.target.group === 'service'" class="linkTextClass" [attr.x]="(link.source.x - link.target.x) / 2 + link.target.x"
|
||||
[attr.y]="(link.source.y - link.target.y) / 2 + link.target.y">{{link.target.target.port.portNumber}}</text>
|
||||
</g>
|
||||
</g>
|
||||
<g *ngFor="let node of nodes">
|
||||
<g class="node-container" [ngClass]="node.group" [attr.nodeId]="node.id" [attr.transform]="'translate(' + node.x + ',' + node.y + ')'">
|
||||
<g *ngIf="node.group === 'zone'">
|
||||
<image [attr.x]="-node.r" [attr.y]="-node.r" [attr.width]="node.r * 2" [attr.height]="node.r * 2"
|
||||
xlink:href="assets/image/node/icon/icon_overflow.svg"></image>
|
||||
</g>
|
||||
<g *ngIf="node.group === 'zone'">
|
||||
<text class="textClass" [attr.y]="(node.r - 10) / 10 + 'em'" text-anchor="middle">{{node.target.network}}</text>
|
||||
</g>
|
||||
<g *ngIf="node.group !== 'zone'">
|
||||
<image [attr.x]="-node.r" [attr.y]="-node.r" [attr.width]="node.r * 2" [attr.height]="node.r * 2"
|
||||
xlink:href="assets/image/node/icon/icon_background.svg"></image>
|
||||
</g>
|
||||
<g *ngIf="node.group === 'host'">
|
||||
<image [attr.x]="-node.r" [attr.y]="-node.r" [attr.width]="node.r * 2" [attr.height]="node.r * 2"
|
||||
attr.xlink:href="assets/image/node/icon/icon_{{node.target.hostType | lowercase}}.svg"></image>
|
||||
</g>
|
||||
<g *ngIf="node.group === 'host' && node.target.hostType === 'HOST' && node.target.osType !== 'UNKNOWN'">
|
||||
<image [attr.x]="-node.r" [attr.y]="-node.r" [attr.width]="node.r * 2" [attr.height]="node.r * 2"
|
||||
attr.xlink:href="assets/image/node/logo/logo_{{node.target.osType | lowercase}}.svg"></image>
|
||||
</g>
|
||||
<!-- <g *ngIf="node.group === 'host' && node.target.hostType !== 'HOST' && node.target.hostVendor !== ''">
|
||||
<text class="textClass" [attr.y]="(node.r - 30) / 10 + 'em'" text-anchor="middle">{{node.target.hostVendor}}</text>
|
||||
</g> -->
|
||||
<g *ngIf="node.group === 'host'">
|
||||
<text class="textClass" [attr.y]="(node.r - 10) / 10 + 'em'" text-anchor="middle">{{node.target.address}}</text>
|
||||
</g>
|
||||
<g *ngIf="node.group === 'service'">
|
||||
<image [attr.x]="-node.r" [attr.y]="-node.r" [attr.width]="node.r * 2" [attr.height]="node.r * 2"
|
||||
attr.xlink:href="assets/image/node/icon/icon_{{node.target.serviceType | lowercase}}.svg"></image>
|
||||
</g>
|
||||
<g *ngIf="node.group === 'service' && node.target.key !== 'UNKNOWN'">
|
||||
<image [attr.x]="-node.r" [attr.y]="-node.r" [attr.width]="node.r * 2" [attr.height]="node.r * 2"
|
||||
attr.xlink:href="assets/image/node/logo/logo_{{node.target.key | lowercase}}.svg"></image>
|
||||
</g>
|
||||
<g *ngIf="node.group === 'service'">
|
||||
<text class="textClass" [attr.y]="(node.r - 10) / 10 + 'em'" text-anchor="middle">{{node.target.name}}</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<p-card class="ui-map-info" *ngIf="discoveryResult">
|
||||
<div class="ui-map-info-row ui-border-bottom">
|
||||
<div>Total Hosts: </div>{{discoveryResult.totalHosts}}
|
||||
</div>
|
||||
<div class="ui-map-info-row ui-border-bottom">
|
||||
<div>Total Services: </div>{{discoveryResult.totalServices}}
|
||||
</div>
|
||||
<div class="ui-map-info-row">
|
||||
<div>Elapsed: </div>{{discoveryResult.elapsedTime}}
|
||||
</div>
|
||||
</p-card>
|
||||
|
||||
<div #detailSidebar style="position: sticky; top: 0; left: 0; height: 100%;"></div>
|
||||
|
||||
<p-sidebar [(visible)]="displaySidebar" [modal]="false" [appendTo]="detailSidebar" styleClass="ui-sidebar-md"
|
||||
position="right" (onHide)="onHideDetail()" [style]="{position:'absolute'}">
|
||||
<div *ngIf="selectedNode !== null">
|
||||
<app-node-detail [node]="selectedNode" (otherHostSelect)="otherHostSelected($event)"></app-node-detail>
|
||||
</div>
|
||||
</p-sidebar>
|
||||
<div *ngIf="!(showWelcomPage$ | async)" class="display-container">
|
||||
<app-target-display></app-target-display>
|
||||
</div>
|
||||
</of-p-div>
|
||||
|
||||
<p-confirmDialog></p-confirmDialog>
|
||||
|
||||
<p-blockUI id="discovery-blockUI" [target]="discoveryContainer" [blocked]="discoveryRequestID !== null">
|
||||
</p-blockUI>
|
||||
|
||||
<p-dialog [showHeader]="false" [(visible)]="stopping" [modal]="true" [responsive]="false" [width]="300" [height]="100"
|
||||
[minY]="70" [closeOnEscape]="false" [closable]="false">
|
||||
<div class="ui-dialog-text-center">Discovery is being stopped...</div>
|
||||
</p-dialog>
|
||||
|
||||
|
||||
<!-- <div class="ui-fluid">
|
||||
<div class="ui-g">
|
||||
<div class="ui-g-12">
|
||||
<h1>Home works!!!!</h1>
|
||||
<p-panel #content [showHeader]="false" class="block-panel">
|
||||
<div class="ui-g" dir="rtl">
|
||||
<button class="ui-button-width-fit" type="button" label="Discovery" icon="ui-icon-search" pButton></button>
|
||||
</div>
|
||||
</p-panel>
|
||||
|
||||
<h3 class="first">Document</h3>
|
||||
<p-blockUI [blocked]="blockedDocument"></p-blockUI>
|
||||
|
||||
<button type="button" pButton label="Block" (click)="blockDocument()"></button>
|
||||
|
||||
<h3>Panel</h3>
|
||||
<button type="button" pButton label="Block" (click)="blockedPanel=true"></button>
|
||||
<button type="button" pButton label="Unblock" (click)="blockedPanel=false"></button>
|
||||
|
||||
<p-blockUI [target]="pnl" [blocked]="blockedPanel">
|
||||
<i class="fa fa-lock fa-5x" style="position:absolute;top:25%;left:50%"></i>
|
||||
</p-blockUI>
|
||||
<p-panel #pnl header="Godfather I" [style]="{'margin-top':'20px'}">
|
||||
The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding. His beloved
|
||||
son Michael has just come home from the war, but does not intend to become part of his father's business.
|
||||
Through Michael's life the nature of the family business becomes clear. The business of the family is
|
||||
just like the head of the family, kind and benevolent to those who give respect, but given to ruthless
|
||||
violence whenever anything stands against the good of the family.
|
||||
</p-panel>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
|
@ -48,105 +48,15 @@
|
|||
padding: .6em .75em;
|
||||
}
|
||||
|
||||
.discovery-container {
|
||||
height: 100vh;
|
||||
margin: -0.6em -0.9em -0.7em -0.9em; //-0.5em -0.75em;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 400px; //text-align: center;
|
||||
}
|
||||
|
||||
.link {
|
||||
stroke: #999;
|
||||
stroke-opacity: 0.6;
|
||||
}
|
||||
|
||||
.textClass {
|
||||
stroke: #323232;
|
||||
font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
|
||||
font-weight: normal;
|
||||
stroke-width: .5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.linkTextClass {
|
||||
stroke: #b6b4b4;
|
||||
font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
|
||||
font-weight: normal;
|
||||
stroke-width: .3;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.focused {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.semi-focused {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
|
||||
.semi-unfocused {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.unfocused {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.semi-unselected {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.unselected {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.ui-map-info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
.ui-map-info-row {
|
||||
//display: inline;
|
||||
font-size: 0.8em;
|
||||
line-height: 2em;
|
||||
width: 120px;
|
||||
font-weight: bold;
|
||||
user-select: text;
|
||||
div {
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
padding-left: 5px;
|
||||
width: 75px;
|
||||
user-select: text;
|
||||
}
|
||||
}
|
||||
.ui-border-bottom {
|
||||
border-bottom: 1px solid #d6d6d6;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .ui-card-body {
|
||||
padding: 0.5em;
|
||||
border: 1px solid #d6d6d6;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.detail-sidebar {
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// /deep/ .ui-blockui {
|
||||
// opacity: 0.1;
|
||||
// }
|
||||
/deep/ .ui-widget-overlay {
|
||||
background-color: #666666;
|
||||
opacity: .20;
|
||||
filter: Alpha(Opacity=50);
|
||||
.display-container {
|
||||
position: relative; // height: 100vh;
|
||||
// margin: -0.6em -0.9em -0.7em -0.9em; //-0.5em -0.75em;
|
||||
// padding: 0;
|
||||
// box-sizing: border-box;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// min-width: 400px; //text-align: center;
|
||||
}
|
||||
|
||||
.ui-dialog-text-center {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { CommonsUIModule } from '@overflow/commons/ui/commons-ui.module';
|
||||
|
||||
import { HomePageComponent } from './home-page.component';
|
||||
import { HomePageRoutingModule } from './home-page-routing.module';
|
||||
import { CommonsModule } from '../../../commons/commons.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
CommonsUIModule,
|
||||
HomePageRoutingModule,
|
||||
CommonsModule
|
||||
],
|
||||
entryComponents: [
|
||||
],
|
||||
declarations: [HomePageComponent],
|
||||
})
|
||||
export class HomePageModule { }
|
5
src/app/pages/home/index.ts
Normal file
5
src/app/pages/home/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { HomePageComponent } from './home-page.component';
|
||||
|
||||
export const PAGES = [
|
||||
HomePageComponent,
|
||||
];
|
8
src/app/pages/index.ts
Normal file
8
src/app/pages/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { PagesComponent } from './pages.component';
|
||||
|
||||
import { PAGES as HOME_PAGES } from './home';
|
||||
|
||||
export const PAGES = [
|
||||
PagesComponent,
|
||||
...HOME_PAGES,
|
||||
];
|
|
@ -1,20 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { PagesComponent } from './pages.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: PagesComponent,
|
||||
children: [
|
||||
{ path: '', redirectTo: 'home' },
|
||||
{ path: 'home', loadChildren: './home/home-page.module#HomePageModule' },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PagesRoutingModule { }
|
|
@ -1,9 +1,9 @@
|
|||
<app-toolbar>
|
||||
<app-nic-dropdown [blockTarget]="pagesContent" (select)="onNICSelect($event)"></app-nic-dropdown>
|
||||
<app-scanner-setting-dropdown [blockTarget]="pagesContent" (ready)="onConfigReady($event)"></app-scanner-setting-dropdown>
|
||||
<app-layout-toolbar-nic-dropdown [blockTarget]="pagesContent"></app-layout-toolbar-nic-dropdown>
|
||||
<app-layout-toolbar-scanner-setting-dropdown [blockTarget]="pagesContent"></app-layout-toolbar-scanner-setting-dropdown>
|
||||
<ng-template #play>
|
||||
<div class="toolbar-button push-pull-button" style="width: 32px">
|
||||
<button class="button-component" type="button" (click)="onStart()" [hidden]="discoveryStatus === 'Started' ">
|
||||
<button class="button-component" type="button" (click)="requestDiscover()" [hidden]="(discoveryStatus$ | async) === 'Started' ">
|
||||
<svg aria-hidden="true" class="octicon icon" version="1.1" viewBox="0 0 15 17">
|
||||
<path d="M0.2,15.6c0,0.2,0.1,0.4,0.2,0.6c0.4,0.6,1.2,0.8,1.8,0.5l12.2-7.1c0.2-0.1,0.3-0.3,0.4-0.4
|
||||
c0.4-0.6,0.1-1.4-0.5-1.8L2.1,0.3C1.9,0.2,1.7,0.2,1.5,0.2c-0.7,0-1.3,0.6-1.3,1.3V15.6z"></path>
|
||||
|
@ -13,8 +13,8 @@
|
|||
</ng-template>
|
||||
|
||||
<!-- Stop button -->
|
||||
<div class="toolbar-button push-pull-button" style="width: 36px" *ngIf="discoveryStatus === 'Started' else play">
|
||||
<button class="button-component" type="button" (click)="onStop()">
|
||||
<div class="toolbar-button push-pull-button" style="width: 36px" *ngIf="(discoveryStatus$ | async) === 'Started' else play">
|
||||
<button class="button-component" type="button" (click)="requestDiscoverStop()">
|
||||
<svg aria-hidden="true" class="octicon icon" version="1.1" viewBox="0 0 15 17">
|
||||
<path d="M13.6,16.1H1.4c-0.8,0-1.4-0.6-1.4-1.4V2.5c0-0.8,0.6-1.4,1.4-1.4h12.2c0.8,0,1.4,0.6,1.4,1.4v12.2
|
||||
C15,15.5,14.4,16.1,13.6,16.1z" />
|
||||
|
@ -23,7 +23,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Loading image -->
|
||||
<div class="toolbar-button push-pull-button" style="width: 36px" *ngIf="discoveryStatus !== 'Stopped' ">
|
||||
<div class="toolbar-button push-pull-button" style="width: 36px" *ngIf="(discoveryStatus$ | async) !== 'Stopped' ">
|
||||
<button class="button-component" type="button">
|
||||
<svg aria-hidden="true" class="octicon icon spin" version="1.1" viewBox="0 0 15 15">
|
||||
<path d="M14.6,5.2l-0.7,0.3l-0.7,0.3c0.7,2.6-0.3,5.4-2.7,6.8c-2.3,1.3-5.1,1-7-0.7L4.4,12l0.1-1.5l-3.1-0.2l-0.9,3.2
|
||||
|
@ -33,8 +33,8 @@
|
|||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="discoveryMode" class="ui-menu-mode">
|
||||
<span>{{discoveryMode}} Mode</span>
|
||||
<div *ngIf="(discoveryMode$ | async)" class="ui-menu-mode">
|
||||
<span>{{discoveryMode$ | async}} Mode</span>
|
||||
</div>
|
||||
</app-toolbar>
|
||||
|
||||
|
@ -43,3 +43,6 @@
|
|||
<router-outlet #o="outlet"></router-outlet>
|
||||
</div>
|
||||
</of-p-div>
|
||||
|
||||
<p-blockUI id="pagesContent-blockUI" [target]="pagesContent" [blocked]="blockPagesContent$ | async">
|
||||
</p-blockUI>
|
|
@ -2,8 +2,17 @@ import {
|
|||
Component, AfterViewInit, ElementRef, Renderer, ViewChild, OnDestroy, OnInit, NgZone
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { DiscoverHost, Zone } from '@overflow/model/discovery';
|
||||
import { DiscoveryConfigService, DiscoveryStatusType } from '../../commons/service/discovery-config.service';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { DiscoveryStatusType } from '../core/type';
|
||||
|
||||
import * as AppStore from '../store';
|
||||
import * as DiscoveryRequestStore from '../store/discovery/request';
|
||||
import { DiscoveryUtil } from '../core/util/discovery.util';
|
||||
import { map, catchError, take } from 'rxjs/operators';
|
||||
import { of } from 'rxjs';
|
||||
import { ProbeService } from '../service/probe.service';
|
||||
import { DiscoverySession } from '../core/discovery/discovery-session';
|
||||
|
||||
enum MenuOrientation {
|
||||
STATIC,
|
||||
|
@ -57,17 +66,18 @@ export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
|
|||
|
||||
|
||||
rippleInitListener: any;
|
||||
|
||||
rippleMouseDownListener: any;
|
||||
|
||||
discoveryMode: string;
|
||||
discoveryStatus: DiscoveryStatusType;
|
||||
discoveryMode$ = this.store.pipe(select(AppStore.DiscoverySelector.RequestSelector.selectDiscoveryMode));
|
||||
discoveryStatus$ = this.store.pipe(select(AppStore.DiscoverySelector.RequestSelector.selectDiscoveryStatus));
|
||||
blockPagesContent$ = this.store.pipe(select(AppStore.UISelector.LayoutSelector.selectBlockPagesContent));
|
||||
|
||||
constructor(
|
||||
public renderer: Renderer,
|
||||
private store: Store<any>,
|
||||
public zone: NgZone,
|
||||
private router: Router,
|
||||
private discoveryConfigService: DiscoveryConfigService,
|
||||
private probeService: ProbeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -76,14 +86,6 @@ export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
|
|||
return;
|
||||
}
|
||||
this.zone.runOutsideAngular(() => { this.bindRipple(); });
|
||||
this.discoveryConfigService.discoveryMode.subscribe(res => {
|
||||
this.discoveryMode = res as string;
|
||||
});
|
||||
|
||||
this.discoveryConfigService.discoveryStatus.subscribe(res => {
|
||||
this.discoveryStatus = res as DiscoveryStatusType;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
bindRipple() {
|
||||
|
@ -365,20 +367,12 @@ export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
|
|||
this.router.navigate([command]);
|
||||
}
|
||||
|
||||
onNICSelect(zone: Zone) {
|
||||
this.discoveryConfigService.setZone(zone);
|
||||
requestDiscover() {
|
||||
DiscoverySession.requestDiscover(this.store, this.probeService);
|
||||
}
|
||||
|
||||
onConfigReady(discoverHost: DiscoverHost) {
|
||||
this.discoveryConfigService.setDiscoverHost(discoverHost);
|
||||
}
|
||||
|
||||
onStart() {
|
||||
this.discoveryConfigService.setDiscoveryStatus(DiscoveryStatusType.Started);
|
||||
}
|
||||
|
||||
onStop() {
|
||||
this.discoveryConfigService.setDiscoveryStatus(DiscoveryStatusType.Stopping);
|
||||
requestDiscoverStop() {
|
||||
DiscoverySession.requestDiscoverStop(this.store);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { CommonModule, LocationStrategy, HashLocationStrategy } from '@angular/common';
|
||||
|
||||
import { CommonsUIModule } from '@overflow/commons/ui/commons-ui.module';
|
||||
|
||||
import { CommonsModule } from '../../commons/commons.module';
|
||||
|
||||
import { PagesComponent } from './pages.component';
|
||||
import { PagesRoutingModule } from './pages-routing.module';
|
||||
import { DiscoveryConfigService } from '../../commons/service/discovery-config.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
PagesRoutingModule,
|
||||
|
||||
CommonsUIModule,
|
||||
CommonsModule,
|
||||
],
|
||||
declarations: [
|
||||
PagesComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: LocationStrategy, useClass: HashLocationStrategy },
|
||||
DiscoveryConfigService,
|
||||
]
|
||||
})
|
||||
export class PagesModule { }
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import Dexie from 'dexie';
|
||||
import { LaunchState } from '../model';
|
||||
import { LaunchState } from '../../commons/model';
|
||||
|
||||
const DatabaseVersion = 1;
|
||||
|
55
src/app/service/discovery.service.ts
Normal file
55
src/app/service/discovery.service.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Zone, DiscoverHost, Host, DiscoverPort, Port, DiscoverService } from '@overflow/model/discovery';
|
||||
|
||||
import { ProbeService } from './probe.service';
|
||||
import { DiscoverRequestInfo } from '../core/model';
|
||||
|
||||
@Injectable()
|
||||
export class DiscoveryService {
|
||||
|
||||
public constructor(
|
||||
private probeService: ProbeService,
|
||||
) {
|
||||
}
|
||||
|
||||
public discover(discoverRequestInfo: DiscoverRequestInfo): void {
|
||||
if (null !== discoverRequestInfo.zone && null !== discoverRequestInfo.discoverHost) {
|
||||
this.discoverHost(
|
||||
discoverRequestInfo.requesterID,
|
||||
discoverRequestInfo.zone,
|
||||
discoverRequestInfo.discoverHost
|
||||
);
|
||||
} else if (null !== discoverRequestInfo.host && null !== discoverRequestInfo.discoverPort) {
|
||||
this.discoverPort(
|
||||
discoverRequestInfo.requesterID,
|
||||
discoverRequestInfo.host,
|
||||
discoverRequestInfo.discoverPort
|
||||
);
|
||||
} else if (null !== discoverRequestInfo.port && null !== discoverRequestInfo.discoverService) {
|
||||
this.discoverService(
|
||||
discoverRequestInfo.requesterID,
|
||||
discoverRequestInfo.port,
|
||||
discoverRequestInfo.discoverService
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public discoverHost(requesterID: string, zone: Zone, discoverHost: DiscoverHost): void {
|
||||
this.probeService.send('DiscoveryService.DiscoverHost', requesterID, zone, discoverHost);
|
||||
}
|
||||
|
||||
public discoverPort(requesterID: string, host: Host, discoverPort: DiscoverPort): void {
|
||||
this.probeService.send('DiscoveryService.DiscoverPort', requesterID, host, discoverPort);
|
||||
}
|
||||
|
||||
public discoverService(requesterID: string, port: Port, discoverService: DiscoverService): void {
|
||||
this.probeService.send('DiscoveryService.DiscoverService', requesterID, port, discoverService);
|
||||
}
|
||||
|
||||
public discoverStop(requesterID: string, requestID: string): void {
|
||||
this.probeService.send('DiscoveryService.DiscoverStop', requesterID, requestID);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@ import { catchError, exhaustMap, map, tap, take } from 'rxjs/operators';
|
|||
import { Store } from '@ngrx/store';
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import { MenuEvent } from '../type';
|
||||
import { LaunchState } from '../model';
|
||||
import { MenuEvent } from '../../commons/type';
|
||||
import { LaunchService } from './launch.service';
|
||||
import { LaunchState } from '../../commons/model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
|
@ -2,12 +2,16 @@ import { DatabaseService } from './database.service';
|
|||
import { ElectronProxyService } from './electron-proxy.service';
|
||||
import { LaunchService } from './launch.service';
|
||||
import { ProbeService } from './probe.service';
|
||||
import { DiscoveryConfigService } from './discovery-config.service';
|
||||
import { MachineService } from './machine.service';
|
||||
import { DiscoveryService } from './discovery.service';
|
||||
import { PingService } from './ping.service';
|
||||
|
||||
export const SERVICES = [
|
||||
DatabaseService,
|
||||
ElectronProxyService,
|
||||
LaunchService,
|
||||
ProbeService,
|
||||
DiscoveryConfigService
|
||||
MachineService,
|
||||
DiscoveryService,
|
||||
PingService,
|
||||
];
|
|
@ -2,13 +2,13 @@ import { Injectable } from '@angular/core';
|
|||
import { Observable, defer } from 'rxjs';
|
||||
|
||||
import { DatabaseService } from './database.service';
|
||||
import { LaunchState } from '../model';
|
||||
import { LaunchState } from '../../commons/model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LaunchService {
|
||||
public constructor(private readonly databaseService: DatabaseService) {}
|
||||
public constructor(private readonly databaseService: DatabaseService) { }
|
||||
|
||||
public save(launchState: LaunchState): Observable<number> {
|
||||
return defer(async () => {
|
22
src/app/service/machine.service.ts
Normal file
22
src/app/service/machine.service.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Interface } from '@overflow/model/net/nic';
|
||||
|
||||
import { ProbeService } from './probe.service';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class MachineService {
|
||||
|
||||
public constructor(
|
||||
private probeService: ProbeService,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public interfaces(): Observable<Interface[]> {
|
||||
return this.probeService.call<Interface[]>('MachineService.Interfaces');
|
||||
}
|
||||
|
||||
}
|
29
src/app/service/ping.service.ts
Normal file
29
src/app/service/ping.service.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Interface } from '@overflow/model/net/nic';
|
||||
|
||||
import { ProbeService } from './probe.service';
|
||||
import { PingResult } from '@overflow/model/ping';
|
||||
import { Host, Service } from '@overflow/model/discovery';
|
||||
import { PingOption } from '@overflow/model/config/ping';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class PingService {
|
||||
|
||||
public constructor(
|
||||
private probeService: ProbeService,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public pingHost(host: Host, pingOption: PingOption): Observable<PingResult> {
|
||||
return this.probeService.call<PingResult>('PingService.PingHost', host, pingOption);
|
||||
}
|
||||
|
||||
public pingService(service: Service, pingOption: PingOption): Observable<PingResult> {
|
||||
return this.probeService.call<PingResult>('PingService.PingService', service, pingOption);
|
||||
}
|
||||
|
||||
}
|
39
src/app/store/app/app.action.ts
Normal file
39
src/app/store/app/app.action.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { Action } from '@ngrx/store';
|
||||
|
||||
export enum ActionType {
|
||||
AppInit = '[app] AppInit',
|
||||
AppAfterContentInit = '[app] AppAfterContentInit',
|
||||
AppAfterViewInit = '[app] AppAfterViewInit',
|
||||
AppDestroy = '[app] AppDestroy',
|
||||
}
|
||||
|
||||
export class AppInit implements Action {
|
||||
readonly type = ActionType.AppInit;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class AppAfterContentInit implements Action {
|
||||
readonly type = ActionType.AppAfterContentInit;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class AppAfterViewInit implements Action {
|
||||
readonly type = ActionType.AppAfterViewInit;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class AppDestroy implements Action {
|
||||
readonly type = ActionType.AppDestroy;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export type Actions =
|
||||
| AppInit
|
||||
| AppAfterContentInit
|
||||
| AppAfterViewInit
|
||||
| AppDestroy
|
||||
;
|
1
src/app/store/app/index.ts
Normal file
1
src/app/store/app/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './app.action';
|
26
src/app/store/discovery/config/config.action.ts
Normal file
26
src/app/store/discovery/config/config.action.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { Action } from '@ngrx/store';
|
||||
import { Zone, DiscoverHost } from '@overflow/model/discovery';
|
||||
|
||||
export enum ActionType {
|
||||
ChangeZone = '[app.discovery] ChangeZone',
|
||||
ChangeDiscoverHost = '[app.discovery] ChangeDiscoverHost',
|
||||
}
|
||||
|
||||
export class ChangeZone implements Action {
|
||||
readonly type = ActionType.ChangeZone;
|
||||
|
||||
constructor(public payload: Zone) { }
|
||||
}
|
||||
|
||||
export class ChangeDiscoverHost implements Action {
|
||||
readonly type = ActionType.ChangeDiscoverHost;
|
||||
|
||||
constructor(public payload: DiscoverHost) { }
|
||||
}
|
||||
|
||||
|
||||
export type Actions =
|
||||
| ChangeZone
|
||||
| ChangeDiscoverHost
|
||||
|
||||
;
|
8
src/app/store/discovery/config/config.effect.ts
Normal file
8
src/app/store/discovery/config/config.effect.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class ConfigEffects {
|
||||
|
||||
constructor(
|
||||
) { }
|
||||
}
|
31
src/app/store/discovery/config/config.reducer.ts
Normal file
31
src/app/store/discovery/config/config.reducer.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import {
|
||||
Actions,
|
||||
ActionType,
|
||||
} from './config.action';
|
||||
|
||||
import {
|
||||
State,
|
||||
initialState,
|
||||
} from './config.state';
|
||||
|
||||
export function reducer(state: State = initialState, action: Actions): State {
|
||||
switch (action.type) {
|
||||
case ActionType.ChangeZone: {
|
||||
return {
|
||||
...state,
|
||||
zone: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.ChangeDiscoverHost: {
|
||||
return {
|
||||
...state,
|
||||
discoverHost: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
32
src/app/store/discovery/config/config.state.ts
Normal file
32
src/app/store/discovery/config/config.state.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { Selector, createSelector } from '@ngrx/store';
|
||||
import { Zone, DiscoverHost, Port, Host, DiscoverPort, DiscoverService } from '@overflow/model/discovery';
|
||||
|
||||
export interface State {
|
||||
zone: Zone | null;
|
||||
host: Host | null;
|
||||
port: Port | null;
|
||||
discoverHost: DiscoverHost | null;
|
||||
discoverPort: DiscoverPort | null;
|
||||
discoverService: DiscoverService | null;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
zone: null,
|
||||
host: null,
|
||||
port: null,
|
||||
discoverHost: null,
|
||||
discoverPort: null,
|
||||
discoverService: null,
|
||||
};
|
||||
|
||||
|
||||
export function getSelectors<S>(selector: Selector<any, State>) {
|
||||
return {
|
||||
selectZone: createSelector(selector, (state: State) => state.zone),
|
||||
selectHost: createSelector(selector, (state: State) => state.host),
|
||||
selectPort: createSelector(selector, (state: State) => state.port),
|
||||
selectDiscoverHost: createSelector(selector, (state: State) => state.discoverHost),
|
||||
selectDiscoverPort: createSelector(selector, (state: State) => state.discoverPort),
|
||||
selectDiscoverService: createSelector(selector, (state: State) => state.discoverService),
|
||||
};
|
||||
}
|
4
src/app/store/discovery/config/index.ts
Normal file
4
src/app/store/discovery/config/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from './config.action';
|
||||
export * from './config.effect';
|
||||
export * from './config.reducer';
|
||||
export * from './config.state';
|
38
src/app/store/discovery/index.ts
Normal file
38
src/app/store/discovery/index.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { Type } from '@angular/core';
|
||||
import {
|
||||
Selector,
|
||||
createSelector,
|
||||
combineReducers
|
||||
} from '@ngrx/store';
|
||||
|
||||
import * as ConfigStore from './config';
|
||||
import * as RequestStore from './request';
|
||||
|
||||
|
||||
export interface State {
|
||||
config: ConfigStore.State;
|
||||
request: RequestStore.State;
|
||||
}
|
||||
|
||||
export const EFFECTS: Type<any>[] = [
|
||||
ConfigStore.ConfigEffects,
|
||||
RequestStore.RequestEffects,
|
||||
];
|
||||
|
||||
export const REDUCER = combineReducers({
|
||||
config: ConfigStore.reducer,
|
||||
request: RequestStore.reducer,
|
||||
});
|
||||
|
||||
export function getSelectors<S>(selector: Selector<any, State>) {
|
||||
return {
|
||||
ConfigSelector: ConfigStore.getSelectors(createSelector(
|
||||
selector,
|
||||
(state: State) => state.config,
|
||||
)),
|
||||
RequestSelector: RequestStore.getSelectors(createSelector(
|
||||
selector,
|
||||
(state: State) => state.request,
|
||||
)),
|
||||
};
|
||||
}
|
4
src/app/store/discovery/request/index.ts
Normal file
4
src/app/store/discovery/request/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from './request.action';
|
||||
export * from './request.effect';
|
||||
export * from './request.reducer';
|
||||
export * from './request.state';
|
54
src/app/store/discovery/request/request.action.ts
Normal file
54
src/app/store/discovery/request/request.action.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import { Action } from '@ngrx/store';
|
||||
import { DiscoveryModeType } from '@overflow/model/discovery';
|
||||
import { DiscoverySession } from '../../../core/discovery/discovery-session';
|
||||
import { DiscoveryStatusType } from 'src/app/core/type';
|
||||
|
||||
export enum ActionType {
|
||||
RequestDiscover = '[app.discovery] RequestDiscover',
|
||||
|
||||
RequestDiscoverStop = '[app.discovery] RequestDiscoverStop',
|
||||
|
||||
ChangeDiscoveryMode = '[app.discovery] ChangeDiscoveryMode',
|
||||
ChangeDiscoveryStatus = '[app.discovery] ChangeDiscoveryStatus',
|
||||
|
||||
DiscoveryComplete = '[app.discovery] DiscoveryComplete',
|
||||
}
|
||||
|
||||
|
||||
export class RequestDiscover implements Action {
|
||||
readonly type = ActionType.RequestDiscover;
|
||||
|
||||
constructor(public payload: { discoverySession: DiscoverySession }) { }
|
||||
}
|
||||
|
||||
export class ChangeDiscoveryMode implements Action {
|
||||
readonly type = ActionType.ChangeDiscoveryMode;
|
||||
|
||||
constructor(public payload: { discoveryMode: DiscoveryModeType }) { }
|
||||
}
|
||||
|
||||
export class RequestDiscoverStop implements Action {
|
||||
readonly type = ActionType.RequestDiscoverStop;
|
||||
|
||||
constructor(public payload: { discoverySession: DiscoverySession }) { }
|
||||
}
|
||||
|
||||
export class ChangeDiscoveryStatus implements Action {
|
||||
readonly type = ActionType.ChangeDiscoveryStatus;
|
||||
|
||||
constructor(public payload: { discoveryStatus: DiscoveryStatusType }) { }
|
||||
}
|
||||
|
||||
export class DiscoveryComplete implements Action {
|
||||
readonly type = ActionType.DiscoveryComplete;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export type Actions =
|
||||
| RequestDiscover
|
||||
| ChangeDiscoveryMode
|
||||
| RequestDiscoverStop
|
||||
| ChangeDiscoveryStatus
|
||||
| DiscoveryComplete
|
||||
;
|
41
src/app/store/discovery/request/request.effect.ts
Normal file
41
src/app/store/discovery/request/request.effect.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions, Effect, ofType } from '@ngrx/effects';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
ActionType,
|
||||
RequestDiscover,
|
||||
RequestDiscoverStop,
|
||||
ChangeDiscoveryStatus,
|
||||
} from './request.action';
|
||||
import { DiscoveryService } from '../../../service/discovery.service';
|
||||
import { DiscoveryStatusType } from 'src/app/core/type';
|
||||
|
||||
@Injectable()
|
||||
export class RequestEffects {
|
||||
@Effect({ dispatch: false })
|
||||
requestDiscover$ = this.actions$.pipe(
|
||||
ofType<RequestDiscover>(ActionType.RequestDiscover),
|
||||
map((action) => {
|
||||
this.discoveryService.discover(action.payload.discoverySession.discoverRequestInfo);
|
||||
}),
|
||||
);
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
requestDiscoverStop$ = this.actions$.pipe(
|
||||
ofType<RequestDiscoverStop>(ActionType.RequestDiscoverStop),
|
||||
map((action) => action.payload),
|
||||
map((payload) => {
|
||||
this.discoveryService.discoverStop(payload.discoverySession.discoverRequestInfo.requesterID, payload.discoverySession.requestID);
|
||||
})
|
||||
);
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private actions$: Actions,
|
||||
private router: Router,
|
||||
private discoveryService: DiscoveryService,
|
||||
) { }
|
||||
}
|
54
src/app/store/discovery/request/request.reducer.ts
Normal file
54
src/app/store/discovery/request/request.reducer.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import {
|
||||
Actions,
|
||||
ActionType,
|
||||
} from './request.action';
|
||||
|
||||
import {
|
||||
State,
|
||||
initialState,
|
||||
} from './request.state';
|
||||
import { DiscoveryStatusType } from '../../../core/type';
|
||||
|
||||
export function reducer(state: State = initialState, action: Actions): State {
|
||||
switch (action.type) {
|
||||
case ActionType.RequestDiscover: {
|
||||
return {
|
||||
...state,
|
||||
discoverySession: action.payload.discoverySession,
|
||||
discoveryStatus: DiscoveryStatusType.Requested,
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.RequestDiscoverStop: {
|
||||
return {
|
||||
...state,
|
||||
discoveryStatus: DiscoveryStatusType.Stopping,
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.ChangeDiscoveryMode: {
|
||||
return {
|
||||
...state,
|
||||
discoveryMode: action.payload.discoveryMode,
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.ChangeDiscoveryStatus: {
|
||||
return {
|
||||
...state,
|
||||
discoveryStatus: action.payload.discoveryStatus,
|
||||
};
|
||||
}
|
||||
|
||||
case ActionType.DiscoveryComplete: {
|
||||
return {
|
||||
...state,
|
||||
discoverySession: null,
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
27
src/app/store/discovery/request/request.state.ts
Normal file
27
src/app/store/discovery/request/request.state.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { Selector, createSelector } from '@ngrx/store';
|
||||
import { DiscoveryModeType } from '@overflow/model/discovery';
|
||||
import { DiscoveryStatusType } from '../../../core/type';
|
||||
import { DiscoverySession } from '../../../core/discovery/discovery-session';
|
||||
|
||||
export interface State {
|
||||
discoveryMode: DiscoveryModeType | null;
|
||||
discoveryStatus: DiscoveryStatusType | null;
|
||||
|
||||
discoverySession: DiscoverySession | null;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
discoveryMode: null,
|
||||
discoveryStatus: DiscoveryStatusType.Stopped,
|
||||
|
||||
discoverySession: null,
|
||||
};
|
||||
|
||||
|
||||
export function getSelectors<S>(selector: Selector<any, State>) {
|
||||
return {
|
||||
selectDiscoveryMode: createSelector(selector, (state: State) => state.discoveryMode),
|
||||
selectDiscoveryStatus: createSelector(selector, (state: State) => state.discoveryStatus),
|
||||
selectDiscoverySession: createSelector(selector, (state: State) => state.discoverySession),
|
||||
};
|
||||
}
|
38
src/app/store/environment/index.ts
Normal file
38
src/app/store/environment/index.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { Type } from '@angular/core';
|
||||
import {
|
||||
Selector,
|
||||
createSelector,
|
||||
combineReducers
|
||||
} from '@ngrx/store';
|
||||
|
||||
import * as InterfacesStore from './interfaces';
|
||||
import * as UserStore from './user';
|
||||
|
||||
|
||||
export interface State {
|
||||
interfaces: InterfacesStore.State;
|
||||
user: UserStore.State;
|
||||
}
|
||||
|
||||
export const EFFECTS: Type<any>[] = [
|
||||
InterfacesStore.InterfacesEffects,
|
||||
UserStore.UserEffects,
|
||||
];
|
||||
|
||||
export const REDUCER = combineReducers({
|
||||
interfaces: InterfacesStore.reducer,
|
||||
user: UserStore.reducer,
|
||||
});
|
||||
|
||||
export function getSelectors<S>(selector: Selector<any, State>) {
|
||||
return {
|
||||
InterfacesSelector: InterfacesStore.getSelectors(createSelector(
|
||||
selector,
|
||||
(state: State) => state.interfaces,
|
||||
)),
|
||||
UserSelector: UserStore.getSelectors(createSelector(
|
||||
selector,
|
||||
(state: State) => state.user,
|
||||
)),
|
||||
};
|
||||
}
|
4
src/app/store/environment/interfaces/index.ts
Normal file
4
src/app/store/environment/interfaces/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from './interfaces.action';
|
||||
export * from './interfaces.effect';
|
||||
export * from './interfaces.reducer';
|
||||
export * from './interfaces.state';
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user