mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-02-20 17:52:46 +00:00
I have improved progress bar when uploading files
This commit is contained in:
parent
f055836f44
commit
23fe8ae9b8
@ -277,6 +277,7 @@ import { LoggedUserComponent } from './components/users/logged-user/logged-user.
|
||||
import { ImageManagerComponent } from './components/image-manager/image-manager.component';
|
||||
import { AddImageDialogComponent } from './components/image-manager/add-image-dialog/add-image-dialog.component';
|
||||
import { DeleteAllImageFilesDialogComponent } from './components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component';
|
||||
import { UploadingProcessbarComponent } from './common/uploading-processbar/uploading-processbar.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -470,6 +471,7 @@ import { DeleteAllImageFilesDialogComponent } from './components/image-manager/d
|
||||
ImageManagerComponent,
|
||||
AddImageDialogComponent,
|
||||
DeleteAllImageFilesDialogComponent,
|
||||
UploadingProcessbarComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UploadServiceService } from './upload-service.service';
|
||||
|
||||
describe('UploadServiceService', () => {
|
||||
let service: UploadServiceService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(UploadServiceService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UploadServiceService {
|
||||
|
||||
private countSource = new BehaviorSubject(0);
|
||||
currentCount = this.countSource.asObservable();
|
||||
private cancelItem = new BehaviorSubject(false);
|
||||
currentCancelItemDetails = this.cancelItem.asObservable();
|
||||
|
||||
constructor() { }
|
||||
|
||||
processBarCount(processCount:number) {
|
||||
this.countSource.next(processCount)
|
||||
}
|
||||
cancelFileUploading(){
|
||||
this.cancelItem.next(true)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<p>Image Uploading please wait .... {{uploadProgress}}%</p>
|
||||
<div class="row proccessBar-row ">
|
||||
<div class="col-md-9 proccessBar-col">
|
||||
<mat-progress-bar mode="determinate" [value]="uploadProgress" aria-valuemin="0" aria-valuemax="100">
|
||||
</mat-progress-bar>
|
||||
</div>
|
||||
<div class="col-md-3 proccessBar-col">
|
||||
<button mat-button color="primary" (click)="cancelItem()" class="file-button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,11 @@
|
||||
|
||||
.mat-snack-bar-container{
|
||||
min-width: 450px !important;
|
||||
}
|
||||
|
||||
.proccessBar-row{
|
||||
display: flex;
|
||||
}
|
||||
.proccessBar-col{
|
||||
margin: auto;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UploadingProcessbarComponent } from './uploading-processbar.component';
|
||||
|
||||
describe('UploadingProcessbarComponent', () => {
|
||||
let component: UploadingProcessbarComponent;
|
||||
let fixture: ComponentFixture<UploadingProcessbarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ UploadingProcessbarComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UploadingProcessbarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,44 @@
|
||||
import { Component, Inject, OnInit, Renderer2, ViewEncapsulation } from '@angular/core';
|
||||
import { MatSnackBarRef, MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { UploadServiceService } from './upload-service.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-uploading-processbar',
|
||||
templateUrl: './uploading-processbar.component.html',
|
||||
styleUrls: ['./uploading-processbar.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
|
||||
})
|
||||
export class UploadingProcessbarComponent implements OnInit {
|
||||
uploadProgress: number = 0
|
||||
subscription: Subscription;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_SNACK_BAR_DATA) public data,
|
||||
private _snackRef: MatSnackBarRef<UploadingProcessbarComponent>,
|
||||
private _US: UploadServiceService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.subscription = this._US.currentCount.subscribe((count) => {
|
||||
this.uploadProgress = count;
|
||||
if (this.uploadProgress === 100) {
|
||||
this.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
dismiss() {
|
||||
this._snackRef.dismiss();
|
||||
}
|
||||
cancelItem() {
|
||||
this._US.cancelFileUploading()
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
@ -51,7 +51,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div *ngIf="uploadedFile">
|
||||
<mat-progress-bar mode="indeterminate" [value]="uploadProgress" aria-valuemin="0" aria-valuemax="100">
|
||||
<mat-progress-bar mode="determinate" [value]="uploadProgress" aria-valuemin="0" aria-valuemax="100">
|
||||
</mat-progress-bar>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { Component, DoCheck, Inject, OnInit } from '@angular/core';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { Server } from '../../../models/server';
|
||||
@ -20,7 +20,7 @@ import { ImageData } from '../../../models/images';
|
||||
],
|
||||
})
|
||||
|
||||
export class AddImageDialogComponent implements OnInit {
|
||||
export class AddImageDialogComponent implements OnInit,DoCheck {
|
||||
server: Server;
|
||||
uploadedFile: boolean = false;
|
||||
isExistImage: boolean = false;
|
||||
@ -28,7 +28,7 @@ export class AddImageDialogComponent implements OnInit {
|
||||
install_appliance: boolean = false
|
||||
selectFile: any = [];
|
||||
uploadFileMessage: ImageData = []
|
||||
|
||||
uploadProgress:number = 0
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
public dialogRef: MatDialogRef<AddImageDialogComponent>,
|
||||
@ -58,10 +58,19 @@ export class AddImageDialogComponent implements OnInit {
|
||||
this.selectFile.forEach(imgElement => {
|
||||
calls.push(this.imageService.uploadedImage(this.server, this.install_appliance, imgElement.name, imgElement).pipe(catchError(error => of(error))))
|
||||
});
|
||||
this.uploadProgress = calls.length
|
||||
Observable.forkJoin(calls).subscribe(responses => {
|
||||
this.uploadFileMessage = responses
|
||||
this.uploadedFile = false;
|
||||
this.isExistImage = true;
|
||||
});
|
||||
}
|
||||
ngDoCheck(){
|
||||
setTimeout(() => {
|
||||
if(this.uploadProgress < 95){
|
||||
this.uploadProgress = this.uploadProgress + 1
|
||||
}
|
||||
}, 100000);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -103,9 +103,7 @@
|
||||
placeholder="Please enter name"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<div *ngIf="uploadedFile">
|
||||
<mat-progress-bar mode="determinate" [value]="uploadProgress" aria-valuemin="0" aria-valuemax="100"></mat-progress-bar>
|
||||
</div>
|
||||
<!-- here removed the processbar and common processbar -->
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UploadServiceService } from '../../../../common/uploading-processbar/upload-service.service';
|
||||
import { UploadingProcessbarComponent } from 'app/common/uploading-processbar/uploading-processbar.component';
|
||||
import { FileItem, FileUploader, FileUploaderOptions, ParsedResponseHeaders } from 'ng2-file-upload';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { Compute } from '../../../../models/compute';
|
||||
@ -51,7 +54,9 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
||||
private formBuilder: FormBuilder,
|
||||
private templateMocksService: TemplateMocksService,
|
||||
private configurationService: QemuConfigurationService,
|
||||
private computeService: ComputeService
|
||||
private computeService: ComputeService,
|
||||
private snackBar : MatSnackBar,
|
||||
private uploadServiceService : UploadServiceService
|
||||
) {
|
||||
this.qemuTemplate = new QemuTemplate();
|
||||
|
||||
@ -91,6 +96,8 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
||||
|
||||
this.uploader.onProgressItem = (progress: any) => {
|
||||
this.uploadProgress = progress['progress'];
|
||||
this.uploadServiceService.processBarCount(this.uploadProgress)
|
||||
|
||||
};
|
||||
|
||||
const server_id = this.route.snapshot.paramMap.get('server_id');
|
||||
@ -117,6 +124,14 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
||||
this.consoleTypes = this.configurationService.getConsoleTypes();
|
||||
});
|
||||
|
||||
this.uploadServiceService.currentCancelItemDetails.subscribe((isCancel) => {
|
||||
if (isCancel) {
|
||||
this.cancelUploading()
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
setServerType(serverType: string) {
|
||||
@ -131,7 +146,7 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
||||
|
||||
uploadImageFile(event) {
|
||||
|
||||
this.uploadedFile = true;
|
||||
// this.uploadedFile = true;
|
||||
let name = event.target.files[0].name;
|
||||
this.diskForm.controls['fileName'].setValue(name);
|
||||
|
||||
@ -142,7 +157,13 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
||||
|
||||
if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; ((itemToUpload as any).options.headers =[{name:'Authorization',value:'Bearer ' + this.server.authToken}])
|
||||
this.uploader.uploadItem(itemToUpload);
|
||||
this.snackBar.openFromComponent(UploadingProcessbarComponent,{panelClass: 'uplaoding-file-snackabar',});
|
||||
}
|
||||
|
||||
cancelUploading() {
|
||||
this.uploader.clearQueue();
|
||||
this.uploadServiceService.processBarCount(100)
|
||||
this.toasterService.warning('Image Uploading canceled');
|
||||
}
|
||||
|
||||
goBack() {
|
||||
@ -171,4 +192,6 @@ export class AddQemuVmTemplateComponent implements OnInit {
|
||||
this.toasterService.error(`Fill all required fields`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -154,7 +154,7 @@
|
||||
>
|
||||
<mat-icon aria-label="Refresh list of images">refresh</mat-icon></button
|
||||
><br />
|
||||
<div>
|
||||
<div>
|
||||
<div *ngFor="let version of applianceToInstall.versions">
|
||||
<div class="list-item">
|
||||
<span>{{ applianceToInstall.name }} version {{ version.name }}</span>
|
||||
@ -225,6 +225,7 @@
|
||||
[uploader]="uploaderImage"
|
||||
/>
|
||||
<button class="button" mat-raised-button (click)="file2.click()">Import</button>
|
||||
|
||||
<button
|
||||
class="button"
|
||||
mat-raised-button
|
||||
|
@ -2,9 +2,11 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
|
||||
import { ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
import { MatStepper } from '@angular/material/stepper';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { UploadingProcessbarComponent } from 'app/common/uploading-processbar/uploading-processbar.component';
|
||||
import { FileItem, FileUploader, ParsedResponseHeaders } from 'ng2-file-upload';
|
||||
import * as SparkMD5 from 'spark-md5';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
@ -29,6 +31,7 @@ import { TemplateService } from '../../../services/template.service';
|
||||
import { ToasterService } from '../../../services/toaster.service';
|
||||
import { ApplianceInfoDialogComponent } from './appliance-info-dialog/appliance-info-dialog.component';
|
||||
import { TemplateNameDialogComponent } from './template-name-dialog/template-name-dialog.component';
|
||||
import { UploadServiceService } from '../../../common/uploading-processbar/upload-service.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-new-template-dialog',
|
||||
@ -75,6 +78,7 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
private iouImages: Image[] = [];
|
||||
|
||||
private templates: Template[] = [];
|
||||
uploadProgress: number = 0;
|
||||
|
||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||
@ViewChild('stepper', { static: true }) stepper: MatStepper;
|
||||
@ -92,7 +96,9 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
public dialog: MatDialog,
|
||||
private computeService: ComputeService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private progressService: ProgressService
|
||||
private progressService: ProgressService,
|
||||
public snackBar: MatSnackBar,
|
||||
private uploadServiceService: UploadServiceService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
@ -195,6 +201,18 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
this.uploaderImage.clearQueue();
|
||||
};
|
||||
|
||||
this.uploaderImage.onProgressItem = (progress: any) => {
|
||||
this.uploadProgress = progress['progress'];
|
||||
this.uploadServiceService.processBarCount(this.uploadProgress)
|
||||
};
|
||||
|
||||
this.uploadServiceService.currentCancelItemDetails.subscribe((isCancel) => {
|
||||
if (isCancel) {
|
||||
this.cancelUploading()
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
updateAppliances() {
|
||||
@ -213,7 +231,6 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
}
|
||||
|
||||
refreshImages() {
|
||||
|
||||
this.qemuService.getImages(this.server).subscribe((qemuImages) => {
|
||||
this.qemuImages = qemuImages;
|
||||
});
|
||||
@ -353,8 +370,9 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
dialogRef.componentInstance.appliance = object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
importImage(event, imageName) {
|
||||
this.progressService.activate();
|
||||
this.computeChecksumMd5(event.target.files[0], false).then((output) => {
|
||||
let imageToInstall = this.applianceToInstall.images.filter((n) => n.filename === imageName)[0];
|
||||
|
||||
@ -371,12 +389,14 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
dialogRef.afterClosed().subscribe((answer: boolean) => {
|
||||
if (answer) {
|
||||
this.importImageFile(event);
|
||||
this.openSnackBar()
|
||||
} else {
|
||||
this.uploaderImage.clearQueue();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.importImageFile(event);
|
||||
this.openSnackBar()
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -400,12 +420,17 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
if ((itemToUpload as any).options) (itemToUpload as any).options.disableMultipart = true; ((itemToUpload as any).options.headers = [{ name: 'Authorization', value: 'Bearer ' + this.server.authToken }])
|
||||
|
||||
this.uploaderImage.uploadItem(itemToUpload);
|
||||
this.progressService.activate();
|
||||
};
|
||||
|
||||
fileReader.readAsText(file);
|
||||
}
|
||||
|
||||
cancelUploading() {
|
||||
this.uploaderImage.clearQueue();
|
||||
this.uploadServiceService.processBarCount(100)
|
||||
this.toasterService.warning('Image imported canceled');
|
||||
}
|
||||
|
||||
checkImageFromVersion(image: string): boolean {
|
||||
let imageToInstall = this.applianceToInstall.images.filter((n) => n.filename === image)[0];
|
||||
if (this.applianceToInstall.qemu) {
|
||||
@ -510,7 +535,6 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
dialogRef.afterClosed().subscribe((answer: string) => {
|
||||
if (answer) {
|
||||
iouTemplate.name = answer;
|
||||
|
||||
this.iouService.addTemplate(this.server, iouTemplate).subscribe((template) => {
|
||||
this.templateService.newTemplateCreated.next(template);
|
||||
this.toasterService.success('Template added');
|
||||
@ -697,6 +721,13 @@ export class NewTemplateDialogComponent implements OnInit {
|
||||
processChunk(0);
|
||||
});
|
||||
}
|
||||
|
||||
openSnackBar() {
|
||||
this.snackBar.openFromComponent(UploadingProcessbarComponent, {
|
||||
panelClass: 'uplaoding-file-snackabar',
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function compareNames(a: string, b: string, isAsc: boolean) {
|
||||
|
@ -15,6 +15,14 @@ export class ImageManagerService {
|
||||
return this.httpServer.get<Image[]>(server, '/images') as Observable<Image[]>;
|
||||
}
|
||||
|
||||
getImagePath(server:Server, install_appliance, image_path){
|
||||
return `${server.protocol}//${server.host}:${server.port}/v3/images/upload/${image_path}?install_appliances=${install_appliance}`;
|
||||
}
|
||||
|
||||
getUploadPath(server: Server, emulator: string, filename: string) {
|
||||
return `${server.protocol}//${server.host}:${server.port}/v3/images/upload/${filename}`;
|
||||
}
|
||||
|
||||
uploadedImage(server:Server, install_appliance, image_path, flie){
|
||||
return this.httpServer.post<Image[]>(server, `/images/upload/${image_path}?install_appliances=${install_appliance}`,flie) as Observable<Image[]>;
|
||||
}
|
||||
|
@ -14,6 +14,11 @@ a.table-link {
|
||||
background: #0097a7 !important;
|
||||
color: white !important;
|
||||
}
|
||||
.uplaoding-file-snackabar {
|
||||
background: #263238 !important;
|
||||
color: white !important;
|
||||
max-width: 80% !important;
|
||||
}
|
||||
|
||||
.snackbar-warning {
|
||||
background: rgb(197, 199, 64) !important;
|
||||
|
Loading…
x
Reference in New Issue
Block a user