Merge branch 'master' into BASEPATH

This commit is contained in:
Jason Kulatunga
2022-05-09 14:29:48 -07:00
committed by GitHub
125 changed files with 26973 additions and 14987 deletions
@@ -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);
}