diff --git a/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.html b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.html new file mode 100644 index 0000000..df68121 --- /dev/null +++ b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.html @@ -0,0 +1,61 @@ +
+
+ + + +
+
+
+ {{deviceTitle(deviceSummary.device)}} +
+ Last Updated on {{deviceSummary.smart.collector_date | date:'MMMM dd, yyyy - HH:mm' }} +
+
+ +
+
+
+
Status
+
{{ deviceStatusString(deviceSummary.device.device_status) | titlecase}}
+
No Data
+
+
+
Temperature
+
{{ deviceSummary.smart?.temp }}°C
+
--
+
+
+
Capacity
+
{{ deviceSummary.device.capacity | fileSize}}
+
+
+
Powered On
+
{{ humanizeDuration(deviceSummary.smart?.power_on_hours * 60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] }) }}
+
--
+
+
+
+ diff --git a/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.scss b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.spec.ts b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.spec.ts new file mode 100644 index 0000000..dba412c --- /dev/null +++ b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DashboardDeviceComponent } from './dashboard-device.component'; + +describe('DashboardDeviceComponent', () => { + let component: DashboardDeviceComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardDeviceComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DashboardDeviceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.ts b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.ts new file mode 100644 index 0000000..5cd83be --- /dev/null +++ b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.component.ts @@ -0,0 +1,115 @@ +import {Component, Input, OnInit} from '@angular/core'; +import * as moment from "moment"; +import {takeUntil} from "rxjs/operators"; +import {AppConfig} from "app/core/config/app.config"; +import {TreoConfigService} from "@treo/services/config"; +import {Subject} from "rxjs"; +import humanizeDuration from 'humanize-duration' + +@Component({ + selector: 'app-dashboard-device', + templateUrl: './dashboard-device.component.html', + styleUrls: ['./dashboard-device.component.scss'] +}) +export class DashboardDeviceComponent implements OnInit { + @Input() deviceSummary: any; + @Input() deviceWWN: string; + + config: AppConfig; + + private _unsubscribeAll: Subject; + + constructor( + private _configService: TreoConfigService, + ) { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + ngOnInit(): void { + // Subscribe to config changes + this._configService.config$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config: AppConfig) => { + this.config = config; + }); + } + + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + classDeviceLastUpdatedOn(deviceSummary){ + if (deviceSummary.device.device_status !== 0) { + return 'text-red' // if the device has failed, always highlight in red + } else if(deviceSummary.device.device_status === 0 && deviceSummary.smart){ + if(moment().subtract(14, 'd').isBefore(deviceSummary.smart.collector_date)){ + // this device was updated in the last 2 weeks. + return 'text-green' + } else if(moment().subtract(1, 'm').isBefore(deviceSummary.smart.collector_date)){ + // this device was updated in the last month + return 'text-yellow' + } else{ + // last updated more than a month ago. + return 'text-red' + } + + } else { + return '' + } + } + + deviceTitle(disk){ + + console.log(`Displaying Device ${disk.wwn} with: ${this.config.dashboardDisplay}`) + let titleParts = [] + if (disk.host_id) titleParts.push(disk.host_id) + + //add device identifier (fallback to generated device name) + titleParts.push(deviceDisplayTitle(disk, this.config.dashboardDisplay) || deviceDisplayTitle(disk, 'name')) + + return titleParts.join(' - ') + } + + deviceStatusString(deviceStatus){ + if(deviceStatus == 0){ + return "passed" + } else { + return "failed" + } + } + + readonly humanizeDuration = humanizeDuration; + +} + +export function deviceDisplayTitle(disk, titleType: string){ + let titleParts = [] + switch(titleType){ + case 'name': + titleParts.push(`/dev/${disk.device_name}`) + if (disk.device_type && disk.device_type != 'scsi' && disk.device_type != 'ata'){ + titleParts.push(disk.device_type) + } + titleParts.push(disk.model_name) + + break; + case 'serial_id': + if(!disk.device_serial_id) return '' + titleParts.push(`/by-id/${disk.device_serial_id}`) + break; + case 'uuid': + if(!disk.device_uuid) return '' + titleParts.push(`/by-uuid/${disk.device_uuid}`) + break; + case 'label': + if(disk.label){ + titleParts.push(disk.label) + } else if(disk.device_label){ + titleParts.push(`/by-label/${disk.device_label}`) + } + break; + } + return titleParts.join(' - ') +} diff --git a/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.module.ts b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.module.ts new file mode 100644 index 0000000..bb77189 --- /dev/null +++ b/webapp/frontend/src/app/layout/common/dashboard-device/dashboard-device.module.ts @@ -0,0 +1,52 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { Overlay } from '@angular/cdk/overlay'; +import { MAT_AUTOCOMPLETE_SCROLL_STRATEGY, MatAutocompleteModule } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatSelectModule } from '@angular/material/select'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { SharedModule } from 'app/shared/shared.module'; +import {DashboardDeviceComponent} from 'app/layout/common/dashboard-device/dashboard-device.component' +import { MatDialogModule } from "@angular/material/dialog"; +import { MatButtonToggleModule} from "@angular/material/button-toggle"; +import {MatTabsModule} from "@angular/material/tabs"; +import {MatSliderModule} from "@angular/material/slider"; +import {MatSlideToggleModule} from "@angular/material/slide-toggle"; +import {MatTooltipModule} from "@angular/material/tooltip"; +import {dashboardRoutes} from "../../../modules/dashboard/dashboard.routing"; +import {MatDividerModule} from "@angular/material/divider"; +import {MatMenuModule} from "@angular/material/menu"; +import {MatProgressBarModule} from "@angular/material/progress-bar"; +import {MatSortModule} from "@angular/material/sort"; +import {MatTableModule} from "@angular/material/table"; +import {NgApexchartsModule} from "ng-apexcharts"; +import {DashboardSettingsModule} from "../dashboard-settings/dashboard-settings.module"; + +@NgModule({ + declarations: [ + DashboardDeviceComponent + ], + imports : [ + RouterModule.forChild([]), + RouterModule.forChild(dashboardRoutes), + MatButtonModule, + MatDividerModule, + MatTooltipModule, + MatIconModule, + MatMenuModule, + MatProgressBarModule, + MatSortModule, + MatTableModule, + NgApexchartsModule, + SharedModule, + ], + exports : [ + DashboardDeviceComponent, + ], + providers : [] +}) +export class DashboardDeviceModule +{ +} diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html index a642e32..6c9a2d9 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html @@ -48,68 +48,7 @@
-
-
-
- - - -
-
-
- {{deviceTitle(summary.value.device)}} -
- Last Updated on {{summary.value.smart.collector_date | date:'MMMM dd, yyyy - HH:mm' }} -
-
- -
-
-
-
Status
-
{{ deviceStatusString(summary.value.device.device_status) | titlecase}}
-
No Data
-
-
-
Temperature
-
{{ summary.value.smart?.temp }}°C
-
--
-
-
-
Capacity
-
{{ summary.value.device.capacity | fileSize}}
-
-
-
Powered On
-
{{ humanizeDuration(summary.value.smart?.power_on_hours * 60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] }) }}
-
--
-
-
-
-
+
diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts b/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts index a4ea071..d5d59a0 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts @@ -5,13 +5,12 @@ import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import {ApexOptions, ChartComponent} from 'ng-apexcharts'; import { DashboardService } from 'app/modules/dashboard/dashboard.service'; -import * as moment from 'moment'; import {MatDialog} from '@angular/material/dialog'; import { DashboardSettingsComponent } from 'app/layout/common/dashboard-settings/dashboard-settings.component'; -import humanizeDuration from 'humanize-duration' -import {AppConfig} from 'app/core/config/app.config'; -import { TreoConfigService } from '@treo/services/config'; -import {Router, NavigationEnd,ActivatedRoute} from '@angular/router'; +import {deviceDisplayTitle} from "app/layout/common/dashboard-device/dashboard-device.component"; +import {AppConfig} from "app/core/config/app.config"; +import {TreoConfigService} from "@treo/services/config"; +import {Router} from "@angular/router"; @Component({ selector : 'example', @@ -24,8 +23,8 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy { data: any; temperatureOptions: ApexOptions; - config: AppConfig; tempDurationKey: string = "forever" + config: AppConfig; // Private private _unsubscribeAll: Subject; @@ -38,11 +37,9 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy */ constructor( private _smartService: DashboardService, - public dialog: MatDialog, private _configService: TreoConfigService, + public dialog: MatDialog, private router: Router, - private activatedRoute: ActivatedRoute - ) { // Set the private defaults @@ -59,6 +56,7 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy */ ngOnInit(): void { + // Subscribe to config changes this._configService.config$ .pipe(takeUntil(this._unsubscribeAll)) @@ -202,49 +200,10 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy }; } - private _deviceDisplayTitle(disk, titleType: string){ - let deviceDisplay = '' - let titleParts = [] - switch(titleType){ - case 'name': - titleParts.push(`/dev/${disk.device_name}`) - if (disk.device_type && disk.device_type != 'scsi' && disk.device_type != 'ata'){ - titleParts.push(disk.device_type) - } - titleParts.push(disk.model_name) - - break; - case 'serial_id': - if(!disk.device_serial_id) return '' - titleParts.push(`/by-id/${disk.device_serial_id}`) - break; - case 'uuid': - if(!disk.device_uuid) return '' - titleParts.push(`/by-uuid/${disk.device_uuid}`) - break; - case 'label': - if(disk.label){ - titleParts.push(disk.label) - } else if(disk.device_label){ - titleParts.push(`/by-label/${disk.device_label}`) - } - break; - } - return titleParts.join(' - ') - } - // ----------------------------------------------------------------------------------------------------- // @ Public methods // ----------------------------------------------------------------------------------------------------- - openDialog() { - const dialogRef = this.dialog.open(DashboardSettingsComponent); - - dialogRef.afterClosed().subscribe(result => { - console.log(`Dialog result: ${result}`); - }); - } - deviceTitle(disk){ console.log(`Displaying Device ${disk.wwn} with: ${this.config.dashboardDisplay}`) @@ -252,37 +211,17 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy if (disk.host_id) titleParts.push(disk.host_id) //add device identifier (fallback to generated device name) - titleParts.push(this._deviceDisplayTitle(disk, this.config.dashboardDisplay) || this._deviceDisplayTitle(disk, 'name')) + titleParts.push(deviceDisplayTitle(disk, this.config.dashboardDisplay) || deviceDisplayTitle(disk, 'name')) return titleParts.join(' - ') } - deviceStatusString(deviceStatus){ - if(deviceStatus == 0){ - return "passed" - } else { - return "failed" - } - } + openDialog() { + const dialogRef = this.dialog.open(DashboardSettingsComponent); - classDeviceLastUpdatedOn(deviceSummary){ - if (deviceSummary.device.device_status !== 0) { - return 'text-red' // if the device has failed, always highlight in red - } else if(deviceSummary.device.device_status === 0 && deviceSummary.smart){ - if(moment().subtract(14, 'd').isBefore(deviceSummary.smart.collector_date)){ - // this device was updated in the last 2 weeks. - return 'text-green' - } else if(moment().subtract(1, 'm').isBefore(deviceSummary.smart.collector_date)){ - // this device was updated in the last month - return 'text-yellow' - } else{ - // last updated more than a month ago. - return 'text-red' - } - - } else { - return '' - } + dialogRef.afterClosed().subscribe(result => { + console.log(`Dialog result: ${result}`); + }); } /* @@ -321,6 +260,4 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy return item.id || index; } - readonly humanizeDuration = humanizeDuration; - } diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.module.ts b/webapp/frontend/src/app/modules/dashboard/dashboard.module.ts index 2de2203..0eca908 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.module.ts +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.module.ts @@ -13,12 +13,13 @@ import { MatTableModule } from '@angular/material/table'; import { NgApexchartsModule } from 'ng-apexcharts'; import { MatTooltipModule } from '@angular/material/tooltip' import { DashboardSettingsModule } from "app/layout/common/dashboard-settings/dashboard-settings.module"; +import { DashboardDeviceModule } from "app/layout/common/dashboard-device/dashboard-device.module"; @NgModule({ declarations: [ DashboardComponent ], - imports : [ + imports: [ RouterModule.forChild(dashboardRoutes), MatButtonModule, MatDividerModule, @@ -30,7 +31,8 @@ import { DashboardSettingsModule } from "app/layout/common/dashboard-settings/da MatTableModule, NgApexchartsModule, SharedModule, - DashboardSettingsModule + DashboardSettingsModule, + DashboardDeviceModule ] }) export class DashboardModule