mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-06-18 06:48:09 +00:00
Initial implementation
This commit is contained in:
@ -111,6 +111,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
|
<app-template [server]="server" (onNodeCreation)="onNodeCreation($event)"></app-template>
|
||||||
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
<button matTooltip="Add a link" mat-icon-button [color]="tools.draw_link ? 'primary' : 'basic'" (click)="toggleDrawLineMode()">
|
<button matTooltip="Add a link" mat-icon-button [color]="tools.draw_link ? 'primary' : 'basic'" (click)="toggleDrawLineMode()">
|
||||||
<mat-icon>timeline</mat-icon>
|
<mat-icon>timeline</mat-icon>
|
||||||
@ -127,10 +131,6 @@
|
|||||||
<app-snapshot-menu-item [server]="server" [project]="project"> </app-snapshot-menu-item>
|
<app-snapshot-menu-item [server]="server" [project]="project"> </app-snapshot-menu-item>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
|
||||||
<app-template [server]="server" (onNodeCreation)="onNodeCreation($event)"></app-template>
|
|
||||||
</mat-toolbar-row>
|
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
<button matTooltip="Go to preferences" mat-icon-button routerLink="/server/{{server.id}}/preferences">
|
<button matTooltip="Go to preferences" mat-icon-button routerLink="/server/{{server.id}}/preferences">
|
||||||
<mat-icon>settings_applications</mat-icon>
|
<mat-icon>settings_applications</mat-icon>
|
||||||
@ -160,9 +160,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="zoom-buttons">
|
<div id="zoom-buttons">
|
||||||
<button class="zoom-button" (click)="zoomIn()">+</button>
|
<button class="zoom-button" (click)="zoomIn()"><mat-icon>zoom_in</mat-icon></button>
|
||||||
<button class="zoom-button" (click)="resetZoom()"><mat-icon>adjust</mat-icon></button>
|
<button class="zoom-button" (click)="resetZoom()"><mat-icon>adjust</mat-icon></button>
|
||||||
<button class="zoom-button" (click)="zoomOut()">-</button>
|
<button class="zoom-button" (click)="zoomOut()"><mat-icon>zoom_out</mat-icon></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-progress></app-progress>
|
<app-progress></app-progress>
|
||||||
|
@ -111,7 +111,7 @@ mat-divider.divider {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
mat-icon {
|
mat-icon {
|
||||||
margin-top: 8px;
|
margin-left: -6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ mat-divider.divider {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
mat-icon {
|
mat-icon {
|
||||||
margin-top: 8px;
|
margin-left: -6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,6 +407,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.mapChangeDetectorRef.detectChanges();
|
this.mapChangeDetectorRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//here we should support adding multiple nodes on single click
|
||||||
onNodeCreation(template: Template) {
|
onNodeCreation(template: Template) {
|
||||||
if(!template) {
|
if(!template) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,22 +1,78 @@
|
|||||||
|
<div class="title-container">
|
||||||
|
<h1 mat-dialog-title>Add a node</h1>
|
||||||
|
<button mat-button class="top-button" color="accent" (click)="onNoClick()" routerLink="/server/{{server.id}}/preferences">Go to template preferences</button>
|
||||||
|
</div>
|
||||||
<div mat-dialog-content class="content">
|
<div mat-dialog-content class="content">
|
||||||
<div class="header">
|
<div class="title-container">
|
||||||
<mat-form-field floatPlaceholder="never">
|
<h6>Template</h6>
|
||||||
<input matInput #filter placeholder="Filter templates" />
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
</div>
|
||||||
|
<mat-form-field class="form-field" floatPlaceholder="never">
|
||||||
<mat-table #table [dataSource]="dataSource">
|
<!-- <input matInput #filter placeholder="Filter templates by name" /> -->
|
||||||
|
<input matInput
|
||||||
|
placeholder="Search by name"
|
||||||
|
[(ngModel)]="searchText"
|
||||||
|
[ngModelOptions]="{standalone: true}">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
placeholder="Filter templates by type"
|
||||||
|
(selectionChange)="filterTemplates($event)"
|
||||||
|
[(ngModel)]="selectedType">
|
||||||
|
<mat-option *ngFor="let type of templateTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
placeholder="Choose template"
|
||||||
|
(selectionChange)="chooseTemplate($event)"
|
||||||
|
[(ngModel)]="selectedTemplate">
|
||||||
|
<mat-option *ngFor="let template of templates" [value]="template.name">
|
||||||
|
{{template.name}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<!-- <mat-table class="mat-table" #table [dataSource]="dataSource">
|
||||||
<ng-container matColumnDef="name">
|
<ng-container matColumnDef="name">
|
||||||
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
|
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row">
|
<mat-cell *matCellDef="let row">
|
||||||
<a (click)="addNode(row)" href="javascript:void(0);" class="table-link">{{ row.name }}</a>
|
<a (click)="addNode(row)" href="javascript:void(0);" class="table-link">{{ row.name }}</a>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||||
</mat-table>
|
</mat-table> -->
|
||||||
|
|
||||||
|
<div class="title-container">
|
||||||
|
<h6>Configuration</h6>
|
||||||
|
</div>
|
||||||
|
<form [formGroup]="configurationForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="name" placeholder="Enter name (default is taken from template)" />
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="numberOfNodes" placeholder="Enter number of nodes (default value is 1)" />
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="title-container">
|
||||||
|
<h6>Position</h6>
|
||||||
|
</div>
|
||||||
|
<form [formGroup]="positionForm">
|
||||||
|
Left:
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput formControlName="left"/>
|
||||||
|
</mat-form-field>
|
||||||
|
Top:
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput formControlName="top"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions align="end">
|
<div mat-dialog-actions align="end">
|
||||||
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">Close</button>
|
<button mat-button (click)="onNoClick()" tabindex="-1" color="accent">Close</button>
|
||||||
|
<button mat-button (click)="onAddClick()" tabindex="2" mat-raised-button color="primary">Add</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mat-table {
|
.mat-table {
|
||||||
overflow: auto;
|
height: 200px;
|
||||||
max-height: 400px;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
@ -17,11 +17,21 @@
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
scrollbar-color: darkgrey #263238;
|
scrollbar-color: darkgrey #263238;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #0097a7;
|
||||||
|
}
|
||||||
|
|
||||||
mat-table {
|
mat-table {
|
||||||
scrollbar-color: darkgrey #263238;
|
scrollbar-color: darkgrey #263238;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
@ -36,6 +46,17 @@ mat-table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background-color: darkgrey;
|
background-color: darkgrey;
|
||||||
outline: 1px solid #263238;
|
outline: 1px solid #263238;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterBox {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
|
|||||||
import { Server } from '../../../models/server';
|
import { Server } from '../../../models/server';
|
||||||
import { TemplateService } from '../../../services/template.service';
|
import { TemplateService } from '../../../services/template.service';
|
||||||
import { Template } from '../../../models/template';
|
import { Template } from '../../../models/template';
|
||||||
|
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-template-list-dialog',
|
selector: 'app-template-list-dialog',
|
||||||
@ -19,32 +20,51 @@ export class TemplateListDialogComponent implements OnInit {
|
|||||||
templateDatabase: TemplateDatabase;
|
templateDatabase: TemplateDatabase;
|
||||||
dataSource: TemplateDataSource;
|
dataSource: TemplateDataSource;
|
||||||
displayedColumns = ['name'];
|
displayedColumns = ['name'];
|
||||||
|
templateTypes: string[] = ['cloud', 'ethernet_hub', 'ethernet_switch', 'docker', 'dynamips', 'vpcs', 'traceng', 'virtualbox', 'vmware', 'iou', 'qemu'];
|
||||||
|
selectedType: string;
|
||||||
|
configurationForm: FormGroup;
|
||||||
|
positionForm: FormGroup;
|
||||||
|
templates: Template[];
|
||||||
|
searchText: string;
|
||||||
|
|
||||||
@ViewChild('filter', {static: true}) filter: ElementRef;
|
@ViewChild('filter', {static: true}) filter: ElementRef;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: MatDialogRef<TemplateListDialogComponent>,
|
public dialogRef: MatDialogRef<TemplateListDialogComponent>,
|
||||||
private templateService: TemplateService,
|
private templateService: TemplateService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any
|
@Inject(MAT_DIALOG_DATA) public data: any
|
||||||
) {
|
) {
|
||||||
this.server = data['server'];
|
this.server = data['server'];
|
||||||
|
this.configurationForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('new node', Validators.required),
|
||||||
|
numberOfNodes: new FormControl(1, Validators.required)
|
||||||
|
});
|
||||||
|
this.positionForm = this.formBuilder.group({
|
||||||
|
top: new FormControl(0, Validators.required),
|
||||||
|
left: new FormControl(0, Validators.required)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.templateDatabase = new TemplateDatabase(this.server, this.templateService);
|
// this.templateDatabase = new TemplateDatabase(this.server, this.templateService);
|
||||||
this.dataSource = new TemplateDataSource(this.templateDatabase);
|
// this.dataSource = new TemplateDataSource(this.templateDatabase);
|
||||||
|
|
||||||
fromEvent(this.filter.nativeElement, 'keyup')
|
this.templateService.list(this.server).subscribe((listOfTemplates: Template[]) => {
|
||||||
.pipe(
|
this.templates = listOfTemplates;
|
||||||
debounceTime(150),
|
|
||||||
distinctUntilChanged()
|
|
||||||
)
|
|
||||||
.subscribe(() => {
|
|
||||||
if (!this.dataSource) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.dataSource.filter = this.filter.nativeElement.value;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// fromEvent(this.filter.nativeElement, 'keyup')
|
||||||
|
// .pipe(
|
||||||
|
// debounceTime(150),
|
||||||
|
// distinctUntilChanged()
|
||||||
|
// )
|
||||||
|
// .subscribe(() => {
|
||||||
|
// if (!this.dataSource) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// this.dataSource.filter = this.filter.nativeElement.value;
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoClick(): void {
|
onNoClick(): void {
|
||||||
@ -54,6 +74,17 @@ export class TemplateListDialogComponent implements OnInit {
|
|||||||
addNode(template: Template): void {
|
addNode(template: Template): void {
|
||||||
this.dialogRef.close(template);
|
this.dialogRef.close(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterTemplates(event) {
|
||||||
|
console.log('filter event ', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseTemplate(event) {
|
||||||
|
console.log('choose event ', event);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddClick(): void {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TemplateDatabase {
|
export class TemplateDatabase {
|
||||||
|
@ -1 +1 @@
|
|||||||
<button matTooltip="Browse all devices" mat-icon-button (click)="listTemplatesModal()"><mat-icon>add_to_queue</mat-icon></button>
|
<button matTooltip="Add a node" mat-icon-button (click)="listTemplatesModal()"><mat-icon>add_to_queue</mat-icon></button>
|
||||||
|
@ -21,7 +21,6 @@ export class TemplateComponent implements OnInit {
|
|||||||
listTemplatesModal() {
|
listTemplatesModal() {
|
||||||
const dialogRef = this.dialog.open(TemplateListDialogComponent, {
|
const dialogRef = this.dialog.open(TemplateListDialogComponent, {
|
||||||
width: '600px',
|
width: '600px',
|
||||||
height: '560px',
|
|
||||||
data: {
|
data: {
|
||||||
server: this.server
|
server: this.server
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user