This commit is contained in:
crusader 2018-10-12 14:14:02 +09:00
parent 673c9cab57
commit 4c630efc84
54 changed files with 416 additions and 283 deletions

View File

@ -2,6 +2,8 @@ import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { CommonsUIModule } from '@overflow/commons/ui/commons-ui.module';
import {
@ -19,6 +21,7 @@ import { COMPONENTS } from './component';
import { PAGES } from './pages';
import { SERVICES } from './service';
import { I18nService } from './service/i18n.service';
const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
suppressScrollX: true
@ -29,7 +32,12 @@ const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
imports: [
BrowserModule,
BrowserAnimationsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useExisting: I18nService,
}
}),
PerfectScrollbarModule,
CommonsUIModule,

View File

@ -7,12 +7,12 @@ import {
} from './menu';
import {
COMPONENTS as TARGET_COMPONENTS
} from './target';
COMPONENTS as INFRA_COMPONENTS
} from './infra';
export const COMPONENTS = [
...LAYOUT_COMPONENTS,
...MENU_COMPONENTS,
...TARGET_COMPONENTS,
...INFRA_COMPONENTS,
];

View File

@ -11,7 +11,7 @@ import { PingService } from '../../../service/ping.service';
import { PingOption } from '@overflow/model/config/ping';
@Component({
selector: 'app-target-detail-host',
selector: 'app-infra-detail-host',
templateUrl: './host.component.html',
styleUrls: ['./host.component.scss'],
})

View File

@ -0,0 +1,26 @@
<div class="ui-g">
<div class="ui-g-12">
<ng-container [ngSwitch]="selectedInfra.group">
<ng-container *ngSwitchCase="'zone'">
<app-infra-detail-zone [zone]="selectedInfra.infra" (otherHostSelect)="otherHostSelected($event)"></app-infra-detail-zone>
</ng-container>
<ng-container *ngSwitchCase="'host'">
<app-infra-detail-host [host]="selectedInfra.infra" (ping)="ping.emit($event)"></app-infra-detail-host>
</ng-container>
<ng-container *ngSwitchCase="'service'">
<app-infra-detail-service [service]="selectedInfra.infra" (ping)="ping.emit($event)"></app-infra-detail-service>
</ng-container>
<ng-container *ngSwitchDefault>
</ng-container>
</ng-container>
</div>
</div>

View File

