You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
scrutiny/webapp/frontend/src/app/modules/detail/detail.component.html

358 lines
19 KiB

<div class="flex flex-col flex-auto w-full p-8 xs:p-2">
<div class="flex flex-wrap w-full">
<div class="flex items-center justify-between w-full my-4 px-4 xs:pr-0">
<div class="mr-6">
<h2 class="m-0">Drive Details - {{device | deviceTitle:config.dashboardDisplay}} </h2>
<div class="text-secondary tracking-tight">Dive into S.M.A.R.T data</div>
</div>
<!-- Action buttons -->
<div class="flex items-center">
<button class="xs:hidden"
matTooltip="not yet implemented"
mat-stroked-button>
<mat-icon class="icon-size-20"
[svgIcon]="'save'"></mat-icon>
<span class="ml-2">Export</span>
</button>
<button class="ml-2 xs:hidden"
(click)="openDialog()"
mat-stroked-button>
<mat-icon class="icon-size-20 rotate-90 mirror"
[svgIcon]="'tune'"></mat-icon>
<span class="ml-2">Settings</span>
</button>
<!-- Actions menu (visible on xs) -->
<div class="hidden xs:flex">
<button [matMenuTriggerFor]="actionsMenu"
mat-icon-button>
<mat-icon [svgIcon]="'more_vert'"></mat-icon>
</button>
<mat-menu #actionsMenu="matMenu">
<button mat-menu-item
matTooltip="not yet implemented">
<mat-icon class="icon-size-20"
[svgIcon]="'save'"></mat-icon>
<span class="ml-2">Export</span>
</button>
<button mat-menu-item
(click)="openDialog()">
<mat-icon class="icon-size-20 rotate-90 mirror"
[svgIcon]="'tune'"></mat-icon>
<span class="ml-2">Settings</span>
</button>
</mat-menu>
</div>
</div>
</div>
<!-- Card -->
<div class="flex flex-auto w-1/4 p-4 lt-md:w-full">
<treo-card class="flex flex-auto p-4 flex-col flex-auto filter-list">
<div class="flex flex-col grid grid-cols-2">
<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 | deviceStatus}}</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="device?.device_uuid" class="my-2 col-span-2 lt-md:col-span-1">
<div>{{device?.device_uuid}}</div>
<div class="text-secondary text-md">Device UUID</div>
</div>
<div *ngIf="device?.device_label" class="my-2 col-span-2 lt-md:col-span-1">
<div>{{device?.device_label}}</div>
<div class="text-secondary text-md">Device Label</div>
</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="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>{{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>{{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>{{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>{{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>{{device?.capacity | fileSize}}</div>
<div class="text-secondary text-md">Capacity</div>
</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="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>{{smart_results[0]?.power_cycle_count}}</div>
<div class="text-secondary text-md">Power Cycle Count</div>
</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>{{smart_results[0]?.temp | temperature:config.temperatureUnit:true}}</div>
<div class="text-secondary text-md">Temperature</div>
</div>
</div>
</treo-card>
</div>
<!-- S.M.A.R.T. Data table -->
<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 {{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">
<table class="w-full bg-transparent"
mat-table
matSort
[dataSource]="smartAttributeDataSource"
[trackBy]="trackByFn"
#smartAttributeTable>
<!-- Status -->
<ng-container matColumnDef="status">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
Status
</span>
</th>
<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': 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': 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>
<!-- ID -->
<ng-container matColumnDef="id">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
ID
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 font-medium text-sm text-secondary whitespace-no-wrap">
{{attribute.attribute_id}} ({{toHex(attribute.attribute_id)}})
</span>
</td>
</ng-container>
<!-- Name -->
<ng-container matColumnDef="name">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
Name
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 whitespace-no-wrap" matTooltip="{{getAttributeDescription(attribute)}}">
{{getAttributeName(attribute)}} <mat-icon *ngIf="getAttributeDescription(attribute)" class="icon-size-10" [svgIcon]="'info'"></mat-icon>
</span>
</td>
</ng-container>
<!-- Value -->
<ng-container matColumnDef="value">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
Value
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 whitespace-no-wrap" matTooltip="{{getAttributeValueType(attribute)}}">
{{getAttributeValue(attribute)}}
</span>
</td>
</ng-container>
<!-- Worst -->
<ng-container matColumnDef="worst">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
Worst
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 whitespace-no-wrap">
{{getAttributeWorst(attribute)}}
</span>
</td>
</ng-container>
<!-- Threshold -->
<ng-container matColumnDef="thresh">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
Threshold
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 whitespace-no-wrap">
{{getAttributeThreshold(attribute)}}
</span>
</td>
</ng-container>
<!-- Ideal -->
<ng-container matColumnDef="ideal">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
Ideal
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 font-medium whitespace-no-wrap">
{{getAttributeIdeal(attribute) }}
</span>
</td>
</ng-container>
<!-- Observed Failure Rate -->
<ng-container matColumnDef="failure">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap" matTooltip="Failure rate is based on data provided by BackBlaze. The current attribute value is matched against the observed failure categories and an annual failure rate is determined.">
Failure Rate <mat-icon [svgIcon]="'info'"></mat-icon>
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 font-medium whitespace-no-wrap">
{{attribute.failure_rate | percent}}
</span>
</td>
</ng-container>
<!-- History -->
<ng-container matColumnDef="history">
<th class="bg-cool-gray-50 dark:bg-cool-gray-700 border-t"
mat-header-cell
mat-sort-header
*matHeaderCellDef>
<span class="whitespace-no-wrap">
History
</span>
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="font-medium whitespace-no-wrap">
<apx-chart
[series]="attribute.chartData"
[chart]="commonSparklineOptions.chart"
[tooltip]="commonSparklineOptions.tooltip"
[stroke]="commonSparklineOptions.stroke"
[annotations]="attribute.chartDataReferenceLine"
></apx-chart>
</span>
</td>
</ng-container>
<!-- Footer -->
<ng-container matColumnDef="recentOrdersTableFooter">
<td class="px-3 border-none"
mat-footer-cell
*matFooterCellDef
colspan="6">
<button mat-button
(click)="toggleOnlyCritical()"
[color]="'primary'">
<span *ngIf="onlyCritical">Show all attributes</span>
<span *ngIf="!onlyCritical">Show critical attributes</span>
</button>
</td>
</ng-container>
<tr mat-header-row
*matHeaderRowDef="smartAttributeTableColumns"></tr>
<tr class="attribute-row h-16"
mat-row
[ngClass]="{'yellow-50': getAttributeCritical(row)}"
*matRowDef="let row; columns: smartAttributeTableColumns;"></tr>
<tr class="h-16"
mat-footer-row
*matFooterRowDef="['recentOrdersTableFooter']"></tr>
</table>
</div>
</div>
</div>
</div>
</div>