diff --git a/data.go b/data.go
index a49ef13..1f8ba11 100644
--- a/data.go
+++ b/data.go
@@ -27,3 +27,29 @@ func (a *App) GetAllRAMTypes() ([]string, error) {
}
return types, err
}
+
+func (a *App) GetAllTypes() ([]string, error) {
+ var types []string
+ var err error
+ for row := range a.db.Query("SELECT type FROM assets GROUP BY type ORDER BY type ASC").Range(&err) {
+ var name string
+ err := row.Scan(&name)
+ if err != nil {
+ return nil, err
+ }
+ types = append(types, name)
+ }
+ return types, err
+}
+
+func (a *App) GetAssetCount() (int, error) {
+ var count int
+ err := a.db.Query("SELECT COUNT(*) FROM assets").ScanSingle(&count)
+ return count, err
+}
+
+func (a *App) GetBrandCount() (int, error) {
+ var count int
+ err := a.db.Query("SELECT COUNT(DISTINCT brand) FROM assets").ScanSingle(&count)
+ return count, err
+}
diff --git a/go.mod b/go.mod
index fd6289b..54d933d 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.24
toolchain go1.24.1
require (
- gitea.seeseepuff.be/seeseemelk/mysqlite v0.7.0
+ gitea.seeseepuff.be/seeseemelk/mysqlite v0.9.0
github.com/gin-gonic/gin v1.10.0
)
diff --git a/go.sum b/go.sum
index cb8a92c..7c65f36 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,5 @@
-gitea.seeseepuff.be/seeseemelk/mysqlite v0.7.0 h1:gq75Ce7QTQ5Rj5fzS/6eeOA/enyV0oDMVt5mejwX14Y=
-gitea.seeseepuff.be/seeseemelk/mysqlite v0.7.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE=
+gitea.seeseepuff.be/seeseemelk/mysqlite v0.9.0 h1:GaU2DSrgDfZEqST3HdnNgfKSI4sNXvMm8SSfeMvBxA4=
+gitea.seeseepuff.be/seeseemelk/mysqlite v0.9.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE=
github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g=
github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
diff --git a/main.go b/main.go
index 0a073c1..39324fd 100644
--- a/main.go
+++ b/main.go
@@ -37,6 +37,8 @@ func main() {
Funcs(template.FuncMap{
"statusText": http.StatusText,
"createDeviceLink": createDeviceLink,
+ "formatMemorySize": formatMemorySize,
+ "formatType": formatType,
}).
ParseFS(templateFS, "templates/*.gohtml")
@@ -54,6 +56,7 @@ func main() {
r.GET("/device", app.getDevice)
r.GET("/create", app.getCreateDevice)
r.POST("/create", app.postCreateDevice)
+ r.GET("/browse", app.getBrowse)
err = r.Run()
if err != nil {
log.Fatalf("error serving website: %v", err)
diff --git a/template_funcs.go b/template_funcs.go
index de900cc..fad1a49 100644
--- a/template_funcs.go
+++ b/template_funcs.go
@@ -1,5 +1,9 @@
package main
+import (
+ "fmt"
+)
+
func createDeviceLink(deviceType, name string, qr *int) CreateDeviceLink {
return CreateDeviceLink{
Type: deviceType,
@@ -13,3 +17,31 @@ type CreateDeviceLink struct {
Name string
Qr *int
}
+
+func formatMemorySize(size int) string {
+ const (
+ KB = 1024
+ MB = KB * 1024
+ GB = MB * 1024
+ )
+
+ switch {
+ case size >= GB:
+ return fmt.Sprintf("%.2f GB", float64(size)/GB)
+ case size >= MB:
+ return fmt.Sprintf("%.2f MB", float64(size)/MB)
+ case size >= KB:
+ return fmt.Sprintf("%.2f KB", float64(size)/KB)
+ default:
+ return fmt.Sprintf("%d B", size)
+ }
+}
+
+func formatType(t string) string {
+ switch t {
+ case "ram":
+ return "Random Access Memory"
+ default:
+ return t
+ }
+}
diff --git a/templates/browse.gohtml b/templates/browse.gohtml
new file mode 100644
index 0000000..c24bd45
--- /dev/null
+++ b/templates/browse.gohtml
@@ -0,0 +1,31 @@
+{{- /*gotype: main.BrowseVM */}}
+{{define "browse"}}
+{{template "header" "Search Results"}}
+
+
+ | QR |
+ Type |
+ Name |
+ Brand |
+ Description |
+ {{if .HasRam}}
+ RAM Type |
+ RAM Capacity |
+ {{end}}
+
+ {{range .Assets}}
+
+ | {{.Qr}} |
+ {{.Type | formatType}} |
+ {{.Name}} |
+ {{.Brand}} |
+ {{.Description}} |
+ {{if $.HasRam}}
+ {{.RamType}} |
+ {{.RamCapacity | formatMemorySize}} |
+ {{end}}
+
+ {{end}}
+
+{{template "footer"}}
+{{end}}
diff --git a/templates/device.gohtml b/templates/device.gohtml
new file mode 100644
index 0000000..bafc0f7
--- /dev/null
+++ b/templates/device.gohtml
@@ -0,0 +1,33 @@
+{{- /*gotype: main.DeviceVM */}}
+{{define "device"}}
+{{template "header" "Device Details"}}
+
+
+ | Name: |
+ {{.Name}} |
+
+
+ | Brand: |
+ {{.Brand}} |
+
+
+ | Type: |
+ {{.Type}} |
+
+
+ | Description: |
+ {{.Description}} |
+
+ {{if eq .Type "ram"}}
+
+ | RAM Type: |
+ {{.RamType}} |
+
+
+ | RAM Capacity: |
+ {{.RamCapacity | formatMemorySize}} |
+
+ {{end}}
+
+{{template "footer"}}
+{{end}}
diff --git a/templates/index.gohtml b/templates/index.gohtml
index 3d0ee11..6aa2b34 100644
--- a/templates/index.gohtml
+++ b/templates/index.gohtml
@@ -1,9 +1,32 @@
{{- /*gotype: main.IndexVM */}}
{{define "index"}}
{{template "header"}}
- Some statistics:
+ Some statistics
- Database contains {{.AssetCount}} assets.
+ - Database contains {{.BrandCount}} brands.
+
+ Filter Devices
+
+
{{template "footer"}}
{{end}}
diff --git a/views.go b/views.go
index 8ba770e..a514f67 100644
--- a/views.go
+++ b/views.go
@@ -16,11 +16,33 @@ type App struct {
type IndexVM struct {
AssetCount int
+ BrandCount int
+ Brands []string
+ Types []string
}
func (a *App) getIndex(c *gin.Context) {
vm := &IndexVM{}
- err := a.db.Query("SELECT COUNT(*) FROM assets").ScanSingle(&vm.AssetCount)
+ var err error
+ vm.AssetCount, err = a.GetAssetCount()
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+
+ vm.BrandCount, err = a.GetBrandCount()
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+
+ vm.Brands, err = a.GetAllBrands()
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+
+ vm.Types, err = a.GetAllTypes()
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
@@ -29,6 +51,15 @@ func (a *App) getIndex(c *gin.Context) {
c.HTML(http.StatusOK, "index", vm)
}
+type DeviceVM struct {
+ Name string
+ Brand string
+ Type string
+ Description string
+ RamType string
+ RamCapacity int
+}
+
func (a *App) getDevice(c *gin.Context) {
qr, err := strconv.Atoi(c.Query("id"))
if err != nil {
@@ -49,6 +80,27 @@ func (a *App) getDevice(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, "/create?id="+strconv.Itoa(qr))
return
}
+
+ vm := &DeviceVM{}
+ err = a.db.Query("SELECT name, brand, type, description FROM assets WHERE qr = ?").
+ Bind(qr).
+ ScanSingle(&vm.Name, &vm.Brand, &vm.Type, &vm.Description)
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+
+ if vm.Type == "ram" {
+ err = a.db.Query("SELECT type, capacity FROM info_ram WHERE asset = ?").
+ Bind(qr).
+ ScanSingle(&vm.RamType, &vm.RamCapacity)
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+ }
+
+ c.HTML(http.StatusOK, "device", vm)
}
type CreateDeviceVM struct {
@@ -153,3 +205,70 @@ func (a *App) postCreateDeviceRam(c *gin.Context, qr int) error {
}
return tx.Commit()
}
+
+type BrowseVM struct {
+ Assets []Asset
+ HasRam bool
+}
+
+type Asset struct {
+ Qr int
+ Name string
+ Brand string
+ Type string
+ Description string
+ RamType string
+ RamCapacity int
+}
+
+func (a *App) getBrowse(c *gin.Context) {
+ brands := c.QueryArray("brand")
+ types := c.QueryArray("type")
+
+ query := `SELECT assets.qr, assets.name, assets.brand, assets.type, assets.description,
+ info_ram.type, info_ram.capacity
+ FROM assets
+ JOIN info_ram ON info_ram.asset = assets.qr
+ WHERE 1=1`
+ if len(brands) > 0 {
+ query += " AND assets.brand IN (" + placeholders(len(brands)) + ")"
+ }
+ if len(types) > 0 {
+ query += " AND assets.type IN (" + placeholders(len(types)) + ")"
+ }
+
+ vm := &BrowseVM{}
+
+ var err error
+ q := a.db.Query(query).Bind(brands, types)
+ for row := range q.Range(&err) {
+ var asset Asset
+ err := row.Scan(&asset.Qr, &asset.Name, &asset.Brand, &asset.Type, &asset.Description, &asset.RamType, &asset.RamCapacity)
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+ vm.Assets = append(vm.Assets, asset)
+ if asset.Type == "ram" {
+ vm.HasRam = true
+ }
+ }
+ if err != nil {
+ c.AbortWithError(http.StatusInternalServerError, err)
+ return
+ }
+
+ c.HTML(http.StatusOK, "browse", vm)
+}
+
+func placeholders(count int) string {
+ if count == 0 {
+ return ""
+ }
+ placeholder := "?"
+ for count > 1 {
+ placeholder += ", ?"
+ count--
+ }
+ return placeholder
+}