,
+ ) {}
+
+ onCloseClick() {
+ this.dialogRef.close();
+ }
+}
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.html b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.html
new file mode 100644
index 00000000..09856747
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.html
@@ -0,0 +1,44 @@
+Packet filters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.scss b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.scss
new file mode 100644
index 00000000..529a458e
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.scss
@@ -0,0 +1,67 @@
+.spacer {
+ flex-grow: 1;
+}
+
+.content {
+ height: 260px;
+}
+
+.item {
+ height: 25px;
+ font-size: 10pt;
+ margin-bottom: 10px;
+}
+
+.item-name {
+ margin-bottom: 10px;
+}
+
+.item-value {
+ width: 100%;
+ margin-bottom: 10px;
+}
+
+.input-field {
+ width: 100%;
+ margin-top: 10px;
+}
+
+.divider {
+ width: fit-content;
+ flex: 1 1 auto;
+}
+
+.input-color {
+ padding: 0px;
+ border-width: 0px;
+ width: 100%;
+ background-color: transparent;
+ outline: none;
+}
+
+input:focus {
+ outline: none;
+}
+
+input[type="color"] {
+ -webkit-appearance: none;
+ border: none;
+ height: 25px;
+}
+
+input[type="color"]::-webkit-color-swatch-wrapper {
+ padding: 0;
+}
+
+input[type="color"]::-webkit-color-swatch {
+ border: none;
+}
+
+.modal-form-container {
+ display: flex;
+ flex-direction: column;
+}
+
+.modal-form-container > * {
+ width: 100%;
+}
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts
new file mode 100644
index 00000000..257aa33e
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts
@@ -0,0 +1,63 @@
+import { ComponentFixture, TestBed, async } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { CommonModule } from '@angular/common';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { LinkService } from '../../../../services/link.service';
+import { MockedLinkService } from '../../project-map.component.spec';
+import { Link } from '../../../../models/link';
+import { of } from 'rxjs';
+import { PacketFiltersDialogComponent } from './packet-filters.component';
+
+describe('PacketFiltersDialogComponent', () => {
+ let component: PacketFiltersDialogComponent;
+ let fixture: ComponentFixture;
+
+ let mockedLinkService = new MockedLinkService;
+ let dialogRef = {
+ close: jasmine.createSpy('close')
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [MatDialogModule, FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule],
+ providers: [
+ { provide: MatDialogRef, useValue: dialogRef },
+ { provide: MAT_DIALOG_DATA, useValue: [] },
+ { provide: LinkService, useValue: mockedLinkService }
+ ],
+ declarations: [
+ PacketFiltersDialogComponent
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PacketFiltersDialogComponent);
+ component = fixture.componentInstance;
+ component.link = {link_type: 'ethernet'} as Link;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should call update link when filters applied', () => {
+ spyOn(mockedLinkService, 'updateLink').and.returnValue(of({}));
+
+ component.onYesClick();
+
+ expect(mockedLinkService.updateLink).toHaveBeenCalled();
+ });
+
+ it('should call update link after resetting', () => {
+ spyOn(mockedLinkService, 'updateLink').and.returnValue(of({}));
+
+ component.onResetClick();
+
+ expect(mockedLinkService.updateLink).toHaveBeenCalled();
+ });
+});
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts
new file mode 100644
index 00000000..19cf6e7f
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts
@@ -0,0 +1,96 @@
+import { Component, OnInit } from '@angular/core';
+import { Link } from '../../../../models/link';
+import { Server } from '../../../../models/server';
+import { Project } from '../../../../models/project';
+import { MatDialogRef, MatDialog } from '@angular/material';
+import { LinkService } from '../../../../services/link.service';
+import { FilterDescription } from '../../../../models/filter-description';
+import { HelpDialogComponent } from '../../help-dialog/help-dialog.component';
+import { Message } from '../../../../models/message';
+import { Filter } from '../../../../models/filter';
+
+@Component({
+ selector: 'app-packet-filters',
+ templateUrl: './packet-filters.component.html',
+ styleUrls: ['./packet-filters.component.scss']
+})
+export class PacketFiltersDialogComponent implements OnInit{
+ server: Server;
+ project: Project;
+ link: Link;
+ filters: Filter;
+ availableFilters: FilterDescription[];
+
+ constructor(
+ private dialogRef: MatDialogRef,
+ private linkService: LinkService,
+ private dialog: MatDialog
+ ) {}
+
+ ngOnInit(){
+ this.linkService.getLink(this.server, this.link.project_id, this.link.link_id).subscribe((link: Link) => {
+ this.link = link;
+ this.filters = {
+ bpf: [],
+ corrupt: [0],
+ delay: [0, 0],
+ frequency_drop: [0],
+ packet_loss: [0]
+ };
+
+ if (this.link.filters) {
+ this.filters.bpf = this.link.filters.bpf ? this.link.filters.bpf : [];
+ this.filters.corrupt = this.link.filters.corrupt ? this.link.filters.corrupt : [0];
+ this.filters.delay = this.link.filters.delay ? this.link.filters.delay : [0, 0];
+ this.filters.frequency_drop = this.link.filters.frequency_drop ? this.link.filters.frequency_drop : [0];
+ this.filters.packet_loss = this.link.filters.packet_loss ? this.link.filters.packet_loss : [0];
+ }
+ });
+
+ this.linkService.getAvailableFilters(this.server, this.link).subscribe((availableFilters: FilterDescription[]) => {
+ this.availableFilters = availableFilters;
+ });
+ }
+
+ onNoClick() {
+ this.dialogRef.close();
+ }
+
+ onResetClick() {
+ this.link.filters = {
+ bpf: [],
+ corrupt: [0],
+ delay: [0, 0],
+ frequency_drop: [0],
+ packet_loss: [0]
+ };
+
+ this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => {
+ this.dialogRef.close();
+ });
+ }
+
+ onYesClick() {
+ this.link.filters = this.filters;
+ this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => {
+ this.dialogRef.close();
+ });
+ }
+
+ onHelpClick() {
+ const dialogRef = this.dialog.open(HelpDialogComponent, {
+ width: '500px',
+ autoFocus: false
+ });
+ let instance = dialogRef.componentInstance;
+ instance.title = 'Help for filters';
+ let messages: Message[] = [];
+ this.availableFilters.forEach((filter: FilterDescription) => {
+ messages.push({
+ name: filter.name,
+ description: filter.description
+ });
+ });
+ instance.messages = messages;
+ }
+}
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.html b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.html
new file mode 100644
index 00000000..80ece941
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.html
@@ -0,0 +1,30 @@
+Packet capture
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.scss b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.scss
new file mode 100644
index 00000000..396495e3
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.scss
@@ -0,0 +1,3 @@
+.input-field {
+ width: 100%;
+}
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts
new file mode 100644
index 00000000..945caaee
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts
@@ -0,0 +1,82 @@
+import { StartCaptureDialogComponent } from "./start-capture.component";
+import { ComponentFixture, TestBed, async } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { CommonModule } from '@angular/common';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { ToasterService } from '../../../../services/toaster.service';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { MockedToasterService } from '../../../../services/toaster.service.spec';
+import { LinkService } from '../../../../services/link.service';
+import { MockedLinkService, MockedNodesDataSource } from '../../project-map.component.spec';
+import { Link } from '../../../../models/link';
+import { of } from 'rxjs';
+import { NodesDataSource } from '../../../../cartography/datasources/nodes-datasource';
+
+describe('StartCaptureDialogComponent', () => {
+ let component: StartCaptureDialogComponent;
+ let fixture: ComponentFixture;
+
+ let mockedToasterService = new MockedToasterService;
+ let mockedLinkService = new MockedLinkService;
+ let mockedNodesDataSource = new MockedNodesDataSource;
+ let dialogRef = {
+ close: jasmine.createSpy('close')
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [MatDialogModule, FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule],
+ providers: [
+ { provide: MatDialogRef, useValue: dialogRef },
+ { provide: MAT_DIALOG_DATA, useValue: [] },
+ { provide: ToasterService, useValue: mockedToasterService },
+ { provide: LinkService, useValue: mockedLinkService },
+ { provide: NodesDataSource, useValue: mockedNodesDataSource }
+ ],
+ declarations: [
+ StartCaptureDialogComponent
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(StartCaptureDialogComponent);
+ component = fixture.componentInstance;
+ component.link = {link_type: 'ethernet', nodes: [{node_id: '1'}, {node_id: '2'}]} as Link;
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should call link service when input is valid', () => {
+ component.inputForm.controls['linkType'].setValue('Ethernet');
+ component.inputForm.controls['fileName'].setValue('SampleFileName');
+ spyOn(mockedLinkService, 'startCaptureOnLink').and.returnValue(of({}));
+
+ component.onYesClick();
+
+ expect(mockedLinkService.startCaptureOnLink).toHaveBeenCalled();
+ });
+
+ it('should not call link service when link type is not set', () => {
+ component.inputForm.controls['fileName'].setValue('SampleFileName');
+ spyOn(mockedLinkService, 'startCaptureOnLink').and.returnValue(of({}));
+
+ component.onYesClick();
+
+ expect(mockedLinkService.startCaptureOnLink).not.toHaveBeenCalled();
+ });
+
+ it('should not call link service when filename is empty', () => {
+ component.inputForm.controls['linkType'].setValue('Ethernet');
+ component.inputForm.controls['fileName'].setValue('');
+ spyOn(mockedLinkService, 'startCaptureOnLink').and.returnValue(of({}));
+
+ component.onYesClick();
+
+ expect(mockedLinkService.startCaptureOnLink).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts
new file mode 100644
index 00000000..b9ef34c7
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts
@@ -0,0 +1,85 @@
+import { Component, OnInit } from '@angular/core';
+import { Server } from '../../../../models/server';
+import { Link } from '../../../../models/link';
+import { MatDialogRef } from '@angular/material';
+import { PacketFiltersDialogComponent } from '../packet-filters/packet-filters.component';
+import { LinkService } from '../../../../services/link.service';
+import { CapturingSettings } from '../../../../models/capturingSettings';
+import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
+import { ToasterService } from '../../../../services/toaster.service';
+import { LinkNode } from '../../../../models/link-node';
+import { NodesDataSource } from '../../../../cartography/datasources/nodes-datasource';
+
+@Component({
+ selector: 'app-start-capture',
+ templateUrl: './start-capture.component.html',
+ styleUrls: ['./start-capture.component.scss']
+})
+export class StartCaptureDialogComponent implements OnInit {
+ server: Server;
+ link: Link;
+ linkTypes = [];
+ inputForm: FormGroup;
+ startProgram: boolean;
+
+ constructor(
+ private dialogRef: MatDialogRef,
+ private linkService: LinkService,
+ private formBuilder: FormBuilder,
+ private toasterService: ToasterService,
+ private nodesDataSource: NodesDataSource
+ ) {
+ this.inputForm = this.formBuilder.group({
+ linkType: new FormControl('', Validators.required),
+ fileName: new FormControl('', Validators.required)
+ });
+ }
+
+ ngOnInit() {
+ if (this.link.link_type === 'ethernet') {
+ this.linkTypes = [
+ ["Ethernet", "DLT_EN10MB"]
+ ];
+ } else {
+ this.linkTypes = [
+ ["Cisco HDLC", "DLT_C_HDLC"],
+ ["Cisco PPP", "DLT_PPP_SERIAL"],
+ ["Frame Relay", "DLT_FRELAY"],
+ ["ATM", "DLT_ATM_RFC1483"]
+ ];
+ }
+
+ const sourceNode = this.nodesDataSource.get(this.link.nodes[0].node_id);
+ const targetNode = this.nodesDataSource.get(this.link.nodes[1].node_id);
+ const sourcePort = sourceNode.ports[this.link.nodes[0].port_number];
+ const targetPort = targetNode.ports[this.link.nodes[1].port_number];
+ this.inputForm.controls['fileName'].setValue(`${sourceNode.name}_${sourcePort.name}_to_${targetNode.name}_${targetPort.name}`);
+ }
+
+ onYesClick() {
+ let isAnyRunningDevice = false;
+ this.link.nodes.forEach((linkNode: LinkNode) => {
+ let node = this.nodesDataSource.get(linkNode.node_id);
+ if (node.status === 'started') isAnyRunningDevice = true;
+ });
+
+ if (!isAnyRunningDevice) {
+ this.toasterService.error(`Cannot capture because there is no running device on this link`);
+ } else if (this.inputForm.invalid) {
+ this.toasterService.error(`Fill all required fields`);
+ } else {
+ let captureSettings: CapturingSettings = {
+ capture_file_name: this.inputForm.get('fileName').value,
+ data_link_type: this.inputForm.get('linkType').value
+ };
+
+ this.linkService.startCaptureOnLink(this.server, this.link, captureSettings).subscribe(() => {
+ this.dialogRef.close();
+ });
+ }
+ }
+
+ onNoClick() {
+ this.dialogRef.close();
+ }
+}
diff --git a/src/app/components/project-map/project-map.component.spec.ts b/src/app/components/project-map/project-map.component.spec.ts
index 1a3d2c4e..11ea2a36 100644
--- a/src/app/components/project-map/project-map.component.spec.ts
+++ b/src/app/components/project-map/project-map.component.spec.ts
@@ -40,6 +40,8 @@ import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProje
import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter';
import { Link } from '../../models/link';
import { Project } from '../../models/project';
+import { CapturingSettings } from '../../models/capturingSettings';
+import { LinkWidget } from '../../cartography/widgets/link';
export class MockedProgressService {
public activate() {}
@@ -112,8 +114,16 @@ export class MockedDrawingService {
export class MockedLinkService {
constructor() {}
+ getLink(server: Server, projectId: string, linkId: string) {
+ return of({});
+ }
+
deleteLink(_server: Server, link: Link){
- return of({})
+ return of({});
+ }
+
+ updateLink(server: Server, link: Link) {
+ return of({});
}
createLink() {
@@ -123,6 +133,14 @@ export class MockedLinkService {
updateNodes() {
return of({});
}
+
+ startCaptureOnLink(server: Server, link: Link, settings: CapturingSettings) {
+ return of({});
+ }
+
+ getAvailableFilters(server: Server, link: Link) {
+ return of({});
+ }
}
export class MockedDrawingsDataSource {
@@ -145,7 +163,7 @@ export class MockedNodesDataSource {
clear() {}
get() {
- return of({});
+ return {status: 'started'};
}
update() {
@@ -179,6 +197,7 @@ describe('ProjectMapComponent', () => {
{ provide: ProjectWebServiceHandler },
{ provide: MapChangeDetectorRef },
{ provide: NodeWidget },
+ { provide: LinkWidget },
{ provide: DrawingsWidget },
{ provide: MapNodeToNodeConverter },
{ provide: MapDrawingToDrawingConverter },
diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts
index 05b15f80..0681ef01 100644
--- a/src/app/components/project-map/project-map.component.ts
+++ b/src/app/components/project-map/project-map.component.ts
@@ -30,7 +30,7 @@ import { MapNodeToNodeConverter } from '../../cartography/converters/map/map-nod
import { SettingsService, Settings } from '../../services/settings.service';
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
import { ToolsService } from '../../services/tools.service';
-import { DrawingContextMenu } from '../../cartography/events/event-source';
+import { DrawingContextMenu, LinkContextMenu } from '../../cartography/events/event-source';
import { MapDrawingToDrawingConverter } from '../../cartography/converters/map/map-drawing-to-drawing-converter';
import { SelectionManager } from '../../cartography/managers/selection-manager';
import { SelectionTool } from '../../cartography/tools/selection-tool';
@@ -42,6 +42,7 @@ import { MapLabelToLabelConverter } from '../../cartography/converters/map/map-l
import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service';
import { MapLink } from '../../cartography/models/map/map-link';
import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter';
+import { LinkWidget } from '../../cartography/widgets/link';
@Component({
@@ -95,6 +96,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
private mapChangeDetectorRef: MapChangeDetectorRef,
private nodeWidget: NodeWidget,
private drawingsWidget: DrawingsWidget,
+ private linkWidget: LinkWidget,
private mapNodeToNode: MapNodeToNodeConverter,
private mapDrawingToDrawing: MapDrawingToDrawingConverter,
private mapLabelToLabel: MapLabelToLabelConverter,
@@ -219,6 +221,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
this.toolsService.selectionToolActivation(true);
}
+ const onLinkContextMenu = this.linkWidget.onContextMenu.subscribe((eventLink: LinkContextMenu) => {
+ const link = this.mapLinkToLink.convert(eventLink.link);
+ this.contextMenu.openMenuForListOfElements([], [], [], [link], eventLink.event.pageY, eventLink.event.pageX);
+ });
+
const onNodeContextMenu = this.nodeWidget.onContextMenu.subscribe((eventNode: NodeContextMenu) => {
const node = this.mapNodeToNode.convert(eventNode.node);
this.contextMenu.openMenuForNode(node, eventNode.event.pageY, eventNode.event.pageX);
@@ -253,6 +260,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
this.contextMenu.openMenuForListOfElements(drawings, nodes, labels, links, event.pageY, event.pageX);
});
+ this.subscriptions.push(onLinkContextMenu);
this.subscriptions.push(onNodeContextMenu);
this.subscriptions.push(onDrawingContextMenu);
this.subscriptions.push(onContextMenu);
diff --git a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts
index 78a806b8..a346e751 100644
--- a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts
+++ b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts
@@ -48,11 +48,6 @@ export class SnapshotMenuItemComponent implements OnInit {
(created_snapshot: Snapshot) => {
this.toaster.success(`Snapshot '${snapshot.name}' has been created.`);
progress.close();
- },
- response => {
- const error = response.json();
- this.toaster.error(`Cannot create snapshot: ${error.message}`);
- progress.close();
}
);
diff --git a/src/app/material.imports.ts b/src/app/material.imports.ts
index 9dc2260b..fdc33412 100644
--- a/src/app/material.imports.ts
+++ b/src/app/material.imports.ts
@@ -19,7 +19,8 @@ import {
MatTooltipModule,
MatStepperModule,
MatRadioModule,
- MatGridListModule
+ MatGridListModule,
+ MatTabsModule
} from '@angular/material';
export const MATERIAL_IMPORTS = [
@@ -43,5 +44,6 @@ export const MATERIAL_IMPORTS = [
MatTooltipModule,
MatStepperModule,
MatRadioModule,
- MatGridListModule
+ MatGridListModule,
+ MatTabsModule
];
diff --git a/src/app/models/capturingSettings.ts b/src/app/models/capturingSettings.ts
new file mode 100644
index 00000000..7cf85ba8
--- /dev/null
+++ b/src/app/models/capturingSettings.ts
@@ -0,0 +1,4 @@
+export class CapturingSettings {
+ capture_file_name: string;
+ data_link_type: string;
+}
diff --git a/src/app/models/filter-description.ts b/src/app/models/filter-description.ts
new file mode 100644
index 00000000..77238e27
--- /dev/null
+++ b/src/app/models/filter-description.ts
@@ -0,0 +1,14 @@
+export class FilterDescription {
+ description: string;
+ name: string;
+ parameters: Parameter[];
+ type: string;
+}
+
+interface Parameter {
+ maximum?: number;
+ minimum?: number;
+ name: string;
+ type: string;
+ unit?: string;
+}
diff --git a/src/app/models/filter.ts b/src/app/models/filter.ts
new file mode 100644
index 00000000..5a27c67a
--- /dev/null
+++ b/src/app/models/filter.ts
@@ -0,0 +1,7 @@
+export class Filter {
+ bpf?: string[];
+ corrupt?: number[];
+ delay?: number[];
+ frequency_drop?: number[];
+ packet_loss?: number[];
+}
diff --git a/src/app/models/link.ts b/src/app/models/link.ts
index d33d3845..74f06bcd 100644
--- a/src/app/models/link.ts
+++ b/src/app/models/link.ts
@@ -1,14 +1,17 @@
import { Node } from '../cartography/models/node';
import { LinkNode } from './link-node';
+import { Filter } from './filter';
export class Link {
capture_file_name: string;
capture_file_path: string;
capturing: boolean;
+ filters?: Filter;
link_id: string;
link_type: string;
nodes: LinkNode[];
project_id: string;
+ suspend: boolean;
distance: number; // this is not from server
length: number; // this is not from server
diff --git a/src/app/models/message.ts b/src/app/models/message.ts
new file mode 100644
index 00000000..3d21b1cc
--- /dev/null
+++ b/src/app/models/message.ts
@@ -0,0 +1,4 @@
+export class Message {
+ name?: string;
+ description: string;
+}
diff --git a/src/app/services/link.service.ts b/src/app/services/link.service.ts
index 37d2ebfa..89735923 100644
--- a/src/app/services/link.service.ts
+++ b/src/app/services/link.service.ts
@@ -7,16 +7,13 @@ import { HttpServer } from './http-server.service';
import { Port } from '../models/port';
import { Link } from '../models/link';
import { LinkNode } from '../models/link-node';
+import { FilterDescription } from '../models/filter-description';
+import { CapturingSettings } from '../models/capturingSettings';
@Injectable()
export class LinkService {
constructor(private httpServer: HttpServer) {}
- deleteLink(server: Server, link: Link) {
- //return this.httpServer.delete(server, `/compute/projects/${link.project_id}/vpcs/nodes/${link.nodes[0].node_id}/adapters/0/ports/0/nio`)
- return this.httpServer.delete(server, `/projects/${link.project_id}/links/${link.link_id}`)
- }
-
createLink(server: Server, source_node: Node, source_port: Port, target_node: Node, target_port: Port) {
return this.httpServer.post(server, `/projects/${source_node.project_id}/links`, {
nodes: [
@@ -34,6 +31,22 @@ export class LinkService {
});
}
+ getLink(server: Server, projectId: string, linkId: string) {
+ return this.httpServer.get(server, `/projects/${projectId}/links/${linkId}`);
+ }
+
+ deleteLink(server: Server, link: Link) {
+ return this.httpServer.delete(server, `/projects/${link.project_id}/links/${link.link_id}`)
+ }
+
+ updateLink(server: Server, link: Link) {
+ return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, link);
+ }
+
+ getAvailableFilters(server: Server, link: Link) {
+ return this.httpServer.get(server, `/projects/${link.project_id}/links/${link.link_id}/available_filters`);
+ }
+
updateNodes(server: Server, link: Link, nodes: LinkNode[]) {
const requestNodes = nodes.map(linkNode => {
return {
@@ -52,4 +65,16 @@ export class LinkService {
return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, { nodes: requestNodes });
}
+
+ startCaptureOnLink(server: Server, link: Link, settings: CapturingSettings) {
+ return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/start_capture`, settings);
+ }
+
+ stopCaptureOnLink(server: Server, link: Link) {
+ return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/stop_capture`, {});
+ }
+
+ streamPcap(server: Server, link: Link) {
+ return this.httpServer.get(server, `/projects/${link.project_id}/links/${link.link_id}/pcap`)
+ }
}
diff --git a/src/assets/resources/images/filter-capture.svg b/src/assets/resources/images/filter-capture.svg
new file mode 100644
index 00000000..aa95a12c
--- /dev/null
+++ b/src/assets/resources/images/filter-capture.svg
@@ -0,0 +1,428 @@
+
+
+
diff --git a/src/assets/resources/images/filter.svg b/src/assets/resources/images/filter.svg
new file mode 100644
index 00000000..a67a6f9c
--- /dev/null
+++ b/src/assets/resources/images/filter.svg
@@ -0,0 +1,708 @@
+
+
+
diff --git a/src/assets/resources/images/inspect.svg b/src/assets/resources/images/inspect.svg
new file mode 100644
index 00000000..f2573ffc
--- /dev/null
+++ b/src/assets/resources/images/inspect.svg
@@ -0,0 +1,312 @@
+
+
+