mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-01-31 00:23:57 +00:00
Fixes after review
Unit tests updated Cancel option added to every step Code cleaned up
This commit is contained in:
parent
b3aa58b9c9
commit
31f22728a9
@ -161,6 +161,7 @@ import { CopyIouTemplateComponent } from './components/preferences/ios-on-unix/c
|
|||||||
import { CopyDockerTemplateComponent } from './components/preferences/docker/copy-docker-template/copy-docker-template.component';
|
import { CopyDockerTemplateComponent } from './components/preferences/docker/copy-docker-template/copy-docker-template.component';
|
||||||
import { EmptyTemplatesListComponent } from './components/preferences/common/empty-templates-list/empty-templates-list.component';
|
import { EmptyTemplatesListComponent } from './components/preferences/common/empty-templates-list/empty-templates-list.component';
|
||||||
import { SymbolsMenuComponent } from './components/preferences/common/symbols-menu/symbols-menu.component';
|
import { SymbolsMenuComponent } from './components/preferences/common/symbols-menu/symbols-menu.component';
|
||||||
|
import { SearchFilter } from './filters/searchFilter.pipe';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||||
@ -261,7 +262,8 @@ if (environment.production) {
|
|||||||
CopyIouTemplateComponent,
|
CopyIouTemplateComponent,
|
||||||
CopyDockerTemplateComponent,
|
CopyDockerTemplateComponent,
|
||||||
EmptyTemplatesListComponent,
|
EmptyTemplatesListComponent,
|
||||||
SymbolsMenuComponent
|
SymbolsMenuComponent,
|
||||||
|
SearchFilter
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<mat-card>
|
<mat-card>
|
||||||
|
<input matInput type="text" [(ngModel)]="searchText" placeholder="Search by filename"><br/><br/>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="buttonWrapper" *ngFor="let symbol of symbols">
|
<div class="buttonWrapper" *ngFor="let symbol of symbols | filenamefilter: searchText">
|
||||||
<button [ngClass]="{ buttonSelected: isSelected === symbol.symbol_id }" class="button" (click)="setSelected(symbol.symbol_id)">
|
<button [ngClass]="{ buttonSelected: isSelected === symbol.symbol_id }" class="button" (click)="setSelected(symbol.symbol_id)">
|
||||||
<img [ngClass]="{ imageSelected: isSelected === symbol.symbol_id }" class="image" src="http://127.0.0.1:3080/v2/symbols/{{symbol.symbol_id}}/raw"/>
|
<img [ngClass]="{ imageSelected: isSelected === symbol.symbol_id }" class="image" src="http://127.0.0.1:3080/v2/symbols/{{symbol.symbol_id}}/raw"/>
|
||||||
</button>
|
</button>
|
||||||
|
@ -8,6 +8,7 @@ import { RouterTestingModule } from '@angular/router/testing';
|
|||||||
import { SymbolsComponent } from './symbols.component';
|
import { SymbolsComponent } from './symbols.component';
|
||||||
import { SymbolService } from '../../../../services/symbol.service';
|
import { SymbolService } from '../../../../services/symbol.service';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { SearchFilter } from '../../../../filters/searchFilter.pipe';
|
||||||
|
|
||||||
export class MockedSymbolService {
|
export class MockedSymbolService {
|
||||||
public list() {
|
public list() {
|
||||||
@ -29,7 +30,8 @@ describe('Symbols component', () => {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
SymbolsComponent
|
SymbolsComponent,
|
||||||
|
SearchFilter
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
@ -16,6 +16,7 @@ export class SymbolsComponent implements OnInit {
|
|||||||
|
|
||||||
symbols: Symbol[] = [];
|
symbols: Symbol[] = [];
|
||||||
isSelected: string = '';
|
isSelected: string = '';
|
||||||
|
searchText: string = '';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private symbolService: SymbolService
|
private symbolService: SymbolService
|
||||||
|
@ -87,9 +87,12 @@
|
|||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="dockerTemplate.environment"></textarea>
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.environment"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="addTemplate()">Add template</button></div>
|
|
||||||
</mat-step>
|
</mat-step>
|
||||||
</mat-vertical-stepper>
|
</mat-vertical-stepper>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
width: 50%;
|
|
||||||
padding-top: 20px;
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-bar {
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonvisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-button {
|
|
||||||
width: 18%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name-form-field {
|
|
||||||
padding-left: 2%;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
@ -15,7 +15,7 @@ import { DockerImage } from '../../../../models/docker/docker-image';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-docker-template',
|
selector: 'app-add-docker-template',
|
||||||
templateUrl: './add-docker-template.component.html',
|
templateUrl: './add-docker-template.component.html',
|
||||||
styleUrls: ['./add-docker-template.component.scss']
|
styleUrls: ['./add-docker-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class AddDockerTemplateComponent implements OnInit {
|
export class AddDockerTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -80,12 +80,16 @@ export class AddDockerTemplateComponent implements OnInit {
|
|||||||
this.newImageSelected = value === "newImage";
|
this.newImageSelected = value === "newImage";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (!this.virtualMachineForm.invalid && !this.containerNameForm.invalid && !this.networkAdaptersForm.invalid) {
|
if (!this.virtualMachineForm.invalid && !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) => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -6,14 +6,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="default-content">
|
<div class="default-content">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-form-field class="form-field">
|
<form [formGroup]="templateNameForm">
|
||||||
<input
|
<mat-form-field class="form-field">
|
||||||
matInput type="text"
|
<input
|
||||||
[(ngModel)]="templateName"
|
matInput type="text"
|
||||||
placeholder="Name"
|
[(ngModel)]="templateName"
|
||||||
ngDefaultControl/>
|
placeholder="Name"
|
||||||
</mat-form-field><br/>
|
formControlName="templateName"/>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="addTemplate()">Copy template</button></div>
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Copy template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
width: 50%;
|
|
||||||
padding-top: 20px;
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-bar {
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonvisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-button {
|
|
||||||
width: 18%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name-form-field {
|
|
||||||
padding-left: 2%;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
@ -1,30 +1,37 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
import { DockerService } from '../../../../services/docker.service';
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-copy-docker-template',
|
selector: 'app-copy-docker-template',
|
||||||
templateUrl: './copy-docker-template.component.html',
|
templateUrl: './copy-docker-template.component.html',
|
||||||
styleUrls: ['./copy-docker-template.component.scss']
|
styleUrls: ['./copy-docker-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class CopyDockerTemplateComponent implements OnInit {
|
export class CopyDockerTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
templateName: string = '';
|
templateName: string = '';
|
||||||
dockerTemplate: DockerTemplate;
|
dockerTemplate: DockerTemplate;
|
||||||
|
templateNameForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
private dockerService: DockerService,
|
private dockerService: DockerService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
) {}
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.templateNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -40,13 +47,17 @@ export class CopyDockerTemplateComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (this.templateName) {
|
if (!this.templateNameForm.invalid) {
|
||||||
this.dockerTemplate.template_id = uuid();
|
this.dockerTemplate.template_id = uuid();
|
||||||
this.dockerTemplate.name = this.templateName;
|
this.dockerTemplate.name = this.templateName;
|
||||||
|
|
||||||
this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => {
|
this.dockerService.addTemplate(this.server, this.dockerTemplate).subscribe((template: DockerTemplate) => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -12,54 +12,56 @@
|
|||||||
General settings
|
General settings
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<form [formGroup]="generalSettingsForm">
|
||||||
<input matInput type="text" [(ngModel)]="dockerTemplate.name" placeholder="Template name">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="templateName" matInput type="text" [(ngModel)]="dockerTemplate.name" placeholder="Template name">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="dockerTemplate.default_name_format" placeholder="Default name format">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="defaultName" matInput type="text" [(ngModel)]="dockerTemplate.default_name_format" placeholder="Default name format">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<mat-select placeholder="Category" [(ngModel)]="dockerTemplate.category">
|
<mat-form-field class="form-field">
|
||||||
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Category" [(ngModel)]="dockerTemplate.category">
|
||||||
{{category[0]}}
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
</mat-option>
|
{{category[0]}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="dockerTemplate.symbol" placeholder="Symbol">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="symbol" matInput type="text" [(ngModel)]="dockerTemplate.symbol" placeholder="Symbol">
|
||||||
<button mat-raised-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
<input matInput type="text" [(ngModel)]="dockerTemplate.start_command" placeholder="Start command">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="dockerTemplate.start_command" placeholder="Start command">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="number" [(ngModel)]="dockerTemplate.adapters" placeholder="Adapters">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="adapter" matInput type="number" [(ngModel)]="dockerTemplate.adapters" placeholder="Adapters">
|
||||||
<mat-form-field class="select">
|
</mat-form-field>
|
||||||
<mat-select placeholder="Console type" [(ngModel)]="dockerTemplate.console_type">
|
<mat-form-field class="select">
|
||||||
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Console type" [(ngModel)]="dockerTemplate.console_type">
|
||||||
{{type}}
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
</mat-option>
|
{{type}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
<mat-checkbox [(ngModel)]="dockerTemplate.console_auto_start">
|
</mat-form-field>
|
||||||
Auto start console
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="dockerTemplate.console_auto_start">
|
||||||
</mat-checkbox>
|
Auto start console
|
||||||
<mat-form-field class="select">
|
</mat-checkbox>
|
||||||
<mat-select placeholder="VNC console resolution" [(ngModel)]="dockerTemplate.console_resolution">
|
<mat-form-field class="select">
|
||||||
<mat-option *ngFor="let resolution of consoleResolutions" [value]="resolution">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="VNC console resolution" [(ngModel)]="dockerTemplate.console_resolution">
|
||||||
{{resolution}}
|
<mat-option *ngFor="let resolution of consoleResolutions" [value]="resolution">
|
||||||
</mat-option>
|
{{resolution}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="number" [(ngModel)]="dockerTemplate.console_http_port" placeholder="HTTP port in the container">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input [ngModelOptions]="{standalone: true}" matInput type="number" [(ngModel)]="dockerTemplate.console_http_port" placeholder="HTTP port in the container">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="dockerTemplate.console_http_path" placeholder="HTTP path">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input [ngModelOptions]="{standalone: true}" matInput type="text" [(ngModel)]="dockerTemplate.console_http_path" placeholder="HTTP path">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
<h6>Environment</h6>
|
<h6>Environment</h6>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="dockerTemplate.environment"></textarea>
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.environment"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
@ -70,7 +72,7 @@
|
|||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<h6>Extra hosts</h6>
|
<h6>Extra hosts</h6>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="dockerTemplate.extra_hosts"></textarea>
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.extra_hosts"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
@ -80,22 +82,15 @@
|
|||||||
Usage
|
Usage
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="dockerTemplate.usage"></textarea>
|
<textarea matInput type="text" [(ngModel)]="dockerTemplate.usage"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="onSave()">Save</button></div>
|
<div class="buttons-bar">
|
||||||
</div>
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
</div>
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
<div class="content" class="configurator" *ngIf="isSymbolSelectionOpened">
|
|
||||||
<div class="default-header">
|
|
||||||
<div class="row">
|
|
||||||
<h1 class="col">Symbol selection</h1>
|
|
||||||
<button class="top-button" (click)="chooseSymbol()" mat-raised-button color="primary">Save</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content">
|
|
||||||
<app-symbols [server]="server" [symbol]="dockerTemplate.symbol" (symbolChanged)="symbolChanged($event)"></app-symbols>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && dockerTemplate" [server]="server" [symbol]="dockerTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
.row {
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonvisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-button {
|
|
||||||
width: 18%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name-form-field {
|
|
||||||
padding-right: 2%;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configButton {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configHideButton {
|
|
||||||
margin-left: 80%;
|
|
||||||
width: 20%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadowed {
|
|
||||||
display: none;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbolSelectionButton {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonshadowed {
|
|
||||||
opacity: 0;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
border: 0px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
th.mat-header-cell {
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.mat-cell {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
@ -68,6 +68,10 @@ describe('DockerTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should call save template', () => {
|
it('should call save template', () => {
|
||||||
spyOn(mockedDockerService, 'saveTemplate').and.returnValue(of({} as DockerTemplate));
|
spyOn(mockedDockerService, 'saveTemplate').and.returnValue(of({} as DockerTemplate));
|
||||||
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
|
component.generalSettingsForm.controls['adapter'].setValue(1);
|
||||||
|
component.generalSettingsForm.controls['symbol'].setValue('symbol path');
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute, ParamMap, 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 { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
@ -7,12 +7,13 @@ import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
|||||||
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
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 { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-docker-template-details',
|
selector: 'app-docker-template-details',
|
||||||
templateUrl: './docker-template-details.component.html',
|
templateUrl: './docker-template-details.component.html',
|
||||||
styleUrls: ['./docker-template-details.component.scss']
|
styleUrls: ['./docker-template-details.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class DockerTemplateDetailsComponent implements OnInit {
|
export class DockerTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -26,13 +27,24 @@ export class DockerTemplateDetailsComponent implements OnInit {
|
|||||||
adapters: CustomAdapter[] = [];
|
adapters: CustomAdapter[] = [];
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name'];
|
displayedColumns: string[] = ['adapter_number', 'port_name'];
|
||||||
|
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
private dockerService: DockerService,
|
private dockerService: DockerService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private configurationService: DockerConfigurationService
|
private configurationService: DockerConfigurationService,
|
||||||
){}
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router
|
||||||
|
){
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
adapter: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(){
|
ngOnInit(){
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -53,10 +65,18 @@ export class DockerTemplateDetailsComponent implements OnInit {
|
|||||||
this.consoleResolutions = this.configurationService.getConsoleResolutions();
|
this.consoleResolutions = this.configurationService.getConsoleResolutions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'docker', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
onSave(){
|
onSave(){
|
||||||
this.dockerService.saveTemplate(this.server, this.dockerTemplate).subscribe((savedTemplate: DockerTemplate) => {
|
if (this.generalSettingsForm.invalid) {
|
||||||
this.toasterService.success("Changes saved");
|
this.toasterService.error(`Fill all required fields`);
|
||||||
});
|
} else {
|
||||||
|
this.dockerService.saveTemplate(this.server, this.dockerTemplate).subscribe((savedTemplate: DockerTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chooseSymbol() {
|
chooseSymbol() {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="default-header">
|
<div class="default-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col">Docker container templates</h1>
|
<h1 class="col">Docker container templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/docker/addtemplate" mat-raised-button color="primary">Add Docker container template</button>
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/docker/addtemplate" mat-raised-button color="primary">Add Docker container template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,8 +10,8 @@
|
|||||||
<div class="default-content" *ngIf="dockerTemplates.length">
|
<div class="default-content" *ngIf="dockerTemplates.length">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-nav-list *ngIf="server">
|
<mat-nav-list *ngIf="server">
|
||||||
<mat-list-item *ngFor='let template of dockerTemplates'>
|
<div class="list-item" *ngFor='let template of dockerTemplates'>
|
||||||
<span class="name" routerLink="{{template.template_id}}">{{template.name}}</span>
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
<button mat-icon-button class="menu-button" [matMenuTriggerFor]="menu">
|
<button mat-icon-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
<mat-icon>more_vert</mat-icon>
|
<mat-icon>more_vert</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<mat-icon>content_copy</mat-icon><span>Copy</span>
|
<mat-icon>content_copy</mat-icon><span>Copy</span>
|
||||||
</button>
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</mat-list-item>
|
</div>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-button {
|
|
||||||
width: 5%;
|
|
||||||
}
|
|
@ -1,8 +1,7 @@
|
|||||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
import { DockerTemplate } from '../../../../models/templates/docker-template';
|
||||||
import { DockerService } from '../../../../services/docker.service';
|
import { DockerService } from '../../../../services/docker.service';
|
||||||
@ -11,7 +10,7 @@ import { DockerService } from '../../../../services/docker.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-docker-templates',
|
selector: 'app-docker-templates',
|
||||||
templateUrl: './docker-templates.component.html',
|
templateUrl: './docker-templates.component.html',
|
||||||
styleUrls: ['./docker-templates.component.scss']
|
styleUrls: ['./docker-templates.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class DockerTemplatesComponent implements OnInit {
|
export class DockerTemplatesComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
|
@ -34,7 +34,6 @@ export class IosTemplatesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTemplates() {
|
getTemplates() {
|
||||||
this.iosTemplates = [];
|
|
||||||
this.iosService.getTemplates(this.server).subscribe((templates: IosTemplate[]) => {
|
this.iosService.getTemplates(this.server).subscribe((templates: IosTemplate[]) => {
|
||||||
this.iosTemplates = templates.filter((elem) => elem.template_type === 'dynamips');
|
this.iosTemplates = templates.filter((elem) => elem.template_type === 'dynamips');
|
||||||
});
|
});
|
||||||
|
@ -31,6 +31,16 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.configButton {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.configHideButton {
|
||||||
|
margin-left: 80%;
|
||||||
|
width: 20%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.symbolSelectionButton {
|
.symbolSelectionButton {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ServerService } from '../../services/server.service';
|
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-vertical-stepper [linear]="true">
|
<mat-vertical-stepper [linear]="true">
|
||||||
<mat-step label="QEMU VM Name">
|
<mat-step label="QEMU VM Name">
|
||||||
<form [formGroup]="firstStepForm">
|
<form [formGroup]="nameForm">
|
||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput type="text"
|
matInput type="text"
|
||||||
@ -23,12 +23,12 @@
|
|||||||
</form>
|
</form>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
<mat-step label="QEMU binary and memory">
|
<mat-step label="QEMU binary and memory">
|
||||||
<form [formGroup]="secondStepForm">
|
<form [formGroup]="memoryForm">
|
||||||
<mat-form-field class="form-field">
|
<mat-form-field class="form-field">
|
||||||
<mat-select
|
<mat-select
|
||||||
placeholder="Qemu binary"
|
placeholder="Qemu binary"
|
||||||
[(ngModel)]="selectedBinary"
|
[(ngModel)]="selectedBinary"
|
||||||
[ngModelOptions]="{standalone: true}" >
|
formControlName="binary" >
|
||||||
<mat-option *ngFor="let binary of qemuBinaries" [value]="binary">
|
<mat-option *ngFor="let binary of qemuBinaries" [value]="binary">
|
||||||
{{binary.path}}
|
{{binary.path}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@ -57,11 +57,11 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
<mat-step label="Disk image">
|
<mat-step label="Disk image">
|
||||||
<form [formGroup]="fourthStepForm">
|
<form [formGroup]="diskForm">
|
||||||
<mat-radio-group class="radio-group">
|
<mat-radio-group class="radio-group">
|
||||||
<mat-radio-button class="radio-button" value="1" (click)="setDiskImage('existingImage')" checked>Existing image</mat-radio-button>
|
<mat-radio-button class="radio-button" value="1" (click)="setDiskImage('existingImage')" checked>Existing image</mat-radio-button>
|
||||||
<mat-radio-button class="radio-button" value="2" (click)="setDiskImage('newImage')">New image</mat-radio-button>
|
<mat-radio-button class="radio-button" value="2" (click)="setDiskImage('newImage')">New image</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group><br/><br/>
|
||||||
<mat-select
|
<mat-select
|
||||||
*ngIf="!newImageSelected"
|
*ngIf="!newImageSelected"
|
||||||
placeholder="Disk image (hda)"
|
placeholder="Disk image (hda)"
|
||||||
@ -90,9 +90,12 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="addTemplate()">Add template</button></div>
|
|
||||||
</mat-step>
|
</mat-step>
|
||||||
</mat-vertical-stepper>
|
</mat-vertical-stepper>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
width: 50%;
|
|
||||||
padding-top: 20px;
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-bar {
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonvisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-button {
|
|
||||||
width: 18%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name-form-field {
|
|
||||||
padding-left: 2%;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
@ -79,9 +79,10 @@ describe('AddQemuVmTemplateComponent', () => {
|
|||||||
|
|
||||||
it('should call add template', () => {
|
it('should call add template', () => {
|
||||||
spyOn(mockedQemuService, 'addTemplate').and.returnValue(of({} as QemuTemplate));
|
spyOn(mockedQemuService, 'addTemplate').and.returnValue(of({} as QemuTemplate));
|
||||||
component.firstStepForm.controls['templateName'].setValue('template name');
|
component.nameForm.controls['templateName'].setValue('template name');
|
||||||
component.secondStepForm.controls['ramMemory'].setValue(0);
|
component.memoryForm.controls['binary'].setValue('binary');
|
||||||
component.fourthStepForm.controls['fileName'].setValue('file name');
|
component.memoryForm.controls['ramMemory'].setValue(0);
|
||||||
|
component.diskForm.controls['fileName'].setValue('file name');
|
||||||
component.chosenImage = 'path';
|
component.chosenImage = 'path';
|
||||||
component.selectedBinary = {
|
component.selectedBinary = {
|
||||||
path: 'path',
|
path: 'path',
|
||||||
@ -97,9 +98,10 @@ describe('AddQemuVmTemplateComponent', () => {
|
|||||||
|
|
||||||
it('should not call add template when template name is empty', () => {
|
it('should not call add template when template name is empty', () => {
|
||||||
spyOn(mockedQemuService, 'addTemplate').and.returnValue(of({} as QemuTemplate));
|
spyOn(mockedQemuService, 'addTemplate').and.returnValue(of({} as QemuTemplate));
|
||||||
component.firstStepForm.controls['templateName'].setValue('');
|
component.nameForm.controls['templateName'].setValue('');
|
||||||
component.secondStepForm.controls['ramMemory'].setValue(0);
|
component.memoryForm.controls['binary'].setValue('binary');
|
||||||
component.fourthStepForm.controls['fileName'].setValue('file name');
|
component.memoryForm.controls['ramMemory'].setValue(0);
|
||||||
|
component.diskForm.controls['fileName'].setValue('file name');
|
||||||
component.chosenImage = 'path';
|
component.chosenImage = 'path';
|
||||||
component.selectedBinary = {
|
component.selectedBinary = {
|
||||||
path: 'path',
|
path: 'path',
|
||||||
@ -115,8 +117,9 @@ describe('AddQemuVmTemplateComponent', () => {
|
|||||||
|
|
||||||
it('should not call add template when ram is not set', () => {
|
it('should not call add template when ram is not set', () => {
|
||||||
spyOn(mockedQemuService, 'addTemplate').and.returnValue(of({} as QemuTemplate));
|
spyOn(mockedQemuService, 'addTemplate').and.returnValue(of({} as QemuTemplate));
|
||||||
component.firstStepForm.controls['templateName'].setValue('template name');
|
component.nameForm.controls['templateName'].setValue('template name');
|
||||||
component.fourthStepForm.controls['fileName'].setValue('file name');
|
component.memoryForm.controls['binary'].setValue('binary');
|
||||||
|
component.diskForm.controls['fileName'].setValue('file name');
|
||||||
component.chosenImage = 'path';
|
component.chosenImage = 'path';
|
||||||
component.selectedBinary = {
|
component.selectedBinary = {
|
||||||
path: 'path',
|
path: 'path',
|
||||||
|
@ -16,7 +16,7 @@ import { QemuConfigurationService } from '../../../../services/qemu-configuratio
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-qemu-virtual-machine-template',
|
selector: 'app-add-qemu-virtual-machine-template',
|
||||||
templateUrl: './add-qemu-vm-template.component.html',
|
templateUrl: './add-qemu-vm-template.component.html',
|
||||||
styleUrls: ['./add-qemu-vm-template.component.scss']
|
styleUrls: ['./add-qemu-vm-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class AddQemuVmTemplateComponent implements OnInit {
|
export class AddQemuVmTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -30,9 +30,9 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
|||||||
chosenImage: string = '';
|
chosenImage: string = '';
|
||||||
qemuTemplate: QemuTemplate;
|
qemuTemplate: QemuTemplate;
|
||||||
|
|
||||||
firstStepForm: FormGroup;
|
nameForm: FormGroup;
|
||||||
secondStepForm: FormGroup;
|
memoryForm: FormGroup;
|
||||||
fourthStepForm: FormGroup;
|
diskForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -46,15 +46,16 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
|||||||
) {
|
) {
|
||||||
this.qemuTemplate = new QemuTemplate();
|
this.qemuTemplate = new QemuTemplate();
|
||||||
|
|
||||||
this.firstStepForm = this.formBuilder.group({
|
this.nameForm = this.formBuilder.group({
|
||||||
templateName: new FormControl('', Validators.required)
|
templateName: new FormControl('', Validators.required)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.secondStepForm = this.formBuilder.group({
|
this.memoryForm = this.formBuilder.group({
|
||||||
|
binary: new FormControl('', Validators.required),
|
||||||
ramMemory: new FormControl('', Validators.required)
|
ramMemory: new FormControl('', Validators.required)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.fourthStepForm = this.formBuilder.group({
|
this.diskForm = this.formBuilder.group({
|
||||||
fileName: new FormControl('', Validators.required)
|
fileName: new FormControl('', Validators.required)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -88,8 +89,12 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
|||||||
this.chosenImage = event.target.files[0].name;
|
this.chosenImage = event.target.files[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (!this.firstStepForm.invalid && !this.secondStepForm.invalid && (this.selectedImage || this.chosenImage)) {
|
if (!this.nameForm.invalid && !this.memoryForm.invalid && (this.selectedImage || this.chosenImage)) {
|
||||||
this.qemuTemplate.ram = this.ramMemory;
|
this.qemuTemplate.ram = this.ramMemory;
|
||||||
this.qemuTemplate.qemu_path = this.selectedBinary.path;
|
this.qemuTemplate.qemu_path = this.selectedBinary.path;
|
||||||
if (this.newImageSelected) {
|
if (this.newImageSelected) {
|
||||||
@ -100,7 +105,7 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
|||||||
this.qemuTemplate.template_id = uuid();
|
this.qemuTemplate.template_id = uuid();
|
||||||
|
|
||||||
this.qemuService.addTemplate(this.server, this.qemuTemplate).subscribe((template: QemuTemplate) => {
|
this.qemuService.addTemplate(this.server, this.qemuTemplate).subscribe((template: QemuTemplate) => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -5,15 +5,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content">
|
<div class="default-content">
|
||||||
<div class="container mat-elevation-z8">
|
<mat-card class="matCard">
|
||||||
<mat-form-field class="form-field">
|
<form [formGroup]="nameForm">
|
||||||
<input
|
<mat-form-field class="form-field">
|
||||||
matInput type="text"
|
<input
|
||||||
[(ngModel)]="templateName"
|
matInput type="text"
|
||||||
placeholder="Name"
|
[(ngModel)]="templateName"
|
||||||
ngDefaultControl/>
|
placeholder="Name"
|
||||||
</mat-form-field><br/>
|
formControlName="templateName"/>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="addTemplate()">Copy template</button></div>
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Copy template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-button {
|
|
||||||
width: 50%;
|
|
||||||
padding-top: 20px;
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-bar {
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonvisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-button {
|
|
||||||
width: 18%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name-form-field {
|
|
||||||
padding-left: 2%;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
@ -1,25 +1,26 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, 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';
|
||||||
import { QemuBinary } from '../../../../models/qemu/qemu-binary';
|
import { QemuBinary } from '../../../../models/qemu/qemu-binary';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { QemuTemplate } from '../../../../models/templates/qemu-template';
|
import { QemuTemplate } from '../../../../models/templates/qemu-template';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-copy-qemu-virtual-machine-template',
|
selector: 'app-copy-qemu-virtual-machine-template',
|
||||||
templateUrl: './copy-qemu-vm-template.component.html',
|
templateUrl: './copy-qemu-vm-template.component.html',
|
||||||
styleUrls: ['./copy-qemu-vm-template.component.scss']
|
styleUrls: ['./copy-qemu-vm-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class CopyQemuVmTemplateComponent implements OnInit {
|
export class CopyQemuVmTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
qemuBinaries: QemuBinary[] = [];
|
qemuBinaries: QemuBinary[] = [];
|
||||||
templateName: string = '';
|
templateName: string = '';
|
||||||
qemuTemplate: QemuTemplate;
|
qemuTemplate: QemuTemplate;
|
||||||
|
nameForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -27,7 +28,12 @@ export class CopyQemuVmTemplateComponent implements OnInit {
|
|||||||
private qemuService: QemuService,
|
private qemuService: QemuService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
) {}
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.nameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -43,13 +49,17 @@ export class CopyQemuVmTemplateComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (this.templateName) {
|
if (!this.nameForm.invalid) {
|
||||||
this.qemuTemplate.template_id = uuid();
|
this.qemuTemplate.template_id = uuid();
|
||||||
this.qemuTemplate.name = this.templateName;
|
this.qemuTemplate.name = this.templateName;
|
||||||
|
|
||||||
this.qemuService.addTemplate(this.server, this.qemuTemplate).subscribe((template: QemuTemplate) => {
|
this.qemuService.addTemplate(this.server, this.qemuTemplate).subscribe((template: QemuTemplate) => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -12,44 +12,46 @@
|
|||||||
General settings
|
General settings
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<form [formGroup]="generalSettingsForm">
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.name" placeholder="Template name">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput type="text" formControlName="templateName" [(ngModel)]="qemuTemplate.name" placeholder="Template name">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.default_name_format" placeholder="Default name format">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput type="text" formControlName="defaultName" [(ngModel)]="qemuTemplate.default_name_format" placeholder="Default name format">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.symbol" placeholder="Symbol">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput type="text" formControlName="symbol" [(ngModel)]="qemuTemplate.symbol" placeholder="Symbol">
|
||||||
<button mat-raised-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
</form>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Category" [(ngModel)]="qemuTemplate.category">
|
<mat-select placeholder="Category" [(ngModel)]="qemuTemplate.category">
|
||||||
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
{{category[0]}}
|
{{category[0]}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="qemuTemplate.ram" placeholder="RAM">
|
<input matInput type="number" [(ngModel)]="qemuTemplate.ram" placeholder="RAM">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="qemuTemplate.cpus" placeholder="vCPUs">
|
<input matInput type="number" [(ngModel)]="qemuTemplate.cpus" placeholder="vCPUs">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Qemu binary" [(ngModel)]="qemuTemplate.qemu_path">
|
<mat-select placeholder="Qemu binary" [(ngModel)]="qemuTemplate.qemu_path">
|
||||||
<mat-option *ngFor="let binary of binaries" [value]="binary.path">
|
<mat-option *ngFor="let binary of binaries" [value]="binary.path">
|
||||||
{{binary.path}}
|
{{binary.path}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Boot priority" [(ngModel)]="qemuTemplate.boot_priority">
|
<mat-select placeholder="Boot priority" [(ngModel)]="qemuTemplate.boot_priority">
|
||||||
<mat-option *ngFor="let priority of bootPriorities" [value]="priority[1]">
|
<mat-option *ngFor="let priority of bootPriorities" [value]="priority[1]">
|
||||||
{{priority[0]}}
|
{{priority[0]}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="On close" [(ngModel)]="qemuTemplate.on_close">
|
<mat-select placeholder="On close" [(ngModel)]="qemuTemplate.on_close">
|
||||||
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
||||||
{{option[0]}}
|
{{option[0]}}
|
||||||
@ -79,10 +81,10 @@
|
|||||||
HDA (Primary Master)
|
HDA (Primary Master)
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput [(ngModel)]="qemuTemplate.hda_disk_image" placeholder="Disk image">
|
<input matInput [(ngModel)]="qemuTemplate.hda_disk_image" placeholder="Disk image">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hda_disk_interface">
|
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hda_disk_interface">
|
||||||
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
{{interface}}
|
{{interface}}
|
||||||
@ -97,10 +99,10 @@
|
|||||||
HDB (Primary Slave)
|
HDB (Primary Slave)
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput [(ngModel)]="qemuTemplate.hdb_disk_image" placeholder="Disk image">
|
<input matInput [(ngModel)]="qemuTemplate.hdb_disk_image" placeholder="Disk image">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hdb_disk_interface">
|
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hdb_disk_interface">
|
||||||
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
{{interface}}
|
{{interface}}
|
||||||
@ -115,10 +117,10 @@
|
|||||||
HDC (Secondary Master)
|
HDC (Secondary Master)
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput [(ngModel)]="qemuTemplate.hdc_disk_image" placeholder="Disk image">
|
<input matInput [(ngModel)]="qemuTemplate.hdc_disk_image" placeholder="Disk image">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hdc_disk_interface">
|
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hdc_disk_interface">
|
||||||
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
{{interface}}
|
{{interface}}
|
||||||
@ -133,10 +135,10 @@
|
|||||||
HDD (Secondary Slave)
|
HDD (Secondary Slave)
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput [(ngModel)]="qemuTemplate.hdd_disk_image" placeholder="Disk image">
|
<input matInput [(ngModel)]="qemuTemplate.hdd_disk_image" placeholder="Disk image">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hdd_disk_interface">
|
<mat-select placeholder="Disk interface" [(ngModel)]="qemuTemplate.hdd_disk_interface">
|
||||||
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
{{interface}}
|
{{interface}}
|
||||||
@ -153,6 +155,7 @@
|
|||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<div>
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="filecdrom.click()" class="file-button">Browse</button>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
#filecdrom
|
#filecdrom
|
||||||
@ -165,7 +168,6 @@
|
|||||||
[(ngModel)]="qemuTemplate.cdrom_image"
|
[(ngModel)]="qemuTemplate.cdrom_image"
|
||||||
placeholder="Image"/>
|
placeholder="Image"/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" (click)="filecdrom.click()" class="file-button">Browse</button>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
<mat-expansion-panel>
|
<mat-expansion-panel>
|
||||||
@ -174,29 +176,29 @@
|
|||||||
Network
|
Network
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="qemuTemplate.adapters" placeholder="Adapters">
|
<input matInput type="number" [(ngModel)]="qemuTemplate.adapters" placeholder="Adapters">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.first_port_name" placeholder="First port name">
|
<input matInput type="text" [(ngModel)]="qemuTemplate.first_port_name" placeholder="First port name">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.port_name_format" placeholder="Name format">
|
<input matInput type="text" [(ngModel)]="qemuTemplate.port_name_format" placeholder="Name format">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="qemuTemplate.port_segment_size" placeholder="Segment size">
|
<input matInput type="number" [(ngModel)]="qemuTemplate.port_segment_size" placeholder="Segment size">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.mac_address" placeholder="Base MAC">
|
<input matInput type="text" [(ngModel)]="qemuTemplate.mac_address" placeholder="Base MAC">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Type" [(ngModel)]="qemuTemplate.adapter_type">
|
<mat-select placeholder="Type" [(ngModel)]="qemuTemplate.adapter_type">
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type[0]">
|
<mat-option *ngFor="let type of networkTypes" [value]="type[0]">
|
||||||
{{type[1]}} ({{type[0]}})
|
{{type[1]}} ({{type[0]}})
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button class="configButton" (click)="configureCustomAdapters()">Configure custom adapters</button><br/>
|
<button mat-button class="configButton" (click)="configureCustomAdapters()">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>
|
||||||
@ -214,6 +216,7 @@
|
|||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<div>
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="fileinitrd.click()" class="file-button">Browse</button>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
#fileinitrd
|
#fileinitrd
|
||||||
@ -226,9 +229,9 @@
|
|||||||
[(ngModel)]="qemuTemplate.initrd"
|
[(ngModel)]="qemuTemplate.initrd"
|
||||||
placeholder="Initial RAM disk (initrd)"/>
|
placeholder="Initial RAM disk (initrd)"/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" (click)="fileinitrd.click()" class="file-button">Browse</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="filekerenelimage.click()" class="file-button">Browse</button>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
#filekernelimage
|
#filekernelimage
|
||||||
@ -241,9 +244,8 @@
|
|||||||
[(ngModel)]="qemuTemplate.kernel_image"
|
[(ngModel)]="qemuTemplate.kernel_image"
|
||||||
placeholder="Kernel image"/>
|
placeholder="Kernel image"/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" (click)="filekerenelimage.click()" class="file-button">Browse</button>
|
|
||||||
</div>
|
</div>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.kernel_command_line" placeholder="Kernel command line">
|
<input matInput type="text" [(ngModel)]="qemuTemplate.kernel_command_line" placeholder="Kernel command line">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
@ -255,6 +257,7 @@
|
|||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<div>
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="filebios.click()" class="file-button">Browse</button>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
#filebios
|
#filebios
|
||||||
@ -267,7 +270,6 @@
|
|||||||
[(ngModel)]="qemuTemplate.bios_image"
|
[(ngModel)]="qemuTemplate.bios_image"
|
||||||
placeholder="Bios image"/>
|
placeholder="Bios image"/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" (click)="filebios.click()" class="file-button">Browse</button>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
@ -280,10 +282,10 @@
|
|||||||
<mat-checkbox [(ngModel)]="activateCpuThrottling">
|
<mat-checkbox [(ngModel)]="activateCpuThrottling">
|
||||||
Activate CPU throttling
|
Activate CPU throttling
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<mat-form-field *ngIf="activateCpuThrottling" class="row">
|
<mat-form-field *ngIf="activateCpuThrottling" class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="qemuTemplate.cpu_throttling" placeholder="Perecentage of CPU allowed">
|
<input matInput type="number" [(ngModel)]="qemuTemplate.cpu_throttling" placeholder="Perecentage of CPU allowed">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Process priority" [(ngModel)]="qemuTemplate.process_priority">
|
<mat-select placeholder="Process priority" [(ngModel)]="qemuTemplate.process_priority">
|
||||||
<mat-option *ngFor="let priority of priorities" [value]="priority">
|
<mat-option *ngFor="let priority of priorities" [value]="priority">
|
||||||
{{priority}}
|
{{priority}}
|
||||||
@ -298,7 +300,7 @@
|
|||||||
Additional settings
|
Additional settings
|
||||||
</mat-card-subtitle>
|
</mat-card-subtitle>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="qemuTemplate.options" placeholder="Options">
|
<input matInput type="text" [(ngModel)]="qemuTemplate.options" placeholder="Options">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-checkbox [(ngModel)]="qemuTemplate.linked_clone">
|
<mat-checkbox [(ngModel)]="qemuTemplate.linked_clone">
|
||||||
@ -313,12 +315,15 @@
|
|||||||
Usage
|
Usage
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="qemuTemplate.usage"></textarea>
|
<textarea matInput type="text" [(ngModel)]="qemuTemplate.usage"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="onSave()">Save</button></div>
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
||||||
@ -355,19 +360,10 @@
|
|||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="buttons-bar">
|
||||||
<button mat-raised-button color="primary" class="configHideButton" (click)="configureCustomAdapters()">Apply</button><br/>
|
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isSymbolSelectionOpened">
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && qemuTemplate" [server]="server" [symbol]="qemuTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
||||||
<div class="default-header">
|
|
||||||
<div class="row">
|
|
||||||
<h1 class="col">Symbol selection</h1>
|
|
||||||
<button class="top-button" (click)="chooseSymbol()" mat-raised-button color="primary">Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="default-content">
|
|
||||||
<app-symbols [server]="server" [symbol]="qemuTemplate.symbol" (symbolChanged)="symbolChanged($event)"></app-symbols>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
.row {
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonvisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-button {
|
|
||||||
width: 18%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name-form-field {
|
|
||||||
padding-right: 2%;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configButton {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configHideButton {
|
|
||||||
margin-left: 80%;
|
|
||||||
width: 20%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadowed {
|
|
||||||
display: none;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbolSelectionButton {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonshadowed {
|
|
||||||
opacity: 0;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
border: 0px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
th.mat-header-cell {
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.mat-cell {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
@ -76,6 +76,9 @@ describe('QemuVmTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should call save template', () => {
|
it('should call save template', () => {
|
||||||
spyOn(mockedQemuService, 'saveTemplate').and.returnValue(of({} as QemuTemplate));
|
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('symbol');
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, ParamMap } 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';
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
@ -8,12 +8,13 @@ import { QemuBinary } from '../../../../models/qemu/qemu-binary';
|
|||||||
import { ToasterService } from '../../../../services/toaster.service';
|
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';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-qemu-virtual-machine-template-details',
|
selector: 'app-qemu-virtual-machine-template-details',
|
||||||
templateUrl: './qemu-vm-template-details.component.html',
|
templateUrl: './qemu-vm-template-details.component.html',
|
||||||
styleUrls: ['./qemu-vm-template-details.component.scss']
|
styleUrls: ['./qemu-vm-template-details.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class QemuVmTemplateDetailsComponent implements OnInit {
|
export class QemuVmTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -34,13 +35,23 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
adapters: CustomAdapter[] = [];
|
adapters: CustomAdapter[] = [];
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
||||||
|
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
private qemuService: QemuService,
|
private qemuService: QemuService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private configurationService: QemuConfigurationService
|
private configurationService: QemuConfigurationService,
|
||||||
){}
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router
|
||||||
|
){
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(){
|
ngOnInit(){
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -97,19 +108,31 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
this.qemuTemplate.bios_image = event.target.files[0].name;
|
this.qemuTemplate.bios_image = event.target.files[0].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancelConfigureCustomAdapters(){
|
||||||
|
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
||||||
|
}
|
||||||
|
|
||||||
configureCustomAdapters(){
|
configureCustomAdapters(){
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
||||||
this.qemuTemplate.custom_adapters = this.adapters;
|
this.qemuTemplate.custom_adapters = this.adapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSave(){
|
goBack() {
|
||||||
if (!this.activateCpuThrottling){
|
this.router.navigate(['/server', this.server.id, 'preferences', 'qemu', 'templates']);
|
||||||
this.qemuTemplate.cpu_throttling = 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.qemuService.saveTemplate(this.server, this.qemuTemplate).subscribe((savedTemplate: QemuTemplate) => {
|
onSave(){
|
||||||
this.toasterService.success("Changes saved");
|
if (this.generalSettingsForm.invalid) {
|
||||||
});
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else {
|
||||||
|
if (!this.activateCpuThrottling){
|
||||||
|
this.qemuTemplate.cpu_throttling = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.qemuService.saveTemplate(this.server, this.qemuTemplate).subscribe((savedTemplate: QemuTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chooseSymbol() {
|
chooseSymbol() {
|
||||||
@ -117,6 +140,7 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
symbolChanged(chosenSymbol: string) {
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
this.qemuTemplate.symbol = chosenSymbol;
|
this.qemuTemplate.symbol = chosenSymbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="default-header">
|
<div class="default-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col">QEMU VM templates</h1>
|
<h1 class="col">QEMU VM templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/qemu/addtemplate" mat-raised-button color="primary">Add QEMU VM template</button>
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/qemu/addtemplate" mat-raised-button color="primary">Add QEMU VM template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,8 +10,8 @@
|
|||||||
<div class="default-content" *ngIf="qemuTemplates.length">
|
<div class="default-content" *ngIf="qemuTemplates.length">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-nav-list *ngIf="server">
|
<mat-nav-list *ngIf="server">
|
||||||
<mat-list-item *ngFor='let template of qemuTemplates'>
|
<div class="list-item" *ngFor='let template of qemuTemplates'>
|
||||||
<span class="name" routerLink="{{template.template_id}}">{{template.name}}</span>
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
<button mat-icon-button class="menu-button" [matMenuTriggerFor]="menu">
|
<button mat-icon-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
<mat-icon>more_vert</mat-icon>
|
<mat-icon>more_vert</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<mat-icon>content_copy</mat-icon><span>Copy</span>
|
<mat-icon>content_copy</mat-icon><span>Copy</span>
|
||||||
</button>
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</mat-list-item>
|
</div>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-button {
|
|
||||||
width: 5%;
|
|
||||||
}
|
|
@ -1,8 +1,7 @@
|
|||||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { QemuTemplate } from '../../../../models/templates/qemu-template';
|
import { QemuTemplate } from '../../../../models/templates/qemu-template';
|
||||||
import { QemuService } from '../../../../services/qemu.service';
|
import { QemuService } from '../../../../services/qemu.service';
|
||||||
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
@ -11,7 +10,7 @@ import { DeleteTemplateComponent } from '../../common/delete-template-component/
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-qemu-virtual-machines-templates',
|
selector: 'app-qemu-virtual-machines-templates',
|
||||||
templateUrl: './qemu-vm-templates.component.html',
|
templateUrl: './qemu-vm-templates.component.html',
|
||||||
styleUrls: ['./qemu-vm-templates.component.scss']
|
styleUrls: ['./qemu-vm-templates.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class QemuVmTemplatesComponent implements OnInit {
|
export class QemuVmTemplatesComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -34,13 +33,8 @@ export class QemuVmTemplatesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTemplates() {
|
getTemplates() {
|
||||||
this.qemuTemplates = [];
|
|
||||||
this.qemuService.getTemplates(this.server).subscribe((qemuTemplates: QemuTemplate[]) => {
|
this.qemuService.getTemplates(this.server).subscribe((qemuTemplates: QemuTemplate[]) => {
|
||||||
qemuTemplates.forEach((template) => {
|
this.qemuTemplates = qemuTemplates.filter((elem) => elem.template_type === 'dynamips');
|
||||||
if ((template.template_type === 'qemu') && !template.builtin) {
|
|
||||||
this.qemuTemplates.push(template);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,19 +5,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content" *ngIf="virtualBoxTemplate">
|
<div class="default-content" *ngIf="virtualBoxTemplate">
|
||||||
<mat-form-field class="form-field">
|
<mat-card class="matCard">
|
||||||
<mat-select
|
<form [formGroup]="vmForm">
|
||||||
placeholder="VM list"
|
<mat-form-field class="form-field">
|
||||||
[(ngModel)]="selectedVM"
|
<mat-select
|
||||||
[ngModelOptions]="{standalone: true}" >
|
placeholder="VM list"
|
||||||
<mat-option *ngFor="let vm of virtualMachines" [value]="vm">
|
[(ngModel)]="selectedVM"
|
||||||
{{vm.vmname}}
|
formControlName="vm" >
|
||||||
</mat-option>
|
<mat-option *ngFor="let vm of virtualMachines" [value]="vm">
|
||||||
</mat-select>
|
{{vm.vmname}}
|
||||||
</mat-form-field><br/>
|
</mat-option>
|
||||||
<mat-checkbox [(ngModel)]="virtualBoxTemplate.linked_clone">
|
</mat-select>
|
||||||
Use as a linked base VM (experimental)
|
</mat-form-field>
|
||||||
</mat-checkbox>
|
</form>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="addTemplate()">Add template</button></div>
|
<mat-checkbox [(ngModel)]="virtualBoxTemplate.linked_clone">
|
||||||
|
Use as a linked base VM (experimental)
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -16,6 +16,7 @@ import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-temp
|
|||||||
import { AddVirtualBoxTemplateComponent } from './add-virtual-box-template.component';
|
import { AddVirtualBoxTemplateComponent } from './add-virtual-box-template.component';
|
||||||
import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
||||||
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
export class MockedVirtualBoxService {
|
export class MockedVirtualBoxService {
|
||||||
public addTemplate(server: Server, virtualBoxTemplate: VirtualBoxTemplate) {
|
public addTemplate(server: Server, virtualBoxTemplate: VirtualBoxTemplate) {
|
||||||
@ -38,7 +39,7 @@ describe('AddVirtualBoxTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
@ -95,6 +96,7 @@ describe('AddVirtualBoxTemplateComponent', () => {
|
|||||||
component.virtualBoxTemplate = {} as VirtualBoxTemplate;
|
component.virtualBoxTemplate = {} as VirtualBoxTemplate;
|
||||||
component.selectedVM = template;
|
component.selectedVM = template;
|
||||||
component.server = {id: 1} as Server;
|
component.server = {id: 1} as Server;
|
||||||
|
component.vmForm.controls['vm'].setValue('virtual machine');
|
||||||
|
|
||||||
component.addTemplate();
|
component.addTemplate();
|
||||||
|
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
||||||
import { VirtualBoxVm } from '../../../../models/virtualBox/virtual-box-vm';
|
import { VirtualBoxVm } from '../../../../models/virtualBox/virtual-box-vm';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template';
|
import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-virtual-box-template',
|
selector: 'app-add-virtual-box-template',
|
||||||
templateUrl: './add-virtual-box-template.component.html',
|
templateUrl: './add-virtual-box-template.component.html',
|
||||||
styleUrls: ['./add-virtual-box-template.component.scss']
|
styleUrls: ['./add-virtual-box-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class AddVirtualBoxTemplateComponent implements OnInit {
|
export class AddVirtualBoxTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
virtualMachines: VirtualBoxVm[];
|
virtualMachines: VirtualBoxVm[];
|
||||||
selectedVM: VirtualBoxVm;
|
selectedVM: VirtualBoxVm;
|
||||||
virtualBoxTemplate: VirtualBoxTemplate;
|
virtualBoxTemplate: VirtualBoxTemplate;
|
||||||
|
vmForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -28,8 +29,13 @@ export class AddVirtualBoxTemplateComponent implements OnInit {
|
|||||||
private virtualBoxService: VirtualBoxService,
|
private virtualBoxService: VirtualBoxService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private templateMocksService: TemplateMocksService,
|
private templateMocksService: TemplateMocksService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
) {}
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.vmForm = this.formBuilder.group({
|
||||||
|
vm: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -46,15 +52,19 @@ export class AddVirtualBoxTemplateComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'virtualbox', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (this.selectedVM) {
|
if (!this.vmForm.invalid) {
|
||||||
this.virtualBoxTemplate.name = this.selectedVM.vmname;
|
this.virtualBoxTemplate.name = this.selectedVM.vmname;
|
||||||
this.virtualBoxTemplate.vmname = this.selectedVM.vmname;
|
this.virtualBoxTemplate.vmname = this.selectedVM.vmname;
|
||||||
this.virtualBoxTemplate.ram = this.selectedVM.ram;
|
this.virtualBoxTemplate.ram = this.selectedVM.ram;
|
||||||
this.virtualBoxTemplate.template_id = uuid();
|
this.virtualBoxTemplate.template_id = uuid();
|
||||||
|
|
||||||
this.virtualBoxService.addTemplate(this.server, this.virtualBoxTemplate).subscribe((template: VirtualBoxTemplate) => {
|
this.virtualBoxService.addTemplate(this.server, this.virtualBoxTemplate).subscribe(() => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'virtualbox', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -12,43 +12,45 @@
|
|||||||
General settings
|
General settings
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<form [formGroup]="generalSettingsForm">
|
||||||
<input matInput type="text" [(ngModel)]="virtualBoxTemplate.name" placeholder="Template name">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput formControlName="templateName" type="text" [(ngModel)]="virtualBoxTemplate.name" placeholder="Template name">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="virtualBoxTemplate.default_name_format" placeholder="Default name format">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput formControlName="defaultName" type="text" [(ngModel)]="virtualBoxTemplate.default_name_format" placeholder="Default name format">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="virtualBoxTemplate.symbol" placeholder="Symbol">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput formControlName="symbol" type="text" [(ngModel)]="virtualBoxTemplate.symbol" placeholder="Symbol">
|
||||||
<button mat-raised-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
<mat-select placeholder="Category" [(ngModel)]="virtualBoxTemplate.category">
|
<mat-form-field class="form-field">
|
||||||
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Category" [(ngModel)]="virtualBoxTemplate.category">
|
||||||
{{category[0]}}
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
</mat-option>
|
{{category[0]}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
<mat-form-field class="select">
|
</mat-form-field>
|
||||||
<mat-select placeholder="Console type" [(ngModel)]="virtualBoxTemplate.console_type">
|
<mat-form-field class="select">
|
||||||
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Console type" [(ngModel)]="virtualBoxTemplate.console_type">
|
||||||
{{type}}
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
</mat-option>
|
{{type}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
<mat-checkbox [(ngModel)]="virtualBoxTemplate.console_auto_start">
|
</mat-form-field>
|
||||||
Auto start console
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="virtualBoxTemplate.console_auto_start">
|
||||||
</mat-checkbox>
|
Auto start console
|
||||||
<mat-form-field class="row">
|
</mat-checkbox>
|
||||||
<input matInput type="number" [(ngModel)]="virtualBoxTemplate.ram" placeholder="RAM">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input matInput formControlName="ram" type="number" [(ngModel)]="virtualBoxTemplate.ram" placeholder="RAM">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<mat-select placeholder="On close" [(ngModel)]="virtualBoxTemplate.on_close">
|
<mat-form-field class="form-field">
|
||||||
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="On close" [(ngModel)]="virtualBoxTemplate.on_close">
|
||||||
{{option[0]}}
|
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
||||||
</mat-option>
|
{{option[0]}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
<mat-checkbox [(ngModel)]="virtualBoxTemplate.headless">
|
<mat-checkbox [(ngModel)]="virtualBoxTemplate.headless">
|
||||||
Start VM in headless mode
|
Start VM in headless mode
|
||||||
</mat-checkbox><br/>
|
</mat-checkbox><br/>
|
||||||
@ -62,26 +64,28 @@
|
|||||||
Network
|
Network
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<form [formGroup]="networkForm">
|
||||||
<input matInput type="number" [(ngModel)]="virtualBoxTemplate.adapters" placeholder="Adapters">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="adapters" matInput type="number" [(ngModel)]="virtualBoxTemplate.adapters" placeholder="Adapters">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="virtualBoxTemplate.first_port_name" placeholder="First port name">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input [ngModelOptions]="{standalone: true}" matInput type="text" [(ngModel)]="virtualBoxTemplate.first_port_name" placeholder="First port name">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="virtualBoxTemplate.port_name_format" placeholder="Name format">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="nameFormat" matInput type="text" [(ngModel)]="virtualBoxTemplate.port_name_format" placeholder="Name format">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input matInput type="number" [(ngModel)]="virtualBoxTemplate.port_segment_size" placeholder="Segment size">
|
<mat-form-field class="form-field">
|
||||||
</mat-form-field>
|
<input formControlName="size" matInput type="number" [(ngModel)]="virtualBoxTemplate.port_segment_size" placeholder="Segment size">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<mat-select placeholder="Type" [(ngModel)]="virtualBoxTemplate.adapter_type">
|
<mat-form-field class="form-field">
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Type" [(ngModel)]="virtualBoxTemplate.adapter_type">
|
||||||
{{type}}
|
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
||||||
</mat-option>
|
{{type}}
|
||||||
</mat-select>
|
</mat-option>
|
||||||
</mat-form-field>
|
</mat-select>
|
||||||
<button mat-raised-button class="configButton" (click)="configureCustomAdapters()">Configure custom adapters</button><br/>
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<button mat-button class="configButton" (click)="configureCustomAdapters()">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>
|
||||||
@ -92,12 +96,15 @@
|
|||||||
Usage
|
Usage
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="virtualBoxTemplate.usage"></textarea>
|
<textarea matInput type="text" [(ngModel)]="virtualBoxTemplate.usage"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="onSave()">Save</button></div>
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
<div class="content" class="configurator" *ngIf="isConfiguratorOpened">
|
||||||
@ -134,19 +141,10 @@
|
|||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="buttons-bar">
|
||||||
<button mat-raised-button color="primary" class="configHideButton" (click)="configureCustomAdapters()">Apply</button><br/>
|
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isSymbolSelectionOpened">
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && virtualBoxTemplate" [server]="server" [symbol]="virtualBoxTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
||||||
<div class="default-header">
|
|
||||||
<div class="row">
|
|
||||||
<h1 class="col">Symbol selection</h1>
|
|
||||||
<button class="top-button" (click)="chooseSymbol()" mat-raised-button color="primary">Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="default-content">
|
|
||||||
<app-symbols [server]="server" [symbol]="virtualBoxTemplate.symbol" (symbolChanged)="symbolChanged($event)"></app-symbols>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
.row {
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configButton {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configHideButton {
|
|
||||||
margin-left: 80%;
|
|
||||||
width: 20%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadowed {
|
|
||||||
display: none;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbolSelectionButton {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonshadowed {
|
|
||||||
opacity: 0;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
border: 0px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
th.mat-header-cell {
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.mat-cell {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute } 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';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
@ -13,7 +13,7 @@ import { VirtualBoxConfigurationService } from '../../../../services/virtual-box
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-virtual-box-template-details',
|
selector: 'app-virtual-box-template-details',
|
||||||
templateUrl: './virtual-box-template-details.component.html',
|
templateUrl: './virtual-box-template-details.component.html',
|
||||||
styleUrls: ['./virtual-box-template-details.component.scss']
|
styleUrls: ['./virtual-box-template-details.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -29,14 +29,31 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
|
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
networkForm: FormGroup
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
private virtualBoxService: VirtualBoxService,
|
private virtualBoxService: VirtualBoxService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private virtualBoxConfigurationService: VirtualBoxConfigurationService
|
private virtualBoxConfigurationService: VirtualBoxConfigurationService,
|
||||||
) {}
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required),
|
||||||
|
ram: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.networkForm = this.formBuilder.group({
|
||||||
|
adapters: new FormControl('', Validators.required),
|
||||||
|
nameFormat: new FormControl('', Validators.required),
|
||||||
|
size: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -75,6 +92,14 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
this.virtualBoxTemplate.custom_adapters = this.adapters;
|
this.virtualBoxTemplate.custom_adapters = this.adapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancelConfigureCustomAdapters(){
|
||||||
|
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'virtualbox', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
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");
|
||||||
@ -86,6 +111,7 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
symbolChanged(chosenSymbol: string) {
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
this.virtualBoxTemplate.symbol = chosenSymbol;
|
this.virtualBoxTemplate.symbol = chosenSymbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="default-header">
|
<div class="default-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col">VirtualBox VM templates</h1>
|
<h1 class="col">VirtualBox VM templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/virtualbox/addtemplate" mat-raised-button color="primary">Add Virtual Box VM template</button>
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/virtualbox/addtemplate" mat-raised-button color="primary">Add Virtual Box VM template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,12 +10,12 @@
|
|||||||
<div class="default-content" *ngIf="virtualBoxTemplates.length">
|
<div class="default-content" *ngIf="virtualBoxTemplates.length">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-nav-list *ngIf="server">
|
<mat-nav-list *ngIf="server">
|
||||||
<mat-list-item *ngFor='let template of virtualBoxTemplates'>
|
<div class="list-item" *ngFor='let template of virtualBoxTemplates'>
|
||||||
<span class="name" routerLink="{{template.template_id}}">{{template.name}}</span>
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
<button class="delete-button" mat-icon-button (click)="deleteTemplate(template)">
|
<button class="delete-button" mat-icon-button (click)="deleteTemplate(template)">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-list-item>
|
</div>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
width: 10%;
|
|
||||||
}
|
|
@ -1,8 +1,7 @@
|
|||||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template';
|
import { VirtualBoxTemplate } from '../../../../models/templates/virtualbox-template';
|
||||||
import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
import { VirtualBoxService } from '../../../../services/virtual-box.service';
|
||||||
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
@ -12,7 +11,7 @@ import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-virtual-box-templates',
|
selector: 'app-virtual-box-templates',
|
||||||
templateUrl: './virtual-box-templates.component.html',
|
templateUrl: './virtual-box-templates.component.html',
|
||||||
styleUrls: ['./virtual-box-templates.component.scss']
|
styleUrls: ['./virtual-box-templates.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class VirtualBoxTemplatesComponent implements OnInit {
|
export class VirtualBoxTemplatesComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -34,13 +33,8 @@ export class VirtualBoxTemplatesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTemplates(){
|
getTemplates(){
|
||||||
this.virtualBoxTemplates = [];
|
|
||||||
this.virtualBoxService.getTemplates(this.server).subscribe((virtualBoxTemplates: VirtualBoxTemplate[]) => {
|
this.virtualBoxService.getTemplates(this.server).subscribe((virtualBoxTemplates: VirtualBoxTemplate[]) => {
|
||||||
virtualBoxTemplates.forEach((template) => {
|
this.virtualBoxTemplates = virtualBoxTemplates.filter((elem) => elem.template_type === 'virtualbox');
|
||||||
if ((template.template_type === 'virtualbox') && !template.builtin) {
|
|
||||||
this.virtualBoxTemplates.push(template);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,19 +5,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content" *ngIf="vmwareTemplate">
|
<div class="default-content" *ngIf="vmwareTemplate">
|
||||||
<mat-form-field class="form-field">
|
<mat-card class="matCard">
|
||||||
<mat-select
|
<form [formGroup]="templateNameForm">
|
||||||
placeholder="VM list"
|
<mat-form-field class="form-field">
|
||||||
[(ngModel)]="selectedVM"
|
<mat-select
|
||||||
[ngModelOptions]="{standalone: true}" >
|
placeholder="VM list"
|
||||||
<mat-option *ngFor="let vm of virtualMachines" [value]="vm">
|
formControlName="templateName"
|
||||||
{{vm.vmname}}
|
[(ngModel)]="selectedVM" >
|
||||||
</mat-option>
|
<mat-option *ngFor="let vm of virtualMachines" [value]="vm">
|
||||||
</mat-select>
|
{{vm.vmname}}
|
||||||
</mat-form-field><br/>
|
</mat-option>
|
||||||
<mat-checkbox [(ngModel)]="vmwareTemplate.linked_clone">
|
</mat-select>
|
||||||
Use as a linked base VM (experimental)
|
</mat-form-field><br/>
|
||||||
</mat-checkbox>
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="vmwareTemplate.linked_clone">
|
||||||
<div class="buttons-bar"><button mat-raised-button color="primary" (click)="addTemplate()">Add template</button></div>
|
Use as a linked base VM (experimental)
|
||||||
|
</mat-checkbox>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.form-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -1,26 +1,27 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { VmwareVm } from '../../../../models/vmware/vmware-vm';
|
import { VmwareVm } from '../../../../models/vmware/vmware-vm';
|
||||||
import { VmwareTemplate } from '../../../../models/templates/vmware-template';
|
import { VmwareTemplate } from '../../../../models/templates/vmware-template';
|
||||||
import { VmwareService } from '../../../../services/vmware.service';
|
import { VmwareService } from '../../../../services/vmware.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-vmware-template',
|
selector: 'app-add-vmware-template',
|
||||||
templateUrl: './add-vmware-template.component.html',
|
templateUrl: './add-vmware-template.component.html',
|
||||||
styleUrls: ['./add-vmware-template.component.scss']
|
styleUrls: ['./add-vmware-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class AddVmwareTemplateComponent implements OnInit {
|
export class AddVmwareTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
virtualMachines: VmwareVm[];
|
virtualMachines: VmwareVm[];
|
||||||
selectedVM: VmwareVm;
|
selectedVM: VmwareVm;
|
||||||
vmwareTemplate: VmwareTemplate;
|
vmwareTemplate: VmwareTemplate;
|
||||||
|
templateNameForm: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -28,8 +29,13 @@ export class AddVmwareTemplateComponent implements OnInit {
|
|||||||
private vmwareService: VmwareService,
|
private vmwareService: VmwareService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private templateMocksService: TemplateMocksService,
|
private templateMocksService: TemplateMocksService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
) {}
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.templateNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl(null, [Validators.required])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -46,14 +52,18 @@ export class AddVmwareTemplateComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'vmware', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (this.selectedVM) {
|
if (!this.templateNameForm.invalid) {
|
||||||
this.vmwareTemplate.name = this.selectedVM.vmname;
|
this.vmwareTemplate.name = this.selectedVM.vmname;
|
||||||
this.vmwareTemplate.vmx_path = this.selectedVM.vmx_path;
|
this.vmwareTemplate.vmx_path = this.selectedVM.vmx_path;
|
||||||
this.vmwareTemplate.template_id = uuid();
|
this.vmwareTemplate.template_id = uuid();
|
||||||
|
|
||||||
this.vmwareService.addTemplate(this.server, this.vmwareTemplate).subscribe((template: VmwareTemplate) => {
|
this.vmwareService.addTemplate(this.server, this.vmwareTemplate).subscribe(() => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'vmware', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -17,6 +17,7 @@ import { VmwareTemplate } from '../../../../models/templates/vmware-template';
|
|||||||
import { AddVmwareTemplateComponent } from './add-vmware-template.component';
|
import { AddVmwareTemplateComponent } from './add-vmware-template.component';
|
||||||
import { VmwareService } from '../../../../services/vmware.service';
|
import { VmwareService } from '../../../../services/vmware.service';
|
||||||
import { VmwareVm } from '../../../../models/vmware/vmware-vm';
|
import { VmwareVm } from '../../../../models/vmware/vmware-vm';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
export class MockedVmwareService {
|
export class MockedVmwareService {
|
||||||
public addTemplate(server: Server, vmwareTemplate: VmwareTemplate) {
|
public addTemplate(server: Server, vmwareTemplate: VmwareTemplate) {
|
||||||
@ -39,7 +40,7 @@ describe('AddVmwareTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
@ -76,6 +77,7 @@ describe('AddVmwareTemplateComponent', () => {
|
|||||||
component.vmwareTemplate = {} as VmwareTemplate;
|
component.vmwareTemplate = {} as VmwareTemplate;
|
||||||
component.selectedVM = template;
|
component.selectedVM = template;
|
||||||
component.server = {id: 1} as Server;
|
component.server = {id: 1} as Server;
|
||||||
|
component.templateNameForm.controls['templateName'].setValue('template name');
|
||||||
|
|
||||||
component.addTemplate();
|
component.addTemplate();
|
||||||
|
|
||||||
|
@ -12,30 +12,30 @@
|
|||||||
General settings
|
General settings
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<form [formGroup]="inputForm">
|
<form [formGroup]="generalSettingsForm">
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput type="text"
|
matInput type="text"
|
||||||
[(ngModel)]="vmwareTemplate.name"
|
[(ngModel)]="vmwareTemplate.name"
|
||||||
formControlName="templateName"
|
formControlName="templateName"
|
||||||
placeholder="Template name">
|
placeholder="Template name">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput type="text"
|
matInput type="text"
|
||||||
[(ngModel)]="vmwareTemplate.default_name_format"
|
[(ngModel)]="vmwareTemplate.default_name_format"
|
||||||
formControlName="defaultName"
|
formControlName="defaultName"
|
||||||
placeholder="Default name format">
|
placeholder="Default name format">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input
|
<input
|
||||||
matInput type="text"
|
matInput type="text"
|
||||||
[(ngModel)]="vmwareTemplate.symbol"
|
[(ngModel)]="vmwareTemplate.symbol"
|
||||||
formControlName="symbol"
|
formControlName="symbol"
|
||||||
placeholder="Symbol">
|
placeholder="Symbol">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select
|
<mat-select
|
||||||
placeholder="Category"
|
placeholder="Category"
|
||||||
[ngModelOptions]="{standalone: true}"
|
[ngModelOptions]="{standalone: true}"
|
||||||
@ -60,7 +60,7 @@
|
|||||||
[(ngModel)]="vmwareTemplate.console_auto_start">
|
[(ngModel)]="vmwareTemplate.console_auto_start">
|
||||||
Auto start console
|
Auto start console
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select
|
<mat-select
|
||||||
placeholder="On close"
|
placeholder="On close"
|
||||||
[ngModelOptions]="{standalone: true}"
|
[ngModelOptions]="{standalone: true}"
|
||||||
@ -88,26 +88,26 @@
|
|||||||
Network
|
Network
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="vmwareTemplate.adapters" placeholder="Adapters">
|
<input matInput type="number" [(ngModel)]="vmwareTemplate.adapters" placeholder="Adapters">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="vmwareTemplate.first_port_name" placeholder="First port name">
|
<input matInput type="text" [(ngModel)]="vmwareTemplate.first_port_name" placeholder="First port name">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="text" [(ngModel)]="vmwareTemplate.port_name_format" placeholder="Name format">
|
<input matInput type="text" [(ngModel)]="vmwareTemplate.port_name_format" placeholder="Name format">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<input matInput type="number" [(ngModel)]="vmwareTemplate.port_segment_size" placeholder="Segment size">
|
<input matInput type="number" [(ngModel)]="vmwareTemplate.port_segment_size" placeholder="Segment size">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<mat-select placeholder="Type" [(ngModel)]="vmwareTemplate.adapter_type">
|
<mat-select placeholder="Type" [(ngModel)]="vmwareTemplate.adapter_type">
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
||||||
{{type}}
|
{{type}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button class="configButton" (click)="configureCustomAdapters()">Configure custom adapters</button><br/>
|
<button mat-button class="configButton" (click)="configureCustomAdapters()">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>
|
||||||
@ -118,13 +118,14 @@
|
|||||||
Usage
|
Usage
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-form-field class="row">
|
<mat-form-field class="form-field">
|
||||||
<textarea matInput type="text" [(ngModel)]="vmwareTemplate.usage"></textarea>
|
<textarea matInput type="text" [(ngModel)]="vmwareTemplate.usage"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
<div class="buttons-bar">
|
<div class="buttons-bar">
|
||||||
<button mat-raised-button color="primary" (click)="onSave()">Save</button><br/>
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -162,19 +163,10 @@
|
|||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="buttons-bar">
|
||||||
<button mat-raised-button color="primary" class="configHideButton" (click)="saveCustomAdapters()">Apply</button><br/>
|
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="configureCustomAdapters()">Apply</button><br/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class="configurator" *ngIf="isSymbolSelectionOpened">
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && vmwareTemplate" [server]="server" [symbol]="vmwareTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
||||||
<div class="default-header">
|
|
||||||
<div class="row">
|
|
||||||
<h1 class="col">Symbol selection</h1>
|
|
||||||
<button class="top-button" (click)="chooseSymbol()" mat-raised-button color="primary">Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="default-content">
|
|
||||||
<app-symbols [server]="server" [symbol]="vmwareTemplate.symbol" (symbolChanged)="symbolChanged($event)"></app-symbols>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
.row {
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configButton {
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.configHideButton {
|
|
||||||
margin-left: 80%;
|
|
||||||
width: 20%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadowed {
|
|
||||||
display: none;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbolSelectionButton {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonshadowed {
|
|
||||||
opacity: 0;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
border: 0px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
th.mat-header-cell {
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.mat-cell {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
@ -68,9 +68,9 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should call save template', () => {
|
it('should call save template', () => {
|
||||||
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
||||||
component.inputForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.inputForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.inputForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
@ -79,9 +79,9 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should not call save template when template name is empty', () => {
|
it('should not call save template when template name is empty', () => {
|
||||||
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
||||||
component.inputForm.controls['templateName'].setValue('');
|
component.generalSettingsForm.controls['templateName'].setValue('');
|
||||||
component.inputForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.inputForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
@ -90,9 +90,9 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should not call save template when default name is empty', () => {
|
it('should not call save template when default name is empty', () => {
|
||||||
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
||||||
component.inputForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.inputForm.controls['defaultName'].setValue('');
|
component.generalSettingsForm.controls['defaultName'].setValue('');
|
||||||
component.inputForm.controls['symbol'].setValue('symbol');
|
component.generalSettingsForm.controls['symbol'].setValue('symbol');
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
@ -101,9 +101,9 @@ describe('VmwareTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should not call save template when symbol path is empty', () => {
|
it('should not call save template when symbol path is empty', () => {
|
||||||
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
spyOn(mockedVmwareService, 'saveTemplate').and.returnValue(of({} as VmwareTemplate));
|
||||||
component.inputForm.controls['templateName'].setValue('template name');
|
component.generalSettingsForm.controls['templateName'].setValue('template name');
|
||||||
component.inputForm.controls['defaultName'].setValue('default name');
|
component.generalSettingsForm.controls['defaultName'].setValue('default name');
|
||||||
component.inputForm.controls['symbol'].setValue('');
|
component.generalSettingsForm.controls['symbol'].setValue('');
|
||||||
|
|
||||||
component.onSave();
|
component.onSave();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute } 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';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
@ -13,12 +13,12 @@ import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vmware-template-details',
|
selector: 'app-vmware-template-details',
|
||||||
templateUrl: './vmware-template-details.component.html',
|
templateUrl: './vmware-template-details.component.html',
|
||||||
styleUrls: ['./vmware-template-details.component.scss']
|
styleUrls: ['./vmware-template-details.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class VmwareTemplateDetailsComponent implements OnInit {
|
export class VmwareTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
vmwareTemplate: VmwareTemplate;
|
vmwareTemplate: VmwareTemplate;
|
||||||
inputForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
adapters: CustomAdapter[] = [];
|
adapters: CustomAdapter[] = [];
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
||||||
@ -36,9 +36,10 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
private vmwareService: VmwareService,
|
private vmwareService: VmwareService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private vmwareConfigurationService: VmwareConfigurationService
|
private vmwareConfigurationService: VmwareConfigurationService,
|
||||||
|
private router: Router
|
||||||
) {
|
) {
|
||||||
this.inputForm = this.formBuilder.group({
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
templateName: new FormControl('', Validators.required),
|
templateName: new FormControl('', Validators.required),
|
||||||
defaultName: new FormControl('', Validators.required),
|
defaultName: new FormControl('', Validators.required),
|
||||||
symbol: new FormControl('', Validators.required)
|
symbol: new FormControl('', Validators.required)
|
||||||
@ -65,8 +66,12 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
this.networkTypes = this.vmwareConfigurationService.getNetworkTypes();
|
this.networkTypes = this.vmwareConfigurationService.getNetworkTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'vmware', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
if (this.inputForm.invalid) {
|
if (this.generalSettingsForm.invalid) {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
} else {
|
} else {
|
||||||
this.vmwareService.saveTemplate(this.server, this.vmwareTemplate).subscribe((vmwareTemplate: VmwareTemplate) => {
|
this.vmwareService.saveTemplate(this.server, this.vmwareTemplate).subscribe((vmwareTemplate: VmwareTemplate) => {
|
||||||
@ -75,6 +80,10 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancelConfigureCustomAdapters(){
|
||||||
|
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
||||||
|
}
|
||||||
|
|
||||||
configureCustomAdapters() {
|
configureCustomAdapters() {
|
||||||
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
this.isConfiguratorOpened = !this.isConfiguratorOpened;
|
||||||
this.adapters = [];
|
this.adapters = [];
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="default-header">
|
<div class="default-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col">VMware VM templates</h1>
|
<h1 class="col">VMware VM templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/vmware/addtemplate" mat-raised-button color="primary">Add VMware template</button>
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/vmware/addtemplate" mat-raised-button color="primary">Add VMware template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,12 +10,12 @@
|
|||||||
<div class="default-content" *ngIf="vmwareTemplates.length">
|
<div class="default-content" *ngIf="vmwareTemplates.length">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-nav-list *ngIf="server">
|
<mat-nav-list *ngIf="server">
|
||||||
<mat-list-item *ngFor='let template of vmwareTemplates'>
|
<div class="list-item" *ngFor='let template of vmwareTemplates'>
|
||||||
<span class="name" routerLink="{{template.template_id}}">{{template.name}}</span>
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
<button class="delete-button" mat-icon-button (click)="deleteTemplate(template)">
|
<button class="delete-button" mat-icon-button (click)="deleteTemplate(template)">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-list-item>
|
</div>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
width: 10%;
|
|
||||||
}
|
|
@ -1,19 +1,16 @@
|
|||||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { VmwareTemplate } from '../../../../models/templates/vmware-template';
|
import { VmwareTemplate } from '../../../../models/templates/vmware-template';
|
||||||
import { VmwareService } from '../../../../services/vmware.service';
|
import { VmwareService } from '../../../../services/vmware.service';
|
||||||
import { MatDialog } from '@angular/material';
|
|
||||||
import { DeleteConfirmationDialogComponent } from '../../common/delete-confirmation-dialog/delete-confirmation-dialog.component';
|
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
|
||||||
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vmware-templates',
|
selector: 'app-vmware-templates',
|
||||||
templateUrl: './vmware-templates.component.html',
|
templateUrl: './vmware-templates.component.html',
|
||||||
styleUrls: ['./vmware-templates.component.scss']
|
styleUrls: ['./vmware-templates.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class VmwareTemplatesComponent implements OnInit {
|
export class VmwareTemplatesComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
|
@ -5,10 +5,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content">
|
<div class="default-content">
|
||||||
<mat-form-field class="row">
|
<mat-card class="matCard">
|
||||||
<input matInput type="text" [(ngModel)]="templateName" placeholder="Template name">
|
<form [formGroup]="templateNameForm">
|
||||||
</mat-form-field>
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="templateName" type="text" [(ngModel)]="templateName" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
<div class="buttons-bar">
|
<div class="buttons-bar">
|
||||||
|
<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 color="primary" (click)="addTemplate()">Add template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.row {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -16,6 +16,7 @@ import { TemplateMocksService } from '../../../../services/template-mocks.servic
|
|||||||
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
import { MockedToasterService } from '../../../../services/toaster.service.spec';
|
||||||
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
||||||
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
import { MockedActivatedRoute } from '../../preferences.component.spec';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
export class MockedVpcsService {
|
export class MockedVpcsService {
|
||||||
public addTemplate(server: Server, vpcsTemplate: VpcsTemplate) {
|
public addTemplate(server: Server, vpcsTemplate: VpcsTemplate) {
|
||||||
@ -34,7 +35,7 @@ describe('AddVpcsTemplateComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
imports: [FormsModule, ReactiveFormsModule, MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: ActivatedRoute, useValue: activatedRoute
|
provide: ActivatedRoute, useValue: activatedRoute
|
||||||
@ -64,6 +65,7 @@ describe('AddVpcsTemplateComponent', () => {
|
|||||||
it('should call add template', () => {
|
it('should call add template', () => {
|
||||||
spyOn(mockedVpcsService, 'addTemplate').and.returnValue(of({} as VpcsTemplate));
|
spyOn(mockedVpcsService, 'addTemplate').and.returnValue(of({} as VpcsTemplate));
|
||||||
component.templateName = "sample name";
|
component.templateName = "sample name";
|
||||||
|
component.templateNameForm.controls['templateName'].setValue('template name');
|
||||||
component.server = {id: 1} as Server;
|
component.server = {id: 1} as Server;
|
||||||
|
|
||||||
component.addTemplate();
|
component.addTemplate();
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { VpcsService } from '../../../../services/vpcs.service';
|
import { VpcsService } from '../../../../services/vpcs.service';
|
||||||
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-vpcs-template',
|
selector: 'app-add-vpcs-template',
|
||||||
templateUrl: './add-vpcs-template.component.html',
|
templateUrl: './add-vpcs-template.component.html',
|
||||||
styleUrls: ['./add-vpcs-template.component.scss']
|
styleUrls: ['./add-vpcs-template.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class AddVpcsTemplateComponent implements OnInit {
|
export class AddVpcsTemplateComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
templateName: string = '';
|
templateName: string = '';
|
||||||
|
templateNameForm: FormGroup
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -25,8 +26,13 @@ export class AddVpcsTemplateComponent implements OnInit {
|
|||||||
private vpcsService: VpcsService,
|
private vpcsService: VpcsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private templateMocksService: TemplateMocksService
|
private templateMocksService: TemplateMocksService,
|
||||||
) {}
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.templateNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl(null, [Validators.required])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const server_id = this.route.snapshot.paramMap.get("server_id");
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
@ -35,8 +41,12 @@ export class AddVpcsTemplateComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'vpcs', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (this.templateName) {
|
if (!this.templateNameForm.invalid) {
|
||||||
let vpcsTemplate: VpcsTemplate;
|
let vpcsTemplate: VpcsTemplate;
|
||||||
|
|
||||||
this.templateMocksService.getVpcsTemplate().subscribe((template: VpcsTemplate) => {
|
this.templateMocksService.getVpcsTemplate().subscribe((template: VpcsTemplate) => {
|
||||||
@ -46,8 +56,8 @@ export class AddVpcsTemplateComponent implements OnInit {
|
|||||||
vpcsTemplate.template_id = uuid(),
|
vpcsTemplate.template_id = uuid(),
|
||||||
vpcsTemplate.name = this.templateName,
|
vpcsTemplate.name = this.templateName,
|
||||||
|
|
||||||
this.vpcsService.addTemplate(this.server, vpcsTemplate).subscribe((vpcsTemplate) => {
|
this.vpcsService.addTemplate(this.server, vpcsTemplate).subscribe(() => {
|
||||||
this.router.navigate(['/server', this.server.id, 'preferences', 'vpcs', 'templates']);
|
this.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,77 +5,68 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="default-content" *ngIf="vpcsTemplate">
|
<div class="default-content" *ngIf="vpcsTemplate">
|
||||||
<form [formGroup]="inputForm">
|
<mat-card class="matCard">
|
||||||
<mat-form-field class="row">
|
<form [formGroup]="inputForm">
|
||||||
<input
|
<mat-form-field class="form-field">
|
||||||
matInput type="text"
|
<input
|
||||||
[(ngModel)]="vpcsTemplate.name"
|
matInput type="text"
|
||||||
formControlName="templateName"
|
[(ngModel)]="vpcsTemplate.name"
|
||||||
placeholder="Template name">
|
formControlName="templateName"
|
||||||
</mat-form-field>
|
placeholder="Template name">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input
|
<mat-form-field class="form-field">
|
||||||
matInput type="text"
|
<input
|
||||||
[(ngModel)]="vpcsTemplate.default_name_format"
|
matInput type="text"
|
||||||
formControlName="defaultName"
|
[(ngModel)]="vpcsTemplate.default_name_format"
|
||||||
placeholder="Default name format">
|
formControlName="defaultName"
|
||||||
</mat-form-field>
|
placeholder="Default name format">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input
|
<mat-form-field class="form-field">
|
||||||
matInput type="text"
|
<input
|
||||||
[(ngModel)]="vpcsTemplate.base_script_file"
|
matInput type="text"
|
||||||
formControlName="scriptFile"
|
[(ngModel)]="vpcsTemplate.base_script_file"
|
||||||
placeholder="Base script file">
|
formControlName="scriptFile"
|
||||||
</mat-form-field>
|
placeholder="Base script file">
|
||||||
<mat-form-field class="row">
|
</mat-form-field>
|
||||||
<input
|
<mat-form-field class="form-field">
|
||||||
matInput type="text"
|
<input
|
||||||
[(ngModel)]="vpcsTemplate.symbol"
|
matInput type="text"
|
||||||
formControlName="symbol"
|
[(ngModel)]="vpcsTemplate.symbol"
|
||||||
placeholder="Symbol">
|
formControlName="symbol"
|
||||||
</mat-form-field>
|
placeholder="Symbol">
|
||||||
<button mat-raised-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
</mat-form-field>
|
||||||
<mat-form-field class="row">
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
<mat-select
|
<mat-form-field class="form-field">
|
||||||
placeholder="Category"
|
<mat-select
|
||||||
|
placeholder="Category"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="vpcsTemplate.category">
|
||||||
|
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
||||||
|
{{category[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="vpcsTemplate.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox
|
||||||
[ngModelOptions]="{standalone: true}"
|
[ngModelOptions]="{standalone: true}"
|
||||||
[(ngModel)]="vpcsTemplate.category">
|
[(ngModel)]="vpcsTemplate.console_auto_start">
|
||||||
<mat-option *ngFor="let category of categories" [value]="category[1]">
|
Auto start console
|
||||||
{{category[0]}}
|
</mat-checkbox>
|
||||||
</mat-option>
|
</form>
|
||||||
</mat-select>
|
</mat-card>
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="select">
|
|
||||||
<mat-select
|
|
||||||
placeholder="Console type"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
[(ngModel)]="vpcsTemplate.console_type">
|
|
||||||
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
|
||||||
{{type}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-checkbox
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
[(ngModel)]="vpcsTemplate.console_auto_start">
|
|
||||||
Auto start console
|
|
||||||
</mat-checkbox>
|
|
||||||
</form>
|
|
||||||
<div class="buttons-bar">
|
<div class="buttons-bar">
|
||||||
<button mat-raised-button color="primary" (click)="onSave()">Save</button><br/>
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && vpcsTemplate" [server]="server" [symbol]="vpcsTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
||||||
<div class="content" class="configurator" *ngIf="isSymbolSelectionOpened">
|
|
||||||
<div class="default-header">
|
|
||||||
<div class="row">
|
|
||||||
<h1 class="col">Symbol selection</h1>
|
|
||||||
<button class="top-button" class="cancel-button" (click)="cancelChooseSymbol()" mat-raised-button color="primary">Cancel</button>
|
|
||||||
<button class="top-button" class="choose-symbol-button" (click)="chooseSymbol()" mat-raised-button color="primary">Choose symbol</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="default-content">
|
|
||||||
<app-symbols [server]="server" [symbol]="vpcsTemplate.symbol" (symbolChanged)="symbolChanged($event)"></app-symbols>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
.row {
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadowed {
|
|
||||||
display: none;
|
|
||||||
transition: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.symbolSelectionButton {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute } 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';
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
@ -12,16 +12,13 @@ import { VpcsConfigurationService } from '../../../../services/vpcs-configuratio
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vpcs-template-details',
|
selector: 'app-vpcs-template-details',
|
||||||
templateUrl: './vpcs-template-details.component.html',
|
templateUrl: './vpcs-template-details.component.html',
|
||||||
styleUrls: ['./vpcs-template-details.component.scss','../../preferences.component.scss']
|
styleUrls: ['./vpcs-template-details.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class VpcsTemplateDetailsComponent implements OnInit {
|
export class VpcsTemplateDetailsComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
vpcsTemplate: VpcsTemplate;
|
vpcsTemplate: VpcsTemplate;
|
||||||
inputForm: FormGroup;
|
inputForm: FormGroup;
|
||||||
|
|
||||||
isSymbolSelectionOpened: boolean = false;
|
isSymbolSelectionOpened: boolean = false;
|
||||||
copyOfSymbol: string;
|
|
||||||
|
|
||||||
consoleTypes: string[] = [];
|
consoleTypes: string[] = [];
|
||||||
categories = [];
|
categories = [];
|
||||||
|
|
||||||
@ -31,7 +28,8 @@ export class VpcsTemplateDetailsComponent implements OnInit {
|
|||||||
private vpcsService: VpcsService,
|
private vpcsService: VpcsService,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private vpcsConfigurationService: VpcsConfigurationService
|
private vpcsConfigurationService: VpcsConfigurationService,
|
||||||
|
private router: Router
|
||||||
) {
|
) {
|
||||||
this.inputForm = this.formBuilder.group({
|
this.inputForm = this.formBuilder.group({
|
||||||
templateName: new FormControl('', Validators.required),
|
templateName: new FormControl('', Validators.required),
|
||||||
@ -59,6 +57,10 @@ export class VpcsTemplateDetailsComponent implements OnInit {
|
|||||||
this.categories = this.vpcsConfigurationService.getCategories();
|
this.categories = this.vpcsConfigurationService.getCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'vpcs', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
if (this.inputForm.invalid) {
|
if (this.inputForm.invalid) {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
@ -70,16 +72,11 @@ export class VpcsTemplateDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
chooseSymbol() {
|
chooseSymbol() {
|
||||||
this.copyOfSymbol = this.vpcsTemplate.symbol;
|
|
||||||
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelChooseSymbol() {
|
|
||||||
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
|
||||||
this.vpcsTemplate.symbol = this.copyOfSymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbolChanged(chosenSymbol: string) {
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
this.vpcsTemplate.symbol = chosenSymbol;
|
this.vpcsTemplate.symbol = chosenSymbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="default-header">
|
<div class="default-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col">VPCS node templates</h1>
|
<h1 class="col">VPCS node templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/vpcs/addtemplate" mat-raised-button color="primary">Add VPCS template</button>
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/vpcs/addtemplate" mat-raised-button color="primary">Add VPCS template</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,12 +10,12 @@
|
|||||||
<div class="default-content" *ngIf="vpcsTemplates.length">
|
<div class="default-content" *ngIf="vpcsTemplates.length">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<mat-nav-list *ngIf="server">
|
<mat-nav-list *ngIf="server">
|
||||||
<mat-list-item *ngFor='let template of vpcsTemplates'>
|
<div class="list-item" *ngFor='let template of vpcsTemplates'>
|
||||||
<span class="name" routerLink="{{template.template_id}}">{{template.name}}</span>
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
<button class="delete-button" mat-icon-button (click)="deleteTemplate(template)">
|
<button class="delete-button" mat-icon-button (click)="deleteTemplate(template)">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-list-item>
|
</div>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
.top-button {
|
|
||||||
height: 36px;
|
|
||||||
margin-top: 22px
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
width: 10%;
|
|
||||||
}
|
|
@ -1,19 +1,16 @@
|
|||||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { Server } from '../../../../models/server';
|
import { Server } from '../../../../models/server';
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ServerService } from '../../../../services/server.service';
|
import { ServerService } from '../../../../services/server.service';
|
||||||
import { VpcsService } from '../../../../services/vpcs.service';
|
import { VpcsService } from '../../../../services/vpcs.service';
|
||||||
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
import { VpcsTemplate } from '../../../../models/templates/vpcs-template';
|
||||||
import { MatDialog } from '@angular/material';
|
|
||||||
import { DeleteConfirmationDialogComponent } from '../../common/delete-confirmation-dialog/delete-confirmation-dialog.component';
|
|
||||||
import { ToasterService } from '../../../../services/toaster.service';
|
|
||||||
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vpcs-templates',
|
selector: 'app-vpcs-templates',
|
||||||
templateUrl: './vpcs-templates.component.html',
|
templateUrl: './vpcs-templates.component.html',
|
||||||
styleUrls: ['./vpcs-templates.component.scss']
|
styleUrls: ['./vpcs-templates.component.scss', '../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class VpcsTemplatesComponent implements OnInit {
|
export class VpcsTemplatesComponent implements OnInit {
|
||||||
server: Server;
|
server: Server;
|
||||||
@ -35,13 +32,8 @@ export class VpcsTemplatesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTemplates() {
|
getTemplates() {
|
||||||
this.vpcsTemplates = [];
|
|
||||||
this.vpcsService.getTemplates(this.server).subscribe((vpcsTemplates: VpcsTemplate[]) => {
|
this.vpcsService.getTemplates(this.server).subscribe((vpcsTemplates: VpcsTemplate[]) => {
|
||||||
vpcsTemplates.forEach((template) => {
|
this.vpcsTemplates = vpcsTemplates.filter((elem) => elem.template_type === 'vpcs');
|
||||||
if ((template.template_type === 'vpcs') && !template.builtin) {
|
|
||||||
this.vpcsTemplates.push(template);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
src/app/filters/searchFilter.pipe.spec.ts
Normal file
0
src/app/filters/searchFilter.pipe.spec.ts
Normal file
17
src/app/filters/searchFilter.pipe.ts
Normal file
17
src/app/filters/searchFilter.pipe.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'filenamefilter'
|
||||||
|
})
|
||||||
|
export class SearchFilter implements PipeTransform {
|
||||||
|
transform(items: any[], searchText: string): any[] {
|
||||||
|
if(!items) return [];
|
||||||
|
if(!searchText) return items;
|
||||||
|
|
||||||
|
searchText = searchText.toLowerCase();
|
||||||
|
return items.filter( item => {
|
||||||
|
return item.filename.toLowerCase().includes(searchText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user