@ -4,13 +4,13 @@ import { Host, Port, Service } from '@overflow/model/discovery';
@Component({
selector: 'app-target-detail-node',
selector: 'app-infra-detail-node',
templateUrl: './node.component.html',
styleUrls: ['./node.component.scss'],
})
export class NodeComponent {
@Input() selectedTarget: { group: string, target: Host | Port | Service } | null;
@Input() selectedInfra: { group: string, infra: Host | Port | Service } | null;
@Output() otherHostSelect = new EventEmitter<Host>();
@Output() ping = new EventEmitter<PingResult>();

View File

@ -11,7 +11,7 @@ import { PingService } from '../../../service/ping.service';
import { PingOption } from '@overflow/model/config/ping';
@Component({
selector: 'app-target-detail-service',
selector: 'app-infra-detail-service',
templateUrl: './service.component.html',
styleUrls: ['./service.component.scss'],
})

View File

@ -5,7 +5,7 @@ import { AutoHeightDirective } from '@overflow/commons/ui/directive/auto-height.
const IPCIDR = require('ip-cidr');
@Component({
selector: 'app-target-detail-zone',
selector: 'app-infra-detail-zone',
templateUrl: './zone.component.html',
styleUrls: ['./zone.component.scss'],
})

View File

@ -1,8 +1,8 @@
<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 [ngSwitch]="(infraDisplayType$ | async)">
<app-infra-display-map *ngSwitchCase="'MAP'"></app-infra-display-map>
<app-infra-display-grid *ngSwitchCase="'GRID'"></app-infra-display-grid>
<app-infra-display-tree *ngSwitchCase="'TREE'"></app-infra-display-tree>
</ng-container>
@ -10,8 +10,8 @@
<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 *ngIf="selectedInfra">
<app-infra-detail-node [selectedInfra]="selectedInfra" (otherHostSelect)="otherHostSelected($event)"></app-infra-detail-node>
</div>
</p-sidebar>

View File

@ -1,4 +1,4 @@
/deep/ .target-display {
/deep/ .infra-display {
width: 100%;
height: 100vh;
margin: -0.6em -0.9em -0.7em -0.9em; //-0.5em -0.75em;

View File

@ -13,22 +13,22 @@ import { map, catchError, take, tap } from 'rxjs/operators';
import { Port, Service, Host } from '@overflow/model/discovery';
import { TargetDisplayType, DiscoveryStatusType } from '../../../core/type';
import { InfraDisplayType, DiscoveryStatusType } from '../../../core/type';
import * as AppStore from '../../../store';
import * as TargetStore from '../../../store/target/target';
import * as InfraStore from '../../../store/infra/infra';
@Component({
selector: 'app-target-display',
selector: 'app-infra-display',
templateUrl: './display.component.html',
styleUrls: ['./display.component.scss']
})
export class DisplayComponent implements OnInit, AfterContentInit, OnDestroy {
private targetDisplayType$: Observable<TargetDisplayType>;
private infraDisplayType$: Observable<InfraDisplayType>;
displaySidebar = false;
selectedTargetSubscription: Subscription | null;
selectedTarget: { group: string, target: Host | Port | Service } | null;
selectedInfraSubscription: Subscription | null;
selectedInfra: { group: string, infra: Host | Port | Service } | null;
displayDiscoveryStopping: boolean;
discoveryStatusSubscription: Subscription | null;
@ -42,18 +42,18 @@ export class DisplayComponent implements OnInit, AfterContentInit, OnDestroy {
ngOnInit(): void {
const __this = this;
this.targetDisplayType$ = this.store.pipe(select(AppStore.TargetSelector.TargetSelector.selectTargetDisplayType));
this.infraDisplayType$ = this.store.pipe(select(AppStore.InfraSelector.InfraSelector.selectInfraDisplayType));
this.selectedTargetSubscription = this.store.pipe(
select(AppStore.TargetSelector.TargetSelector.selectSelectedTarget)
this.selectedInfraSubscription = this.store.pipe(
select(AppStore.InfraSelector.InfraSelector.selectSelectedInfra)
).pipe(
map((_selectedTarget) => {
if (null === _selectedTarget) {
map((_selectedInfra) => {
if (null === _selectedInfra) {
__this.displaySidebar = false;
__this.selectedTarget = null;
__this.selectedInfra = null;
} else {
__this.displaySidebar = true;
__this.selectedTarget = _selectedTarget;
__this.selectedInfra = _selectedInfra;
}
__this.changeDetector.detectChanges();
}),
@ -84,8 +84,8 @@ export class DisplayComponent implements OnInit, AfterContentInit, OnDestroy {
}
ngOnDestroy(): void {
if (null !== this.selectedTargetSubscription) {
this.selectedTargetSubscription.unsubscribe();
if (null !== this.selectedInfraSubscription) {
this.selectedInfraSubscription.unsubscribe();
}
if (null !== this.discoveryStatusSubscription) {
this.discoveryStatusSubscription.unsubscribe();
@ -93,7 +93,7 @@ export class DisplayComponent implements OnInit, AfterContentInit, OnDestroy {
}
onHideDetail() {
this.store.dispatch(new TargetStore.ChangeSelectedTarget(null));
this.store.dispatch(new InfraStore.ChangeSelectedInfra(null));
}
}

View File

@ -8,7 +8,7 @@ import {
import { Store } from '@ngrx/store';
@Component({
selector: 'app-target-display-grid',
selector: 'app-infra-display-grid',
templateUrl: './grid.component.html',
styleUrls: ['./grid.component.scss']
})

View File

@ -1,5 +1,5 @@
<div class="target-display">
<svg #displayTarget width="100%" height="100%">
<div class="infra-display">
<svg #displayInfra width="100%" height="100%">
<g>
<g *ngFor="let link of links">
<g class="link-container" [ngClass]="'link-'+link.target.group" [attr.sourceId]="link.source.id"

View File

@ -24,7 +24,7 @@ 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 InfraStore from '../../../store/infra/infra';
import * as UILayoutStore from '../../../store/ui/layout';
import { DiscoverySession } from '../../../core/discovery/discovery-session';
import { DiscoveryMessageType } from 'src/app/core/type';
@ -92,7 +92,7 @@ export class DisplaySummary {
}
@Component({
selector: 'app-target-display-map',
selector: 'app-infra-display-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss']
})
@ -109,26 +109,26 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
selectedNode: Node | null = null;
@ViewChild('displayTarget') set displayTarget(content: ElementRef) {
this.displayTargetRef = content;
this.store.dispatch(new TargetStore.ChangeTargetDisplayElementRef({ targetDisplayElementRef: content }));
@ViewChild('displayInfra') set displayInfra(content: ElementRef) {
this.displayInfraRef = content;
this.store.dispatch(new InfraStore.ChangeInfraDisplayElementRef({ infraDisplayElementRef: content }));
}
private displayTargetRef: ElementRef;
private displayInfraRef: ElementRef;
public simulation: d3.Simulation<Node, Link> | undefined;
private zoomBehavior: d3.ZoomBehavior<Element, {}>;
private displayTargetWidth: number;
private displayTargetHeight: number;
private displayInfraWidth: number;
private displayInfraHeight: 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;
refreshInfraDisplaySubscription: Subscription | null = null;
infraSubscription: Subscription | null = null;
infraObservable: Observable<void>;
selectedInfraSubscription: Subscription | null = null;
discoverySubscription: Subscription | null = null;
@ -146,13 +146,13 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
this.minScale = 0.7;
const __this = this;
this.targetObservable = this.store.pipe(
this.infraObservable = 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);
const hosts = AppStore.InfraSelector.InfraSelector.selectHosts(state);
const ports = AppStore.InfraSelector.InfraSelector.selectPorts(state);
const services = AppStore.InfraSelector.InfraSelector.selectServices(state);
__this.initMapDisplay(zone, hosts, ports, services);
}),
@ -169,12 +169,12 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
@HostListener('window:resize', ['$event'])
onResize(event) {
if (undefined !== this.displayTargetRef) {
this.displayTargetWidth = this.displayTargetRef.nativeElement.clientWidth;
this.displayTargetHeight = this.displayTargetRef.nativeElement.clientHeight;
if (undefined !== this.displayInfraRef) {
this.displayInfraWidth = this.displayInfraRef.nativeElement.clientWidth;
this.displayInfraHeight = this.displayInfraRef.nativeElement.clientHeight;
this.zoneNode.fx = this.displayTargetWidth / 2;
this.zoneNode.fy = this.displayTargetHeight / 2;
this.zoneNode.fx = this.displayInfraWidth / 2;
this.zoneNode.fy = this.displayInfraHeight / 2;
this.simulationRestart(false);
}
@ -242,14 +242,14 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
}),
).subscribe();
this.refreshTargetDisplaySubscription = this.store.pipe(
select(AppStore.TargetSelector.TargetSelector.selectRefreshTargetDisplay),
this.refreshInfraDisplaySubscription = this.store.pipe(
select(AppStore.InfraSelector.InfraSelector.selectRefreshInfraDisplay),
filter(v => !!v),
map((refreshTargetDisplay: boolean) => {
if (!refreshTargetDisplay) {
map((refreshInfraDisplay: boolean) => {
if (!refreshInfraDisplay) {
return;
}
__this.targetObservable.subscribe();
__this.infraObservable.subscribe();
}),
catchError(error => {
console.log(error);
@ -257,11 +257,11 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
}),
).subscribe();
this.selectedTargetSubscription = this.store.pipe(
select(AppStore.TargetSelector.TargetSelector.selectSelectedTarget)
this.selectedInfraSubscription = this.store.pipe(
select(AppStore.InfraSelector.InfraSelector.selectSelectedInfra)
).pipe(
map((selectedTarget) => {
if (null === selectedTarget) {
map((selectedInfra) => {
if (null === selectedInfra) {
__this.onHideDetail();
return;
} else {
@ -293,26 +293,26 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
}
ngAfterContentInit(): void {
this.displayTargetWidth = this.displayTargetRef.nativeElement.clientWidth;
this.displayTargetHeight = this.displayTargetRef.nativeElement.clientHeight;
this.displayInfraWidth = this.displayInfraRef.nativeElement.clientWidth;
this.displayInfraHeight = this.displayInfraRef.nativeElement.clientHeight;
this.targetObservable.subscribe();
this.infraObservable.subscribe();
}
ngOnDestroy(): void {
this.store.dispatch(new TargetStore.ChangeTargetDisplayElementRef({ targetDisplayElementRef: null }));
this.store.dispatch(new InfraStore.ChangeInfraDisplayElementRef({ infraDisplayElementRef: null }));
if (null !== this.targetSubscription) {
this.targetSubscription.unsubscribe();
if (null !== this.infraSubscription) {
this.infraSubscription.unsubscribe();
}
if (null !== this.refreshTargetDisplaySubscription) {
this.refreshTargetDisplaySubscription.unsubscribe();
if (null !== this.refreshInfraDisplaySubscription) {
this.refreshInfraDisplaySubscription.unsubscribe();
}
if (null !== this.discoverySessionSubscription) {
this.discoverySessionSubscription.unsubscribe();
}
if (null !== this.selectedTargetSubscription) {
this.selectedTargetSubscription.unsubscribe();
if (null !== this.selectedInfraSubscription) {
this.selectedInfraSubscription.unsubscribe();
}
if (null !== this.preventBrowserCloseSubscription) {
this.preventBrowserCloseSubscription.unsubscribe();
@ -360,7 +360,7 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
return;
}
const svg = d3.select(this.displayTargetRef.nativeElement);
const svg = d3.select(this.displayInfraRef.nativeElement);
this.zoomBehavior = d3.zoom()
.scaleExtent([0.2, 4])
@ -376,7 +376,7 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
.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('center', d3.forceCenter(this.displayInfraWidth / 2, this.displayInfraHeight / 2))
.force('collision', d3.forceCollide().radius(function (node: Node) {
return node.r * 1.2;
}))
@ -391,7 +391,7 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
this.simulation
.nodes(this.nodes)
.force('link', d3.forceLink(this.links).distance(150))
.force('center', d3.forceCenter(this.displayTargetWidth / 2, this.displayTargetHeight / 2))
.force('center', d3.forceCenter(this.displayInfraWidth / 2, this.displayInfraHeight / 2))
.alpha(1)
.restart()
;
@ -400,8 +400,8 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
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');
const nodeElements = d3.select(this.displayInfraRef.nativeElement).selectAll('.node-container');
const linkElements = d3.select(this.displayInfraRef.nativeElement).selectAll('.link-container');
function getNodeFromElement(element: Element): Node | null {
const container = d3.select(element);
@ -480,7 +480,7 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
const nodeElement = this as Element;
const node = getNodeFromElement(nodeElement);
if (null === node || 'zone' === node.group) {
__this.onTargetClick(node);
__this.onInfraClick(node);
return;
}
@ -536,14 +536,14 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
});
__this.onTargetClick(node);
__this.onInfraClick(node);
});
// Highlight
const displayTarget = d3.select(this.displayTargetRef.nativeElement);
displayTarget.on('click', function () {
const displayInfra = d3.select(this.displayInfraRef.nativeElement);
displayInfra.on('click', function () {
__this.selectedNode = null;
__this.store.dispatch(new TargetStore.ChangeSelectedTarget(null));
__this.store.dispatch(new InfraStore.ChangeSelectedInfra(null));
nodeElements.each(function () {
const _thisElement = this as Element;
@ -649,11 +649,11 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
}
zoomToFit(paddingPercent, transitionDuration) {
const root = d3.select(this.displayTargetRef.nativeElement);
const root = d3.select(this.displayInfraRef.nativeElement);
const bounds = root.node().getBBox();
const fullWidth = this.displayTargetWidth;
const fullHeight = this.displayTargetHeight;
const fullWidth = this.displayInfraWidth;
const fullHeight = this.displayInfraHeight;
const width = bounds.width;
const height = bounds.height;
@ -681,7 +681,7 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
.call(this.zoomBehavior.transform, d3.zoomIdentity.translate(translate[0], translate[1]).scale(scale));
}
onTargetClick(node: Node) {
onInfraClick(node: Node) {
console.log(node);
switch (node.group) {
@ -709,9 +709,9 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
break;
}
this.store.dispatch(new TargetStore.ChangeSelectedTarget({
this.store.dispatch(new InfraStore.ChangeSelectedInfra({
group: node.group,
target: node.target,
infra: node.target,
}));
this.selectedNode = node;
@ -720,8 +720,8 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
onHideDetail() {
const __this = this;
const nodeElements = d3.select(this.displayTargetRef.nativeElement).selectAll('.node-container');
const linkElements = d3.select(this.displayTargetRef.nativeElement).selectAll('.link-container');
const nodeElements = d3.select(this.displayInfraRef.nativeElement).selectAll('.node-container');
const linkElements = d3.select(this.displayInfraRef.nativeElement).selectAll('.link-container');
__this.selectedNode = null;
@ -752,7 +752,7 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
}
refreshTargetDisplay(zone: Zone, hosts: Host[], services: Service[]) {
refreshInfraDisplay(zone: Zone, hosts: Host[], services: Service[]) {
}
@ -764,8 +764,8 @@ export class MapComponent implements OnInit, AfterContentInit, OnDestroy {
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.fx = this.displayInfraWidth / 2;
this.zoneNode.fy = this.displayInfraHeight / 2;
this.zoneNode.r = 60;
this.nodes.push(

View File

@ -8,7 +8,7 @@ import {
import { Store } from '@ngrx/store';
@Component({
selector: 'app-target-display-tree',
selector: 'app-infra-display-tree',
templateUrl: './tree.component.html',
styleUrls: ['./tree.component.scss']
})

View File

@ -3,7 +3,7 @@ import { Store, select } from '@ngrx/store';
import { take } from 'rxjs/operators';
import * as AppStore from '../../store';
import { TargetDisplayType } from '../../core/type';
import { InfraDisplayType } from '../../core/type';
import { Message } from 'primeng/primeng';
const { saveSvgAsPng, svgAsDataUri } = require('save-svg-as-png');
@ -37,10 +37,10 @@ export class ExportJPEGComponent implements OnInit, AfterContentInit, OnDestroy
this.store.pipe(
take(1),
select((state) => {
const targetDisplayType = AppStore.TargetSelector.TargetSelector.selectTargetDisplayType(state);
const targetDisplayElementRef = AppStore.TargetSelector.TargetSelector.selectTargetDisplayElementRef(state);
const infraDisplayType = AppStore.InfraSelector.InfraSelector.selectInfraDisplayType(state);
const infraDisplayElementRef = AppStore.InfraSelector.InfraSelector.selectInfraDisplayElementRef(state);
if (TargetDisplayType.MAP !== targetDisplayType) {
if (InfraDisplayType.MAP !== infraDisplayType) {
this.msgs = [];
this.msgs.push({
severity: 'error',
@ -50,10 +50,10 @@ export class ExportJPEGComponent implements OnInit, AfterContentInit, OnDestroy
return;
}
// svgAsDataUri(targetDisplayElementRef.nativeElement, {}, function (uri) {
// svgAsDataUri(infraDisplayElementRef.nativeElement, {}, function (uri) {
// console.log(`uri: ${uri}`);
// });
saveSvgAsPng(targetDisplayElementRef.nativeElement, 'diagram.jpeg', { backgroundColor: '#ffffff', encoderType: 'image/jpeg' });
saveSvgAsPng(infraDisplayElementRef.nativeElement, 'diagram.jpeg', { backgroundColor: '#ffffff', encoderType: 'image/jpeg' });
}),
).subscribe();
}

View File

@ -3,7 +3,7 @@ import { Store, select } from '@ngrx/store';
import { take } from 'rxjs/operators';
import * as AppStore from '../../store';
import { TargetDisplayType } from '../../core/type';
import { InfraDisplayType } from '../../core/type';
import { Message } from 'primeng/primeng';
const { saveSvgAsPng, svgAsDataUri } = require('save-svg-as-png');
@ -37,10 +37,10 @@ export class ExportPNGComponent implements OnInit, AfterContentInit, OnDestroy {
this.store.pipe(
take(1),
select((state) => {
const targetDisplayType = AppStore.TargetSelector.TargetSelector.selectTargetDisplayType(state);
const targetDisplayElementRef = AppStore.TargetSelector.TargetSelector.selectTargetDisplayElementRef(state);
const infraDisplayType = AppStore.InfraSelector.InfraSelector.selectInfraDisplayType(state);
const infraDisplayElementRef = AppStore.InfraSelector.InfraSelector.selectInfraDisplayElementRef(state);
if (TargetDisplayType.MAP !== targetDisplayType) {
if (InfraDisplayType.MAP !== infraDisplayType) {
this.msgs = [];
this.msgs.push({
severity: 'error',
@ -50,10 +50,10 @@ export class ExportPNGComponent implements OnInit, AfterContentInit, OnDestroy {
return;
}
// svgAsDataUri(targetDisplayElementRef.nativeElement, {}, function (uri) {
// svgAsDataUri(infraDisplayElementRef.nativeElement, {}, function (uri) {
// console.log(`uri: ${uri}`);
// });
saveSvgAsPng(targetDisplayElementRef.nativeElement, 'diagram.png', { backgroundColor: '#ffffff' });
saveSvgAsPng(infraDisplayElementRef.nativeElement, 'diagram.png', { backgroundColor: '#ffffff' });
}),
).subscribe();
}

View File

@ -3,7 +3,7 @@ import { Store, select } from '@ngrx/store';
import { take } from 'rxjs/operators';
import * as AppStore from '../../store';
import { TargetDisplayType } from '../../core/type';
import { InfraDisplayType } from '../../core/type';
import { Message } from 'primeng/primeng';
const { saveSvgAsPng, svgAsDataUri, download } = require('save-svg-as-png');
@ -37,10 +37,10 @@ export class ExportSVGComponent implements OnInit, AfterContentInit, OnDestroy {
this.store.pipe(
take(1),
select((state) => {
const targetDisplayType = AppStore.TargetSelector.TargetSelector.selectTargetDisplayType(state);
const targetDisplayElementRef = AppStore.TargetSelector.TargetSelector.selectTargetDisplayElementRef(state);
const infraDisplayType = AppStore.InfraSelector.InfraSelector.selectInfraDisplayType(state);
const infraDisplayElementRef = AppStore.InfraSelector.InfraSelector.selectInfraDisplayElementRef(state);
if (TargetDisplayType.MAP !== targetDisplayType) {
if (InfraDisplayType.MAP !== infraDisplayType) {
this.msgs = [];
this.msgs.push({
severity: 'error',
@ -50,7 +50,7 @@ export class ExportSVGComponent implements OnInit, AfterContentInit, OnDestroy {
return;
}
svgAsDataUri(targetDisplayElementRef.nativeElement, { backgroundColor: '#ffffff' }, function (uri) {
svgAsDataUri(infraDisplayElementRef.nativeElement, { backgroundColor: '#ffffff' }, function (uri) {
download('diagram.svg', uri);
});
}),

View File

@ -1,26 +0,0 @@
<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>

View File

@ -10,9 +10,9 @@ 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 * as InfraInfraStore from '../../store/infra/infra';
import { take, map } from 'rxjs/operators';
import { DiscoveryMessageType, TargetDisplayType, DiscoveryStatusType } from '../type';
import { DiscoveryMessageType, InfraDisplayType, DiscoveryStatusType } from '../type';
import { Subject, Observable } from 'rxjs';
export class DiscoverySession {
@ -65,11 +65,11 @@ export class DiscoverySession {
}
store.dispatch(new UserStore.ChangeShowWelcomPage({ showWelcomPage: false }));
store.dispatch(new TargetTargetStore.ChangeTargetDisplayType({ targetDisplayType: TargetDisplayType.MAP }));
store.dispatch(new InfraInfraStore.ChangeInfraDisplayType({ infraDisplayType: InfraDisplayType.MAP }));
store.dispatch(new DiscoveryRequestStore.RequestDiscover({ discoverySession }));
// store.dispatch(new UserStore.ChangeShowWelcomPage({ showWelcomPage: false }));
// store.dispatch(new TargetTargetStore.ChangeTargetDisplayType({ targetDisplayType: TargetDisplayType.MAP }));
// store.dispatch(new InfraInfraStore.ChangeInfraDisplayType({ infraDisplayType: InfraDisplayType.MAP }));
}),
).subscribe();
}

View File

@ -1,3 +1,3 @@
export * from './discovery-message';
export * from './discovery-status';
export * from './target-display';
export * from './infra-display';

View File

@ -1,5 +1,5 @@
export enum TargetDisplayType {
export enum InfraDisplayType {
NONE = 'NONE',
MAP = 'MAP',
GRID = 'GRID',

View File

@ -16,7 +16,7 @@
</div>
<div *ngIf="!(showWelcomPage$ | async)" class="display-container">
<app-target-display></app-target-display>
<app-infra-display></app-infra-display>
</div>
</of-p-div>

View File

@ -64,4 +64,18 @@ export class ElectronProxyService {
public getAppMenu(): void {
ipcRenderer.send('get-app-menu');
}
public getRendererI18n({ filePath, fileName }: { filePath: string, fileName: string }): Promise<any> {
return new Promise<any>((resolve, reject) => {
ipcRenderer.once(
'get-renderer-i18n-result',
(event: Electron.IpcMessageEvent, { result }: { result: any }) => {
resolve(result);
}
);
ipcRenderer.send('get-renderer-i18n', { filePath, fileName });
});
}
}

View File

@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { TranslateLoader } from '@ngx-translate/core';
import { ElectronProxyService } from './electron-proxy.service';
@Injectable({
providedIn: 'root'
})
export class I18nService extends TranslateLoader {
private prefix: string;
private suffix: string;
public constructor(
private electronProxyService: ElectronProxyService,
) {
super();
this.prefix = 'assets/i18n';
this.suffix = '.json';
}
getTranslation(lang: string): Observable<any> {
return of(this.electronProxyService.getRendererI18n({
filePath: `${this.prefix}`,
fileName: `${lang}.${this.suffix}`,
}));
}
}

View File

@ -5,6 +5,7 @@ import { ProbeService } from './probe.service';
import { MachineService } from './machine.service';
import { DiscoveryService } from './discovery.service';
import { PingService } from './ping.service';
import { I18nService } from './i18n.service';
export const SERVICES = [
DatabaseService,
@ -14,4 +15,5 @@ export const SERVICES = [
MachineService,
DiscoveryService,
PingService,
I18nService,
];

View File

@ -11,7 +11,7 @@ import { storeFreeze } from 'ngrx-store-freeze';
import * as DiscoveryStore from './discovery';
import * as EnvironmentStore from './environment';
import * as TargetStore from './target';
import * as InfraStore from './infra';
import * as UIStore from './ui';
@ -20,7 +20,7 @@ import { environment } from '../../environments/environment';
export const EFFECTS: Type<any>[] = [
...DiscoveryStore.EFFECTS,
...EnvironmentStore.EFFECTS,
...TargetStore.EFFECTS,
...InfraStore.EFFECTS,
...UIStore.EFFECTS,
];
@ -28,7 +28,7 @@ export const REDUCERS: ActionReducerMap<any> = {
router: fromRouter.routerReducer,
discovery: DiscoveryStore.REDUCER,
environment: EnvironmentStore.REDUCER,
target: TargetStore.REDUCER,
infra: InfraStore.REDUCER,
ui: UIStore.REDUCER,
};
@ -54,7 +54,7 @@ export interface State {
router: fromRouter.RouterReducerState;
discovery: DiscoveryStore.State;
environment: EnvironmentStore.State;
target: TargetStore.State;
infra: InfraStore.State;
ui: UIStore.State;
}
@ -66,8 +66,8 @@ export const EnvironmentSelector = EnvironmentStore.getSelectors(
(state: State) => state.environment,
);
export const TargetSelector = TargetStore.getSelectors(
(state: State) => state.target,
export const InfraSelector = InfraStore.getSelectors(
(state: State) => state.infra,
);
export const UISelector = UIStore.getSelectors(

View File

@ -5,26 +5,26 @@ import {
combineReducers
} from '@ngrx/store';
import * as TargetStore from './target';
import * as InfraStore from './infra';
export interface State {
target: TargetStore.State;
infra: InfraStore.State;
}
export const EFFECTS: Type<any>[] = [
TargetStore.TargetEffects,
InfraStore.InfraEffects,
];
export const REDUCER = combineReducers({
target: TargetStore.reducer,
infra: InfraStore.reducer,
});
export function getSelectors<S>(selector: Selector<any, State>) {
return {
TargetSelector: TargetStore.getSelectors(createSelector(
InfraSelector: InfraStore.getSelectors(createSelector(
selector,
(state: State) => state.target,
(state: State) => state.infra,
)),
};
}

View File

@ -0,0 +1,4 @@
export * from './infra.action';
export * from './infra.effect';
export * from './infra.reducer';
export * from './infra.state';

View File

@ -0,0 +1,68 @@
import { ElementRef } from '@angular/core';
import { Action } from '@ngrx/store';
import { Host, Port, Service } from '@overflow/model/discovery';
import { InfraDisplayType } from '../../../core/type';
export enum ActionType {
SetHosts = '[app.infra] SetHosts',
SetPorts = '[app.infra] SetPorts',
SetServices = '[app.infra] SetServices',
ChangeInfraDisplayType = '[app.infra] ChangeInfraDisplayType',
RefreshInfraDisplay = '[app.infra] RefreshInfraDisplay',
ChangeSelectedInfra = '[app.infra] ChangeSelectedInfra',
ChangeInfraDisplayElementRef = '[app.infra] ChangeInfraDisplayElementRef',
}
export class SetHosts implements Action {
readonly type = ActionType.SetHosts;
constructor(public payload: Host[]) { }
}
export class SetPorts implements Action {
readonly type = ActionType.SetPorts;
constructor(public payload: Port[]) { }
}
export class SetServices implements Action {
readonly type = ActionType.SetServices;
constructor(public payload: Service[]) { }
}
export class ChangeInfraDisplayType implements Action {
readonly type = ActionType.ChangeInfraDisplayType;
constructor(public payload: { infraDisplayType: InfraDisplayType }) { }
}
export class RefreshInfraDisplay implements Action {
readonly type = ActionType.RefreshInfraDisplay;
constructor(public payload: boolean) { }
}
export class ChangeSelectedInfra implements Action {
readonly type = ActionType.ChangeSelectedInfra;
constructor(public payload: { group: string, infra: Host | Port | Service }) { }
}
export class ChangeInfraDisplayElementRef implements Action {
readonly type = ActionType.ChangeInfraDisplayElementRef;
constructor(public payload: { infraDisplayElementRef: ElementRef }) { }
}
export type Actions =
| SetHosts
| SetPorts
| SetServices
| ChangeInfraDisplayType
| RefreshInfraDisplay
| ChangeSelectedInfra
| ChangeInfraDisplayElementRef
;

View File

@ -4,7 +4,7 @@ import { Actions, Effect, ofType } from '@ngrx/effects';
import { map, tap } from 'rxjs/operators';
@Injectable()
export class TargetEffects {
export class InfraEffects {
constructor(
private actions$: Actions,

View File

@ -1,12 +1,12 @@
import {
Actions,
ActionType,
} from './target.action';
} from './infra.action';
import {
State,
initialState,
} from './target.state';
} from './infra.state';
export function reducer(state: State = initialState, action: Actions): State {
switch (action.type) {
@ -31,31 +31,31 @@ export function reducer(state: State = initialState, action: Actions): State {
};
}
case ActionType.ChangeTargetDisplayType: {
case ActionType.ChangeInfraDisplayType: {
return {
...state,
targetDisplayType: action.payload.targetDisplayType,
infraDisplayType: action.payload.infraDisplayType,
};
}
case ActionType.RefreshTargetDisplay: {
case ActionType.RefreshInfraDisplay: {
return {
...state,
refreshTargetDisplay: action.payload,
refreshInfraDisplay: action.payload,
};
}
case ActionType.ChangeSelectedTarget: {
case ActionType.ChangeSelectedInfra: {
return {
...state,
selectedTarget: action.payload,
selectedInfra: action.payload,
};
}
case ActionType.ChangeTargetDisplayElementRef: {
case ActionType.ChangeInfraDisplayElementRef: {
return {
...state,
targetDisplayElementRef: action.payload.targetDisplayElementRef,
infraDisplayElementRef: action.payload.infraDisplayElementRef,
};
}

View File

@ -0,0 +1,41 @@
import { ElementRef } from '@angular/core';
import { Selector, createSelector } from '@ngrx/store';
import { Host, Port, Service } from '@overflow/model/discovery';
import { InfraDisplayType } from '../../../core/type';
export interface State {
hosts: Host[] | null;
ports: Port[] | null;
services: Service[] | null;
infraDisplayType: InfraDisplayType;
refreshInfraDisplay: boolean;
selectedInfra: {
group: string;
infra: Host | Port | Service;
} | null;
infraDisplayElementRef: ElementRef;
}
export const initialState: State = {
hosts: null,
ports: null,
services: null,
infraDisplayType: InfraDisplayType.NONE,
refreshInfraDisplay: false,
selectedInfra: null,
infraDisplayElementRef: null,
};
export function getSelectors<S>(selector: Selector<any, State>) {
return {
selectHosts: createSelector(selector, (state: State) => state.hosts),
selectPorts: createSelector(selector, (state: State) => state.ports),
selectServices: createSelector(selector, (state: State) => state.services),
selectInfraDisplayType: createSelector(selector, (state: State) => state.infraDisplayType),
selectRefreshInfraDisplay: createSelector(selector, (state: State) => state.refreshInfraDisplay),
selectSelectedInfra: createSelector(selector, (state: State) => state.selectedInfra),
selectInfraDisplayElementRef: createSelector(selector, (state: State) => state.infraDisplayElementRef),
};
}

View File

@ -1,4 +0,0 @@
export * from './target.action';
export * from './target.effect';
export * from './target.reducer';
export * from './target.state';

View File

@ -1,68 +0,0 @@
import { ElementRef } from '@angular/core';
import { Action } from '@ngrx/store';
import { Host, Port, Service } from '@overflow/model/discovery';
import { TargetDisplayType } from '../../../core/type';
export enum ActionType {
SetHosts = '[app.target] SetHosts',
SetPorts = '[app.target] SetPorts',
SetServices = '[app.target] SetServices',
ChangeTargetDisplayType = '[app.target] ChangeTargetDisplayType',
RefreshTargetDisplay = '[app.target] RefreshTargetDisplay',
ChangeSelectedTarget = '[app.target] ChangeSelectedTarget',
ChangeTargetDisplayElementRef = '[app.target] ChangeTargetDisplayElementRef',
}
export class SetHosts implements Action {
readonly type = ActionType.SetHosts;
constructor(public payload: Host[]) { }
}
export class SetPorts implements Action {
readonly type = ActionType.SetPorts;
constructor(public payload: Port[]) { }
}
export class SetServices implements Action {
readonly type = ActionType.SetServices;
constructor(public payload: Service[]) { }
}
export class ChangeTargetDisplayType implements Action {
readonly type = ActionType.ChangeTargetDisplayType;
constructor(public payload: { targetDisplayType: TargetDisplayType }) { }
}
export class RefreshTargetDisplay implements Action {
readonly type = ActionType.RefreshTargetDisplay;
constructor(public payload: boolean) { }
}
export class ChangeSelectedTarget implements Action {
readonly type = ActionType.ChangeSelectedTarget;
constructor(public payload: { group: string, target: Host | Port | Service }) { }
}
export class ChangeTargetDisplayElementRef implements Action {
readonly type = ActionType.ChangeTargetDisplayElementRef;
constructor(public payload: { targetDisplayElementRef: ElementRef }) { }
}
export type Actions =
| SetHosts
| SetPorts
| SetServices
| ChangeTargetDisplayType
| RefreshTargetDisplay
| ChangeSelectedTarget
| ChangeTargetDisplayElementRef
;

View File

@ -1,41 +0,0 @@
import { ElementRef } from '@angular/core';
import { Selector, createSelector } from '@ngrx/store';
import { Host, Port, Service } from '@overflow/model/discovery';
import { TargetDisplayType } from '../../../core/type';
export interface State {
hosts: Host[] | null;
ports: Port[] | null;
services: Service[] | null;
targetDisplayType: TargetDisplayType;
refreshTargetDisplay: boolean;
selectedTarget: {
group: string;
target: Host | Port | Service;
} | null;
targetDisplayElementRef: ElementRef;
}
export const initialState: State = {
hosts: null,
ports: null,
services: null,
targetDisplayType: TargetDisplayType.NONE,
refreshTargetDisplay: false,
selectedTarget: null,
targetDisplayElementRef: null,
};
export function getSelectors<S>(selector: Selector<any, State>) {
return {
selectHosts: createSelector(selector, (state: State) => state.hosts),
selectPorts: createSelector(selector, (state: State) => state.ports),
selectServices: createSelector(selector, (state: State) => state.services),
selectTargetDisplayType: createSelector(selector, (state: State) => state.targetDisplayType),
selectRefreshTargetDisplay: createSelector(selector, (state: State) => state.refreshTargetDisplay),
selectSelectedTarget: createSelector(selector, (state: State) => state.selectedTarget),
selectTargetDisplayElementRef: createSelector(selector, (state: State) => state.targetDisplayElementRef),
};
}

48
src/assets/i18n/en.json Normal file
View File

@ -0,0 +1,48 @@
{
"ui": {
"button": {
"apply": "Apply",
"reset": "Reset"
},
"menu": {
"save": "Save",
"export_as": "Export as",
"print": "Print",
"toggle_full_screen": "Toggle Full Screen"
}
},
"network": {
"ip": "IP",
"port": "Port",
"range": "Range"
},
"infra": {
"detail": {
"title": {
"general": "General",
"metadata": "Metadata",
"ports": "Ports",
"health": "Health"
},
"general": {
"ip_address": "IP Address",
"type": "Type",
"vendor": "Vendor",
"model": "Model",
"os": "OS"
},
"health": {
"count": "Count",
"interval": "Interval",
"deadline": "Deadline",
"ping": "Ping"
}
}
},
"discovery": {
"total_hosts": "Total Hosts",
"total_ports": "Total Ports",
"total_services": "Total Services",
"elapsed": "Elapsed"
}
}

6
src/assets/i18n/ko.json Normal file
View File

@ -0,0 +1,6 @@
{
"HOME": {
"TITLE": "Hello Angular with ngx-translate!",
"SELECT": "Change language"
}
}

12
src/electron/app-path.ts Normal file
View File

@ -0,0 +1,12 @@
import * as fse from 'fs-extra';
import * as path from 'path';
const _root = __DEV__
? path.resolve(__dirname, '..', '..')
: path.resolve(__dirname);
export function root(...paths: string[]) {
const args = Array.prototype.slice.call(paths, 0);
return path.join.apply(path, [_root].concat(args));
}

View File

@ -15,6 +15,7 @@ import { parseAppURL } from '@overflow/core/parse-app-url';
import { now } from '@overflow/core/now';
import { IMenuItem } from '@overflow/core/menu-item';
import { root } from './app-path';
import { AppWindow } from './app-window';
import { handleSquirrelEvent } from './squirrel-updater';
@ -227,6 +228,18 @@ app.on('ready', () => {
let menu = buildDefaultMenu();
Menu.setApplicationMenu(menu);
ipcMain.on(
'get-renderer-i18n', (
event: Electron.IpcMessageEvent,
{ filePath, fileName }: { filePath: string, fileName: string }
) => {
const rBuf = fse.readFileSync(root(filePath, fileName));
const i18n = JSON.parse(rBuf.toString('utf8'));
event.sender.send('get-renderer-i18n-result', { i18n });
}
);
ipcMain.on(
'update-preferred-app-menu-item-labels',
(event: Electron.IpcMessageEvent) => {