Compare commits

..

2 Commits

Author SHA1 Message Date
8bc381bde8 Merge branch 'master' into dependabot/npm_and_yarn/electron-18.3.7 2023-02-01 08:44:52 +05:45
030429dfe9 Bump electron from 13.6.6 to 18.3.7
Bumps [electron](https://github.com/electron/electron) from 13.6.6 to 18.3.7.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v13.6.6...v18.3.7)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-16 10:37:09 +00:00
52 changed files with 436 additions and 915 deletions

File diff suppressed because one or more lines are too long

View File

@ -13,10 +13,10 @@ name: "CodeQL"
on:
push:
branches: [ "master", "master-3.0" ]
branches: [ "master-3.0" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master", "master-3.0" ]
branches: [ "master-3.0" ]
schedule:
- cron: '38 18 * * 6'

View File

@ -26,9 +26,8 @@
"rxjs/add/operator/map",
"rxjs-compat/add/operator/map",
"classnames",
"stylenames",
"ipaddr.js"
],
"stylenames"
],
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
@ -244,4 +243,4 @@
"cli": {
"analytics": false
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "gns3-web-ui",
"version": "2.2.54",
"version": "2.2.38.dev1",
"author": {
"name": "GNS3 Technology Inc.",
"email": "developers@gns3.com"
@ -66,7 +66,6 @@
"d3-ng2-service": "^2.2.0",
"eev": "^0.1.5",
"ini": "^2.0.0",
"ipaddr.js": "^2.1.0",
"material-design-icons": "^3.0.1",
"mousetrap": "^1.6.5",
"ng-circle-progress": "^1.6.0",
@ -103,7 +102,7 @@
"@types/jasminewd2": "^2.0.10",
"@types/node": "16.11.6",
"codelyzer": "^6.0.2",
"electron": "^13.6.6",
"electron": "^18.3.7",
"electron-builder": "^22.9.1",
"file-loader": "^6.2.0",
"jasmine-core": "~3.10.1",
@ -126,7 +125,7 @@
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0",
"typescript": "4.2.3",
"webpack": "5.76.0",
"webpack": "5.62.1",
"yarn-upgrade-all": "^0.5.4"
},
"greenkeeper": {

View File

@ -1,6 +1,6 @@
setuptools==78.1.1
setuptools==65.5.1
cx_Freeze==5.1.1
requests==2.32.4
requests==2.25.1
packaging==20.9
appdirs==1.4.4
psutil==5.8.0

View File

@ -1,4 +1,4 @@
<div [ngClass]="{ dark: darkThemeEnabled, light: !darkThemeEnabled }">
<router-outlet></router-outlet>
<!-- <app-adbutler></app-adbutler> -->
<app-adbutler></app-adbutler>
</div>

View File

@ -215,7 +215,6 @@ import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.
import { MATERIAL_IMPORTS } from './material.imports';
import { ServerResolve } from './resolvers/server-resolve';
import { ApplianceService } from './services/appliances.service';
import { ProtocolHandlerService } from './services/protocol-handler.service';
import { BuiltInTemplatesConfigurationService } from './services/built-in-templates-configuration.service';
import { BuiltInTemplatesService } from './services/built-in-templates.service';
import { ComputeService } from './services/compute.service';
@ -539,7 +538,6 @@ import { RotationValidator } from './validators/rotation-validator';
ComputeService,
TracengService,
PacketCaptureService,
ProtocolHandlerService,
NotificationService,
Gns3vmService,
ThemeService,

View File

@ -7,6 +7,4 @@
[attr.stroke-dasharray]="stroke_dasharray"
[attr.width]="rect.width"
[attr.height]="rect.height"
[attr.rx]="rect.rx"
[attr.ry]="rect.ry"
/>

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 278 B

View File

@ -14,7 +14,7 @@ export class MapDrawingToSvgConverter implements Converter<MapDrawing, string> {
let elem = ``;
if (mapDrawing.element instanceof RectElement) {
elem = `<rect fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" rx=\"${mapDrawing.element.rx}\" ry=\"${mapDrawing.element.ry}\" />`;
elem = `<rect fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
} else if (mapDrawing.element instanceof EllipseElement) {
elem = `<ellipse fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" cx=\"${mapDrawing.element.cx}\" cy=\"${mapDrawing.element.cy}\" rx=\"${mapDrawing.element.rx}\" ry=\"${mapDrawing.element.ry}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
} else if (mapDrawing.element instanceof LineElement) {

View File

@ -13,8 +13,6 @@ export class RectangleElementFactory implements DrawingElementFactory {
rectElement.stroke_width = 2;
rectElement.width = 200;
rectElement.height = 100;
rectElement.rx = 0;
rectElement.ry = 0;
return rectElement;
}
}

View File

@ -17,8 +17,6 @@ describe('RectConverter', () => {
element.setAttribute('width', '100px');
element.setAttribute('height', '200px');
element.setAttribute('rx', '0');
element.setAttribute('ry', '0');
const drawing = rectConverter.convert(element);
expect(drawing.fill).toEqual('#ffffff');
@ -27,8 +25,6 @@ describe('RectConverter', () => {
expect(drawing.stroke_dasharray).toEqual('5,25,25');
expect(drawing.width).toEqual(100);
expect(drawing.height).toEqual(200);
expect(drawing.rx).toEqual(0);
expect(drawing.ry).toEqual(0);
});
it('should parse with no attributes', () => {
@ -41,7 +37,5 @@ describe('RectConverter', () => {
expect(drawing.stroke_dasharray).toBeUndefined();
expect(drawing.width).toBeUndefined();
expect(drawing.height).toBeUndefined();
expect(drawing.rx).toBeUndefined();
expect(drawing.ry).toBeUndefined();
});
});

View File

@ -40,16 +40,6 @@ export class RectConverter implements SvgConverter {
drawing.height = parseInt(height.value, 10);
}
const rx = element.attributes.getNamedItem('rx');
if (rx) {
drawing.rx = parseInt(rx.value, 0);
}
const ry = element.attributes.getNamedItem('ry');
if (ry) {
drawing.ry = parseInt(ry.value, 0);
}
return drawing;
}
}

View File

@ -8,6 +8,4 @@ export class RectElement implements DrawingElement {
stroke: string;
stroke_width: number;
stroke_dasharray: string;
rx: number;
ry: number;
}

View File

@ -14,7 +14,6 @@ export class Properties {
headless: boolean;
linked_clone: boolean;
on_close: string;
aux: number;
ram: number;
nvram: number;
usage: string;
@ -57,7 +56,6 @@ export class Properties {
extra_volumes: string[];
replicate_network_connection_state: boolean;
tpm: boolean;
uefi: boolean;
}
export class Node {

View File

@ -28,8 +28,6 @@ describe('RectDrawingWidget', () => {
rect.stroke_dasharray = '5,25,25';
rect.width = 100;
rect.height = 200;
rect.rx = 0;
rect.ry = 0;
drawing.element = rect;
const drawings = svg.canvas.selectAll<SVGGElement, MapDrawing>('g.drawing').data([drawing]);
@ -48,7 +46,5 @@ describe('RectDrawingWidget', () => {
expect(rect_element.getAttribute('stroke-dasharray')).toEqual('5,25,25');
expect(rect_element.getAttribute('width')).toEqual('100');
expect(rect_element.getAttribute('height')).toEqual('200');
expect(rect_element.getAttribute('rx')).toEqual('0');
expect(rect_element.getAttribute('ry')).toEqual('0');
});
});

View File

@ -33,9 +33,7 @@ export class RectDrawingWidget implements DrawingShapeWidget {
.attr('stroke-width', (rect) => rect.stroke_width)
.attr('stroke-dasharray', (rect) => this.qtDasharrayFixer.fix(rect.stroke_dasharray))
.attr('width', (rect) => rect.width)
.attr('height', (rect) => rect.height)
.attr('rx', (rect) => rect.rx)
.attr('ry', (rect) => rect.ry);
.attr('height', (rect) => rect.height);
drawing.exit().remove();
}

View File

@ -90,7 +90,7 @@ export class InterfaceStatusWidget implements Widget {
.merge(status_started_enter)
.attr('class', 'status_started')
.attr('width', (ls: LinkStatus) => {
return ls.port.length * 10 + 5;
return ls.port.length * 8 + 10;
})
.attr('height', 20)
.attr('x', (ls: LinkStatus) => ls.x - 30)
@ -122,7 +122,7 @@ export class InterfaceStatusWidget implements Widget {
.merge(status_stopped_enter)
.attr('class', 'status_stopped')
.attr('width', (ls: LinkStatus) => {
return ls.port.length * 10 + 5;
return ls.port.length * 8 + 10;
})
.attr('height', 20)
.attr('x', (ls: LinkStatus) => ls.x - 30)
@ -154,7 +154,7 @@ export class InterfaceStatusWidget implements Widget {
.merge(status_suspended_enter)
.attr('class', 'status_suspended')
.attr('width', (ls: LinkStatus) => {
return ls.port.length * 10 + 5;
return ls.port.length * 8 + 10;
})
.attr('height', 20)
.attr('x', (ls: LinkStatus) => ls.x - 30)

View File

@ -13,8 +13,8 @@
<th mat-header-cell *matHeaderCellDef>Adapter type</th>
<td mat-cell *matCellDef="let element; let i = index">
<mat-select placeholder="Type" [(ngModel)]="element.adapter_type">
<mat-option *ngFor="let type of networkTypes" [value]="type.value">
{{ type.name }}
<mat-option *ngFor="let type of networkTypes" [value]="type">
{{ type }}
</mat-option>
</mat-select>
</td>

View File

@ -30,7 +30,6 @@ export class PortsComponent implements OnInit {
}
onAdd() {
this.newPort.name = "Ethernet" + this.newPort.port_number;
this.ethernetPorts.push(this.newPort);
this.newPort = {

View File

@ -59,15 +59,6 @@
placeholder="Start command"
/>
</mat-form-field>
<mat-form-field class="form-field">
<input
matInput
type="text"
[ngModelOptions]="{ standalone: true }"
[(ngModel)]="dockerTemplate.mac_address"
placeholder="Base MAC"
/>
</mat-form-field>
<mat-form-field class="form-field">
<input
formControlName="adapter"

View File

@ -61,7 +61,7 @@
<div *ngIf="newImageSelected">
<input
type="file"
accept=".bin, .image, .iol"
accept=".bin"
#file
class="nonvisible"
(change)="uploadImageFile($event)"

View File

@ -52,7 +52,7 @@
</mat-form-field>
<input
type="file"
accept=".bin, .image, .iol"
accept=".bin"
#file
class="nonvisible"
(change)="uploadImageFile($event)"
@ -98,14 +98,14 @@
<mat-checkbox [(ngModel)]="iouTemplate.l1_keepalives">
Enable layer 1 keepalive messages (non-functional) </mat-checkbox
><br />
<mat-checkbox [(ngModel)]="iouTemplate.use_default_iou_values"> Use default IOU values for memories </mat-checkbox>
<mat-form-field class="form-field" *ngIf="!iouTemplate.use_default_iou_values">
<mat-checkbox [(ngModel)]="defaultSettings"> Use default IOU values for memories </mat-checkbox>
<mat-form-field class="form-field" *ngIf="!defaultSettings">
<input matInput type="number" [(ngModel)]="iouTemplate.ram" placeholder="RAM size" />
<span matSuffix>MB</span>
</mat-form-field>
<mat-form-field class="form-field" *ngIf="!iouTemplate.use_default_iou_values">
<mat-form-field class="form-field" *ngIf="!defaultSettings">
<input matInput type="number" [(ngModel)]="iouTemplate.nvram" placeholder="NVRAM size" />
<span matSuffix>KB</span>
<span matSuffix>MB</span>
</mat-form-field>
</mat-expansion-panel>
<mat-expansion-panel>

View File

@ -186,15 +186,13 @@
</mat-form-field>
<mat-form-field class="form-field">
<mat-select placeholder="Type" [(ngModel)]="qemuTemplate.adapter_type">
<mat-option *ngFor="let type of networkTypes" [value]="type.value">{{type.name}} ({{type.value}}) </mat-option>
<mat-option *ngFor="let type of networkTypes" [value]="type[0]"> {{ type[1] }} ({{ type[0] }}) </mat-option>
</mat-select>
</mat-form-field>
<button mat-button class="configButton" (click)="setCustomAdaptersConfiguratorState(true)">
Configure custom adapters</button
>
<br /><mat-checkbox [(ngModel)]="qemuTemplate.legacy_networking"> Use the legacy networking mode </mat-checkbox>
<br /><mat-checkbox [(ngModel)]="qemuTemplate.replicate_network_connection_state"> Replicate network connection state </mat-checkbox>
><br />
<mat-checkbox [(ngModel)]="qemuTemplate.legacy_networking"> Use the legacy networking mode </mat-checkbox>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
@ -273,8 +271,6 @@
<input matInput type="text" [(ngModel)]="qemuTemplate.options" placeholder="Options" />
</mat-form-field>
<mat-checkbox [(ngModel)]="qemuTemplate.linked_clone"> Use as a linked base VM </mat-checkbox>
<br /><mat-checkbox [(ngModel)]="qemuTemplate.tpm"> Enable the Trusted Platform Module (TPM)</mat-checkbox>
<br /><mat-checkbox [(ngModel)]="qemuTemplate.uefi"> Enable the UEFI boot mode </mat-checkbox>
</mat-card-content>
</mat-card>
</mat-expansion-panel>

View File

@ -2,11 +2,3 @@
<mat-icon>web_asset</mat-icon>
<span>Console</span>
</button>
<button
mat-menu-item
*ngIf="node.node_type === 'docker' || node.node_type === 'dynamips' || node.node_type === 'qemu'"
(click)="openConsole(auxiliary=true)"
>
<mat-icon>web_asset</mat-icon>
<span>Auxiliary console</span>
</button>

View File

@ -4,9 +4,6 @@ import { Node } from '../../../../../cartography/models/node';
import { Server } from '../../../../../models/server';
import { NodeService } from '../../../../../services/node.service';
import { ToasterService } from '../../../../../services/toaster.service';
import { ProtocolHandlerService } from '../../../../../services/protocol-handler.service';
import * as ipaddr from 'ipaddr.js';
@Component({
selector: 'app-console-device-action-browser',
@ -16,16 +13,41 @@ export class ConsoleDeviceActionBrowserComponent {
@Input() server: Server;
@Input() node: Node;
constructor(private toasterService: ToasterService, private nodeService: NodeService, private protocolHandlerService: ProtocolHandlerService) {}
constructor(private toasterService: ToasterService, private nodeService: NodeService, private deviceService: DeviceDetectorService) {}
openConsole(auxiliary: boolean = false) {
openConsole() {
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
this.node = node;
this.startConsole(auxiliary);
this.startConsole();
});
}
startConsole(auxiliary: boolean) {
createHiddenIframe(target: Element, uri: string) {
const iframe = document.createElement("iframe");
iframe.src = uri;
iframe.id = "hiddenIframe";
iframe.style.display = "none";
target.appendChild(iframe);
return iframe;
}
openUriUsingFirefox(uri: string) {
var iframe = (document.querySelector("#hiddenIframe") as HTMLIFrameElement);
if (!iframe) {
iframe = this.createHiddenIframe(document.body, "about:blank");
}
try {
iframe.contentWindow.location.href = uri;
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL") {
this.toasterService.error('Protocol handler does not exist');
}
}
}
startConsole() {
if (this.node.status !== 'started') {
this.toasterService.error('This node must be started before a console can be opened');
} else {
@ -37,38 +59,27 @@ export class ConsoleDeviceActionBrowserComponent {
this.node.console_host = this.server.host;
}
const device = this.deviceService.getDeviceInfo();
try {
var uri;
var host = this.node.console_host;
if (ipaddr.IPv6.isValid(host)) {
host = `[${host}]`;
}
if (this.node.console_type === 'telnet') {
var console_port;
if (auxiliary === true) {
console_port = this.node.properties.aux;
if (console_port === undefined) {
this.toasterService.error('Auxiliary console port is not set.');
return;
}
} else {
console_port = this.node.console;
}
uri = `gns3+telnet://${host}:${console_port}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`;
uri = `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') {
uri = `gns3+vnc://${host}:${this.node.console}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`;
uri = `gns3+vnc://${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.startsWith('spice')) {
uri = `gns3+spice://${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.startsWith('http')) {
uri = `${this.node.console_type}://${host}:${this.node.console}`
return window.open(uri); // open an http console directly in a new window/tab
uri = `gns3+spice://${this.node.console_host}:${this.node.console}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`
} else {
this.toasterService.error('Supported console types are: telnet, vnc, spice and spice+agent.');
return;
}
this.protocolHandlerService.open(uri);
if (device.browser === "Firefox") {
// Use a hidden iframe otherwise Firefox will disconnect
// from the GNS3 controller websocket if we use location.assign()
this.openUriUsingFirefox(uri);
} else {
location.assign(uri);
}
} catch (e) {
this.toasterService.error(e);

View File

@ -2,7 +2,7 @@
<div class="modal-form-container">
<form [formGroup]="formGroup">
<mat-form-field class="form-field" *ngIf="element.fill !== undefined">
<mat-form-field class="form-field">
<input
matInput
[ngModelOptions]="{ standalone: true }"
@ -23,13 +23,7 @@
</mat-form-field>
<mat-form-field class="form-field">
<input
matInput formControlName="borderWidth"
placeholder="Border width"
type="number"
min="0"
max="100"
/>
<input matInput formControlName="borderWidth" placeholder="Border width" type="number" />
</mat-form-field>
<mat-form-field class="form-field" *ngIf="element.stroke_dasharray">
@ -42,41 +36,6 @@
/>
</mat-form-field>
<mat-form-field class="form-field" *ngIf="element.width !== undefined">
<input
matInput
[ngModelOptions]="{ standalone: true }"
placeholder="Width"
min="0"
type="number"
[(ngModel)]="element.width"
/>
</mat-form-field>
<mat-form-field class="form-field" *ngIf="element.height !== undefined">
<input
matInput
[ngModelOptions]="{ standalone: true }"
placeholder="Height"
min="0"
type="number"
[(ngModel)]="element.height"
/>
</mat-form-field>
<mat-form-field class="form-field" *ngIf="element.rx !== undefined">
<input
matInput
[ngModelOptions]="{ standalone: true }"
placeholder="Corner radius"
type="number"
min="0"
max="100"
[(ngModel)]="element.rx"
/>
</mat-form-field>
<mat-form-field class="form-field">
<input matInput formControlName="rotation" placeholder="Rotation" type="number" />
</mat-form-field>

View File

@ -49,8 +49,6 @@ export class StyleEditorDialogComponent implements OnInit {
if (this.drawing.element instanceof RectElement || this.drawing.element instanceof EllipseElement) {
this.element.fill = this.drawing.element.fill;
this.element.width = this.drawing.element.width;
this.element.height = this.drawing.element.height;
this.element.stroke = this.drawing.element.stroke;
this.element.stroke_dasharray = this.drawing.element.stroke_dasharray;
this.element.stroke_width = this.drawing.element.stroke_width;
@ -60,11 +58,6 @@ export class StyleEditorDialogComponent implements OnInit {
this.element.stroke_width = this.drawing.element.stroke_width;
}
if (this.drawing.element instanceof RectElement) {
this.element.rx = this.drawing.element.rx;
this.element.ry = this.drawing.element.ry;
}
if (this.element.stroke_width === undefined) this.element.stroke_width = 0;
this.formGroup.controls['borderWidth'].setValue(this.element.stroke_width);
this.formGroup.controls['rotation'].setValue(this.drawing.rotation);
@ -81,8 +74,6 @@ export class StyleEditorDialogComponent implements OnInit {
if (this.drawing.element instanceof RectElement || this.drawing.element instanceof EllipseElement) {
this.drawing.element.fill = this.element.fill;
this.drawing.element.width = this.element.width;
this.drawing.element.height = this.element.height;
this.drawing.element.stroke = this.element.stroke;
this.drawing.element.stroke_dasharray = this.element.stroke_dasharray;
this.drawing.element.stroke_width = this.element.stroke_width;
@ -92,11 +83,6 @@ export class StyleEditorDialogComponent implements OnInit {
this.drawing.element.stroke_width = this.element.stroke_width;
}
if (this.drawing.element instanceof RectElement) {
this.drawing.element.rx = this.element.rx;
this.drawing.element.ry = this.element.rx; // set ry with rx because we don't have ry in the form
}
let mapDrawing = this.drawingToMapDrawingConverter.convert(this.drawing);
mapDrawing.element = this.drawing.element;
@ -114,11 +100,7 @@ export class StyleEditorDialogComponent implements OnInit {
export class ElementData {
fill: string;
width: number;
height: number;
stroke: string;
stroke_width: number;
stroke_dasharray: string;
rx: number;
ry: number;
}

View File

@ -91,7 +91,6 @@ export class ImportApplianceComponent implements OnInit {
template.console_auto_start = appliance.iou.console_auto_start;
template.ethernet_adapters = appliance.iou.ethernet_adapters;
template.l1_keepalives = appliance.iou.l1_keepalives;
template.use_default_iou_values = appliance.iou.use_default_iou_values;
template.nvram = appliance.iou.nvram;
template.ram = appliance.iou.ram;
template.serial_adapters = appliance.iou.serial_adapters;

View File

@ -6,7 +6,6 @@ import { MatMenuModule } from '@angular/material/menu';
import { BrowserModule } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { ToasterService } from '../../../services/toaster.service';
import { ProtocolHandlerService } from '../../../services/protocol-handler.service';
import { of } from 'rxjs';
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
import { ProjectWebServiceHandler, WebServiceMessage } from '../../../handlers/project-web-service-handler';
@ -39,7 +38,6 @@ describe('LogConsoleComponent', () => {
let nodeConsoleService: NodeConsoleService;
let mapSettingsService: MapSettingsService;
let toasterService: ToasterService;
let protocolHandlerService: ProtocolHandlerService;
let httpServer = new HttpServer({} as HttpClient, {} as ServerErrorHandler);
@ -54,7 +52,6 @@ describe('LogConsoleComponent', () => {
{ provide: HttpServer, useValue: httpServer },
NodeConsoleService,
ToasterService,
ProtocolHandlerService,
MapSettingsService
],
declarations: [LogConsoleComponent],
@ -62,7 +59,6 @@ describe('LogConsoleComponent', () => {
}).compileComponents();
toasterService = TestBed.inject(ToasterService);
protocolHandlerService = TestBed.inject(ProtocolHandlerService);
mapSettingsService = TestBed.inject(MapSettingsService);
nodeConsoleService = TestBed.inject(NodeConsoleService);
}));

View File

@ -23,11 +23,9 @@ import { Server } from '../../../models/server';
import { HttpServer } from '../../../services/http-server.service';
import { NodeService } from '../../../services/node.service';
import { NodeConsoleService } from '../../../services/nodeConsole.service';
import { ProtocolHandlerService } from '../../../services/protocol-handler.service';
import { ThemeService } from '../../../services/theme.service';
import { version } from '../../../version';
import { LogEventsDataSource } from './log-events-datasource';
import * as ipaddr from 'ipaddr.js';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
@ -71,7 +69,6 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy {
private projectWebServiceHandler: ProjectWebServiceHandler,
private nodeService: NodeService,
private nodesDataSource: NodesDataSource,
private protocolHandlerService: ProtocolHandlerService,
private logEventsDataSource: LogEventsDataSource,
private httpService: HttpServer,
private themeService: ThemeService,
@ -227,24 +224,18 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy {
} else if (this.regexConsole.test(this.command)) {
if (node.status === 'started') {
this.showCommand(`Launching console for node ${splittedCommand[1]}...`);
var host = node.console_host;
if (ipaddr.IPv6.isValid(host)) {
host = `[${host}]`;
}
if (node.console_type === 'telnet') {
this.protocolHandlerService.open(
`gns3+telnet://${host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
location.assign(
`gns3+telnet://${node.console_host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
);
} else if (node.console_type === 'vnc') {
this.protocolHandlerService.open(
`gns3+vnc://${host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
location.assign(
`gns3+vnc://${node.console_host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
);
} else if (node.console_type.startsWith('spice')) {
this.protocolHandlerService.open(
`gns3+spice://${host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
location.assign(
`gns3+spice://${node.console_host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
);
} else if (node.console_type.startsWith('http')) {
window.open(`${node.console_type}://${host}:${node.console}`);
} else {
this.showCommand('Supported console types are: telnet, vnc, spice and spice+agent');
}

View File

@ -77,7 +77,7 @@
</ng-container>
<!-- <ng-container matColumnDef="expandedDetail">
<mat-cell *matCellDef="let detail">
<mat-cell *matCellDef="let detail">
The symbol for {{detail.element}}
</mat-cell>
</ng-container> -->
@ -85,14 +85,14 @@
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
<!-- <mat-row
<!-- <mat-row
*matRowDef="let row; columns: displayedColumns;"
matRipple
class="element-row"
matRipple
class="element-row"
[class.expanded]="expandedElement == row"
(click)="expandedElement = row">
</mat-row>
<mat-row
<mat-row
*matRowDef="let row; columns: ['expandedDetail']; when: isExpansionDetailRow"
[@detailExpand]="row.element == expandedElement ? 'expanded' : 'collapsed'"
style="overflow: hidden">
@ -170,7 +170,7 @@
</mat-select>
</div>
<div>
Install the required files
Install required files
<button
mat-icon-button
matTooltip="Refresh list of images"
@ -292,70 +292,6 @@
</div>
</div>
<div class="list-item-inside" *ngIf="version.images.hdc_disk_image">
<span>
{{ version.images.hdb_disk_image }}
</span>
<div>
<span *ngIf="checkImageFromVersion(version.images.hdc_disk_image)"
><mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon></span
>
<span *ngIf="!checkImageFromVersion(version.images.hdc_disk_image)"
><mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon></span
>
<input
type="file"
class="non-visible"
#file4
(change)="importImage($event, version.images.hdc_disk_image)"
ng2FileSelect
[uploader]="uploaderImage"
/>
<button class="button" mat-raised-button (click)="file4.click()">Import</button>
<button
class="button"
mat-raised-button
(click)="downloadImageFromVersion(version.images.hdc_disk_image)"
>
Download
</button>
</div>
</div>
<div class="list-item-inside" *ngIf="version.images.hdd_disk_image">
<span>
{{ version.images.hdd_disk_image }}
</span>
<div>
<span *ngIf="checkImageFromVersion(version.images.hdd_disk_image)"
><mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon></span
>
<span *ngIf="!checkImageFromVersion(version.images.hdd_disk_image)"
><mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon></span
>
<input
type="file"
class="non-visible"
#file5
(change)="importImage($event, version.images.hdd_disk_image)"
ng2FileSelect
[uploader]="uploaderImage"
/>
<button class="button" mat-raised-button (click)="file5.click()">Import</button>
<button
class="button"
mat-raised-button
(click)="downloadImageFromVersion(version.images.hdd_disk_image)"
>
Download
</button>
</div>
</div>
<div class="list-item-inside" *ngIf="version.images.cdrom_image">
<span>
{{ version.images.cdrom_image}}
@ -372,12 +308,12 @@
<input
type="file"
class="non-visible"
#file6
#file4
(change)="importImage($event, version.images.cdrom_image)"
ng2FileSelect
[uploader]="uploaderImage"
/>
<button class="button" mat-raised-button (click)="file6.click()">Import</button>
<button class="button" mat-raised-button (click)="file4.click()">Import</button>
<button
class="button"
mat-raised-button
@ -441,7 +377,7 @@
</mat-radio-group>
</div>
<div>
Install the required images
Install required files
<button
mat-icon-button
matTooltip="Refresh list of images"
@ -453,16 +389,10 @@
<mat-list>
<mat-list-item *ngFor="let image of applianceToInstall.images">
<div class="list-item">
<span>
{{ image.filename }}
</span>
<div>
<span *ngIf="checkImageFromVersion(image.filename)">
<mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon>
</span>
<span *ngIf="!checkImageFromVersion(image.filename)">
<mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon>
</span>
{{ image.filename }}
</div>
<div>
<input
type="file"
class="non-visible"
@ -505,7 +435,7 @@
</mat-radio-group>
</div>
<div>
Install the required images
Install required files
<button
mat-icon-button
matTooltip="Refresh list of images"
@ -517,15 +447,9 @@
<mat-list>
<mat-list-item *ngFor="let image of applianceToInstall.images">
<div class="list-item">
<span>
<div>
{{ image.filename }}
</span>
<span *ngIf="checkImageFromVersion(image.filename)">
<mat-icon matTooltip="Ready to install" matTooltipClass="custom-tooltip">check</mat-icon>
</span>
<span *ngIf="!checkImageFromVersion(image.filename)">
<mat-icon matTooltip="Missing" matTooltipClass="custom-tooltip">close</mat-icon>
</span>
</div>
<div>
<input
type="file"

View File

@ -143,7 +143,7 @@ export class NewTemplateDialogComponent implements OnInit {
this.qemuBinaries = binaries;
});
this.uploader = new FileUploader({url: ''});
this.uploader = new FileUploader({});
this.uploader.onAfterAddingFile = (file) => {
file.withCredentials = false;
};
@ -162,7 +162,7 @@ export class NewTemplateDialogComponent implements OnInit {
this.getAppliance(item.url);
};
this.uploaderImage = new FileUploader({url: ''});
this.uploaderImage = new FileUploader({});
this.uploaderImage.onAfterAddingFile = (file) => {
file.withCredentials = false;
};
@ -320,17 +320,17 @@ export class NewTemplateDialogComponent implements OnInit {
setTimeout(() => {
if (this.qemuBinaries.length) {
if (this.applianceToInstall.qemu.arch === 'x86_64') {
let filtered_binaries = this.qemuBinaries.filter((n) => n.path.endsWith('qemu-system-x86_64'));
let filtered_binaries = this.qemuBinaries.filter((n) => n.path.includes('qemu-system-x86_64'));
if (filtered_binaries.length) {
this.selectedBinary = filtered_binaries[0];
}
} else if (this.applianceToInstall.qemu.arch === 'i386') {
let filtered_binaries = this.qemuBinaries.filter((n) => n.path.endsWith('qemu-system-i386'));
let filtered_binaries = this.qemuBinaries.filter((n) => n.path.includes('qemu-system-i386'));
if (filtered_binaries.length) {
this.selectedBinary = filtered_binaries[0];
}
} else if (this.applianceToInstall.qemu.arch === 'arm') {
let filtered_binaries = this.qemuBinaries.filter((n) => n.path.endsWith('qemu-system-arm'));
} else if (this.applianceToInstall.qemu.arch === 'x86_64') {
let filtered_binaries = this.qemuBinaries.filter((n) => n.path.includes('qemu-system-arm'));
if (filtered_binaries.length) {
this.selectedBinary = filtered_binaries[0];
}
@ -364,7 +364,7 @@ export class NewTemplateDialogComponent implements OnInit {
autoFocus: false,
disableClose: true,
});
dialogRef.componentInstance.confirmationMessage = `This is not the correct file.
dialogRef.componentInstance.confirmationMessage = `This is not the correct file.
The MD5 sum is ${output} and should be ${imageToInstall.md5sum}. Do you want to accept it at your own risks?`;
dialogRef.afterClosed().subscribe((answer: boolean) => {
if (answer) {
@ -401,8 +401,7 @@ export class NewTemplateDialogComponent implements OnInit {
this.progressService.activate();
};
//fileReader.readAsText(file); //web browser out ouf memory when upload large image file
fileReader.onloadend(undefined);
fileReader.readAsText(file);
}
checkImageFromVersion(image: string): boolean {
@ -486,7 +485,7 @@ export class NewTemplateDialogComponent implements OnInit {
iouTemplate.startup_config = this.applianceToInstall.iou.startup_config;
iouTemplate.builtin = this.applianceToInstall.builtin;
iouTemplate.category = this.getCategory();
iouTemplate.default_name_format = this.applianceToInstall.default_name_format;
iouTemplate.default_name_format = this.applianceToInstall.port_name_format;
iouTemplate.symbol = this.applianceToInstall.symbol;
iouTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local';
iouTemplate.template_id = uuid();
@ -535,7 +534,7 @@ export class NewTemplateDialogComponent implements OnInit {
iosTemplate.slot7 = this.applianceToInstall.dynamips.slot7;
iosTemplate.builtin = this.applianceToInstall.builtin;
iosTemplate.category = this.getCategory();
iosTemplate.default_name_format = this.applianceToInstall.default_name_format;
iosTemplate.default_name_format = this.applianceToInstall.port_name_format;
iosTemplate.symbol = this.applianceToInstall.symbol;
iosTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local';
iosTemplate.template_id = uuid();
@ -573,7 +572,7 @@ export class NewTemplateDialogComponent implements OnInit {
dockerTemplate.console_type = this.applianceToInstall.docker.console_type;
dockerTemplate.builtin = this.applianceToInstall.builtin;
dockerTemplate.category = this.getCategory();
dockerTemplate.default_name_format = this.applianceToInstall.default_name_format;
dockerTemplate.default_name_format = this.applianceToInstall.port_name_format;
dockerTemplate.symbol = this.applianceToInstall.symbol;
dockerTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local';
dockerTemplate.template_id = uuid();
@ -630,17 +629,12 @@ export class NewTemplateDialogComponent implements OnInit {
qemuTemplate.category = this.getCategory();
qemuTemplate.first_port_name = this.applianceToInstall.first_port_name;
qemuTemplate.port_name_format = this.applianceToInstall.port_name_format;
qemuTemplate.port_segment_size = this.applianceToInstall.port_segment_size;
qemuTemplate.default_name_format = this.applianceToInstall.default_name_format
qemuTemplate.symbol = this.applianceToInstall.symbol;
qemuTemplate.qemu_path = this.selectedBinary.path;
qemuTemplate.compute_id = this.isGns3VmChosen ? 'vm' : 'local';
qemuTemplate.template_id = uuid();
qemuTemplate.hda_disk_image = version.images.hda_disk_image;
qemuTemplate.hdb_disk_image = version.images.hdb_disk_image;
qemuTemplate.hdc_disk_image = version.images.hdc_disk_image;
qemuTemplate.hdd_disk_image = version.images.hdd_disk_image;
qemuTemplate.cdrom_image = version.images.cdrom_image;
qemuTemplate.template_type = 'qemu';
qemuTemplate.usage = this.applianceToInstall.usage;

View File

@ -20,14 +20,13 @@
</mat-select>
</mat-form-field>
<mat-checkbox [(ngModel)]="node.console_auto_start"> Auto start console </mat-checkbox><br />
<mat-checkbox [(ngModel)]="node.properties.use_default_iou_values"> Use default IOU values for memories </mat-checkbox>
<mat-form-field class="form-field" *ngIf="!node.properties.use_default_iou_values">
<mat-form-field class="form-field">
<input matInput type="number" [(ngModel)]="node.properties.ram" placeholder="RAM size" />
<span matSuffix>MB</span>
</mat-form-field>
<mat-form-field class="form-field" *ngIf="!node.properties.use_default_iou_values">
<mat-form-field class="form-field">
<input matInput type="number" [(ngModel)]="node.properties.nvram" placeholder="NVRAM size" />
<span matSuffix>KB</span>
<span matSuffix>MB</span>
</mat-form-field>
</mat-tab>
@ -39,7 +38,7 @@
matInput
formControlName="ethernetAdapters"
type="number"
[(ngModel)]="node.properties.ethernet_adapters"
[(ngModel)]="node.ethernet_adapters"
placeholder="Ethernet adapters"
/>
</mat-form-field>
@ -48,7 +47,7 @@
matInput
formControlName="serialAdapters"
type="number"
[(ngModel)]="node.properties.serial_adapters"
[(ngModel)]="node.serial_adapters"
placeholder="Serial adapters"
/>
</mat-form-field>

View File

@ -241,9 +241,6 @@
<br /><mat-checkbox [(ngModel)]="node.properties.tpm">
Enable the Trusted Platform Module (TPM)
</mat-checkbox>
<br /><mat-checkbox [(ngModel)]="node.properties.uefi">
Enable the UEFI boot mode
</mat-checkbox>
</mat-card-content>
</mat-card>
</mat-tab>

View File

@ -17,7 +17,6 @@ import { ToasterService } from '../../../../services/toaster.service';
import { MockedToasterService } from '../../../../services/toaster.service.spec';
import { MockedLinkService, MockedNodesDataSource } from '../../project-map.component.spec';
import { StartCaptureDialogComponent } from './start-capture.component';
import { ProtocolHandlerService } from '../../../../services/protocol-handler.service';
describe('StartCaptureDialogComponent', () => {
let component: StartCaptureDialogComponent;
@ -26,8 +25,6 @@ describe('StartCaptureDialogComponent', () => {
let mockedToasterService = new MockedToasterService();
let mockedLinkService = new MockedLinkService();
let mockedNodesDataSource = new MockedNodesDataSource();
let protocolHandlerService: ProtocolHandlerService;
let dialogRef = {
close: jasmine.createSpy('close'),
};
@ -52,13 +49,10 @@ describe('StartCaptureDialogComponent', () => {
{ provide: LinkService, useValue: mockedLinkService },
{ provide: NodesDataSource, useValue: mockedNodesDataSource },
{ provide: PacketCaptureService },
ProtocolHandlerService,
],
declarations: [StartCaptureDialogComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
protocolHandlerService = TestBed.inject(ProtocolHandlerService);
}));
beforeEach(() => {

View File

@ -67,7 +67,6 @@ import { SymbolService } from '../../services/symbol.service';
import { ThemeService } from '../../services/theme.service';
import { ToasterService } from '../../services/toaster.service';
import { ToolsService } from '../../services/tools.service';
import { ProtocolHandlerService } from '../../services/protocol-handler.service';
import { AddBlankProjectDialogComponent } from '../projects/add-blank-project-dialog/add-blank-project-dialog.component';
import { ConfirmationBottomSheetComponent } from '../projects/confirmation-bottomsheet/confirmation-bottomsheet.component';
import { EditProjectDialogComponent } from '../projects/edit-project-dialog/edit-project-dialog.component';
@ -174,9 +173,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
private title: Title,
private nodeConsoleService: NodeConsoleService,
private symbolService: SymbolService,
private protocolHandlerService: ProtocolHandlerService,
private cd: ChangeDetectorRef,
private cfr: ComponentFactoryResolver,
private cfr: ComponentFactoryResolver,
private injector: Injector
) {}
@ -231,7 +229,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
this.instance.instance.ngOnDestroy();
this.instance.destroy();
}
}
}
}
addSubscriptions() {
@ -977,7 +975,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
) {
this.toasterService.error('Project with running nodes cannot be exported.');
} else {
this.protocolHandlerService.open(this.projectService.getExportPath(this.server, this.project));
location.assign(this.projectService.getExportPath(this.server, this.project));
}
}
@ -992,8 +990,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
fileReader.onloadend = () => {
let image = fileReader.result;
let svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"
height=\"${imageToUpload.height}\" width=\"${imageToUpload.width}\">\n<image height=\"${imageToUpload.height}\" width=\"${imageToUpload.width}\"
let svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"
height=\"${imageToUpload.height}\" width=\"${imageToUpload.width}\">\n<image height=\"${imageToUpload.height}\" width=\"${imageToUpload.width}\"
xlink:href=\"${image}\"/>\n</svg>`;
this.drawingService
.add(this.server, this.project.project_id, -(imageToUpload.width / 2), -(imageToUpload.height / 2), svg)

View File

@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
@Injectable()
export class ProjectNameValidator {
get(projectName) {
var pattern = new RegExp(/[~`!#$%\^&*+=\[\]\\';,/{}|\\"<>\?]/);
var pattern = new RegExp(/[~`!#$%\^&*+=\[\]\\';,/{}|\\":<>\?]/);
if (!pattern.test(projectName.value)) {
return null;

View File

@ -61,7 +61,7 @@
{{ node.name }}
</div>
<div *ngIf="node.console != null && node.console != undefined && node.console_type != 'none'">
{{ node.console_type }}://{{ node.console_host }}:{{ node.console }}
{{ node.console_type }} {{ node.console_host }}:{{ node.console }}
</div>
<div *ngIf="node.console === null || node.console === undefined || node.console_type === 'none'">
none

View File

@ -39,4 +39,4 @@
<app-progress></app-progress>
<footer class="footer mat-app-background">GNS3 Web-UI &copy;2018-{{ currentYear }} v{{ uiVersion }}</footer>
<footer class="footer mat-app-background">GNS3 Web UI &copy; 2020 - v{{ uiVersion }}</footer>

View File

@ -17,7 +17,6 @@ import { version } from './../../version';
export class DefaultLayoutComponent implements OnInit, OnDestroy {
public isInstalledSoftwareAvailable = false;
public uiVersion = version;
public currentYear = new Date().getFullYear();
serverStatusSubscription: Subscription;
shouldStopServersOnClosing = true;

View File

@ -55,9 +55,6 @@ export interface Iou {
export interface Images {
hda_disk_image: string;
hdb_disk_image: string;
hdc_disk_image: string;
hdd_disk_image: string;
cdrom_image: string;
}
export interface Version {
@ -77,13 +74,11 @@ export interface Appliance {
maintainer_email: string;
name: string;
port_name_format: string;
port_segment_size: number;
product_name: string;
product_url: string;
registry_version: number;
status: string;
symbol: string;
default_name_format: string;
usage: string;
vendor_name: string;
vendor_url: string;

View File

@ -10,7 +10,6 @@ export class DockerTemplate {
console_http_port: number;
console_resolution: string;
console_type: string;
mac_address: string;
custom_adapters: CustomAdapter[];
default_name_format: string;
environment: string;

View File

@ -43,7 +43,4 @@ export class QemuTemplate {
template_id: string;
template_type: string;
usage: string;
replicate_network_connection_state: boolean;
tpm: boolean;
uefi: boolean;
}

View File

@ -149,7 +149,7 @@ describe('DrawingService', () => {
drawing.z = 1;
drawing.rotation = 0;
drawing.svg =
'<svg height="100" width="200"><rect fill="#ffffff" fill-opacity="1.0" height="100" stroke="#000000" stroke-width="2" width="200" rx="0" ry="0" /></svg>';
'<svg height="100" width="200"><rect fill="#ffffff" fill-opacity="1.0" height="100" stroke="#000000" stroke-width="2" width="200" /></svg>';
service.duplicate(server, drawing.project_id, drawing).subscribe();

View File

@ -31,11 +31,6 @@ export class MapSettingsService {
} else {
localStorage.setItem('symbolScaling', 'true');
}
if (localStorage.getItem('showInterfaceLabels')) {
this.showInterfaceLabels = localStorage.getItem('showInterfaceLabels') === 'true' ? true : false;
} else {
localStorage.setItem('showInterfaceLabels', 'true');
}
}
public getSymbolScaling(): boolean {
@ -77,12 +72,6 @@ export class MapSettingsService {
toggleShowInterfaceLabels(value: boolean) {
this.showInterfaceLabels = value;
localStorage.removeItem('showInterfaceLabels');
if (value) {
localStorage.setItem('showInterfaceLabels', 'true');
} else {
localStorage.setItem('showInterfaceLabels', 'false');
}
}
toggleIntegrateInterfaceLabels(value: boolean) {

View File

@ -2,17 +2,14 @@ import { Injectable } from '@angular/core';
import { Link } from '../models/link';
import { Project } from '../models/project';
import { Server } from '../models/server';
import { ProtocolHandlerService } from './protocol-handler.service';
@Injectable()
export class PacketCaptureService {
constructor(private protocolHandlerService: ProtocolHandlerService) {}
constructor() {}
startCapture(server: Server, project: Project, link: Link, name: string) {
const uri = `gns3+pcap://${server.host}:${server.port}?protocol=${server.protocol.slice(0, -1)}&project_id=${project.project_id}&link_id=${link.link_id}&project=${project.name}&name=${name}`;
this.protocolHandlerService.open(uri);
location.assign(
`gns3+pcap://${server.host}:${server.port}?project_id=${project.project_id}&link_id=${link.link_id}&name=${name}`
);
}
}

View File

@ -1,48 +0,0 @@
import { Injectable } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
import { ToasterService } from './toaster.service';
@Injectable()
export class ProtocolHandlerService {
constructor(private toasterService: ToasterService, private deviceService: DeviceDetectorService) {}
createHiddenIframe(target: Element, uri: string) {
const iframe = document.createElement("iframe");
iframe.src = uri;
iframe.id = "hiddenIframe";
iframe.style.display = "none";
target.appendChild(iframe);
return iframe;
}
openUriUsingFirefox(uri: string) {
var iframe = (document.querySelector("#hiddenIframe") as HTMLIFrameElement);
if (!iframe) {
iframe = this.createHiddenIframe(document.body, "about:blank");
}
try {
iframe.contentWindow.location.href = uri;
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL") {
this.toasterService.error('Protocol handler does not exist');
}
}
}
open(uri: string) {
const device = this.deviceService.getDeviceInfo();
console.log("Launching external protocol handler with " + device.browser + ": " + uri)
if (device.browser === "Firefox") {
// Use a hidden iframe otherwise Firefox will disconnect
// from the GNS3 controller websocket if we use location.assign()
this.openUriUsingFirefox(uri);
} else {
location.assign(uri);
}
}
}

View File

@ -12,31 +12,53 @@ export class QemuConfigurationService {
getNetworkTypes() {
// needs extending of custom adapter component
// let networkTypes = [["e1000", "Intel Gigabit Ethernet"],
// ["i82550", "Intel i82550 Ethernet"],
// ["i82551", "Intel i82551 Ethernet"],
// ["i82557a", "Intel i82557A Ethernet"],
// ["i82557b", "Intel i82557B Ethernet"],
// ["i82557c", "Intel i82557C Ethernet"],
// ["i82558a", "Intel i82558A Ethernet"],
// ["i82558b", "Intel i82558B Ethernet"],
// ["i82559a", "Intel i82559A Ethernet"],
// ["i82559b", "Intel i82559B Ethernet"],
// ["i82559c", "Intel i82559C Ethernet"],
// ["i82559er", "Intel i82559ER Ethernet"],
// ["i82562", "Intel i82562 Ethernet"],
// ["i82801", "Intel i82801 Ethernet"],
// ["ne2k_pci", "NE2000 Ethernet"],
// ["pcnet", "AMD PCNet Ethernet"],
// ["rtl8139", "Realtek 8139 Ethernet"],
// ["virtio", "Legacy paravirtualized Network I/O"],
// ["virtio-net-pci", "Paravirtualized Network I/O"],
// ["vmxnet3", "VMWare Paravirtualized Ethernet v3"]];
let networkTypes = [
{ value: 'e1000', name: 'Intel Gigabit Ethernet' },
{ value: 'e1000-82544gc', name: 'Intel 82544GC Gigabit Ethernet' },
{ value: 'e1000-82545em', name: 'Intel 82545EM Gigabit Ethernet' },
{ value: 'e1000e', name: 'Intel PCIe Gigabit Ethernet' },
{ value: 'i82550', name: 'Intel i82550 Ethernet' },
{ value: 'i82551', name: 'Intel i82551 Ethernet' },
{ value: 'i82557a', name: 'Intel i82557A Ethernet' },
{ value: 'i82557b', name: 'Intel i82557B Ethernet' },
{ value: 'i82557c', name: 'Intel i82557C Ethernet' },
{ value: 'i82558a', name: 'Intel i82558A Ethernet' },
{ value: 'i82558b', name: 'Intel i82558B Ethernet' },
{ value: 'i82559a', name: 'Intel i82559A Ethernet' },
{ value: 'i82559b', name: 'Intel i82559B Ethernet' },
{ value: 'i82559c', name: 'Intel i82559C Ethernet' },
{ value: 'i82559er', name: 'Intel i82559ER Ethernet' },
{ value: 'i82562', name: 'Intel i82562 Ethernet' },
{ value: 'i82801', name: 'Intel i82801 Ethernet' },
{ value: 'igb', name: 'Intel 82576 Gigabit Ethernet' },
{ value: 'ne2k_pci', name: 'NE2000 Ethernet' },
{ value: 'pcnet', name: 'AMD PCNet Ethernet' },
{ value: 'rocker', name: 'Rocker L2 switch device' },
{ value: 'rtl8139', name: 'Realtek 8139 Ethernet' },
{ value: 'virtio-net-pci', name: 'Paravirtualized Network I/O' },
{ value: 'vmxnet3', name: 'VMWare Paravirtualized Ethernet v3' },
'e1000',
'e1000-82544gc',
'e1000-82545em',
'e1000e',
'rocker',
'Intel Gigabit Ethernet',
'i82550',
'i82551',
'i82557a',
'i82557b',
'i82557c',
'i82558a',
'i82558b',
'i82559a',
'i82559b',
'i82559c',
'i82559er',
'i82562',
'i82801',
'ne2k_pci',
'pcnet',
'rtl8139',
'virtio',
'virtio-net-pci',
'vmxnet3',
];
return networkTypes;

View File

@ -78,9 +78,6 @@ describe('QemuService', () => {
template_id: '1',
template_type: 'qemu',
usage: '',
replicate_network_connection_state: true,
tpm: false,
uefi: false,
};
service.saveTemplate(server, template).subscribe();
@ -134,9 +131,6 @@ describe('QemuService', () => {
template_id: '',
template_type: 'qemu',
usage: '',
replicate_network_connection_state: true,
tpm: false,
uefi: false,
};
service.addTemplate(server, template).subscribe();

View File

@ -75,9 +75,6 @@ export class TemplateMocksService {
template_id: '',
template_type: 'qemu',
usage: '',
replicate_network_connection_state: true,
tpm: false,
uefi: false,
};
return of(template);
@ -256,7 +253,6 @@ export class TemplateMocksService {
console_http_port: 80,
console_resolution: '1024x768',
console_type: 'telnet',
mac_address: '',
custom_adapters: [],
default_name_format: '{name}-{0}',
environment: '',

View File

@ -38,7 +38,7 @@
<body class="mat-app-background" oncontextmenu="return false;">
<app-root></app-root>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-0BT7QQV1W1"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-5D6FZL9923"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
@ -46,7 +46,7 @@
}
gtag('js', new Date());
gtag('config', 'G-0BT7QQV1W1');
gtag('config', 'G-5D6FZL9923');
</script>
</body>
</html>

742
yarn.lock

File diff suppressed because it is too large Load Diff