Compare commits

...

24 Commits

Author SHA1 Message Date
packagrio-bot b953456d6b (v0.4.12) Automated packaging of release by Packagr 2022-06-11 23:32:42 +00:00
Jason Kulatunga 4057699cad Merge pull request #296 from AnalogJ/beta 2022-06-11 16:22:55 -07:00
Jason Kulatunga d3e7fc6067 make sure we dont create incorrect temp data. 2022-06-11 15:57:12 -07:00
Jason Kulatunga 09a8574d83 fixing tooltip theme. 2022-06-11 15:21:20 -07:00
Jason Kulatunga 7695cc185f color the barchart data in the sparklines, so that we know when a failure/warning was detected (historically) 2022-06-11 14:43:34 -07:00
Jason Kulatunga fc7208020e remove status reason click for more details text. 2022-06-11 12:18:27 -07:00
Jason Kulatunga 75d5930835 correctly using the latest data for table. 2022-06-11 11:00:00 -07:00
Jason Kulatunga 3c9e16169e correctly using the latest data for table. 2022-06-11 09:28:37 -07:00
Jason Kulatunga 9e1076f302 using constants for Attribute status values. 2022-06-11 09:17:35 -07:00
Jason Kulatunga 75ab87e109 Update TROUBLESHOOTING_INFLUXDB.md 2022-06-11 08:13:29 -07:00
Jason Kulatunga 0b8251fce2 Merge pull request #295 from AnalogJ/expanding_row 2022-06-11 08:07:03 -07:00
Jason Kulatunga f57b71ae96 updated tooltips in details page (click for more details). 2022-06-11 08:05:52 -07:00
Jason Kulatunga ce324c3de1 moved nightly build into its own ci job.
fixes #289
2022-06-11 07:47:25 -07:00
packagrio-bot 281b56d287 (v0.4.11) Automated packaging of release by Packagr 2022-06-11 03:29:04 +00:00
Jason Kulatunga cbd23e334b Merge pull request #293 from AnalogJ/beta 2022-06-10 19:48:22 -07:00
Jason Kulatunga 7a0b9c9e0d trying to fix docker image build. 2022-06-10 08:20:13 -07:00
Jason Kulatunga 44b3d982dd trying to fix docker image build. 2022-06-10 08:19:25 -07:00
Jason Kulatunga 769f253e7d fixing the table header for failures. 2022-06-09 22:42:21 -07:00
Jason Kulatunga fbd5bb57ac update descriptions for SCSI attributes. 2022-06-09 22:31:35 -07:00
Jason Kulatunga b9eb5687cd working on expanding row content. 2022-06-09 22:13:44 -07:00
Jason Kulatunga cbd230a7e0 wip expanding row for more details for attributes.
see https://stackblitz.com/angular/eaajjobynjkl?file=src%2Fapp%2Ftable-expandable-rows-example.html

