Progress screen

This commit is contained in:
ziajka 2018-06-26 16:47:40 +02:00
parent 0cb1b4197a
commit 934c2f9933
18 changed files with 216 additions and 6 deletions

View File

@ -6,7 +6,7 @@ import { RouterModule, Routes } from '@angular/router';
import { ProjectMapComponent } from './project-map/project-map.component';
import { ServersComponent } from "./servers/servers.component";
import { ProjectsComponent } from "./projects/projects.component";
import { DefaultLayoutComponent } from "./default-layout/default-layout.component";
import { DefaultLayoutComponent } from "./layouts/default-layout/default-layout.component";
import { SettingsComponent } from "./settings/settings.component";
import { LocalServerComponent } from "./local-server/local-server.component";

View File

@ -23,7 +23,8 @@ import {
MatListModule,
MatExpansionModule,
MatSortModule,
MatSelectModule
MatSelectModule,
MatTooltipModule
} from '@angular/material';
import { D3Service } from 'd3-ng2-service';
@ -47,7 +48,7 @@ import { ApplianceService } from "./shared/services/appliance.service";
import { LinkService } from "./shared/services/link.service";
import { ProjectsComponent } from './projects/projects.component';
import { DefaultLayoutComponent } from './default-layout/default-layout.component';
import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.component';
import { ProgressDialogComponent } from './shared/progress-dialog/progress-dialog.component';
import { AppComponent } from './app.component';
@ -76,6 +77,8 @@ import { SettingsService } from "./shared/services/settings.service";
import { RavenErrorHandler } from "./raven-error-handler";
import { LocalServerComponent } from './local-server/local-server.component';
import { ProgressComponent } from './progress/progress.component';
import { ProgressService } from "./progress/progress.service";
Raven
.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726')
@ -104,6 +107,7 @@ Raven
ProjectMapShortcutsComponent,
SettingsComponent,
LocalServerComponent,
ProgressComponent,
],
imports: [
NgbModule.forRoot(),
@ -130,6 +134,7 @@ Raven
MatExpansionModule,
MatSortModule,
MatSelectModule,
MatTooltipModule,
CartographyModule,
HotkeyModule.forRoot(),
PersistenceModule,
@ -151,6 +156,7 @@ Raven
SnapshotService,
ProgressDialogService,
ToasterService,
ProgressService,
ProjectWebServiceHandler,
LinksDataSource,
NodesDataSource,

View File

@ -18,6 +18,8 @@
<router-outlet></router-outlet>
</main>
<app-progress></app-progress>
<footer class="footer mat-app-background">
GNS3 Web UI demo &copy; 2018
</footer>

View File

@ -1,16 +1,51 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LocalServerComponent } from './local-server.component';
import { Location } from "@angular/common";
import { RouterTestingModule } from "@angular/router/testing";
import { Router } from "@angular/router";
import { ServerService } from "../shared/services/server.service";
import { MockedServerService } from "../shared/services/server.service.spec";
class MockedLocation {
private _hostname: string;
private _port: number;
get hostname(): string {
return this._hostname;
}
set hostname(hostname: string) {
this._hostname = hostname;
}
get port(): number {
return this._port;
}
set port(port: number) {
this._port = port;
}
}
describe('LocalServerComponent', () => {
let component: LocalServerComponent;
let fixture: ComponentFixture<LocalServerComponent>;
let router: Router;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ RouterTestingModule.withRoutes([]) ],
providers: [
{ provide: Location, useClass: MockedLocation},
{ provide: ServerService, useClass: MockedServerService }
],
declarations: [ LocalServerComponent ]
})
.compileComponents();
router = TestBed.get(Router);
}));
beforeEach(() => {

View File

@ -0,0 +1,8 @@
<div class="overlay" *ngIf="visible">
<div class="loading-spinner">
<mat-spinner color="primary">
</mat-spinner>
</div>
</div>

View File

@ -0,0 +1,18 @@
.overlay {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.5);
z-index: 1000;
}
.loading-spinner {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProgressComponent } from './progress.component';
describe('ProgressComponent', () => {
let component: ProgressComponent;
let fixture: ComponentFixture<ProgressComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ProgressComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProgressComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,22 @@
import { Component, OnInit } from '@angular/core';
import { ProgressService } from "./progress.service";
@Component({
selector: 'app-progress',
templateUrl: './progress.component.html',
styleUrls: ['./progress.component.scss']
})
export class ProgressComponent implements OnInit {
visible = false;
constructor(
private progressService: ProgressService
) { }
ngOnInit() {
this.progressService.state.subscribe((state) => {
this.visible = state.visible;
});
}
}

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { ProgressService } from './progress.service';
describe('ProgressService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ProgressService]
});
});
it('should be created', inject([ProgressService], (service: ProgressService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from "rxjs/BehaviorSubject";
export class State {
public visible: boolean;
constructor(visible: boolean) {
this.visible = visible;
}
}
@Injectable()
export class ProgressService {
state = new BehaviorSubject<State>(new State(false));
constructor() {}
public activate() {
this.state.next(new State(true));
}
public deactivate() {
this.state.next(new State(false));
}
}

View File

@ -17,7 +17,13 @@
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
<mat-cell *matCellDef="let row" style="text-align: right">
<button mat-icon-button (click)="delete(row)" *ngIf="settings.experimental_features">
<button mat-icon-button matTooltip="Open project" (click)="open(row)" *ngIf="row.status == 'closed'">
<mat-icon aria-label="Open project">play_arrow</mat-icon>
</button>
<button mat-icon-button matTooltip="Close project" (click)="close(row)" *ngIf="row.status == 'opened'">
<mat-icon aria-label="Close project">pause</mat-icon>
</button>
<button mat-icon-button matTooltip="Delete project" (click)="delete(row)" *ngIf="settings.experimental_features">
<mat-icon aria-label="Delete project">delete</mat-icon>
</button>
</mat-cell>

View File

@ -10,6 +10,7 @@ import { BehaviorSubject } from "rxjs/BehaviorSubject";
import { DataSource } from "@angular/cdk/collections";
import { Observable } from "rxjs/Observable";
import { SettingsService, Settings } from "../shared/services/settings.service";
import { ProgressService } from "../progress/progress.service";
@Component({
@ -29,7 +30,8 @@ export class ProjectsComponent implements OnInit {
constructor(private route: ActivatedRoute,
private serverService: ServerService,
private projectService: ProjectService,
private settingsService: SettingsService
private settingsService: SettingsService,
private progressService: ProgressService
) {
}
@ -65,6 +67,23 @@ export class ProjectsComponent implements OnInit {
this.projectDatabase.remove(project);
});
}
open(project: Project) {
this.progressService.activate();
this.projectService.open(this.server, project.project_id).subscribe(() => {
}, () => {}, () => {
this.progressService.deactivate();
});
}
close(project: Project) {
this.progressService.activate();
this.projectService.close(this.server, project.project_id).subscribe(() => {}, () => {}, () => {
this.progressService.deactivate();
});
}
}

View File

@ -71,6 +71,16 @@ describe('ProjectService', () => {
expect(req.request.body).toEqual({});
}));
it('should close the project', inject([ProjectService], (service: ProjectService) => {
service.close(server, "myproject").subscribe();
const req = httpTestingController.expectOne(
'http://127.0.0.1:3080/v2/projects/myproject/close');
expect(req.request.method).toEqual("POST");
expect(req.request.body).toEqual({});
}));
it('should list projects', inject([ProjectService], (service: ProjectService) => {
service.list(server).subscribe();

View File

@ -26,6 +26,11 @@ export class ProjectService {
.post<Project>(server, `/projects/${project_id}/open`, {});
}
close(server: Server, project_id: string) {
return this.httpServer
.post<Project>(server, `/projects/${project_id}/close`, {});
}
list(server: Server) {
return this.httpServer
.get<Project[]>(server, '/projects');

View File

@ -1,11 +1,22 @@
import { TestBed, inject } from '@angular/core/testing';
import { ServerService } from './server.service';
import { Server } from "../models/server";
export class MockedServerService {
public getLocalServer(hostname: string, port: number) {
return new Promise((resolve, reject) => {
const server = new Server();
server.id = 99;
resolve(server);
});
}
}
describe('ServerService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ServerService]
providers: [ ServerService ]
});
});