Merge pull request #276 from shamoon/dark-mode

This commit is contained in:
Jason Kulatunga
2022-06-04 08:13:43 -07:00
committed by GitHub
10 changed files with 172 additions and 20 deletions
+2 -1
View File
@@ -58,11 +58,12 @@ Scrutiny uses `smartctl --scan` to detect devices/drives.
- All RAID controllers supported by `smartctl` are automatically supported by Scrutiny. - All RAID controllers supported by `smartctl` are automatically supported by Scrutiny.
- While some RAID controllers support passing through the underlying SMART data to `smartctl` others do not. - While some RAID controllers support passing through the underlying SMART data to `smartctl` others do not.
- In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). - In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45).
Scrutiny will eventually support overriding detected device type via the config file. Scrutiny supports overriding detected device type via the config file: see [example.collector.yaml](https://github.com/AnalogJ/scrutiny/blob/master/example.collector.yaml)
- If you use docker, you **must** pass though the RAID virtual disk to the container using `--device` (see below) - If you use docker, you **must** pass though the RAID virtual disk to the container using `--device` (see below)
- This device may be in `/dev/*` or `/dev/bus/*`. - This device may be in `/dev/*` or `/dev/bus/*`.
- If you're unsure, run `smartctl --scan` on your host, and pass all listed devices to the container. - If you're unsure, run `smartctl --scan` on your host, and pass all listed devices to the container.
See [docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md](./docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md) for help
## Docker ## Docker
+2
View File
@@ -83,9 +83,11 @@ Now that we have downloaded the required files, let's prepare the filesystem.
chmod +x /opt/scrutiny/bin/scrutiny-web-linux-amd64 chmod +x /opt/scrutiny/bin/scrutiny-web-linux-amd64
# Next, lets extract the frontend files. # Next, lets extract the frontend files.
# NOTE: after extraction, there **should not** be a `dist` subdirectory in `/opt/scrutiny/web` directory.
cd /opt/scrutiny/web cd /opt/scrutiny/web
tar xvzf scrutiny-web-frontend.tar.gz --strip-components 1 -C . tar xvzf scrutiny-web-frontend.tar.gz --strip-components 1 -C .
# Cleanup # Cleanup
rm -rf scrutiny-web-frontend.tar.gz rm -rf scrutiny-web-frontend.tar.gz
``` ```
+72
View File
@@ -0,0 +1,72 @@
# pfsense Install
This bascially follows the [Manual collector instructions](https://github.com/AnalogJ/scrutiny/blob/master/docs/INSTALL_MANUAL.md#collector) and assumes you are running a hub and spoke deployment and already have the web app setup.
### Dependencies
SSH into pfsense, hit `8` for the shell and install the required dependencies.
```
pkg install smartmontools
```
Ensure smartmontools is v7+. This won't be a problem in pfsense 2.6.0+
### Directory Structure
Now let's create a directory structure to contain the Scrutiny collector binary.
```
mkdir -p /opt/scrutiny/bin
```
### Download Files
Next, we'll download the Scrutiny collector binary from the [latest Github release](https://github.com/analogj/scrutiny/releases).
> NOTE: Ensure you have the latest version in the below command
```
fetch -o /opt/scrutiny/bin https://github.com/AnalogJ/scrutiny/releases/download/vX.X.X/scrutiny-collector-metrics-freebsd-amd64
```
### Prepare Scrutiny
Now that we have downloaded the required files, let's prepare the filesystem.
```
chmod +x /opt/scrutiny/bin/scrutiny-collector-metrics-freebsd-amd64
```
### Start Scrutiny Collector, Populate Webapp
Next, we will manually trigger the collector, to populate the Scrutiny dashboard:
> NOTE: if you need to pass a config file to the scrutiny collector, you can provide it using the `--config` flag.
```
/opt/scrutiny/bin/scrutiny-collector-metrics-freebsd-amd64 run --api-endpoint "http://localhost:8080"
```
> NOTE: change the IP address to that of your web app
### Schedule Collector with Cron
Finally you need to schedule the collector to run periodically.
Login to the pfsense webGUI and head to `Services/Cron` add an entry with the following details:
```
Minute: */15
Hour: *
Day of the Month: *
Month of the Year: *
Day of the Week: *
User: root
Command: /opt/scrutiny/bin/scrutiny-collector-metrics-freebsd-amd64 run --api-endpoint "http://localhost:8080" >/dev/null 2>&1
```
> NOTE: `>/dev/null 2>&1` is used to stop cron confirmation emails being sent.
+3 -1
View File
@@ -4,11 +4,13 @@ These are the officially supported NAS OS's (with documentation and setup guides
Once a guide is created (in `docs/guides/`) it will be linked here. Once a guide is created (in `docs/guides/`) it will be linked here.
- [ ] freenas/truenas - [ ] freenas/truenas
- [x] [unraid](https://github.com/AnalogJ/scrutiny/blob/master/docs/INSTALL_UNRAID.md) - [x] [unraid](./INSTALL_UNRAID.md)
- [ ] ESXI - [ ] ESXI
- [ ] Proxmox - [ ] Proxmox
- [ ] Synology - [ ] Synology
- [ ] OMV - [ ] OMV
- [ ] Amahi - [ ] Amahi
- [ ] Running in a LXC container - [ ] Running in a LXC container
- [x] [PFSense](./INSTALL_UNRAID.md)
- [ ] QNAP
+16
View File
@@ -52,6 +52,8 @@ If the output is the same, your devices will be processed by Scrutiny.
In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45).
Scrutiny will supports overriding the detected device type via the config file. Scrutiny will supports overriding the detected device type via the config file.
[example.collector.yaml](https://github.com/AnalogJ/scrutiny/blob/master/example.collector.yaml)
### RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc) ### RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc)
Smartctl has support for a large number of [RAID controllers](https://www.smartmontools.org/wiki/Supported_RAID-Controllers), however this Smartctl has support for a large number of [RAID controllers](https://www.smartmontools.org/wiki/Supported_RAID-Controllers), however this
support is not automatic, and may require some additional device type hinting. You can provide this information to the Scrutiny collector support is not automatic, and may require some additional device type hinting. You can provide this information to the Scrutiny collector
@@ -186,3 +188,17 @@ Thankfully the collector has a special `--host-id` flag (or `COLLECTOR_HOST_ID`
See the [docs/INSTALL_HUB_SPOKE.md](/docs/INSTALL_HUB_SPOKE.md) guide for more information. See the [docs/INSTALL_HUB_SPOKE.md](/docs/INSTALL_HUB_SPOKE.md) guide for more information.
## Collector DEBUG mode
You can use environmental variables to enable debug logging and/or log files for the collector:
```bash
DEBUG=true
COLLECTOR_LOG_FILE=/tmp/collector.log
```
Or if you're not using docker, you can pass CLI arguments to the collector during startup:
```bash
scrutiny-collector-metrics run --debug --log-file /tmp/collector.log
```
@@ -2,6 +2,7 @@ import { Inject, Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { TREO_APP_CONFIG } from '@treo/services/config/config.constants'; import { TREO_APP_CONFIG } from '@treo/services/config/config.constants';
import { AppConfig } from 'app/core/config/app.config';
const SCRUTINY_CONFIG_LOCAL_STORAGE_KEY = 'scrutiny'; const SCRUTINY_CONFIG_LOCAL_STORAGE_KEY = 'scrutiny';
@@ -12,20 +13,26 @@ export class TreoConfigService
{ {
// Private // Private
private _config: BehaviorSubject<any>; private _config: BehaviorSubject<any>;
private systemPrefersDark: boolean;
/** /**
* Constructor * Constructor
*/ */
constructor(@Inject(TREO_APP_CONFIG) defaultConfig: any) constructor(@Inject(TREO_APP_CONFIG) defaultConfig: any)
{ {
this.systemPrefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
let currentScrutinyConfig = defaultConfig let currentScrutinyConfig = defaultConfig
const localConfigStr = localStorage.getItem(SCRUTINY_CONFIG_LOCAL_STORAGE_KEY) let localConfigStr = localStorage.getItem(SCRUTINY_CONFIG_LOCAL_STORAGE_KEY)
if(localConfigStr){ if (localConfigStr){
// check localstorage for a value //check localstorage for a value
const localConfig = JSON.parse(localConfigStr) let localConfig = JSON.parse(localConfigStr)
currentScrutinyConfig = Object.assign({}, localConfig, currentScrutinyConfig) // make sure defaults are available if missing from localStorage. currentScrutinyConfig = Object.assign({}, localConfig, currentScrutinyConfig) // make sure defaults are available if missing from localStorage.
} }
currentScrutinyConfig.theme = this.determineTheme(currentScrutinyConfig);
// Set the private defaults // Set the private defaults
this._config = new BehaviorSubject(currentScrutinyConfig); this._config = new BehaviorSubject(currentScrutinyConfig);
} }
@@ -41,10 +48,12 @@ export class TreoConfigService
set config(value: any) set config(value: any)
{ {
// Merge the new config over to the current config // Merge the new config over to the current config
const config = _.merge({}, this._config.getValue(), value); let config = _.merge({}, this._config.getValue(), value);
//Store the config in localstorage //Store the config in localstorage
localStorage.setItem(SCRUTINY_CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config)); localStorage.setItem(SCRUTINY_CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config));
config.theme = this.determineTheme(config);
// Execute the observable // Execute the observable
this._config.next(config); this._config.next(config);
@@ -56,6 +65,17 @@ export class TreoConfigService
return this._config.asObservable(); return this._config.asObservable();
} }
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Checks if theme should be set to dark based on config & system settings
*/
private determineTheme(config:AppConfig): string {
return (config.darkModeUseSystem && this.systemPrefersDark) ? "dark" : config.theme;
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Public methods // @ Public methods
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -17,6 +17,8 @@ export interface AppConfig
dashboardSort: string; dashboardSort: string;
temperatureUnit: string; temperatureUnit: string;
darkModeUseSystem: boolean;
} }
/** /**
@@ -35,5 +37,7 @@ export const appConfig: AppConfig = {
dashboardSort: "status", dashboardSort: "status",
temperatureUnit: "celsius", temperatureUnit: "celsius",
darkModeUseSystem: true,
}; };
@@ -2,6 +2,21 @@
<mat-dialog-content class="mat-typography"> <mat-dialog-content class="mat-typography">
<div class="flex flex-col p-8 pb-0 overflow-hidden"> <div class="flex flex-col p-8 pb-0 overflow-hidden">
<div class="flex flex-col gt-md:flex-row">
<mat-slide-toggle class="mb-2" [(ngModel)]="darkModeUseSystem">Use system settings for dark mode</mat-slide-toggle>
<p [class.text-hint]="darkModeUseSystem">
Theme:
<mat-button-toggle-group class="ml-2" #group="matButtonToggleGroup" [(ngModel)]="theme" [disabled]="darkModeUseSystem">
<mat-button-toggle value="light" aria-label="Light mode">
<mat-icon>light_mode</mat-icon>
</mat-button-toggle>
<mat-button-toggle value="dark" aria-label="Dark mode">
<mat-icon>dark_mode</mat-icon>
</mat-button-toggle>
</mat-button-toggle-group>
</p>
</div>
<div class="flex flex-col mt-5 gt-md:flex-row"> <div class="flex flex-col mt-5 gt-md:flex-row">
<mat-form-field class="flex-auto gt-xs:pr-3 gt-md:pr-3"> <mat-form-field class="flex-auto gt-xs:pr-3 gt-md:pr-3">
<mat-label>Display Title</mat-label> <mat-label>Display Title</mat-label>
@@ -38,24 +53,24 @@
<mat-tab-group mat-align-tabs="start"> <mat-tab-group mat-align-tabs="start">
<mat-tab label="Ata"> <mat-tab label="Ata">
<div matTooltip="not yet implemented" class="gray-200 flex flex-col mt-5 gt-md:flex-row"> <div matTooltip="not yet implemented" class="flex flex-col mt-5 gt-md:flex-row">
<mat-form-field class="flex-auto gt-md:pr-3"> <mat-form-field class="flex-auto gt-md:pr-3">
<mat-label>Critical Error Threshold</mat-label> <mat-label class="text-hint">Critical Error Threshold</mat-label>
<input disabled matInput [value]="'10%'"> <input disabled matInput [value]="'10%'">
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto gt-md:pl-3"> <mat-form-field class="flex-auto gt-md:pl-3">
<mat-label>Critical Warning Threshold</mat-label> <mat-label class="text-hint">Critical Warning Threshold</mat-label>
<input disabled matInput> <input disabled matInput>
</mat-form-field> </mat-form-field>
</div> </div>
<div matTooltip="not yet implemented" class="gray-200 flex flex-col gt-md:flex-row"> <div matTooltip="not yet implemented" class="flex flex-col gt-md:flex-row">
<mat-form-field class="flex-auto gt-md:pr-3"> <mat-form-field class="flex-auto gt-md:pr-3">
<mat-label>Error Threshold</mat-label> <mat-label class="text-hint">Error Threshold</mat-label>
<input disabled matInput [value]="'20%'"> <input disabled matInput [value]="'20%'">
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto gt-md:pl-3"> <mat-form-field class="flex-auto gt-md:pl-3">
<mat-label>Warning Threshold</mat-label> <mat-label class="text-hint">Warning Threshold</mat-label>
<input disabled matInput [value]="'10%'"> <input disabled matInput [value]="'10%'">
</mat-form-field> </mat-form-field>
</div> </div>
@@ -63,26 +78,26 @@
</mat-tab> </mat-tab>
<mat-tab label="NVMe"> <mat-tab label="NVMe">
<div matTooltip="not yet implemented" class="gray-200 flex flex-col mt-5 gt-md:flex-row"> <div matTooltip="not yet implemented" class="flex flex-col mt-5 gt-md:flex-row">
<mat-form-field class="flex-auto gt-md:pr-3"> <mat-form-field class="flex-auto gt-md:pr-3">
<mat-label>Critical Error Threshold</mat-label> <mat-label class="text-hint">Critical Error Threshold</mat-label>
<input disabled matInput [value]="'enabled'"> <input disabled matInput [value]="'enabled'">
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto gt-md:pl-3"> <mat-form-field class="flex-auto gt-md:pl-3">
<mat-label>Critical Warning Threshold</mat-label> <mat-label class="text-hint">Critical Warning Threshold</mat-label>
<input disabled matInput> <input disabled matInput>
</mat-form-field> </mat-form-field>
</div> </div>
</mat-tab> </mat-tab>
<mat-tab label="SCSI"> <mat-tab label="SCSI">
<div matTooltip="not yet implemented" class="gray-200 flex flex-col mt-5 gt-md:flex-row"> <div matTooltip="not yet implemented" class="flex flex-col mt-5 gt-md:flex-row">
<mat-form-field class="flex-auto gt-md:pr-3"> <mat-form-field class="flex-auto gt-md:pr-3">
<mat-label>Critical Error Threshold</mat-label> <mat-label class="text-hint">Critical Error Threshold</mat-label>
<input disabled matInput [value]="'enabled'"> <input disabled matInput [value]="'enabled'">
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto gt-md:pl-3"> <mat-form-field class="flex-auto gt-md:pl-3">
<mat-label>Critical Warning Threshold</mat-label> <mat-label class="text-hint">Critical Warning Threshold</mat-label>
<input disabled matInput> <input disabled matInput>
</mat-form-field> </mat-form-field>
</div> </div>
@@ -13,7 +13,9 @@ export class DashboardSettingsComponent implements OnInit {
dashboardDisplay: string; dashboardDisplay: string;
dashboardSort: string; dashboardSort: string;
temperatureUnit: string temperatureUnit: string;
darkModeUseSystem: boolean;
theme: string;
// Private // Private
private _unsubscribeAll: Subject<any>; private _unsubscribeAll: Subject<any>;
@@ -35,7 +37,11 @@ export class DashboardSettingsComponent implements OnInit {
this.dashboardDisplay = config.dashboardDisplay; this.dashboardDisplay = config.dashboardDisplay;
this.dashboardSort = config.dashboardSort; this.dashboardSort = config.dashboardSort;
this.temperatureUnit = config.temperatureUnit; this.temperatureUnit = config.temperatureUnit;
this.darkModeUseSystem = config.darkModeUseSystem;
this.theme = config.theme;
}); });
} }
saveSettings(): void { saveSettings(): void {
@@ -43,6 +49,8 @@ export class DashboardSettingsComponent implements OnInit {
dashboardDisplay: this.dashboardDisplay, dashboardDisplay: this.dashboardDisplay,
dashboardSort: this.dashboardSort, dashboardSort: this.dashboardSort,
temperatureUnit: this.temperatureUnit, temperatureUnit: this.temperatureUnit,
darkModeUseSystem: this.darkModeUseSystem,
theme: this.theme
} }
this._configService.config = newSettings this._configService.config = newSettings
console.log(`Saved Settings: ${JSON.stringify(newSettings)}`) console.log(`Saved Settings: ${JSON.stringify(newSettings)}`)
+12
View File
@@ -4,3 +4,15 @@
// @ Styles from this file will override anything from 'vendors.scss' file allowing customizations and // @ Styles from this file will override anything from 'vendors.scss' file allowing customizations and
// modifications of third party libraries. // modifications of third party libraries.
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
.treo-theme-dark .yellow-50 {
background-color: #242b38 !important;
.mat-icon {
color: #6f4315 !important;
}
.text-secondary {
color: rgb(203 101 37 / 70%) !important
}
}