ing
This commit is contained in:
parent
1be35047cf
commit
a8422cad14
|
@ -98,7 +98,7 @@ export class PopupPanelComponent implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
onOverlayAnimationDone(event: AnimationEvent) {
|
onOverlayAnimationDone(event: AnimationEvent) {
|
||||||
console.log('onOverlayAnimationDone');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
appendOverlay() {
|
appendOverlay() {
|
||||||
|
|
|
@ -30,10 +30,6 @@ export class AutoHeightDirective implements OnInit, OnDestroy, AfterViewInit {
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisible(event) {
|
|
||||||
console.log('visibilitychange');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* forceCalculate
|
* forceCalculate
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +47,6 @@ export class AutoHeightDirective implements OnInit, OnDestroy, AfterViewInit {
|
||||||
const footerElementMargin = this.getfooterElementMargin();
|
const footerElementMargin = this.getfooterElementMargin();
|
||||||
|
|
||||||
this.elementRef.nativeElement.style.height = windowHeight - footerElementMargin - elementOffsetTop + 'px';
|
this.elementRef.nativeElement.style.height = windowHeight - footerElementMargin - elementOffsetTop + 'px';
|
||||||
console.log([windowHeight, elementOffsetTop, elementMarginBottom, footerElementMargin, this.elementRef.nativeElement.style.height]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getElementOffsetTop() {
|
private getElementOffsetTop() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
export * from './discovery';
|
||||||
|
|
||||||
export * from './DiscoverHost';
|
export * from './DiscoverHost';
|
||||||
export * from './DiscoverPort';
|
export * from './DiscoverPort';
|
||||||
export * from './DiscoverService';
|
export * from './DiscoverService';
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { PagesComponent } from './pages/pages.component';
|
||||||
|
import { HomePageComponent } from './pages/home/home-page.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', loadChildren: './pages/pages.module#PagesModule' },
|
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: PagesComponent,
|
||||||
|
children: [
|
||||||
|
{ path: 'home', component: HomePageComponent },
|
||||||
|
]
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes, { useHash: true })],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AppRoutingModule { }
|
export class AppRoutingModule { }
|
||||||
|
|
|
@ -8,14 +8,14 @@ import { EffectsModule } from '@ngrx/effects';
|
||||||
|
|
||||||
|
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { reducers, metaReducers, effects } from '../commons/store';
|
import { REDUCERS, META_REDUCERS, EFFECTS } from './store';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
exports: [
|
exports: [
|
||||||
StoreModule,
|
StoreModule,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
StoreModule.forRoot(reducers, { metaReducers }),
|
StoreModule.forRoot(REDUCERS, { metaReducers: META_REDUCERS }),
|
||||||
/**
|
/**
|
||||||
* @ngrx/router-store keeps router state up-to-date in the store.
|
* @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,
|
maxAge: 50,
|
||||||
logOnly: environment.production,
|
logOnly: environment.production,
|
||||||
}),
|
}),
|
||||||
EffectsModule.forRoot(effects),
|
EffectsModule.forRoot(EFFECTS),
|
||||||
],
|
],
|
||||||
providers: [
|
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 { of, Subscription } from 'rxjs';
|
||||||
import { map, catchError, take } from 'rxjs/operators';
|
import { map, catchError, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ElectronProxyService } from '../commons/service/electron-proxy.service';
|
import { ElectronProxyService } from './service/electron-proxy.service';
|
||||||
import { ProbeService } from '../commons/service/probe.service';
|
|
||||||
import { MenuEvent } from '../commons/type';
|
import { MenuEvent } from '../commons/type';
|
||||||
|
import * as AppStore from './store/app';
|
||||||
|
import * as UserStore from './store/environment/user';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit, OnDestroy {
|
export class AppComponent implements OnInit, AfterContentInit, AfterViewInit, OnDestroy {
|
||||||
title = 'scanner-app';
|
title = 'scanner-app';
|
||||||
showTitleBar: boolean;
|
showTitleBar: boolean;
|
||||||
block: boolean;
|
block: boolean;
|
||||||
|
@ -25,6 +28,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private changeDetector: ChangeDetectorRef,
|
private changeDetector: ChangeDetectorRef,
|
||||||
|
private store: Store<any>,
|
||||||
private electronProxyService: ElectronProxyService,
|
private electronProxyService: ElectronProxyService,
|
||||||
) {
|
) {
|
||||||
// this.showTitleBar = !__LINUX__;
|
// this.showTitleBar = !__LINUX__;
|
||||||
|
@ -33,6 +37,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.store.dispatch(new AppStore.AppInit());
|
||||||
|
this.store.dispatch(new UserStore.SetMemberID({ memberID: 'scannerUser' }));
|
||||||
// this.probeService.connect();
|
// this.probeService.connect();
|
||||||
this.electronProxyService.sendReady(performance.now());
|
this.electronProxyService.sendReady(performance.now());
|
||||||
this.menuSubscription = this.electronProxyService.menuObservable()
|
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 {
|
ngOnDestroy(): void {
|
||||||
|
this.store.dispatch(new AppStore.AppDestroy());
|
||||||
|
|
||||||
this.menuSubscription.unsubscribe();
|
this.menuSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,30 +4,50 @@ import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
import { CommonsUIModule } from '@overflow/commons/ui/commons-ui.module';
|
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 { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppStoreModule } from './app-store.module';
|
import { AppStoreModule } from './app-store.module';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
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({
|
@NgModule({
|
||||||
declarations: [
|
|
||||||
AppComponent
|
|
||||||
],
|
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
|
|
||||||
|
PerfectScrollbarModule,
|
||||||
|
|
||||||
CommonsUIModule,
|
CommonsUIModule,
|
||||||
CommonsModule,
|
|
||||||
|
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
AppStoreModule,
|
AppStoreModule,
|
||||||
],
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
...COMPONENTS,
|
||||||
|
...PAGES,
|
||||||
|
],
|
||||||
providers: [
|
providers: [
|
||||||
...SERVICES,
|
...SERVICES,
|
||||||
|
{
|
||||||
|
provide: PERFECT_SCROLLBAR_CONFIG,
|
||||||
|
useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG
|
||||||
|
}
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
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">
|
<!-- <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>
|
<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> -->
|
</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="description">{{selected.network || ''}}</div>
|
||||||
<div _ngcontent-c1="" class="title">{{selected.friendlyName || ''}}</div>
|
<div _ngcontent-c1="" class="title">{{selected.friendlyName || ''}}</div>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #loading>
|
<ng-template *ngIf="pending$ | async">
|
||||||
Loading...
|
Loading...
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<svg _ngcontent-c1="" aria-hidden="true" class="octicon dropdownArrow" version="1.1" viewBox="0 0 12 16" width="16px"
|
<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 { DropdownPanelComponent } from '@overflow/commons/ui/component/primeng';
|
||||||
import { DiscoverHost, Zone } from '@overflow/model/discovery';
|
import { DiscoverHost, Zone } from '@overflow/model/discovery';
|
||||||
import { toMetaIPType, MetaIPTypeEnum, MetaPortTypeEnum } from '@overflow/model/meta';
|
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');
|
const IPCIDR = require('ip-cidr');
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-scanner-setting-dropdown',
|
selector: 'app-layout-toolbar-scanner-setting-dropdown',
|
||||||
templateUrl: './scanner-setting-dropdown.component.html',
|
templateUrl: './scanner-setting-dropdown.component.html',
|
||||||
styleUrls: ['./scanner-setting-dropdown.component.scss'],
|
styleUrls: ['./scanner-setting-dropdown.component.scss'],
|
||||||
})
|
})
|
||||||
|
|
||||||
export class ScannerSettingDropdownComponent implements OnInit {
|
export class ScannerSettingDropdownComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input() blockTarget: any;
|
@Input() blockTarget: any;
|
||||||
@Output() ready = new EventEmitter<DiscoverHost>();
|
|
||||||
@ViewChild('panel') panel: DropdownPanelComponent;
|
@ViewChild('panel') panel: DropdownPanelComponent;
|
||||||
|
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
|
@ -35,17 +41,36 @@ export class ScannerSettingDropdownComponent implements OnInit {
|
||||||
|
|
||||||
validIPArray: string[];
|
validIPArray: string[];
|
||||||
|
|
||||||
|
zoneSubscription: Subscription | null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private discoveryConfigService: DiscoveryConfigService
|
private store: Store<any>,
|
||||||
|
private changeDetector: ChangeDetectorRef,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.discoveryConfigService.zone.subscribe(res => {
|
this.zoneSubscription = this.store.pipe(
|
||||||
this.zone = res as Zone;
|
select(AppStore.DiscoverySelector.ConfigSelector.selectZone),
|
||||||
this.setDefault();
|
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 {
|
setDefault(): void {
|
||||||
|
@ -66,6 +91,8 @@ export class ScannerSettingDropdownComponent implements OnInit {
|
||||||
this.portErrMsg = '';
|
this.portErrMsg = '';
|
||||||
|
|
||||||
this.setSummary();
|
this.setSummary();
|
||||||
|
|
||||||
|
this.changeDetector.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
validateIP(value: string, idx: number) {
|
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 {
|
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 { Host } from '@overflow/model/discovery';
|
||||||
import { PingResult } from '@overflow/model/ping';
|
import { PingResult } from '@overflow/model/ping';
|
||||||
|
|
||||||
import { ProbeService } from '../../service/probe.service';
|
|
||||||
import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.directive';
|
import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.directive';
|
||||||
|
import { PingService } from '../../../service/ping.service';
|
||||||
|
import { PingOption } from '@overflow/model/config/ping';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-host-detail',
|
selector: 'app-target-detail-host',
|
||||||
templateUrl: './host-detail.component.html',
|
templateUrl: './host.component.html',
|
||||||
styleUrls: ['./host-detail.component.scss'],
|
styleUrls: ['./host.component.scss'],
|
||||||
})
|
})
|
||||||
export class HostDetailComponent implements OnChanges {
|
export class HostComponent implements OnChanges {
|
||||||
@Input() host: Host;
|
@Input() host: Host;
|
||||||
|
|
||||||
@ViewChildren(AutoHeightDirective) autoHeightDirectives: QueryList<AutoHeightDirective>;
|
@ViewChildren(AutoHeightDirective) autoHeightDirectives: QueryList<AutoHeightDirective>;
|
||||||
|
@ -32,7 +32,7 @@ export class HostDetailComponent implements OnChanges {
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private probeService: ProbeService,
|
private pingService: PingService,
|
||||||
) {
|
) {
|
||||||
this.pingWaiting = false;
|
this.pingWaiting = false;
|
||||||
this.count = 5;
|
this.count = 5;
|
||||||
|
@ -48,14 +48,13 @@ export class HostDetailComponent implements OnChanges {
|
||||||
doPing() {
|
doPing() {
|
||||||
this.pingWaiting = true;
|
this.pingWaiting = true;
|
||||||
|
|
||||||
const option = {
|
const option: PingOption = {
|
||||||
Count: this.count,
|
count: this.count,
|
||||||
Interval: this.interval,
|
interval: this.interval,
|
||||||
Deadline: this.deadline,
|
deadline: this.deadline,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.probeService
|
this.pingService.pingHost(this.host, option)
|
||||||
.call<PingResult>('PingService.PingHost', this.host, option)
|
|
||||||
.pipe(
|
.pipe(
|
||||||
map((pingResult: PingResult) => {
|
map((pingResult: PingResult) => {
|
||||||
if (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 { 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 { 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 { 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({
|
@Component({
|
||||||
selector: 'app-service-detail',
|
selector: 'app-target-detail-service',
|
||||||
templateUrl: './service-detail.component.html',
|
templateUrl: './service.component.html',
|
||||||
styleUrls: ['./service-detail.component.scss'],
|
styleUrls: ['./service.component.scss'],
|
||||||
})
|
})
|
||||||
export class ServiceDetailComponent implements OnChanges {
|
export class ServiceComponent implements OnChanges {
|
||||||
|
|
||||||
@Input() service: Service;
|
@Input() service: Service;
|
||||||
|
|
||||||
|
@ -28,7 +32,7 @@ export class ServiceDetailComponent implements OnChanges {
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private probeService: ProbeService
|
private pingService: PingService
|
||||||
) {
|
) {
|
||||||
this.pingWaiting = false;
|
this.pingWaiting = false;
|
||||||
this.count = 5;
|
this.count = 5;
|
||||||
|
@ -44,14 +48,13 @@ export class ServiceDetailComponent implements OnChanges {
|
||||||
doPing() {
|
doPing() {
|
||||||
this.pingWaiting = true;
|
this.pingWaiting = true;
|
||||||
|
|
||||||
const option = {
|
const option: PingOption = {
|
||||||
Count: this.count,
|
count: this.count,
|
||||||
Interval: this.interval,
|
interval: this.interval,
|
||||||
Deadline: this.deadline,
|
deadline: this.deadline,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.probeService
|
this.pingService.pingService(this.service, option)
|
||||||
.call<PingResult>('PingService.PingService', this.service, option)
|
|
||||||
.pipe(
|
.pipe(
|
||||||
map((pingResult: PingResult) => {
|
map((pingResult: PingResult) => {
|
||||||
console.log(pingResult);
|
console.log(pingResult);
|
|
@ -5,11 +5,11 @@ import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.
|
||||||
const IPCIDR = require('ip-cidr');
|
const IPCIDR = require('ip-cidr');
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-zone-detail',
|
selector: 'app-target-detail-zone',
|
||||||
templateUrl: './zone-detail.component.html',
|
templateUrl: './zone.component.html',
|
||||||
styleUrls: ['./zone-detail.component.scss'],
|
styleUrls: ['./zone.component.scss'],
|
||||||
})
|
})
|
||||||
export class ZoneDetailComponent implements OnInit {
|
export class ZoneComponent implements OnInit {
|
||||||
|
|
||||||
@Input() zone: Zone;
|
@Input() zone: Zone;
|
||||||
@Output() otherHostSelect = new EventEmitter<Host>();
|
@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>
|
<div class="target-display">
|
||||||
<svg #discoveryTarget width="100%" height="100%">
|
<svg #displayTarget width="100%" height="100%">
|
||||||
<g>
|
<g>
|
||||||
<g *ngFor="let link of links">
|
<g *ngFor="let link of links">
|
||||||
<g class="link-container" [ngClass]="'link-'+link.target.group" [attr.sourceId]="link.source.id"
|
<g class="link-container" [ngClass]="'link-'+link.target.group" [attr.sourceId]="link.source.id"
|
||||||
|
@ -51,15 +51,18 @@
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</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 class="ui-map-info-row ui-border-bottom">
|
||||||
<div>Total Hosts: </div>{{discoveryResult.totalHosts}}
|
<div>Total Hosts: </div>{{displaySummary.totalHosts}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-map-info-row ui-border-bottom">
|
<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>
|
||||||
<div class="ui-map-info-row">
|
<div class="ui-map-info-row">
|
||||||
<div>Elapsed: </div>{{discoveryResult.elapsedTime}}
|
<div>Elapsed: </div>{{displaySummary.elapsedTime}}
|
||||||
</div>
|
</div>
|
||||||
</p-card>
|
</p-card>
|
||||||
</div>
|
</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>
|
<of-p-div>
|
||||||
<div *ngIf="showIntro" class="home-start">
|
<div *ngIf="(showWelcomPage$ | async)" class="home-start">
|
||||||
<div class="start-button" (click)="discoveryConfigService.setDiscoveryStatus('Started')">
|
<div class="start-button" (click)="requestDiscover()">
|
||||||
<svg version="1.1" viewBox="0 0 200 210">
|
<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
|
<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" />
|
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">
|
<img src="assets/image/logo/overFlow_CI_white_90.png">
|
||||||
<h1>Network Scanner </h1>
|
<h1>Network Scanner </h1>
|
||||||
<br>
|
<br>
|
||||||
<b>를 이용해 주셔서 감사합니다.</b>
|
<b>이용해 주셔서 감사합니다.</b>
|
||||||
<br> 좌측의 버튼을 클릭 하시면 기본 설정으로 스캐닝이 시작 됩니다. 설정의 변경을 원하시면 상단의 설정 영역을 클릭하여 변경이 가능합니다.
|
<br> 좌측의 버튼을 클릭 하시면 기본 설정으로 스캐닝이 시작 됩니다. 설정의 변경을 원하시면 상단의 설정 영역을 클릭하여 변경이 가능합니다.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!showIntro" class="discovery-container">
|
<div *ngIf="!(showWelcomPage$ | async)" class="display-container">
|
||||||
<svg #discoveryTarget width="100%" height="100%">
|
<app-target-display></app-target-display>
|
||||||
<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>
|
</div>
|
||||||
</of-p-div>
|
</of-p-div>
|
||||||
|
|
||||||
<p-confirmDialog></p-confirmDialog>
|
<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"
|
<p-dialog [showHeader]="false" [(visible)]="stopping" [modal]="true" [responsive]="false" [width]="300" [height]="100"
|
||||||
[minY]="70" [closeOnEscape]="false" [closable]="false">
|
[minY]="70" [closeOnEscape]="false" [closable]="false">
|
||||||
<div class="ui-dialog-text-center">Discovery is being stopped...</div>
|
<div class="ui-dialog-text-center">Discovery is being stopped...</div>
|
||||||
</p-dialog>
|
</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;
|
padding: .6em .75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.discovery-container {
|
.display-container {
|
||||||
height: 100vh;
|
position: relative; // height: 100vh;
|
||||||
margin: -0.6em -0.9em -0.7em -0.9em; //-0.5em -0.75em;
|
// margin: -0.6em -0.9em -0.7em -0.9em; //-0.5em -0.75em;
|
||||||
padding: 0;
|
// padding: 0;
|
||||||
box-sizing: border-box;
|
// box-sizing: border-box;
|
||||||
display: flex;
|
// display: flex;
|
||||||
align-items: center;
|
// align-items: center;
|
||||||
justify-content: center;
|
// justify-content: center;
|
||||||
min-width: 400px; //text-align: 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-dialog-text-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-toolbar>
|
||||||
<app-nic-dropdown [blockTarget]="pagesContent" (select)="onNICSelect($event)"></app-nic-dropdown>
|
<app-layout-toolbar-nic-dropdown [blockTarget]="pagesContent"></app-layout-toolbar-nic-dropdown>
|
||||||
<app-scanner-setting-dropdown [blockTarget]="pagesContent" (ready)="onConfigReady($event)"></app-scanner-setting-dropdown>
|
<app-layout-toolbar-scanner-setting-dropdown [blockTarget]="pagesContent"></app-layout-toolbar-scanner-setting-dropdown>
|
||||||
<ng-template #play>
|
<ng-template #play>
|
||||||
<div class="toolbar-button push-pull-button" style="width: 32px">
|
<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">
|
<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
|
<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>
|
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>
|
</ng-template>
|
||||||
|
|
||||||
<!-- Stop button -->
|
<!-- Stop button -->
|
||||||
<div class="toolbar-button push-pull-button" style="width: 36px" *ngIf="discoveryStatus === 'Started' else play">
|
<div class="toolbar-button push-pull-button" style="width: 36px" *ngIf="(discoveryStatus$ | async) === 'Started' else play">
|
||||||
<button class="button-component" type="button" (click)="onStop()">
|
<button class="button-component" type="button" (click)="requestDiscoverStop()">
|
||||||
<svg aria-hidden="true" class="octicon icon" version="1.1" viewBox="0 0 15 17">
|
<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
|
<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" />
|
C15,15.5,14.4,16.1,13.6,16.1z" />
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading image -->
|
<!-- 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">
|
<button class="button-component" type="button">
|
||||||
<svg aria-hidden="true" class="octicon icon spin" version="1.1" viewBox="0 0 15 15">
|
<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
|
<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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="discoveryMode" class="ui-menu-mode">
|
<div *ngIf="(discoveryMode$ | async)" class="ui-menu-mode">
|
||||||
<span>{{discoveryMode}} Mode</span>
|
<span>{{discoveryMode$ | async}} Mode</span>
|
||||||
</div>
|
</div>
|
||||||
</app-toolbar>
|
</app-toolbar>
|
||||||
|
|
||||||
|
@ -42,4 +42,7 @@
|
||||||
<div id="pages-content">
|
<div id="pages-content">
|
||||||
<router-outlet #o="outlet"></router-outlet>
|
<router-outlet #o="outlet"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
</of-p-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
|
Component, AfterViewInit, ElementRef, Renderer, ViewChild, OnDestroy, OnInit, NgZone
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { DiscoverHost, Zone } from '@overflow/model/discovery';
|
import { Store, select } from '@ngrx/store';
|
||||||
import { DiscoveryConfigService, DiscoveryStatusType } from '../../commons/service/discovery-config.service';
|
|
||||||
|
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 {
|
enum MenuOrientation {
|
||||||
STATIC,
|
STATIC,
|
||||||
|
@ -57,17 +66,18 @@ export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
|
||||||
|
|
||||||
|
|
||||||
rippleInitListener: any;
|
rippleInitListener: any;
|
||||||
|
|
||||||
rippleMouseDownListener: any;
|
rippleMouseDownListener: any;
|
||||||
|
|
||||||
discoveryMode: string;
|
discoveryMode$ = this.store.pipe(select(AppStore.DiscoverySelector.RequestSelector.selectDiscoveryMode));
|
||||||
discoveryStatus: DiscoveryStatusType;
|
discoveryStatus$ = this.store.pipe(select(AppStore.DiscoverySelector.RequestSelector.selectDiscoveryStatus));
|
||||||
|
blockPagesContent$ = this.store.pipe(select(AppStore.UISelector.LayoutSelector.selectBlockPagesContent));
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public renderer: Renderer,
|
public renderer: Renderer,
|
||||||
|
private store: Store<any>,
|
||||||
public zone: NgZone,
|
public zone: NgZone,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private discoveryConfigService: DiscoveryConfigService,
|
private probeService: ProbeService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,14 +86,6 @@ export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.zone.runOutsideAngular(() => { this.bindRipple(); });
|
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() {
|
bindRipple() {
|
||||||
|
@ -365,20 +367,12 @@ export class PagesComponent implements AfterViewInit, OnDestroy, OnInit {
|
||||||
this.router.navigate([command]);
|
this.router.navigate([command]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onNICSelect(zone: Zone) {
|
requestDiscover() {
|
||||||
this.discoveryConfigService.setZone(zone);
|
DiscoverySession.requestDiscover(this.store, this.probeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfigReady(discoverHost: DiscoverHost) {
|
requestDiscoverStop() {
|
||||||
this.discoveryConfigService.setDiscoverHost(discoverHost);
|
DiscoverySession.requestDiscoverStop(this.store);
|
||||||
}
|
|
||||||
|
|
||||||
onStart() {
|
|
||||||
this.discoveryConfigService.setDiscoveryStatus(DiscoveryStatusType.Started);
|
|
||||||
}
|
|
||||||
|
|
||||||
onStop() {
|
|
||||||
this.discoveryConfigService.setDiscoveryStatus(DiscoveryStatusType.Stopping);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 { Injectable } from '@angular/core';
|
||||||
import Dexie from 'dexie';
|
import Dexie from 'dexie';
|
||||||
import { LaunchState } from '../model';
|
import { LaunchState } from '../../commons/model';
|
||||||
|
|
||||||
const DatabaseVersion = 1;
|
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 { Store } from '@ngrx/store';
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
import { MenuEvent } from '../type';
|
import { MenuEvent } from '../../commons/type';
|
||||||
import { LaunchState } from '../model';
|
|
||||||
import { LaunchService } from './launch.service';
|
import { LaunchService } from './launch.service';
|
||||||
|
import { LaunchState } from '../../commons/model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
|
@ -2,12 +2,16 @@ import { DatabaseService } from './database.service';
|
||||||
import { ElectronProxyService } from './electron-proxy.service';
|
import { ElectronProxyService } from './electron-proxy.service';
|
||||||
import { LaunchService } from './launch.service';
|
import { LaunchService } from './launch.service';
|
||||||
import { ProbeService } from './probe.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 = [
|
export const SERVICES = [
|
||||||
DatabaseService,
|
DatabaseService,
|
||||||
ElectronProxyService,
|
ElectronProxyService,
|
||||||
LaunchService,
|
LaunchService,
|
||||||
ProbeService,
|
ProbeService,
|
||||||
DiscoveryConfigService
|
MachineService,
|
||||||
|
DiscoveryService,
|
||||||
|
PingService,
|
||||||
];
|
];
|
|
@ -2,13 +2,13 @@ import { Injectable } from '@angular/core';
|
||||||
import { Observable, defer } from 'rxjs';
|
import { Observable, defer } from 'rxjs';
|
||||||
|
|
||||||
import { DatabaseService } from './database.service';
|
import { DatabaseService } from './database.service';
|
||||||
import { LaunchState } from '../model';
|
import { LaunchState } from '../../commons/model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class LaunchService {
|
export class LaunchService {
|
||||||
public constructor(private readonly databaseService: DatabaseService) {}
|
public constructor(private readonly databaseService: DatabaseService) { }
|
||||||
|
|
||||||
public save(launchState: LaunchState): Observable<number> {
|
public save(launchState: LaunchState): Observable<number> {
|
||||||
return defer(async () => {
|
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