Skip to content

Commit

Permalink
feat(file.detail): enable download file
Browse files Browse the repository at this point in the history
  • Loading branch information
ElonH committed Jun 10, 2020
1 parent 4ea8e66 commit 1f578f7
Show file tree
Hide file tree
Showing 14 changed files with 224 additions and 5 deletions.
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@
"bootstrap": "^4.5.0",
"chart.js": "^2.9.3",
"eva-icons": "^1.1.3",
"file-saver": "^2.0.2",
"humanize-duration-ts": "^2.1.1",
"jquery": "^3.5.1",
"moment": "^2.26.0",
"nebular-icons": "^1.1.0",
"ng2-charts": "^2.3.2",
"ngx-easy-table": "^12.0.0",
"ngx-filesaver": "^9.0.0",
"ngx-modialog-7": "^9.0.2",
"ngx-monaco-editor": "^9.0.0",
"ngx-pagination": "^5.0.0",
Expand Down
1 change: 1 addition & 0 deletions src/app/@dataflow/core/ajax-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CombErr, FlowInNode, FlowOutNode } from './bare-flow';
import { CacheFlow } from './cache-flow';
import { FlowSupNode } from './superset-flow';

// TODO: rename
export type AjaxFlowInteralNode = [{ ajaxRsp: AjaxResponse }, Error[]];

export abstract class AjaxFlow<
Expand Down
4 changes: 3 additions & 1 deletion src/app/@dataflow/extra/operations-list-extends-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as moment from 'moment';
import { Observable, of } from 'rxjs';
import { getIconForFile, getIconForFolder } from 'vscode-icons-js';
import { FormatBytes } from '../../utils/format-bytes';
import { BareFlow, CombErr, NothingFlow } from '../core';
import { BareFlow, CombErr } from '../core';
import {
OperationsListFlowInNode,
OperationsListFlowOutItemNode,
Expand All @@ -16,6 +16,7 @@ export interface OperationsListExtendsFlowInNode
ClipboardFlowNode {}

export interface OperationsListExtendsFlowOutItemNode extends OperationsListFlowOutItemNode {
remote: string;
SizeHumanReadable: string;
ModTimeHumanReadable: string;
ModTimeMoment: moment.Moment;
Expand All @@ -41,6 +42,7 @@ export abstract class OperationsListExtendsFlow extends BareFlow<
const ModTimeMoment = moment(item.ModTime);
return {
...item,
remote: pre[0].remote,
SizeHumanReadable: FormatBytes(item.Size),
ModTimeMoment,
ModTimeHumanReadable: ModTimeMoment.fromNow(),
Expand Down
26 changes: 26 additions & 0 deletions src/app/@dataflow/rclone/download-file-flow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { AjaxRequest, AjaxResponse } from 'rxjs/ajax';
import { AjaxFlowInteralNode, CombErr } from '../core';
import { IRcloneServer } from '../extra';
import { GetFlow } from './get-flow';

export interface DownloadFileFlowParamsNode {
remote: string;
Path: string;
Name: string;
}
export interface DownloadFileFlowInNode extends IRcloneServer, DownloadFileFlowParamsNode {}
export abstract class DownloadFileFlow extends GetFlow<
DownloadFileFlowInNode,
{ ajaxRsp: AjaxResponse }
> {
// public prerequest$: Observable<CombErr<DownloadFileFlowInNode>>;
protected requestAjax(x: CombErr<DownloadFileFlowInNode>): AjaxRequest {
const req = super.requestAjax(x);
req.url = `${x[0].url}/[${x[0].remote}:]/${x[0].Path}`;
req.responseType = 'blob';
return req;
}
protected reconstructAjaxResult(x: AjaxFlowInteralNode): AjaxFlowInteralNode {
return x;
}
}
25 changes: 25 additions & 0 deletions src/app/@dataflow/rclone/get-flow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AjaxRequest } from 'rxjs/ajax';
import { AjaxFlow, CombErr, FlowOutNode, FlowSupNode } from '../core';
import { IRcloneServer } from '../extra';

export abstract class GetFlow<
Tin extends IRcloneServer,
Tout extends FlowOutNode,
Tsup extends FlowSupNode = Tin & Tout
> extends AjaxFlow<Tin, Tout, Tsup> {
// public prerequest$: Observable<CombErr<Tin>>;
protected cacheSupport = false;
protected cachePath = '';
protected requestAjax(x: CombErr<Tin>): AjaxRequest {
const headers = {};
if (x[0]['user'] && x[0]['user'] !== '' && x[0]['password'] && x[0]['password'] !== '')
headers['Authorization'] = 'Basic ' + btoa(`${x[0]['user']}:${x[0]['password']}`);
return {
method: 'GET',
headers,
};
}
// protected reconstructAjaxResult(x: AjaxFlowInteralNode): CombErr<Tout> {
// throw new Error('Method not implemented.');
// }
}
2 changes: 2 additions & 0 deletions src/app/@dataflow/rclone/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ export * from './options-get-flow';
export * from './options-set-flow';
export * from './operations-fsinfo-flow';
export * from './operations-about-flow';
export * from './get-flow';
export * from './download-file-flow';
16 changes: 16 additions & 0 deletions src/app/pages/manager/fileMode/download-file.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* tslint:disable:no-unused-variable */

import { async, inject, TestBed } from '@angular/core/testing';
import { DownloadFileService } from './download-file.service';

describe('Service: DownloadFile', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [DownloadFileService],
});
});

