mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-06-21 07:58:25 +00:00
Update from master
This commit is contained in:
@ -17,6 +17,9 @@ files:
|
|||||||
- local-server.js
|
- local-server.js
|
||||||
- package.json
|
- package.json
|
||||||
|
|
||||||
|
extraFiles:
|
||||||
|
- dist/exe.gns3server/**
|
||||||
|
|
||||||
mac:
|
mac:
|
||||||
category: public.app-category.developer-tools
|
category: public.app-category.developer-tools
|
||||||
# publish: github
|
# publish: github
|
||||||
|
@ -3,35 +3,24 @@ const kill = require('tree-kill');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { ipcMain } = require('electron')
|
const { ipcMain } = require('electron')
|
||||||
|
const { app } = require('electron')
|
||||||
|
|
||||||
const isWin = /^win/.test(process.platform);
|
const isWin = /^win/.test(process.platform);
|
||||||
|
|
||||||
let runningServers = {};
|
let runningServers = {};
|
||||||
|
|
||||||
exports.getLocalServerPath = async () => {
|
exports.getLocalServerPath = async () => {
|
||||||
const distDirectory = path.join(__dirname, 'dist');
|
const lookupDirectories = [
|
||||||
if (!fs.existsSync(distDirectory)) {
|
__dirname,
|
||||||
return;
|
path.dirname(app.getPath('exe'))
|
||||||
}
|
];
|
||||||
|
|
||||||
const files = fs.readdirSync(distDirectory);
|
for(var directory of lookupDirectories) {
|
||||||
|
const serverPath = await findLocalServerPath(directory);
|
||||||
let serverPath = null;
|
if(serverPath !== undefined) {
|
||||||
|
|
||||||
files.forEach((directory) => {
|
|
||||||
if(directory.startsWith('exe.')) {
|
|
||||||
if (isWin) {
|
|
||||||
serverPath = path.join(__dirname, 'dist', directory, 'gns3server.exe');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serverPath = path.join(__dirname, 'dist', directory, 'gns3server');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(serverPath !== null && fs.existsSync(serverPath)) {
|
|
||||||
return serverPath;
|
return serverPath;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -54,6 +43,35 @@ exports.stopAllLocalServers = async () => {
|
|||||||
return await stopAll();
|
return await stopAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function findLocalServerPath(baseDirectory) {
|
||||||
|
const distDirectory = path.join(baseDirectory, 'dist');
|
||||||
|
|
||||||
|
if (!fs.existsSync(distDirectory)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = fs.readdirSync(distDirectory);
|
||||||
|
|
||||||
|
let serverPath = null;
|
||||||
|
|
||||||
|
files.forEach((directory) => {
|
||||||
|
if(directory.startsWith('exe.')) {
|
||||||
|
if (isWin) {
|
||||||
|
serverPath = path.join(baseDirectory, 'dist', directory, 'gns3server.exe');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serverPath = path.join(baseDirectory, 'dist', directory, 'gns3server');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(serverPath !== null && fs.existsSync(serverPath)) {
|
||||||
|
return serverPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function getServerArguments(server, overrides) {
|
function getServerArguments(server, overrides) {
|
||||||
let serverArguments = [];
|
let serverArguments = [];
|
||||||
if(server.host) {
|
if(server.host) {
|
||||||
|
@ -167,6 +167,7 @@ import { DeleteActionComponent } from './components/project-map/context-menu/act
|
|||||||
import { ListOfSnapshotsComponent } from './components/snapshots/list-of-snapshots/list-of-snapshots.component';
|
import { ListOfSnapshotsComponent } from './components/snapshots/list-of-snapshots/list-of-snapshots.component';
|
||||||
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';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||||
@ -271,7 +272,8 @@ if (environment.production) {
|
|||||||
SearchFilter,
|
SearchFilter,
|
||||||
DateFilter,
|
DateFilter,
|
||||||
NameFilter,
|
NameFilter,
|
||||||
ListOfSnapshotsComponent
|
ListOfSnapshotsComponent,
|
||||||
|
CustomAdaptersComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
<div class="content" class="configurator">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">Custom adapters configuration</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<div class="container mat-elevation-z8">
|
||||||
|
<table class="table" mat-table [dataSource]="adapters">
|
||||||
|
<ng-container matColumnDef="adapter_number">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Adapter number </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> Adapter {{element.adapter_number}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="port_name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port name </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> Ethernet {{element.adapter_number}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="adapter_type">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Adapter type </th>
|
||||||
|
<td mat-cell *matCellDef="let element; let i = index;">
|
||||||
|
<mat-select placeholder="Type" [(ngModel)]="adapters[i].adapter_type">
|
||||||
|
<mat-option *ngFor="let type of networkTypes" [value]="type[0]">
|
||||||
|
{{type[1]}} ({{type[0]}})
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,47 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MatCheckboxModule, MatIconModule, MatToolbarModule, MatMenuModule, MatTableModule } from '@angular/material';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { CustomAdaptersComponent } from './custom-adapters.component';
|
||||||
|
|
||||||
|
describe('Custom adapters component', () => {
|
||||||
|
let component: CustomAdaptersComponent;
|
||||||
|
let fixture: ComponentFixture<CustomAdaptersComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MatTableModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule],
|
||||||
|
declarations: [
|
||||||
|
CustomAdaptersComponent
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CustomAdaptersComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit event when apply clicked', () => {
|
||||||
|
spyOn(component.saveConfigurationEmitter, 'emit');
|
||||||
|
|
||||||
|
component.configureCustomAdapters();
|
||||||
|
|
||||||
|
expect(component.saveConfigurationEmitter.emit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit event when cancel clicked', () => {
|
||||||
|
spyOn(component.closeConfiguratorEmitter, 'emit');
|
||||||
|
|
||||||
|
component.cancelConfigureCustomAdapters();
|
||||||
|
|
||||||
|
expect(component.closeConfiguratorEmitter.emit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,26 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-custom-adapters',
|
||||||
|
templateUrl: './custom-adapters.component.html',
|
||||||
|
styleUrls: ['./custom-adapters.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CustomAdaptersComponent {
|
||||||
|
@Input() networkTypes = [];
|
||||||
|
@Input() displayedColumns: string[] = [];
|
||||||
|
@Output() closeConfiguratorEmitter = new EventEmitter<boolean>();
|
||||||
|
@Output() saveConfigurationEmitter = new EventEmitter<CustomAdapter[]>();
|
||||||
|
|
||||||
|
public adapters: CustomAdapter[];
|
||||||
|
public numberOfAdapters: number;
|
||||||
|
|
||||||
|
cancelConfigureCustomAdapters(){
|
||||||
|
this.closeConfiguratorEmitter.emit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
configureCustomAdapters(){
|
||||||
|
this.saveConfigurationEmitter.emit(this.adapters);
|
||||||
|
}
|
||||||
|
}
|
@ -198,7 +198,7 @@
|
|||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-button class="configButton" (click)="configureCustomAdapters()">Configure custom adapters</button><br/>
|
<button mat-button class="configButton" (click)="setCustomAdaptersConfiguratorState(true)">Configure custom adapters</button><br/>
|
||||||
<mat-checkbox [(ngModel)]="qemuTemplate.legacy_networking">
|
<mat-checkbox [(ngModel)]="qemuTemplate.legacy_networking">
|
||||||
Use the legacy networking mode
|
Use the legacy networking mode
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
@ -326,44 +326,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
<app-custom-adapters
|
||||||
<div class="default-header">
|
[hidden]="!(isConfiguratorOpened && qemuTemplate)"
|
||||||
<div class="row">
|
#customAdaptersConfigurator
|
||||||
<h1 class="col">Custom adapters configuration</h1>
|
[networkTypes]="networkTypes"
|
||||||
</div>
|
[displayedColumns]="displayedColumns"
|
||||||
</div>
|
(closeConfiguratorEmitter)="setCustomAdaptersConfiguratorState($event)"
|
||||||
<div class="default-content" *ngIf="qemuTemplate">
|
(saveConfigurationEmitter)="saveCustomAdapters($event)"
|
||||||
<div class="container mat-elevation-z8">
|
></app-custom-adapters>
|
||||||
<table class="table" mat-table [dataSource]="adapters">
|
<app-symbols-menu
|
||||||
<ng-container matColumnDef="adapter_number">
|
*ngIf="isSymbolSelectionOpened && qemuTemplate"
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter number </th>
|
[server]="server"
|
||||||
<td mat-cell *matCellDef="let element"> Adapter {{element.adapter_number}} </td>
|
[symbol]="qemuTemplate.symbol"
|
||||||
</ng-container>
|
(symbolChangedEmitter)="symbolChanged($event)"
|
||||||
|
></app-symbols-menu>
|
||||||
<ng-container matColumnDef="port_name">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Port name </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> Ethernet {{element.adapter_number}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="adapter_type">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter type </th>
|
|
||||||
<td mat-cell *matCellDef="let element; let i = index;">
|
|
||||||
<mat-select placeholder="Type" [(ngModel)]="adapters[i].adapter_type">
|
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type[0]">
|
|
||||||
{{type[1]}} ({{type[0]}})
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="buttons-bar">
|
|
||||||
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
|
||||||
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-symbols-menu *ngIf="isSymbolSelectionOpened && qemuTemplate" [server]="server" [symbol]="qemuTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
|
||||||
|
@ -79,9 +79,59 @@ describe('QemuVmTemplateDetailsComponent', () => {
|
|||||||
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.qemuTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as QemuTemplate;
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
expect(mockedQemuService.saveTemplate).toHaveBeenCalled();
|
expect(mockedQemuService.saveTemplate).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not call save template when template name is empty', () => {
|
||||||
|
spyOn(mockedQemuService, 'saveTemplate').and.returnValue(of({} as QemuTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.qemuTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as QemuTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedQemuService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should not call save template when default name is empty', () => {
|
||||||
|
spyOn(mockedQemuService, 'saveTemplate').and.returnValue(of({} as QemuTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.qemuTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as QemuTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedQemuService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call save template when symbol is empty', () => {
|
||||||
|
spyOn(mockedQemuService, 'saveTemplate').and.returnValue(of({} as QemuTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('');
|
||||||
|
component.qemuTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as QemuTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedQemuService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit, ViewChildren, ViewChild, QueryList } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { QemuService } from '../../../../services/qemu.service';
|
import { QemuService } from '../../../../services/qemu.service';
|
||||||
@ -9,6 +9,7 @@ import { ToasterService } from '../../../../services/toaster.service';
|
|||||||
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
import { QemuConfigurationService } from '../../../../services/qemu-configuration.service';
|
import { QemuConfigurationService } from '../../../../services/qemu-configuration.service';
|
||||||
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
|
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
|
||||||
|
import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-adapters.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -19,9 +20,7 @@ import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms'
|
|||||||
export class QemuVmTemplateDetailsComponent implements OnInit {
|
export class QemuVmTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
qemuTemplate: QemuTemplate;
|
qemuTemplate: QemuTemplate;
|
||||||
|
|
||||||
isSymbolSelectionOpened: boolean = false;
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
consoleTypes: string[] = [];
|
consoleTypes: string[] = [];
|
||||||
diskInterfaces: string[] = [];
|
diskInterfaces: string[] = [];
|
||||||
networkTypes = [];
|
networkTypes = [];
|
||||||
@ -32,11 +31,12 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
binaries: QemuBinary[] = [];
|
binaries: QemuBinary[] = [];
|
||||||
activateCpuThrottling: boolean = true;
|
activateCpuThrottling: boolean = true;
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
adapters: CustomAdapter[] = [];
|
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
||||||
|
|
||||||
generalSettingsForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
|
@ViewChild("customAdaptersConfigurator")
|
||||||
|
customAdaptersConfigurator: CustomAdaptersComponent;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
@ -62,22 +62,11 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
this.getConfiguration();
|
this.getConfiguration();
|
||||||
this.qemuService.getTemplate(this.server, template_id).subscribe((qemuTemplate: QemuTemplate) => {
|
this.qemuService.getTemplate(this.server, template_id).subscribe((qemuTemplate: QemuTemplate) => {
|
||||||
this.qemuTemplate = qemuTemplate;
|
this.qemuTemplate = qemuTemplate;
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
|
||||||
this.qemuService.getBinaries(server).subscribe((qemuBinaries: QemuBinary[]) => {
|
this.qemuService.getBinaries(server).subscribe((qemuBinaries: QemuBinary[]) => {
|
||||||
this.binaries = qemuBinaries;
|
this.binaries = qemuBinaries;
|
||||||
});
|
});
|
||||||
|
|
||||||
for(let i=0; i<this.qemuTemplate.adapters; i++){
|
|
||||||
let adapter = this.qemuTemplate.custom_adapters.find(elem => elem.adapter_number === i);
|
|
||||||
if (adapter) {
|
|
||||||
this.adapters.push(adapter);
|
|
||||||
} else {
|
|
||||||
this.adapters.push({
|
|
||||||
adapter_number: i,
|
|
||||||
adapter_type: this.qemuTemplate.adapter_type
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -108,13 +97,41 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
this.qemuTemplate.bios_image = event.target.files[0].name;
|
this.qemuTemplate.bios_image = event.target.files[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelConfigureCustomAdapters(){
|
setCustomAdaptersConfiguratorState(state: boolean) {
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.isConfiguratorOpened = state;
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
this.customAdaptersConfigurator.numberOfAdapters = this.qemuTemplate.adapters;
|
||||||
|
this.customAdaptersConfigurator.adapters = [];
|
||||||
|
this.qemuTemplate.custom_adapters.forEach((adapter: CustomAdapter) => {
|
||||||
|
this.customAdaptersConfigurator.adapters.push({
|
||||||
|
adapter_number: adapter.adapter_number,
|
||||||
|
adapter_type: adapter.adapter_type
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configureCustomAdapters(){
|
saveCustomAdapters(adapters: CustomAdapter[]){
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.setCustomAdaptersConfiguratorState(false);
|
||||||
this.qemuTemplate.custom_adapters = this.adapters;
|
this.qemuTemplate.custom_adapters = adapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillCustomAdapters() {
|
||||||
|
let copyOfAdapters = this.qemuTemplate.custom_adapters ? this.qemuTemplate.custom_adapters : [];
|
||||||
|
this.qemuTemplate.custom_adapters = [];
|
||||||
|
|
||||||
|
for(let i=0; i<this.qemuTemplate.adapters; i++){
|
||||||
|
if (copyOfAdapters[i]) {
|
||||||
|
this.qemuTemplate.custom_adapters.push(copyOfAdapters[i]);
|
||||||
|
} else {
|
||||||
|
this.qemuTemplate.custom_adapters.push({
|
||||||
|
adapter_number: i,
|
||||||
|
adapter_type: 'e1000'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
goBack() {
|
goBack() {
|
||||||
@ -128,6 +145,7 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
if (!this.activateCpuThrottling){
|
if (!this.activateCpuThrottling){
|
||||||
this.qemuTemplate.cpu_throttling = 0;
|
this.qemuTemplate.cpu_throttling = 0;
|
||||||
}
|
}
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
|
||||||
this.qemuService.saveTemplate(this.server, this.qemuTemplate).subscribe((savedTemplate: QemuTemplate) => {
|
this.qemuService.saveTemplate(this.server, this.qemuTemplate).subscribe((savedTemplate: QemuTemplate) => {
|
||||||
this.toasterService.success("Changes saved");
|
this.toasterService.success("Changes saved");
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
<button mat-button class="configButton" (click)="configureCustomAdapters()">Configure custom adapters</button><br/>
|
<button mat-button class="configButton" (click)="setCustomAdaptersConfiguratorState(true)">Configure custom adapters</button><br/>
|
||||||
<mat-checkbox [(ngModel)]="virtualBoxTemplate.use_any_adapter">
|
<mat-checkbox [(ngModel)]="virtualBoxTemplate.use_any_adapter">
|
||||||
Allow GNS3 to use any configured VirtualBox adapter
|
Allow GNS3 to use any configured VirtualBox adapter
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
@ -107,44 +107,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
<app-custom-adapters
|
||||||
<div class="default-header">
|
[hidden]="!(isConfiguratorOpened && virtualBoxTemplate)"
|
||||||
<div class="row">
|
#customAdaptersConfigurator
|
||||||
<h1 class="col">Custom adapters configuration</h1>
|
[networkTypes]="networkTypes"
|
||||||
</div>
|
[displayedColumns]="displayedColumns"
|
||||||
</div>
|
(closeConfiguratorEmitter)="setCustomAdaptersConfiguratorState($event)"
|
||||||
<div class="default-content" *ngIf="virtualBoxTemplate">
|
(saveConfigurationEmitter)="saveCustomAdapters($event)"
|
||||||
<div class="container mat-elevation-z8">
|
></app-custom-adapters>
|
||||||
<table class="table" mat-table [dataSource]="adapters">
|
<app-symbols-menu
|
||||||
<ng-container matColumnDef="adapter_number">
|
*ngIf="isSymbolSelectionOpened && virtualBoxTemplate"
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter number </th>
|
[server]="server"
|
||||||
<td mat-cell *matCellDef="let element"> Adapter {{element.adapter_number}} </td>
|
[symbol]="virtualBoxTemplate.symbol"
|
||||||
</ng-container>
|
(symbolChangedEmitter)="symbolChanged($event)"
|
||||||
|
></app-symbols-menu>
|
||||||
<ng-container matColumnDef="port_name">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Port name </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> Ethernet {{element.adapter_number}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="adapter_type">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter type </th>
|
|
||||||
<td mat-cell *matCellDef="let element; let i = index;">
|
|
||||||
<mat-select placeholder="Type" [(ngModel)]="adapters[i].adapter_type">
|
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
|
||||||
{{type}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="buttons-bar">
|
|
||||||
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
|
||||||
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-symbols-menu *ngIf="isSymbolSelectionOpened && virtualBoxTemplate" [server]="server" [symbol]="virtualBoxTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
|
||||||
|
@ -68,9 +68,58 @@ describe('VirtualBoxTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should call save template', () => {
|
it('should call save template', () => {
|
||||||
spyOn(mockedVirtualBoxService, 'saveTemplate').and.returnValue(of({} as VirtualBoxTemplate));
|
spyOn(mockedVirtualBoxService, 'saveTemplate').and.returnValue(of({} as VirtualBoxTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.generalSettingsForm.controls['ram'].setValue('256');
|
||||||
|
component.networkForm.controls['adapters'].setValue('1');
|
||||||
|
component.networkForm.controls['nameFormat'].setValue('{}');
|
||||||
|
component.networkForm.controls['size'].setValue('256');
|
||||||
|
component.virtualBoxTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VirtualBoxTemplate;
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
expect(mockedVirtualBoxService.saveTemplate).toHaveBeenCalled();
|
expect(mockedVirtualBoxService.saveTemplate).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not call save template when general settings are not filled', () => {
|
||||||
|
spyOn(mockedVirtualBoxService, 'saveTemplate').and.returnValue(of({} as VirtualBoxTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.generalSettingsForm.controls['ram'].setValue('256');
|
||||||
|
component.networkForm.controls['adapters'].setValue('1');
|
||||||
|
component.networkForm.controls['nameFormat'].setValue('{}');
|
||||||
|
component.networkForm.controls['size'].setValue('256');
|
||||||
|
component.virtualBoxTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VirtualBoxTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedVirtualBoxService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call save template when network settings are not filled', () => {
|
||||||
|
spyOn(mockedVirtualBoxService, 'saveTemplate').and.returnValue(of({} as VirtualBoxTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.generalSettingsForm.controls['ram'].setValue('256');
|
||||||
|
component.networkForm.controls['adapters'].setValue('');
|
||||||
|
component.networkForm.controls['nameFormat'].setValue('{}');
|
||||||
|
component.networkForm.controls['size'].setValue('256');
|
||||||
|
component.virtualBoxTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VirtualBoxTemplate;
|
||||||
|
|
||||||
|
component.onSave();
|
||||||
|
|
||||||
|
expect(mockedVirtualBoxService.saveTemplate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, 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';
|
||||||
@ -8,6 +8,7 @@ import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
|||||||
import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template';
|
import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template';
|
||||||
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
import { VirtualBoxConfigurationService } from '../../../../services/virtual-box-configuration.service';
|
import { VirtualBoxConfigurationService } from '../../../../services/virtual-box-configuration.service';
|
||||||
|
import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-adapters.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -18,20 +19,19 @@ import { VirtualBoxConfigurationService } from '../../../../services/virtual-box
|
|||||||
export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
virtualBoxTemplate: VirtualBoxTemplate;
|
virtualBoxTemplate: VirtualBoxTemplate;
|
||||||
|
|
||||||
isSymbolSelectionOpened: boolean = false;
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
consoleTypes: string[] = [];
|
consoleTypes: string[] = [];
|
||||||
onCloseOptions = [];
|
onCloseOptions = [];
|
||||||
categories = [];
|
categories = [];
|
||||||
networkTypes = [];
|
networkTypes = [];
|
||||||
adapters: CustomAdapter[] = [];
|
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
|
|
||||||
generalSettingsForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
networkForm: FormGroup
|
networkForm: FormGroup
|
||||||
|
|
||||||
|
@ViewChild("customAdaptersConfigurator")
|
||||||
|
customAdaptersConfigurator: CustomAdaptersComponent;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
@ -64,18 +64,7 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
this.getConfiguration();
|
this.getConfiguration();
|
||||||
this.virtualBoxService.getTemplate(this.server, template_id).subscribe((virtualBoxTemplate: VirtualBoxTemplate) => {
|
this.virtualBoxService.getTemplate(this.server, template_id).subscribe((virtualBoxTemplate: VirtualBoxTemplate) => {
|
||||||
this.virtualBoxTemplate = virtualBoxTemplate;
|
this.virtualBoxTemplate = virtualBoxTemplate;
|
||||||
|
this.fillCustomAdapters();
|
||||||
for(let i=0; i<this.virtualBoxTemplate.adapters; i++){
|
|
||||||
let adapter = this.virtualBoxTemplate.custom_adapters.find(elem => elem.adapter_number === i);
|
|
||||||
if (adapter) {
|
|
||||||
this.adapters.push(adapter);
|
|
||||||
} else {
|
|
||||||
this.adapters.push({
|
|
||||||
adapter_number: i,
|
|
||||||
adapter_type: this.virtualBoxTemplate.adapter_type
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -87,13 +76,41 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
this.networkTypes = this.virtualBoxConfigurationService.getNetworkTypes();
|
this.networkTypes = this.virtualBoxConfigurationService.getNetworkTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
configureCustomAdapters(){
|
setCustomAdaptersConfiguratorState(state: boolean) {
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.isConfiguratorOpened = state;
|
||||||
this.virtualBoxTemplate.custom_adapters = this.adapters;
|
|
||||||
|
if (state) {
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
this.customAdaptersConfigurator.numberOfAdapters = this.virtualBoxTemplate.adapters;
|
||||||
|
this.customAdaptersConfigurator.adapters = [];
|
||||||
|
this.virtualBoxTemplate.custom_adapters.forEach((adapter: CustomAdapter) => {
|
||||||
|
this.customAdaptersConfigurator.adapters.push({
|
||||||
|
adapter_number: adapter.adapter_number,
|
||||||
|
adapter_type: adapter.adapter_type
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelConfigureCustomAdapters(){
|
saveCustomAdapters(adapters: CustomAdapter[]){
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.setCustomAdaptersConfiguratorState(false);
|
||||||
|
this.virtualBoxTemplate.custom_adapters = adapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillCustomAdapters() {
|
||||||
|
let copyOfAdapters = this.virtualBoxTemplate.custom_adapters ? this.virtualBoxTemplate.custom_adapters : [];
|
||||||
|
this.virtualBoxTemplate.custom_adapters = [];
|
||||||
|
|
||||||
|
for(let i=0; i<this.virtualBoxTemplate.adapters; i++){
|
||||||
|
if (copyOfAdapters[i]) {
|
||||||
|
this.virtualBoxTemplate.custom_adapters.push(copyOfAdapters[i]);
|
||||||
|
} else {
|
||||||
|
this.virtualBoxTemplate.custom_adapters.push({
|
||||||
|
adapter_number: i,
|
||||||
|
adapter_type: 'e1000'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
goBack() {
|
goBack() {
|
||||||
@ -101,10 +118,16 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
|
if (this.generalSettingsForm.invalid || this.networkForm.invalid) {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else {
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
|
||||||
this.virtualBoxService.saveTemplate(this.server, this.virtualBoxTemplate).subscribe((virtualBoxTemplate: VirtualBoxTemplate) => {
|
this.virtualBoxService.saveTemplate(this.server, this.virtualBoxTemplate).subscribe((virtualBoxTemplate: VirtualBoxTemplate) => {
|
||||||
this.toasterService.success("Changes saved");
|
this.toasterService.success("Changes saved");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chooseSymbol() {
|
chooseSymbol() {
|
||||||
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
@ -107,7 +107,7 @@
|
|||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-button class="configButton" (click)="configureCustomAdapters()">Configure custom adapters</button><br/>
|
<button mat-button class="configButton" (click)="setCustomAdaptersConfiguratorState(true)">Configure custom adapters</button><br/>
|
||||||
<mat-checkbox [(ngModel)]="vmwareTemplate.use_any_adapter">
|
<mat-checkbox [(ngModel)]="vmwareTemplate.use_any_adapter">
|
||||||
Allow GNS3 to override non custom VMware adapter
|
Allow GNS3 to override non custom VMware adapter
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
@ -129,44 +129,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
<app-custom-adapters
|
||||||
<div class="default-header">
|
[hidden]="!(isConfiguratorOpened && vmwareTemplate)"
|
||||||
<div class="row">
|
#customAdaptersConfigurator
|
||||||
<h1 class="col">Custom adapters configuration</h1>
|
[networkTypes]="networkTypes"
|
||||||
</div>
|
[displayedColumns]="displayedColumns"
|
||||||
</div>
|
(closeConfiguratorEmitter)="setCustomAdaptersConfiguratorState($event)"
|
||||||
<div class="default-content" *ngIf="vmwareTemplate">
|
(saveConfigurationEmitter)="saveCustomAdapters($event)"
|
||||||
<div class="container mat-elevation-z8">
|
></app-custom-adapters>
|
||||||
<table class="table" mat-table [dataSource]="adapters">
|
<app-symbols-menu
|
||||||
<ng-container matColumnDef="adapter_number">
|
*ngIf="isSymbolSelectionOpened && vmwareTemplate"
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter number </th>
|
[server]="server"
|
||||||
<td mat-cell *matCellDef="let element"> Adapter {{element.adapter_number}} </td>
|
[symbol]="vmwareTemplate.symbol"
|
||||||
</ng-container>
|
(symbolChangedEmitter)="symbolChanged($event)"
|
||||||
|
></app-symbols-menu>
|
||||||
<ng-container matColumnDef="port_name">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Port name </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> Ethernet {{element.adapter_number}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="adapter_type">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter type </th>
|
|
||||||
<td mat-cell *matCellDef="let element; let i = index;">
|
|
||||||
<mat-select placeholder="Type" [(ngModel)]="adapters[i].adapter_type">
|
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
|
||||||
{{type}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="buttons-bar">
|
|
||||||
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
|
||||||
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-symbols-menu *ngIf="isSymbolSelectionOpened && vmwareTemplate" [server]="server" [symbol]="vmwareTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
|
||||||
|
@ -71,6 +71,10 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.vmwareTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VmwareTemplate;
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
@ -82,6 +86,10 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
component.generalSettingsForm.controls['templateName'].setValue('');
|
component.generalSettingsForm.controls['templateName'].setValue('');
|
||||||
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.vmwareTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VmwareTemplate;
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
@ -93,6 +101,10 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.generalSettingsForm.controls['defaultName'].setValue('');
|
component.generalSettingsForm.controls['defaultName'].setValue('');
|
||||||
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
component.vmwareTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VmwareTemplate;
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
@ -104,6 +116,10 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.generalSettingsForm.controls['symbol'].setValue('');
|
component.generalSettingsForm.controls['symbol'].setValue('');
|
||||||
|
component.vmwareTemplate = {
|
||||||
|
adapters: 0,
|
||||||
|
custom_adapters: []
|
||||||
|
} as VmwareTemplate;
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, 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';
|
||||||
@ -8,6 +8,7 @@ import { VmwareTemplate } from '../../../../models/templates/vmware-template';
|
|||||||
import { VmwareService } from '../../../../services/vmware.service';
|
import { VmwareService } from '../../../../services/vmware.service';
|
||||||
import { VmwareConfigurationService } from '../../../../services/vmware-configuration.service';
|
import { VmwareConfigurationService } from '../../../../services/vmware-configuration.service';
|
||||||
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
|
import { CustomAdaptersComponent } from '../../common/custom-adapters/custom-adapters.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -19,17 +20,17 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
server: Server;
|
server: Server;
|
||||||
vmwareTemplate: VmwareTemplate;
|
vmwareTemplate: VmwareTemplate;
|
||||||
generalSettingsForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
adapters: CustomAdapter[] = [];
|
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
isSymbolSelectionOpened: boolean = false;
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
consoleTypes: string[] = [];
|
consoleTypes: string[] = [];
|
||||||
categories = [];
|
categories = [];
|
||||||
onCloseOptions = [];
|
onCloseOptions = [];
|
||||||
networkTypes = [];
|
networkTypes = [];
|
||||||
|
|
||||||
|
@ViewChild("customAdaptersConfigurator")
|
||||||
|
customAdaptersConfigurator: CustomAdaptersComponent;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
@ -55,6 +56,7 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
this.getConfiguration();
|
this.getConfiguration();
|
||||||
this.vmwareService.getTemplate(this.server, template_id).subscribe((vmwareTemplate: VmwareTemplate) => {
|
this.vmwareService.getTemplate(this.server, template_id).subscribe((vmwareTemplate: VmwareTemplate) => {
|
||||||
this.vmwareTemplate = vmwareTemplate;
|
this.vmwareTemplate = vmwareTemplate;
|
||||||
|
this.fillCustomAdapters();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -74,37 +76,49 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
if (this.generalSettingsForm.invalid) {
|
if (this.generalSettingsForm.invalid) {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
} else {
|
} else {
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
|
||||||
this.vmwareService.saveTemplate(this.server, this.vmwareTemplate).subscribe((vmwareTemplate: VmwareTemplate) => {
|
this.vmwareService.saveTemplate(this.server, this.vmwareTemplate).subscribe((vmwareTemplate: VmwareTemplate) => {
|
||||||
this.toasterService.success("Changes saved");
|
this.toasterService.success("Changes saved");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelConfigureCustomAdapters(){
|
setCustomAdaptersConfiguratorState(state: boolean) {
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.isConfiguratorOpened = state;
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
this.fillCustomAdapters();
|
||||||
|
this.customAdaptersConfigurator.numberOfAdapters = this.vmwareTemplate.adapters;
|
||||||
|
this.customAdaptersConfigurator.adapters = [];
|
||||||
|
this.vmwareTemplate.custom_adapters.forEach((adapter: CustomAdapter) => {
|
||||||
|
this.customAdaptersConfigurator.adapters.push({
|
||||||
|
adapter_number: adapter.adapter_number,
|
||||||
|
adapter_type: adapter.adapter_type
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configureCustomAdapters() {
|
saveCustomAdapters(adapters: CustomAdapter[]){
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.setCustomAdaptersConfiguratorState(false);
|
||||||
this.adapters = [];
|
this.vmwareTemplate.custom_adapters = adapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillCustomAdapters() {
|
||||||
|
let copyOfAdapters = this.vmwareTemplate.custom_adapters ? this.vmwareTemplate.custom_adapters : [];
|
||||||
|
this.vmwareTemplate.custom_adapters = [];
|
||||||
|
|
||||||
let adapters: CustomAdapter[] = [];
|
|
||||||
for(let i=0; i<this.vmwareTemplate.adapters; i++){
|
for(let i=0; i<this.vmwareTemplate.adapters; i++){
|
||||||
if (this.vmwareTemplate.custom_adapters[i]) {
|
if (copyOfAdapters[i]) {
|
||||||
adapters.push(this.vmwareTemplate.custom_adapters[i]);
|
this.vmwareTemplate.custom_adapters.push(copyOfAdapters[i]);
|
||||||
} else {
|
} else {
|
||||||
adapters.push({
|
this.vmwareTemplate.custom_adapters.push({
|
||||||
adapter_number: i,
|
adapter_number: i,
|
||||||
adapter_type: 'e1000'
|
adapter_type: 'e1000'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.adapters = adapters;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveCustomAdapters() {
|
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
|
||||||
this.vmwareTemplate.custom_adapters = this.adapters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chooseSymbol() {
|
chooseSymbol() {
|
||||||
|
Reference in New Issue
Block a user