mirror of
https://github.com/JustKato/drive-health.git
synced 2026-03-04 16:39:45 +02:00
Compare commits
9 Commits
v0.1.7
...
feature/3-
| Author | SHA1 | Date | |
|---|---|---|---|
| 145362b7ef | |||
| f17d8b44a3 | |||
| de08a7f970 | |||
| d6588742d3 | |||
| 44d4237bec | |||
| f2c84fb6b2 | |||
| 4f50819f92 | |||
| 6117157598 | |||
| 79e44bd88a |
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
!main.go
|
||||||
|
!/lib
|
||||||
|
!/templates
|
||||||
|
!/static
|
||||||
|
!/go.mod
|
||||||
|
!/go.sum
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
# Build Stage
|
# Build Stage
|
||||||
FROM debian:bullseye
|
FROM debian:bullseye-slim
|
||||||
ENV IS_DOCKER TRUE
|
ENV IS_DOCKER TRUE
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.source https://github.com/JustKato/drive-health
|
||||||
|
|
||||||
# Install build dependencies and runtime dependencies
|
# Install build dependencies and runtime dependencies
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
gcc \
|
gcc \
|
||||||
@@ -22,10 +24,9 @@ ENV PATH /usr/local/go/bin:$PATH
|
|||||||
ENV GOPATH=/go
|
ENV GOPATH=/go
|
||||||
ENV PATH=$GOPATH/bin:$PATH
|
ENV PATH=$GOPATH/bin:$PATH
|
||||||
ENV GO111MODULE=on
|
ENV GO111MODULE=on
|
||||||
ENV DIST_DIR=/app
|
|
||||||
|
|
||||||
# Create the directory and set it as the working directory
|
# Create the directory and set it as the working directory
|
||||||
WORKDIR $DIST_DIR
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy the Go files and download dependencies
|
# Copy the Go files and download dependencies
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
|
|||||||
61
README.md
61
README.md
@@ -1,13 +1,17 @@
|
|||||||
## 📖 About
|
## 📖 About
|
||||||
|
|
||||||
Drive Health is a program written in golang to help with tracking and monitoring of your hardware's temperature.
|
Drive Health is a program written in golang to help with tracking and monitoring of your hardware's temperature.
|
||||||
|
|
||||||
This tool has been with the purpose of installing it in different servers I own with different configurations to help keep track of the temperature of different hard-disks, ssds, nvme drives, etc... The testing has been very limited to only 4 different computers and not on laptops so expect some mishaps.
|
This tool had been conceived with the purpose of installing it on different servers I own with different configurations to help keep track of the temperature of hard-disks, ssds, nvme drives, etc...
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Disk Listing
|
||||||
|
- Temperature Graphing
|
||||||
|
- Disk activity logging
|
||||||
|
- [API](./lib/web/api.go)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## ❗ Disclaimer
|
## ❗ Disclaimer
|
||||||
|
|
||||||
I'm not exactly a linux hardware wizard, so I honestly have no clue about a lot of things and I myself can tell there's a lot to improve upon and that there's a lot of other things missing that are a little bit more obscure, I personally don't currently own any m.2 sata drives to test the code on, or many of the other drive types, I have only tested on HDD, SSD and NVMe drives, any issues opened would help me so much!
|
I'm not exactly a linux hardware wizard, so I honestly have no clue about a lot of things and I myself can tell there's a lot to improve upon and that there's a lot of other things missing that are a little bit more obscure, I personally don't currently own any m.2 sata drives to test the code on, or many of the other drive types, I have only tested on HDD, SSD and NVMe drives, any issues opened would help me so much!
|
||||||
|
|
||||||
## ❗ Requirements
|
## ❗ Requirements
|
||||||
@@ -18,12 +22,48 @@ The program depends on this to be able to log the temperature of your devices.
|
|||||||
|
|
||||||
|
|
||||||
## 📖 How to use
|
## 📖 How to use
|
||||||
|
1. Follow the `Deployment` section instrcutions to launch the program
|
||||||
|
|
||||||
The program is straight forward to use really, edit the [.env](./.env) file and make the changes you would like applied.
|
2. Once the program has launched, access it in your browser
|
||||||
|
|
||||||
### Docker ( Recommended/Hassle free )
|
3. Enter the administrative username and password for the simple HTTP Auth
|
||||||
|
|
||||||
|
4. You now have access to the application, you can monitor your disk's temperature over a period of time.
|
||||||
|
|
||||||
|
## 🐦 Deployment
|
||||||
|
To deploy the application you have multiple choices, the preffered method should be one which runs the binary directly and not containerization, the `docker` image is taking up a wopping `1Gb+` because I have to include sqlite3-dev and musl-dev dependencies, which sucks, so I whole heartedly recommend just installing this on your system as a binary either with `SystemD` or whichever service manager you are using.
|
||||||
|
|
||||||
|
Download binaries from [the releases page](https://github.com/JustKato/drive-health/releases)
|
||||||
|
|
||||||
|
### 🐋 Docker
|
||||||
|
In the project there's a `docker-compose.prod.yml` which you can deploy on your server, you will notice that there's also a "dev" version, this version simply has a `build` instead of `image` property, so feel free to use either.
|
||||||
|
|
||||||
|
Please do take notice that I have just fed the `environment file` directly to the service via docker-compose, and I recommend you do the same but please feel free to pass in `environment` variables straight to the process as well.
|
||||||
|
|
||||||
|
[Docker Compose File](./docker-compose.prod.yml)
|
||||||
|
```yaml
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
drive-health:
|
||||||
|
# Latest image pull, mention the specific version here please.
|
||||||
|
image: ghcr.io/justkato/drive-health:latest
|
||||||
|
# Restart in case of crashing
|
||||||
|
restart: unless-stopped
|
||||||
|
# Load environment variables from .env file
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
# Mount the volume to the local drive
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
# Setup application ports
|
||||||
|
ports:
|
||||||
|
- 5003:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### 💾 SystemD
|
||||||
|
When running with SystemD or any other service manager, please make sure you have a `.env` inside the `WorkingDirectory` of your runner, in the below example I will simply put my env in `/home/daniel/services/drive-health/.env`
|
||||||
|
|
||||||
### SystemD
|
|
||||||
```ini
|
```ini
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Drive Health Service
|
Description=Drive Health Service
|
||||||
@@ -43,15 +83,16 @@ WantedBy=multi-user.target
|
|||||||
## ❔ FAQ
|
## ❔ FAQ
|
||||||
|
|
||||||
### How does it work?
|
### How does it work?
|
||||||
Currently the program does not depend on any hardware library as I couldn't find anything that would not require root access while giving me the possibility to interrogate the temperature of the drives, I chose not to depend on `lsblk` either, so how does the program work? Well it looks in `/sys/block` and simply
|
Currently the program does not depend on any go library for hardware detection as I couldn't find anything that would not require root access while giving me the possibility to interrogate the temperature of the drives.
|
||||||
|
|
||||||
|
I chose not to depend on `lsblk` either, so how does the program work?
|
||||||
|
The program currently looks in `/sys/block` and then tries to make sense of the devices, I have had limited testing with my hardware specs, any issues being open in regards to different kinds of hardware would be highly appreciated
|
||||||
|
|
||||||
### Why not just run as root?
|
### Why not just run as root?
|
||||||
I really, really, **really** want to avoid asking people to run **ANY** program I write as root and even try and prevent that from happening since that's how things can go bad, especially because I am runnig actions over hardware items. I think you can see how easy it is for a mistake or a **malicious attack** to easily deal damage
|
I really, REALLY, **REALLY** want to avoid asking people to run **ANY** program I write as root and even try and prevent that from happening since that's how things can go bad, especially because I am running actions over hardware devices.
|
||||||
|
|
||||||
## Support & Contribution
|
## Support & Contribution
|
||||||
|
|
||||||
For support, bug reports, or feature requests, please open an issue on the [GitHub repository](https://github.com/JustKato/drive-health/issues). Contributions are welcome! Fork the repository, make your changes, and submit a pull request.
|
For support, bug reports, or feature requests, please open an issue on the [GitHub repository](https://github.com/JustKato/drive-health/issues). Contributions are welcome! Fork the repository, make your changes, and submit a pull request.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the [Apache License 2.0](./LICENSE).
|
This project is licensed under the [Apache License 2.0](./LICENSE).
|
||||||
39
build.sh
39
build.sh
@@ -1,19 +1,50 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
|
# Function to display messages in color
|
||||||
|
echo_color() {
|
||||||
|
color=$1
|
||||||
|
text=$2
|
||||||
|
case $color in
|
||||||
|
"green") echo -e "\033[0;32m$text\033[0m" ;;
|
||||||
|
"yellow") echo -e "\033[0;33m$text\033[0m" ;;
|
||||||
|
"red") echo -e "\033[0;31m$text\033[0m" ;;
|
||||||
|
*) echo "$text" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Getting GIT_VERSION from the most recent tag or commit hash
|
||||||
|
GIT_VERSION=$(git describe --tags --always)
|
||||||
|
if [ -z "$GIT_VERSION" ]; then
|
||||||
|
echo_color red "Error: Unable to determine GIT_VERSION."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
APP_NAME="drive-health"
|
APP_NAME="drive-health"
|
||||||
DIST_DIR="${DIST_DIR:-dist}"
|
DIST_DIR="${DIST_DIR:-dist}"
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
# make sure we are in the source dir
|
||||||
|
cd $SCRIPT_DIR;
|
||||||
|
|
||||||
# Create the dist directory if it doesn't exist
|
# Create the dist directory if it doesn't exist
|
||||||
mkdir -p $DIST_DIR
|
mkdir -p $DIST_DIR
|
||||||
|
|
||||||
# Build the application
|
# Build the application
|
||||||
echo "Building the application..."
|
echo_color yellow "[🦝] Building the application..."
|
||||||
GOOS=linux CGO_ENABLED=1 GOARCH=amd64 go build -o $DIST_DIR/$APP_NAME
|
GOOS=linux CGO_ENABLED=1 GOARCH=amd64 go build -o $DIST_DIR/$APP_NAME
|
||||||
|
|
||||||
# echo "Copying additional resources..."
|
# Copying additional resources...
|
||||||
cp -r static templates $DIST_DIR/
|
cp -r static templates $DIST_DIR/
|
||||||
|
|
||||||
echo "Compilation and packaging completed."
|
echo_color yellow "[🦝] Compilation and packaging completed, archiving..."
|
||||||
|
|
||||||
|
cd $DIST_DIR/
|
||||||
|
|
||||||
|
zip "drive-health_$GIT_VERSION.zip" -r .
|
||||||
|
|
||||||
|
# TODO: Add reliable method of cleaning up the compiled files optionally
|
||||||
|
|
||||||
|
cd $SCRIPT_DIR;
|
||||||
17
docker-compose.prod.yml
Normal file
17
docker-compose.prod.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
drive-health:
|
||||||
|
# Latest image pull, mention the specific version here please.
|
||||||
|
image: ghcr.io/justkato/drive-health:latest
|
||||||
|
# Restart in case of crashing
|
||||||
|
restart: unless-stopped
|
||||||
|
# Load environment variables from .env file
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
# Mount the volume to the local drive
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
# Setup application ports
|
||||||
|
ports:
|
||||||
|
- 5003:8080
|
||||||
@@ -44,16 +44,19 @@ type Snapshots struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HardDrive) GetTemperature() int {
|
func (h *HardDrive) GetTemperature() int {
|
||||||
|
|
||||||
|
possiblePaths := []string{
|
||||||
|
"/sys/block/" + h.Name + "/device/hwmon/",
|
||||||
|
"/sys/block/" + h.Name + "/device/",
|
||||||
|
"/sys/block/" + h.Name + "/device/generic/device/",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range possiblePaths {
|
||||||
// Try HDD/SSD path
|
// Try HDD/SSD path
|
||||||
temp, found := h.getTemperatureFromPath("/sys/block/" + h.Name + "/device/hwmon/")
|
temp, found := h.getTemperatureFromPath(path)
|
||||||
if found {
|
if found {
|
||||||
return temp
|
return temp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try NVMe path
|
|
||||||
temp, found = h.getTemperatureFromPath("/sys/block/" + h.Name + "/device/")
|
|
||||||
if found {
|
|
||||||
return temp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("[🛑] Failed to get temperature for %s\n", h.Name)
|
fmt.Printf("[🛑] Failed to get temperature for %s\n", h.Name)
|
||||||
|
|||||||
@@ -15,6 +15,21 @@ func setupFrontend(r *gin.Engine) {
|
|||||||
r.LoadHTMLGlob("templates/*")
|
r.LoadHTMLGlob("templates/*")
|
||||||
r.Static("/static", "./static")
|
r.Static("/static", "./static")
|
||||||
|
|
||||||
|
r.GET("/disk/:id", func(ctx *gin.Context) {
|
||||||
|
id := ctx.Param("id")
|
||||||
|
var hdd hardware.HardDrive
|
||||||
|
tx := svc.GetDatabaseRef().Where("id = ?", id).Preload("Temperatures").First(&hdd)
|
||||||
|
if tx.Error != nil {
|
||||||
|
ctx.AbortWithError(500, tx.Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the HTML template
|
||||||
|
ctx.HTML(http.StatusOK, "drive.html", gin.H{
|
||||||
|
"hdd": hdd,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// Set up a route for the root URL
|
// Set up a route for the root URL
|
||||||
r.GET("/", func(ctx *gin.Context) {
|
r.GET("/", func(ctx *gin.Context) {
|
||||||
hardDrives, err := hardware.GetSystemHardDrives(svc.GetDatabaseRef(), nil, nil)
|
hardDrives, err := hardware.GetSystemHardDrives(svc.GetDatabaseRef(), nil, nil)
|
||||||
|
|||||||
@@ -11,14 +11,17 @@
|
|||||||
--fg1: #434c56;
|
--fg1: #434c56;
|
||||||
|
|
||||||
--acc1: #2aa3f4;
|
--acc1: #2aa3f4;
|
||||||
|
--acc1H: #0089e5;
|
||||||
--acc1BG0: #2aa3f450;
|
--acc1BG0: #2aa3f450;
|
||||||
--acc1BG1: #2aa3f430;
|
--acc1BG1: #2aa3f430;
|
||||||
|
|
||||||
--acc2: #2af488;
|
--acc2: #2af488;
|
||||||
|
--acc2H: #2af488;
|
||||||
--acc2BG0: #2af48850;
|
--acc2BG0: #2af48850;
|
||||||
--acc2BG1: #2af48830;
|
--acc2BG1: #2af48830;
|
||||||
|
|
||||||
--acc3: #f4e02a;
|
--acc3: #f4e02a;
|
||||||
|
--acc3H: #f4e02a;
|
||||||
--acc3BG0: #f4e02a50;
|
--acc3BG0: #f4e02a50;
|
||||||
--acc3BG1: #f4e02a30;
|
--acc3BG1: #f4e02a30;
|
||||||
}
|
}
|
||||||
@@ -28,6 +31,17 @@
|
|||||||
font-family: "Noto Sans Mono", "Roboto", sans-serif;
|
font-family: "Noto Sans Mono", "Roboto", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -155,6 +169,32 @@ input {
|
|||||||
background-color: var(--bg3);
|
background-color: var(--bg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-link {
|
||||||
|
color: var(--acc1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-link:hover {
|
||||||
|
color: var(--acc1H);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-button {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
mask-image: url("/static/view-svgrepo-com.svg");
|
||||||
|
background: var(--fg0);
|
||||||
|
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-position: center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-button:hover {
|
||||||
|
mask-image: url("/static/view-alt-svgrepo-com.svg");
|
||||||
|
background-color: var(--acc1);
|
||||||
|
}
|
||||||
|
|
||||||
.input-grp {
|
.input-grp {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
|||||||
5
static/view-alt-svgrepo-com.svg
Normal file
5
static/view-alt-svgrepo-com.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17 4H17.2C18.9913 4 19.887 4 20.4435 4.5565C21 5.11299 21 6.00866 21 7.8V8M17 20H17.2C18.9913 20 19.887 20 20.4435 19.4435C21 18.887 21 17.9913 21 16.2V16M7 4H6.8C5.00866 4 4.11299 4 3.5565 4.5565C3 5.11299 3 6.00866 3 7.8V8M7 20H6.8C5.00866 20 4.11299 20 3.5565 19.4435C3 18.887 3 17.9913 3 16.2V16" stroke="#33363F" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.8149 12C18.8149 11.4637 18.6892 11.2462 18.4379 10.8112C17.5834 9.33247 15.6561 7 12 7C8.34395 7 6.41664 9.33247 5.56212 10.8112C5.31077 11.2462 5.18509 11.4637 5.18509 12C5.18509 12.5363 5.31077 12.7538 5.56212 13.1888C6.41664 14.6675 8.34395 17 12 17C15.6561 17 17.5834 14.6675 18.4379 13.1888C18.6892 12.7538 18.8149 12.5363 18.8149 12ZM12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3432 9 9.00001 10.3431 9.00001 12C9.00001 13.6569 10.3432 15 12 15Z" fill="#33363F"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
4
static/view-svgrepo-com.svg
Normal file
4
static/view-svgrepo-com.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.7703 12C20.7703 11.6412 20.5762 11.4056 20.188 10.9343C18.768 9.21014 15.6357 6 12 6C8.36428 6 5.23207 9.21014 3.81198 10.9343C3.42382 11.4056 3.22974 11.6412 3.22974 12C3.22974 12.3588 3.42382 12.5944 3.81198 13.0657C5.23207 14.7899 8.36428 18 12 18C15.6357 18 18.768 14.7899 20.188 13.0657C20.5762 12.5944 20.7703 12.3588 20.7703 12ZM12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3432 9 9.00002 10.3431 9.00002 12C9.00002 13.6569 10.3432 15 12 15Z" fill="#33363F"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 767 B |
46
templates/drive.html
Normal file
46
templates/drive.html
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
|
<title>Drive Health Dashboard</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container bordered">
|
||||||
|
|
||||||
|
<div class="container-titlebar">
|
||||||
|
<div class="pad">
|
||||||
|
<h4>{{ .hdd.Model }} <span class="grooved">{{ .hdd.Size }}</span></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-body">
|
||||||
|
<div class="pad">
|
||||||
|
<table id="disks-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>ID</td>
|
||||||
|
<td>Name</td>
|
||||||
|
<td>Model</td>
|
||||||
|
<td>Serial</td>
|
||||||
|
<td>Temperature</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="disk-table-body">
|
||||||
|
<tr>
|
||||||
|
<td>#{{ .hdd.ID }}</td>
|
||||||
|
<td> {{ .hdd.Name }}</td>
|
||||||
|
<td> {{ .hdd.Model }}</td>
|
||||||
|
<td> {{ .hdd.Serial }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
<td>Model</td>
|
<td>Model</td>
|
||||||
<td>Serial</td>
|
<td>Serial</td>
|
||||||
<td>Temperature</td>
|
<td>Temperature</td>
|
||||||
|
<td>Actions</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="disk-table-body">
|
<tbody id="disk-table-body">
|
||||||
@@ -49,6 +50,9 @@
|
|||||||
{{ else }} <!-- Temperature 30°C or below -->
|
{{ else }} <!-- Temperature 30°C or below -->
|
||||||
<td style="color: lime;">{{ $temp }}°C</td>
|
<td style="color: lime;">{{ $temp }}°C</td>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
<td>
|
||||||
|
<a title="View Disk" class="info-button" href="/disk/{{ .ID }}"></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Reference in New Issue
Block a user