You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by dg...@apache.org on 2020/04/27 14:10:33 UTC
[incubator-dlab] branch bucket-browser-gcp updated: [Dlab 1551]:
Fixed bug file download (#708)
This is an automated email from the ASF dual-hosted git repository.
dgnatyshyn pushed a commit to branch bucket-browser-gcp
in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
The following commit(s) were added to refs/heads/bucket-browser-gcp by this push:
new 3b3a0fe [Dlab 1551]: Fixed bug file download (#708)
3b3a0fe is described below
commit 3b3a0fea00f6f0e4d4f92cdd63913d1e02afbf1f
Author: Dmytro Gnatyshyn <42...@users.noreply.github.com>
AuthorDate: Mon Apr 27 17:10:24 2020 +0300
[Dlab 1551]: Fixed bug file download (#708)
[DLAB-1551]: Bucket browser on UI
---
.../administration/project/project.component.ts | 1 -
.../core/interceptors/http.token.interceptor.ts | 10 +-
.../src/app/core/services/appRouting.service.ts | 1 +
.../services/applicationServiceFacade.service.ts | 21 ++--
.../app/core/services/bucket-browser.service.ts | 95 +----------------
.../webapp/src/app/core/util/fileUtils.ts | 10 ++
.../bucket-browser/bucket-browser.component.html | 29 +++---
.../bucket-browser/bucket-browser.component.scss | 16 +++
.../bucket-browser/bucket-browser.component.ts | 107 +++++++------------
.../bucket-browser/bucket-data.service.ts | 108 ++++++++++++++++++++
.../folder-tree/folder-tree.component.ts | 113 ++++++++++++---------
.../detail-dialog/detail-dialog.component.html | 4 +-
.../detail-dialog/detail-dialog.component.ts | 4 +-
.../webapp/src/app/resources/resources.module.ts | 3 +
14 files changed, 292 insertions(+), 230 deletions(-)
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
index 9833a40..ef71ca7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
@@ -96,7 +96,6 @@ export class ProjectComponent implements OnInit, OnDestroy {
if (this.projectList.length)
this.dialog.open(EditProjectComponent, { data: { action: 'create', item: null }, panelClass: 'modal-xl-s' })
.afterClosed().subscribe(() => {
- console.log('Create project');
this.getEnvironmentHealthStatus();
});
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/interceptors/http.token.interceptor.ts b/services/self-service/src/main/resources/webapp/src/app/core/interceptors/http.token.interceptor.ts
index 29aa010..9d72d0b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/interceptors/http.token.interceptor.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/interceptors/http.token.interceptor.ts
@@ -33,7 +33,15 @@ import { Observable } from 'rxjs';
if (token)
headersConfig['Authorization'] = `Bearer ${token}`;
- if (!request.headers.has('Content-Type') && !request.headers.has('Upload') && request.url.indexOf('upload') === -1)
+ // if (request.url.indexOf('api/bucket') !== -1) {
+ // headersConfig['Authorization'] = `Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJfSEVvZmliX2djZXJpcllidE51dVBoSk81OEJNOFc5M1dHZW9VR3hTR2l3In0.eyJqdGkiOiIxY2E4OTQ1OS02MDU5LTQzOTctYTZhMy1kMzY5YTY0OTkyNzIiLCJleHAiOjE1ODc5OTUyNjgsIm5iZiI6MCwiaWF0IjoxNTg3OTk0OTY4LCJpc3MiOiJodHRwczovL2lkcC5kZW1vLmRsYWJhbmFseXRpY3MuY29tL2F1dGgvcmVhbG1zL2RsYWIiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNWIwYWEwMmYtYTU3ZS00MGM0LTk4ODQtNDlmYmU5OGViMzU4IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoib2Z1a3MtMTMwNC11aSIsIm [...]
+ // }
+
+ if (!request.headers.has('Content-Type')
+ && !request.headers.has('Upload')
+ && request.url.indexOf('upload') === -1
+ && request.url.indexOf('download') === -1)
+
headersConfig['Content-Type'] = 'application/json; charset=UTF-8';
const header = request.clone({ setHeaders: headersConfig });
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
index 1a80759..0f05bcb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
@@ -34,6 +34,7 @@ export class AppRoutingService {
}
redirectToHomePage(): void {
+ console.log('redirect');
this.router.navigate(['/resources_list']);
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
index ebaec6d..792b748 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
@@ -22,7 +22,6 @@ import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { Dictionary } from '../collections';
-
import { environment } from '../../../environments/environment';
import { HTTPMethod } from '../util';
@@ -254,10 +253,11 @@ export class ApplicationServiceFacade {
null);
}
- public buildGetBucketData(): Observable<any> {
+
+ public buildGetBucketData(data): Observable<any> {
return this.buildRequest(HTTPMethod.GET,
- this.requestRegistry.Item(ApplicationServiceFacade.BUCKET) + '/ofuks-1304-prj1-local-bucket/endpoint/local',
- null);
+ this.requestRegistry.Item(ApplicationServiceFacade.BUCKET),
+ data);
}
public buildUploadFileToBucket(data): Observable<any> {
@@ -266,10 +266,12 @@ export class ApplicationServiceFacade {
data);
}
- public buildDownloadFileFromBucket(data): Observable<any> {
+ public buildDownloadFileFromBucket(data) {
return this.buildRequest(HTTPMethod.GET,
this.requestRegistry.Item(ApplicationServiceFacade.BUCKET),
- data, { observe: 'response', responseType: 'text' } );
+ data, { dataType : 'binary',
+ processData : false,
+ responseType : 'arraybuffer' } );
}
public buildDeleteFileFromBucket(data): Observable<any> {
@@ -722,6 +724,9 @@ export class ApplicationServiceFacade {
private buildRequest(method: HTTPMethod, url_path: string, body: any, opt?) {
// added to simplify development process
const url = environment.production ? url_path : API_URL + url_path;
+ // if (url_path.indexOf('/api/bucket') !== -1) {
+ // url = 'https://35.233.183.55' + url_path;
+ // }
if (method === HTTPMethod.POST) {
return this.http.post(url, body, opt);
@@ -729,6 +734,8 @@ export class ApplicationServiceFacade {
return this.http.delete(body ? url + JSON.parse(body) : url, opt);
} else if (method === HTTPMethod.PUT) {
return this.http.put(url, body, opt);
- } else return this.http.get(body ? (url + body) : url, opt);
+ } else {
+ return this.http.get(body ? (url + body) : url, opt);
+ }
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/bucket-browser.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/bucket-browser.service.ts
index ff27ef5..0cb8557 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/bucket-browser.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/bucket-browser.service.ts
@@ -1,8 +1,11 @@
import { Injectable } from '@angular/core';
-import {BehaviorSubject, Observable} from 'rxjs';
+
+import {Observable} from 'rxjs';
import {catchError, map} from 'rxjs/operators';
import {ErrorUtils} from '../util';
import {ApplicationServiceFacade} from './applicationServiceFacade.service';
+import {insideWorkspace} from '@angular/cli/utilities/project';
+
export class TodoItemNode {
children: TodoItemNode[];
@@ -11,46 +14,12 @@ export class TodoItemNode {
size: number;
}
-/** Flat to-do item node with expandable and level information */
export class TodoItemFlatNode {
item: string;
level: number;
expandable: boolean;
}
-/**
- * The Json object for to-do list data.
- */
-
-
-const array = [{'bucket': 'ofuks-1304-prj1-local-bucket', 'object': '4.txt', 'size': '18 bytes', 'creationDate': '21-4-2020 11:36:36'}, {'bucket': 'ofuks-1304-prj1-local-bucket', 'object': '5.txt', 'size': '18 bytes', 'creationDate': '21-4-2020 11:56:46'}, {'bucket': 'ofuks-1304-prj1-local-bucket', 'object': 'Untitled', 'size': '5 bytes', 'creationDate': '13-4-2020 03:39:11'}, {'bucket': 'ofuks-1304-prj1-local-bucket', 'object': 'adasdas', 'size': '1 KB', 'creationDate': '15-4-2020 02:17 [...]
-
-const processFiles = (files, target) => {
- let pointer = target;
- files.forEach((file, index) => {
- if (!pointer[file]) {
- pointer[file] = {};
- }
- pointer = pointer[file];
- });
-
-};
-
-const processFolderArray = (acc, curr) => {
- const files = curr.object.split('/').filter(x => x.length > 0);
- processFiles(files, acc);
- return acc;
-};
-
-const convertToFolderTree = (data) => data
- .reduce(
- processFolderArray,
- {}
- );
-
-const TREE_DATA = convertToFolderTree(array);
-
-
@Injectable({
providedIn: 'root'
})
@@ -71,58 +40,6 @@ export class BucketBrowserService {
catchError(ErrorUtils.handleServiceError));
}
- public initialize() {
- let backetData = [];
- this.getBacketData().subscribe(v => {
- this.serverData = v;
- backetData = convertToFolderTree(v);
- const data = this.buildFileTree({'ofuks-1304-prj1-local-bucket': backetData}, 0);
- this.dataChange.next(data);
- });
- // this.serverData = array;
- // backetData = convertToFolderTree(this.serverData);
- // const data = this.buildFileTree({'ofuks-1304-prj1-local-bucket': backetData}, 0);
- // this.dataChange.next(data);
- }
-
- /**
- * Build the file structure tree. The `value` is the Json object, or a sub-tree of a Json object.
- * The return value is the list of `TodoItemNode`.
- */
- public buildFileTree(obj: {[key: string]: any}, level: number): TodoItemNode[] {
- return Object.keys(obj).reduce<TodoItemNode[]>((accumulator, key) => {
- const value = obj[key];
- const node = new TodoItemNode();
- node.item = key;
- if (Object.keys(value).length) {
- if (typeof value === 'object') {
- node.children = this.buildFileTree(value, level + 1);
- } else {
- node.item = value;
- }
- } else {
- node.size = this.serverData.filter(v => v.object.indexOf(node.item) !== -1)[0];
- }
- return accumulator.concat(node);
- }, []);
- }
-
- public insertItem(parent: TodoItemNode, name, isFile) {
- if (parent.children) {
- if (isFile) {
- parent.children.push(name as TodoItemNode);
- } else {
- parent.children.unshift({item: name, children: []} as TodoItemNode);
- this.dataChange.next(this.data);
- }
- }
- }
-
- public updateItem(node: TodoItemNode, file) {
- node.item = file;
- this.dataChange.next(this.data);
- }
-
public downloadFile(data) {
return this.applicationServiceFacade
.buildDownloadFileFromBucket(data)
@@ -147,7 +64,5 @@ export class BucketBrowserService {
map(response => response),
catchError(ErrorUtils.handleServiceError));
}
- // initBucket(bucketType) {
- // bucketType !== 'project' ? TREE_DATA = local : TREE_DATA = projecta;
- // }
+
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/fileUtils.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/fileUtils.ts
index 98ec0f5..d1c2628 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/fileUtils.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/fileUtils.ts
@@ -37,6 +37,16 @@ export class FileUtils {
window.URL.revokeObjectURL(url);
}
+ public static downloadBigFiles(data, fileName) {
+ const a = document.createElement('a');
+ document.body.appendChild(a);
+ const blob = new Blob([data], { type: 'octet/stream' }),
+ url = window.URL.createObjectURL(blob);
+ a.href = url;
+ a.download = fileName;
+ a.click();
+ window.URL.revokeObjectURL(url);
+ }
public static copyToClipboard(val: string) {
const selBox = document.createElement('textarea');
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html
index 8671562..3feda30 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html
@@ -22,7 +22,8 @@
<h4 class="modal-title">Bucket browser</h4>
<button type="button" class="close" (click)="dialogRef.close()">×</button>
</header>
- <div class="dialog-content tabs">
+
+ <div class="dialog-content tabs" [hidden]="!path" >
<div class="submit m-bott-10 m-top-10">
<button mat-raised-button type="button" class="butt action"><input type="file" (change)="handleFileInput($event)">Add file</button>
<button mat-raised-button type="button" class="butt action" (click)="folderTreeComponent.addNewItem(selectedFolder, '', false)">Create folder</button>
@@ -52,10 +53,10 @@
<span class="item-name">{{file.item}}</span>
</div>
<div class="size">{{file.size.size}}</div>
- <div class="size">{{file.size.creationDate }}</div>
-<!-- <div class="progress-wrapper">-->
-<!--<!– <div class="progres" *ngIf="file.isSelected"><div class="bar"></div></div>–>-->
-<!-- </div>-->
+ <div class="size" *ngIf="!file.isDownloading">{{file.size.lastModifiedDate }}</div>
+ <div class="progress-wrapper" *ngIf="file.isDownloading">
+ <mat-progress-bar mode="indeterminate"></mat-progress-bar>
+ </div>
</div>
</li>
@@ -64,15 +65,9 @@
<li *ngFor="let file of addedFiles" class="folder-item">
<div class="folder-item-wrapper">
<div class="name">{{file.item}}</div>
- <div class="size">{{file.size}} MB</div>
+ <div class="size">{{file.size}}MB</div>
<div class="progress-wrapper">
-<!-- <div class="progres">-->
-<!-- <div class="bar" [ngClass]="{'full': isUploading}">-->
-<!-- -->
-<!-- </div>-->
-
-<!-- </div>-->
- <mat-progress-bar mode="indeterminate" *ngIf="isUploading"></mat-progress-bar>
+ <mat-progress-bar mode="indeterminate" *ngIf="isUploading"></mat-progress-bar>
</div>
<div (click)="deleteAddedFile(file)"><i class="material-icons close">close</i></div>
</div>
@@ -87,4 +82,12 @@
<button *ngIf="this.addedFiles.length !== 0" type="button" class="butt butt-success" mat-raised-button (click)="uploadNewFile()">Upload</button>
</div>
</div>
+
+ <div class="loading-block" *ngIf="!path">
+ <div class="uploading">
+ <p>Please wait until DLab loads bucket: <span class="strong">{{data.bucket}}</span>...</p>
+ <mat-progress-bar mode="indeterminate"></mat-progress-bar>
+ </div>
+ </div>
+
</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.scss
index b9033da..bb16184 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.scss
@@ -18,6 +18,22 @@
*/
.bucket-browser {
+ .loading-block{
+ width: 80%;
+ margin: 20% auto 0 auto;
+ display: flex;
+ align-content: center;
+ justify-content: center;
+ height: 100%;
+ .uploading{
+ width: 100%;
+ text-align: center;
+ p{
+ margin-bottom: 20px;
+ }
+ }
+ }
+
.path{
margin: 0 4px 10px 4px;
padding: 4px 4px 4px 20px;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
index fef7d0d..04b2d3f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
@@ -26,6 +26,12 @@ import { ManageUngitService } from '../../core/services';
import {FolderTreeComponent} from './folder-tree/folder-tree.component';
import {BucketBrowserService, TodoItemNode} from '../../core/services/bucket-browser.service';
import {FileUtils} from '../../core/util';
+import {BucketDataService} from './bucket-data.service';
+import FileSaver from 'file-saver';
+import {HttpErrorResponse, HttpEventType} from '@angular/common/http';
+import {catchError, map} from 'rxjs/operators';
+import {of} from 'rxjs';
+
@Component({
selector: 'dlab-bucket-browser',
@@ -33,7 +39,6 @@ import {FileUtils} from '../../core/util';
styleUrls: ['./bucket-browser.component.scss']
})
export class BucketBrowserComponent implements OnInit {
- public filenames: Array<any> = [];
public addedFiles = [];
public folderItems = [];
public path = '';
@@ -55,13 +60,14 @@ export class BucketBrowserComponent implements OnInit {
private manageUngitService: ManageUngitService,
private _fb: FormBuilder,
private bucketBrowserService: BucketBrowserService,
+ private bucketDataService: BucketDataService,
private formBuilder: FormBuilder
) {
}
ngOnInit() {
- // this.bucketBrowserService.getBacketData();
+ this.bucketDataService.refreshBucketdata(this.data.bucket, this.data.endpoint);
this.endpoint = this.data.endpoint;
this.uploadForm = this.formBuilder.group({
file: ['']
@@ -74,54 +80,46 @@ export class BucketBrowserComponent implements OnInit {
}
public handleFileInput(event) {
- // for (let i = 0; i < files.length; i++) {
- // const file = files[i];
- // const path = file.webkitRelativePath.split('/');
- // }
- // }
if (event.target.files.length > 0) {
const file = event.target.files[0];
this.uploadForm.get('file').setValue(file);
- this.filenames = Object['values'](event.target.files).map(v => ({item: v.name, 'size': (v.size / 1048576).toFixed(2)} as unknown as TodoItemNode));
- this.addedFiles = [...this.addedFiles, ...this.filenames];
+ const newAddedFiles = Object['values'](event.target.files).map(v => (
+ {item: v['name'], 'size': (v['size'] / 1048576).toFixed(2)} as unknown as TodoItemNode ));
+ this.addedFiles = [...newAddedFiles];
}
-
}
+
public toggleSelectedFile(file) {
+ // remove if when will be possible download several files
+ if (!file.isSelected) {
+ this.folderItems.forEach(item => item.isSelected = false);
+ }
+
file.isSelected = !file.isSelected;
this.selected = this.folderItems.filter(item => item.isSelected);
}
filesPicked(files) {
- // console.log(files);
Array.prototype.forEach.call(files, file => {
this.addedFiles.push(file.webkitRelativePath);
});
- // console.log(this.addedFiles);
}
public onFolderClick(event) {
this.selectedFolder = event.flatNode;
this.folderItems = event.element ? event.element.children : event.children;
- // this.folderItems = this.folderItems.sort((a, b) => (a.children > b.children) ? 1 : -1)
- // console.log(this.folderItems);
- this.path = event.path;
- this.pathInsideBucket = this.path.indexOf('/') !== -1 ? this.path.slice(this.path.indexOf('/') + 1) + '/' : '';
- this.bucketName = this.path.substring(0, this.path.indexOf('/')) || this.path;
- this.folderItems.forEach(item => item.isSelected = false);
- }
+ if (this.folderItems) {
+ const folders = this.folderItems.filter(v => v.children).sort((a, b) => a.item > b.item ? 1 : -1);
+ const files = this.folderItems.filter(v => !v.children).sort((a, b) => a.item > b.item ? 1 : -1);
+ this.folderItems = [...folders, ...files];
+ this.path = event.path;
+ this.pathInsideBucket = this.path.indexOf('/') !== -1 ? this.path.slice(this.path.indexOf('/') + 1) + '/' : '';
+ this.bucketName = this.path.substring(0, this.path.indexOf('/')) || this.path;
+ this.folderItems.forEach(item => item.isSelected = false);
+ }
- private upload(tree, path) {
- tree.files.forEach(file => {
- this.addedFiles.push(path + file.name);
- });
- tree.directories.forEach(directory => {
- const newPath = path + directory.name + '/';
- this.addedFiles.push(newPath);
- this.upload(directory, newPath);
- });
}
public deleteAddedFile(file) {
@@ -134,31 +132,12 @@ export class BucketBrowserComponent implements OnInit {
const formData = new FormData();
formData.append('file', this.uploadForm.get('file').value);
formData.append('object', path);
- formData.append('bucket', 'ofuks-1304-prj1-local-bucket');
- formData.append('endpoint', this.endpoint);
- // file.inProgress = true;
+ formData.append('bucket', this.bucketName);
+ formData.append('endpoint', this.endpoint);
this.isUploading = true;
this.bucketBrowserService.uploadFile(formData)
- // .pipe(
- // map(event => {
- // switch (event.type) {
- // case HttpEventType.UploadProgress:
- // file.progress = Math.round(event.loaded * 100 / event.total);
- // break;
- // case HttpEventType.Response:
- // return event;
- // }
- // }),
- // catchError((error: HttpErrorResponse) => {
- // file.inProgress = false;
- // return of(`${file.name} upload failed.`);
- // }))
.subscribe((event: any) => {
- // if (typeof (event) === 'object') {
- // console.log(event.body);
- // }
- // this.isUploading = false;
- this.bucketBrowserService.initialize();
+ this.bucketDataService.refreshBucketdata(this.data.bucket, this.data.endpoint);
this.addedFiles = [];
this.isUploading = false;
this.toastr.success('File successfully uploaded!', 'Success!');
@@ -168,37 +147,29 @@ export class BucketBrowserComponent implements OnInit {
public fileAction(action) {
this.selected = this.folderItems.filter(item => item.isSelected);
+ const selected = this.folderItems.filter(item => item.isSelected)[0];
const path = encodeURIComponent(`${this.pathInsideBucket}${this.selected[0].item}`);
if (action === 'download') {
- this.bucketBrowserService.downloadFile(`/${this.bucketName}/object/${path}/endpoint/${this.endpoint}/download`
- ).subscribe(data => {
- FileUtils.downloadFile(data);
- // this.downLoadFile(response, 'aplication/octet-stream');
- this.toastr.success('File downloading started!', 'Success!');
+ selected['isDownloading'] = true;
+ this.bucketBrowserService.downloadFile(`/${this.bucketName}/object/${path}/endpoint/${this.endpoint}/download`)
+ .subscribe(data => {
+ FileUtils.downloadBigFiles(data, selected.item);
+ selected['isDownloading'] = false;
+ this.folderItems.forEach(item => item.isSelected = false);
}, error => this.toastr.error(error.message || 'File downloading error!', 'Oops!')
);
}
if (action === 'delete') {
this.bucketBrowserService.deleteFile(`/${this.bucketName}/object/${path}/endpoint/${this.endpoint}`).subscribe(() => {
- this.bucketBrowserService.initialize();
+
+ this.bucketDataService.refreshBucketdata(this.data.bucket, this.data.endpoint);
this.toastr.success('File successfully deleted!', 'Success!');
+ this.folderItems.forEach(item => item.isSelected = false);
}, error => this.toastr.error(error.message || 'File deleting error!', 'Oops!')
);
}
-
- this.folderItems.forEach(item => item.isSelected = false);
- this.selected = this.folderItems.filter(item => item.isSelected);
}
-
- // downLoadFile(data: any, type: string) {
- // const blob = new Blob([data], { type: type});
- // const url = window.URL.createObjectURL(blob);
- // const pwa = window.open(url);
- // if (!pwa || pwa.closed || typeof pwa.closed === 'undefined') {
- // alert( 'Please disable your Pop-up blocker and try again.');
- // }
- // }
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-data.service.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-data.service.ts
new file mode 100644
index 0000000..7a169e5
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-data.service.ts
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, of } from 'rxjs';
+import {BucketBrowserService, TodoItemNode} from '../../core/services/bucket-browser.service';
+
+const array = [{'bucket': 'ofuks-1304-prj1-local-bucket', 'object': '4.txt', 'size': '18 bytes', 'creationDate': '21-4-2020 11:36:36'}, {'bucket': 'ofuks-1304-prj1-local-bucket', 'object': '5.txt', 'size': '18 bytes', 'creationDate': '21-4-2020 11:56:46'}, {'bucket': 'ofuks-1304-prj1-local-bucket', 'object': 'Untitled', 'size': '5 bytes', 'creationDate': '13-4-2020 03:39:11'}, {'bucket': 'ofuks-1304-prj1-local-bucket', 'object': 'adasdas', 'size': '1 KB', 'creationDate': '15-4-2020 02:17 [...]
+
+
+@Injectable()
+export class BucketDataService {
+ public _bucketData = new BehaviorSubject<any>(null);
+ private serverData: any = [];
+ get data(): TodoItemNode[] { return this._bucketData.value; }
+ constructor(
+ private bucketBrowserService: BucketBrowserService,
+ ) {
+ }
+
+ public refreshBucketdata(bucket, endpoint) {
+ let backetData = [];
+ this.bucketBrowserService.getBacketData(bucket, endpoint).subscribe(v => {
+ this.serverData = v;
+ backetData = this.convertToFolderTree(v);
+ const data = this.buildFileTree({[bucket]: backetData}, 0);
+ this._bucketData.next(data);
+ });
+
+ // this.serverData = array;
+ // backetData = this.convertToFolderTree(array);
+ // const data = this.buildFileTree({[bucket]: backetData}, 0);
+ // this._bucketData.next(data);
+ // }
+ }
+ public buildFileTree(obj: {[key: string]: any}, level: number): TodoItemNode[] {
+ return Object.keys(obj).reduce<TodoItemNode[]>((accumulator, key) => {
+ const value = obj[key];
+ const node = new TodoItemNode();
+ node.item = key;
+ if (Object.keys(value).length) {
+ if (typeof value === 'object') {
+ node.children = this.buildFileTree(value, level + 1);
+ } else {
+ node.item = value;
+ }
+ } else {
+ node.size = this.serverData.filter(v => v.object.indexOf(node.item) !== -1)[0];
+ }
+ return accumulator.concat(node);
+ }, []);
+ }
+
+ public insertItem(parent: TodoItemNode, name, isFile) {
+ if (parent.children) {
+ if (isFile) {
+ parent.children.push(name as TodoItemNode);
+ } else {
+ parent.children.unshift({item: name, children: []} as TodoItemNode);
+ this._bucketData.next(this.data);
+ }
+ }
+ }
+
+ public updateItem(node: TodoItemNode, file) {
+ node.item = file;
+ this._bucketData.next(this.data);
+ }
+
+ public processFiles = (files, target) => {
+ let pointer = target;
+ files.forEach((file, index) => {
+ if (!pointer[file]) {
+ pointer[file] = {};
+ }
+ pointer = pointer[file];
+ });
+ }
+
+ public processFolderArray = (acc, curr) => {
+ const files = curr.object.split('/').filter(x => x.length > 0);
+ this.processFiles(files, acc);
+ return acc;
+ }
+
+ public convertToFolderTree = (data) => data
+ .reduce(
+ this.processFolderArray,
+ {}
+ )
+
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts
index 0b367c5..2e93cc1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts
@@ -1,8 +1,11 @@
-import {Component, OnInit, AfterViewInit, Output, EventEmitter} from '@angular/core';
+import {Component, OnInit, AfterViewInit, Output, EventEmitter, OnDestroy} from '@angular/core';
import {SelectionModel} from '@angular/cdk/collections';
import {FlatTreeControl} from '@angular/cdk/tree';
import {MatTreeFlatDataSource, MatTreeFlattener} from '@angular/material/tree';
import {BucketBrowserService, TodoItemFlatNode, TodoItemNode} from '../../../core/services/bucket-browser.service';
+import {BucketDataService} from '../bucket-data.service';
+import {Subscription} from 'rxjs';
+
@Component({
@@ -10,39 +13,45 @@ import {BucketBrowserService, TodoItemFlatNode, TodoItemNode} from '../../../cor
templateUrl: './folder-tree.component.html',
styleUrls: ['./folder-tree.component.scss']
})
-export class FolderTreeComponent implements OnInit {
-
- @Output() showFolderContent: EventEmitter<any> = new EventEmitter();
- path = [];
- selectedFolder: TodoItemFlatNode;
- flatNodeMap = new Map<TodoItemFlatNode, TodoItemNode>();
- nestedNodeMap = new Map<TodoItemNode, TodoItemFlatNode>();
- selectedParent: TodoItemFlatNode | null = null;
- newItemName = '';
- treeControl: FlatTreeControl<TodoItemFlatNode>;
- treeFlattener: MatTreeFlattener<TodoItemNode, TodoItemFlatNode>;
- dataSource: MatTreeFlatDataSource<TodoItemNode, TodoItemFlatNode>;
-
- checklistSelection = new SelectionModel<TodoItemFlatNode>(true /* multiple */);
-
- constructor(private bucketBrowserService: BucketBrowserService) {
- this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel,
- this.isExpandable, this.getChildren);
+export class FolderTreeComponent implements OnInit, OnDestroy {
+ @Output() showFolderContent: EventEmitter<any> = new EventEmitter();
+ private folderTreeSubs;
+ private path = [];
+ private selectedFolder: TodoItemFlatNode;
+ private flatNodeMap = new Map<TodoItemFlatNode, TodoItemNode>();
+ private nestedNodeMap = new Map<TodoItemNode, TodoItemFlatNode>();
+ private selectedParent: TodoItemFlatNode | null = null;
+ private newItemName = '';
+ private subscriptions: Subscription = new Subscription();
+ public treeControl: FlatTreeControl<TodoItemFlatNode>;
+ private treeFlattener: MatTreeFlattener<TodoItemNode, TodoItemFlatNode>;
+ public dataSource: MatTreeFlatDataSource<TodoItemNode, TodoItemFlatNode>;
+
+ private checklistSelection = new SelectionModel<TodoItemFlatNode>(true /* multiple */);
+
+ constructor(
+ private bucketBrowserService: BucketBrowserService,
+ private bucketDataService: BucketDataService,
+ ) {
+ this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel, this.isExpandable, this.getChildren);
this.treeControl = new FlatTreeControl<TodoItemFlatNode>(this.getLevel, this.isExpandable);
this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
- bucketBrowserService.dataChange.subscribe(data => {
- this.dataSource.data = data;
- if (!this.selectedFolder) {
+ this.subscriptions.add(bucketDataService._bucketData.subscribe(data => {
+ if (data) {
+ this.dataSource.data = data;
const subject = this.dataSource._flattenedData;
- subject.subscribe((subjectData) => {
- this.treeControl.expand(subjectData[0]);
- this.showItem(subjectData[0]);
+ this.folderTreeSubs = subject.subscribe((subjectData) => {
+ if (this.selectedFolder) {
+ this.selectedFolder = subjectData.filter(v => v.item === this.selectedFolder.item && v.level === this.selectedFolder.level)[0];
+ }
+ this.expandAllParents(this.selectedFolder || subjectData[0]);
+ this.showItem(this.selectedFolder || subjectData[0]);
});
}
- });
+ }));
}
getLevel = (node: TodoItemFlatNode) => node.level;
@@ -70,14 +79,14 @@ export class FolderTreeComponent implements OnInit {
ngOnInit() {
- // const subject = this.dataSource._flattenedData;
- // subject.subscribe((data) => {
- // this.treeControl.expand(data[0]);
- // this.showItem(data[0]);
- // });
}
- showItem(el) {
+ ngOnDestroy() {
+ this.folderTreeSubs.unsubscribe();
+ this.bucketDataService._bucketData.next([]);
+ }
+
+ private showItem(el) {
if (el) {
this.treeControl.expand(el);
this.selectedFolder = el;
@@ -92,7 +101,7 @@ export class FolderTreeComponent implements OnInit {
}
}
- getPath(el) {
+ private getPath(el) {
if (el) {
if (this.path.length === 0) {
this.path.unshift(el.item);
@@ -105,7 +114,17 @@ export class FolderTreeComponent implements OnInit {
}
}
- descendantsAllSelected(node: TodoItemFlatNode): boolean {
+ private expandAllParents(el) {
+ if (el) {
+ this.treeControl.expand(el);
+ if (this.getParentNode(el) !== null) {
+ this.expandAllParents(this.getParentNode(el));
+ }
+ }
+ }
+
+ private descendantsAllSelected(node: TodoItemFlatNode): boolean {
+
const descendants = this.treeControl.getDescendants(node);
const descAllSelected = descendants.every(child =>
this.checklistSelection.isSelected(child)
@@ -113,13 +132,14 @@ export class FolderTreeComponent implements OnInit {
return descAllSelected;
}
- descendantsPartiallySelected(node: TodoItemFlatNode): boolean {
+ private descendantsPartiallySelected(node: TodoItemFlatNode): boolean {
+
const descendants = this.treeControl.getDescendants(node);
const result = descendants.some(child => this.checklistSelection.isSelected(child));
return result && !this.descendantsAllSelected(node);
}
- todoItemSelectionToggle(node: TodoItemFlatNode): void {
+ private todoItemSelectionToggle(node: TodoItemFlatNode): void {
this.checklistSelection.toggle(node);
const descendants = this.treeControl.getDescendants(node);
this.checklistSelection.isSelected(node)
@@ -133,12 +153,12 @@ export class FolderTreeComponent implements OnInit {
this.checkAllParentsSelection(node);
}
- todoLeafItemSelectionToggle(node: TodoItemFlatNode): void {
+ private todoLeafItemSelectionToggle(node: TodoItemFlatNode): void {
this.checklistSelection.toggle(node);
this.checkAllParentsSelection(node);
}
- checkAllParentsSelection(node: TodoItemFlatNode): void {
+ private checkAllParentsSelection(node: TodoItemFlatNode): void {
let parent: TodoItemFlatNode | null = this.getParentNode(node);
while (parent) {
this.checkRootNodeSelection(parent);
@@ -146,7 +166,8 @@ export class FolderTreeComponent implements OnInit {
}
}
- checkRootNodeSelection(node: TodoItemFlatNode): void {
+
+ private checkRootNodeSelection(node: TodoItemFlatNode): void {
const nodeSelected = this.checklistSelection.isSelected(node);
const descendants = this.treeControl.getDescendants(node);
const descAllSelected = descendants.every(child =>
@@ -159,9 +180,8 @@ export class FolderTreeComponent implements OnInit {
}
}
- getParentNode(node: TodoItemFlatNode): TodoItemFlatNode | null {
+ private getParentNode(node: TodoItemFlatNode): TodoItemFlatNode | null {
const currentLevel = this.getLevel(node);
-
if (currentLevel < 1) {
return null;
}
@@ -177,15 +197,16 @@ export class FolderTreeComponent implements OnInit {
}
return null;
}
-
- addNewItem(node: TodoItemFlatNode, file, isFile, path) {
+
+ private addNewItem(node: TodoItemFlatNode, file, isFile, path) {
const parentNode = this.flatNodeMap.get(node);
- this.bucketBrowserService.insertItem(parentNode!, file, isFile);
+ this.bucketDataService.insertItem(parentNode!, file, isFile);
this.treeControl.expand(node);
}
- saveNode(node: TodoItemFlatNode, itemValue: string) {
+ private saveNode(node: TodoItemFlatNode, itemValue: string) {
const nestedNode = this.flatNodeMap.get(node);
- this.bucketBrowserService.updateItem(nestedNode!, itemValue);
+ this.bucketDataService.updateItem(nestedNode!, itemValue);
+
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
index 817ca22..9e669b6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
@@ -60,14 +60,14 @@
class="strong">{{ notebook.password }}</span></p>
<p class="m-top-30">{{ DICTIONARY[PROVIDER].personal_storage }}: </p>
- <div class="links_block" (click)="bucketBrowser('project', notebook.endpoint)">
+ <div class="links_block" (click)="bucketBrowser(notebook.bucket_name, notebook.endpoint)">
<p *ngIf="DICTIONARY[PROVIDER].cloud_provider === 'azure' && notebook.account_name">{{ DICTIONARY[PROVIDER].account }}
<span class="bucket-info">{{ notebook.account_name}}</span></p>
<p *ngIf="notebook.bucket_name">{{ DICTIONARY[PROVIDER].container }} <span
class="bucket-info">{{ notebook.bucket_name }}</span></p>
</div>
<p>Shared endpoint bucket: </p>
- <div class="links_block" (click)="bucketBrowser('endpoint', notebook.endpoint)">
+ <div class="links_block" (click)="bucketBrowser(notebook.shared_bucket_name, notebook.endpoint)">
<p *ngIf="DICTIONARY[PROVIDER].cloud_provider === 'azure' && notebook.shared_account_name">{{ DICTIONARY[PROVIDER].account }}
<span class="bucket-info">{{ notebook.shared_account_name}}</span></p>
<p *ngIf="notebook.shared_bucket_name">{{ DICTIONARY[PROVIDER].container }}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts
index ca264b9..ac5b6ba 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts
@@ -123,8 +123,8 @@ export class DetailDialogComponent implements OnInit {
: null;
}
- public bucketBrowser(type, endpoint): void {
- this.dialog.open(BucketBrowserComponent, { data: {type: type, endpoint: endpoint}, panelClass: 'modal-fullscreen' })
+ public bucketBrowser(bucketName, endpoint): void {
+ this.dialog.open(BucketBrowserComponent, { data: {bucket: bucketName, endpoint: endpoint}, panelClass: 'modal-fullscreen' })
.afterClosed().subscribe();
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
index d2d5f02..c87d12c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
@@ -30,6 +30,8 @@ import { ConfirmDeleteAccountDialog } from './manage-ungit/manage-ungit.componen
import {BucketBrowserComponent} from './bucket-browser/bucket-browser.component';
import {FolderTreeComponent} from './bucket-browser/folder-tree/folder-tree.component';
import {MatTreeModule} from '@angular/material/tree';
+import {BucketDataService} from './bucket-browser/bucket-data.service';
+
@NgModule({
imports: [
@@ -49,6 +51,7 @@ import {MatTreeModule} from '@angular/material/tree';
FolderTreeComponent
],
entryComponents: [ManageUngitComponent, ConfirmDeleteAccountDialog, BucketBrowserComponent, FolderTreeComponent],
+ providers: [BucketDataService],
exports: [ResourcesComponent]
})
export class ResourcesModule { }
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@dlab.apache.org
For additional commands, e-mail: commits-help@dlab.apache.org