@ -1,18 +1,21 @@
import { AfterViewInit , Component , OnDestroy , OnInit , ViewChild } from '@angular/core' ;
import humanizeDuration from 'humanize-duration' ;
import { AfterViewInit , Component , Inject , LOCALE_ID , OnDestroy , OnInit , ViewChild } from '@angular/core' ;
import { ApexOptions } from 'ng-apexcharts' ;
import { MatTableDataSource } from '@angular/material/table' ;
import { MatSort } from '@angular/material/sort' ;
import { Subject } from 'rxjs' ;
import { AppConfig } from 'app/core/config/app.config' ;
import { DetailService } from './detail.service' ;
import { takeUntil } from 'rxjs/operators' ;
import { DetailSettingsComponent } from 'app/layout/common/detail-settings/detail-settings.component' ;
import { MatDialog } from '@angular/material/dialog' ;
import humanizeDuration from 'humanize-duration' ;
import { MatSort } from '@angular/material/sort' ;
import { MatTableDataSource } from '@angular/material/table' ;
import { Subject } from 'rxjs' ;
import { TreoConfigService } from '@treo/services/config' ;
import { AppConfig } from 'app/core/config/app.config' ;
import { animate , state , style , transition , trigger } from '@angular/animations' ;
import { formatDate } from '@angular/common' ;
import { LOCALE_ID , Inject } from '@angular/core' ;
import { takeUntil } from 'rxjs/operators' ;
import { DeviceModel } from 'app/core/models/device-model' ;
import { SmartModel } from 'app/core/models/measurements/smart-model' ;
import { SmartAttributeModel } from 'app/core/models/measurements/smart-attribute-model' ;
import { AttributeMetadataModel } from 'app/core/models/thresholds/attribute-metadata-model' ;
// from Constants.go - these must match
const AttributeStatusPassed = 0
@ -22,9 +25,9 @@ const AttributeStatusFailedScrutiny = 4
@Component ( {
selector : 'detail' ,
templateUrl : './detail.component.html' ,
styleUrls : [ './detail.component.scss' ] ,
selector : 'detail' ,
templateUrl : './detail.component.html' ,
styleUrls : [ './detail.component.scss' ] ,
animations : [
trigger ( 'detailExpand' , [
state ( 'collapsed' , style ( { height : '0px' , minHeight : '0' } ) ) ,
@ -40,22 +43,23 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
* Constructor
*
* @param { DetailService } _detailService
* @param { MatDialog } dialog
* @param { TreoConfigService } _configService
* @param { string } locale
* /
constructor (
private _detailService : DetailService ,
public dialog : MatDialog ,
private _configService : TreoConfigService ,
@Inject ( LOCALE_ID ) public locale : string
)
{
) {
// Set the private defaults
this . _unsubscribeAll = new Subject ( ) ;
// Set the defaults
this . smartAttributeDataSource = new MatTableDataSource ( ) ;
// this.recentTransactionsTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh'];
this . smartAttributeTableColumns = [ 'status' , 'id' , 'name' , 'value' , 'worst' , 'thresh' , 'ideal' , 'failure' , 'history' ] ;
this . smartAttributeTableColumns = [ 'status' , 'id' , 'name' , 'value' , 'worst' , 'thresh' , 'ideal' , 'failure' , 'history' ] ;
this . systemPrefersDark = window . matchMedia && window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ;
@ -65,14 +69,15 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
onlyCritical = true ;
// data: any;
expandedAttribute : any | null ;
expandedAttribute : SmartAttributeModel | null ;
metadata : any ;
device : any ;
smart_results : any [ ] ;
metadata : { [ p : string ] : AttributeMetadataModel } | { [ p : number ] : AttributeMetadataModel } ;
device : DeviceModel ;
// tslint:disable-next-line:variable-name
smart_results : SmartModel [ ] ;
commonSparklineOptions : Partial < ApexOptions > ;
smartAttributeDataSource : MatTableDataSource < any > ;
smartAttributeDataSource : MatTableDataSource < SmartAttributeModel > ;
smartAttributeTableColumns : string [ ] ;
@ViewChild ( 'smartAttributeTable' , { read : MatSort } )
@ -91,8 +96,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
/ * *
* On init
* /
ngOnInit ( ) : void
{
ngOnInit ( ) : void {
// Subscribe to config changes
this . _configService . config $
. pipe ( takeUntil ( this . _unsubscribeAll ) )
@ -104,13 +108,13 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
// Get the data
this . _detailService . data $
. pipe ( takeUntil ( this . _unsubscribeAll ) )
. subscribe ( ( data ) = > {
. subscribe ( ( respWrapper ) = > {
// Store the data
// this.data = data;
this . device = data . data . device ;
this . smart_results = data . data . smart_results
this . metadata = data . metadata ;
this . device = respWrapper . data . device ;
this . smart_results = respWrapper . data . smart_results
this . metadata = respWrapper . metadata ;
// Store the table data
@ -124,8 +128,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
/ * *
* After view init
* /
ngAfterViewInit ( ) : void
{
ngAfterViewInit ( ) : void {
// Make the data source sortable
this . smartAttributeDataSource . sort = this . smartAttributeTableMatSort ;
}
@ -133,8 +136,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
/ * *
* On destroy
* /
ngOnDestroy ( ) : void
{
ngOnDestroy ( ) : void {
// Unsubscribe from all subscriptions
this . _unsubscribeAll . next ( ) ;
this . _unsubscribeAll . complete ( ) ;
@ -147,22 +149,23 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
getAttributeStatusName ( attributeStatus : number ) : string {
// tslint:disable:no-bitwise
if ( attributeStatus === AttributeStatusPassed ) {
if ( attributeStatus === AttributeStatusPassed ) {
return 'passed'
} else if ( ( attributeStatus & AttributeStatusFailedScrutiny ) !== 0 || ( attributeStatus & AttributeStatusFailedSmart ) !== 0 ) {
} else if ( ( attributeStatus & AttributeStatusFailedScrutiny ) !== 0 || ( attributeStatus & AttributeStatusFailedSmart ) !== 0 ) {
return 'failed'
} else if ( ( attributeStatus & AttributeStatusWarningScrutiny ) !== 0 ) {
} else if ( ( attributeStatus & AttributeStatusWarningScrutiny ) !== 0 ) {
return 'warn'
}
return ''
// tslint:enable:no-bitwise
}
getAttributeScrutinyStatusName ( attributeStatus : number ) : string {
// tslint:disable:no-bitwise
if ( ( attributeStatus & AttributeStatusFailedScrutiny ) !== 0 ) {
if ( ( attributeStatus & AttributeStatusFailedScrutiny ) !== 0 ) {
return 'failed'
} else if ( ( attributeStatus & AttributeStatusWarningScrutiny ) !== 0 ) {
} else if ( ( attributeStatus & AttributeStatusWarningScrutiny ) !== 0 ) {
return 'warn'
} else {
return 'passed'
@ -172,7 +175,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
getAttributeSmartStatusName ( attributeStatus : number ) : string {
// tslint:disable:no-bitwise
if ( ( attributeStatus & AttributeStatusFailedSmart ) !== 0 ) {
if ( ( attributeStatus & AttributeStatusFailedSmart ) !== 0 ) {
return 'failed'
} else {
return 'passed'
@ -181,138 +184,140 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
}
getAttributeName ( attribute _data ) : string {
const attribute _metadata = this . metadata [ attribute_d ata. attribute_id ]
if ( ! attribute_metadata ) {
getAttributeName ( attribute Data: SmartAttributeModel ) : string {
const attribute Metadata = this . metadata [ attributeD ata. attribute_id ]
if ( ! attributeMetadata ) {
return 'Unknown Attribute Name'
} else {
return attribute _m etadata. display_name
return attribute M etadata. display_name
}
}
getAttributeDescription ( attribute_data ) {
const attribute_metadata = this . metadata [ attribute_data . attribute_id ]
if ( ! attribute_metadata ) {
getAttributeDescription ( attributeData : SmartAttributeModel ) : string {
const attributeMetadata = this . metadata [ attributeData . attribute_id ]
if ( ! attributeMetadata ) {
return 'Unknown'
} else {
return attribute _m etadata. description
return attribute M etadata. description
}
return
}
getAttributeValue ( attribute _data) {
if ( this . isAta ( ) ) {
const attribute _metadata = this . metadata [ attribute_d ata. attribute_id ]
if ( ! attribute_metadata ) {
return attribute _d ata. value
} else if ( attribute _metadata. display_type == 'raw' ) {
return attribute _d ata. raw_value
} else if ( attribute _metadata. display_type == 'transformed' && attribute_d ata. transformed_value ) {
return attribute _d ata. transformed_value
getAttributeValue ( attribute Data: SmartAttributeModel ) : number {
if ( this . isAta ( ) ) {
const attribute Metadata = this . metadata [ attributeD ata. attribute_id ]
if ( ! attributeMetadata ) {
return attribute D ata. value
} else if ( attribute Metadata. display_type = == 'raw' ) {
return attribute D ata. raw_value
} else if ( attribute Metadata. display_type === 'transformed' && attributeD ata. transformed_value ) {
return attribute D ata. transformed_value
} else {
return attribute _d ata. value
return attribute D ata. value
}
}
else {
return attribute_data . value
} else {
return attributeData . value
}
}
getAttributeValueType ( attribute _data) {
if ( this . isAta ( ) ) {
const attribute _metadata = this . metadata [ attribute_d ata. attribute_id ]
if ( ! attribute_metadata ) {
getAttributeValueType ( attribute Data: SmartAttributeModel ) : string {
if ( this . isAta ( ) ) {
const attribute Metadata = this . metadata [ attributeD ata. attribute_id ]
if ( ! attributeMetadata ) {
return ''
} else {
return attribute _m etadata. display_type
return attribute M etadata. display_type
}
} else {
return ''
}
}
getAttributeIdeal ( attribute _data) {
if ( this . isAta ( ) ) {
return this . metadata [ attribute _d ata. attribute_id ] ? . display_type == 'raw' ? this . metadata [ attribute _d ata. attribute_id ] ? . ideal : ''
getAttributeIdeal ( attribute Data: SmartAttributeModel ) : string {
if ( this . isAta ( ) ) {
return this . metadata [ attribute D ata. attribute_id ] ? . display_type = == 'raw' ? this . metadata [ attribute D ata. attribute_id ] ? . ideal : ''
} else {
return this . metadata [ attribute _d ata. attribute_id ] ? . ideal
return this . metadata [ attribute D ata. attribute_id ] ? . ideal
}
}
getAttributeWorst ( attribute _data) {
const attribute _metadata = this . metadata [ attribute_d ata. attribute_id ]
if ( ! attribute_metadata ) {
return attribute _d ata. worst
getAttributeWorst ( attribute Data: SmartAttributeModel ) : number | string {
const attribute Metadata = this . metadata [ attributeD ata. attribute_id ]
if ( ! attributeMetadata ) {
return attribute D ata. worst
} else {
return attribute _m etadata? . display_type == 'normalized' ? attribute _d ata. worst : ''
return attribute M etadata? . display_type = == 'normalized' ? attribute D ata. worst : ''
}
}
getAttributeThreshold ( attribute _data) {
if ( this . isAta ( ) ) {
const attribute _metadata = this . metadata [ attribute_d ata. attribute_id ]
if ( ! attribute_metadata || attribute_metadata . display_type == 'normalized' ) {
return attribute _d ata. thresh
getAttributeThreshold ( attribute Data: SmartAttributeModel ) : number | string {
if ( this . isAta ( ) ) {
const attribute Metadata = this . metadata [ attributeD ata. attribute_id ]
if ( ! attributeMetadata || attributeMetadata . display_type === 'normalized' ) {
return attribute D ata. thresh
} else {
// if(this.data.metadata[attribute_data.attribute_id].observed_thresholds){
//
// } else {
// }
// return ''
return attribute _d ata. thresh
return attribute D ata. thresh
}
} else {
return ( attribute _data. thresh == - 1 ? '' : attribute_data . thresh )
return ( attribute Data. thresh === - 1 ? '' : attributeData . thresh )
}
}
getAttributeCritical ( attribute _data) {
return this . metadata [ attribute _d ata. attribute_id ] ? . critical
getAttributeCritical ( attribute Data: SmartAttributeModel ) : boolean {
return this . metadata [ attribute D ata. attribute_id ] ? . critical
}
getHiddenAttributes ( ) {
if ( ! this . smart_results || this . smart_results . length == 0 ) {
getHiddenAttributes ( ) : number {
if ( ! this . smart_results || this . smart_results . length === 0 ) {
return 0
}
let attributes _l ength = 0
let attributes L ength = 0
const attributes = this . smart_results [ 0 ] ? . attrs
if ( attributes ) {
attributes _l ength = Object . keys ( attributes ) . length
attributes L ength = Object . keys ( attributes ) . length
}
return attributes _l ength - this . smartAttributeDataSource . data . length
return attributes L ength - this . smartAttributeDataSource . data . length
}
isAta ( ) : boolean {
return this . device . device_protocol == 'ATA'
return this . device . device_protocol == = 'ATA'
}
isScsi ( ) : boolean {
return this . device . device_protocol == 'SCSI'
return this . device . device_protocol == = 'SCSI'
}
isNvme ( ) : boolean {
return this . device . device_protocol == 'NVMe'
return this . device . device_protocol == = 'NVMe'
}
private _generateSmartAttributeTableDataSource ( smart _results) {
const smartAttributeDataSource = [ ] ;
private _generateSmartAttributeTableDataSource ( smart Results: SmartModel [ ] ) : SmartAttributeModel [ ] {
const smartAttributeDataSource : SmartAttributeModel [ ] = [ ] ;
if ( smart_results . length == 0 ) {
if ( smartResults . length === 0 ) {
return smartAttributeDataSource
}
const latest _smart_result = smart_r esults[ 0 ] ;
let attributes = { }
if ( this . isScsi ( ) ) {
const latest SmartResult = smartR esults[ 0 ] ;
let attributes : { [ p : string ] : SmartAttributeModel } = { }
if ( this . isScsi ( ) ) {
this . smartAttributeTableColumns = [ 'status' , 'name' , 'value' , 'thresh' , 'history' ] ;
attributes = latest _smart_r esult. attrs
} else if ( this . isNvme ( ) ) {
attributes = latest SmartR esult. attrs
} else if ( this . isNvme ( ) ) {
this . smartAttributeTableColumns = [ 'status' , 'name' , 'value' , 'thresh' , 'ideal' , 'history' ] ;
attributes = latest _smart_r esult. attrs
attributes = latest SmartR esult. attrs
} else {
// ATA
attributes = latest _smart_r esult. attrs
this . smartAttributeTableColumns = [ 'status' , 'id' , 'name' , 'value' , 'thresh' , 'ideal' , 'failure' , 'history' ] ;
attributes = latest SmartR esult. attrs
this . smartAttributeTableColumns = [ 'status' , 'id' , 'name' , 'value' , 'thresh' , 'ideal' , 'failure' , 'history' ] ;
}
for ( const attrId in attributes ) {
for ( const attrId in attributes ) {
const attr = attributes [ attrId ]
// chart history data
@ -320,18 +325,18 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
const attrHistory = [ ]
for ( const smart _result of smart_results ) {
for ( const smart Result of smartResults ) {
// attrHistory.push(this.getAttributeValue(smart_result.attrs[attrId]))
const chartDatapoint = {
x : formatDate ( smart _r esult. date , 'MMMM dd, yyyy - HH:mm' , this . locale ) ,
y : this.getAttributeValue ( smart _r esult. attrs [ attrId ] )
x : formatDate ( smart R esult. date , 'MMMM dd, yyyy - HH:mm' , this . locale ) ,
y : this.getAttributeValue ( smart R esult. attrs [ attrId ] )
}
const attributeStatusName = this . getAttributeStatusName ( smart _r esult. attrs [ attrId ] . status )
if ( attributeStatusName === 'failed' ) {
const attributeStatusName = this . getAttributeStatusName ( smart R esult. attrs [ attrId ] . status )
if ( attributeStatusName === 'failed' ) {
chartDatapoint [ 'strokeColor' ] = '#F05252'
chartDatapoint [ 'fillColor' ] = '#F05252'
} else if ( attributeStatusName === 'warn' ) {
} else if ( attributeStatusName === 'warn' ) {
chartDatapoint [ 'strokeColor' ] = '#C27803'
chartDatapoint [ 'fillColor' ] = '#C27803'
}
@ -350,7 +355,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
}
// determine when to include the attributes in table.
if ( ! this . onlyCritical || this . onlyCritical && this . metadata [ attr . attribute_id ] ? . critical || attr . value < attr . thresh ) {
if ( ! this . onlyCritical || this . onlyCritical && this . metadata [ attr . attribute_id ] ? . critical || attr . value < attr . thresh ) {
smartAttributeDataSource . push ( attr )
}
}
@ -362,8 +367,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
*
* @private
* /
private _prepareChartData ( ) : void
{
private _prepareChartData ( ) : void {
// Account balance
this . commonSparklineOptions = {
@ -392,7 +396,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
} ,
y : {
title : {
formatter : function ( seriesName ) {
formatter : ( seriesName ) = > {
return '' ;
}
}
@ -410,27 +414,28 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
} ;
}
private determineTheme ( config :AppConfig ) : string {
private determineTheme ( config : AppConfig ) : string {
if ( config . theme === 'system' ) {
return this . systemPrefersDark ? 'dark' : 'light'
} else {
return config . theme
}
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
toHex ( decimalNumb ) {
toHex ( decimalNumb : number | string ) : string {
return '0x' + Number ( decimalNumb ) . toString ( 16 ) . padStart ( 2 , '0' ) . toUpperCase ( )
}
toggleOnlyCritical ( ) {
toggleOnlyCritical ( ) : void {
this . onlyCritical = ! this . onlyCritical
this . smartAttributeDataSource . data = this . _generateSmartAttributeTableDataSource ( this . smart_results ) ;
}
openDialog () {
openDialog ( ): void {
const dialogRef = this . dialog . open ( DetailSettingsComponent ) ;
dialogRef . afterClosed ( ) . subscribe ( result = > {
@ -444,8 +449,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
* @param index
* @param item
* /
trackByFn ( index : number , item : any ) : any
{
trackByFn ( index : number , item : any ) : any {
return index ;
// return item.id || index;
}