Merge branch 'master' into e2e

This commit is contained in:
piotrpekala7 2020-02-28 14:07:50 +01:00
commit 0d1739e63e
12 changed files with 99 additions and 35 deletions

View File

@ -61,6 +61,7 @@ import { PageNotFoundComponent } from './components/page-not-found/page-not-foun
import { Gns3vmComponent } from './components/preferences/gns3vm/gns3vm.component';
import { DirectLinkComponent } from './components/direct-link/direct-link.component';
import { SystemStatusComponent } from './components/system-status/system-status.component';
import { ProjectMapGuard } from './guards/project-map-guard';
const routes: Routes = [
{
@ -140,7 +141,9 @@ const routes: Routes = [
]
},
{
path: 'server/:server_id/project/:project_id', component: ProjectMapComponent,
path: 'server/:server_id/project/:project_id',
component: ProjectMapComponent,
canActivate: [ProjectMapGuard]
},
{
path: '**',
@ -149,7 +152,7 @@ const routes: Routes = [
];
@NgModule({
imports: [RouterModule.forRoot(routes, { anchorScrolling: 'enabled', scrollPositionRestoration: 'enabled'})],
imports: [RouterModule.forRoot(routes, { anchorScrolling: 'enabled', enableTracing: true, scrollPositionRestoration: 'enabled'})],
exports: [RouterModule]
})
export class AppRoutingModule {}

View File

@ -8,6 +8,7 @@ import { PersistenceService } from 'angular-persistence';
import { ElectronService, NgxElectronModule } from 'ngx-electron';
import createSpyObj = jasmine.createSpyObj;
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ProgressService } from './common/progress/progress.service';
describe('AppComponent', () => {
let component: AppComponent;
@ -19,7 +20,7 @@ describe('AppComponent', () => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [RouterTestingModule, MatIconModule, NgxElectronModule],
providers: [SettingsService, PersistenceService],
providers: [SettingsService, PersistenceService, ProgressService],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

View File

@ -4,6 +4,8 @@ import { DomSanitizer } from '@angular/platform-browser';
import { ElectronService } from 'ngx-electron';
import { SettingsService } from './services/settings.service';
import { ThemeService } from './services/theme.service';
import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
import { ProgressService } from './common/progress/progress.service';
@Component({
selector: 'app-root',
@ -16,10 +18,16 @@ export class AppComponent implements OnInit {
sanitizer: DomSanitizer,
private settingsService: SettingsService,
private electronService: ElectronService,
private themeService: ThemeService
private themeService: ThemeService,
private router: Router,
private progressService: ProgressService
) {
iconReg.addSvgIcon('gns3', sanitizer.bypassSecurityTrustResourceUrl('./assets/gns3_icon.svg'));
iconReg.addSvgIcon('gns3black', sanitizer.bypassSecurityTrustResourceUrl('./assets/gns3_icon_black.svg'));
router.events.subscribe((value) => {
this.checkEvent(value);
});
}
ngOnInit(): void {
@ -35,4 +43,16 @@ export class AppComponent implements OnInit {
this.themeService.setDarkMode(true);
}
}
checkEvent(routerEvent) : void {
if (routerEvent instanceof NavigationStart) {
this.progressService.activate();
}
else if (routerEvent instanceof NavigationEnd ||
routerEvent instanceof NavigationCancel ||
routerEvent instanceof NavigationError) {
this.progressService.deactivate();
}
}
}

View File

@ -266,6 +266,7 @@ import { StatusChartComponent } from './components/system-status/status-chart/st
import { NgCircleProgressModule } from 'ng-circle-progress';
import { OpenFileExplorerActionComponent } from './components/project-map/context-menu/actions/open-file-explorer/open-file-explorer-action.component';
import { NgxChildProcessModule } from 'ngx-childprocess';
import { ProjectMapGuard } from './guards/project-map-guard';
if (environment.production) {
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
@ -539,6 +540,7 @@ if (environment.production) {
Gns3vmService,
ThemeService,
GoogleAnalyticsService,
ProjectMapGuard,
Title
],
entryComponents: [

View File

@ -1,4 +1,4 @@
import { Component, ViewChild, ElementRef, OnInit, Input, EventEmitter, OnDestroy, Renderer2 } from '@angular/core';
import { Component, ViewChild, ElementRef, OnInit, Input, EventEmitter, OnDestroy, Renderer2, NgZone } from '@angular/core';
import { DrawingsEventSource } from '../../events/drawings-event-source';
import { TextAddedDataEvent, TextEditedDataEvent } from '../../events/event-source';
import { ToolsService } from '../../../services/tools.service';
@ -55,7 +55,8 @@ export class TextEditorComponent implements OnInit, OnDestroy {
private linksDataSource: LinksDataSource,
private nodesDataSource: NodesDataSource,
private selectionManager: SelectionManager,
private fontFixer: FontFixer
private fontFixer: FontFixer,
private ngZone: NgZone
) {}
ngOnInit() {
@ -63,8 +64,8 @@ export class TextEditorComponent implements OnInit, OnDestroy {
isActive ? this.activateTextAdding() : this.deactivateTextAdding();
});
this.activateTextEditingForDrawings();
this.activateTextEditingForNodeLabels();
this.ngZone.runOutsideAngular(this.activateTextEditingForDrawings.bind(this));
this.ngZone.runOutsideAngular(this.activateTextEditingForNodeLabels.bind(this));
}
activateTextAdding() {

View File

@ -17,6 +17,7 @@ export class ShowNodeActionComponent {
showNode() {
const dialogRef = this.dialog.open(InfoDialogComponent, {
width: '600px',
maxHeight: '600px',
autoFocus: false,
disableClose: true
});

View File

@ -73,6 +73,8 @@ export class ProjectsComponent implements OnInit {
this.settings = this.settingsService.getAll();
this.projectService.projectListSubject.subscribe(() => this.refresh());
let gns3vmConfig = localStorage.getItem('gns3vmConfig');
if (this.electronService.isElectronApp && gns3vmConfig!=='configured') {
const dialogRef = this.dialog.open(ConfigureGns3VMDialogComponent, {

View File

@ -0,0 +1,35 @@
import { Injectable } from "@angular/core";
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { ProjectMapComponent } from '../components/project-map/project-map.component';
import { Observable, pipe, timer, from } from 'rxjs';
import { ProjectService } from '../services/project.service';
import { Server } from '../models/server';
import { ServerService } from '../services/server.service';
import { switchMap, map } from 'rxjs/operators';
import { ToasterService } from '../services/toaster.service';
@Injectable()
export class ProjectMapGuard implements CanActivate {
constructor(
private projectService: ProjectService,
private serverService: ServerService,
private toasterService: ToasterService
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
const server_id = route.paramMap.get("server_id");
const project_id = route.paramMap.get("project_id");
return from(this.serverService.get(parseInt(server_id, 10))).pipe(
switchMap(response => this.projectService.list(response as Server)),
map(response => {
let projectToOpen = response.find(n => n.project_id === project_id);
if (projectToOpen) return true;
this.toasterService.error('Project could not be opened');
this.projectService.projectListUpdated();
return false;
})
)
}
}

View File

@ -67,7 +67,7 @@ export class InfoService {
node.node_type === "iou") {
return 'Command line information is not supported for this type of node.';
} else {
if (node.status === 'started') {
if (node.command_line) {
return node.command_line;
} else {
return 'Please start the node in order to get the command line information.';

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { Project } from '../models/project';
import { Node } from '../cartography/models/node';
import { Observable } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { Link } from '../models/link';
import { Server } from '../models/server';
import { HttpServer } from './http-server.service';
@ -10,8 +10,14 @@ import { SettingsService } from './settings.service';
@Injectable()
export class ProjectService {
public projectListSubject = new Subject<boolean>();
constructor(private httpServer: HttpServer, private settingsService: SettingsService) {}
projectListUpdated() {
this.projectListSubject.next(true);
}
get(server: Server, project_id: string) {
return this.httpServer.get<Project>(server, `/projects/${project_id}`);
}

View File

@ -8,6 +8,7 @@ import { getTestServer } from './testing';
import { SymbolService } from './symbol.service';
import { Symbol } from '../models/symbol';
import { AppTestingModule } from '../testing/app-testing/app-testing.module';
import { of } from 'rxjs';
describe('SymbolService', () => {
let httpClient: HttpClient;
@ -50,20 +51,11 @@ describe('SymbolService', () => {
}));
it('should load symbols', inject([SymbolService], (service: SymbolService) => {
service.load(server).subscribe();
spyOn(service, 'load').and.returnValue(of([]));
const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/symbols');
service.list(server).subscribe();
req.flush([{ symbol_id: 'myid' }]);
const raw = httpTestingController.expectOne('http://127.0.0.1:3080/v2/symbols/myid/raw');
raw.flush('myraw');
service.symbols.subscribe(symbols => {
expect(symbols.length).toEqual(1);
expect(symbols[0].symbol_id).toEqual('myid');
expect(symbols[0].raw).toEqual('myraw');
});
expect(service.load).toHaveBeenCalled();
}));
it('should get symbols', inject([SymbolService], (service: SymbolService) => {

View File

@ -1,13 +1,17 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, forkJoin, Observable } from 'rxjs';
import { BehaviorSubject, forkJoin, Observable, of } from 'rxjs';
import { Symbol } from '../models/symbol';
import { Server } from '../models/server';
import { HttpServer } from './http-server.service';
import { shareReplay } from 'rxjs/operators';
const CACHE_SIZE = 1;
@Injectable()
export class SymbolService {
public symbols: BehaviorSubject<Symbol[]> = new BehaviorSubject<Symbol[]>([]);
private cache: Observable<Symbol[]>;
constructor(private httpServer: HttpServer) {}
@ -16,25 +20,22 @@ export class SymbolService {
}
add(server: Server, symbolName: string, symbol: string) {
this.cache = null;
return this.httpServer.post(server, `/symbols/${symbolName}/raw`, symbol)
}
load(server: Server): Observable<Symbol[]> {
const subscription = this.list(server).subscribe((symbols: Symbol[]) => {
const streams = symbols.map(symbol => this.raw(server, symbol.symbol_id));
forkJoin(streams).subscribe(results => {
symbols.forEach((symbol: Symbol, i: number) => {
symbol.raw = results[i];
});
this.symbols.next(symbols);
subscription.unsubscribe();
});
});
return this.symbols.asObservable();
return this.httpServer.get<Symbol[]>(server, '/symbols');
}
list(server: Server) {
return this.httpServer.get<Symbol[]>(server, '/symbols');
if(!this.cache) {
this.cache = this.load(server).pipe(
shareReplay(CACHE_SIZE)
);
}
return this.cache;
}
raw(server: Server, symbol_id: string) {