Implemented frontend

+ Graph Generation as images for frontend performance
+ A new decent style
This commit is contained in:
2024-01-21 18:25:23 +02:00
parent eb94ce4552
commit 545eed44cd
7 changed files with 315 additions and 40 deletions

View File

@@ -67,8 +67,6 @@ func GetSystemHardDrives(db *gorm.DB, olderThan *time.Time, newerThan *time.Time
q := db.Where("serial = ? AND model = ? AND type = ?", sysHDD.Serial, sysHDD.Model, sysHDD.Type)
if newerThan != nil && olderThan != nil {
fmt.Printf("\nNewer Than: %s\n", newerThan)
fmt.Printf("Older Than: %s\n\n", olderThan)
q = q.Preload("Temperatures", "time_stamp < ? AND time_stamp > ?", newerThan, olderThan)
}

View File

@@ -1,9 +1,11 @@
package svc
import (
"bytes"
"fmt"
"time"
"github.com/wcharczuk/go-chart/v2"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"tea.chunkbyte.com/kato/drive-health/lib/config"
@@ -66,3 +68,114 @@ func RunLoggerService() {
}
}()
}
func GetDiskGraphImage(hddID int, newerThan *time.Time, olderThan *time.Time) (*bytes.Buffer, error) {
var hdd hardware.HardDrive
// Fetch by a combination of fields
q := db.Where("id = ?", hddID)
if newerThan == nil && olderThan == nil {
q = q.Preload("Temperatures")
} else {
q = q.Preload("Temperatures", "time_stamp < ? AND time_stamp > ?", newerThan, olderThan)
}
// Query for the instance
result := q.First(&hdd)
if result.Error != nil {
return nil, result.Error
}
// Prepare slices for X (time) and Y (temperature) values
var xValues []time.Time
var yValues []float64
for _, temp := range hdd.Temperatures {
xValues = append(xValues, temp.TimeStamp)
yValues = append(yValues, float64(temp.Temperature))
}
// Allocate a buffer for the graph image
graphImageBuffer := bytes.NewBuffer([]byte{})
// TODO: Graph dark theme
// Generate the chart
graph := chart.Chart{
Title: fmt.Sprintf("%s:%s[%s]", hdd.Name, hdd.Serial, hdd.Size),
TitleStyle: chart.Style{
FontSize: 14,
},
// TODO: Implement customizable sizing
Width: 1280,
Background: chart.Style{
Padding: chart.Box{
Top: 20, Right: 20, Bottom: 20, Left: 20,
},
},
XAxis: chart.XAxis{
Name: "Time",
ValueFormatter: func(v interface{}) string {
if ts, isValidTime := v.(float64); isValidTime {
t := time.Unix(int64(ts/1e9), 0)
return t.Format("Jan 2 2006, 15:04")
}
return ""
},
Style: chart.Style{},
GridMajorStyle: chart.Style{
StrokeColor: chart.ColorAlternateGray,
StrokeWidth: 0.5,
},
GridMinorStyle: chart.Style{
StrokeColor: chart.ColorAlternateGray.WithAlpha(64),
StrokeWidth: 0.25,
},
},
YAxis: chart.YAxis{
Name: "Temperature (C)",
Style: chart.Style{},
GridMajorStyle: chart.Style{
StrokeColor: chart.ColorAlternateGray,
StrokeWidth: 0.5,
},
GridMinorStyle: chart.Style{
StrokeColor: chart.ColorAlternateGray.WithAlpha(64),
StrokeWidth: 0.25,
},
},
Series: []chart.Series{
chart.TimeSeries{
Name: "Temperature",
XValues: xValues,
YValues: yValues,
Style: chart.Style{
StrokeColor: chart.ColorCyan,
StrokeWidth: 2.0,
},
},
},
}
// Add a legend to the chart
graph.Elements = []chart.Renderable{
chart.Legend(&graph, chart.Style{
Padding: chart.Box{
Top: 5, Right: 5, Bottom: 5, Left: 5,
},
FontSize: 10,
}),
}
// Render the chart into the byte buffer
err := graph.Render(chart.PNG, graphImageBuffer)
if err != nil {
return nil, err
}
return graphImageBuffer, nil
}

View File

@@ -2,6 +2,7 @@ package web
import (
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
@@ -12,6 +13,44 @@ import (
func setupApi(r *gin.Engine) {
api := r.Group("/api/v1")
api.GET("/disks/:diskid/chart", func(ctx *gin.Context) {
diskIDString := ctx.Param("diskid")
diskId, err := strconv.Atoi(diskIDString)
if err != nil {
ctx.AbortWithStatusJSON(400, gin.H{
"error": err.Error(),
"message": "Invalid Disk ID",
})
return
}
graphData, err := svc.GetDiskGraphImage(diskId, nil, nil)
if err != nil {
ctx.AbortWithStatusJSON(500, gin.H{
"error": err.Error(),
"message": "Graph generation issue",
})
return
}
// Set the content type header
ctx.Writer.Header().Set("Content-Type", "image/png")
// Write the image data to the response
ctx.Writer.WriteHeader(http.StatusOK)
_, err = graphData.WriteTo(ctx.Writer)
if err != nil {
ctx.AbortWithStatusJSON(500, gin.H{
"error": err.Error(),
"message": "Write error",
})
return
}
})
api.GET("/disks", func(ctx *gin.Context) {
olderThan := time.Now().Add(time.Minute * time.Duration(10) * -1)