diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f6452a5a..38565b87 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -249,6 +249,7 @@ import { PageNotFoundComponent } from './components/page-not-found/page-not-foun import { AlignHorizontallyActionComponent } from './components/project-map/context-menu/actions/align-horizontally/align-horizontally.component'; import { AlignVerticallyActionComponent } from './components/project-map/context-menu/actions/align_vertically/align-vertically.component'; import { ConfirmationBottomSheetComponent } from './components/projects/confirmation-bottomsheet/confirmation-bottomsheet.component'; +import { TemplateFilter } from './filters/templateFilter.pipe'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -362,6 +363,7 @@ if (environment.production) { SearchFilter, DateFilter, NameFilter, + TemplateFilter, ProjectsFilter, ListOfSnapshotsComponent, CustomAdaptersComponent, diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 3ff59f03..28d3cee4 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -112,7 +112,7 @@ - + diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index b9ff6f07..1e6c39d0 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -63,6 +63,7 @@ import { EthernetLinkWidget } from '../../cartography/widgets/links/ethernet-lin import { SerialLinkWidget } from '../../cartography/widgets/links/serial-link'; import { NavigationDialogComponent } from '../projects/navigation-dialog/navigation-dialog.component'; import { ConfirmationBottomSheetComponent } from '../projects/confirmation-bottomsheet/confirmation-bottomsheet.component'; +import { NodeAddedEvent } from '../template/template-list-dialog/template-list-dialog.component'; @Component({ @@ -406,14 +407,13 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.subscriptions.push(onInterfaceLabelContextMenu); this.mapChangeDetectorRef.detectChanges(); } - - //here we should support adding multiple nodes on single click - onNodeCreation(template: Template) { - if(!template) { + + onNodeCreation(nodeAddedEvent: NodeAddedEvent) { + if(!nodeAddedEvent) { return; } - this.nodeService.createFromTemplate(this.server, this.project, template, 0, 0, 'local').subscribe(() => { + this.nodeService.createFromTemplate(this.server, this.project, nodeAddedEvent.template, nodeAddedEvent.x, nodeAddedEvent.y, 'local').subscribe(() => { this.projectService.nodes(this.server, this.project.project_id).subscribe((nodes: Node[]) => { nodes.filter((node) => node.label.style === null).forEach((node) => { diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.html b/src/app/components/template/template-list-dialog/template-list-dialog.component.html index 137c5a8d..1bf9d570 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.html +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.html @@ -7,7 +7,6 @@
Template
- - + {{template.name}} -
Configuration
diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.ts b/src/app/components/template/template-list-dialog/template-list-dialog.component.ts index 328be6f2..76283bd5 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.ts +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.ts @@ -1,14 +1,14 @@ import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; import { DataSource } from '@angular/cdk/collections'; - import { Observable, BehaviorSubject, fromEvent, merge } from 'rxjs'; import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; - import { Server } from '../../../models/server'; import { TemplateService } from '../../../services/template.service'; import { Template } from '../../../models/template'; import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms'; +import { ToasterService } from '../../../services/toaster.service'; +import { Project } from '../../../models/project'; @Component({ selector: 'app-template-list-dialog', @@ -17,25 +17,25 @@ import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms' }) export class TemplateListDialogComponent implements OnInit { server: Server; - templateDatabase: TemplateDatabase; - dataSource: TemplateDataSource; - displayedColumns = ['name']; + project: Project; 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; + filteredTemplates: Template[]; + selectedTemplate: Template; + searchText: string = ''; constructor( public dialogRef: MatDialogRef, private templateService: TemplateService, private formBuilder: FormBuilder, - @Inject(MAT_DIALOG_DATA) public data: any + @Inject(MAT_DIALOG_DATA) public data: any, + private toasterService: ToasterService ) { this.server = data['server']; + this.project = data['project']; this.configurationForm = this.formBuilder.group({ name: new FormControl('new node', Validators.required), numberOfNodes: new FormControl(1, Validators.required) @@ -47,46 +47,60 @@ export class TemplateListDialogComponent implements OnInit { } ngOnInit() { - // this.templateDatabase = new TemplateDatabase(this.server, this.templateService); - // this.dataSource = new TemplateDataSource(this.templateDatabase); - this.templateService.list(this.server).subscribe((listOfTemplates: Template[]) => { + this.filteredTemplates = listOfTemplates; this.templates = listOfTemplates; }); - - // fromEvent(this.filter.nativeElement, 'keyup') - // .pipe( - // debounceTime(150), - // distinctUntilChanged() - // ) - // .subscribe(() => { - // if (!this.dataSource) { - // return; - // } - // this.dataSource.filter = this.filter.nativeElement.value; - // }); } onNoClick(): void { this.dialogRef.close(); } - addNode(template: Template): void { - this.dialogRef.close(template); - } - filterTemplates(event) { - console.log('filter event ', event); + let temporaryTemplates = this.templates.filter( item => { + return item.name.toLowerCase().includes(this.searchText.toLowerCase()); + }); + this.filteredTemplates = temporaryTemplates.filter(t => t.template_type === event.value.toString()); } chooseTemplate(event) { - console.log('choose event ', event); + this.selectedTemplate = event.value; + this.configurationForm.controls['name'].setValue(this.selectedTemplate.default_name_format); } onAddClick(): void { + if (!this.selectedTemplate) { + this.toasterService.error('Please firstly choose template.'); + } else if (!this.positionForm.valid || !this.configurationForm.valid) { + this.toasterService.error('Please fill all required fields.'); + } else { + let x: number = this.positionForm.get('left').value; + let y: number = this.positionForm.get('top').value; + if (x>(this.project.scene_width/2) || x<-(this.project.scene_width/2) || y>(this.project.scene_height/2) || y<-(this.project.scene_height)) { + this.toasterService.error('Please set correct position values.') + } else { + let event: NodeAddedEvent = { + template: this.selectedTemplate, + name: this.configurationForm.get('name').value, + numberOfNodes: this.configurationForm.get('numberOfNodes').value, + x: x, + y: y + }; + this.dialogRef.close(event); + } + } } } +export interface NodeAddedEvent { + template: Template, + name: string, + numberOfNodes: number; + x: number; + y: number; +} + export class TemplateDatabase { dataChange: BehaviorSubject = new BehaviorSubject([]); diff --git a/src/app/components/template/template.component.ts b/src/app/components/template/template.component.ts index 8df8e513..8b833e40 100644 --- a/src/app/components/template/template.component.ts +++ b/src/app/components/template/template.component.ts @@ -1,9 +1,10 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { MatDialog } from '@angular/material'; -import { TemplateListDialogComponent } from './template-list-dialog/template-list-dialog.component'; +import { TemplateListDialogComponent, NodeAddedEvent } from './template-list-dialog/template-list-dialog.component'; import { Server } from '../../models/server'; import { Template } from '../../models/template'; +import { Project } from '../../models/project'; @Component({ selector: 'app-template', @@ -12,6 +13,7 @@ import { Template } from '../../models/template'; }) export class TemplateComponent implements OnInit { @Input() server: Server; + @Input() project: Project; @Output() onNodeCreation = new EventEmitter(); constructor(private dialog: MatDialog) {} @@ -22,14 +24,15 @@ export class TemplateComponent implements OnInit { const dialogRef = this.dialog.open(TemplateListDialogComponent, { width: '600px', data: { - server: this.server + server: this.server, + project: this.project }, autoFocus: false }); - dialogRef.afterClosed().subscribe((template: Template) => { - if (template !== null) { - this.onNodeCreation.emit(template); + dialogRef.afterClosed().subscribe((nodeAddedEvent: NodeAddedEvent) => { + if (nodeAddedEvent !== null) { + this.onNodeCreation.emit(nodeAddedEvent); } }); } diff --git a/src/app/filters/templateFilter.pipe.ts b/src/app/filters/templateFilter.pipe.ts new file mode 100644 index 00000000..7c1e30a1 --- /dev/null +++ b/src/app/filters/templateFilter.pipe.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { Template } from '../models/template'; + + +@Pipe({ + name: 'templatefilter' +}) +export class TemplateFilter implements PipeTransform { + transform(items: Template[], searchText: string): any[] { + if(!items) return []; + if(!searchText) return items; + + searchText = searchText.toLowerCase(); + return items.filter( item => { + return item.name.toLowerCase().includes(searchText); + }); + } +} diff --git a/src/app/models/template.ts b/src/app/models/template.ts index 1dc03032..9a6ef23d 100644 --- a/src/app/models/template.ts +++ b/src/app/models/template.ts @@ -7,4 +7,5 @@ export class Template { name: string; node_type: string; symbol: string; + template_type: string; }