it('should ...', inject([DownloadFileService], (service: DownloadFileService) => {
expect(service).toBeTruthy();
}));
});
52 changes: 52 additions & 0 deletions src/app/pages/manager/fileMode/download-file.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Injectable } from '@angular/core';
import { NbToastrService } from '@nebular/theme';
import { FileSaverService } from 'ngx-filesaver';
import { Observable, Subject } from 'rxjs';
import { map, withLatestFrom } from 'rxjs/operators';
import { CombErr } from '../../..//@dataflow/core';
import {
DownloadFileFlow,
DownloadFileFlowInNode,
DownloadFileFlowParamsNode,
} from '../../../@dataflow/rclone';
import { ConnectionService } from '../../connection.service';

@Injectable({
providedIn: 'root',
})
export class DownloadFileService {
private trigger = new Subject<DownloadFileFlowParamsNode>();
download$: DownloadFileFlow;

post(task: DownloadFileFlowParamsNode) {
this.trigger.next(task);
this.toastr.default(task.Name, 'Downloading ...');
}

constructor(
private cmdService: ConnectionService,
private toastr: NbToastrService,
private fileSaverService: FileSaverService
) {
const outer = this;
this.download$ = new (class extends DownloadFileFlow {
public prerequest$: Observable<CombErr<DownloadFileFlowInNode>> = outer.trigger.pipe(
withLatestFrom(outer.cmdService.connection$.getOutput()),
map(
([item, connectNode]): CombErr<DownloadFileFlowInNode> => [
{ ...connectNode[0], ...item },
connectNode[1],
]
)
);
})();
this.download$.deploy();
this.download$.getSupersetOutput().subscribe(x => {
if (x[1].length !== 0) {
this.toastr.danger(`${x[0].remote}:${x[0].Path}`, 'File download failure.');
return;
}
this.fileSaverService.save(x[0].ajaxRsp.response, x[0].Name);
});
}
}
57 changes: 57 additions & 0 deletions src/app/pages/manager/fileMode/file.detail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Component, OnInit } from '@angular/core';
import { OperationsListExtendsFlowOutItemNode } from '../../../@dataflow/extra';
import { DownloadFileService } from './download-file.service';

