Merge branch 'master' into Packet-capture-preferences

This commit is contained in:
Piotr Pekala 2019-03-26 08:12:20 -07:00
commit 226a04a638
11 changed files with 74 additions and 13 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "gns3-web-ui", "name": "gns3-web-ui",
"version": "2019.1.0-alpha.2dev", "version": "2019.1.0-alpha.3dev",
"author": { "author": {
"name": "GNS3 Technology Inc.", "name": "GNS3 Technology Inc.",
"email": "developers@gns3.com" "email": "developers@gns3.com"

View File

@ -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]

View File

@ -120,6 +120,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'
} }
]; ];

View File

@ -6,6 +6,7 @@ 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';
describe('LocalServerComponent', () => { describe('LocalServerComponent', () => {
let component: LocalServerComponent; let component: LocalServerComponent;
let fixture: ComponentFixture<LocalServerComponent>; let fixture: ComponentFixture<LocalServerComponent>;
@ -24,7 +25,8 @@ 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: [{ provide: Router, useValue: router },
{ provide: ServerService, useValue: serverService }],
declarations: [LocalServerComponent] declarations: [LocalServerComponent]
}).compileComponents(); }).compileComponents();

View File

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, Inject } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { ServerService } from '../../services/server.service'; import { ServerService } from '../../services/server.service';
import { Server } from '../../models/server'; import { Server } from '../../models/server';
import { DOCUMENT } from '@angular/common';
@Component({ @Component({
selector: 'app-local-server', selector: 'app-local-server',
@ -10,10 +11,16 @@ import { Server } from '../../models/server';
styleUrls: ['./local-server.component.scss'] styleUrls: ['./local-server.component.scss']
}) })
export class LocalServerComponent implements OnInit { export class LocalServerComponent implements OnInit {
constructor(private router: Router, private serverService: ServerService) {} constructor(
private router: Router,
private serverService: ServerService,
@Inject(DOCUMENT) private document) {}
ngOnInit() { ngOnInit() {
this.serverService.getLocalServer(location.hostname, parseInt(location.port, 10)).then((server: Server) => { this.serverService.getLocalServer(
this.document.location.hostname,
parseInt(this.document.location.port, 10))
.then((server: Server) => {
this.router.navigate(['/server', server.id, 'projects']); this.router.navigate(['/server', server.id, 'projects']);
}); });
} }

View File

@ -93,7 +93,7 @@
<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> <app-nodes-menu [server]="server" [project]="project"></app-nodes-menu>
<mat-divider class="style-fix" [vertical]="true"></mat-divider> <mat-divider class="divider" [vertical]="true"></mat-divider>
<button <button
matTooltip="Add a note" matTooltip="Add a note"
mat-icon-button mat-icon-button

View File

@ -81,11 +81,12 @@ g.node:hover {
overflow: hidden; overflow: hidden;
} }
mat-divider.style-fix { mat-divider.divider {
height: 40px; height: 40px;
margin-left: 1px; margin-left: 1px;
margin-right: 7px; margin-right: 7px;
width: 10px; width: 10px;
color: gray;
} }
@-moz-document url-prefix() { @-moz-document url-prefix() {

View File

@ -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>

View File

@ -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 {

View File

@ -151,7 +151,7 @@ describe('ServerService', () => {
expectedServer.name = 'local'; expectedServer.name = 'local';
expectedServer.host = 'hostname'; expectedServer.host = 'hostname';
expectedServer.port = 9999; expectedServer.port = 9999;
expectedServer.location = 'local'; expectedServer.location = 'remote';
expectedServer.is_local = true; expectedServer.is_local = true;
service.getLocalServer('hostname', 9999).then(() => { service.getLocalServer('hostname', 9999).then(() => {

View File

@ -70,7 +70,7 @@ export class ServerService {
server.name = 'local'; server.name = 'local';
server.host = host; server.host = host;
server.port = port; server.port = port;
server.location = 'local'; server.location = 'remote';
server.is_local = true; server.is_local = true;
this.create(server).then(created => { this.create(server).then(created => {
resolve(created); resolve(created);