mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-01-02 19:16:44 +00:00
I completed enhancement work #1284 Image manager
This commit is contained in:
parent
9558b2137f
commit
147cae1313
@ -56,6 +56,7 @@ import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.
|
|||||||
import { ServerResolve } from './resolvers/server-resolve';
|
import { ServerResolve } from './resolvers/server-resolve';
|
||||||
import { UserManagementComponent } from './components/user-management/user-management.component';
|
import { UserManagementComponent } from './components/user-management/user-management.component';
|
||||||
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
|
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
|
||||||
|
import { ImageManagerComponent } from '@components/image-manager/image-manager.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -67,6 +68,7 @@ const routes: Routes = [
|
|||||||
{ path: 'bundled', component: BundledServerFinderComponent },
|
{ path: 'bundled', component: BundledServerFinderComponent },
|
||||||
{ path: 'server/:server_id/login', component: LoginComponent },
|
{ path: 'server/:server_id/login', component: LoginComponent },
|
||||||
{ path: 'server/:server_id/loggeduser', component: LoggedUserComponent },
|
{ path: 'server/:server_id/loggeduser', component: LoggedUserComponent },
|
||||||
|
{path : 'server/:server_id/image-manager', component: ImageManagerComponent},
|
||||||
{
|
{
|
||||||
path: 'server/:server_id/projects',
|
path: 'server/:server_id/projects',
|
||||||
component: ProjectsComponent,
|
component: ProjectsComponent,
|
||||||
|
@ -272,6 +272,9 @@ import { HttpRequestsInterceptor } from './interceptors/http.interceptor';
|
|||||||
import { UserManagementComponent } from './components/user-management/user-management.component'
|
import { UserManagementComponent } from './components/user-management/user-management.component'
|
||||||
import { UserService } from './services/user.service';
|
import { UserService } from './services/user.service';
|
||||||
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
|
import { LoggedUserComponent } from './components/users/logged-user/logged-user.component';
|
||||||
|
import { ImageManagerComponent } from './components/image-manager/image-manager.component';
|
||||||
|
import { AddImageDialogComponent } from './components/image-manager/add-image-dialog/add-image-dialog.component';
|
||||||
|
import { DeleteallfilesDialogComponent } from './components/image-manager/deleteallfiles-dialog/deleteallfiles-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -459,7 +462,10 @@ import { LoggedUserComponent } from './components/users/logged-user/logged-user.
|
|||||||
ConfigureCustomAdaptersDialogComponent,
|
ConfigureCustomAdaptersDialogComponent,
|
||||||
EditNetworkConfigurationDialogComponent,
|
EditNetworkConfigurationDialogComponent,
|
||||||
UserManagementComponent,
|
UserManagementComponent,
|
||||||
ProjectReadmeComponent
|
ProjectReadmeComponent,
|
||||||
|
ImageManagerComponent,
|
||||||
|
AddImageDialogComponent,
|
||||||
|
DeleteallfilesDialogComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
<div class="row" style="display: flex;">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<mat-label>Please Select Image</mat-label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 txt-align">
|
||||||
|
<input type="file" accept=".qcow2, .bin,.image,.qcow2,.vmdk,.img" multiple #file class="non-visible"
|
||||||
|
(change)="uploadImageFile($event)" />
|
||||||
|
<button mat-raised-button color="primary" (click)="file.click()" class="file-button">Browse</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 txt-align">
|
||||||
|
<button mat-button (click)="dialogRef.close()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" *ngFor="let img of selectFile; let i = index">
|
||||||
|
<mat-title> {{i+1}}. {{img?.name}} </mat-title>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,65 @@
|
|||||||
|
.progress-bar {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.progress {
|
||||||
|
width: 50px;
|
||||||
|
background-color: #263238;
|
||||||
|
height: 28px;
|
||||||
|
margin-left: 13px;
|
||||||
|
}
|
||||||
|
.mat-input-element {
|
||||||
|
font-size: medium;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
#fileInput {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
opacity: 0;
|
||||||
|
height: 100%;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
.mat-toolbar-single-row {
|
||||||
|
height: auto !important;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.mat-toolbar-single-row button {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
background-color: #ddd;
|
||||||
|
padding: 15px;
|
||||||
|
color: #333;
|
||||||
|
border: #aaa solid 1px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.preview {
|
||||||
|
max-width: 200px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.list-card {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.list-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.non-visible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-progress-bar{
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.txt-align{
|
||||||
|
text-align: end;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AddImageDialogComponent } from './add-image-dialog.component';
|
||||||
|
|
||||||
|
describe('AddImageDialogComponent', () => {
|
||||||
|
let component: AddImageDialogComponent;
|
||||||
|
let fixture: ComponentFixture<AddImageDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ AddImageDialogComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AddImageDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,70 @@
|
|||||||
|
import { Component, 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';
|
||||||
|
import { ImageManagerService } from '../../../services/image-manager.service';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-image-dialog',
|
||||||
|
templateUrl: './add-image-dialog.component.html',
|
||||||
|
styleUrls: ['./add-image-dialog.component.scss'],
|
||||||
|
animations: [
|
||||||
|
trigger('detailExpand', [
|
||||||
|
state('collapsed', style({ height: '0px', minHeight: '0', visibility: 'hidden' })),
|
||||||
|
state('expanded', style({ height: '*', visibility: 'visible' })),
|
||||||
|
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export class AddImageDialogComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
uploadedFile: boolean = false;
|
||||||
|
uploadProgress: number = 0;
|
||||||
|
selectFile: any = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
public dialogRef: MatDialogRef<AddImageDialogComponent>,
|
||||||
|
private imageService: ImageManagerService,
|
||||||
|
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public ngOnInit(): void {
|
||||||
|
this.server = this.data
|
||||||
|
}
|
||||||
|
|
||||||
|
async uploadImageFile(event) {
|
||||||
|
for (let imgFile of event.target.files) {
|
||||||
|
this.selectFile.push(imgFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.upload().subscribe((_) => {
|
||||||
|
console.log(_)
|
||||||
|
this.dialogRef.close('file uploaded');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// files uploading
|
||||||
|
upload() {
|
||||||
|
return new Observable<any>(observe => {
|
||||||
|
this.selectFile.forEach((img, i) => {
|
||||||
|
let resCount = 1
|
||||||
|
try {
|
||||||
|
resCount = resCount + i
|
||||||
|
this.uploadedFile = true;
|
||||||
|
this.imageService.uploadedImage(this.server, img.name, img)
|
||||||
|
.subscribe(() => {
|
||||||
|
this.selectFile.length == resCount ? observe.next() : ''
|
||||||
|
}, (error) => {
|
||||||
|
observe.error(error)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<div *ngIf="!isDelete">
|
||||||
|
<h1 mat-dialog-title>Do you want delete all files ?.</h1>
|
||||||
|
<div mat-dialog-content >
|
||||||
|
<p>Your selected files</p>
|
||||||
|
<p *ngFor="let file of deleteData?.deleteFilesPaths; let i = index">{{i+1}}. {{file?.filename}}</p>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions align="end">
|
||||||
|
<button mat-button (click)="deleteAll()">Delete</button>
|
||||||
|
<button mat-button mat-dialog-close cdkFocusInitial>Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="isDelete">
|
||||||
|
<h1 align="center" mat-dialog-title>Please wait.</h1>
|
||||||
|
|
||||||
|
<div mat-dialog-content align="center">
|
||||||
|
<mat-spinner color="accent"></mat-spinner>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DeleteallfilesDialogComponent } from './deleteallfiles-dialog.component';
|
||||||
|
|
||||||
|
describe('DeleteallfilesDialogComponent', () => {
|
||||||
|
let component: DeleteallfilesDialogComponent;
|
||||||
|
let fixture: ComponentFixture<DeleteallfilesDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ DeleteallfilesDialogComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DeleteallfilesDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
import { ImageManagerService } from '@services/image-manager.service';
|
||||||
|
import { ToasterService } from '@services/toaster.service';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-deleteallfiles-dialog',
|
||||||
|
templateUrl: './deleteallfiles-dialog.component.html',
|
||||||
|
styleUrls: ['./deleteallfiles-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class DeleteallfilesDialogComponent implements OnInit {
|
||||||
|
isDelete: boolean = false;
|
||||||
|
constructor(
|
||||||
|
@Inject(MAT_DIALOG_DATA) public deleteData: any,
|
||||||
|
public dialogRef: MatDialogRef<DeleteallfilesDialogComponent>,
|
||||||
|
private imageService: ImageManagerService,
|
||||||
|
private toasterService: ToasterService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAll() {
|
||||||
|
this.isDelete = true
|
||||||
|
await this.delete().subscribe((_) => {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
this.isDelete = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
delete() {
|
||||||
|
return new Observable<any>(observe => {
|
||||||
|
this.deleteData.deleteFilesPaths.forEach((_, i) => {
|
||||||
|
let imgDeleteCount = 1
|
||||||
|
try {
|
||||||
|
imgDeleteCount = imgDeleteCount + i
|
||||||
|
this.imageService.deleteImage(this.deleteData.server, _.filename).subscribe(
|
||||||
|
() => {
|
||||||
|
this.deleteData.deleteFilesPaths.length === imgDeleteCount ? observe.next() : ''
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.toasterService.error(error)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
this.toasterService.error(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<h1>Image Manager</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 btn-box">
|
||||||
|
<button class="img-btn" mat-button
|
||||||
|
(click)="addImageDialog()">
|
||||||
|
<mat-icon>add</mat-icon> Add Image
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<app-server-discovery></app-server-discovery>
|
||||||
|
|
||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<mat-table #table [dataSource]="dataSource">
|
||||||
|
<ng-container matColumnDef="select">
|
||||||
|
<mat-header-cell *matHeaderCellDef>
|
||||||
|
<mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection.hasValue() && isAllSelected()"
|
||||||
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let row">
|
||||||
|
<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(row) : null"
|
||||||
|
[checked]="selection.isSelected(row)">
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-cell>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="filename">
|
||||||
|
<mat-header-cell *matHeaderCellDef> File Name </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let row">
|
||||||
|
<a class="table-link">{{ row.filename }}</a>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="image_type">
|
||||||
|
<mat-header-cell *matHeaderCellDef> Image Type </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let row"> {{ row.image_type }} </mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="image_size">
|
||||||
|
<mat-header-cell *matHeaderCellDef> Image Size </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let row"> {{ (row.image_size/1000000).toFixed()}} MB </mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="delete" >
|
||||||
|
<mat-header-cell *matHeaderCellDef>
|
||||||
|
<button mat-fab color="primary" *ngIf="selection.hasValue() && isAllSelected()" class="fb-btn" (click)="deleteAllFiles()" aria-label="Example icon button with a delete icon">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let row" >
|
||||||
|
<button mat-fab color="primary" *ngIf="selection.isSelected(row)" class="fb-btn" (click)="deleteFile(row.path)" aria-label="Example icon button with a delete icon">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||||
|
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||||
|
</mat-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,22 @@
|
|||||||
|
.non-visible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-btn{
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.btn-box{
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fb-btn{
|
||||||
|
background-color: #263238 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
mat-header-cell, mat-cell {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ImageManagerComponent } from './image-manager.component';
|
||||||
|
|
||||||
|
describe('ImageManagerComponent', () => {
|
||||||
|
let component: ImageManagerComponent;
|
||||||
|
let fixture: ComponentFixture<ImageManagerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ImageManagerComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ImageManagerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
177
src/app/components/image-manager/image-manager.component.ts
Normal file
177
src/app/components/image-manager/image-manager.component.ts
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ServerService } from '../../services/server.service';
|
||||||
|
import { VersionService } from '../../services/version.service';
|
||||||
|
import { ProgressService } from 'app/common/progress/progress.service';
|
||||||
|
import { Images } from '../../models/images';
|
||||||
|
import { Server } from '../../models/server';
|
||||||
|
import { ImageManagerService } from "../../services/image-manager.service";
|
||||||
|
import { Version } from '../../models/version';
|
||||||
|
import { DataSource, SelectionModel } from '@angular/cdk/collections';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { BehaviorSubject, Observable, Subscription, merge } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
import { AddImageDialogComponent } from './add-image-dialog/add-image-dialog.component';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { ToasterService } from '../../services/toaster.service';
|
||||||
|
import { NotificationService } from '@services/notification.service';
|
||||||
|
import { DeleteallfilesDialogComponent } from './deleteallfiles-dialog/deleteallfiles-dialog.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-image-manager',
|
||||||
|
templateUrl: './image-manager.component.html',
|
||||||
|
styleUrls: ['./image-manager.component.scss']
|
||||||
|
})
|
||||||
|
export class ImageManagerComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
public version: string;
|
||||||
|
dataSource: imageDataSource;
|
||||||
|
imageDatabase = new imageDatabase();
|
||||||
|
isAllDelete: boolean = false
|
||||||
|
selection = new SelectionModel(true, []);
|
||||||
|
|
||||||
|
displayedColumns = ['select', 'filename', 'image_type', 'image_size', 'delete'];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private imageService: ImageManagerService,
|
||||||
|
private progressService: ProgressService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private versionService: VersionService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
let server_id = parseInt(this.route.snapshot.paramMap.get('server_id'));
|
||||||
|
this.serverService.get(server_id).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
if (server.authToken) {
|
||||||
|
this.getImages()
|
||||||
|
}
|
||||||
|
this.versionService.get(this.server).subscribe((version: Version) => {
|
||||||
|
this.version = version.version;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.dataSource = new imageDataSource(this.imageDatabase);
|
||||||
|
}
|
||||||
|
|
||||||
|
getImages() {
|
||||||
|
this.imageService.getSavedImgList(this.server).subscribe(
|
||||||
|
(images: Images[]) => {
|
||||||
|
this.imageDatabase.addImages(images)
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.progressService.setError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFile(path) {
|
||||||
|
this.imageService.deleteImage(this.server, path).subscribe(
|
||||||
|
(res) => {
|
||||||
|
this.getImages()
|
||||||
|
this.unChecked()
|
||||||
|
this.toasterService.success('File deleted');
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.toasterService.error(error)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isAllSelected() {
|
||||||
|
const numSelected = this.selection.selected.length;
|
||||||
|
const numRows = this.imageDatabase.data.length;
|
||||||
|
return numSelected === numRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
masterToggle() {
|
||||||
|
this.isAllSelected() ? this.unChecked() : this.allChecked()
|
||||||
|
}
|
||||||
|
|
||||||
|
unChecked() {
|
||||||
|
this.selection.clear()
|
||||||
|
this.isAllDelete = false
|
||||||
|
}
|
||||||
|
|
||||||
|
allChecked() {
|
||||||
|
this.imageDatabase.data.forEach(row => this.selection.select(row))
|
||||||
|
this.isAllDelete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addImageDialog() {
|
||||||
|
console.log(this.server)
|
||||||
|
const dialogRef = this.dialog.open(AddImageDialogComponent, {
|
||||||
|
width: '750px',
|
||||||
|
maxHeight: '550px',
|
||||||
|
autoFocus: false,
|
||||||
|
disableClose: true,
|
||||||
|
data: this.server
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((answer: string) => {
|
||||||
|
if (answer) {
|
||||||
|
this.getImages()
|
||||||
|
this.toasterService.success('File added');
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteAllFiles() {
|
||||||
|
console.log(this.server)
|
||||||
|
const dialogRef = this.dialog.open(DeleteallfilesDialogComponent, {
|
||||||
|
width: '400px',
|
||||||
|
maxHeight: '350px',
|
||||||
|
autoFocus: false,
|
||||||
|
disableClose: true,
|
||||||
|
data: {
|
||||||
|
server: this.server,
|
||||||
|
deleteFilesPaths: this.imageDatabase.data
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((isAllfilesdeleted: boolean) => {
|
||||||
|
if (isAllfilesdeleted) {
|
||||||
|
this.unChecked()
|
||||||
|
this.getImages()
|
||||||
|
this.toasterService.success('All files deleted');
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class imageDatabase {
|
||||||
|
dataChange: BehaviorSubject<Images[]> = new BehaviorSubject<Images[]>([]);
|
||||||
|
get data(): Images[] {
|
||||||
|
return this.dataChange.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addImages(fliesData: Images[]) {
|
||||||
|
this.dataChange.next(fliesData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class imageDataSource extends DataSource<Images> {
|
||||||
|
constructor(private serverDatabase: imageDatabase) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(): Observable<Images[]> {
|
||||||
|
return merge(this.serverDatabase.dataChange).pipe(
|
||||||
|
map(() => {
|
||||||
|
return this.serverDatabase.data;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() { }
|
||||||
|
}
|
||||||
|
|
@ -103,6 +103,10 @@
|
|||||||
<mat-icon>settings</mat-icon>
|
<mat-icon>settings</mat-icon>
|
||||||
<span>Go to settings</span>
|
<span>Go to settings</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button mat-menu-item [routerLink]="['/server', server.id, 'image-manager']">
|
||||||
|
<mat-icon>collections</mat-icon>
|
||||||
|
<span>Image manager</span>
|
||||||
|
</button>
|
||||||
<button mat-menu-item (click)="addNewTemplate()">
|
<button mat-menu-item (click)="addNewTemplate()">
|
||||||
<mat-icon>control_point</mat-icon>
|
<mat-icon>control_point</mat-icon>
|
||||||
<span>New template</span>
|
<span>New template</span>
|
||||||
|
10
src/app/models/images.ts
Normal file
10
src/app/models/images.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export class Images {
|
||||||
|
filename: string;
|
||||||
|
path: string;
|
||||||
|
image_type: string;
|
||||||
|
image_size: number;
|
||||||
|
checksum: string;
|
||||||
|
checksum_algorithm: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
16
src/app/services/image-manager.service.spec.ts
Normal file
16
src/app/services/image-manager.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ImageManagerService } from './image-manager.service';
|
||||||
|
|
||||||
|
describe('ImageManagerService', () => {
|
||||||
|
let service: ImageManagerService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(ImageManagerService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
23
src/app/services/image-manager.service.ts
Normal file
23
src/app/services/image-manager.service.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Server } from '../models/server';
|
||||||
|
import { HttpServer } from './http-server.service';
|
||||||
|
import { merge, Observable, Subscription } from 'rxjs';
|
||||||
|
import { Images } from "../models/images";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ImageManagerService {
|
||||||
|
|
||||||
|
constructor(private httpServer: HttpServer) { }
|
||||||
|
|
||||||
|
getSavedImgList(server: Server) {
|
||||||
|
return this.httpServer.get<Images[]>(server, '/images') as Observable<Images[]>;
|
||||||
|
}
|
||||||
|
uploadedImage(server:Server, image_path, flie){
|
||||||
|
return this.httpServer.post<Images[]>(server, `/images/upload/${image_path}?install_appliances=true`,flie) as Observable<Images[]>;
|
||||||
|
}
|
||||||
|
deleteImage(server:Server, image_path){
|
||||||
|
return this.httpServer.delete<Images[]>(server, `/images/${image_path}`) as Observable<Images[]>;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user