mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-06-11 03:31:37 +00:00
Merge branch 'master' into fix-for-tests
This commit is contained in:
commit
9dfd58b14b
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gns3-web-ui",
|
"name": "gns3-web-ui",
|
||||||
"version": "2020.3.0-beta.1",
|
"version": "2020.3.0-beta.2",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "GNS3 Technology Inc.",
|
"name": "GNS3 Technology Inc.",
|
||||||
"email": "developers@gns3.com"
|
"email": "developers@gns3.com"
|
||||||
@ -51,10 +51,10 @@
|
|||||||
"@angular/platform-browser": "^10.0.2",
|
"@angular/platform-browser": "^10.0.2",
|
||||||
"@angular/platform-browser-dynamic": "^10.0.2",
|
"@angular/platform-browser-dynamic": "^10.0.2",
|
||||||
"@angular/router": "^10.0.2",
|
"@angular/router": "^10.0.2",
|
||||||
|
"@sentry/browser": "^5.18.0",
|
||||||
"@types/jest": "^26.0.3",
|
"@types/jest": "^26.0.3",
|
||||||
"@types/mocha": "^7.0.2",
|
"@types/mocha": "^7.0.2",
|
||||||
"angular-draggable-droppable": "^4.5.1",
|
"angular-draggable-droppable": "^4.5.1",
|
||||||
"@sentry/browser": "^5.18.0",
|
|
||||||
"angular-persistence": "^1.0.1",
|
"angular-persistence": "^1.0.1",
|
||||||
"angular-resizable-element": "^3.3.2",
|
"angular-resizable-element": "^3.3.2",
|
||||||
"angular2-draggable": "^2.3.2",
|
"angular2-draggable": "^2.3.2",
|
||||||
@ -79,6 +79,7 @@
|
|||||||
"rxjs-compat": "^6.5.5",
|
"rxjs-compat": "^6.5.5",
|
||||||
"save-html-as-image": "^1.3.3",
|
"save-html-as-image": "^1.3.3",
|
||||||
"save-svg-as-png": "^1.4.14",
|
"save-svg-as-png": "^1.4.14",
|
||||||
|
"snyk": "^1.361.3",
|
||||||
"svg-crowbar": "^0.6.0",
|
"svg-crowbar": "^0.6.0",
|
||||||
"tree-kill": "^1.2.1",
|
"tree-kill": "^1.2.1",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
@ -87,8 +88,7 @@
|
|||||||
"xterm-addon-attach": "^0.6.0",
|
"xterm-addon-attach": "^0.6.0",
|
||||||
"xterm-addon-fit": "^0.4.0",
|
"xterm-addon-fit": "^0.4.0",
|
||||||
"yargs": "^15.3.1",
|
"yargs": "^15.3.1",
|
||||||
"zone.js": "~0.10.3",
|
"zone.js": "~0.10.3"
|
||||||
"snyk": "^1.361.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "~0.1000.0",
|
"@angular-devkit/build-angular": "~0.1000.0",
|
||||||
|
@ -159,6 +159,10 @@ const routes: Routes = [
|
|||||||
path: 'server/:server_id/project/:project_id/nodes/:node_id',
|
path: 'server/:server_id/project/:project_id/nodes/:node_id',
|
||||||
component: WebConsoleFullWindowComponent
|
component: WebConsoleFullWindowComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'static/web-ui/server/:server_id/project/:project_id/nodes/:node_id',
|
||||||
|
component: WebConsoleFullWindowComponent
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '**',
|
path: '**',
|
||||||
component: PageNotFoundComponent
|
component: PageNotFoundComponent
|
||||||
|
@ -278,6 +278,7 @@ import { DataSourceFilter } from './filters/dataSourceFilter';
|
|||||||
import { ChangeHostnameActionComponent } from './components/project-map/context-menu/actions/change-hostname/change-hostname-action.component';
|
import { ChangeHostnameActionComponent } from './components/project-map/context-menu/actions/change-hostname/change-hostname-action.component';
|
||||||
import { ChangeHostnameDialogComponent } from './components/project-map/change-hostname-dialog/change-hostname-dialog.component';
|
import { ChangeHostnameDialogComponent } from './components/project-map/change-hostname-dialog/change-hostname-dialog.component';
|
||||||
import { ApplianceInfoDialogComponent } from './components/project-map/new-template-dialog/appliance-info-dialog/appliance-info-dialog.component';
|
import { ApplianceInfoDialogComponent } from './components/project-map/new-template-dialog/appliance-info-dialog/appliance-info-dialog.component';
|
||||||
|
import { InformationDialogComponent } from './components/dialogs/information-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -460,7 +461,8 @@ import { ApplianceInfoDialogComponent } from './components/project-map/new-templ
|
|||||||
NewTemplateDialogComponent,
|
NewTemplateDialogComponent,
|
||||||
ChangeHostnameActionComponent,
|
ChangeHostnameActionComponent,
|
||||||
ChangeHostnameDialogComponent,
|
ChangeHostnameDialogComponent,
|
||||||
ApplianceInfoDialogComponent
|
ApplianceInfoDialogComponent,
|
||||||
|
InformationDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -606,4 +608,6 @@ import { ApplianceInfoDialogComponent } from './components/project-map/new-templ
|
|||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {
|
||||||
|
constructor(protected _googleAnalyticsService: GoogleAnalyticsService) { }
|
||||||
|
}
|
||||||
|
@ -89,8 +89,14 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
@Input('show-interface-labels')
|
@Input('show-interface-labels')
|
||||||
set showInterfaceLabels(value) {
|
set showInterfaceLabels(value) {
|
||||||
this.settings.show_interface_labels = value;
|
if (value && !this.mapSettingsService.integrateLinkLabelsToLinks) {
|
||||||
this.interfaceLabelWidget.setEnabled(value);
|
this.settings.show_interface_labels = true;
|
||||||
|
this.interfaceLabelWidget.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
this.settings.show_interface_labels = false;
|
||||||
|
this.interfaceLabelWidget.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
this.mapChangeDetectorRef.detectChanges();
|
this.mapChangeDetectorRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ export class MapLink implements Indexed {
|
|||||||
target: MapNode; // this is not from server
|
target: MapNode; // this is not from server
|
||||||
|
|
||||||
isSelected = false; // this is not from server
|
isSelected = false; // this is not from server
|
||||||
|
isMultiplied = false; // this is not from server
|
||||||
x: number; // this is not from server
|
x: number; // this is not from server
|
||||||
y: number; // this is not from server
|
y: number; // this is not from server
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,22 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
|
|
||||||
public draw(view: SVGSelection) {
|
public draw(view: SVGSelection) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
let mapLinks: MapLink[] = [];
|
||||||
|
|
||||||
|
view.each(function(this: SVGGElement, l: MapLink) {
|
||||||
|
mapLinks.push(l);
|
||||||
|
});
|
||||||
|
mapLinks.forEach(mapLink => {
|
||||||
|
mapLinks.forEach(n => {
|
||||||
|
if (n.nodes[0].linkId !== mapLink.nodes[0].linkId){
|
||||||
|
if ((mapLink.nodes[0].nodeId === n.nodes[0].nodeId && mapLink.nodes[1].nodeId === n.nodes[1].nodeId) ||
|
||||||
|
(mapLink.nodes[0].nodeId === n.nodes[1].nodeId && mapLink.nodes[1].nodeId === n.nodes[0].nodeId) ||
|
||||||
|
(mapLink.nodes[1].nodeId === n.nodes[0].nodeId && mapLink.nodes[0].nodeId === n.nodes[1].nodeId)) {
|
||||||
|
mapLink.isMultiplied = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
view.each(function(this: SVGGElement, l: MapLink) {
|
view.each(function(this: SVGGElement, l: MapLink) {
|
||||||
const link_group = select<SVGGElement, MapLink>(this);
|
const link_group = select<SVGGElement, MapLink>(this);
|
||||||
@ -27,10 +43,10 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
|
|
||||||
let statuses = [];
|
let statuses = [];
|
||||||
if (link_path.node()) {
|
if (link_path.node()) {
|
||||||
const start_point: SVGPoint = link_path.node().getPointAtLength(100);
|
const start_point: SVGPoint = link_path.node().getPointAtLength(80);
|
||||||
const end_point: SVGPoint = link_path.node().getPointAtLength(link_path.node().getTotalLength() - 100);
|
const end_point: SVGPoint = link_path.node().getPointAtLength(link_path.node().getTotalLength() - 80);
|
||||||
|
|
||||||
if (link_path.node().getTotalLength() > 2 * 45 + 10) {
|
if (link_path.node().getTotalLength() > 2 * 45 + 130) {
|
||||||
if (l.source && l.target) {
|
if (l.source && l.target) {
|
||||||
let sourcePort = l.nodes.find(node => node.nodeId === l.source.id).label.text;
|
let sourcePort = l.nodes.find(node => node.nodeId === l.source.id).label.text;
|
||||||
let destinationPort = l.nodes.find(node => node.nodeId === l.target.id).label.text;
|
let destinationPort = l.nodes.find(node => node.nodeId === l.target.id).label.text;
|
||||||
@ -62,7 +78,7 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
link_group
|
link_group
|
||||||
.selectAll<SVGTextElement, LinkStatus>('text.status_suspended_label').remove();
|
.selectAll<SVGTextElement, LinkStatus>('text.status_suspended_label').remove();
|
||||||
|
|
||||||
if (self.mapSettingsService.integrateLinkLabelsToLinks) {
|
if (self.mapSettingsService.showInterfaceLabels && self.mapSettingsService.integrateLinkLabelsToLinks && !l.isMultiplied) {
|
||||||
const status_started = link_group
|
const status_started = link_group
|
||||||
.selectAll<SVGRectElement, LinkStatus>('rect.status_started')
|
.selectAll<SVGRectElement, LinkStatus>('rect.status_started')
|
||||||
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'started'));
|
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'started'));
|
||||||
@ -70,9 +86,11 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
status_started
|
status_started
|
||||||
.merge(status_started_enter)
|
.merge(status_started_enter)
|
||||||
.attr('class', 'status_started')
|
.attr('class', 'status_started')
|
||||||
.attr('width', 40)
|
.attr('width', (ls: LinkStatus) => {
|
||||||
|
return (ls.port.length * 8) + 10;
|
||||||
|
})
|
||||||
.attr('height', 20)
|
.attr('height', 20)
|
||||||
.attr('x', (ls: LinkStatus) => ls.x - 10)
|
.attr('x', (ls: LinkStatus) => ls.x - 30)
|
||||||
.attr('y', (ls: LinkStatus) => ls.y - 10)
|
.attr('y', (ls: LinkStatus) => ls.y - 10)
|
||||||
.attr('rx', 8)
|
.attr('rx', 8)
|
||||||
.attr('ry', 8)
|
.attr('ry', 8)
|
||||||
@ -88,7 +106,7 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
.merge(status_started_label_enter)
|
.merge(status_started_label_enter)
|
||||||
.attr('class', 'status_started_label')
|
.attr('class', 'status_started_label')
|
||||||
.text((ls: LinkStatus) => ls.port)
|
.text((ls: LinkStatus) => ls.port)
|
||||||
.attr('x', (ls: LinkStatus) => ls.x - 5)
|
.attr('x', (ls: LinkStatus) => ls.x - 25)
|
||||||
.attr('y', (ls: LinkStatus) => ls.y + 5)
|
.attr('y', (ls: LinkStatus) => ls.y + 5)
|
||||||
.attr('fill', `black`);
|
.attr('fill', `black`);
|
||||||
status_started_label.exit().remove();
|
status_started_label.exit().remove();
|
||||||
@ -100,9 +118,11 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
status_stopped
|
status_stopped
|
||||||
.merge(status_stopped_enter)
|
.merge(status_stopped_enter)
|
||||||
.attr('class', 'status_stopped')
|
.attr('class', 'status_stopped')
|
||||||
.attr('width', 40)
|
.attr('width', (ls: LinkStatus) => {
|
||||||
|
return (ls.port.length * 8) + 10;
|
||||||
|
})
|
||||||
.attr('height', 20)
|
.attr('height', 20)
|
||||||
.attr('x', (ls: LinkStatus) => ls.x - 10)
|
.attr('x', (ls: LinkStatus) => ls.x - 30)
|
||||||
.attr('y', (ls: LinkStatus) => ls.y - 10)
|
.attr('y', (ls: LinkStatus) => ls.y - 10)
|
||||||
.attr('rx', 8)
|
.attr('rx', 8)
|
||||||
.attr('ry', 8)
|
.attr('ry', 8)
|
||||||
@ -118,7 +138,7 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
.merge(status_stopped_label_enter)
|
.merge(status_stopped_label_enter)
|
||||||
.attr('class', 'status_stopped_label')
|
.attr('class', 'status_stopped_label')
|
||||||
.text((ls: LinkStatus) => ls.port)
|
.text((ls: LinkStatus) => ls.port)
|
||||||
.attr('x', (ls: LinkStatus) => ls.x - 5)
|
.attr('x', (ls: LinkStatus) => ls.x - 25)
|
||||||
.attr('y', (ls: LinkStatus) => ls.y + 5)
|
.attr('y', (ls: LinkStatus) => ls.y + 5)
|
||||||
.attr('fill', `black`);
|
.attr('fill', `black`);
|
||||||
status_stopped_label.exit().remove();
|
status_stopped_label.exit().remove();
|
||||||
@ -130,9 +150,11 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
status_suspended
|
status_suspended
|
||||||
.merge(status_suspended_enter)
|
.merge(status_suspended_enter)
|
||||||
.attr('class', 'status_suspended')
|
.attr('class', 'status_suspended')
|
||||||
.attr('width', 40)
|
.attr('width', (ls: LinkStatus) => {
|
||||||
|
return (ls.port.length * 8) + 10;
|
||||||
|
})
|
||||||
.attr('height', 20)
|
.attr('height', 20)
|
||||||
.attr('x', (ls: LinkStatus) => ls.x - 10)
|
.attr('x', (ls: LinkStatus) => ls.x - 30)
|
||||||
.attr('y', (ls: LinkStatus) => ls.y - 10)
|
.attr('y', (ls: LinkStatus) => ls.y - 10)
|
||||||
.attr('rx', 8)
|
.attr('rx', 8)
|
||||||
.attr('ry', 8)
|
.attr('ry', 8)
|
||||||
@ -148,7 +170,7 @@ export class InterfaceStatusWidget implements Widget {
|
|||||||
.merge(status_suspended_label_enter)
|
.merge(status_suspended_label_enter)
|
||||||
.attr('class', 'status_suspended_label')
|
.attr('class', 'status_suspended_label')
|
||||||
.text((ls: LinkStatus) => ls.port)
|
.text((ls: LinkStatus) => ls.port)
|
||||||
.attr('x', (ls: LinkStatus) => ls.x - 5)
|
.attr('x', (ls: LinkStatus) => ls.x - 25)
|
||||||
.attr('y', (ls: LinkStatus) => ls.y + 5)
|
.attr('y', (ls: LinkStatus) => ls.y + 5)
|
||||||
.attr('fill', `black`);
|
.attr('fill', `black`);
|
||||||
status_suspended_label.exit().remove();
|
status_suspended_label.exit().remove();
|
||||||
|
@ -66,6 +66,6 @@ export class SentryErrorHandler implements ErrorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Optionally show user dialog to provide details on what happened.
|
// Optionally show user dialog to provide details on what happened.
|
||||||
Sentry.showReportDialog({ eventId });
|
// Sentry.showReportDialog({ eventId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,10 @@ import { SentryErrorHandler } from './sentry-error-handler';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class ToasterErrorHandler extends SentryErrorHandler {
|
export class ToasterErrorHandler extends SentryErrorHandler {
|
||||||
handleError(err: any): void {
|
handleError(err: any): void {
|
||||||
super.handleError(err);
|
if (err.error && err.error.status && !(err.error.status === 403 || err.error.status === 404)) {
|
||||||
|
super.handleError(err);
|
||||||
|
}
|
||||||
|
|
||||||
if (!err) return;
|
if (!err) return;
|
||||||
|
|
||||||
const toasterService = this.injector.get(ToasterService);
|
const toasterService = this.injector.get(ToasterService);
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<div class="error-icon"><mat-icon>error_outline</mat-icon></div>
|
<div class="error-icon"><mat-icon>error_outline</mat-icon></div>
|
||||||
<div>Error occurred: {{ error.message }}</div>
|
<div>Error occurred: {{ error.message }}</div>
|
||||||
<div>
|
<div>
|
||||||
<button mat-button (click)="refresh()" matTooltip="Refresh page"><mat-icon>refresh</mat-icon></button>
|
<button mat-button (click)="refresh()" matTooltip="Refresh page" matTooltipClass="custom-tooltip"><mat-icon>refresh</mat-icon></button>
|
||||||
<button mat-button routerLink="/" matTooltip="Go to home"><mat-icon>home</mat-icon></button>
|
<button mat-button routerLink="/" matTooltip="Go to home" matTooltipClass="custom-tooltip"><mat-icon>home</mat-icon></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: #0097a7;
|
background-color: #0097a7;
|
||||||
margin-top: 10px;
|
margin-top: 2px;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -23,7 +23,7 @@ export class AdbutlerComponent implements OnInit {
|
|||||||
this.httpClient
|
this.httpClient
|
||||||
.get('https://servedbyadbutler.com/adserve/;ID=165803;size=0x0;setID=371476;type=json;').subscribe(
|
.get('https://servedbyadbutler.com/adserve/;ID=165803;size=0x0;setID=371476;type=json;').subscribe(
|
||||||
response => {
|
response => {
|
||||||
if (response && response['placements']) {
|
if (response && response['placements'] && response['placements'].placement_1 && response['placements'].placement_1.body) {
|
||||||
this.onLoad.emit(true);
|
this.onLoad.emit(true);
|
||||||
this.htmlCode = response['placements'].placement_1.body;
|
this.htmlCode = response['placements'].placement_1.body;
|
||||||
this.ad.nativeElement.insertAdjacentHTML('beforeend', this.htmlCode);
|
this.ad.nativeElement.insertAdjacentHTML('beforeend', this.htmlCode);
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<span>{{ confirmationMessage }}</span>
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button class="cancelButton" (click)="onNoClick()" color="accent">No</button>
|
||||||
|
<button mat-button class="confirmButton" (click)="onYesClick()" tabindex="2" mat-raised-button color="primary">
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
</div>
|
22
src/app/components/dialogs/information-dialog.component.ts
Normal file
22
src/app/components/dialogs/information-dialog.component.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-information-dialog',
|
||||||
|
templateUrl: 'information-dialog.component.html',
|
||||||
|
styleUrls: ['information-dialog.component.css']
|
||||||
|
})
|
||||||
|
export class InformationDialogComponent implements OnInit {
|
||||||
|
public confirmationMessage: string;
|
||||||
|
constructor(public dialogRef: MatDialogRef<InformationDialogComponent>) {}
|
||||||
|
|
||||||
|
ngOnInit() {}
|
||||||
|
|
||||||
|
onNoClick(): void {
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onYesClick(): void {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,9 @@ export class NotificationBoxComponent implements OnInit, OnDestroy {
|
|||||||
interval = 10;
|
interval = 10;
|
||||||
|
|
||||||
delayTime: number = 5000;
|
delayTime: number = 5000;
|
||||||
breakTime: number = 20;
|
breakTime: number = 20 * 60;
|
||||||
isEndless: boolean = false;
|
isEndless: boolean = true;
|
||||||
|
|
||||||
numberOfViews: number = 1;
|
numberOfViews: number = 1;
|
||||||
isLightThemeEnabled: boolean = false;
|
isLightThemeEnabled: boolean = false;
|
||||||
|
|
||||||
@ -41,7 +42,10 @@ export class NotificationBoxComponent implements OnInit, OnDestroy {
|
|||||||
let adbutler = localStorage.getItem('adbutler');
|
let adbutler = localStorage.getItem('adbutler');
|
||||||
var today = new Date().toISOString().substring(0, 10);
|
var today = new Date().toISOString().substring(0, 10);
|
||||||
|
|
||||||
if (!this.location.path().includes('nodes') && !(adbutler == today)) this.startTimer();
|
// to show ad once a day
|
||||||
|
// if (!this.location.path().includes('nodes') && !(adbutler == today)) this.startTimer();
|
||||||
|
|
||||||
|
if (!this.location.path().includes('nodes')) this.startTimer();
|
||||||
this.themeService.getActualTheme() === 'light' ? this.isLightThemeEnabled = true : this.isLightThemeEnabled = false;
|
this.themeService.getActualTheme() === 'light' ? this.isLightThemeEnabled = true : this.isLightThemeEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +65,9 @@ export class NotificationBoxComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
startTimer() {
|
startTimer() {
|
||||||
this.timer = timer(this.delayTime, 1000);
|
this.timer = timer(this.delayTime, 1000);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showNotification();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
this.timerSubscription = this.timer.subscribe(() => {
|
this.timerSubscription = this.timer.subscribe(() => {
|
||||||
this.ticks++;
|
this.ticks++;
|
||||||
@ -82,7 +89,7 @@ export class NotificationBoxComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showNotification() {
|
showNotification() {
|
||||||
localStorage.setItem('adbutler', new Date().toISOString().substring(0, 10));
|
// localStorage.setItem('adbutler', new Date().toISOString().substring(0, 10));
|
||||||
|
|
||||||
this.viewTimer = timer(0, 100);
|
this.viewTimer = timer(0, 100);
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element">
|
||||||
<button mat-icon-button matTooltip="Delete adapter" (click)="delete(element)">
|
<button mat-icon-button matTooltip="Delete adapter" matTooltipClass="custom-tooltip" (click)="delete(element)">
|
||||||
<mat-icon aria-label="Delete adapter">delete</mat-icon>
|
<mat-icon aria-label="Delete adapter">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -33,11 +33,9 @@ export class DeleteTemplateComponent {
|
|||||||
|
|
||||||
dialogRef.afterClosed().subscribe((answer: boolean) => {
|
dialogRef.afterClosed().subscribe((answer: boolean) => {
|
||||||
if (answer) {
|
if (answer) {
|
||||||
this.templateService.deleteTemplate(this.server, templateId).subscribe((answer: boolean) => {
|
this.templateService.deleteTemplate(this.server, templateId).subscribe((answer) => {
|
||||||
if(answer) {
|
this.deleteEvent.emit(templateId);
|
||||||
this.deleteEvent.emit(templateId);
|
this.toasterService.success(`Template ${templateName} deleted.`);
|
||||||
this.toasterService.success(`Template ${templateName} deleted.`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<ng-container matColumnDef="action">
|
<ng-container matColumnDef="action">
|
||||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element">
|
||||||
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
<button mat-icon-button matTooltip="Delete port" matTooltipClass="custom-tooltip" (click)="delete(element)">
|
||||||
<mat-icon aria-label="Delete port">delete</mat-icon>
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<ng-container matColumnDef="action">
|
<ng-container matColumnDef="action">
|
||||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element">
|
||||||
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
<button mat-icon-button matTooltip="Delete port" matTooltipClass="custom-tooltip" (click)="delete(element)">
|
||||||
<mat-icon aria-label="Delete port">delete</mat-icon>
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -146,7 +146,7 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
|||||||
|
|
||||||
addTemplate() {
|
addTemplate() {
|
||||||
if (!this.nameForm.invalid && !this.memoryForm.invalid && (this.selectedImage || this.chosenImage)) {
|
if (!this.nameForm.invalid && !this.memoryForm.invalid && (this.selectedImage || this.chosenImage)) {
|
||||||
this.qemuTemplate.ram = this.memoryForm.get("ramMemory").value;
|
this.qemuTemplate.ram = +this.memoryForm.get("ramMemory").value;
|
||||||
this.qemuTemplate.qemu_path = this.selectedBinary.path;
|
this.qemuTemplate.qemu_path = this.selectedBinary.path;
|
||||||
if (this.newImageSelected) {
|
if (this.newImageSelected) {
|
||||||
this.qemuTemplate.hda_disk_image = this.diskForm.get("fileName").value;
|
this.qemuTemplate.hda_disk_image = this.diskForm.get("fileName").value;
|
||||||
|
@ -29,6 +29,10 @@ export class ConsoleDeviceActionBrowserComponent {
|
|||||||
if (this.node.status !== "started") {
|
if (this.node.status !== "started") {
|
||||||
this.toasterService.error("This node must be started before a console can be opened");
|
this.toasterService.error("This node must be started before a console can be opened");
|
||||||
} else {
|
} else {
|
||||||
|
if (this.node.console_host === '0.0.0.0' || this.node.console_host === '0:0:0:0:0:0:0:0' || this.node.console_host === '::') {
|
||||||
|
this.node.console_host = this.server.host;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.node.console_type === "telnet") {
|
if (this.node.console_type === "telnet") {
|
||||||
location.assign(`gns3+telnet://${this.node.console_host}:${this.node.console}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`);
|
location.assign(`gns3+telnet://${this.node.console_host}:${this.node.console}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`);
|
||||||
} else if (this.node.console_type === "vnc") {
|
} else if (this.node.console_type === "vnc") {
|
||||||
|
@ -56,11 +56,11 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
|
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row" style="text-align: right">
|
<mat-cell *matCellDef="let row" style="text-align: right">
|
||||||
<button mat-icon-button matTooltip="Install" (click)="install(row)">
|
<button mat-icon-button matTooltip="Install" matTooltipClass="custom-tooltip" (click)="install(row)">
|
||||||
<mat-icon aria-label="Install">archive</mat-icon>
|
<mat-icon aria-label="Install">archive</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button mat-icon-button matTooltip="Show info" (click)="showInfo(row)">
|
<button mat-icon-button matTooltip="Show info" matTooltipClass="custom-tooltip" (click)="showInfo(row)">
|
||||||
<mat-icon aria-label="Show info">info</mat-icon>
|
<mat-icon aria-label="Show info">info</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
@ -113,17 +113,17 @@
|
|||||||
<mat-step *ngIf="applianceToInstall">
|
<mat-step *ngIf="applianceToInstall">
|
||||||
<ng-template matStepLabel>{{secondActionTitle}}</ng-template>
|
<ng-template matStepLabel>{{secondActionTitle}}</ng-template>
|
||||||
|
|
||||||
<mat-card [hidden]="applianceToInstall">
|
<mat-card [hidden]="!(!isLinuxPlatform && !isGns3VmAvailable && !applianceToInstall.dynamips)">
|
||||||
Please select appliance to install first
|
Please configure GNS3 VM to install selected appliance
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
||||||
<mat-card [hidden]="!applianceToInstall">
|
<mat-card [hidden]="!(isLinuxPlatform || isGns3VmAvailable || applianceToInstall.dynamips)">
|
||||||
<div *ngIf="applianceToInstall.qemu">
|
<div *ngIf="applianceToInstall.qemu">
|
||||||
<div>
|
<div>
|
||||||
Server type<br/>
|
Server type<br/>
|
||||||
<mat-radio-group class="radio-group">
|
<mat-radio-group class="radio-group">
|
||||||
<mat-radio-button [disabled]="true" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
<mat-radio-button [disabled]="!isLinuxPlatform" [checked]="!isGns3VmChosen" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
||||||
<mat-radio-button class="radio-button" value="2" checked (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
<mat-radio-button [disabled]="!isGns3VmAvailable" [checked]="isGns3VmChosen" class="radio-button" value="2" (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -139,30 +139,60 @@
|
|||||||
</mat-select>
|
</mat-select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Install required files
|
Install required files <br/>
|
||||||
<mat-list>
|
<div>
|
||||||
<mat-list-item *ngFor="let image of applianceToInstall.images">
|
<div *ngFor="let version of applianceToInstall.versions">
|
||||||
<div class="list-item">
|
<div class="list-item">
|
||||||
<div>
|
<span>{{applianceToInstall.name}} version {{version.name}}</span>
|
||||||
{{image.filename}}
|
|
||||||
|
<div>
|
||||||
|
<button class="button" mat-raised-button color="primary" (click)="createQemuTemplateFromVersion(version)">Create</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<span *ngIf="checkImage(image)"><mat-icon matTooltip="Ready to install">check</mat-icon></span>
|
<div class="list-item-inside" *ngIf="version.images.hda_disk_image">
|
||||||
<span *ngIf="!checkImage(image)"><mat-icon matTooltip="Missing">close</mat-icon></span>
|
<span>
|
||||||
<input
|
{{version.images.hda_disk_image}}
|
||||||
type="file"
|
</span>
|
||||||
class="non-visible"
|
|
||||||
#file2
|
<div>
|
||||||
(change)="importImage($event)"
|
<span *ngIf="checkImageFromVersion(version.images.hda_disk_image)"><mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon></span>
|
||||||
ng2FileSelect
|
<span *ngIf="!checkImageFromVersion(version.images.hda_disk_image)"><mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon></span>
|
||||||
[uploader]="uploaderImage"/>
|
|
||||||
<button class="button" mat-raised-button (click)="file2.click()">Import</button>
|
<input
|
||||||
<button class="button" mat-raised-button (click)="downloadImage(image)">Download</button>
|
type="file"
|
||||||
<button *ngIf="checkImage(image)" class="button" mat-raised-button color="primary" (click)="createQemuTemplate(image)">Create</button>
|
class="non-visible"
|
||||||
|
#file2
|
||||||
|
(change)="importImage($event)"
|
||||||
|
ng2FileSelect
|
||||||
|
[uploader]="uploaderImage"/>
|
||||||
|
<button class="button" mat-raised-button (click)="file2.click()">Import</button>
|
||||||
|
<button class="button" mat-raised-button (click)="downloadImageFromVersion(version.images.hda_disk_image)">Download</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</mat-list-item>
|
<div class="list-item-inside" *ngIf="version.images.hdb_disk_image">
|
||||||
</mat-list>
|
<span>
|
||||||
|
{{version.images.hdb_disk_image}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span *ngIf="checkImageFromVersion(version.images.hdb_disk_image)"><mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon></span>
|
||||||
|
<span *ngIf="!checkImageFromVersion(version.images.hdb_disk_image)"><mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon></span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
class="non-visible"
|
||||||
|
#file2
|
||||||
|
(change)="importImage($event)"
|
||||||
|
ng2FileSelect
|
||||||
|
[uploader]="uploaderImage"/>
|
||||||
|
<button class="button" mat-raised-button (click)="file2.click()">Import</button>
|
||||||
|
<button class="button" mat-raised-button (click)="downloadImageFromVersion(version.images.hdb_disk_image)">Download</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -170,8 +200,8 @@
|
|||||||
<div>
|
<div>
|
||||||
Server type<br/>
|
Server type<br/>
|
||||||
<mat-radio-group class="radio-group">
|
<mat-radio-group class="radio-group">
|
||||||
<mat-radio-button [disabled]="true" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
<mat-radio-button [disabled]="!isLinuxPlatform" [checked]="!isGns3VmChosen" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
||||||
<mat-radio-button class="radio-button" value="2" checked (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
<mat-radio-button [disabled]="!isGns3VmAvailable" [checked]="isGns3VmChosen" class="radio-button" value="2" (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<button mat-raised-button color="primary" (click)="createDockerTemplate()" class="create-button">Create docker template</button>
|
<button mat-raised-button color="primary" (click)="createDockerTemplate()" class="create-button">Create docker template</button>
|
||||||
@ -181,8 +211,8 @@
|
|||||||
<div>
|
<div>
|
||||||
Server type<br/>
|
Server type<br/>
|
||||||
<mat-radio-group class="radio-group">
|
<mat-radio-group class="radio-group">
|
||||||
<mat-radio-button [disabled]="true" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
<mat-radio-button [checked]="!isGns3VmChosen" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
||||||
<mat-radio-button class="radio-button" value="2" checked (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
<mat-radio-button [disabled]="!isGns3VmAvailable" [checked]="isGns3VmChosen" class="radio-button" value="2" (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -214,8 +244,8 @@
|
|||||||
<div>
|
<div>
|
||||||
Server type<br/>
|
Server type<br/>
|
||||||
<mat-radio-group class="radio-group">
|
<mat-radio-group class="radio-group">
|
||||||
<mat-radio-button [disabled]="true" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
<mat-radio-button [disabled]="!isLinuxPlatform" [checked]="!isGns3VmChosen" class="radio-button" value="1" (click)="setServerType('local')">Install the appliance locally</mat-radio-button>
|
||||||
<mat-radio-button class="radio-button" value="2" checked (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
<mat-radio-button [disabled]="!isGns3VmAvailable" [checked]="isGns3VmChosen" class="radio-button" value="2" (click)="setServerType('gns3 vm')">Install the appliance on the GNS3 VM</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -42,6 +42,15 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-inside {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 30px;
|
||||||
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
|
@ -9,7 +9,7 @@ import { Server } from '../../../models/server';
|
|||||||
import { Node } from '../../../cartography/models/node';
|
import { Node } from '../../../cartography/models/node';
|
||||||
import { Project } from '../../../models/project';
|
import { Project } from '../../../models/project';
|
||||||
import { ApplianceService } from '../../../services/appliances.service';
|
import { ApplianceService } from '../../../services/appliances.service';
|
||||||
import { Appliance, Image } from '../../../models/appliance';
|
import { Appliance, Image, Version } from '../../../models/appliance';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { FileUploader, FileItem, ParsedResponseHeaders } from 'ng2-file-upload';
|
import { FileUploader, FileItem, ParsedResponseHeaders } from 'ng2-file-upload';
|
||||||
import { ToasterService } from '../../../services/toaster.service';
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
@ -26,6 +26,8 @@ import { IouService } from '../../../services/iou.service';
|
|||||||
import { IouTemplate } from '../../../models/templates/iou-template';
|
import { IouTemplate } from '../../../models/templates/iou-template';
|
||||||
import { TemplateService } from '../../../services/template.service';
|
import { TemplateService } from '../../../services/template.service';
|
||||||
import { Template } from '../../../models/template';
|
import { Template } from '../../../models/template';
|
||||||
|
import { ComputeService } from '../../../services/compute.service';
|
||||||
|
import { InformationDialogComponent } from '../../../components/dialogs/information-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-new-template-dialog',
|
selector: 'app-new-template-dialog',
|
||||||
@ -56,7 +58,10 @@ export class NewTemplateDialogComponent implements OnInit {
|
|||||||
public applianceToInstall: Appliance;
|
public applianceToInstall: Appliance;
|
||||||
public selectedImages: any[];
|
public selectedImages: any[];
|
||||||
|
|
||||||
private isGns3VmChosen = true;
|
public isGns3VmAvailable = false;
|
||||||
|
public isLinuxPlatform = false;
|
||||||
|
|
||||||
|
private isGns3VmChosen = false;
|
||||||
private isLocalComputerChosen = false;
|
private isLocalComputerChosen = false;
|
||||||
|
|
||||||
public qemuBinaries: QemuBinary[] = [];
|
public qemuBinaries: QemuBinary[] = [];
|
||||||
@ -85,10 +90,21 @@ export class NewTemplateDialogComponent implements OnInit {
|
|||||||
private iosService: IosService,
|
private iosService: IosService,
|
||||||
private iouService: IouService,
|
private iouService: IouService,
|
||||||
private templateService: TemplateService,
|
private templateService: TemplateService,
|
||||||
public dialog: MatDialog
|
public dialog: MatDialog,
|
||||||
|
private computeService: ComputeService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.computeService.getComputes(this.server).subscribe((computes) => {
|
||||||
|
computes.forEach(compute => {
|
||||||
|
if (compute.compute_id === 'vm') {
|
||||||
|
this.isGns3VmAvailable = true;
|
||||||
|
this.isGns3VmChosen = true;
|
||||||
|
}
|
||||||
|
if (compute.capabilities.platform === 'linux') this.isLinuxPlatform = true;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
this.qemuService.getImages(this.server).subscribe((qemuImages) => {
|
this.qemuService.getImages(this.server).subscribe((qemuImages) => {
|
||||||
this.qemuImages = qemuImages;
|
this.qemuImages = qemuImages;
|
||||||
});
|
});
|
||||||
@ -289,8 +305,58 @@ export class NewTemplateDialogComponent implements OnInit {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkImageFromVersion(image: string): boolean {
|
||||||
|
if (this.applianceToInstall.qemu) {
|
||||||
|
if (this.qemuImages.filter(n => n.filename === image).length > 0) return true;
|
||||||
|
} else if (this.applianceToInstall.dynamips) {
|
||||||
|
if (this.iosImages.filter(n => n.filename === image).length > 0) return true;
|
||||||
|
} else if (this.applianceToInstall.iou) {
|
||||||
|
if (this.iouImages.filter(n => n.filename === image).length > 0) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkImages(version: Version): boolean {
|
||||||
|
if (this.checkImageFromVersion(version.images.hda_disk_image) && this.checkImageFromVersion(version.images.hdb_disk_image)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
openConfirmationDialog(message: string, link: string) {
|
||||||
|
const dialogRef = this.dialog.open(InformationDialogComponent, {
|
||||||
|
width: '400px',
|
||||||
|
height: '200px',
|
||||||
|
autoFocus: false,
|
||||||
|
disableClose: true
|
||||||
|
});
|
||||||
|
dialogRef.componentInstance.confirmationMessage = message;
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((answer: boolean) => {
|
||||||
|
if (answer) {
|
||||||
|
window.open(link);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
downloadImage(image: Image) {
|
downloadImage(image: Image) {
|
||||||
window.open(image.download_url);
|
const directDownloadMessage: string = "Download will redirect you where the required file can be downloaded, you may have to be registered with the vendor in order to download the file.";
|
||||||
|
const compressionMessage: string = `The file is compressed with ${image.compression}, it must be uncompressed first.`;
|
||||||
|
|
||||||
|
if (image.direct_download_url) {
|
||||||
|
if (image.compression) {
|
||||||
|
this.openConfirmationDialog(compressionMessage, image.direct_download_url);
|
||||||
|
} else {
|
||||||
|
window.open(image.direct_download_url);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.openConfirmationDialog(directDownloadMessage, image.download_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadImageFromVersion(image: string) {
|
||||||
|
this.applianceToInstall.images.forEach(n => {
|
||||||
|
if (n.filename === image) this.downloadImage(n);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createIouTemplate (image: Image) {
|
createIouTemplate (image: Image) {
|
||||||
@ -370,7 +436,12 @@ export class NewTemplateDialogComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createQemuTemplate(image: Image) {
|
createQemuTemplateFromVersion(version: Version) {
|
||||||
|
if (!this.checkImages(version)) {
|
||||||
|
this.toasterService.error('Please install required images first');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.selectedBinary) {
|
if (!this.selectedBinary) {
|
||||||
this.toasterService.error('Please select QEMU binary first');
|
this.toasterService.error('Please select QEMU binary first');
|
||||||
return;
|
return;
|
||||||
@ -383,6 +454,9 @@ export class NewTemplateDialogComponent implements OnInit {
|
|||||||
qemuTemplate.boot_priority = this.applianceToInstall.qemu.boot_priority;
|
qemuTemplate.boot_priority = this.applianceToInstall.qemu.boot_priority;
|
||||||
qemuTemplate.console_type = this.applianceToInstall.qemu.console_type;
|
qemuTemplate.console_type = this.applianceToInstall.qemu.console_type;
|
||||||
qemuTemplate.hda_disk_interface = this.applianceToInstall.qemu.hda_disk_interface;
|
qemuTemplate.hda_disk_interface = this.applianceToInstall.qemu.hda_disk_interface;
|
||||||
|
qemuTemplate.hdb_disk_interface = this.applianceToInstall.qemu.hdb_disk_interface;
|
||||||
|
qemuTemplate.hdc_disk_interface = this.applianceToInstall.qemu.hdc_disk_interface;
|
||||||
|
qemuTemplate.hdd_disk_interface = this.applianceToInstall.qemu.hdd_disk_interface;
|
||||||
qemuTemplate.builtin = this.applianceToInstall.builtin;
|
qemuTemplate.builtin = this.applianceToInstall.builtin;
|
||||||
qemuTemplate.category = this.applianceToInstall.category;
|
qemuTemplate.category = this.applianceToInstall.category;
|
||||||
qemuTemplate.first_port_name = this.applianceToInstall.first_port_name;
|
qemuTemplate.first_port_name = this.applianceToInstall.first_port_name;
|
||||||
@ -391,8 +465,10 @@ export class NewTemplateDialogComponent implements OnInit {
|
|||||||
qemuTemplate.qemu_path = this.selectedBinary.path;
|
qemuTemplate.qemu_path = this.selectedBinary.path;
|
||||||
qemuTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local';
|
qemuTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local';
|
||||||
qemuTemplate.template_id = uuid();
|
qemuTemplate.template_id = uuid();
|
||||||
qemuTemplate.hda_disk_image = image.filename;
|
qemuTemplate.hda_disk_image = version.images.hda_disk_image;
|
||||||
|
qemuTemplate.hdb_disk_image = version.images.hdb_disk_image;
|
||||||
qemuTemplate.template_type = 'qemu';
|
qemuTemplate.template_type = 'qemu';
|
||||||
|
qemuTemplate.usage = this.applianceToInstall.usage;
|
||||||
|
|
||||||
this.qemuService.addTemplate(this.server, qemuTemplate).subscribe((template) => {
|
this.qemuService.addTemplate(this.server, qemuTemplate).subscribe((template) => {
|
||||||
this.templateService.newTemplateCreated.next(template as any as Template);
|
this.templateService.newTemplateCreated.next(template as any as Template);
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element">
|
||||||
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
<button mat-icon-button matTooltip="Delete port" matTooltipClass="custom-tooltip" (click)="delete(element)">
|
||||||
<mat-icon aria-label="Delete port">delete</mat-icon>
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element">
|
||||||
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
<button mat-icon-button matTooltip="Delete port" matTooltipClass="custom-tooltip" (click)="delete(element)">
|
||||||
<mat-icon aria-label="Delete port">delete</mat-icon>
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<button
|
<button
|
||||||
matTooltip="Console connect to all nodes"
|
matTooltip="Console connect to all nodes"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
(click)="startConsoleForAllNodes()"
|
(click)="startConsoleForAllNodes()"
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
@ -8,6 +9,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Start/Resume all nodes"
|
matTooltip="Start/Resume all nodes"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
(click)="startNodes()"
|
(click)="startNodes()"
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
@ -16,6 +18,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Suspend all nodes"
|
matTooltip="Suspend all nodes"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
(click)="suspendNodes()"
|
(click)="suspendNodes()"
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
@ -24,6 +27,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Stop all nodes"
|
matTooltip="Stop all nodes"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
(click)="stopNodes()"
|
(click)="stopNodes()"
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
@ -32,6 +36,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Reload all nodes"
|
matTooltip="Reload all nodes"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
(click)="reloadNodes()"
|
(click)="reloadNodes()"
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<button
|
<button
|
||||||
matTooltip="Add a note"
|
matTooltip="Add a note"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
(click)="addDrawing('text')">
|
(click)="addDrawing('text')">
|
||||||
@ -13,6 +14,7 @@
|
|||||||
(change)="uploadImageFile($event)"/>
|
(change)="uploadImageFile($event)"/>
|
||||||
<button
|
<button
|
||||||
matTooltip="Insert a picture"
|
matTooltip="Insert a picture"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
(click)="file.click()">
|
(click)="file.click()">
|
||||||
@ -20,6 +22,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Draw a rectangle"
|
matTooltip="Draw a rectangle"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
(click)="addDrawing('rectangle')">
|
(click)="addDrawing('rectangle')">
|
||||||
@ -27,6 +30,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Draw an ellipse"
|
matTooltip="Draw an ellipse"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
(click)="addDrawing('ellipse')">
|
(click)="addDrawing('ellipse')">
|
||||||
@ -34,6 +38,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button *ngIf="!isLightThemeEnabled"
|
<button *ngIf="!isLightThemeEnabled"
|
||||||
matTooltip="Draw a line"
|
matTooltip="Draw a line"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button class="menu-button"
|
mat-icon-button class="menu-button"
|
||||||
(click)="addDrawing('line')">
|
(click)="addDrawing('line')">
|
||||||
<svg height="40" width="40">
|
<svg height="40" width="40">
|
||||||
@ -48,6 +53,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button *ngIf="isLightThemeEnabled"
|
<button *ngIf="isLightThemeEnabled"
|
||||||
matTooltip="Draw a line"
|
matTooltip="Draw a line"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button class="menu-button"
|
mat-icon-button class="menu-button"
|
||||||
(click)="addDrawing('line')">
|
(click)="addDrawing('line')">
|
||||||
<svg height="40" width="40">
|
<svg height="40" width="40">
|
||||||
@ -62,6 +68,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Lock or unlock all items"
|
matTooltip="Lock or unlock all items"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
(click)="changeLockValue()">
|
(click)="changeLockValue()">
|
||||||
@ -69,6 +76,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
matTooltip="Take a screenshot"
|
matTooltip="Take a screenshot"
|
||||||
|
matTooltipClass="custom-tooltip"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
class="menu-button"
|
class="menu-button"
|
||||||
(click)="takeScreenshot()"
|
(click)="takeScreenshot()"
|
||||||
|
@ -35,11 +35,11 @@
|
|||||||
<div *ngIf="toolbarVisibility" class="project-toolbar">
|
<div *ngIf="toolbarVisibility" class="project-toolbar">
|
||||||
<mat-toolbar color="primary" class="project-toolbar" [ngClass]="{lightTheme: isLightThemeEnabled}">
|
<mat-toolbar color="primary" class="project-toolbar" [ngClass]="{lightTheme: isLightThemeEnabled}">
|
||||||
<mat-toolbar-row *ngIf="!isLightThemeEnabled">
|
<mat-toolbar-row *ngIf="!isLightThemeEnabled">
|
||||||
<button matTooltip="Open menu" mat-icon-button [matMenuTriggerFor]="mainMenu"><mat-icon svgIcon="gns3"></mat-icon></button>
|
<button matTooltip="Open menu" matTooltipClass="custom-tooltip" mat-icon-button [matMenuTriggerFor]="mainMenu"><mat-icon svgIcon="gns3"></mat-icon></button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="isLightThemeEnabled">
|
<mat-toolbar-row *ngIf="isLightThemeEnabled">
|
||||||
<button matTooltip="Open menu" mat-icon-button [matMenuTriggerFor]="mainMenu"><mat-icon svgIcon="gns3black"></mat-icon></button>
|
<button matTooltip="Open menu" matTooltipClass="custom-tooltip" mat-icon-button [matMenuTriggerFor]="mainMenu"><mat-icon svgIcon="gns3black"></mat-icon></button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-menu #mainMenu="matMenu" [overlapTrigger]="false">
|
<mat-menu #mainMenu="matMenu" [overlapTrigger]="false">
|
||||||
@ -109,11 +109,8 @@
|
|||||||
|
|
||||||
<mat-menu #viewMenu="matMenu" [overlapTrigger]="false">
|
<mat-menu #viewMenu="matMenu" [overlapTrigger]="false">
|
||||||
<div class="options-item">
|
<div class="options-item">
|
||||||
<mat-checkbox [ngModel]="mapSettingsService.integrateLinkLabelsToLinks" (change)="toggleIntegrateLinkLabelsToLinks($event.checked)">
|
|
||||||
Integrate link labels to links
|
|
||||||
</mat-checkbox>
|
|
||||||
<mat-checkbox [ngModel]="isInterfaceLabelVisible" (change)="toggleShowInterfaceLabels($event.checked)">
|
<mat-checkbox [ngModel]="isInterfaceLabelVisible" (change)="toggleShowInterfaceLabels($event.checked)">
|
||||||
Show interface labels separately
|
Show interface labels
|
||||||
</mat-checkbox><br/>
|
</mat-checkbox><br/>
|
||||||
<mat-checkbox [ngModel]="isConsoleVisible" (change)="toggleShowConsole($event.checked)">
|
<mat-checkbox [ngModel]="isConsoleVisible" (change)="toggleShowConsole($event.checked)">
|
||||||
Show console
|
Show console
|
||||||
@ -141,13 +138,13 @@
|
|||||||
</mat-toolbar-row>
|
</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" matTooltipClass="custom-tooltip" mat-icon-button [color]="tools.draw_link ? 'primary' : 'basic'" (click)="toggleDrawLineMode()">
|
||||||
<mat-icon>timeline</mat-icon>
|
<mat-icon>timeline</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row>
|
<mat-toolbar-row>
|
||||||
<button matTooltip="Enable/disable moving mode" mat-icon-button [color]="tools.moving ? 'primary' : 'basic'" (click)="toggleMovingMode()">
|
<button matTooltip="Enable/disable moving mode" matTooltipClass="custom-tooltip" mat-icon-button [color]="tools.moving ? 'primary' : 'basic'" (click)="toggleMovingMode()">
|
||||||
<mat-icon>zoom_out_map</mat-icon>
|
<mat-icon>zoom_out_map</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
@ -157,13 +154,13 @@
|
|||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
<button matTooltip="Fit in view" mat-icon-button (click)="fitInView()">
|
<button matTooltip="Fit in view" matTooltipClass="custom-tooltip" mat-icon-button (click)="fitInView()">
|
||||||
<mat-icon>fullscreen</mat-icon>
|
<mat-icon>fullscreen</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
|
|
||||||
<mat-toolbar-row *ngIf="!readonly">
|
<mat-toolbar-row *ngIf="!readonly">
|
||||||
<button matTooltip="Center view" mat-icon-button (click)="centerView()">
|
<button matTooltip="Center view" matTooltipClass="custom-tooltip" mat-icon-button (click)="centerView()">
|
||||||
<mat-icon>center_focus_strong</mat-icon>
|
<mat-icon>center_focus_strong</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
@ -185,9 +182,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-buttons">
|
<div [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-buttons">
|
||||||
<button matTooltip="Zoom in" [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-button" (click)="zoomIn()"><mat-icon>zoom_in</mat-icon></button>
|
<button matTooltip="Zoom in" matTooltipClass="custom-tooltip" [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-button" (click)="zoomIn()"><mat-icon>zoom_in</mat-icon></button>
|
||||||
<button matTooltip="Reset zoom" [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-button" (click)="resetZoom()"><mat-icon>adjust</mat-icon></button>
|
<button matTooltip="Reset zoom" matTooltipClass="custom-tooltip" [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-button" (click)="resetZoom()"><mat-icon>adjust</mat-icon></button>
|
||||||
<button matTooltip="Zoom out" [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-button" (click)="zoomOut()"><mat-icon>zoom_out</mat-icon></button>
|
<button matTooltip="Zoom out" matTooltipClass="custom-tooltip" [ngClass]="{lightTheme: isLightThemeEnabled}" class="zoom-button" (click)="zoomOut()"><mat-icon>zoom_out</mat-icon></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-progress></app-progress>
|
<app-progress></app-progress>
|
||||||
|
@ -258,12 +258,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.projectService.open(this.server, this.project.project_id);
|
this.projectService.open(this.server, this.project.project_id);
|
||||||
this.title.setTitle(this.project.name);
|
this.title.setTitle(this.project.name);
|
||||||
|
|
||||||
// old settings
|
this.isInterfaceLabelVisible = this.mapSettingsService.showInterfaceLabels;
|
||||||
// if (this.mapSettingsService.interfaceLabels.has(project.project_id)) {
|
|
||||||
// this.isInterfaceLabelVisible = this.mapSettingsService.interfaceLabels.get(project.project_id);
|
|
||||||
// } else {
|
|
||||||
// this.isInterfaceLabelVisible = this.project.show_interface_labels;
|
|
||||||
// }
|
|
||||||
|
|
||||||
this.recentlyOpenedProjectService.setServerId(this.server.id.toString());
|
this.recentlyOpenedProjectService.setServerId(this.server.id.toString());
|
||||||
this.recentlyOpenedProjectService.setProjectId(this.project.project_id);
|
this.recentlyOpenedProjectService.setProjectId(this.project.project_id);
|
||||||
@ -481,6 +476,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.progressService.deactivate();
|
this.progressService.deactivate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
this.toasterService.error(error.error.message);
|
||||||
|
this.progressService.deactivate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,17 +674,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
public toggleShowInterfaceLabels(enabled: boolean) {
|
public toggleShowInterfaceLabels(enabled: boolean) {
|
||||||
this.isInterfaceLabelVisible = enabled;
|
this.isInterfaceLabelVisible = enabled;
|
||||||
this.mapSettingsService.toggleShowInterfaceLabels(this.project.project_id, this.isInterfaceLabelVisible);
|
this.mapSettingsService.toggleShowInterfaceLabels(this.isInterfaceLabelVisible);
|
||||||
|
|
||||||
this.mapSettingsService.integrateLinkLabelsToLinks = false;
|
|
||||||
this.mapSettingsService.mapRenderedEmitter.emit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleIntegrateLinkLabelsToLinks(enabled: boolean) {
|
|
||||||
this.isInterfaceLabelVisible = false;
|
|
||||||
this.mapSettingsService.toggleShowInterfaceLabels(this.project.project_id, this.isInterfaceLabelVisible);
|
|
||||||
|
|
||||||
this.mapSettingsService.integrateLinkLabelsToLinks = enabled;
|
|
||||||
this.mapSettingsService.mapRenderedEmitter.emit(true);
|
this.mapSettingsService.mapRenderedEmitter.emit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,7 +880,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
public addNewTemplate() {
|
public addNewTemplate() {
|
||||||
const dialogRef = this.dialog.open(NewTemplateDialogComponent, {
|
const dialogRef = this.dialog.open(NewTemplateDialogComponent, {
|
||||||
width: '1000px',
|
width: '1000px',
|
||||||
maxHeight: '500px',
|
maxHeight: '700px',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
disableClose: true
|
disableClose: true
|
||||||
});
|
});
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element">
|
||||||
<button mat-icon-button matTooltip="Delete variable" (click)="deleteVariable(element)">
|
<button mat-icon-button matTooltip="Delete variable" matTooltipClass="custom-tooltip" (click)="deleteVariable(element)">
|
||||||
<mat-icon aria-label="Delete adapter">delete</mat-icon>
|
<mat-icon aria-label="Delete adapter">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
ng2FileSelect
|
ng2FileSelect
|
||||||
[uploader]="uploader"
|
[uploader]="uploader"
|
||||||
/>
|
/>
|
||||||
<button mat-raised-button color="primary" (click)="file.click()" matTooltip="Import your .gns3p or .gns3project file" class="file-button">Choose file</button>
|
<button mat-raised-button color="primary" (click)="file.click()" matTooltip="Import your .gns3p or .gns3project file" matTooltipClass="custom-tooltip" class="file-button">Choose file</button>
|
||||||
<mat-form-field [ngClass]="{ empty: !isDeleteVisible }" class="file-name-form-field">
|
<mat-form-field [ngClass]="{ empty: !isDeleteVisible }" class="file-name-form-field">
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
|
@ -53,16 +53,16 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
|
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row" style="text-align: right">
|
<mat-cell *matCellDef="let row" style="text-align: right">
|
||||||
<button mat-icon-button matTooltip="Open project" (click)="open(row)" *ngIf="row.status == 'closed'">
|
<button mat-icon-button matTooltip="Open project" matTooltipClass="custom-tooltip" (click)="open(row)" *ngIf="row.status == 'closed'">
|
||||||
<mat-icon aria-label="Open project">play_arrow</mat-icon>
|
<mat-icon aria-label="Open project">play_arrow</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button matTooltip="Close project" (click)="close(row)" *ngIf="row.status == 'opened'">
|
<button mat-icon-button matTooltip="Close project" matTooltipClass="custom-tooltip" (click)="close(row)" *ngIf="row.status == 'opened'">
|
||||||
<mat-icon aria-label="Close project">pause</mat-icon>
|
<mat-icon aria-label="Close project">pause</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button matTooltip="Duplicate project" (click)="duplicate(row)" *ngIf="row.status == 'closed'">
|
<button mat-icon-button matTooltip="Duplicate project" matTooltipClass="custom-tooltip" (click)="duplicate(row)" *ngIf="row.status == 'closed'">
|
||||||
<mat-icon aria-label="Duplicate project">filter_2</mat-icon>
|
<mat-icon aria-label="Duplicate project">filter_2</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button matTooltip="Delete project" (click)="delete(row)" *ngIf="row.status == 'closed'">
|
<button mat-icon-button matTooltip="Delete project" matTooltipClass="custom-tooltip" (click)="delete(row)" *ngIf="row.status == 'closed'">
|
||||||
<mat-icon aria-label="Delete project">delete</mat-icon>
|
<mat-icon aria-label="Delete project">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
|
@ -10,9 +10,8 @@
|
|||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<mat-checkbox [(ngModel)]="settings.crash_reports"
|
<mat-checkbox [(ngModel)]="settings.crash_reports">Send anonymous crash reports</mat-checkbox><br/>
|
||||||
>Send anonymous crash reports</mat-checkbox
|
<mat-checkbox [(ngModel)]="integrateLinksLabelsToLinks">Integrate link labels to links</mat-checkbox>
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
|
@ -3,6 +3,7 @@ import { SettingsService } from '../../services/settings.service';
|
|||||||
import { ToasterService } from '../../services/toaster.service';
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
import { ConsoleService } from '../../services/settings/console.service';
|
import { ConsoleService } from '../../services/settings/console.service';
|
||||||
import { ThemeService } from '../../services/theme.service';
|
import { ThemeService } from '../../services/theme.service';
|
||||||
|
import { MapSettingsService } from '../../services/mapsettings.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
@ -12,22 +13,26 @@ import { ThemeService } from '../../services/theme.service';
|
|||||||
export class SettingsComponent implements OnInit {
|
export class SettingsComponent implements OnInit {
|
||||||
settings = { ...SettingsService.DEFAULTS };
|
settings = { ...SettingsService.DEFAULTS };
|
||||||
consoleCommand: string;
|
consoleCommand: string;
|
||||||
|
integrateLinksLabelsToLinks: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
private toaster: ToasterService,
|
private toaster: ToasterService,
|
||||||
private consoleService: ConsoleService,
|
private consoleService: ConsoleService,
|
||||||
private themeService: ThemeService
|
private themeService: ThemeService,
|
||||||
|
public mapSettingsService: MapSettingsService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.settings = this.settingsService.getAll();
|
this.settings = this.settingsService.getAll();
|
||||||
this.consoleCommand = this.consoleService.command;
|
this.consoleCommand = this.consoleService.command;
|
||||||
|
this.integrateLinksLabelsToLinks = this.mapSettingsService.integrateLinkLabelsToLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.settingsService.setAll(this.settings);
|
this.settingsService.setAll(this.settings);
|
||||||
this.toaster.success('Settings have been saved.');
|
this.toaster.success('Settings have been saved.');
|
||||||
|
this.mapSettingsService.toggleIntegrateInterfaceLabels(this.integrateLinksLabelsToLinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
setDarkMode(value: boolean) {
|
setDarkMode(value: boolean) {
|
||||||
|
@ -28,11 +28,11 @@
|
|||||||
<ng-container matColumnDef="actions">
|
<ng-container matColumnDef="actions">
|
||||||
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
|
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row" style="text-align: right">
|
<mat-cell *matCellDef="let row" style="text-align: right">
|
||||||
<button mat-icon-button matTooltip="Restore snapshot" (click)="restoreSnapshot(row)">
|
<button mat-icon-button matTooltip="Restore snapshot" matTooltipClass="custom-tooltip" (click)="restoreSnapshot(row)">
|
||||||
<mat-icon aria-label="Restore snapshot">restore</mat-icon>
|
<mat-icon aria-label="Restore snapshot">restore</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button mat-icon-button matTooltip="Delete snapshot" (click)="deleteSnapshot(row)">
|
<button mat-icon-button matTooltip="Delete snapshot" matTooltipClass="custom-tooltip" (click)="deleteSnapshot(row)">
|
||||||
<mat-icon aria-label="Delete snapshot">delete</mat-icon>
|
<mat-icon aria-label="Delete snapshot">delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
|
@ -1 +1 @@
|
|||||||
<button matTooltip="Manage snapshots" mat-icon-button (click)="createSnapshotModal()"><mat-icon>snooze</mat-icon></button>
|
<button matTooltip="Manage snapshots" matTooltipClass="custom-tooltip" mat-icon-button (click)="createSnapshotModal()"><mat-icon>snooze</mat-icon></button>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<button class="addNode" matTooltip="Add a node" mat-icon-button [matMenuTriggerFor]="mainMenu">
|
<button class="addNode" matTooltip="Add a node" matTooltipClass="custom-tooltip" mat-icon-button [matMenuTriggerFor]="mainMenu">
|
||||||
<mat-icon>add_to_queue</mat-icon>
|
<mat-icon>add_to_queue</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ export class TopologySummaryComponent implements OnInit, OnDestroy {
|
|||||||
this.nodesDataSource.changes.subscribe((nodes: Node[]) => {
|
this.nodesDataSource.changes.subscribe((nodes: Node[]) => {
|
||||||
this.nodes = nodes;
|
this.nodes = nodes;
|
||||||
this.nodes.forEach(n => {
|
this.nodes.forEach(n => {
|
||||||
if (n.console_host === '0.0.0.0') {
|
if (n.console_host === '0.0.0.0' || n.console_host === '0:0:0:0:0:0:0:0' || n.console_host === '::') {
|
||||||
n.console_host = this.server.host;
|
n.console_host = this.server.host;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
export interface Image {
|
export interface Image {
|
||||||
|
compression? : string;
|
||||||
|
direct_download_url? : string;
|
||||||
download_url: string;
|
download_url: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
filesize: any;
|
filesize: any;
|
||||||
@ -13,6 +15,9 @@ export interface Qemu {
|
|||||||
boot_priority: string;
|
boot_priority: string;
|
||||||
console_type: string;
|
console_type: string;
|
||||||
hda_disk_interface: string;
|
hda_disk_interface: string;
|
||||||
|
hdb_disk_interface: string;
|
||||||
|
hdc_disk_interface: string;
|
||||||
|
hdd_disk_interface: string;
|
||||||
kvm: string;
|
kvm: string;
|
||||||
ram: number;
|
ram: number;
|
||||||
}
|
}
|
||||||
@ -49,6 +54,7 @@ export interface Iou {
|
|||||||
|
|
||||||
export interface Images {
|
export interface Images {
|
||||||
hda_disk_image: string;
|
hda_disk_image: string;
|
||||||
|
hdb_disk_image: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Version {
|
export interface Version {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {Router, NavigationEnd} from '@angular/router';
|
import {Router, NavigationEnd} from '@angular/router';
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
declare var ga:Function;
|
declare var gtag:Function;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GoogleAnalyticsService {
|
export class GoogleAnalyticsService {
|
||||||
@ -11,8 +11,8 @@ export class GoogleAnalyticsService {
|
|||||||
if (!environment.production) return;
|
if (!environment.production) return;
|
||||||
router.events.subscribe(event => {
|
router.events.subscribe(event => {
|
||||||
if (event instanceof NavigationEnd) {
|
if (event instanceof NavigationEnd) {
|
||||||
ga('set', 'page', event.url);
|
gtag('set', 'page', event.url);
|
||||||
ga('send', 'pageview');
|
gtag('send', 'pageview');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,8 @@ export class LinkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateLink(server: Server, link: Link) {
|
updateLink(server: Server, link: Link) {
|
||||||
// link.x = Math.round(link.x);
|
link.x = Math.round(link.x);
|
||||||
// link.y = Math.round(link.y);
|
link.y = Math.round(link.y);
|
||||||
|
|
||||||
return this.httpServer.put<Link>(server, `/projects/${link.project_id}/links/${link.link_id}`, link);
|
return this.httpServer.put<Link>(server, `/projects/${link.project_id}/links/${link.link_id}`, link);
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,15 @@ export class MapSettingsService {
|
|||||||
public isTopologySummaryVisible: boolean = true;
|
public isTopologySummaryVisible: boolean = true;
|
||||||
public isLogConsoleVisible: boolean = false;
|
public isLogConsoleVisible: boolean = false;
|
||||||
public isLayerNumberVisible: boolean = false;
|
public isLayerNumberVisible: boolean = false;
|
||||||
public interfaceLabels: Map<string, boolean> = new Map<string, boolean>();
|
|
||||||
public logConsoleSubject = new Subject<boolean>();
|
public logConsoleSubject = new Subject<boolean>();
|
||||||
public mapRenderedEmitter = new EventEmitter<boolean>();
|
public mapRenderedEmitter = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
public showInterfaceLabels: boolean = true;
|
||||||
public integrateLinkLabelsToLinks: boolean = true;
|
public integrateLinkLabelsToLinks: boolean = true;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isLayerNumberVisible = localStorage.getItem('layersVisibility') === 'true' ? true : false;
|
this.isLayerNumberVisible = localStorage.getItem('layersVisibility') === 'true' ? true : false;
|
||||||
|
if (localStorage.getItem('integrateLinkLabelsToLinks')) this.integrateLinkLabelsToLinks = localStorage.getItem('integrateLinkLabelsToLinks') === 'true' ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeMapLockValue(value: boolean) {
|
changeMapLockValue(value: boolean) {
|
||||||
@ -33,7 +34,17 @@ export class MapSettingsService {
|
|||||||
this.isLayerNumberVisible = value;
|
this.isLayerNumberVisible = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleShowInterfaceLabels(projectId: string, value: boolean) {
|
toggleShowInterfaceLabels(value: boolean) {
|
||||||
this.interfaceLabels.set(projectId, value);
|
this.showInterfaceLabels = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleIntegrateInterfaceLabels(value: boolean) {
|
||||||
|
this.integrateLinkLabelsToLinks = value;
|
||||||
|
localStorage.removeItem('integrateLinkLabelsToLinks');
|
||||||
|
if (value) {
|
||||||
|
localStorage.setItem('integrateLinkLabelsToLinks', 'true');
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('integrateLinkLabelsToLinks', 'false');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,7 @@ export class TemplateService {
|
|||||||
return this.httpServer.get<Template[]>(server, '/templates') as Observable<Template[]>;
|
return this.httpServer.get<Template[]>(server, '/templates') as Observable<Template[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteTemplate(server: Server, templateId: string): Observable<boolean> {
|
deleteTemplate(server: Server, templateId: string): Observable<any> {
|
||||||
return this.httpServer.delete(server, `/templates/${templateId}`, { observe: 'body' }).map(response => {
|
return this.httpServer.delete(server, `/templates/${templateId}`, { observe: 'body' });
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.catch((response) => { return Observable.throw(false)});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,3 +42,8 @@ app-root {
|
|||||||
mat-menu-panel {
|
mat-menu-panel {
|
||||||
min-height: 0px;
|
min-height: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-tooltip {
|
||||||
|
background-color: grey;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
12
yarn.lock
12
yarn.lock
@ -7813,9 +7813,9 @@ lodash.values@^4.3.0:
|
|||||||
integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
|
integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
|
||||||
|
|
||||||
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.10:
|
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.10:
|
||||||
version "4.17.15"
|
version "4.17.19"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||||
|
|
||||||
log-symbols@^3.0.0:
|
log-symbols@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
@ -13006,9 +13006,9 @@ xterm-addon-fit@^0.4.0:
|
|||||||
integrity sha512-p4BESuV/g2L6pZzFHpeNLLnep9mp/DkF3qrPglMiucSFtD8iJxtMufEoEJbN8LZwB4i+8PFpFvVuFrGOSpW05w==
|
integrity sha512-p4BESuV/g2L6pZzFHpeNLLnep9mp/DkF3qrPglMiucSFtD8iJxtMufEoEJbN8LZwB4i+8PFpFvVuFrGOSpW05w==
|
||||||
|
|
||||||
xterm@^4.1.0:
|
xterm@^4.1.0:
|
||||||
version "4.7.0"
|
version "4.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.7.0.tgz#254485811146b03fbea10c911f7f68a99e1d3bfd"
|
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.8.1.tgz#155a1729a43e1a89b406524e22c5634339e39ca1"
|
||||||
integrity sha512-UeH6U/1iknCBP94/AcKAFBeQz6ZicMugJHGXruTmsY8RcZt+mkx+vl8jLLOqNYweXdBbywCg2kK88WDKjcmSmg==
|
integrity sha512-ax91ny4tI5eklqIfH79OUSGE2PUX2rGbwONmB6DfqpyhSZO8/cf++sqiaMWEVCMjACyMfnISW7C3gGMoNvNolQ==
|
||||||
|
|
||||||
y18n@^3.2.0:
|
y18n@^3.2.0:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user