see https://material.angular.io/components/table/examples#table-expandable-rows
2022-06-09 19:39:46 -07:00
Jason Kulatunga 892e9685f3 attempting to fix https://github.com/AnalogJ/scrutiny/issues/281 by removing static flag in artifact build 2022-06-09 19:34:16 -07:00
Jason Kulatunga 7ba7b6efda Update TROUBLESHOOTING_DOCKER.md 2022-06-09 07:35:07 -07:00
Jason Kulatunga 453069deec Create TROUBLESHOOTING_DOCKER.md 2022-06-09 07:34:14 -07:00
16 changed files with 352 additions and 44 deletions
-2
View File
@@ -1,7 +1,5 @@
name: Docker
on:
schedule:
- cron: '36 12 * * *'
push:
branches: [ master, beta ]
# Publish semver tags as releases.
+69
View File
@@ -0,0 +1,69 @@
name: Docker
on:
schedule:
- cron: '36 12 * * *'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
omnibus:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: "Populate frontend version information"
run: "cd webapp/frontend && ./git.version.sh"
- name: "Generate frontend & version information"
uses: addnab/docker-run-action@v3
with:
image: node:lts
options: -v ${{ github.workspace }}:/work
run: |
cd /work
make frontend && echo "print contents of /work/dist" && ls -alt /work/dist
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: 'arm64,arm'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v4
with:
tags: |
type=ref,enable=true,event=branch,suffix=-omnibus-nightly
type=ref,enable=true,event=tag,suffix=-omnibus-nightly
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
platforms: linux/amd64,linux/arm64
context: .
file: docker/Dockerfile
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# cache-from: type=gha
# cache-to: type=gha,mode=max
+3 -3
View File
@@ -6,9 +6,9 @@ WORKDIR /go/src/github.com/analogj/scrutiny
COPY . /go/src/github.com/analogj/scrutiny
RUN go mod vendor && \
go build -ldflags '-w -extldflags "-static"' -o scrutiny webapp/backend/cmd/scrutiny/scrutiny.go && \
go build -ldflags '-w -extldflags "-static"' -o scrutiny-collector-selftest collector/cmd/collector-selftest/collector-selftest.go && \
go build -ldflags '-w -extldflags "-static"' -o scrutiny-collector-metrics collector/cmd/collector-metrics/collector-metrics.go
go build -o scrutiny webapp/backend/cmd/scrutiny/scrutiny.go && \
go build -o scrutiny-collector-selftest collector/cmd/collector-selftest/collector-selftest.go && \
go build -o scrutiny-collector-metrics collector/cmd/collector-metrics/collector-metrics.go
########
FROM debian:bullseye-slim as runtime
+1 -1
View File
@@ -6,7 +6,7 @@ WORKDIR /go/src/github.com/analogj/scrutiny
COPY . /go/src/github.com/analogj/scrutiny
RUN go mod vendor && \
go build -ldflags '-w -extldflags "-static"' -o scrutiny webapp/backend/cmd/scrutiny/scrutiny.go
go build -o scrutiny webapp/backend/cmd/scrutiny/scrutiny.go
########
FROM debian:bullseye-slim as runtime
+25
View File
@@ -0,0 +1,25 @@
# Docker Images `master-omnibus` vs `latest`
> TL;DR; The `master-omnibus` and `latest` tags are almost semantically identical, as I follow a `golden master`
development process. However if you want to ensure you're only using the latest release, you can change to `latest`
The CI script used to orchestrate the docker image builds can be found here: https://github.com/AnalogJ/scrutiny/blob/master/.github/workflows/docker-build.yaml#L166-L184
In general Scrutiny follows a `golden master` development process, which means that the `master` branch is not directly updated (unless its for documentation changes),
instead development is done in a feature branch, or committed to the `beta` branch.
As development progresses, and we're satisfied that a feature is complete, and the quality is acceptable,
I merge the changes to `master` and trigger the creation of a new release -- ie, when master is updated, a new release
is almost immediately created (and tagged with `latest`)
So changing from `master-omnibus -> latest` will be the same thing for all intents and purposes.
Having said that -- the one key difference is the `automated cron builds` that run on the `master` and `beta` branches.
They trigger a `nightly` build, even if nothing has changed on the branch. This has a couple of benefits, but one is to
ensure that there's no broken external dependencies in our (unchanged) code.
However, as everyone unfortunately found out recently, I had an error in my CI script, which caused failures to be
ignored -- https://github.com/AnalogJ/scrutiny/issues/287. That has since been fixed.
Hope that gives you an understanding for how everything is wired up.
+9
View File
@@ -54,6 +54,15 @@ time="2022-05-13T14:38:05Z" level=info msg="Successfully connected to scrutiny s
panic: a username and password is required for a setup
```
or
```
Start the scrutiny server
time="2022-06-11T10:35:04-04:00" level=info msg="Trying to connect to scrutiny sqlite db: \n"
time="2022-06-11T10:35:04-04:00" level=info msg="Successfully connected to scrutiny sqlite db: \n"
panic: failed to check influxdb setup status - parse "://:": missing protocol scheme
```
As discussed in [#248](https://github.com/AnalogJ/scrutiny/issues/248) and [#234](https://github.com/AnalogJ/scrutiny/issues/234),
this usually related to either:
+12
View File
@@ -0,0 +1,12 @@
package database
import (
"github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
"sort"
)
func sortSmartMeasurementsDesc(smartResults []measurements.Smart) {
sort.SliceStable(smartResults, func(i, j int) bool {
return smartResults[i].Date.After(smartResults[j].Date)
})
}
@@ -0,0 +1,30 @@
package database
import (
"github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func Test_sortSmartMeasurementsDesc_LatestFirst(t *testing.T) {
//setup
timeNow := time.Now()
smartResults := []measurements.Smart{
{
Date: timeNow.AddDate(0, 0, -2),
},
{
Date: timeNow,
},
{
Date: timeNow.AddDate(0, 0, -1),
},
}
//test
sortSmartMeasurementsDesc(smartResults)
//assert
require.Equal(t, smartResults[0].Date, timeNow)
}
@@ -29,6 +29,7 @@ func (sr *scrutinyRepository) SaveSmartAttributes(ctx context.Context, wwn strin
return deviceSmartData, sr.saveDatapoint(sr.influxWriteApi, "smart", tags, fields, deviceSmartData.Date, ctx)
}
// GetSmartAttributeHistory MUST return in sorted order, where newest entries are at the beginning of the list, and oldest are at the end.
func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn string, durationKey string, attributes []string) ([]measurements.Smart, error) {
// Get SMartResults from InfluxDB
@@ -64,6 +65,9 @@ func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn
return nil, err
}
//we have to sort the smartResults again, because the `union` command will return multiple 'tables' and only sort the records in each table.
sortSmartMeasurementsDesc(smartResults)
return smartResults, nil
//if err := device.SquashHistory(); err != nil {
@@ -109,7 +109,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string {
|> toInt()
temp_data
|> aggregateWindow(fn: mean, every: aggWindow)
|> aggregateWindow(fn: mean, every: aggWindow, createEmpty: false)
|> to(bucket: destBucket, org: destOrg)
`,
sourceBucket,
@@ -19,7 +19,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "low",
Critical: true,
Description: "",
Description: "The grown defect count shows the amount of swapped (defective) blocks since the drive was shipped by it's vendor. Each additional defective block increases the count by one.",
},
"read_errors_corrected_by_eccfast": {
ID: "read_errors_corrected_by_eccfast",
@@ -27,7 +27,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "An error correction was applied to get perfect data (a.k.a. ECC on-the-fly). \"Without substantial delay\" means the correction did not postpone reading of later sectors (e.g. a revolution was not lost). The counter is incremented once for each logical block that requires correction. Two different blocks corrected during the same command are counted as two events.",
},
"read_errors_corrected_by_eccdelayed": {
ID: "read_errors_corrected_by_eccdelayed",
@@ -35,7 +35,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "An error code or algorithm (e.g. ECC, checksum) is applied in order to get perfect data with substantial delay. \"With possible delay\" means the correction took longer than a sector time so that reading/writing of subsequent sectors was delayed (e.g. a lost revolution). The counter is incremented once for each logical block that requires correction. A block with a double error that is correctable counts as one event and two different blocks corrected during the same command count as two events. ",
},
"read_errors_corrected_by_rereads_rewrites": {
ID: "read_errors_corrected_by_rereads_rewrites",
@@ -43,7 +43,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "low",
Critical: true,
Description: "",
Description: "This parameter code specifies the counter counting the number of errors that are corrected by applying retries. This counts errors recovered, not the number of retries. If five retries were required to recover one block of data, the counter increments by one, not five. The counter is incremented once for each logical block that is recovered using retries. If an error is not recoverable while applying retries and is recovered by ECC, it isn't counted by this counter; it will be counted by the counter specified by parameter code 01h - Errors Corrected With Possible Delays. ",
},
"read_total_errors_corrected": {
ID: "read_total_errors_corrected",
@@ -51,7 +51,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "This counter counts the total of parameter code errors 00h, 01h and 02h (i.e. error corrected by ECC: fast and delayed plus errors corrected by rereads and rewrites). There is no \"double counting\" of data errors among these three counters. The sum of all correctable errors can be reached by adding parameter code 01h and 02h errors, not by using this total.",
},
"read_correction_algorithm_invocations": {
ID: "read_correction_algorithm_invocations",
@@ -59,7 +59,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "This parameter code specifies the counter that counts the total number of retries, or \"times the retry algorithm is invoked\". If after five attempts a counter 02h type error is recovered, then five is added to this counter. If three retries are required to get stable ECC syndrome before a counter 01h type error is corrected, then those three retries are also counted here. The number of retries applied to unsuccessfully recover an error (counter 06h type error) are also counted by this counter. ",
},
"read_total_uncorrected_errors": {
ID: "read_total_uncorrected_errors",
@@ -67,7 +67,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "low",
Critical: true,
Description: "",
Description: "This parameter code specifies the counter that contains the total number of blocks for which an uncorrected data error has occurred. ",
},
"write_errors_corrected_by_eccfast": {
ID: "write_errors_corrected_by_eccfast",
@@ -75,7 +75,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "An error correction was applied to get perfect data (a.k.a. ECC on-the-fly). \"Without substantial delay\" means the correction did not postpone reading of later sectors (e.g. a revolution was not lost). The counter is incremented once for each logical block that requires correction. Two different blocks corrected during the same command are counted as two events. ",
},
"write_errors_corrected_by_eccdelayed": {
ID: "write_errors_corrected_by_eccdelayed",
@@ -83,7 +83,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "An error code or algorithm (e.g. ECC, checksum) is applied in order to get perfect data with substantial delay. \"With possible delay\" means the correction took longer than a sector time so that reading/writing of subsequent sectors was delayed (e.g. a lost revolution). The counter is incremented once for each logical block that requires correction. A block with a double error that is correctable counts as one event and two different blocks corrected during the same command count as two events. ",
},
"write_errors_corrected_by_rereads_rewrites": {
ID: "write_errors_corrected_by_rereads_rewrites",
@@ -91,7 +91,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "low",
Critical: true,
Description: "",
Description: "This parameter code specifies the counter counting the number of errors that are corrected by applying retries. This counts errors recovered, not the number of retries. If five retries were required to recover one block of data, the counter increments by one, not five. The counter is incremented once for each logical block that is recovered using retries. If an error is not recoverable while applying retries and is recovered by ECC, it isn't counted by this counter; it will be counted by the counter specified by parameter code 01h - Errors Corrected With Possible Delays.",
},
"write_total_errors_corrected": {
ID: "write_total_errors_corrected",
@@ -99,7 +99,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "This counter counts the total of parameter code errors 00h, 01h and 02h (i.e. error corrected by ECC: fast and delayed plus errors corrected by rereads and rewrites). There is no \"double counting\" of data errors among these three counters. The sum of all correctable errors can be reached by adding parameter code 01h and 02h errors, not by using this total.",
},
"write_correction_algorithm_invocations": {
ID: "write_correction_algorithm_invocations",
@@ -107,7 +107,7 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "",
Critical: false,
Description: "",
Description: "This parameter code specifies the counter that counts the total number of retries, or \"times the retry algorithm is invoked\". If after five attempts a counter 02h type error is recovered, then five is added to this counter. If three retries are required to get stable ECC syndrome before a counter 01h type error is corrected, then those three retries are also counted here. The number of retries applied to unsuccessfully recover an error (counter 06h type error) are also counted by this counter. ",
},
"write_total_uncorrected_errors": {
ID: "write_total_uncorrected_errors",
@@ -115,6 +115,6 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{
DisplayType: "",
Ideal: "low",
Critical: true,
Description: "",
Description: " This parameter code specifies the counter that contains the total number of blocks for which an uncorrected data error has occurred.",
},
}
+1 -1
View File
@@ -2,4 +2,4 @@ package version
// VERSION is the app-global version string, which will be replaced with a
// new value during packaging
const VERSION = "0.4.10"
const VERSION = "0.4.12"
@@ -143,6 +143,7 @@
<table class="w-full bg-transparent"
mat-table
matSort
multiTemplateDataRows
[dataSource]="smartAttributeDataSource"
[trackBy]="trackByFn"
#smartAttributeTable>
@@ -203,7 +204,7 @@
</th>
<td mat-cell
*matCellDef="let attribute">
<span class="pr-6 whitespace-no-wrap" matTooltip="{{getAttributeDescription(attribute)}}">
<span class="pr-6 whitespace-no-wrap" matTooltip="click for more details.">
{{getAttributeName(attribute)}} <mat-icon *ngIf="getAttributeDescription(attribute)" class="icon-size-10" [svgIcon]="'info'"></mat-icon>
</span>
</td>
@@ -324,6 +325,72 @@
</td>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let attribute" [attr.colspan]="smartAttributeTableColumns.length">
<div class="attribute-detail"
[@detailExpand]="attribute == expandedAttribute ? 'expanded' : 'collapsed'">
<div class="flex flex-auto w-1/3 min-w-80 py-4">
<div class="flex flex-col flex-auto justify-end text-md pb-3">
{{getAttributeDescription(attribute)}}
</div>
</div>
<div class="flex flex-auto w-2/3 min-w-80">
<div class="flex flex-col flex-auto justify-end text-md px-6 pb-3">
<div class="flex items-center justify-between py-3 border-b last:border-b-0 ng-star-inserted">
<div class="flex items-center w-1/4">Type</div>
<div class="flex items-center w-1/4">Value</div>
<div class="flex items-center w-1/4">Worst/Thresh</div>
<div class="flex items-center w-1/4">Failure %</div>
</div>
<div class="flex items-center justify-between py-3 border-b last:border-b-0 ng-star-inserted">
<div class="flex items-center w-1/4">
<div class="flex-shrink-0 w-2 h-2 mr-3 rounded-full"
[ngClass]="{'bg-red': getAttributeScrutinyStatusName(attribute.status) === 'failed',
'bg-green': getAttributeScrutinyStatusName(attribute.status) === 'passed',
'bg-yellow': getAttributeScrutinyStatusName(attribute.status) === 'warn'}"></div>
<div class="truncate">Scrutiny</div>
</div>
<div class="w-1/4 items-center font-medium">{{getAttributeValue(attribute)}}</div>
<div class="w-1/4 items-center text-secondary">--</div>
<div class="w-1/4 items-center text-secondary">{{(attribute.failure_rate | percent) || '--'}}</div>
</div>
<div class="flex items-center justify-between py-3 border-b last:border-b-0 ng-star-inserted">
<div class="flex items-center w-1/4">
<div class="flex-shrink-0 w-2 h-2 mr-3 rounded-full"
[ngClass]="{'bg-red': getAttributeSmartStatusName(attribute.status) === 'failed',
'bg-green': getAttributeSmartStatusName(attribute.status) === 'passed'}"
></div>
<div class="truncate">Normalized</div>
</div>
<div class="w-1/4 items-center font-medium">{{attribute.value}}</div>
<div class="w-1/4 items-center text-secondary">{{getAttributeWorst(attribute) || '--' }}/{{getAttributeThreshold(attribute)}}</div>
<div class="w-1/4 items-center text-secondary">--</div>
</div>
<div class="flex items-center justify-between py-3 border-b last:border-b-0 ng-star-inserted">
<div class="flex items-center w-1/4">
<div class="flex-shrink-0 w-2 h-2 mr-3 rounded-full"></div>
<div class="truncate">Raw</div>
</div>
<div class="w-1/4 items-center font-medium">{{attribute.raw_value}}</div>
<div class="w-1/4 items-center text-secondary">--</div>
<div class="w-1/4 items-center text-secondary">--</div>
</div>
</div>
</div>
</div>
</td>
</ng-container>
<!-- Footer -->
<ng-container matColumnDef="recentOrdersTableFooter">
<td class="px-3 border-none"
@@ -344,7 +411,10 @@
<tr class="attribute-row h-16"
mat-row
[ngClass]="{'yellow-50': getAttributeCritical(row)}"
[class.attribute-expanded-row]="expandedAttribute === row"
(click)="expandedAttribute = expandedAttribute === row ? null : row"
*matRowDef="let row; columns: smartAttributeTableColumns;"></tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="attribute-detail-row"></tr>
<tr class="h-16"
mat-footer-row
*matFooterRowDef="['recentOrdersTableFooter']"></tr>
@@ -1,7 +1,6 @@
@import 'treo';
detail {
}
// -----------------------------------------------------------------------------------------------------
@@ -20,5 +19,35 @@ detail {
}
}
//table {
// width: 100%;
//}
$primary: map-get($theme, primary);
$is-dark: map-get($theme, is-dark);
tr.attribute-detail-row {
height: 0;
}
//tr.attribute-row:not(.attribute-expanded-row):hover {
// @if ($is-dark) {
// background: rgba(0, 0, 0, 0.05);
// } @else {
// background: map-get($primary, 50);
// }
//}
tr.attribute-row:not(.attribute-expanded-row):active {
background: #efefef;
}
.attribute-row td {
border-bottom-width: 0;
}
.attribute-detail {
overflow: hidden;
display: flex;
}
@@ -11,11 +11,28 @@ import {MatDialog} from "@angular/material/dialog";
import humanizeDuration from 'humanize-duration';
import {TreoConfigService} from "../../../@treo/services/config";
import {AppConfig} from "../../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';
// from Constants.go - these must match
const AttributeStatusPassed = 0
const AttributeStatusFailedSmart = 1
const AttributeStatusWarningScrutiny = 2
const AttributeStatusFailedScrutiny = 4
@Component({
selector: 'detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss']
styleUrls: ['./detail.component.scss'],
animations: [
trigger('detailExpand', [
state('collapsed', style({height: '0px', minHeight: '0'})),
state('expanded', style({height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
@@ -24,6 +41,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
onlyCritical: boolean = true;
// data: any;
expandedAttribute: any | null;
metadata: any;
device: any;
@@ -33,12 +51,12 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
smartAttributeDataSource: MatTableDataSource<any>;
smartAttributeTableColumns: string[];
@ViewChild('smartAttributeTable', {read: MatSort})
smartAttributeTableMatSort: MatSort;
// Private
private _unsubscribeAll: Subject<any>;
private systemPrefersDark: boolean;
/**
* Constructor
@@ -49,7 +67,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
private _detailService: DetailService,
public dialog: MatDialog,
private _configService: TreoConfigService,
@Inject(LOCALE_ID) public locale: string
)
{
@@ -60,6 +78,9 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
this.smartAttributeDataSource = new MatTableDataSource();
// this.recentTransactionsTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh'];
this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh','ideal', 'failure', 'history'];
this.systemPrefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
}
// -----------------------------------------------------------------------------------------------------
@@ -121,26 +142,43 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
getAttributeStatusName(attributeStatus: number): string {
// tslint:disable:no-bitwise
// from Constants.go
// AttributeStatusPassed AttributeStatus = 0
// AttributeStatusFailedSmart AttributeStatus = 1
// AttributeStatusWarningScrutiny AttributeStatus = 2
// AttributeStatusFailedScrutiny AttributeStatus = 4
if(attributeStatus === 0){
if(attributeStatus === AttributeStatusPassed){
return 'passed'
} else if ((attributeStatus & 1) !== 0 || (attributeStatus & 4) !== 0 ){
} else if ((attributeStatus & AttributeStatusFailedScrutiny) !== 0 || (attributeStatus & AttributeStatusFailedSmart) !== 0 ){
return 'failed'
} else if ((attributeStatus & 2) !== 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){
return 'failed'
} else if ((attributeStatus & AttributeStatusWarningScrutiny) !== 0){
return 'warn'
} else {
return 'passed'
}
// tslint:enable:no-bitwise
}
getAttributeSmartStatusName(attributeStatus: number): string {
// tslint:disable:no-bitwise
if ((attributeStatus & AttributeStatusFailedSmart) !== 0){
return 'failed'
} else {
return 'passed'
}
// tslint:enable:no-bitwise
}
getAttributeName(attribute_data): string {
let attribute_metadata = this.metadata[attribute_data.attribute_id]
@@ -270,7 +308,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
} else {
//ATA
attributes = latest_smart_result.attrs
this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh','ideal', 'failure', 'history'];
this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'thresh','ideal', 'failure', 'history'];
}
for(const attrId in attributes){
@@ -282,7 +320,21 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
var attrHistory = []
for (let smart_result of smart_results){
attrHistory.push(this.getAttributeValue(smart_result.attrs[attrId]))
// attrHistory.push(this.getAttributeValue(smart_result.attrs[attrId]))
const chartDatapoint = {
x: formatDate(smart_result.date, 'MMMM dd, yyyy - HH:mm', this.locale),
y: this.getAttributeValue(smart_result.attrs[attrId])
}
const attributeStatusName = this.getAttributeStatusName(smart_result.attrs[attrId].status)
if(attributeStatusName === 'failed') {
chartDatapoint['strokeColor'] = '#F05252'
chartDatapoint['fillColor'] = '#F05252'
} else if (attributeStatusName === 'warn'){
chartDatapoint['strokeColor'] = '#C27803'
chartDatapoint['fillColor'] = '#C27803'
}
attrHistory.push(chartDatapoint)
}
// var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse()
@@ -325,12 +377,17 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
enabled: false
}
},
// theme:{
// // @ts-ignore
// // mode:
// mode: 'dark',
// },
tooltip: {
fixed: {
enabled: false
},
x: {
show: false
show: true
},
y: {
title: {
@@ -341,7 +398,9 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
},
marker: {
show: false
}
},
theme: this.determineTheme(this.config)
},
stroke: {
width: 2,
@@ -350,6 +409,13 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
};
}
private determineTheme(config:AppConfig): string {
if (config.theme === 'system') {
return this.systemPrefersDark ? 'dark' : 'light'
} else {
return config.theme
}
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
-4
View File
@@ -17,8 +17,4 @@
color: #0694a2 !important
}
}
.apexcharts-tooltip {
background: #242b38 !important;
//color: orange;
}
}