mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-06-06 01:01:33 +00:00
Merge branch 'master' into Improvements-for-adding-nodes
This commit is contained in:
commit
f8c798340e
@ -65,12 +65,14 @@
|
|||||||
"ini": "^1.3.5",
|
"ini": "^1.3.5",
|
||||||
"material-design-icons": "^3.0.1",
|
"material-design-icons": "^3.0.1",
|
||||||
"ng2-file-upload": "^1.3.0",
|
"ng2-file-upload": "^1.3.0",
|
||||||
|
"ngx-device-detector": "^1.3.16",
|
||||||
"ngx-electron": "^2.1.1",
|
"ngx-electron": "^2.1.1",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"notosans-fontface": "^1.1.0",
|
"notosans-fontface": "^1.1.0",
|
||||||
"raven-js": "^3.27.2",
|
"raven-js": "^3.27.2",
|
||||||
"rxjs": "^6.5.3",
|
"rxjs": "^6.5.3",
|
||||||
"rxjs-compat": "^6.5.3",
|
"rxjs-compat": "^6.5.3",
|
||||||
|
"save-html-as-image": "^1.2.0",
|
||||||
"save-svg-as-png": "^1.4.14",
|
"save-svg-as-png": "^1.4.14",
|
||||||
"svg-crowbar": "^0.2.4",
|
"svg-crowbar": "^0.2.4",
|
||||||
"tree-kill": "^1.2.1",
|
"tree-kill": "^1.2.1",
|
||||||
@ -118,4 +120,4 @@
|
|||||||
"typescript"
|
"typescript"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,6 +250,9 @@ import { AlignHorizontallyActionComponent } from './components/project-map/conte
|
|||||||
import { AlignVerticallyActionComponent } from './components/project-map/context-menu/actions/align_vertically/align-vertically.component';
|
import { AlignVerticallyActionComponent } from './components/project-map/context-menu/actions/align_vertically/align-vertically.component';
|
||||||
import { ConfirmationBottomSheetComponent } from './components/projects/confirmation-bottomsheet/confirmation-bottomsheet.component';
|
import { ConfirmationBottomSheetComponent } from './components/projects/confirmation-bottomsheet/confirmation-bottomsheet.component';
|
||||||
import { TemplateFilter } from './filters/templateFilter.pipe';
|
import { TemplateFilter } from './filters/templateFilter.pipe';
|
||||||
|
import { NotificationService } from './services/notification.service';
|
||||||
|
import { DeviceDetectorModule } from 'ngx-device-detector';
|
||||||
|
import { ConfigDialogComponent } from './components/project-map/context-menu/dialogs/config-dialog/config-dialog.component';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||||
@ -422,7 +425,8 @@ if (environment.production) {
|
|||||||
PageNotFoundComponent,
|
PageNotFoundComponent,
|
||||||
AlignHorizontallyActionComponent,
|
AlignHorizontallyActionComponent,
|
||||||
AlignVerticallyActionComponent,
|
AlignVerticallyActionComponent,
|
||||||
ConfirmationBottomSheetComponent
|
ConfirmationBottomSheetComponent,
|
||||||
|
ConfigDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -441,7 +445,8 @@ if (environment.production) {
|
|||||||
ResizableModule,
|
ResizableModule,
|
||||||
DragAndDropModule,
|
DragAndDropModule,
|
||||||
DragDropModule,
|
DragDropModule,
|
||||||
MATERIAL_IMPORTS
|
MATERIAL_IMPORTS,
|
||||||
|
DeviceDetectorModule.forRoot()
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
SettingsService,
|
SettingsService,
|
||||||
@ -506,7 +511,8 @@ if (environment.production) {
|
|||||||
InfoService,
|
InfoService,
|
||||||
ComputeService,
|
ComputeService,
|
||||||
TracengService,
|
TracengService,
|
||||||
PacketCaptureService
|
PacketCaptureService,
|
||||||
|
NotificationService
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
AddServerDialogComponent,
|
AddServerDialogComponent,
|
||||||
@ -546,7 +552,8 @@ if (environment.production) {
|
|||||||
ChooseNameDialogComponent,
|
ChooseNameDialogComponent,
|
||||||
NavigationDialogComponent,
|
NavigationDialogComponent,
|
||||||
ScreenshotDialogComponent,
|
ScreenshotDialogComponent,
|
||||||
ConfirmationBottomSheetComponent
|
ConfirmationBottomSheetComponent,
|
||||||
|
ConfigDialogComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<svg #svg class="map" preserveAspectRatio="none" movingCanvas zoomingCanvas>
|
<svg id="map" #svg class="map" preserveAspectRatio="none" movingCanvas zoomingCanvas>
|
||||||
<filter id="grayscale"><feColorMatrix id="feGrayscale" type="saturate" values="0" /></filter>
|
<filter id="grayscale"><feColorMatrix id="feGrayscale" type="saturate" values="0" /></filter>
|
||||||
<defs>
|
<defs>
|
||||||
<pattern id="gridDrawing" attr.width="{{project.drawing_grid_size}}" attr.height="{{project.drawing_grid_size}}" patternUnits="userSpaceOnUse">
|
<pattern id="gridDrawing" attr.width="{{project.drawing_grid_size}}" attr.height="{{project.drawing_grid_size}}" patternUnits="userSpaceOnUse">
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -28,7 +28,7 @@ export class AdbutlerComponent implements OnInit {
|
|||||||
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);
|
||||||
},
|
},
|
||||||
error => this.toasterService.error(error)
|
error => {}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ import { Component, Input } from '@angular/core';
|
|||||||
import { Node } from '../../../../../cartography/models/node';
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
import { NodeService } from '../../../../../services/node.service';
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
import { ConfigDialogComponent } from '../../dialogs/config-dialog/config-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-export-config-action',
|
selector: 'app-export-config-action',
|
||||||
@ -12,13 +14,33 @@ export class ExportConfigActionComponent {
|
|||||||
@Input() node: Node;
|
@Input() node: Node;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private nodeService: NodeService
|
private nodeService: NodeService,
|
||||||
|
private dialog: MatDialog
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
exportConfig() {
|
exportConfig() {
|
||||||
this.nodeService.getStartupConfiguration(this.server, this.node).subscribe((config: any) => {
|
if (this.node.node_type === 'vpcs') {
|
||||||
this.downloadByHtmlTag(config);
|
this.nodeService.getStartupConfiguration(this.server, this.node).subscribe((config: any) => {
|
||||||
});
|
this.downloadByHtmlTag(config);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const dialogRef = this.dialog.open(ConfigDialogComponent, {
|
||||||
|
width: '500px',
|
||||||
|
autoFocus: false
|
||||||
|
});
|
||||||
|
let instance = dialogRef.componentInstance;
|
||||||
|
dialogRef.afterClosed().subscribe((configType: string) => {
|
||||||
|
if (configType === 'startup-config') {
|
||||||
|
this.nodeService.getStartupConfiguration(this.server, this.node).subscribe((config: any) => {
|
||||||
|
this.downloadByHtmlTag(config);
|
||||||
|
});
|
||||||
|
} else if (configType === 'private-config') {
|
||||||
|
this.nodeService.getPrivateConfiguration(this.server, this.node).subscribe((config: any) => {
|
||||||
|
this.downloadByHtmlTag(config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private downloadByHtmlTag(config: string) {
|
private downloadByHtmlTag(config: string) {
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<button mat-menu-item (click)="importConfig()">
|
<input
|
||||||
|
type="file"
|
||||||
|
accept=".txt, .vpc"
|
||||||
|
class="non-visible"
|
||||||
|
#fileInput
|
||||||
|
(change)="importConfig($event)"/>
|
||||||
|
<button mat-menu-item (click)="triggerClick()">
|
||||||
<mat-icon>call_received</mat-icon>
|
<mat-icon>call_received</mat-icon>
|
||||||
<span>Import config</span>
|
<span>Import config</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.non-visible {
|
||||||
|
display: none;
|
||||||
|
}
|
@ -1,19 +1,64 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input, ViewChild, ElementRef } from '@angular/core';
|
||||||
import { Node } from '../../../../../cartography/models/node';
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
import { NodeService } from '../../../../../services/node.service';
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
import { ConfigDialogComponent } from '../../dialogs/config-dialog/config-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-import-config-action',
|
selector: 'app-import-config-action',
|
||||||
templateUrl: './import-config-action.component.html'
|
templateUrl: './import-config-action.component.html',
|
||||||
|
styleUrls: ['./import-config-action.component.scss']
|
||||||
})
|
})
|
||||||
export class ImportConfigActionComponent {
|
export class ImportConfigActionComponent {
|
||||||
@Input() server: Server;
|
@Input() server: Server;
|
||||||
@Input() node: Node;
|
@Input() node: Node;
|
||||||
|
@ViewChild('fileInput', {static: false}) fileInput: ElementRef;
|
||||||
|
configType: string;
|
||||||
|
|
||||||
constructor() {}
|
constructor(
|
||||||
|
private nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private dialog: MatDialog
|
||||||
|
) {}
|
||||||
|
|
||||||
importConfig() {
|
triggerClick() {
|
||||||
//needs implementation
|
if (this.node.node_type !== 'vpcs') {
|
||||||
|
const dialogRef = this.dialog.open(ConfigDialogComponent, {
|
||||||
|
width: '500px',
|
||||||
|
autoFocus: false
|
||||||
|
});
|
||||||
|
let instance = dialogRef.componentInstance;
|
||||||
|
dialogRef.afterClosed().subscribe((configType: string) => {
|
||||||
|
this.configType = configType;
|
||||||
|
this.fileInput.nativeElement.click();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.configType = 'startup-config';
|
||||||
|
this.fileInput.nativeElement.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
importConfig(event) {
|
||||||
|
let file: File = event.target.files[0];
|
||||||
|
let fileReader: FileReader = new FileReader();
|
||||||
|
fileReader.onload = (e) => {
|
||||||
|
let content: string | ArrayBuffer = fileReader.result;
|
||||||
|
if (typeof content !== 'string'){
|
||||||
|
content = content.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.configType === 'startup-config') {
|
||||||
|
this.nodeService.saveConfiguration(this.server, this.node, content).subscribe(() => {
|
||||||
|
this.toasterService.success(`Configuration for node ${this.node.name} imported.`);
|
||||||
|
});
|
||||||
|
} else if (this.configType === 'private-config') {
|
||||||
|
this.nodeService.savePrivateConfiguration(this.server, this.node, content).subscribe(() => {
|
||||||
|
this.toasterService.success(`Configuration for node ${this.node.name} imported.`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileReader.readAsText(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,14 @@
|
|||||||
[project]="project"
|
[project]="project"
|
||||||
[node]="nodes[0]"
|
[node]="nodes[0]"
|
||||||
></app-edit-config-action>
|
></app-edit-config-action>
|
||||||
<app-export-config-action *ngIf="nodes.length===1 && nodes[0].node_type==='vpcs'"
|
<app-export-config-action *ngIf="nodes.length===1 && (nodes[0].node_type==='vpcs' || nodes[0].node_type==='iou' || nodes[0].node_type==='dynamips')"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
[node]="nodes[0]"
|
[node]="nodes[0]"
|
||||||
></app-export-config-action>
|
></app-export-config-action>
|
||||||
<!-- <app-import-config-action *ngIf="nodes.length===1"
|
<app-import-config-action *ngIf="nodes.length===1 && (nodes[0].node_type==='vpcs' || nodes[0].node_type==='iou' || nodes[0].node_type==='dynamips')"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
[node]="nodes[0]"
|
[node]="nodes[0]"
|
||||||
></app-import-config-action> -->
|
></app-import-config-action>
|
||||||
<app-move-layer-up-action
|
<app-move-layer-up-action
|
||||||
*ngIf="!projectService.isReadOnly(project) && (drawings.length || nodes.length)"
|
*ngIf="!projectService.isReadOnly(project) && (drawings.length || nodes.length)"
|
||||||
[server]="server"
|
[server]="server"
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
<h1 mat-dialog-title>Choose configuration file</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="container">
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="close('startup-config')">
|
||||||
|
startup configuration
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="close('private-config')">
|
||||||
|
private configuration
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,5 @@
|
|||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-config-dialog',
|
||||||
|
templateUrl: './config-dialog.component.html',
|
||||||
|
styleUrls: ['./config-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfigDialogComponent {
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfigDialogComponent>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
close(fileType: string) {
|
||||||
|
this.dialogRef.close(fileType);
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import downloadSvg from 'svg-crowbar';
|
|||||||
import { ElectronService } from 'ngx-electron';
|
import { ElectronService } from 'ngx-electron';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
import { ScreenshotDialogComponent, Screenshot } from '../screenshot-dialog/screenshot-dialog.component';
|
import { ScreenshotDialogComponent, Screenshot } from '../screenshot-dialog/screenshot-dialog.component';
|
||||||
|
import { saveAsPng, saveAsJpeg } from 'save-html-as-image';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -56,6 +56,7 @@ import { MockedActivatedRoute } from '../snapshots/list-of-snapshots/list-of-sna
|
|||||||
import { MapNodesDataSource, MapLinksDataSource, MapDrawingsDataSource, MapSymbolsDataSource } from '../../cartography/datasources/map-datasource';
|
import { MapNodesDataSource, MapLinksDataSource, MapDrawingsDataSource, MapSymbolsDataSource } from '../../cartography/datasources/map-datasource';
|
||||||
import { EthernetLinkWidget } from '../../cartography/widgets/links/ethernet-link';
|
import { EthernetLinkWidget } from '../../cartography/widgets/links/ethernet-link';
|
||||||
import { SerialLinkWidget } from '../../cartography/widgets/links/serial-link';
|
import { SerialLinkWidget } from '../../cartography/widgets/links/serial-link';
|
||||||
|
import { NotificationService } from '../../services/notification.service';
|
||||||
|
|
||||||
export class MockedProgressService {
|
export class MockedProgressService {
|
||||||
public activate() {}
|
public activate() {}
|
||||||
@ -298,7 +299,8 @@ describe('ProjectMapComponent', () => {
|
|||||||
{ provide: MapLinksDataSource, useClass: LinksDataSource },
|
{ provide: MapLinksDataSource, useClass: LinksDataSource },
|
||||||
{ provide: MapDrawingsDataSource, useClass: MapDrawingsDataSource },
|
{ provide: MapDrawingsDataSource, useClass: MapDrawingsDataSource },
|
||||||
{ provide: MapSymbolsDataSource, useClass: MapSymbolsDataSource },
|
{ provide: MapSymbolsDataSource, useClass: MapSymbolsDataSource },
|
||||||
{ provide: MapSettingsService, useClass: MapSettingsService }
|
{ provide: MapSettingsService, useClass: MapSettingsService },
|
||||||
|
{ provide: NotificationService }
|
||||||
],
|
],
|
||||||
declarations: [ProjectMapComponent, ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS],
|
declarations: [ProjectMapComponent, ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
@ -64,6 +64,7 @@ import { SerialLinkWidget } from '../../cartography/widgets/links/serial-link';
|
|||||||
import { NavigationDialogComponent } from '../projects/navigation-dialog/navigation-dialog.component';
|
import { NavigationDialogComponent } from '../projects/navigation-dialog/navigation-dialog.component';
|
||||||
import { ConfirmationBottomSheetComponent } from '../projects/confirmation-bottomsheet/confirmation-bottomsheet.component';
|
import { ConfirmationBottomSheetComponent } from '../projects/confirmation-bottomsheet/confirmation-bottomsheet.component';
|
||||||
import { NodeAddedEvent } from '../template/template-list-dialog/template-list-dialog.component';
|
import { NodeAddedEvent } from '../template/template-list-dialog/template-list-dialog.component';
|
||||||
|
import { NotificationService } from '../../services/notification.service';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -79,6 +80,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
public symbols: Symbol[] = [];
|
public symbols: Symbol[] = [];
|
||||||
public project: Project;
|
public project: Project;
|
||||||
public server: Server;
|
public server: Server;
|
||||||
|
public projectws: WebSocket;
|
||||||
public ws: WebSocket;
|
public ws: WebSocket;
|
||||||
public isProjectMapMenuVisible: boolean = false;
|
public isProjectMapMenuVisible: boolean = false;
|
||||||
public isConsoleVisible: boolean = true;
|
public isConsoleVisible: boolean = true;
|
||||||
@ -147,7 +149,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
private mapSettingsService: MapSettingsService,
|
private mapSettingsService: MapSettingsService,
|
||||||
private ethernetLinkWidget: EthernetLinkWidget,
|
private ethernetLinkWidget: EthernetLinkWidget,
|
||||||
private serialLinkWidget: SerialLinkWidget,
|
private serialLinkWidget: SerialLinkWidget,
|
||||||
private bottomSheet: MatBottomSheet
|
private bottomSheet: MatBottomSheet,
|
||||||
|
private notificationService: NotificationService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -312,25 +315,29 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.drawingsDataSource.set(drawings);
|
this.drawingsDataSource.set(drawings);
|
||||||
|
|
||||||
this.setUpMapCallbacks();
|
this.setUpMapCallbacks();
|
||||||
this.setUpWS(project);
|
this.setUpProjectWS(project);
|
||||||
|
|
||||||
this.progressService.deactivate();
|
this.progressService.deactivate();
|
||||||
});
|
});
|
||||||
this.subscriptions.push(subscription);
|
this.subscriptions.push(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
setUpWS(project: Project) {
|
setUpProjectWS(project: Project) {
|
||||||
this.ws = new WebSocket(this.projectService.notificationsPath(this.server, project.project_id));
|
this.projectws = new WebSocket(this.projectService.notificationsPath(this.server, project.project_id));
|
||||||
|
|
||||||
this.ws.onmessage = (event: MessageEvent) => {
|
this.projectws.onmessage = (event: MessageEvent) => {
|
||||||
this.projectWebServiceHandler.handleMessage(JSON.parse(event.data));
|
this.projectWebServiceHandler.handleMessage(JSON.parse(event.data));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.ws.onerror = (event: MessageEvent) => {
|
this.projectws.onerror = (event: MessageEvent) => {
|
||||||
this.toasterService.error('Connection to host lost.');
|
this.toasterService.error('Connection to host lost.');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setUpWS() {
|
||||||
|
this.ws = new WebSocket(this.notificationService.notificationsPath(this.server));
|
||||||
|
}
|
||||||
|
|
||||||
setUpMapCallbacks() {
|
setUpMapCallbacks() {
|
||||||
if (!this.readonly) {
|
if (!this.readonly) {
|
||||||
this.toolsService.selectionToolActivation(true);
|
this.toolsService.selectionToolActivation(true);
|
||||||
@ -812,8 +819,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.nodesDataSource.clear();
|
this.nodesDataSource.clear();
|
||||||
this.linksDataSource.clear();
|
this.linksDataSource.clear();
|
||||||
|
|
||||||
if (this.ws.OPEN) {
|
if (this.projectws) {
|
||||||
this.ws.close();
|
if (this.projectws.OPEN) this.projectws.close();
|
||||||
|
}
|
||||||
|
if (this.ws) {
|
||||||
|
if (this.ws.OPEN) this.ws.close();
|
||||||
}
|
}
|
||||||
this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
|
this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<h1 mat-dialog-title>Take a screenshot</h1>
|
<h1 mat-dialog-title>Take a screenshot</h1>
|
||||||
|
|
||||||
<!-- <mat-radio-group class="radio-group" aria-label="Sorting">
|
<mat-radio-group class="radio-group" aria-label="Sorting">
|
||||||
<mat-radio-button value="1" (click)="setFiletype('svg')" checked>SVG</mat-radio-button>
|
<mat-radio-button value="1" (click)="setFiletype('svg')" checked>SVG</mat-radio-button>
|
||||||
<mat-radio-button [disabled]="!isPngAvailable" value="2" (click)="setFiletype('png')">PNG</mat-radio-button>
|
<mat-radio-button [disabled]="!isPngAvailable" value="2" (click)="setFiletype('png')">PNG</mat-radio-button>
|
||||||
</mat-radio-group> -->
|
</mat-radio-group>
|
||||||
|
|
||||||
<form [formGroup]="nameForm" class="name-form">
|
<form [formGroup]="nameForm" class="name-form">
|
||||||
<mat-form-field class="name-form">
|
<mat-form-field class="name-form">
|
||||||
|
@ -3,6 +3,7 @@ import { MatDialogRef } from '@angular/material';
|
|||||||
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
import { ToasterService } from '../../../services/toaster.service';
|
import { ToasterService } from '../../../services/toaster.service';
|
||||||
import { ElectronService } from 'ngx-electron';
|
import { ElectronService } from 'ngx-electron';
|
||||||
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -19,13 +20,13 @@ export class ScreenshotDialogComponent implements OnInit {
|
|||||||
public dialogRef: MatDialogRef<ScreenshotDialogComponent>,
|
public dialogRef: MatDialogRef<ScreenshotDialogComponent>,
|
||||||
private toasterService: ToasterService,
|
private toasterService: ToasterService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private electronService: ElectronService
|
private electronService: ElectronService,
|
||||||
|
private deviceService: DeviceDetectorService
|
||||||
) {
|
) {
|
||||||
this.nameForm = this.formBuilder.group({
|
this.nameForm = this.formBuilder.group({
|
||||||
screenshotName: new FormControl(null, [Validators.required])
|
screenshotName: new FormControl(null, [Validators.required])
|
||||||
});
|
});
|
||||||
|
this.isPngAvailable = this.electronService.isWindows || (this.deviceService.getDeviceInfo().os==='Windows');
|
||||||
this.isPngAvailable = this.electronService.isWindows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
@ -22,6 +22,7 @@ import { ProjectsFilter } from '../../filters/projectsFilter.pipe';
|
|||||||
import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component';
|
import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component';
|
||||||
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
||||||
import { OverlayRef } from '@angular/cdk/overlay';
|
import { OverlayRef } from '@angular/cdk/overlay';
|
||||||
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
|
|
||||||
describe('ProjectsComponent', () => {
|
describe('ProjectsComponent', () => {
|
||||||
let component: ProjectsComponent;
|
let component: ProjectsComponent;
|
||||||
@ -53,6 +54,7 @@ describe('ProjectsComponent', () => {
|
|||||||
{ provide: ServerService, useClass: MockedServerService },
|
{ provide: ServerService, useClass: MockedServerService },
|
||||||
{ provide: ProjectService, useValue: mockedProjectService },
|
{ provide: ProjectService, useValue: mockedProjectService },
|
||||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
{ provide: SettingsService, useClass: MockedSettingsService },
|
||||||
|
{ provide: ToasterService },
|
||||||
ProgressService
|
ProgressService
|
||||||
],
|
],
|
||||||
declarations: [ProjectsComponent, ChooseNameDialogComponent, ProjectsFilter],
|
declarations: [ProjectsComponent, ChooseNameDialogComponent, ProjectsFilter],
|
||||||
|
@ -19,6 +19,7 @@ import { AddBlankProjectDialogComponent } from './add-blank-project-dialog/add-b
|
|||||||
import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component';
|
import { ChooseNameDialogComponent } from './choose-name-dialog/choose-name-dialog.component';
|
||||||
import { NavigationDialogComponent } from './navigation-dialog/navigation-dialog.component';
|
import { NavigationDialogComponent } from './navigation-dialog/navigation-dialog.component';
|
||||||
import { ConfirmationBottomSheetComponent } from './confirmation-bottomsheet/confirmation-bottomsheet.component';
|
import { ConfirmationBottomSheetComponent } from './confirmation-bottomsheet/confirmation-bottomsheet.component';
|
||||||
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-projects',
|
selector: 'app-projects',
|
||||||
@ -44,7 +45,8 @@ export class ProjectsComponent implements OnInit {
|
|||||||
private progressService: ProgressService,
|
private progressService: ProgressService,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private bottomSheet: MatBottomSheet
|
private bottomSheet: MatBottomSheet,
|
||||||
|
private toasterService: ToasterService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -100,7 +102,11 @@ export class ProjectsComponent implements OnInit {
|
|||||||
() => {
|
() => {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
},
|
},
|
||||||
() => {},
|
() => {
|
||||||
|
this.refresh();
|
||||||
|
this.progressService.deactivate();
|
||||||
|
this.toasterService.error('Project was deleted.');
|
||||||
|
},
|
||||||
() => {
|
() => {
|
||||||
this.progressService.deactivate();
|
this.progressService.deactivate();
|
||||||
}
|
}
|
||||||
|
12
src/app/services/notification.service.ts
Normal file
12
src/app/services/notification.service.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpServer } from './http-server.service';
|
||||||
|
import { Server } from '../models/server';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class NotificationService {
|
||||||
|
constructor(private httpServer: HttpServer) {}
|
||||||
|
|
||||||
|
notificationsPath(server: Server): string {
|
||||||
|
return `ws://${server.host}:${server.port}/v2/notifications/ws`;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user