diff --git a/src/app/@dataflow/rclone/operations-about-flow.ts b/src/app/@dataflow/rclone/operations-about-flow.ts index a4af353..5c6c24e 100644 --- a/src/app/@dataflow/rclone/operations-about-flow.ts +++ b/src/app/@dataflow/rclone/operations-about-flow.ts @@ -35,6 +35,7 @@ export abstract class OperationsAboutFlow extends PostFlow< protected cacheSupport = true; protected params = (pre: CombErr): OperationsAboutFlowParamsNode => { if (pre[1].length !== 0) return {} as any; + if (pre[0].path) return { fs: `${pre[0].remote}:${pre[0].path}` }; return { fs: `${pre[0].remote}:` }; }; protected reconstructAjaxResult(x: AjaxFlowInteralNode): CombErr { diff --git a/src/app/components/rng.module.ts b/src/app/components/rng.module.ts index 63926fc..b41f4d7 100644 --- a/src/app/components/rng.module.ts +++ b/src/app/components/rng.module.ts @@ -1,10 +1,11 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { NbIconModule } from '@nebular/theme'; +import { NbIconModule, NbSpinnerModule } from '@nebular/theme'; import { ChartsModule } from 'ng2-charts'; import { TableModule } from 'ngx-easy-table'; import { RngDiffComponent } from './diff/diff.component'; import { RngKeyValueTableComponent } from './key-value-table/key-value-table.component'; +import { RngSpaceUsageChartComponent } from './space-usage-chart/space-usage-chart.component'; import { RngSpeedChartComponent } from './speed-chart/speed-chart.component'; import { RngSummaryComponent } from './summary/summary.component'; @@ -13,11 +14,12 @@ const RngComponents = [ RngDiffComponent, RngSummaryComponent, RngKeyValueTableComponent, + RngSpaceUsageChartComponent, ]; @NgModule({ declarations: RngComponents, - imports: [CommonModule, TableModule, ChartsModule, NbIconModule], + imports: [CommonModule, TableModule, ChartsModule, NbIconModule, NbSpinnerModule], exports: RngComponents, }) export class RngModule {} diff --git a/src/app/components/space-usage-chart/space-usage-chart.component.spec.ts b/src/app/components/space-usage-chart/space-usage-chart.component.spec.ts new file mode 100644 index 0000000..e7c3507 --- /dev/null +++ b/src/app/components/space-usage-chart/space-usage-chart.component.spec.ts @@ -0,0 +1,27 @@ +/* tslint:disable:no-unused-variable */ +import { DebugElement } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { SpaceUsageChartComponent } from './space-usage-chart.component'; + +describe('SpaceUsageChartComponent', () => { + let component: SpaceUsageChartComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [SpaceUsageChartComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SpaceUsageChartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/space-usage-chart/space-usage-chart.component.ts b/src/app/components/space-usage-chart/space-usage-chart.component.ts new file mode 100644 index 0000000..fd6adf5 --- /dev/null +++ b/src/app/components/space-usage-chart/space-usage-chart.component.ts @@ -0,0 +1,82 @@ +import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { ChartDataSets, ChartOptions } from 'chart.js'; +import { BaseChartDirective, Label } from 'ng2-charts'; +import { OperationsAboutFlowOutItemNode } from '../../@dataflow/rclone'; +import { FormatBytes } from '../../utils/format-bytes'; + +@Component({ + selector: 'app-rng-space-usage-chart', + template: ` +
+ + +
+ `, + styles: [], +}) +export class RngSpaceUsageChartComponent implements OnInit { + constructor() {} + // Doughnut + public doughnutChartOptions: ChartOptions = { + legend: { display: false }, + cutoutPercentage: 0, + animation: { animateScale: true }, + tooltips: { + callbacks: { + label(tooltipItem, data) { + let label = (data.labels[tooltipItem.index] as string) || ''; + if (label) { + label += ': '; + } + const value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + if (typeof value === 'number') label += FormatBytes(value, 3); + else label += value; + return label; + }, + }, + }, + }; + public doughnutChartLabels: Label[] = ['Totol', 'Used', 'Other', 'Trashed', 'Free']; + public doughnutChartData: ChartDataSets[] = [ + { + data: [null, 0, 0, 0, 0], + backgroundColor: ['', '#3366ff', '#0095ff', '#ffaa00', '#00d68f'], + hoverBackgroundColor: ['', '#598bff', '#42aaff', '#ffc94d', '#2ce69b'], + borderWidth: 0, + label: 'Outside', + }, + { + data: [0], + backgroundColor: '#ffffff', + hoverBackgroundColor: '#c5cee0', + borderWidth: 0, + label: 'Inside', + }, + ]; + + @Input() loading = false; + + @ViewChild(BaseChartDirective) chart: BaseChartDirective; + + set data(about: OperationsAboutFlowOutItemNode) { + this.doughnutChartData[0].data = [null, about.used, about.other, about.trashed, about.free]; + this.doughnutChartData[1].data = [about.total ? about.total : null]; + this.chart.update(); + } + + ngOnInit() {} +} diff --git a/src/app/pages/manager/fileMode/file.detail.ts b/src/app/pages/manager/fileMode/file.detail.ts index 6958d75..bc0c650 100644 --- a/src/app/pages/manager/fileMode/file.detail.ts +++ b/src/app/pages/manager/fileMode/file.detail.ts @@ -3,10 +3,21 @@ import { NbToastrService } from '@nebular/theme'; import { overlayConfigFactory } from 'ngx-modialog-7'; // tslint:disable-next-line: no-submodule-imports import { Modal, VEXModalContext } from 'ngx-modialog-7/plugins/vex'; -import { Subject } from 'rxjs'; -import { withLatestFrom } from 'rxjs/operators'; -import { OperationsListExtendsFlowOutItemNode } from '../../../@dataflow/extra'; -import { NestedGet } from '../../../@dataflow/rclone'; +import { combineLatest, Subject } from 'rxjs'; +import { map, withLatestFrom } from 'rxjs/operators'; +import { CombErr } from '../../../@dataflow/core'; +import { + NavigationFlowOutNode, + OperationsListExtendsFlowOutItemNode, +} from '../../../@dataflow/extra'; +import { + NestedGet, + OperationsAboutFlow, + OperationsFsinfoFlow, + OperationsFsinfoFlowInNode, +} from '../../../@dataflow/rclone'; +import { RngSpaceUsageChartComponent } from '../../../components/space-usage-chart/space-usage-chart.component'; +import { ConnectionService } from '../../connection.service'; import { ServerSettingService } from '../../settings/sever-setting/server-setting.service'; import { DownloadFileService } from './download-file.service'; @@ -17,6 +28,8 @@ import { DownloadFileService } from './download-file.service';
{{ name }}
+ +
@@ -72,7 +85,8 @@ export class FileDetailComponent implements OnInit { private downloadService: DownloadFileService, private serverSettingService: ServerSettingService, public modal: Modal, - private toastrService: NbToastrService + private toastrService: NbToastrService, + private cmdService: ConnectionService ) {} /** if user wasn't select any item, right sidebar can show current directory detail. */ @@ -85,8 +99,12 @@ export class FileDetailComponent implements OnInit { typeIcon = ''; private downloadTrigger = new Subject(); + private aboutTrigger = new Subject(); + about$: OperationsAboutFlow; + loadingAbout = false; @ViewChild('EnableServe') public EnableServe: TemplateRef; + @ViewChild(RngSpaceUsageChartComponent) chart: RngSpaceUsageChartComponent; itemNode(x: OperationsListExtendsFlowOutItemNode) { this.remote = x.remote || ''; @@ -95,6 +113,10 @@ export class FileDetailComponent implements OnInit { this.isDir = x.IsDir; this.typeIcon = x.TypeIcon; if (this.remote !== '' && this.path !== '' && this.name !== '') this.currentDirDetail = false; + if (!this.currentDirDetail && this.isDir) { + this.loadingAbout = true; + this.aboutTrigger.next({ remote: this.remote, path: this.path }); + } } download() { @@ -110,6 +132,35 @@ export class FileDetailComponent implements OnInit { } ngOnInit() { + const outer = this; + this.loadingAbout = true; + const fsinfo$ = new (class extends OperationsFsinfoFlow { + public prerequest$ = combineLatest([ + outer.aboutTrigger, + outer.cmdService.listCmd$.verify(this.cmd), + ]).pipe( + map( + ([navNode, cmdNode]): CombErr => { + if (cmdNode[1].length !== 0) return [{}, cmdNode[1]] as any; + return [{ ...cmdNode[0], ...navNode }, []]; + } + ) + ); + })(); + fsinfo$.deploy(); + fsinfo$.getOutput().subscribe(x => { + if (x[1].length !== 0) return; + const fsinfo = x[0]['fs-info']; + }); + this.about$ = new (class extends OperationsAboutFlow { + public prerequest$ = fsinfo$.getSupersetOutput(); + })(); + this.about$.deploy(); + this.about$.getOutput().subscribe(x => { + this.loadingAbout = false; + if (x[1].length !== 0) return; + this.chart.data = x[0].about; + }); this.downloadTrigger .pipe(withLatestFrom(this.serverSettingService.options$.getOutput())) .subscribe(([, optionsNode]) => { diff --git a/src/app/pages/manager/homeMode/remote.detail.ts b/src/app/pages/manager/homeMode/remote.detail.ts index ccb64ef..d4fd285 100644 --- a/src/app/pages/manager/homeMode/remote.detail.ts +++ b/src/app/pages/manager/homeMode/remote.detail.ts @@ -1,6 +1,4 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { ChartDataSets, ChartOptions } from 'chart.js'; -import { BaseChartDirective, Label } from 'ng2-charts'; import { combineLatest, Subject } from 'rxjs'; import { map } from 'rxjs/operators'; import { CombErr } from '../../../@dataflow/core'; @@ -10,31 +8,14 @@ import { OperationsFsinfoFlow, OperationsFsinfoFlowInNode, } from '../../../@dataflow/rclone'; -import { FormatBytes } from '../../../utils/format-bytes'; +import { RngSpaceUsageChartComponent } from '../../../components/space-usage-chart/space-usage-chart.component'; import { ConnectionService } from '../../connection.service'; @Component({ selector: 'app-home-remote-detail', template: `
{{ remote }}
-
- - -
+ Feature @@ -92,49 +73,11 @@ export class RemoteDetailComponent implements OnInit { feature: { k: string; v: boolean }[] = []; hashes: string[] = []; - // Doughnut - public doughnutChartOptions: ChartOptions = { - legend: { display: false }, - cutoutPercentage: 0, - animation: { animateScale: true }, - tooltips: { - callbacks: { - label(tooltipItem, data) { - let label = (data.labels[tooltipItem.index] as string) || ''; - if (label) { - label += ': '; - } - const value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; - if (typeof value === 'number') label += FormatBytes(value, 3); - else label += value; - return label; - }, - }, - }, - }; - public doughnutChartLabels: Label[] = ['Totol', 'Used', 'Other', 'Trashed', 'Free']; - public doughnutChartData: ChartDataSets[] = [ - { - data: [null, 0, 0, 0, 0], - backgroundColor: ['', '#3366ff', '#0095ff', '#ffaa00', '#00d68f'], - hoverBackgroundColor: ['', '#598bff', '#42aaff', '#ffc94d', '#2ce69b'], - borderWidth: 0, - label: 'Outside', - }, - { - data: [0], - backgroundColor: '#ffffff', - hoverBackgroundColor: '#c5cee0', - borderWidth: 0, - label: 'Inside', - }, - ]; - private trigger = new Subject(); fsinfo$: OperationsFsinfoFlow; about$: OperationsAboutFlow; - @ViewChild(BaseChartDirective) chart: BaseChartDirective; + @ViewChild(RngSpaceUsageChartComponent) chart: RngSpaceUsageChartComponent; navNode(x: NavigationFlowOutNode) { this.remote = x.remote || ''; @@ -175,10 +118,7 @@ export class RemoteDetailComponent implements OnInit { this.about$.getOutput().subscribe(x => { this.loadingAbout = false; if (x[1].length !== 0) return; - const about = x[0].about; - this.doughnutChartData[0].data = [null, about.used, about.other, about.trashed, about.free]; - this.doughnutChartData[1].data = [about.total ? about.total : null]; - this.chart.update(); + this.chart.data = x[0].about; }); } } diff --git a/src/app/pages/manager/manager.module.ts b/src/app/pages/manager/manager.module.ts index 7454e00..01f2988 100644 --- a/src/app/pages/manager/manager.module.ts +++ b/src/app/pages/manager/manager.module.ts @@ -21,6 +21,7 @@ import { import { ChartsModule } from 'ng2-charts'; import { TableModule } from 'ngx-easy-table'; import { FileSaverModule } from 'ngx-filesaver'; +import { RngModule } from '../../components/rng.module'; import { BreadcrumbComponent } from './breadcrumb/breadcrumb.component'; import { ClipboardRemotesTableComponent } from './clipboard/clipboard-remotes-table/clipboard-remotes-table.component'; import { ClipboardDialogComponent } from './clipboard/clipboard.dialog'; @@ -71,6 +72,7 @@ import { TasksDialogComponent } from './tasks/tasks.dialog'; NbListModule, ChartsModule, FileSaverModule, + RngModule, ], }) export class ManagerModule {}