Merge branch 'master' into BASEPATH
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<div *ngIf="data && data.data && data.data.length > 0; else emptyDashboard">
|
||||
|
||||
<div *ngIf="data && data.data && data.data.summary; else emptyDashboard">
|
||||
<div class="flex flex-col flex-auto w-full p-8 xs:p-2">
|
||||
|
||||
<div class="flex flex-wrap w-full">
|
||||
@@ -47,38 +48,36 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap w-full">
|
||||
|
||||
<div *ngFor="let disk of data.data | deviceSort" class="flex gt-sm:w-1/2 min-w-80 p-4">
|
||||
<div [ngClass]="{'border-green': disk.smart_results[0]?.smart_status == 'passed',
|
||||
'border-red': disk.smart_results[0]?.smart_status == 'failed' }"
|
||||
<div *ngFor="let summary of data.data.summary | keyvalue" class="flex gt-sm:w-1/2 min-w-80 p-4">
|
||||
<div [ngClass]="{ 'border-green': summary.value.device.device_status == 0 && summary.value.smart,
|
||||
'border-red': summary.value.device.device_status != 0 }"
|
||||
class="relative flex flex-col flex-auto p-6 pr-3 pb-3 bg-card rounded border-l-4 shadow-md overflow-hidden">
|
||||
<div class="absolute bottom-0 right-0 w-24 h-24 -m-6">
|
||||
<mat-icon class="icon-size-96 opacity-12 text-green"
|
||||
*ngIf="disk.smart_results[0]?.smart_status == 'passed'"
|
||||
*ngIf="summary.value.device.device_status == 0 && summary.value.smart"
|
||||
[svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
|
||||
<mat-icon class="icon-size-96 opacity-12 text-red"
|
||||
*ngIf="disk.smart_results[0]?.smart_status == 'failed'"
|
||||
*ngIf="summary.value.device.device_status != 0"
|
||||
[svgIcon]="'heroicons_outline:exclamation-circle'"></mat-icon>
|
||||
<mat-icon class="icon-size-96 opacity-12 text-yellow"
|
||||
*ngIf="!disk.smart_results[0]"
|
||||
*ngIf="!summary.value.smart"
|
||||
[svgIcon]="'heroicons_outline:question-mark-circle'"></mat-icon>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-col">
|
||||
<a [routerLink]="'/device/'+ disk.wwn"
|
||||
class="font-bold text-md text-secondary uppercase tracking-wider">{{deviceTitle(disk)}}</a>
|
||||
<div [ngClass]="{'text-green': disk.smart_results[0]?.smart_status == 'passed',
|
||||
'text-red': disk.smart_results[0]?.smart_status == 'failed' }" class="font-medium text-sm" *ngIf="disk.smart_results[0]">
|
||||
Last Updated on {{disk.smart_results[0]?.date | date:'MMMM dd, yyyy - HH:mm' }}
|
||||
<a [routerLink]="'/device/'+ summary.value.device.wwn"
|
||||
class="font-bold text-md text-secondary uppercase tracking-wider">{{deviceTitle(summary.value.device)}}</a>
|
||||
<div [ngClass]="classDeviceLastUpdatedOn(summary.value)" class="font-medium text-sm" *ngIf="summary.value.smart">
|
||||
Last Updated on {{summary.value.smart.collector_date | date:'MMMM dd, yyyy - HH:mm' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-auto" *ngIf="disk.smart_results">
|
||||
<div class="ml-auto" *ngIf="summary.value.device">
|
||||
<button mat-icon-button
|
||||
[matMenuTriggerFor]="previousStatementMenu">
|
||||
<mat-icon [svgIcon]="'more_vert'"></mat-icon>
|
||||
</button>
|
||||
<mat-menu #previousStatementMenu="matMenu">
|
||||
<a mat-menu-item [routerLink]="'/device/'+ disk.wwn">
|
||||
<a mat-menu-item [routerLink]="'/device/'+ summary.value.device.wwn">
|
||||
<span class="flex items-center">
|
||||
<mat-icon class="icon-size-20 mr-3"
|
||||
[svgIcon]="'payment'"></mat-icon>
|
||||
@@ -90,22 +89,22 @@
|
||||
</div>
|
||||
<div class="flex flex-row flex-wrap mt-4 -mx-6">
|
||||
<div class="flex flex-col mx-6 my-3 xs:w-full">
|
||||
<div class="font-semibold text-xs text-hint uppercase tracking-wider leading-none">S.M.A.R.T</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none" *ngIf="disk.smart_results[0]; else unknownStatus">{{ disk.smart_results[0]?.smart_status | titlecase}}</div>
|
||||
<div class="font-semibold text-xs text-hint uppercase tracking-wider leading-none">Status</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none" *ngIf="summary.value.smart?.collector_date; else unknownStatus">{{ deviceStatusString(summary.value.device.device_status) | titlecase}}</div>
|
||||
<ng-template #unknownStatus><div class="mt-2 font-medium text-3xl leading-none">No Data</div></ng-template>
|
||||
</div>
|
||||
<div class="flex flex-col mx-6 my-3 xs:w-full">
|
||||
<div class="font-semibold text-xs text-hint uppercase tracking-wider leading-none">Temperature</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none" *ngIf="disk.smart_results[0]; else unknownTemp">{{ disk.smart_results[0]?.temp }}°C</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none" *ngIf="summary.value.smart?.collector_date; else unknownTemp">{{ summary.value.smart?.temp }}°C</div>
|
||||
<ng-template #unknownTemp><div class="mt-2 font-medium text-3xl leading-none">--</div></ng-template>
|
||||
</div>
|
||||
<div class="flex flex-col mx-6 my-3 xs:w-full">
|
||||
<div class="font-semibold text-xs text-hint uppercase tracking-wider leading-none">Capacity</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none">{{ disk.capacity | fileSize}}</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none">{{ summary.value.device.capacity | fileSize}}</div>
|
||||
</div>
|
||||
<div class="flex flex-col mx-6 my-3 xs:w-full">
|
||||
<div class="font-semibold text-xs text-hint uppercase tracking-wider leading-none">Powered On</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none" *ngIf="disk.smart_results[0]?.power_on_hours; else unknownPoweredOn">{{ humanizeDuration(disk.smart_results[0]?.power_on_hours * 60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] }) }}</div>
|
||||
<div class="mt-2 font-medium text-3xl leading-none" *ngIf="summary.value.smart?.power_on_hours; else unknownPoweredOn">{{ humanizeDuration(summary.value.smart?.power_on_hours * 60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] }) }}</div>
|
||||
<ng-template #unknownPoweredOn><div class="mt-2 font-medium text-3xl leading-none">--</div></ng-template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -126,21 +125,20 @@
|
||||
<button class="h-8 min-h-8 px-2"
|
||||
matTooltip="not yet implemented"
|
||||
mat-button
|
||||
[matMenuTriggerFor]="accountBalanceMenu">
|
||||
<span class="font-medium text-sm text-hint">12 months</span>
|
||||
[matMenuTriggerFor]="tempRangeMenu">
|
||||
<span class="font-medium text-sm text-hint">1 week</span>
|
||||
</button>
|
||||
<mat-menu #accountBalanceMenu="matMenu">
|
||||
<button mat-menu-item>3 months</button>
|
||||
<button mat-menu-item>6 months</button>
|
||||
<button mat-menu-item>9 months</button>
|
||||
<mat-menu #tempRangeMenu="matMenu">
|
||||
<button mat-menu-item>1 month</button>
|
||||
<button mat-menu-item>12 months</button>
|
||||
<button mat-menu-item>all time</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto">
|
||||
<apx-chart class="flex-auto w-full h-full"
|
||||
<apx-chart *ngIf="temperatureOptions" class="flex-auto w-full h-full"
|
||||
[chart]="temperatureOptions.chart"
|
||||
[colors]="temperatureOptions.colors"
|
||||
[fill]="temperatureOptions.fill"
|
||||
|
||||
@@ -84,16 +84,23 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
private _deviceDataTemperatureSeries() {
|
||||
var deviceTemperatureSeries = []
|
||||
|
||||
for(let device of this.data.data){
|
||||
console.log("DEVICE DATA SUMMARY", this.data)
|
||||
|
||||
for(const wwn in this.data.data.summary){
|
||||
var deviceSummary = this.data.data.summary[wwn]
|
||||
if (!deviceSummary.temp_history){
|
||||
continue
|
||||
}
|
||||
var deviceSeriesMetadata = {
|
||||
name: `/dev/${device.device_name}`,
|
||||
name: `/dev/${deviceSummary.device.device_name}`,
|
||||
data: []
|
||||
}
|
||||
for(let smartResults of device.smart_results){
|
||||
let newDate = new Date(smartResults.CreatedAt);
|
||||
|
||||
for(let tempHistory of deviceSummary.temp_history){
|
||||
let newDate = new Date(tempHistory.date);
|
||||
deviceSeriesMetadata.data.push({
|
||||
x: newDate,
|
||||
y: smartResults.temp
|
||||
y: tempHistory.temp
|
||||
})
|
||||
}
|
||||
deviceTemperatureSeries.push(deviceSeriesMetadata)
|
||||
@@ -181,6 +188,34 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
return title.join(' - ')
|
||||
}
|
||||
|
||||
deviceStatusString(deviceStatus){
|
||||
if(deviceStatus == 0){
|
||||
return "passed"
|
||||
} else {
|
||||
return "failed"
|
||||
}
|
||||
}
|
||||
|
||||
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 ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track by function for ngFor loops
|
||||
*
|
||||
|
||||
@@ -53,59 +53,73 @@
|
||||
<div class="flex flex-auto w-1/4 p-4 lt-md:w-full">
|
||||
<treo-card class="flex flex-auto p-4 pt-6 flex-col flex-auto filter-list">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-2xl font-semibold leading-tight">/dev/{{data.data.device_name}}</div>
|
||||
<div class="text-2xl font-semibold leading-tight">/dev/{{device?.device_name}}</div>
|
||||
</div>
|
||||
<div class="flex flex-col my-2 grid grid-cols-2">
|
||||
<div *ngIf="data.data.host_id" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.host_id}}</div>
|
||||
<div *ngIf="device" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>
|
||||
<span class="inline-flex items-center font-bold text-xs px-2 py-2px rounded-full tracking-wide uppercase"
|
||||
[ngClass]="{'red-200': device?.device_status != 0,
|
||||
'green-200': device?.device_status == 0}">
|
||||
<span class="w-2 h-2 rounded-full mr-2"
|
||||
[ngClass]="{'bg-red': device?.device_status != 0,
|
||||
'bg-green': device?.device_status == 0}"></span>
|
||||
<span class="pr-2px leading-relaxed whitespace-no-wrap">{{device?.device_status == 0 ? 'passed' : 'failed'}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-secondary text-md">Status</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="device?.host_id" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{device?.host_id}}</div>
|
||||
<div class="text-secondary text-md">Host ID</div>
|
||||
</div>
|
||||
<div *ngIf="data.data.device_type && data.data.device_type != 'ata' && data.data.device_type != 'scsi'" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.device_type | uppercase}}</div>
|
||||
<div *ngIf="device?.device_type && device?.device_type != 'ata' && device?.device_type != 'scsi'" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{device?.device_type | uppercase}}</div>
|
||||
<div class="text-secondary text-md">Device Type</div>
|
||||
</div>
|
||||
<div *ngIf="data.data.manufacturer" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.manufacturer}}</div>
|
||||
<div *ngIf="device?.manufacturer" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{device?.manufacturer}}</div>
|
||||
<div class="text-secondary text-md">Model Family</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.model_name}}</div>
|
||||
<div>{{device?.model_name}}</div>
|
||||
<div class="text-secondary text-md">Device Model</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.serial_number}}</div>
|
||||
<div>{{device?.serial_number}}</div>
|
||||
<div class="text-secondary text-md">Serial Number</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.wwn}}</div>
|
||||
<div>{{device?.wwn}}</div>
|
||||
<div class="text-secondary text-md">LU WWN Device Id</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.firmware}}</div>
|
||||
<div>{{device?.firmware}}</div>
|
||||
<div class="text-secondary text-md">Firmware Version</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.capacity | fileSize}}</div>
|
||||
<div>{{device?.capacity | fileSize}}</div>
|
||||
<div class="text-secondary text-md">Capacity</div>
|
||||
</div>
|
||||
<div *ngIf="data.data.rotational_speed" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.rotational_speed}} RPM</div>
|
||||
<div *ngIf="device?.rotational_speed" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{device?.rotational_speed}} RPM</div>
|
||||
<div class="text-secondary text-md">Rotation Rate</div>
|
||||
</div>
|
||||
<div *ngIf="data.data.device_protocol" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.device_protocol}}</div>
|
||||
<div *ngIf="device?.device_protocol" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{device?.device_protocol}}</div>
|
||||
<div class="text-secondary text-md">Protocol</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.smart_results[0]?.power_cycle_count}}</div>
|
||||
<div>{{smart_results[0]?.power_cycle_count}}</div>
|
||||
<div class="text-secondary text-md">Power Cycle Count</div>
|
||||
</div>
|
||||
<div *ngIf="data.data.smart_results[0]?.power_on_hours" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div matTooltip="{{humanizeDuration(data.data.smart_results[0]?.power_on_hours * 60 * 60 * 1000, { conjunction: ' and ', serialComma: false })}}">{{humanizeDuration(data.data.smart_results[0]?.power_on_hours *60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] })}}</div>
|
||||
<div *ngIf="smart_results[0]?.power_on_hours" class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div matTooltip="{{humanizeDuration(smart_results[0]?.power_on_hours * 60 * 60 * 1000, { conjunction: ' and ', serialComma: false })}}">{{humanizeDuration(smart_results[0]?.power_on_hours *60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] })}}</div>
|
||||
<div class="text-secondary text-md">Powered On</div>
|
||||
</div>
|
||||
<div class="my-2 col-span-2 lt-md:col-span-1">
|
||||
<div>{{data.data.smart_results[0]?.temp}}°C</div>
|
||||
<div>{{smart_results[0]?.temp}}°C</div>
|
||||
<div class="text-secondary text-md">Temperature</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,7 +129,7 @@
|
||||
<div class="flex flex-auto w-3/4 p-4 lt-md:w-full">
|
||||
<div class="flex flex-col flex-auto w-full bg-card shadow-md rounded ">
|
||||
<div class="p-6">
|
||||
<div class="font-bold text-md text-secondary uppercase tracking-wider">S.M.A.R.T {{data.data.device_protocol}} Attributes</div>
|
||||
<div class="font-bold text-md text-secondary uppercase tracking-wider">S.M.A.R.T {{device?.device_protocol}} Attributes</div>
|
||||
<div class="text-sm text-hint font-medium">{{this.smartAttributeDataSource.data.length}} visible, {{getHiddenAttributes()}} hidden</div>
|
||||
</div>
|
||||
<div class="overflow-auto">
|
||||
@@ -139,15 +153,15 @@
|
||||
<td mat-cell
|
||||
*matCellDef="let attribute">
|
||||
<span class="inline-flex items-center font-bold text-xs px-2 py-2px rounded-full tracking-wide uppercase"
|
||||
[ngClass]="{'red-200': attribute.status === 'failed',
|
||||
'green-200': attribute.status === 'passed',
|
||||
'yellow-200': attribute.status === 'warn'
|
||||
[ngClass]="{'red-200': getAttributeStatusName(attribute.status) === 'failed',
|
||||
'green-200': getAttributeStatusName(attribute.status) === 'passed',
|
||||
'yellow-200': getAttributeStatusName(attribute.status) === 'warn'
|
||||
}">
|
||||
<span class="w-2 h-2 rounded-full mr-2"
|
||||
[ngClass]="{'bg-red': attribute.status === 'failed',
|
||||
'bg-green': attribute.status === 'passed',
|
||||
'bg-yellow': attribute.status === 'warn'}"></span>
|
||||
<span class="pr-2px leading-relaxed whitespace-no-wrap" matTooltip="{{attribute.status_reason}}">{{attribute.status}}</span>
|
||||
[ngClass]="{'bg-red': getAttributeStatusName(attribute.status) === 'failed',
|
||||
'bg-green': getAttributeStatusName(attribute.status) === 'passed',
|
||||
'bg-yellow': getAttributeStatusName(attribute.status) === 'warn'}"></span>
|
||||
<span class="pr-2px leading-relaxed whitespace-no-wrap" matTooltip="{{attribute.status_reason}}">{{getAttributeStatusName(attribute.status)}}</span>
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
@@ -183,7 +197,7 @@
|
||||
<td mat-cell
|
||||
*matCellDef="let attribute">
|
||||
<span class="pr-6 whitespace-no-wrap" matTooltip="{{getAttributeDescription(attribute)}}">
|
||||
{{attribute.name}} <mat-icon *ngIf="getAttributeDescription(attribute)" class="icon-size-10" [svgIcon]="'info'"></mat-icon>
|
||||
{{getAttributeName(attribute)}} <mat-icon *ngIf="getAttributeDescription(attribute)" class="icon-size-10" [svgIcon]="'info'"></mat-icon>
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@@ -19,7 +19,12 @@ import humanizeDuration from 'humanize-duration';
|
||||
export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
onlyCritical: boolean = true;
|
||||
data: any;
|
||||
// data: any;
|
||||
|
||||
metadata: any;
|
||||
device: any;
|
||||
smart_results: any[];
|
||||
|
||||
commonSparklineOptions: Partial<ApexOptions>;
|
||||
smartAttributeDataSource: MatTableDataSource<any>;
|
||||
smartAttributeTableColumns: string[];
|
||||
@@ -66,10 +71,14 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
.subscribe((data) => {
|
||||
|
||||
// Store the data
|
||||
this.data = data;
|
||||
// this.data = data;
|
||||
this.device = data.data.device;
|
||||
this.smart_results = data.data.smart_results
|
||||
this.metadata = data.metadata;
|
||||
|
||||
|
||||
// Store the table data
|
||||
this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(data.data.smart_results);
|
||||
this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.smart_results);
|
||||
|
||||
// Prepare the chart data
|
||||
this._prepareChartData();
|
||||
@@ -98,8 +107,28 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Private methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
getAttributeStatusName(attribute_status){
|
||||
if(attribute_status == 0){
|
||||
return "passed"
|
||||
} else if (attribute_status == 1){
|
||||
return "warn"
|
||||
} else if (attribute_status == 2){
|
||||
return "failed"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
getAttributeName(attribute_data){
|
||||
let attribute_metadata = this.metadata[attribute_data.attribute_id]
|
||||
if(!attribute_metadata){
|
||||
return 'Unknown Attribute Name'
|
||||
} else {
|
||||
return attribute_metadata.display_name
|
||||
}
|
||||
return
|
||||
}
|
||||
getAttributeDescription(attribute_data){
|
||||
let attribute_metadata = this.data.metadata[attribute_data.attribute_id]
|
||||
let attribute_metadata = this.metadata[attribute_data.attribute_id]
|
||||
if(!attribute_metadata){
|
||||
return 'Unknown'
|
||||
} else {
|
||||
@@ -110,7 +139,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
getAttributeValue(attribute_data){
|
||||
if(this.isAta()) {
|
||||
let attribute_metadata = this.data.metadata[attribute_data.attribute_id]
|
||||
let attribute_metadata = this.metadata[attribute_data.attribute_id]
|
||||
if(!attribute_metadata){
|
||||
return attribute_data.value
|
||||
} else if (attribute_metadata.display_type == "raw") {
|
||||
@@ -128,7 +157,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
getAttributeValueType(attribute_data){
|
||||
if(this.isAta()) {
|
||||
let attribute_metadata = this.data.metadata[attribute_data.attribute_id]
|
||||
let attribute_metadata = this.metadata[attribute_data.attribute_id]
|
||||
if(!attribute_metadata){
|
||||
return ''
|
||||
} else {
|
||||
@@ -141,14 +170,14 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
getAttributeIdeal(attribute_data){
|
||||
if(this.isAta()){
|
||||
return this.data.metadata[attribute_data.attribute_id]?.display_type == "raw" ? this.data.metadata[attribute_data.attribute_id]?.ideal : ''
|
||||
return this.metadata[attribute_data.attribute_id]?.display_type == "raw" ? this.metadata[attribute_data.attribute_id]?.ideal : ''
|
||||
} else {
|
||||
return this.data.metadata[attribute_data.attribute_id]?.ideal
|
||||
return this.metadata[attribute_data.attribute_id]?.ideal
|
||||
}
|
||||
}
|
||||
|
||||
getAttributeWorst(attribute_data){
|
||||
let attribute_metadata = this.data.metadata[attribute_data.attribute_id]
|
||||
let attribute_metadata = this.metadata[attribute_data.attribute_id]
|
||||
if(!attribute_metadata){
|
||||
return attribute_data.worst
|
||||
} else {
|
||||
@@ -158,7 +187,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
getAttributeThreshold(attribute_data){
|
||||
if(this.isAta()){
|
||||
let attribute_metadata = this.data.metadata[attribute_data.attribute_id]
|
||||
let attribute_metadata = this.metadata[attribute_data.attribute_id]
|
||||
if(!attribute_metadata || attribute_metadata.display_type == "normalized"){
|
||||
return attribute_data.thresh
|
||||
} else {
|
||||
@@ -175,29 +204,30 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
getAttributeCritical(attribute_data){
|
||||
return this.data.metadata[attribute_data.attribute_id]?.critical
|
||||
return this.metadata[attribute_data.attribute_id]?.critical
|
||||
}
|
||||
getHiddenAttributes(){
|
||||
let attributes_list
|
||||
if(this.isAta()){
|
||||
attributes_list = this.data.data.smart_results[0]?.ata_attributes
|
||||
} else if(this.isNvme()){
|
||||
attributes_list = this.data.data.smart_results[0]?.nvme_attributes
|
||||
} else {
|
||||
attributes_list = this.data.data.smart_results[0]?.scsi_attributes
|
||||
if (!this.smart_results || this.smart_results.length == 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return attributes_list.length - this.smartAttributeDataSource.data.length
|
||||
let attributes_length = 0
|
||||
let attributes = this.smart_results[0]?.attrs
|
||||
if (attributes) {
|
||||
attributes_length = Object.keys(attributes).length
|
||||
}
|
||||
|
||||
return attributes_length - this.smartAttributeDataSource.data.length
|
||||
}
|
||||
|
||||
isAta(): boolean {
|
||||
return this.data.data.device_protocol == 'ATA'
|
||||
return this.device.device_protocol == 'ATA'
|
||||
}
|
||||
isScsi(): boolean {
|
||||
return this.data.data.device_protocol == 'SCSI'
|
||||
return this.device.device_protocol == 'SCSI'
|
||||
}
|
||||
isNvme(): boolean {
|
||||
return this.data.data.device_protocol == 'NVMe'
|
||||
return this.device.device_protocol == 'NVMe'
|
||||
}
|
||||
|
||||
private _generateSmartAttributeTableDataSource(smart_results){
|
||||
@@ -207,35 +237,44 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
return smartAttributeDataSource
|
||||
}
|
||||
var latest_smart_result = smart_results[0];
|
||||
let attributes_list = []
|
||||
let attributes = {}
|
||||
if(this.isScsi()) {
|
||||
this.smartAttributeTableColumns = ['status', 'name', 'value', 'thresh', 'history'];
|
||||
attributes_list = latest_smart_result.scsi_attributes
|
||||
attributes = latest_smart_result.attrs
|
||||
} else if(this.isNvme()){
|
||||
this.smartAttributeTableColumns = ['status', 'name', 'value', 'thresh', 'ideal', 'history'];
|
||||
attributes_list = latest_smart_result.nvme_attributes
|
||||
attributes = latest_smart_result.attrs
|
||||
} else {
|
||||
//ATA
|
||||
attributes_list = latest_smart_result.ata_attributes
|
||||
attributes = latest_smart_result.attrs
|
||||
this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh','ideal', 'failure', 'history'];
|
||||
}
|
||||
|
||||
for(const attrId in attributes){
|
||||
var attr = attributes[attrId]
|
||||
|
||||
for(let attr of attributes_list){
|
||||
//chart history data
|
||||
if (!attr.chartData) {
|
||||
var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse()
|
||||
rawHistory.push(this.getAttributeValue(attr))
|
||||
attr.chartData = [
|
||||
|
||||
|
||||
var attrHistory = []
|
||||
for (let smart_result of smart_results){
|
||||
attrHistory.push(this.getAttributeValue(smart_result.attrs[attrId]))
|
||||
}
|
||||
|
||||
// var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse()
|
||||
// rawHistory.push(this.getAttributeValue(attr))
|
||||
|
||||
attributes[attrId].chartData = [
|
||||
{
|
||||
name: "chart-line-sparkline",
|
||||
data: rawHistory
|
||||
data: attrHistory
|
||||
}
|
||||
]
|
||||
}
|
||||
//determine when to include the attributes in table.
|
||||
|
||||
if(!this.onlyCritical || this.onlyCritical && this.data.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)
|
||||
}
|
||||
}
|
||||
@@ -297,7 +336,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
toggleOnlyCritical(){
|
||||
this.onlyCritical = !this.onlyCritical
|
||||
this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.data.data.smart_results);
|
||||
this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.smart_results);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user