@Component({
selector: 'app-file-file-detail',
template: `
<div *ngIf="!currentDirDetail">
<img [src]="'assets/icons/' + typeIcon" />
<h5>{{ name }}</h5>
<button nbButton (click)="download()" *ngIf="!isDir">download</button>
</div>
`,
styles: [
`
div {
padding: 0 1.25rem;
display: flex;
flex-direction: column;
}
img {
width: 8rem;
margin: 0 auto;
}
h5 {
overflow-wrap: break-word;
}
`,
],
})
export class FileDetailComponent implements OnInit {
constructor(private downloadService: DownloadFileService) {}

/** if user wasn't select any item, right sidebar can show current directory detail. */
currentDirDetail = true;

remote = '';
path = '';
name = '';
isDir = true;
typeIcon = '';

itemNode(x: OperationsListExtendsFlowOutItemNode) {
this.remote = x.remote || '';
this.path = x.Path || '';
this.name = x.Name || '';
this.isDir = x.IsDir;
this.typeIcon = x.TypeIcon;
if (this.remote !== '' && this.path !== '' && this.name !== '') this.currentDirDetail = false;
}

download() {
this.downloadService.post({ remote: this.remote, Path: this.path, Name: this.name });
}

ngOnInit() {}
}
8 changes: 7 additions & 1 deletion src/app/pages/manager/fileMode/fileMode.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
NavigationFlowOutNode,
OperationsListExtendsFlow,
OperationsListExtendsFlowInNode,
OperationsListExtendsFlowOutItemNode,
} from '../../../@dataflow/extra';
import { OperationsListFlow, OperationsListFlowInNode } from '../../../@dataflow/rclone';
import { ConnectionService } from '../../connection.service';
Expand All @@ -17,7 +18,11 @@ import { ListViewComponent } from './listView/listView.component';
@Component({
selector: 'app-manager-file-mode',
template: `
<app-manager-list-view [listExtends$]="listExtends$" (jump)="jump.emit($event)">
<app-manager-list-view
[listExtends$]="listExtends$"
(jump)="jump.emit($event)"
(showDetail)="showDetail.emit($event)"
>
</app-manager-list-view>
`,
styles: [],
Expand All @@ -28,6 +33,7 @@ export class FileModeComponent implements OnInit {
@Input() nav$: NavigationFlow;

@Output() jump = new EventEmitter<NavigationFlowOutNode>();
@Output() showDetail = new EventEmitter<OperationsListExtendsFlowOutItemNode>();

private listTrigger = new Subject<number>();
private list$: OperationsListFlow;
Expand Down
12 changes: 10 additions & 2 deletions src/app/pages/manager/fileMode/listView/listView.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
OperationsListExtendsFlow,
OperationsListExtendsFlowOutItemNode,
} from '../../../../@dataflow/extra';
import { OperationsListFlowOutItemNode } from '../../../../@dataflow/rclone';
import { ClipboardService } from '../../clipboard/clipboard.service';

@Component({
Expand Down Expand Up @@ -99,6 +98,8 @@ export class ListViewComponent implements OnInit, OnDestroy {

private listScrb: Subscription;

@Output() showDetail = new EventEmitter<OperationsListExtendsFlowOutItemNode>();

loading() {
this.configuration.isLoading = true;
this.checkAll = false; // TODO: not work around.
Expand All @@ -107,7 +108,10 @@ export class ListViewComponent implements OnInit, OnDestroy {
value: 1,
});
}
eventEmitted($event: { event: string; value: { row: OperationsListFlowOutItemNode } }): void {
eventEmitted($event: {
event: string;
value: { row: OperationsListExtendsFlowOutItemNode };
}): void {
// console.log('$event', $event);
if ($event.event === 'onDoubleClick') {
// console.log($event.value);
Expand All @@ -116,6 +120,10 @@ export class ListViewComponent implements OnInit, OnDestroy {
this.jump.emit({ remote: this.remote, path: item.Path });
this.loading();
}
} else if ($event.event === 'onClick') {
// console.log($event.value);
const item = $event.value.row;
this.showDetail.emit(item);
}
}

Expand Down
10 changes: 9 additions & 1 deletion src/app/pages/manager/manager.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ConnectionService } from '../connection.service';
import { ClipboardDialogComponent } from './clipboard/clipboard.dialog';
import { ClipboardService } from './clipboard/clipboard.service';
import { MkdirDialogComponent } from './dialogs/mkdir.dialog';
import { FileDetailComponent } from './fileMode/file.detail';
import { FileModeComponent } from './fileMode/fileMode.component';
import { HomeModeComponent } from './homeMode/homeMode.component';
import { RemoteDetailComponent } from './homeMode/remote.detail';
Expand Down Expand Up @@ -41,13 +42,19 @@ import { TaskService } from './tasks/tasks.service';
(showDetail)="remoteDetail.navNode($event)"
>
</app-manager-home-mode>
<app-manager-file-mode *ngIf="fileMode" [nav$]="nav$" (jump)="addrJump($event)">
<app-manager-file-mode
*ngIf="fileMode"
[nav$]="nav$"
(jump)="addrJump($event)"
(showDetail)="fileDetail.itemNode($event)"
>
</app-manager-file-mode>
</nb-card-body>
</nb-card>
</div>
<nb-sidebar fixed end class="right-bar" tag="detail" state="collapsed">
<app-home-remote-detail *ngIf="homeMode"> </app-home-remote-detail>
<app-file-file-detail *ngIf="fileMode"> </app-file-file-detail>
</nb-sidebar>
<nb-layout-footer [ngClass]="{ mobile: !mainBar, pc: mainBar }">
<nb-actions>
Expand Down Expand Up @@ -160,6 +167,7 @@ export class ManagerComponent implements OnInit, OnDestroy {
@ViewChild(HomeModeComponent) home: HomeModeComponent;
@ViewChild(NbSidebarComponent) detail: NbSidebarComponent;
@ViewChild(RemoteDetailComponent) remoteDetail: RemoteDetailComponent;
@ViewChild(FileDetailComponent) fileDetail: FileDetailComponent;

private navTrigger = new Subject<NavigationFlowOutNode>();
nav$: NavigationFlow;
Expand Down
4 changes: 4 additions & 0 deletions src/app/pages/manager/manager.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import {
} from '@nebular/theme';
import { ChartsModule } from 'ng2-charts';
import { TableModule } from 'ngx-easy-table';
import { FileSaverModule } from 'ngx-filesaver';
import { BreadcrumbComponent } from './breadcrumb/breadcrumb.component';
import { ClipboardRemotesTableComponent } from './clipboard/clipboard-remotes-table/clipboard-remotes-table.component';
import { ClipboardDialogComponent } from './clipboard/clipboard.dialog';
import { MkdirDialogComponent } from './dialogs/mkdir.dialog';
import { FileDetailComponent } from './fileMode/file.detail';
import { FileModeComponent } from './fileMode/fileMode.component';
import { ListViewComponent } from './fileMode/listView/listView.component';
import { HomeModeComponent } from './homeMode/homeMode.component';
Expand All @@ -46,6 +48,7 @@ import { TasksDialogComponent } from './tasks/tasks.dialog';
TasksDialogComponent,
MkdirDialogComponent,
RemoteDetailComponent,
FileDetailComponent,
],
imports: [
CommonModule,
Expand All @@ -67,6 +70,7 @@ import { TasksDialogComponent } from './tasks/tasks.dialog';
NbSpinnerModule,
NbListModule,
ChartsModule,
FileSaverModule,
],
})
export class ManagerModule {}

0 comments on commit 1f578f7

Please sign in to comment.