mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2024-12-18 20:47:51 +00:00
Merge with master
This commit is contained in:
commit
9478f8f6f9
@ -24,7 +24,7 @@ build_script:
|
|||||||
- "%PYTHON%\\python.exe scripts\\build.py build_exe -b dist/exe.gns3server -s"
|
- "%PYTHON%\\python.exe scripts\\build.py build_exe -b dist/exe.gns3server -s"
|
||||||
- "%PYTHON%\\python.exe scripts\\build.py validate -b dist"
|
- "%PYTHON%\\python.exe scripts\\build.py validate -b dist"
|
||||||
- "%PYTHON%\\python.exe scripts\\build.py download_dependencies -b dist"
|
- "%PYTHON%\\python.exe scripts\\build.py download_dependencies -b dist"
|
||||||
- yarn electron-builder --win --x64
|
- yarn electron-builder --win --x64 --publish always
|
||||||
|
|
||||||
test: off
|
test: off
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Dist project
|
name: Dist project
|
||||||
command: |
|
command: |
|
||||||
yarn electron-builder --mac --x64
|
yarn electron-builder --mac --x64 --publish always
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
name: Gather artifacts
|
name: Gather artifacts
|
||||||
|
4
.sentryclirc
Normal file
4
.sentryclirc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[defaults]
|
||||||
|
url = https://sentry.io/
|
||||||
|
org = gns3
|
||||||
|
project = gns3-web-ui
|
13
.travis.yml
13
.travis.yml
@ -68,4 +68,15 @@ after_script:
|
|||||||
python3 scripts/build.py download
|
python3 scripts/build.py download
|
||||||
python3 scripts/build.py build_exe -b dist/exe.gns3server -s
|
python3 scripts/build.py build_exe -b dist/exe.gns3server -s
|
||||||
python3 scripts/build.py validate -b dist
|
python3 scripts/build.py validate -b dist
|
||||||
- yarn electron-builder --linux --x64
|
- yarn electron-builder --linux --x64 --publish always
|
||||||
|
|
||||||
|
# build sourcemaps and upload to Sentry
|
||||||
|
# fix node issue with memory
|
||||||
|
- |
|
||||||
|
if [ -n "$TRAVIS_TAG" ];
|
||||||
|
export NODE_OPTIONS=--max_old_space_size=4096
|
||||||
|
export RELEASE_VERSION=$(node -e "const fs = require('fs'); let p = fs.readFileSync('package.json'); console.log(JSON.parse(p).version);")
|
||||||
|
yarn ng build --configuration=production --base-href /static/web-ui/
|
||||||
|
yarn sentry-cli releases new $RELEASE_VERSION
|
||||||
|
yarn sentry-cli releases files $RELEASE_VERSION upload-sourcemaps dist/
|
||||||
|
fi
|
||||||
|
@ -32,7 +32,11 @@
|
|||||||
"production": {
|
"production": {
|
||||||
"optimization": true,
|
"optimization": true,
|
||||||
"outputHashing": "all",
|
"outputHashing": "all",
|
||||||
"sourceMap": false,
|
"sourceMap": {
|
||||||
|
"hidden": true,
|
||||||
|
"scripts": true,
|
||||||
|
"styles": false
|
||||||
|
},
|
||||||
"extractCss": true,
|
"extractCss": true,
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"aot": true,
|
"aot": true,
|
||||||
|
@ -4,6 +4,7 @@ productName: "GNS3 Web UI"
|
|||||||
artifactName: "${productName}-${os}-${arch}-${version}.${ext}"
|
artifactName: "${productName}-${os}-${arch}-${version}.${ext}"
|
||||||
asar: true
|
asar: true
|
||||||
compression: normal
|
compression: normal
|
||||||
|
generateUpdatesFilesForAllChannels: true
|
||||||
|
|
||||||
directories:
|
directories:
|
||||||
output: build
|
output: build
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gns3-web-ui",
|
"name": "gns3-web-ui",
|
||||||
"version": "0.0.1-beta.0",
|
"version": "2019.1.0-alpha.4dev",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "GNS3 Technology Inc.",
|
"name": "GNS3 Technology Inc.",
|
||||||
"email": "developers@gns3.com"
|
"email": "developers@gns3.com"
|
||||||
@ -77,6 +77,7 @@
|
|||||||
"@angular/cli": "^7.3.3",
|
"@angular/cli": "^7.3.3",
|
||||||
"@angular/compiler-cli": "^7.2.7",
|
"@angular/compiler-cli": "^7.2.7",
|
||||||
"@angular/language-service": "^7.2.7",
|
"@angular/language-service": "^7.2.7",
|
||||||
|
"@sentry/cli": "^1.40.0",
|
||||||
"@sentry/electron": "^0.16.0",
|
"@sentry/electron": "^0.16.0",
|
||||||
"@types/jasmine": "~3.3.9",
|
"@types/jasmine": "~3.3.9",
|
||||||
"@types/jasminewd2": "~2.0.6",
|
"@types/jasminewd2": "~2.0.6",
|
||||||
|
@ -211,6 +211,7 @@ def build_command(arguments):
|
|||||||
("gns3server/appliances", "appliances"),
|
("gns3server/appliances", "appliances"),
|
||||||
("gns3server/templates", "templates"),
|
("gns3server/templates", "templates"),
|
||||||
("gns3server/symbols", "symbols"),
|
("gns3server/symbols", "symbols"),
|
||||||
|
("gns3server/static/web-ui", "static/web-ui")
|
||||||
]
|
]
|
||||||
|
|
||||||
include_files = [(os.path.join(source_directory, x), y) for x, y in include_files]
|
include_files = [(os.path.join(source_directory, x), y) for x, y in include_files]
|
||||||
|
@ -6,7 +6,7 @@ import { ServersComponent } from './components/servers/servers.component';
|
|||||||
import { ProjectsComponent } from './components/projects/projects.component';
|
import { ProjectsComponent } from './components/projects/projects.component';
|
||||||
import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component';
|
import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component';
|
||||||
import { SettingsComponent } from './components/settings/settings.component';
|
import { SettingsComponent } from './components/settings/settings.component';
|
||||||
import { LocalServerComponent } from './components/local-server/local-server.component';
|
import { BundledServerFinderComponent } from './components/bundled-server-finder/bundled-server-finder.component';
|
||||||
import { PreferencesComponent } from './components/preferences/preferences.component';
|
import { PreferencesComponent } from './components/preferences/preferences.component';
|
||||||
import { QemuPreferencesComponent } from './components/preferences/qemu/qemu-preferences/qemu-preferences.component';
|
import { QemuPreferencesComponent } from './components/preferences/qemu/qemu-preferences/qemu-preferences.component';
|
||||||
import { QemuVmTemplatesComponent } from './components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component';
|
import { QemuVmTemplatesComponent } from './components/preferences/qemu/qemu-vm-templates/qemu-vm-templates.component';
|
||||||
@ -60,7 +60,7 @@ const routes: Routes = [
|
|||||||
children: [
|
children: [
|
||||||
{ path: '', redirectTo: 'servers', pathMatch: 'full' },
|
{ path: '', redirectTo: 'servers', pathMatch: 'full' },
|
||||||
{ path: 'servers', component: ServersComponent },
|
{ path: 'servers', component: ServersComponent },
|
||||||
{ path: 'local', component: LocalServerComponent },
|
{ path: 'bundled', component: BundledServerFinderComponent },
|
||||||
{ path: 'server/:server_id/projects', component: ProjectsComponent },
|
{ path: 'server/:server_id/projects', component: ProjectsComponent },
|
||||||
{ path: 'settings', component: SettingsComponent },
|
{ path: 'settings', component: SettingsComponent },
|
||||||
{ path: 'settings/console', component: ConsoleComponent },
|
{ path: 'settings/console', component: ConsoleComponent },
|
||||||
@ -122,6 +122,10 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'server/:server_id/project/:project_id', component: ProjectMapComponent,
|
path: 'server/:server_id/project/:project_id', component: ProjectMapComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '**',
|
||||||
|
redirectTo: 'servers'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ import { ProjectMapShortcutsComponent } from './components/project-map/project-m
|
|||||||
import { SettingsComponent } from './components/settings/settings.component';
|
import { SettingsComponent } from './components/settings/settings.component';
|
||||||
import { SettingsService } from './services/settings.service';
|
import { SettingsService } from './services/settings.service';
|
||||||
|
|
||||||
import { LocalServerComponent } from './components/local-server/local-server.component';
|
import { BundledServerFinderComponent } from './components/bundled-server-finder/bundled-server-finder.component';
|
||||||
import { ProgressComponent } from './common/progress/progress.component';
|
import { ProgressComponent } from './common/progress/progress.component';
|
||||||
import { ProgressService } from './common/progress/progress.service';
|
import { ProgressService } from './common/progress/progress.service';
|
||||||
import { version } from './version';
|
import { version } from './version';
|
||||||
@ -168,8 +168,18 @@ import { ListOfSnapshotsComponent } from './components/snapshots/list-of-snapsho
|
|||||||
import { DateFilter } from './filters/dateFilter.pipe';
|
import { DateFilter } from './filters/dateFilter.pipe';
|
||||||
import { NameFilter } from './filters/nameFilter.pipe';
|
import { NameFilter } from './filters/nameFilter.pipe';
|
||||||
import { CustomAdaptersComponent } from './components/preferences/common/custom-adapters/custom-adapters.component';
|
import { CustomAdaptersComponent } from './components/preferences/common/custom-adapters/custom-adapters.component';
|
||||||
|
|
||||||
import { ConsoleDeviceActionComponent } from './components/project-map/context-menu/actions/console-device-action/console-device-action.component';
|
import { ConsoleDeviceActionComponent } from './components/project-map/context-menu/actions/console-device-action/console-device-action.component';
|
||||||
import { ConsoleComponent } from './components/settings/console/console.component';
|
import { ConsoleComponent } from './components/settings/console/console.component';
|
||||||
|
import { NodesMenuComponent } from './components/project-map/nodes-menu/nodes-menu.component';
|
||||||
|
import { PacketFiltersActionComponent } from './components/project-map/context-menu/actions/packet-filters-action/packet-filters-action.component';
|
||||||
|
import { PacketFiltersDialogComponent } from './components/project-map/packet-capturing/packet-filters/packet-filters.component';
|
||||||
|
import { HelpDialogComponent } from './components/project-map/help-dialog/help-dialog.component';
|
||||||
|
import { StartCaptureActionComponent } from './components/project-map/context-menu/actions/start-capture/start-capture-action.component';
|
||||||
|
import { StartCaptureDialogComponent } from './components/project-map/packet-capturing/start-capture/start-capture.component';
|
||||||
|
import { SuspendLinkActionComponent } from './components/project-map/context-menu/actions/suspend-link/suspend-link-action.component';
|
||||||
|
import { ResumeLinkActionComponent } from './components/project-map/context-menu/actions/resume-link-action/resume-link-action.component';
|
||||||
|
import { StopCaptureActionComponent } from './components/project-map/context-menu/actions/stop-capture/stop-capture-action.component';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||||
@ -204,10 +214,15 @@ if (environment.production) {
|
|||||||
EditStyleActionComponent,
|
EditStyleActionComponent,
|
||||||
EditTextActionComponent,
|
EditTextActionComponent,
|
||||||
DeleteActionComponent,
|
DeleteActionComponent,
|
||||||
|
PacketFiltersActionComponent,
|
||||||
|
StartCaptureActionComponent,
|
||||||
|
StopCaptureActionComponent,
|
||||||
|
ResumeLinkActionComponent,
|
||||||
|
SuspendLinkActionComponent,
|
||||||
ProjectMapShortcutsComponent,
|
ProjectMapShortcutsComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
PreferencesComponent,
|
PreferencesComponent,
|
||||||
LocalServerComponent,
|
BundledServerFinderComponent,
|
||||||
ProgressComponent,
|
ProgressComponent,
|
||||||
ServerDiscoveryComponent,
|
ServerDiscoveryComponent,
|
||||||
NodeSelectInterfaceComponent,
|
NodeSelectInterfaceComponent,
|
||||||
@ -225,6 +240,7 @@ if (environment.production) {
|
|||||||
InstallSoftwareComponent,
|
InstallSoftwareComponent,
|
||||||
StyleEditorDialogComponent,
|
StyleEditorDialogComponent,
|
||||||
TextEditorDialogComponent,
|
TextEditorDialogComponent,
|
||||||
|
PacketFiltersDialogComponent,
|
||||||
QemuPreferencesComponent,
|
QemuPreferencesComponent,
|
||||||
QemuVmTemplatesComponent,
|
QemuVmTemplatesComponent,
|
||||||
AddQemuVmTemplateComponent,
|
AddQemuVmTemplateComponent,
|
||||||
@ -258,6 +274,8 @@ if (environment.production) {
|
|||||||
VmwareTemplateDetailsComponent,
|
VmwareTemplateDetailsComponent,
|
||||||
AddVmwareTemplateComponent,
|
AddVmwareTemplateComponent,
|
||||||
DeleteConfirmationDialogComponent,
|
DeleteConfirmationDialogComponent,
|
||||||
|
HelpDialogComponent,
|
||||||
|
StartCaptureDialogComponent,
|
||||||
DeleteTemplateComponent,
|
DeleteTemplateComponent,
|
||||||
DockerTemplatesComponent,
|
DockerTemplatesComponent,
|
||||||
AddDockerTemplateComponent,
|
AddDockerTemplateComponent,
|
||||||
@ -277,7 +295,8 @@ if (environment.production) {
|
|||||||
ListOfSnapshotsComponent,
|
ListOfSnapshotsComponent,
|
||||||
CustomAdaptersComponent,
|
CustomAdaptersComponent,
|
||||||
ConsoleDeviceActionComponent,
|
ConsoleDeviceActionComponent,
|
||||||
ConsoleComponent
|
ConsoleComponent,
|
||||||
|
NodesMenuComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -357,9 +376,12 @@ if (environment.production) {
|
|||||||
ImportProjectDialogComponent,
|
ImportProjectDialogComponent,
|
||||||
ConfirmationDialogComponent,
|
ConfirmationDialogComponent,
|
||||||
StyleEditorDialogComponent,
|
StyleEditorDialogComponent,
|
||||||
|
PacketFiltersDialogComponent,
|
||||||
TextEditorDialogComponent,
|
TextEditorDialogComponent,
|
||||||
SymbolsComponent,
|
SymbolsComponent,
|
||||||
DeleteConfirmationDialogComponent
|
DeleteConfirmationDialogComponent,
|
||||||
|
HelpDialogComponent,
|
||||||
|
StartCaptureDialogComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@ -15,9 +15,11 @@ export class LinkToMapLinkConverter implements Converter<Link, MapLink> {
|
|||||||
mapLink.captureFileName = link.capture_file_name;
|
mapLink.captureFileName = link.capture_file_name;
|
||||||
mapLink.captureFilePath = link.capture_file_path;
|
mapLink.captureFilePath = link.capture_file_path;
|
||||||
mapLink.capturing = link.capturing;
|
mapLink.capturing = link.capturing;
|
||||||
|
mapLink.filters = link.filters;
|
||||||
mapLink.linkType = link.link_type;
|
mapLink.linkType = link.link_type;
|
||||||
mapLink.nodes = link.nodes.map(linkNode => this.linkNodeToMapLinkNode.convert(linkNode, { link_id: link.link_id }));
|
mapLink.nodes = link.nodes.map(linkNode => this.linkNodeToMapLinkNode.convert(linkNode, { link_id: link.link_id }));
|
||||||
mapLink.projectId = link.project_id;
|
mapLink.projectId = link.project_id;
|
||||||
|
mapLink.suspend = link.suspend;
|
||||||
return mapLink;
|
return mapLink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,11 @@ export class MapLinkToLinkConverter implements Converter<MapLink, Link> {
|
|||||||
link.capture_file_name = mapLink.captureFileName;
|
link.capture_file_name = mapLink.captureFileName;
|
||||||
link.capture_file_path = mapLink.captureFilePath;
|
link.capture_file_path = mapLink.captureFilePath;
|
||||||
link.capturing = mapLink.capturing;
|
link.capturing = mapLink.capturing;
|
||||||
|
link.filters = mapLink.filters;
|
||||||
link.link_type = mapLink.linkType;
|
link.link_type = mapLink.linkType;
|
||||||
link.nodes = mapLink.nodes.map(mapLinkNode => this.mapLinkNodeToMapLinkNode.convert(mapLinkNode));
|
link.nodes = mapLink.nodes.map(mapLinkNode => this.mapLinkNodeToMapLinkNode.convert(mapLinkNode));
|
||||||
link.project_id = mapLink.projectId;
|
link.project_id = mapLink.projectId;
|
||||||
|
link.suspend = mapLink.suspend;
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { TextElement } from '../models/drawings/text-element';
|
import { TextElement } from '../models/drawings/text-element';
|
||||||
import { MapDrawing } from '../models/map/map-drawing';
|
import { MapDrawing } from '../models/map/map-drawing';
|
||||||
|
import { MapLink } from '../models/map/map-link';
|
||||||
|
|
||||||
export class DataEventSource<T> {
|
export class DataEventSource<T> {
|
||||||
constructor(public datum: T, public dx: number, public dy: number) {}
|
constructor(public datum: T, public dx: number, public dy: number) {}
|
||||||
@ -30,3 +31,7 @@ export class TextEditedDataEvent {
|
|||||||
export class DrawingContextMenu {
|
export class DrawingContextMenu {
|
||||||
constructor(public event: any, public drawing: MapDrawing) {}
|
constructor(public event: any, public drawing: MapDrawing) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class LinkContextMenu {
|
||||||
|
constructor(public event:any, public link: MapLink) {}
|
||||||
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import { MapLinkNode } from './map-link-node';
|
import { MapLinkNode } from './map-link-node';
|
||||||
import { MapNode } from './map-node';
|
import { MapNode } from './map-node';
|
||||||
import { Indexed } from '../../datasources/map-datasource';
|
import { Indexed } from '../../datasources/map-datasource';
|
||||||
|
import { Filter } from '../../../models/filter';
|
||||||
|
|
||||||
export class MapLink implements Indexed {
|
export class MapLink implements Indexed {
|
||||||
id: string;
|
id: string;
|
||||||
captureFileName: string;
|
captureFileName: string;
|
||||||
captureFilePath: string;
|
captureFilePath: string;
|
||||||
capturing: boolean;
|
capturing: boolean;
|
||||||
|
filters?: Filter;
|
||||||
linkType: string;
|
linkType: string;
|
||||||
nodes: MapLinkNode[];
|
nodes: MapLinkNode[];
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
suspend: boolean;
|
||||||
|
|
||||||
distance: number; // this is not from server
|
distance: number; // this is not from server
|
||||||
length: number; // this is not from server
|
length: number; // this is not from server
|
||||||
|
@ -57,6 +57,12 @@ export class MovingTool {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// disable zooming on wheel
|
||||||
|
this.zoom.filter(() => {
|
||||||
|
const e: D3ZoomEvent<SVGSVGElement, any> = event;
|
||||||
|
return e.type === 'mousedown';
|
||||||
|
});
|
||||||
|
|
||||||
this.zoom.on('zoom', onZoom);
|
this.zoom.on('zoom', onZoom);
|
||||||
selection.call(this.zoom);
|
selection.call(this.zoom);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
import { Widget } from './widget';
|
import { Widget } from './widget';
|
||||||
import { SVGSelection } from '../models/types';
|
import { SVGSelection } from '../models/types';
|
||||||
@ -9,9 +9,13 @@ import { InterfaceLabelWidget } from './interface-label';
|
|||||||
import { InterfaceStatusWidget } from './interface-status';
|
import { InterfaceStatusWidget } from './interface-status';
|
||||||
import { MapLink } from '../models/map/map-link';
|
import { MapLink } from '../models/map/map-link';
|
||||||
import { SelectionManager } from '../managers/selection-manager';
|
import { SelectionManager } from '../managers/selection-manager';
|
||||||
|
import { event } from 'd3-selection';
|
||||||
|
import { LinkContextMenu } from '../events/event-source';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LinkWidget implements Widget {
|
export class LinkWidget implements Widget {
|
||||||
|
public onContextMenu = new EventEmitter<LinkContextMenu>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private multiLinkCalculatorHelper: MultiLinkCalculatorHelper,
|
private multiLinkCalculatorHelper: MultiLinkCalculatorHelper,
|
||||||
private interfaceLabelWidget: InterfaceLabelWidget,
|
private interfaceLabelWidget: InterfaceLabelWidget,
|
||||||
@ -32,6 +36,58 @@ export class LinkWidget implements Widget {
|
|||||||
return `translate (${translation.dx}, ${translation.dy})`;
|
return `translate (${translation.dx}, ${translation.dy})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
link_body.select('.capture-icon').remove();
|
||||||
|
link_body
|
||||||
|
.filter(l => { return l.capturing && !(l.filters.bpf || l.filters.corrupt || l.filters.delay || l.filters.frequency_drop || l.filters.packet_loss)})
|
||||||
|
.append<SVGGElement>('g')
|
||||||
|
.on('contextmenu', (datum: MapLink) => {
|
||||||
|
const evt = event;
|
||||||
|
this.onContextMenu.emit(new LinkContextMenu(evt, datum));
|
||||||
|
})
|
||||||
|
.attr('class', 'capture-icon')
|
||||||
|
.attr('transform', link => {
|
||||||
|
return `translate (${(link.source.x + link.target.x)/2 + 24}, ${(link.source.y + link.target.y)/2 + 24}) scale(0.5)`
|
||||||
|
})
|
||||||
|
.attr('viewBox', '0 0 20 20')
|
||||||
|
.append<SVGImageElement>('image')
|
||||||
|
.attr("xlink:href", "assets/resources/images/inspect.svg");
|
||||||
|
|
||||||
|
link_body.select('.filter-capture-icon').remove();
|
||||||
|
link_body
|
||||||
|
.filter(l => { return l.capturing && (l.filters.bpf || l.filters.corrupt || l.filters.delay || l.filters.frequency_drop || l.filters.packet_loss)})
|
||||||
|
.append<SVGGElement>('g')
|
||||||
|
.on('contextmenu', (datum: MapLink) => {
|
||||||
|
const evt = event;
|
||||||
|
this.onContextMenu.emit(new LinkContextMenu(evt, datum));
|
||||||
|
})
|
||||||
|
.attr('class', 'filter-capture-icon')
|
||||||
|
.attr('transform', link => {
|
||||||
|
return `translate (${(link.source.x + link.target.x)/2 + 24}, ${(link.source.y + link.target.y)/2 + 24}) scale(0.5)`
|
||||||
|
})
|
||||||
|
.attr('viewBox', '0 0 20 20')
|
||||||
|
.append<SVGImageElement>('image')
|
||||||
|
.attr("xlink:href", "assets/resources/images/filter-capture.svg");
|
||||||
|
|
||||||
|
link_body.select('.filter-icon').remove();
|
||||||
|
link_body
|
||||||
|
.filter(l => { return !l.capturing && (l.filters.bpf || l.filters.corrupt || l.filters.delay || l.filters.frequency_drop || l.filters.packet_loss)})
|
||||||
|
.append<SVGGElement>('g')
|
||||||
|
.on('contextmenu', (datum: MapLink) => {
|
||||||
|
const evt = event;
|
||||||
|
this.onContextMenu.emit(new LinkContextMenu(evt, datum));
|
||||||
|
})
|
||||||
|
.attr('class', 'filter-icon')
|
||||||
|
.attr('width', '48px')
|
||||||
|
.attr('height', '48px')
|
||||||
|
.attr('transform', link => {
|
||||||
|
return `translate (${(link.source.x + link.target.x)/2 + 24}, ${(link.source.y + link.target.y)/2 + 24}) scale(0.5)`
|
||||||
|
})
|
||||||
|
.attr('viewBox', '0 0 20 20')
|
||||||
|
.append<SVGImageElement>('image')
|
||||||
|
.attr('width', '48px')
|
||||||
|
.attr('height', '48px')
|
||||||
|
.attr("xlink:href", "assets/resources/images/filter.svg");
|
||||||
|
|
||||||
const serial_link_widget = new SerialLinkWidget();
|
const serial_link_widget = new SerialLinkWidget();
|
||||||
serial_link_widget.draw(link_body_merge);
|
serial_link_widget.draw(link_body_merge);
|
||||||
|
|
||||||
|
@ -5,6 +5,14 @@ import { ToasterErrorHandler } from './toaster-error-handler';
|
|||||||
import { RavenErrorHandler } from './raven-error-handler';
|
import { RavenErrorHandler } from './raven-error-handler';
|
||||||
import { SettingsService } from '../../services/settings.service';
|
import { SettingsService } from '../../services/settings.service';
|
||||||
import { MockedSettingsService } from '../../services/settings.service.spec';
|
import { MockedSettingsService } from '../../services/settings.service.spec';
|
||||||
|
import { Injector } from '@angular/core';
|
||||||
|
|
||||||
|
class MockedToasterErrorHandler extends ToasterErrorHandler {
|
||||||
|
handleError(err: any): void {
|
||||||
|
const toasterService = this.injector.get(ToasterService);
|
||||||
|
toasterService.error(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe('ToasterErrorHandler', () => {
|
describe('ToasterErrorHandler', () => {
|
||||||
let handler: ToasterErrorHandler;
|
let handler: ToasterErrorHandler;
|
||||||
@ -20,12 +28,13 @@ describe('ToasterErrorHandler', () => {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
handler = TestBed.get(ToasterErrorHandler);
|
handler = new MockedToasterErrorHandler(TestBed.get(Injector));
|
||||||
toasterService = TestBed.get(ToasterService);
|
toasterService = TestBed.get(ToasterService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call toaster with error message', () => {
|
it('should call toaster with error message', () => {
|
||||||
handler.handleError(new Error('message'));
|
handler.handleError(new Error('message'));
|
||||||
|
|
||||||
expect(toasterService.errors).toEqual(['message']);
|
expect(toasterService.errors).toEqual(['message']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<app-progress></app-progress>
|
@ -1,16 +1,21 @@
|
|||||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { LocalServerComponent } from './local-server.component';
|
import { BundledServerFinderComponent } from './bundled-server-finder.component';
|
||||||
import { ServerService } from '../../services/server.service';
|
import { ServerService } from '../../services/server.service';
|
||||||
import { MockedServerService } from '../../services/server.service.spec';
|
import { MockedServerService } from '../../services/server.service.spec';
|
||||||
import { Server } from '../../models/server';
|
import { Server } from '../../models/server';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { ProgressService } from '../../common/progress/progress.service';
|
||||||
|
import { MockedProgressService } from '../project-map/project-map.component.spec';
|
||||||
|
|
||||||
describe('LocalServerComponent', () => {
|
|
||||||
let component: LocalServerComponent;
|
describe('BundledServerFinderComponent', () => {
|
||||||
let fixture: ComponentFixture<LocalServerComponent>;
|
let component: BundledServerFinderComponent;
|
||||||
|
let fixture: ComponentFixture<BundledServerFinderComponent>;
|
||||||
let router: any;
|
let router: any;
|
||||||
let serverService: any;
|
let serverService: any;
|
||||||
|
let progressService: MockedProgressService = new MockedProgressService();
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
router = {
|
router = {
|
||||||
@ -24,11 +29,16 @@ describe('LocalServerComponent', () => {
|
|||||||
spyOn(serverService, 'getLocalServer').and.returnValue(Promise.resolve(server));
|
spyOn(serverService, 'getLocalServer').and.returnValue(Promise.resolve(server));
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [{ provide: Router, useValue: router }, { provide: ServerService, useValue: serverService }],
|
providers: [
|
||||||
declarations: [LocalServerComponent]
|
{ provide: Router, useValue: router },
|
||||||
|
{ provide: ServerService, useValue: serverService },
|
||||||
|
{ provide: ProgressService, useValue: progressService }
|
||||||
|
],
|
||||||
|
declarations: [BundledServerFinderComponent],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(LocalServerComponent);
|
fixture = TestBed.createComponent(BundledServerFinderComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
}));
|
}));
|
@ -0,0 +1,35 @@
|
|||||||
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
import { ServerService } from '../../services/server.service';
|
||||||
|
import { Server } from '../../models/server';
|
||||||
|
import { DOCUMENT } from '@angular/common';
|
||||||
|
import { ProgressService } from '../../common/progress/progress.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-bundled-server-finder',
|
||||||
|
templateUrl: './bundled-server-finder.component.html',
|
||||||
|
styleUrls: ['./bundled-server-finder.component.scss']
|
||||||
|
})
|
||||||
|
export class BundledServerFinderComponent implements OnInit {
|
||||||
|
constructor(
|
||||||
|
private router: Router,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private progressService: ProgressService,
|
||||||
|
@Inject(DOCUMENT) private document) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.progressService.activate();
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
this.serverService.getLocalServer(
|
||||||
|
this.document.location.hostname,
|
||||||
|
parseInt(this.document.location.port, 10))
|
||||||
|
.then((server: Server) => {
|
||||||
|
this.progressService.deactivate();
|
||||||
|
this.router.navigate(['/server', server.id, 'projects']);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
100);
|
||||||
|
}
|
||||||
|
}
|
@ -46,6 +46,10 @@ describe('DrawingAddedComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -30,6 +30,11 @@ describe('DrawingDraggedComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(DrawingDraggedComponent);
|
fixture = TestBed.createComponent(DrawingDraggedComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
@ -37,7 +42,6 @@ describe('DrawingDraggedComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call drawing service when drawing is dragged', () => {
|
it('should call drawing service when drawing is dragged', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
const mapDrawingElement: DrawingElement = {
|
const mapDrawingElement: DrawingElement = {
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100
|
height: 100
|
||||||
|
@ -33,6 +33,11 @@ describe('DrawingResizedComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(DrawingResizedComponent);
|
fixture = TestBed.createComponent(DrawingResizedComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
@ -40,7 +45,6 @@ describe('DrawingResizedComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call drawing service when drawing is resized', () => {
|
it('should call drawing service when drawing is resized', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
const mapDrawingElement: DrawingElement = {
|
const mapDrawingElement: DrawingElement = {
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100
|
height: 100
|
||||||
|
@ -32,6 +32,11 @@ describe('InterfaceLabelDraggedComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(InterfaceLabelDraggedComponent);
|
fixture = TestBed.createComponent(InterfaceLabelDraggedComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
@ -39,7 +44,6 @@ describe('InterfaceLabelDraggedComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call link service when interface label dragged', () => {
|
it('should call link service when interface label dragged', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
const mapLinkNode: MapLinkNode = {
|
const mapLinkNode: MapLinkNode = {
|
||||||
id: 'sampleId',
|
id: 'sampleId',
|
||||||
nodeId: 'sampleNodeId',
|
nodeId: 'sampleNodeId',
|
||||||
|
@ -47,17 +47,21 @@ describe('LinkCreatedComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(LinkCreatedComponent);
|
fixture = TestBed.createComponent(LinkCreatedComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
project.project_id = 'sampleId';
|
project.project_id = 'sampleId';
|
||||||
component.project = project;
|
component.project = project;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call link service when link created', () => {
|
it('should call link service when link created', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
const mapNode: MapNode = {
|
const mapNode: MapNode = {
|
||||||
id: 'sampleId',
|
id: 'sampleId',
|
||||||
commandLine: 'sampleCommandLine',
|
commandLine: 'sampleCommandLine',
|
||||||
|
@ -30,6 +30,11 @@ describe('NodeDraggedComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(NodeDraggedComponent);
|
fixture = TestBed.createComponent(NodeDraggedComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
@ -37,7 +42,6 @@ describe('NodeDraggedComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call node service when node dragged', () => {
|
it('should call node service when node dragged', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
const mapNode: MapNode = {
|
const mapNode: MapNode = {
|
||||||
id: 'sampleId',
|
id: 'sampleId',
|
||||||
commandLine: 'sampleCommandLine',
|
commandLine: 'sampleCommandLine',
|
||||||
|
@ -39,6 +39,11 @@ describe('NodeLabelDraggedComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(NodeLabelDraggedComponent);
|
fixture = TestBed.createComponent(NodeLabelDraggedComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
@ -46,7 +51,6 @@ describe('NodeLabelDraggedComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call node service when node label dragged', () => {
|
it('should call node service when node label dragged', () => {
|
||||||
fixture.detectChanges();
|
|
||||||
const mapLabel: MapLabel = {
|
const mapLabel: MapLabel = {
|
||||||
id: 'sample id',
|
id: 'sample id',
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
|
@ -48,6 +48,10 @@ describe('TextAddedComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,10 @@ describe('TextEditedComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
import { ServerService } from '../../services/server.service';
|
|
||||||
import { Server } from '../../models/server';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-local-server',
|
|
||||||
templateUrl: './local-server.component.html',
|
|
||||||
styleUrls: ['./local-server.component.scss']
|
|
||||||
})
|
|
||||||
export class LocalServerComponent implements OnInit {
|
|
||||||
constructor(private router: Router, private serverService: ServerService) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.serverService.getLocalServer(location.hostname, parseInt(location.port, 10)).then((server: Server) => {
|
|
||||||
this.router.navigate(['/server', server.id, 'projects']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -35,20 +35,28 @@ describe('CloudNodesAddTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatIconModule,
|
||||||
},
|
MatToolbarModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatMenuModule,
|
||||||
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
MatCheckboxModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
CommonModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
NoopAnimationsModule,
|
||||||
],
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/builtin/cloud-nodes', component: CloudNodesAddTemplateComponent}])
|
||||||
declarations: [
|
],
|
||||||
CloudNodesAddTemplateComponent
|
providers: [
|
||||||
],
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
CloudNodesAddTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -35,20 +35,30 @@ describe('EthernetHubsAddTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatIconModule,
|
||||||
},
|
MatToolbarModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatMenuModule,
|
||||||
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
MatCheckboxModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
CommonModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
NoopAnimationsModule,
|
||||||
],
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/builtin/ethernet-hubs', component: EthernetHubsAddTemplateComponent}])
|
||||||
declarations: [
|
],
|
||||||
EthernetHubsAddTemplateComponent
|
providers: [
|
||||||
],
|
{
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetHubsAddTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -35,20 +35,30 @@ describe('EthernetSwitchesAddTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatIconModule,
|
||||||
},
|
MatToolbarModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatMenuModule,
|
||||||
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
MatCheckboxModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
CommonModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
NoopAnimationsModule,
|
||||||
],
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/builtin/ethernet-switches', component: EthernetSwitchesAddTemplateComponent}])
|
||||||
declarations: [
|
],
|
||||||
EthernetSwitchesAddTemplateComponent
|
providers: [
|
||||||
],
|
{
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
|
},
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: BuiltInTemplatesService, useValue: mockedBuiltInTemplatesService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
EthernetSwitchesAddTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
|
class="filename"
|
||||||
type="text"
|
type="text"
|
||||||
[(ngModel)]="dockerTemplate.image"
|
[(ngModel)]="dockerTemplate.image"
|
||||||
formControlName="filename"
|
formControlName="filename"
|
||||||
@ -45,6 +46,7 @@
|
|||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
|
class="templatename"
|
||||||
type="text"
|
type="text"
|
||||||
[(ngModel)]="dockerTemplate.name"
|
[(ngModel)]="dockerTemplate.name"
|
||||||
formControlName="templateName"
|
formControlName="templateName"
|
||||||
@ -57,6 +59,7 @@
|
|||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
|
class="networkadapter"
|
||||||
type="number"
|
type="number"
|
||||||
[(ngModel)]="dockerTemplate.adapters"
|
[(ngModel)]="dockerTemplate.adapters"
|
||||||
formControlName="adapters"
|
formControlName="adapters"
|
||||||
@ -92,7 +95,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="buttons-bar">
|
<div class="buttons-bar">
|
||||||
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
<button mat-raised-button class="add-button" color="primary" (click)="addTemplate()">Add template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
|
||||||
import { MatInputModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatSelectModule, MatFormFieldModule, MatAutocompleteModule, MatTableModule, MatStepperModule } from '@angular/material';
|
import { MatInputModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatSelectModule, MatFormFieldModule, MatAutocompleteModule, MatTableModule, MatStepperModule, MatRadioModule, MatCommonModule } from '@angular/material';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute, Route } from '@angular/router';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { MockedServerService } from '../../../../services/server.service.spec';
|
import { MockedServerService } from '../../../../services/server.service.spec';
|
||||||
@ -13,11 +13,13 @@ import { ToasterService } from '../../../../services/toaster.service';
|
|||||||
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule, AbstractControlDirective, FormControl } from '@angular/forms';
|
||||||
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
import { AddDockerTemplateComponent } from './add-docker-template.component';
|
import { AddDockerTemplateComponent } from './add-docker-template.component';
|
||||||
import { DockerService } from '../../../../services/docker.service';
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
import { DockerConfigurationService } from '../../../../services/docker-configuration.service';
|
import { DockerConfigurationService } from '../../../../services/docker-configuration.service';
|
||||||
|
import { StepperOrientation, STEPPER_GLOBAL_OPTIONS, STEP_STATE, CdkStep } from '@angular/cdk/stepper';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
export class MockedDockerService {
|
export class MockedDockerService {
|
||||||
public addTemplate(server: Server, dockerTemplate: DockerTemplate) {
|
public addTemplate(server: Server, dockerTemplate: DockerTemplate) {
|
||||||
@ -25,7 +27,8 @@ export class MockedDockerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('AddDockerTemplateComponent', () => {
|
//Tests disabled due to instability
|
||||||
|
xdescribe('AddDockerTemplateComponent', () => {
|
||||||
let component: AddDockerTemplateComponent;
|
let component: AddDockerTemplateComponent;
|
||||||
let fixture: ComponentFixture<AddDockerTemplateComponent>;
|
let fixture: ComponentFixture<AddDockerTemplateComponent>;
|
||||||
|
|
||||||
@ -36,76 +39,165 @@ describe('AddDockerTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatStepperModule, FormsModule, MatTableModule, MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, MatSelectModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
MatStepperModule,
|
||||||
{
|
MatAutocompleteModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatCommonModule,
|
||||||
},
|
MatRadioModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
FormsModule,
|
||||||
{ provide: DockerService, useValue: mockedDockerService },
|
MatTableModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
MatAutocompleteModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
MatFormFieldModule,
|
||||||
{ provide: DockerConfigurationService, useClass: DockerConfigurationService }
|
MatInputModule,
|
||||||
],
|
ReactiveFormsModule,
|
||||||
declarations: [
|
MatSelectModule,
|
||||||
AddDockerTemplateComponent
|
MatIconModule,
|
||||||
],
|
MatToolbarModule,
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
MatMenuModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
CommonModule,
|
||||||
|
NoopAnimationsModule,
|
||||||
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/docker/templates', component: AddDockerTemplateComponent}])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: DockerService, useValue: mockedDockerService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
||||||
|
{ provide: DockerConfigurationService, useClass: DockerConfigurationService },
|
||||||
|
{ provide: AbstractControlDirective, useExisting: FormControl, useMulti: true },
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddDockerTemplateComponent
|
||||||
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(AddDockerTemplateComponent);
|
fixture = TestBed.createComponent(AddDockerTemplateComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open first step at start', async(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
fixture.whenStable().then(() => {
|
||||||
|
let stepperComponent = fixture.debugElement
|
||||||
|
.query(By.css('mat-vertical-stepper')).componentInstance;
|
||||||
|
|
||||||
it('should create', () => {
|
expect(stepperComponent.selectedIndex).toBe(0);
|
||||||
expect(component).toBeTruthy();
|
});
|
||||||
});
|
}));
|
||||||
|
|
||||||
it('should call add template', () => {
|
it('should display correct label at start', async(() => {
|
||||||
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
fixture.detectChanges();
|
||||||
component.virtualMachineForm.controls['filename'].setValue('sample name');
|
fixture.whenStable().then(() => {
|
||||||
component.containerNameForm.controls['templateName'].setValue('template name');
|
let selectedLabel = fixture.nativeElement
|
||||||
component.networkAdaptersForm.controls['adapters'].setValue(1);
|
.querySelector('[aria-selected="true"]');
|
||||||
component.server = {id: 1} as Server;
|
|
||||||
|
|
||||||
component.addTemplate();
|
expect(selectedLabel.textContent).toMatch('Server type');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
expect(mockedDockerService.addTemplate).toHaveBeenCalled();
|
it('should not call add template when required fields are empty', async(() => {
|
||||||
});
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let addButton = fixture.debugElement.nativeElement
|
||||||
|
.querySelector('.add-button');
|
||||||
|
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
|
||||||
|
addButton.click();
|
||||||
|
|
||||||
it('should not call add template when file name is missing', () => {
|
expect(component.virtualMachineForm.invalid).toBe(true);
|
||||||
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
expect(component.containerNameForm.invalid).toBe(true);
|
||||||
component.containerNameForm.controls['templateName'].setValue('template name');
|
expect(component.networkAdaptersForm.invalid).toBe(true);
|
||||||
component.networkAdaptersForm.controls['adapters'].setValue(1);
|
|
||||||
component.server = {id: 1} as Server;
|
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
component.addTemplate();
|
it('should call add template when required fields are filled', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let stepperComponent = fixture.debugElement
|
||||||
|
.query(By.css('mat-vertical-stepper')).componentInstance;
|
||||||
|
stepperComponent.selectedIndex = 1;
|
||||||
|
component.newImageSelected = true;
|
||||||
|
|
||||||
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
fixture.detectChanges();
|
||||||
});
|
fixture.whenStable().then(() => {
|
||||||
|
let selectedLabel = fixture.nativeElement
|
||||||
|
.querySelector('[aria-selected="true"]');
|
||||||
|
|
||||||
it('should not call add template when template name is missing', () => {
|
expect(selectedLabel.textContent).toMatch('Docker Virtual Machine');
|
||||||
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
|
||||||
component.virtualMachineForm.controls['filename'].setValue('sample name');
|
|
||||||
component.networkAdaptersForm.controls['adapters'].setValue(1);
|
|
||||||
component.server = {id: 1} as Server;
|
|
||||||
|
|
||||||
component.addTemplate();
|
let filenameInput = fixture.debugElement.nativeElement
|
||||||
|
.querySelector('.filename');
|
||||||
|
filenameInput.value = 'sample filename';
|
||||||
|
filenameInput.dispatchEvent(new Event('input'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.dockerTemplate.image).toBe('sample filename');
|
||||||
|
|
||||||
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
expect(component.virtualMachineForm.invalid).toBe(false);
|
||||||
});
|
expect(component.containerNameForm.invalid).toBe(true);
|
||||||
|
|
||||||
it('should not call add template when adapters field is empty', () => {
|
stepperComponent.selectedIndex = 2;
|
||||||
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
fixture.detectChanges();
|
||||||
component.virtualMachineForm.controls['filename'].setValue('sample name');
|
fixture.whenStable().then(() => {
|
||||||
component.containerNameForm.controls['templateName'].setValue('template name');
|
selectedLabel = fixture.nativeElement
|
||||||
component.server = {id: 1} as Server;
|
.querySelector('[aria-selected="true"]');
|
||||||
|
|
||||||
component.addTemplate();
|
expect(selectedLabel.textContent).toMatch('Container name');
|
||||||
|
|
||||||
expect(mockedDockerService.addTemplate).not.toHaveBeenCalled();
|
let templatenameInput = fixture.debugElement.nativeElement
|
||||||
});
|
.querySelector('.templatename');
|
||||||
|
templatenameInput.value = 'sample templatename';
|
||||||
|
templatenameInput.dispatchEvent(new Event('input'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.dockerTemplate.name).toBe('sample templatename');
|
||||||
|
|
||||||
|
expect(component.virtualMachineForm.invalid).toBe(false);
|
||||||
|
expect(component.containerNameForm.invalid).toBe(false);
|
||||||
|
|
||||||
|
stepperComponent.selectedIndex = 3;
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
selectedLabel = fixture.nativeElement
|
||||||
|
.querySelector('[aria-selected="true"]');
|
||||||
|
|
||||||
|
expect(selectedLabel.textContent).toMatch('Network adapters');
|
||||||
|
|
||||||
|
let networkadapterInput = fixture.debugElement.nativeElement
|
||||||
|
.querySelector('.networkadapter');
|
||||||
|
networkadapterInput.value = 2;
|
||||||
|
networkadapterInput.dispatchEvent(new Event('input'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.dockerTemplate.adapters).toBe(2);
|
||||||
|
|
||||||
|
expect(component.virtualMachineForm.invalid).toBe(false);
|
||||||
|
expect(component.containerNameForm.invalid).toBe(false);
|
||||||
|
expect(component.networkAdaptersForm.invalid).toBe(false);
|
||||||
|
|
||||||
|
let addButton = fixture.debugElement.nativeElement
|
||||||
|
.querySelector('.add-button');
|
||||||
|
spyOn(mockedDockerService, 'addTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
|
||||||
|
addButton.click();
|
||||||
|
|
||||||
|
expect(mockedDockerService.addTemplate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
@ -85,7 +85,7 @@ export class AddDockerTemplateComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (!this.virtualMachineForm.invalid && !this.containerNameForm.invalid && !this.networkAdaptersForm.invalid) {
|
if ((!this.virtualMachineForm.invalid || !this.newImageSelected) && !this.containerNameForm.invalid && !this.networkAdaptersForm.invalid) {
|
||||||
this.dockerTemplate.template_id = uuid();
|
this.dockerTemplate.template_id = uuid();
|
||||||
|
|
||||||
this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => {
|
this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => {
|
||||||
|
@ -25,7 +25,8 @@ export class MockedIosService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('AddIosTemplateComponent', () => {
|
//Tests disabled due to instability
|
||||||
|
xdescribe('AddIosTemplateComponent', () => {
|
||||||
let component: AddIosTemplateComponent;
|
let component: AddIosTemplateComponent;
|
||||||
let fixture: ComponentFixture<AddIosTemplateComponent>;
|
let fixture: ComponentFixture<AddIosTemplateComponent>;
|
||||||
|
|
||||||
@ -36,21 +37,35 @@ describe('AddIosTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatStepperModule, FormsModule, MatTableModule, MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, MatSelectModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
MatStepperModule,
|
||||||
{
|
FormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatTableModule,
|
||||||
},
|
MatAutocompleteModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatFormFieldModule,
|
||||||
{ provide: IosService, useValue: mockedIosService },
|
MatInputModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
ReactiveFormsModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
MatSelectModule,
|
||||||
{ provide: IosConfigurationService, useClass: IosConfigurationService }
|
MatIconModule,
|
||||||
],
|
MatToolbarModule,
|
||||||
declarations: [
|
MatMenuModule,
|
||||||
AddIosTemplateComponent
|
MatCheckboxModule,
|
||||||
],
|
CommonModule,
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
NoopAnimationsModule,
|
||||||
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/dynamips/templates', component: AddIosTemplateComponent}])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: IosService, useValue: mockedIosService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
||||||
|
{ provide: IosConfigurationService, useClass: IosConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddIosTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ export class MockedIouService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('AddIouTemplateComponent', () => {
|
//Tests disabled due to instability
|
||||||
|
xdescribe('AddIouTemplateComponent', () => {
|
||||||
let component: AddIouTemplateComponent;
|
let component: AddIouTemplateComponent;
|
||||||
let fixture: ComponentFixture<AddIouTemplateComponent>;
|
let fixture: ComponentFixture<AddIouTemplateComponent>;
|
||||||
|
|
||||||
@ -36,19 +37,35 @@ describe('AddIouTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatStepperModule, FormsModule, MatTableModule, MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule, MatSelectModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
MatStepperModule,
|
||||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
FormsModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatTableModule,
|
||||||
{ provide: IouService, useValue: mockedIouService },
|
MatAutocompleteModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
MatFormFieldModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
MatInputModule,
|
||||||
{ provide: IouConfigurationService, useClass: IouConfigurationService }
|
ReactiveFormsModule,
|
||||||
],
|
MatSelectModule,
|
||||||
declarations: [
|
MatIconModule,
|
||||||
AddIouTemplateComponent
|
MatToolbarModule,
|
||||||
],
|
MatMenuModule,
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
MatCheckboxModule,
|
||||||
|
CommonModule,
|
||||||
|
NoopAnimationsModule,
|
||||||
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/iou/templates', component: AddIouTemplateComponent}])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: IouService, useValue: mockedIouService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
||||||
|
{ provide: IouConfigurationService, useClass: IouConfigurationService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddIouTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ export class MockedQemuService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('AddQemuVmTemplateComponent', () => {
|
//Tests disabled due to instability
|
||||||
|
xdescribe('AddQemuVmTemplateComponent', () => {
|
||||||
let component: AddQemuVmTemplateComponent;
|
let component: AddQemuVmTemplateComponent;
|
||||||
let fixture: ComponentFixture<AddQemuVmTemplateComponent>;
|
let fixture: ComponentFixture<AddQemuVmTemplateComponent>;
|
||||||
|
|
||||||
@ -47,16 +48,28 @@ describe('AddQemuVmTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatStepperModule, FormsModule, ReactiveFormsModule, MatSelectModule, MatAutocompleteModule, MatIconModule, MatFormFieldModule, MatInputModule,
|
imports: [
|
||||||
MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
MatStepperModule,
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatSelectModule,
|
||||||
},
|
MatAutocompleteModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatToolbarModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
CommonModule,
|
||||||
|
NoopAnimationsModule,
|
||||||
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/qemu/templates', component: AddQemuVmTemplateComponent}])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
{ provide: Router, useValue: router },
|
{ provide: Router, useValue: router },
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
{ provide: QemuService, useValue: mockedQemuService },
|
{ provide: QemuService, useValue: mockedQemuService },
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
{ provide: TemplateMocksService, useClass: TemplateMocksService },
|
||||||
{ provide: QemuConfigurationService, useClass: QemuConfigurationService }
|
{ provide: QemuConfigurationService, useClass: QemuConfigurationService }
|
||||||
],
|
],
|
||||||
|
@ -11,7 +11,7 @@ import { ServerService } from '../../../../services/server.service';
|
|||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule, AbstractControlDirective, FormControl } from '@angular/forms';
|
||||||
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
import { QemuTemplate } from '../../../../models/templates/qemu-template';
|
import { QemuTemplate } from '../../../../models/templates/qemu-template';
|
||||||
import { QemuVmTemplateDetailsComponent } from './qemu-vm-template-details.component';
|
import { QemuVmTemplateDetailsComponent } from './qemu-vm-template-details.component';
|
||||||
@ -49,13 +49,12 @@ describe('QemuVmTemplateDetailsComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatTableModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [FormsModule, ReactiveFormsModule, MatTableModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
|
||||||
},
|
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
{ provide: QemuService, useValue: mockedQemuService },
|
{ provide: QemuService, useValue: mockedQemuService },
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
{ provide: ToasterService, useValue: mockedToasterService},
|
||||||
{ provide: QemuConfigurationService, useClass: QemuConfigurationService }
|
{ provide: QemuConfigurationService, useClass: QemuConfigurationService },
|
||||||
|
{ provide: AbstractControlDirective, useExisting: FormControl, useMulti: true }
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
QemuVmTemplateDetailsComponent
|
QemuVmTemplateDetailsComponent
|
||||||
|
@ -39,20 +39,28 @@ describe('AddVirtualBoxTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatIconModule,
|
||||||
},
|
MatToolbarModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatMenuModule,
|
||||||
{ provide: VirtualBoxService, useValue: mockedVirtualBoxService },
|
MatCheckboxModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
CommonModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
NoopAnimationsModule,
|
||||||
],
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/virtualbox/templates', component: AddVirtualBoxTemplateComponent}])
|
||||||
declarations: [
|
],
|
||||||
AddVirtualBoxTemplateComponent
|
providers: [
|
||||||
],
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: VirtualBoxService, useValue: mockedVirtualBoxService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddVirtualBoxTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -40,20 +40,28 @@ describe('AddVmwareTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatIconModule,
|
||||||
},
|
MatToolbarModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatMenuModule,
|
||||||
{ provide: VmwareService, useValue: mockedVmwareService },
|
MatCheckboxModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
CommonModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
NoopAnimationsModule,
|
||||||
],
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/vmware/templates', component: AddVmwareTemplateComponent}])
|
||||||
declarations: [
|
],
|
||||||
AddVmwareTemplateComponent
|
providers: [
|
||||||
],
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: VmwareService, useValue: mockedVmwareService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddVmwareTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<mat-card class="matCard">
|
<mat-card class="matCard">
|
||||||
<form [formGroup]="templateNameForm">
|
<form [formGroup]="templateNameForm">
|
||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<input matInput formControlName="templateName" type="text" [(ngModel)]="templateName" placeholder="Template name">
|
<input matInput formControlName="templateName" type="text" placeholder="Template name">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
@ -35,20 +35,28 @@ describe('AddVpcsTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
providers: [
|
FormsModule,
|
||||||
{
|
ReactiveFormsModule,
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
MatIconModule,
|
||||||
},
|
MatToolbarModule,
|
||||||
{ provide: ServerService, useValue: mockedServerService },
|
MatMenuModule,
|
||||||
{ provide: VpcsService, useValue: mockedVpcsService },
|
MatCheckboxModule,
|
||||||
{ provide: ToasterService, useValue: mockedToasterService},
|
CommonModule,
|
||||||
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
NoopAnimationsModule,
|
||||||
],
|
RouterTestingModule.withRoutes([{path: 'server/1/preferences/vpcs/templates', component: AddVpcsTemplateComponent}])
|
||||||
declarations: [
|
],
|
||||||
AddVpcsTemplateComponent
|
providers: [
|
||||||
],
|
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
{ provide: ServerService, useValue: mockedServerService },
|
||||||
|
{ provide: VpcsService, useValue: mockedVpcsService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService },
|
||||||
|
{ provide: TemplateMocksService, useClass: TemplateMocksService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AddVpcsTemplateComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ export class AddVpcsTemplateComponent implements OnInit {
|
|||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (!this.templateNameForm.invalid) {
|
if (!this.templateNameForm.invalid) {
|
||||||
|
this.templateName = this.templateNameForm.get('templateName').value;
|
||||||
|
|
||||||
let vpcsTemplate: VpcsTemplate;
|
let vpcsTemplate: VpcsTemplate;
|
||||||
|
|
||||||
this.templateMocksService.getVpcsTemplate().subscribe((template: VpcsTemplate) => {
|
this.templateMocksService.getVpcsTemplate().subscribe((template: VpcsTemplate) => {
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
<button mat-menu-item (click)="openPacketFilters()">
|
||||||
|
<mat-icon>filter_list</mat-icon>
|
||||||
|
<span>Packet filters</span>
|
||||||
|
</button>
|
@ -0,0 +1,30 @@
|
|||||||
|
import { Component, Input } from "@angular/core";
|
||||||
|
import { Link } from '../../../../../models/link';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { Project } from '../../../../../models/project';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
import { PacketFiltersDialogComponent } from '../../../packet-capturing/packet-filters/packet-filters.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-packet-filters-action',
|
||||||
|
templateUrl: './packet-filters-action.component.html'
|
||||||
|
})
|
||||||
|
export class PacketFiltersActionComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() project: Project;
|
||||||
|
@Input() link: Link;
|
||||||
|
|
||||||
|
constructor(private dialog: MatDialog) {}
|
||||||
|
|
||||||
|
openPacketFilters() {
|
||||||
|
const dialogRef = this.dialog.open(PacketFiltersDialogComponent, {
|
||||||
|
width: '900px',
|
||||||
|
height: '400px',
|
||||||
|
autoFocus: false
|
||||||
|
});
|
||||||
|
let instance = dialogRef.componentInstance;
|
||||||
|
instance.server = this.server;
|
||||||
|
instance.project = this.project;
|
||||||
|
instance.link = this.link;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
<button mat-menu-item *ngIf="link.suspend" (click)="resumeLink()">
|
||||||
|
<mat-icon>play_arrow</mat-icon>
|
||||||
|
<span>Resume</span>
|
||||||
|
</button>
|
@ -0,0 +1,22 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { Link } from '../../../../../models/link';
|
||||||
|
import { LinkService } from '../../../../../services/link.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-resume-link-action',
|
||||||
|
templateUrl: './resume-link-action.component.html'
|
||||||
|
})
|
||||||
|
export class ResumeLinkActionComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() link: Link;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private linkService: LinkService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
resumeLink() {
|
||||||
|
this.link.suspend = false;
|
||||||
|
this.linkService.updateLink(this.server, this.link).subscribe(() => {});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
<button mat-menu-item *ngIf="!link.capturing" (click)="startCapture()">
|
||||||
|
<mat-icon>loupe</mat-icon>
|
||||||
|
<span>Start capture</span>
|
||||||
|
</button>
|
@ -0,0 +1,26 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { Link } from '../../../../../models/link';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
import { StartCaptureDialogComponent } from '../../../packet-capturing/start-capture/start-capture.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-start-capture-action',
|
||||||
|
templateUrl: './start-capture-action.component.html'
|
||||||
|
})
|
||||||
|
export class StartCaptureActionComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() link: Link;
|
||||||
|
|
||||||
|
constructor(private dialog: MatDialog) {}
|
||||||
|
|
||||||
|
startCapture() {
|
||||||
|
const dialogRef = this.dialog.open(StartCaptureDialogComponent, {
|
||||||
|
width: '400px',
|
||||||
|
autoFocus: false
|
||||||
|
});
|
||||||
|
let instance = dialogRef.componentInstance;
|
||||||
|
instance.server = this.server;
|
||||||
|
instance.link = this.link;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, OnChanges } from '@angular/core';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
import { NodeService } from '../../../../../services/node.service';
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
import { Node } from '../../../../../cartography/models/node';
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
@ -7,7 +7,7 @@ import { Node } from '../../../../../cartography/models/node';
|
|||||||
selector: 'app-start-node-action',
|
selector: 'app-start-node-action',
|
||||||
templateUrl: './start-node-action.component.html'
|
templateUrl: './start-node-action.component.html'
|
||||||
})
|
})
|
||||||
export class StartNodeActionComponent implements OnInit {
|
export class StartNodeActionComponent implements OnInit, OnChanges {
|
||||||
@Input() server: Server;
|
@Input() server: Server;
|
||||||
@Input() nodes: Node[];
|
@Input() nodes: Node[];
|
||||||
isNodeWithStoppedStatus: boolean;
|
isNodeWithStoppedStatus: boolean;
|
||||||
@ -15,11 +15,17 @@ export class StartNodeActionComponent implements OnInit {
|
|||||||
constructor(private nodeService: NodeService) {}
|
constructor(private nodeService: NodeService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.nodes.forEach((node) => {
|
}
|
||||||
if (node.status === 'stopped') {
|
|
||||||
this.isNodeWithStoppedStatus = true;
|
ngOnChanges(changes) {
|
||||||
}
|
if(changes.nodes) {
|
||||||
});
|
this.isNodeWithStoppedStatus = false;
|
||||||
|
this.nodes.forEach((node) => {
|
||||||
|
if (node.status === 'stopped') {
|
||||||
|
this.isNodeWithStoppedStatus = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startNodes() {
|
startNodes() {
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
<button mat-menu-item *ngIf="link.capturing" (click)="stopCapture()">
|
||||||
|
<mat-icon>pause_circle_filled</mat-icon>
|
||||||
|
<span>Stop capture</span>
|
||||||
|
</button>
|
@ -0,0 +1,21 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { Link } from '../../../../../models/link';
|
||||||
|
import { LinkService } from '../../../../../services/link.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-stop-capture-action',
|
||||||
|
templateUrl: './stop-capture-action.component.html'
|
||||||
|
})
|
||||||
|
export class StopCaptureActionComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() link: Link;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private linkService: LinkService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
stopCapture() {
|
||||||
|
this.linkService.stopCaptureOnLink(this.server, this.link).subscribe(() => {});
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, OnChanges } from '@angular/core';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
import { NodeService } from '../../../../../services/node.service';
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
import { Node } from '../../../../../cartography/models/node';
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
@ -7,7 +7,7 @@ import { Node } from '../../../../../cartography/models/node';
|
|||||||
selector: 'app-stop-node-action',
|
selector: 'app-stop-node-action',
|
||||||
templateUrl: './stop-node-action.component.html'
|
templateUrl: './stop-node-action.component.html'
|
||||||
})
|
})
|
||||||
export class StopNodeActionComponent implements OnInit {
|
export class StopNodeActionComponent implements OnInit, OnChanges {
|
||||||
@Input() server: Server;
|
@Input() server: Server;
|
||||||
@Input() nodes: Node[];
|
@Input() nodes: Node[];
|
||||||
isNodeWithStartedStatus: boolean;
|
isNodeWithStartedStatus: boolean;
|
||||||
@ -15,11 +15,17 @@ export class StopNodeActionComponent implements OnInit {
|
|||||||
constructor(private nodeService: NodeService) {}
|
constructor(private nodeService: NodeService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.nodes.forEach((node) => {
|
}
|
||||||
if (node.status === 'started') {
|
|
||||||
this.isNodeWithStartedStatus = true;
|
ngOnChanges(changes) {
|
||||||
}
|
if(changes.nodes) {
|
||||||
});
|
this.isNodeWithStartedStatus = false;
|
||||||
|
this.nodes.forEach((node) => {
|
||||||
|
if (node.status === 'started') {
|
||||||
|
this.isNodeWithStartedStatus = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stopNodes() {
|
stopNodes() {
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
<button mat-menu-item *ngIf="!link.suspend" (click)="suspendLink()">
|
||||||
|
<mat-icon>pause</mat-icon>
|
||||||
|
<span>Suspend</span>
|
||||||
|
</button>
|
@ -0,0 +1,22 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { Link } from '../../../../../models/link';
|
||||||
|
import { LinkService } from '../../../../../services/link.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-suspend-link-action',
|
||||||
|
templateUrl: './suspend-link-action.component.html'
|
||||||
|
})
|
||||||
|
export class SuspendLinkActionComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() link: Link;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private linkService: LinkService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
suspendLink() {
|
||||||
|
this.link.suspend = true;
|
||||||
|
this.linkService.updateLink(this.server, this.link).subscribe(() => {});
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,34 @@
|
|||||||
[nodes]="nodes"
|
[nodes]="nodes"
|
||||||
[drawings]="drawings"
|
[drawings]="drawings"
|
||||||
></app-move-layer-down-action>
|
></app-move-layer-down-action>
|
||||||
|
<app-start-capture-action
|
||||||
|
*ngIf="!projectService.isReadOnly(project) && isBundledServer
|
||||||
|
&& drawings.length===0 && nodes.length===0 && links.length===1"
|
||||||
|
[server]="server"
|
||||||
|
[link]="links[0]"
|
||||||
|
></app-start-capture-action>
|
||||||
|
<app-stop-capture-action
|
||||||
|
*ngIf="!projectService.isReadOnly(project) && isBundledServer
|
||||||
|
&& drawings.length===0 && nodes.length===0 && links.length===1"
|
||||||
|
[server]="server"
|
||||||
|
[link]="links[0]"
|
||||||
|
></app-stop-capture-action>
|
||||||
|
<app-packet-filters-action
|
||||||
|
*ngIf="!projectService.isReadOnly(project) && drawings.length===0 && nodes.length===0 && links.length===1"
|
||||||
|
[server]="server"
|
||||||
|
[project]="project"
|
||||||
|
[link]="links[0]"
|
||||||
|
></app-packet-filters-action>
|
||||||
|
<app-resume-link-action
|
||||||
|
*ngIf="!projectService.isReadOnly(project) && drawings.length===0 && nodes.length===0 && links.length===1"
|
||||||
|
[server]="server"
|
||||||
|
[link]="links[0]"
|
||||||
|
></app-resume-link-action>
|
||||||
|
<app-suspend-link-action
|
||||||
|
*ngIf="!projectService.isReadOnly(project) && drawings.length===0 && nodes.length===0 && links.length===1"
|
||||||
|
[server]="server"
|
||||||
|
[link]="links[0]"
|
||||||
|
></app-suspend-link-action>
|
||||||
<app-delete-action
|
<app-delete-action
|
||||||
*ngIf="!projectService.isReadOnly(project)"
|
*ngIf="!projectService.isReadOnly(project)"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
|
@ -8,6 +8,7 @@ import { MatMenuModule, MatMenuTrigger } from '@angular/material';
|
|||||||
import { Drawing } from '../../../cartography/models/drawing';
|
import { Drawing } from '../../../cartography/models/drawing';
|
||||||
import { RectElement } from '../../../cartography/models/drawings/rect-element';
|
import { RectElement } from '../../../cartography/models/drawings/rect-element';
|
||||||
import { TextElement } from '../../../cartography/models/drawings/text-element';
|
import { TextElement } from '../../../cartography/models/drawings/text-element';
|
||||||
|
import { Server } from '../../../models/server';
|
||||||
|
|
||||||
describe('ContextMenuComponent', () => {
|
describe('ContextMenuComponent', () => {
|
||||||
let component: ContextMenuComponent;
|
let component: ContextMenuComponent;
|
||||||
@ -28,6 +29,7 @@ describe('ContextMenuComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(ContextMenuComponent);
|
fixture = TestBed.createComponent(ContextMenuComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
component.server = {location: 'local'} as Server;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ export class ContextMenuComponent implements OnInit {
|
|||||||
|
|
||||||
hasTextCapabilities = false;
|
hasTextCapabilities = false;
|
||||||
isElectronApp = false;
|
isElectronApp = false;
|
||||||
|
isBundledServer: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private sanitizer: DomSanitizer,
|
private sanitizer: DomSanitizer,
|
||||||
@ -43,7 +44,9 @@ export class ContextMenuComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.setPosition(0, 0);
|
this.setPosition(0, 0);
|
||||||
|
|
||||||
this.isElectronApp = this.electronService.isElectronApp;
|
this.isElectronApp = this.electronService.isElectronApp;
|
||||||
|
this.isBundledServer = this.server.location === 'bundled';
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPosition(top: number, left: number) {
|
public setPosition(top: number, left: number) {
|
||||||
|
@ -9,6 +9,8 @@ import { MapPort } from '../../../cartography/models/map/map-port';
|
|||||||
import { MapLinkCreated } from '../../../cartography/events/links';
|
import { MapLinkCreated } from '../../../cartography/events/links';
|
||||||
import { Link } from '../../../models/link';
|
import { Link } from '../../../models/link';
|
||||||
import { MapNodeToNodeConverter } from '../../../cartography/converters/map/map-node-to-node-converter';
|
import { MapNodeToNodeConverter } from '../../../cartography/converters/map/map-node-to-node-converter';
|
||||||
|
import { PortToMapPortConverter } from '../../../cartography/converters/map/port-to-map-port-converter';
|
||||||
|
import { NodeToMapNodeConverter } from '../../../cartography/converters/map/node-to-map-node-converter';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-draw-link-tool',
|
selector: 'app-draw-link-tool',
|
||||||
@ -25,7 +27,9 @@ export class DrawLinkToolComponent implements OnInit, OnDestroy {
|
|||||||
private drawingLineTool: DrawingLineWidget,
|
private drawingLineTool: DrawingLineWidget,
|
||||||
private nodesEventSource: NodesEventSource,
|
private nodesEventSource: NodesEventSource,
|
||||||
private linksEventSource: LinksEventSource,
|
private linksEventSource: LinksEventSource,
|
||||||
private mapNodeToNode: MapNodeToNodeConverter
|
private mapNodeToNode: MapNodeToNodeConverter,
|
||||||
|
private nodeToMapNode: NodeToMapNodeConverter,
|
||||||
|
private portToMapPort: PortToMapPortConverter
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -43,8 +47,8 @@ export class DrawLinkToolComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onChooseInterface(event) {
|
public onChooseInterface(event) {
|
||||||
const node: MapNode = event.node;
|
const node: MapNode = this.nodeToMapNode.convert(event.node);
|
||||||
const port: MapPort = event.port;
|
const port: MapPort = this.portToMapPort.convert(event.port);
|
||||||
if (this.drawingLineTool.isDrawing()) {
|
if (this.drawingLineTool.isDrawing()) {
|
||||||
const data = this.drawingLineTool.stop();
|
const data = this.drawingLineTool.stop();
|
||||||
this.linksEventSource.created.emit(new MapLinkCreated(data['node'], data['port'], node, port));
|
this.linksEventSource.created.emit(new MapLinkCreated(data['node'], data['port'], node, port));
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
<h1 mat-dialog-title>{{title}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="message" *ngFor="let message of messages; let i = index">
|
||||||
|
<h6>
|
||||||
|
{{message.name}}
|
||||||
|
</h6>
|
||||||
|
<span class="description">
|
||||||
|
{{message.description}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCloseClick()" color="accent">Close</button>
|
||||||
|
</div>
|
@ -0,0 +1,7 @@
|
|||||||
|
.message {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #b0bec5;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { Message } from '../../../models/message';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-help-dialog',
|
||||||
|
templateUrl: './help-dialog.component.html',
|
||||||
|
styleUrls: ['./help-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class HelpDialogComponent {
|
||||||
|
@Input() title: string;
|
||||||
|
@Input() messages: Message[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<HelpDialogComponent>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
onCloseClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<button
|
||||||
|
matTooltip="Start/Resume all nodes"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="startNodes()"
|
||||||
|
class="menu-button"
|
||||||
|
>
|
||||||
|
<mat-icon>play_arrow</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
matTooltip="Suspend all nodes"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="suspendNodes()"
|
||||||
|
class="menu-button"
|
||||||
|
>
|
||||||
|
<mat-icon>pause</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
matTooltip="Stop all nodes"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="stopNodes()"
|
||||||
|
class="menu-button"
|
||||||
|
>
|
||||||
|
<mat-icon>stop</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
matTooltip="Reload all nodes"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="reloadNodes()"
|
||||||
|
class="menu-button"
|
||||||
|
>
|
||||||
|
<mat-icon>replay</mat-icon>
|
||||||
|
</button>
|
@ -0,0 +1,12 @@
|
|||||||
|
.menu-button {
|
||||||
|
outline: 0 !important;
|
||||||
|
transition: 0.5s;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 40px;
|
||||||
|
margin-right: 12px !important;
|
||||||
|
margin-left: 12px !important;
|
||||||
|
background: #263238;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { NodesMenuComponent } from './nodes-menu.component';
|
||||||
|
import { MockedToasterService } from '../../../services/toaster.service.spec';
|
||||||
|
import { MockedNodeService } from '../project-map.component.spec';
|
||||||
|
import { MatButtonModule, MatIconModule } from '@angular/material';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { NodeService } from '../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
|
describe('NodesMenuComponent', () => {
|
||||||
|
let component: NodesMenuComponent;
|
||||||
|
let fixture: ComponentFixture<NodesMenuComponent>;
|
||||||
|
let mockedToasterService: MockedToasterService = new MockedToasterService();
|
||||||
|
let mockedNodeService: MockedNodeService = new MockedNodeService();
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatButtonModule, MatIconModule, CommonModule, NoopAnimationsModule],
|
||||||
|
providers: [
|
||||||
|
{ provide: NodeService, useValue: mockedNodeService },
|
||||||
|
{ provide: ToasterService, useValue: mockedToasterService }
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
NodesMenuComponent,
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NodesMenuComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call start all nodes', () => {
|
||||||
|
spyOn(mockedNodeService, 'startAll').and.returnValue(of());
|
||||||
|
|
||||||
|
component.startNodes();
|
||||||
|
|
||||||
|
expect(mockedNodeService.startAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call stop all nodes', () => {
|
||||||
|
spyOn(mockedNodeService, 'stopAll').and.returnValue(of());
|
||||||
|
|
||||||
|
component.stopNodes();
|
||||||
|
|
||||||
|
expect(mockedNodeService.stopAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call suspend all nodes', () => {
|
||||||
|
spyOn(mockedNodeService, 'suspendAll').and.returnValue(of());
|
||||||
|
|
||||||
|
component.suspendNodes();
|
||||||
|
|
||||||
|
expect(mockedNodeService.suspendAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call reload all nodes', () => {
|
||||||
|
spyOn(mockedNodeService, 'reloadAll').and.returnValue(of());
|
||||||
|
|
||||||
|
component.reloadNodes();
|
||||||
|
|
||||||
|
expect(mockedNodeService.reloadAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,44 @@
|
|||||||
|
import { Component, Input } from "@angular/core";
|
||||||
|
import { Project } from '../../../models/project';
|
||||||
|
import { Server } from '../../../models/server';
|
||||||
|
import { NodeService } from '../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nodes-menu',
|
||||||
|
templateUrl: './nodes-menu.component.html',
|
||||||
|
styleUrls: ['./nodes-menu.component.scss']
|
||||||
|
})
|
||||||
|
export class NodesMenuComponent {
|
||||||
|
@Input('project') project: Project;
|
||||||
|
@Input('server') server: Server;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
startNodes() {
|
||||||
|
this.nodeService.startAll(this.server, this.project).subscribe(() => {
|
||||||
|
this.toasterService.success('All nodes successfully started');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stopNodes() {
|
||||||
|
this.nodeService.stopAll(this.server, this.project).subscribe(() => {
|
||||||
|
this.toasterService.success('All nodes successfully stopped');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
suspendNodes() {
|
||||||
|
this.nodeService.suspendAll(this.server, this.project).subscribe(() => {
|
||||||
|
this.toasterService.success('All nodes successfully suspended');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadNodes() {
|
||||||
|
this.nodeService.reloadAll(this.server, this.project).subscribe(() => {
|
||||||
|
this.toasterService.success('All nodes successfully reloaded');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
<h1 mat-dialog-title>Packet filters</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container" class="content">
|
||||||
|
<mat-tab-group *ngIf="this.filters">
|
||||||
|
<mat-tab label="Frequency drop">
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<input matInput placeholder="Frequency" type="number" [(ngModel)]="filters.frequency_drop[0]">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Packet loss">
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<input matInput placeholder="Chance" type="number" [(ngModel)]="filters.packet_loss[0]">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Delay">
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<input matInput placeholder="Latency" type="number" [(ngModel)]="filters.delay[0]">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<input matInput placeholder="Jitter" type="number" [(ngModel)]="filters.delay[1]">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Corrupt">
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<input matInput placeholder="Latency" type="number" [(ngModel)]="filters.corrupt[0]">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Berkeley Packet Filter (BPF)">
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="filters.bpf[0]"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-bar">
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div mat-dialog-actions layout="row" class="dialog-actions">
|
||||||
|
<button mat-button (click)="onNoClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onResetClick()" color="accent">Reset</button>
|
||||||
|
<button mat-button (click)="onYesClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<button mat-button (click)="onHelpClick()" color="accent">Help</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -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%;
|
||||||
|
}
|
@ -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<PacketFiltersDialogComponent>;
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
@ -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<PacketFiltersDialogComponent>,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<h1 mat-dialog-title>Packet capture</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Link type"
|
||||||
|
formControlName="linkType"
|
||||||
|
ngDefaultControl>
|
||||||
|
<mat-option *ngFor="let type of linkTypes" [value]="type[1]">
|
||||||
|
{{type[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="input-field">
|
||||||
|
<input
|
||||||
|
placeholder="File name"
|
||||||
|
formControlName="fileName"
|
||||||
|
matInput type="text">
|
||||||
|
</mat-form-field>
|
||||||
|
<!-- <mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="startProgram">
|
||||||
|
Start the capture visualization program
|
||||||
|
</mat-checkbox> -->
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onNoClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onYesClick()" tabindex="2" mat-raised-button color="primary">Ok</button>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
.input-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -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<StartCaptureDialogComponent>;
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
@ -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<PacketFiltersDialogComponent>,
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@
|
|||||||
<div class="project-toolbar">
|
<div class="project-toolbar">
|
||||||
<mat-toolbar color="primary" class="project-toolbar">
|
<mat-toolbar color="primary" class="project-toolbar">
|
||||||
<mat-toolbar-row>
|
<mat-toolbar-row>
|
||||||
<button mat-icon-button [matMenuTriggerFor]="mainMenu"><mat-icon svgIcon="gns3"></mat-icon></button>
|
<button matTooltip="Open menu" mat-icon-button [matMenuTriggerFor]="mainMenu"><mat-icon svgIcon="gns3"></mat-icon></button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-menu #mainMenu="matMenu" [overlapTrigger]="false">
|
<mat-menu #mainMenu="matMenu" [overlapTrigger]="false">
|
||||||
@ -48,7 +48,7 @@
|
|||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<mat-toolbar-row>
|
<mat-toolbar-row>
|
||||||
<button mat-icon-button [matMenuTriggerFor]="viewMenu"><mat-icon>view_module</mat-icon></button>
|
<button matTooltip="Show/hide interface labels" mat-icon-button [matMenuTriggerFor]="viewMenu"><mat-icon>view_module</mat-icon></button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-menu #viewMenu="matMenu" [overlapTrigger]="false">
|
<mat-menu #viewMenu="matMenu" [overlapTrigger]="false">
|
||||||
@ -60,13 +60,13 @@
|
|||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
<button mat-icon-button [color]="tools.draw_link ? 'primary' : 'basic'" (click)="toggleDrawLineMode()">
|
<button matTooltip="Add a link" mat-icon-button [color]="tools.draw_link ? 'primary' : 'basic'" (click)="toggleDrawLineMode()">
|
||||||
<mat-icon>timeline</mat-icon>
|
<mat-icon>timeline</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row>
|
<mat-toolbar-row>
|
||||||
<button mat-icon-button [color]="tools.moving ? 'primary' : 'basic'" (click)="toggleMovingMode()">
|
<button matTooltip="Enable/disable moving mode" mat-icon-button [color]="tools.moving ? 'primary' : 'basic'" (click)="toggleMovingMode()">
|
||||||
<mat-icon>zoom_out_map</mat-icon>
|
<mat-icon>zoom_out_map</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
@ -80,18 +80,20 @@
|
|||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
<button mat-icon-button routerLink="/server/{{server.id}}/preferences">
|
<button matTooltip="Go to preferences" mat-icon-button routerLink="/server/{{server.id}}/preferences">
|
||||||
<mat-icon>settings_applications</mat-icon>
|
<mat-icon>settings_applications</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="show-menu-wrapper" [ngClass]="{ shadowed: !drawTools.visibility }">
|
<div id="show-menu-wrapper" [ngClass]="{ shadowed: !drawTools.visibility }" *ngIf="!readonly">
|
||||||
<button class="arrow-button" mat-icon-button (click)="showMenu()"><mat-icon>keyboard_arrow_right</mat-icon></button>
|
<button class="arrow-button" mat-icon-button (click)="showMenu()"><mat-icon>keyboard_arrow_right</mat-icon></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="menu-wrapper" [ngClass]="{ extended: drawTools.visibility }">
|
<div id="menu-wrapper" [ngClass]="{ extended: drawTools.visibility }">
|
||||||
|
<app-nodes-menu [server]="server" [project]="project"></app-nodes-menu>
|
||||||
|
<mat-divider class="divider" [vertical]="true"></mat-divider>
|
||||||
<button
|
<button
|
||||||
matTooltip="Add a note"
|
matTooltip="Add a note"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
@ -119,7 +121,7 @@
|
|||||||
>
|
>
|
||||||
<mat-icon>panorama_fish_eye</mat-icon>
|
<mat-icon>panorama_fish_eye</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button matTooltip="Draw line" mat-icon-button class="menu-button" (click)="addDrawing('line')">
|
<button matTooltip="Draw a line" mat-icon-button class="menu-button" (click)="addDrawing('line')">
|
||||||
<svg height="40" width="40">
|
<svg height="40" width="40">
|
||||||
<line
|
<line
|
||||||
[ngClass]="{ selected: drawTools.isLineChosen }"
|
[ngClass]="{ selected: drawTools.isLineChosen }"
|
||||||
|
@ -53,6 +53,7 @@ g.node:hover {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: 0.15s;
|
transition: 0.15s;
|
||||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
display: flex;
|
||||||
|
|
||||||
.menu-button {
|
.menu-button {
|
||||||
outline: 0 !important;
|
outline: 0 !important;
|
||||||
@ -75,11 +76,19 @@ g.node:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.extended {
|
.extended {
|
||||||
width: 296px !important;
|
width: 570px !important;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mat-divider.divider {
|
||||||
|
height: 40px;
|
||||||
|
margin-left: 1px;
|
||||||
|
margin-right: 7px;
|
||||||
|
width: 10px;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
@-moz-document url-prefix() {
|
@-moz-document url-prefix() {
|
||||||
/** fixes gray background of drawing menu on Firefox **/
|
/** fixes gray background of drawing menu on Firefox **/
|
||||||
.mat-drawer-content {
|
.mat-drawer-content {
|
||||||
|
@ -39,9 +39,14 @@ import { SelectionTool } from '../../cartography/tools/selection-tool';
|
|||||||
import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service';
|
import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service';
|
||||||
import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter';
|
import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter';
|
||||||
import { Link } from '../../models/link';
|
import { Link } from '../../models/link';
|
||||||
|
import { Project } from '../../models/project';
|
||||||
|
import { CapturingSettings } from '../../models/capturingSettings';
|
||||||
|
import { LinkWidget } from '../../cartography/widgets/link';
|
||||||
|
|
||||||
export class MockedProgressService {
|
export class MockedProgressService {
|
||||||
public activate() {}
|
public activate() {}
|
||||||
|
|
||||||
|
public deactivate() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockedNodeService {
|
export class MockedNodeService {
|
||||||
@ -59,6 +64,22 @@ export class MockedNodeService {
|
|||||||
delete(server: Server, node: Node) {
|
delete(server: Server, node: Node) {
|
||||||
return of();
|
return of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startAll(server: Server, project: Project) {
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
stopAll(server: Server, project: Project) {
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
suspendAll(server: Server, project: Project) {
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadAll(server: Server, project: Project) {
|
||||||
|
return of();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockedDrawingService {
|
export class MockedDrawingService {
|
||||||
@ -93,8 +114,16 @@ export class MockedDrawingService {
|
|||||||
export class MockedLinkService {
|
export class MockedLinkService {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
getLink(server: Server, projectId: string, linkId: string) {
|
||||||
|
return of({});
|
||||||
|
}
|
||||||
|
|
||||||
deleteLink(_server: Server, link: Link){
|
deleteLink(_server: Server, link: Link){
|
||||||
return of({})
|
return of({});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLink(server: Server, link: Link) {
|
||||||
|
return of({});
|
||||||
}
|
}
|
||||||
|
|
||||||
createLink() {
|
createLink() {
|
||||||
@ -104,11 +133,21 @@ export class MockedLinkService {
|
|||||||
updateNodes() {
|
updateNodes() {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startCaptureOnLink(server: Server, link: Link, settings: CapturingSettings) {
|
||||||
|
return of({});
|
||||||
|
}
|
||||||
|
|
||||||
|
getAvailableFilters(server: Server, link: Link) {
|
||||||
|
return of({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockedDrawingsDataSource {
|
export class MockedDrawingsDataSource {
|
||||||
add() {}
|
add() {}
|
||||||
|
|
||||||
|
clear() {}
|
||||||
|
|
||||||
get() {
|
get() {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
@ -121,8 +160,10 @@ export class MockedDrawingsDataSource {
|
|||||||
export class MockedNodesDataSource {
|
export class MockedNodesDataSource {
|
||||||
add() {}
|
add() {}
|
||||||
|
|
||||||
|
clear() {}
|
||||||
|
|
||||||
get() {
|
get() {
|
||||||
return of({});
|
return {status: 'started'};
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
@ -130,11 +171,17 @@ export class MockedNodesDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MockedLinksDataSource {
|
||||||
|
clear() {}
|
||||||
|
}
|
||||||
|
|
||||||
describe('ProjectMapComponent', () => {
|
describe('ProjectMapComponent', () => {
|
||||||
let component: ProjectMapComponent;
|
let component: ProjectMapComponent;
|
||||||
let fixture: ComponentFixture<ProjectMapComponent>;
|
let fixture: ComponentFixture<ProjectMapComponent>;
|
||||||
let drawingService = new MockedDrawingService();
|
let drawingService = new MockedDrawingService();
|
||||||
let drawingsDataSource = new MockedDrawingsDataSource();
|
let drawingsDataSource = new MockedDrawingsDataSource();
|
||||||
|
let nodesDataSource = new MockedNodesDataSource();
|
||||||
|
let linksDataSource = new MockedLinksDataSource();
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@ -150,13 +197,14 @@ describe('ProjectMapComponent', () => {
|
|||||||
{ provide: ProjectWebServiceHandler },
|
{ provide: ProjectWebServiceHandler },
|
||||||
{ provide: MapChangeDetectorRef },
|
{ provide: MapChangeDetectorRef },
|
||||||
{ provide: NodeWidget },
|
{ provide: NodeWidget },
|
||||||
|
{ provide: LinkWidget },
|
||||||
{ provide: DrawingsWidget },
|
{ provide: DrawingsWidget },
|
||||||
{ provide: MapNodeToNodeConverter },
|
{ provide: MapNodeToNodeConverter },
|
||||||
{ provide: MapDrawingToDrawingConverter },
|
{ provide: MapDrawingToDrawingConverter },
|
||||||
{ provide: MapLabelToLabelConverter },
|
{ provide: MapLabelToLabelConverter },
|
||||||
{ provide: MapLinkToLinkConverter },
|
{ provide: MapLinkToLinkConverter },
|
||||||
{ provide: NodesDataSource },
|
{ provide: NodesDataSource, useValue: nodesDataSource },
|
||||||
{ provide: LinksDataSource },
|
{ provide: LinksDataSource, useValue: linksDataSource },
|
||||||
{ provide: DrawingsDataSource, useValue: drawingsDataSource },
|
{ provide: DrawingsDataSource, useValue: drawingsDataSource },
|
||||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
{ provide: SettingsService, useClass: MockedSettingsService },
|
||||||
{ provide: ToolsService },
|
{ provide: ToolsService },
|
||||||
@ -177,6 +225,10 @@ describe('ProjectMapComponent', () => {
|
|||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.ngOnDestroy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -30,7 +30,7 @@ import { MapNodeToNodeConverter } from '../../cartography/converters/map/map-nod
|
|||||||
import { SettingsService, Settings } from '../../services/settings.service';
|
import { SettingsService, Settings } from '../../services/settings.service';
|
||||||
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
|
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
|
||||||
import { ToolsService } from '../../services/tools.service';
|
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 { MapDrawingToDrawingConverter } from '../../cartography/converters/map/map-drawing-to-drawing-converter';
|
||||||
import { SelectionManager } from '../../cartography/managers/selection-manager';
|
import { SelectionManager } from '../../cartography/managers/selection-manager';
|
||||||
import { SelectionTool } from '../../cartography/tools/selection-tool';
|
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 { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service';
|
||||||
import { MapLink } from '../../cartography/models/map/map-link';
|
import { MapLink } from '../../cartography/models/map/map-link';
|
||||||
import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter';
|
import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter';
|
||||||
|
import { LinkWidget } from '../../cartography/widgets/link';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -95,6 +96,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
private mapChangeDetectorRef: MapChangeDetectorRef,
|
private mapChangeDetectorRef: MapChangeDetectorRef,
|
||||||
private nodeWidget: NodeWidget,
|
private nodeWidget: NodeWidget,
|
||||||
private drawingsWidget: DrawingsWidget,
|
private drawingsWidget: DrawingsWidget,
|
||||||
|
private linkWidget: LinkWidget,
|
||||||
private mapNodeToNode: MapNodeToNodeConverter,
|
private mapNodeToNode: MapNodeToNodeConverter,
|
||||||
private mapDrawingToDrawing: MapDrawingToDrawingConverter,
|
private mapDrawingToDrawing: MapDrawingToDrawingConverter,
|
||||||
private mapLabelToLabel: MapLabelToLabelConverter,
|
private mapLabelToLabel: MapLabelToLabelConverter,
|
||||||
@ -219,6 +221,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.toolsService.selectionToolActivation(true);
|
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 onNodeContextMenu = this.nodeWidget.onContextMenu.subscribe((eventNode: NodeContextMenu) => {
|
||||||
const node = this.mapNodeToNode.convert(eventNode.node);
|
const node = this.mapNodeToNode.convert(eventNode.node);
|
||||||
this.contextMenu.openMenuForNode(node, eventNode.event.pageY, eventNode.event.pageX);
|
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.contextMenu.openMenuForListOfElements(drawings, nodes, labels, links, event.pageY, event.pageX);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.subscriptions.push(onLinkContextMenu);
|
||||||
this.subscriptions.push(onNodeContextMenu);
|
this.subscriptions.push(onNodeContextMenu);
|
||||||
this.subscriptions.push(onDrawingContextMenu);
|
this.subscriptions.push(onDrawingContextMenu);
|
||||||
this.subscriptions.push(onContextMenu);
|
this.subscriptions.push(onContextMenu);
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<!-- <div>
|
||||||
<mat-checkbox [(ngModel)]="settings.angular_map"
|
<mat-checkbox [(ngModel)]="settings.angular_map"
|
||||||
>Enable experimental Angular Map (WARNING: IT CAN BREAK YOU LABS!)</mat-checkbox
|
>Enable experimental Angular Map (WARNING: IT CAN BREAK YOU LABS!)</mat-checkbox
|
||||||
>
|
>
|
||||||
</div>
|
</div> -->
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
|
|
||||||
<mat-expansion-panel [expanded]="true">
|
<mat-expansion-panel [expanded]="true">
|
||||||
|
@ -3,9 +3,14 @@
|
|||||||
<button mat-button class="top-button" color="accent" (click)="onNoClick()" routerLink="/server/{{server.id}}/project/{{project.project_id}}/snapshots">Go to snapshots</button>
|
<button mat-button class="top-button" color="accent" (click)="onNoClick()" routerLink="/server/{{server.id}}/project/{{project.project_id}}/snapshots">Go to snapshots</button>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-content>
|
<div mat-dialog-content>
|
||||||
<mat-form-field class="name-input">
|
<form [formGroup]="inputForm">
|
||||||
<input matInput tabindex="1" [(ngModel)]="snapshot.name" placeholder="Name" />
|
<mat-form-field class="name-input">
|
||||||
</mat-form-field>
|
<input
|
||||||
|
matInput tabindex="1"
|
||||||
|
formControlName="snapshotName"
|
||||||
|
placeholder="Name" />
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions>
|
<div mat-dialog-actions>
|
||||||
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">No Thanks</button>
|
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">No Thanks</button>
|
||||||
|
@ -3,6 +3,11 @@ import { Snapshot } from '../../../models/snapshot';
|
|||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
import { Server } from '../../../models/server';
|
import { Server } from '../../../models/server';
|
||||||
import { Project } from '../../../models/project';
|
import { Project } from '../../../models/project';
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
|
import { SnapshotService } from '../../../services/snapshot.service';
|
||||||
|
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
|
||||||
|
import { Node } from '../../../cartography/models/node';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -14,17 +19,53 @@ export class CreateSnapshotDialogComponent {
|
|||||||
server: Server;
|
server: Server;
|
||||||
project: Project;
|
project: Project;
|
||||||
snapshot: Snapshot = new Snapshot();
|
snapshot: Snapshot = new Snapshot();
|
||||||
|
inputForm: FormGroup;
|
||||||
|
snapshots: string[] = [];
|
||||||
|
isInRunningState: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: MatDialogRef<CreateSnapshotDialogComponent>,
|
public dialogRef: MatDialogRef<CreateSnapshotDialogComponent>,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private snapshotService: SnapshotService,
|
||||||
|
private nodesDataSource: NodesDataSource,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
this.server = data['server'];
|
this.server = data['server'];
|
||||||
this.project = data['project'];
|
this.project = data['project'];
|
||||||
|
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
snapshotName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.snapshotService.list(this.server, this.project.project_id).subscribe((snapshots: Snapshot[]) => {
|
||||||
|
snapshots.forEach((snapshot: Snapshot) => {
|
||||||
|
this.snapshots.push(snapshot.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.nodesDataSource.getItems().forEach((node: Node) => {
|
||||||
|
if (node.status !== 'stopped' && !this.isAlwaysRunningNode(node.node_type)) {
|
||||||
|
this.isInRunningState = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isAlwaysRunningNode(nodeType: string) {
|
||||||
|
return !["qemu", "docker", "dynamips", "vpcs", "vmware", "virtualbox", "iou", "traceng"].includes(nodeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddClick(): void {
|
onAddClick(): void {
|
||||||
this.dialogRef.close(this.snapshot);
|
if (this.inputForm.invalid) {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else if (this.snapshots.includes(this.inputForm.get('snapshotName').value)) {
|
||||||
|
this.toasterService.error(`Snapshot with this name already exists`);
|
||||||
|
} else if (this.isInRunningState) {
|
||||||
|
this.toasterService.error(`Project must be stopped in order to export it`);
|
||||||
|
} else {
|
||||||
|
this.snapshot.name = this.inputForm.get('snapshotName').value;
|
||||||
|
this.dialogRef.close(this.snapshot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoClick(): void {
|
onNoClick(): void {
|
||||||
|
@ -1 +1 @@
|
|||||||
<button mat-icon-button (click)="createSnapshotModal()"><mat-icon>snooze</mat-icon></button>
|
<button matTooltip="Manage snapshots" mat-icon-button (click)="createSnapshotModal()"><mat-icon>snooze</mat-icon></button>
|
||||||
|
@ -48,11 +48,6 @@ export class SnapshotMenuItemComponent implements OnInit {
|
|||||||
(created_snapshot: Snapshot) => {
|
(created_snapshot: Snapshot) => {
|
||||||
this.toaster.success(`Snapshot '${snapshot.name}' has been created.`);
|
this.toaster.success(`Snapshot '${snapshot.name}' has been created.`);
|
||||||
progress.close();
|
progress.close();
|
||||||
},
|
|
||||||
response => {
|
|
||||||
const error = response.json();
|
|
||||||
this.toaster.error(`Cannot create snapshot: ${error.message}`);
|
|
||||||
progress.close();
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
<button mat-icon-button (click)="listTemplatesModal()"><mat-icon>add_to_queue</mat-icon></button>
|
<button matTooltip="Browse all devices" mat-icon-button (click)="listTemplatesModal()"><mat-icon>add_to_queue</mat-icon></button>
|
||||||
|
@ -67,6 +67,10 @@ header {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
.mat-dialog-content > * {
|
.mat-dialog-content > * {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,6 @@
|
|||||||
<app-progress></app-progress>
|
<app-progress></app-progress>
|
||||||
|
|
||||||
<footer class="footer mat-app-background">
|
<footer class="footer mat-app-background">
|
||||||
GNS3 Web UI © 2019
|
GNS3 Web UI © 2019 - v{{ uiVersion }}
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
@ -17,17 +17,20 @@ class ElectronServiceMock {
|
|||||||
public isElectronApp: boolean;
|
public isElectronApp: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockedServerManagementService {
|
||||||
|
public serverStatusChanged;
|
||||||
|
public stopAll() {}
|
||||||
|
}
|
||||||
|
|
||||||
describe('DefaultLayoutComponent', () => {
|
describe('DefaultLayoutComponent', () => {
|
||||||
let component: DefaultLayoutComponent;
|
let component: DefaultLayoutComponent;
|
||||||
let fixture: ComponentFixture<DefaultLayoutComponent>;
|
let fixture: ComponentFixture<DefaultLayoutComponent>;
|
||||||
let electronServiceMock: ElectronServiceMock;
|
let electronServiceMock: ElectronServiceMock;
|
||||||
let serverManagementService;
|
let serverManagementService = new MockedServerManagementService();
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
electronServiceMock = new ElectronServiceMock();
|
electronServiceMock = new ElectronServiceMock();
|
||||||
serverManagementService = {
|
serverManagementService.serverStatusChanged = new Subject<ServerStateEvent>();
|
||||||
serverStatusChanged: new Subject<ServerStateEvent>()
|
|
||||||
};
|
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [DefaultLayoutComponent, ProgressComponent],
|
declarations: [DefaultLayoutComponent, ProgressComponent],
|
||||||
|
@ -5,6 +5,8 @@ import { ServerManagementService } from '../../services/server-management.servic
|
|||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
import { ProgressService } from '../../common/progress/progress.service';
|
import { ProgressService } from '../../common/progress/progress.service';
|
||||||
|
import { version } from './../../version';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-default-layout',
|
selector: 'app-default-layout',
|
||||||
@ -14,7 +16,8 @@ import { ProgressService } from '../../common/progress/progress.service';
|
|||||||
})
|
})
|
||||||
export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
public isInstalledSoftwareAvailable = false;
|
public isInstalledSoftwareAvailable = false;
|
||||||
|
public uiVersion = version;
|
||||||
|
|
||||||
serverStatusSubscription: Subscription;
|
serverStatusSubscription: Subscription;
|
||||||
shouldStopServersOnClosing = true;
|
shouldStopServersOnClosing = true;
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ import {
|
|||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatGridListModule
|
MatGridListModule,
|
||||||
|
MatTabsModule
|
||||||
} from '@angular/material';
|
} from '@angular/material';
|
||||||
|
|
||||||
export const MATERIAL_IMPORTS = [
|
export const MATERIAL_IMPORTS = [
|
||||||
@ -43,5 +44,6 @@ export const MATERIAL_IMPORTS = [
|
|||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatGridListModule
|
MatGridListModule,
|
||||||
|
MatTabsModule
|
||||||
];
|
];
|
||||||
|
4
src/app/models/capturingSettings.ts
Normal file
4
src/app/models/capturingSettings.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export class CapturingSettings {
|
||||||
|
capture_file_name: string;
|
||||||
|
data_link_type: string;
|
||||||
|
}
|
14
src/app/models/filter-description.ts
Normal file
14
src/app/models/filter-description.ts
Normal file
@ -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;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user