Moved hosting.templ into the view directory

- Pages will go to view
- pages will be seperated into each file by type (host, vm, etc.)
- each page will have multiple sections in each file that can be
  either rendered together, or loaded via HTMX, depending on the call
- started on htmx api endpoints
This commit is contained in:
Matthew Stobbs 2024-03-17 00:10:04 -06:00
parent 5ae4fb3ab9
commit 4819cc8e9b
12 changed files with 544 additions and 186 deletions

1
go.mod
View File

@ -10,6 +10,7 @@ require (
require ( require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/wcharczuk/go-chart/v2 v2.1.1 // indirect github.com/wcharczuk/go-chart/v2 v2.1.1 // indirect
golang.org/x/image v0.11.0 // indirect golang.org/x/image v0.11.0 // indirect
) )

2
go.sum
View File

@ -6,6 +6,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/wcharczuk/go-chart/v2 v2.1.1 h1:2u7na789qiD5WzccZsFz4MJWOJP72G+2kUuJoSNqWnE= github.com/wcharczuk/go-chart/v2 v2.1.1 h1:2u7na789qiD5WzccZsFz4MJWOJP72G+2kUuJoSNqWnE=
github.com/wcharczuk/go-chart/v2 v2.1.1/go.mod h1:CyCAUt2oqvfhCl6Q5ZvAZwItgpQKZOkCJGb+VGv6l14= github.com/wcharczuk/go-chart/v2 v2.1.1/go.mod h1:CyCAUt2oqvfhCl6Q5ZvAZwItgpQKZOkCJGb+VGv6l14=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=

View File

@ -1,6 +1,7 @@
package host package host
import ( import (
"fmt"
"log" "log"
"strings" "strings"
@ -13,13 +14,19 @@ import (
func (h *Host) ChartMemory() string { func (h *Host) ChartMemory() string {
h.getNodeInfo() h.getNodeInfo()
log.Println("Generating Chart") log.Println("Generating Chart")
memFree := float64(h.NodeMemory.Free)
memCached := float64(h.NodeMemory.Cached)
memBuffer := float64(h.NodeMemory.Buffers)
memTotal := float64(h.NodeMemory.Total)
c := chart.PieChart{ c := chart.PieChart{
Width: 128, Title: fmt.Sprintf("Memory Info %s", h.SystemHostName),
Height: 128, Width: 256,
Height: 256,
Values: []chart.Value{ Values: []chart.Value{
{Value: float64(h.NodeMemory.Free) / float64(h.NodeMemory.Total), Label: "Free"}, {Value: memTotal - memFree, Label: fmt.Sprintf("%.2f%% Free", memFree/memTotal*100)},
{Value: float64(h.NodeMemory.Cached) / float64(h.NodeMemory.Total), Label: "Cached"}, {Value: memTotal - memCached, Label: fmt.Sprintf("%.2f%% Cached", memCached/memTotal*100)},
{Value: float64(h.NodeMemory.Buffers) / float64(h.NodeMemory.Total), Label: "Buffers"}, {Value: memTotal - memBuffer, Label: fmt.Sprintf("%.2f%% Buffers", memBuffer/memTotal*100)},
}, },
} }
sb := new(strings.Builder) sb := new(strings.Builder)

View File

@ -232,13 +232,13 @@ func (h *Host) getInfo() {
infoFuncs := []func(){ infoFuncs := []func(){
h.getDevicesInfo, h.getDevicesInfo,
h.getDomainInfo, // h.getDomainInfo,
h.getIfaceInfo, h.getIfaceInfo,
h.getNetsInfo, h.getNetsInfo,
h.getNodeInfo, h.getNodeInfo,
h.getSEVInfo, // h.getSEVInfo,
h.getSecretsInfo, // h.getSecretsInfo,
h.getStoragePools, // h.getStoragePools,
} }
for _, f := range infoFuncs { for _, f := range infoFuncs {

32
main.go
View File

@ -1,12 +1,14 @@
package main package main
import ( import (
"context"
"fmt"
"log" "log"
"net/http" "net/http"
"git.staur.ca/stobbsm/clustvirt/lib/host" "git.staur.ca/stobbsm/clustvirt/lib/host"
"git.staur.ca/stobbsm/clustvirt/view"
"git.staur.ca/stobbsm/clustvirt/view/components" "git.staur.ca/stobbsm/clustvirt/view/components"
"git.staur.ca/stobbsm/clustvirt/view/layouts"
"git.staur.ca/stobbsm/clustvirt/view/static" "git.staur.ca/stobbsm/clustvirt/view/static"
"github.com/a-h/templ" "github.com/a-h/templ"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@ -18,22 +20,11 @@ const DEBUG bool = true
func main() { func main() {
log.Println("Starting clustvirt, the libvirt cluster manager") log.Println("Starting clustvirt, the libvirt cluster manager")
venus, err := host.ConnectHost(host.URI_QEMU_SSH_SYSTEM, "venus.staur.ca")
if err != nil {
log.Fatal(err)
}
log.Println("Connected to host `venus.staur.ca`")
defer venus.Close()
//lm, err := venus.GetGuestByName("logan-minecraft")
//if err != nil {
// log.Fatal(err)
//}
//defer lm.Close()
// Start webserver and serve homepage // Start webserver and serve homepage
defaultNavBar := []components.NavItem{ defaultNavBar := []components.NavItem{
{Name: "Home", Href: "/"}, {Name: "Home", Href: "/"},
{Name: "Hosts", Href: "/hostinfo"},
{Name: "About", Href: "/about"}, {Name: "About", Href: "/about"},
} }
fs := http.StripPrefix("/static/", http.FileServer(http.Dir("public"))) fs := http.StripPrefix("/static/", http.FileServer(http.Dir("public")))
@ -47,9 +38,20 @@ func main() {
defer r.Body.Close() defer r.Body.Close()
fs.ServeHTTP(w, r) fs.ServeHTTP(w, r)
}) })
r.Get("/", templ.Handler(layouts.Manager("Cluster Manager", "ClustVirt", defaultNavBar)).ServeHTTP) r.Get("/", templ.Handler(view.HostMain(defaultNavBar)).ServeHTTP)
r.Get("/about", templ.Handler(static.Home()).ServeHTTP) r.Get("/about", templ.Handler(static.Home()).ServeHTTP)
r.Get("/chart", templ.Handler(components.HostInfo(venus)).ServeHTTP)
r.Route("/htmx", func(r chi.Router) {
r.Get("/host/{hostname}", func(w http.ResponseWriter, r *http.Request) {
rhost, err := host.ConnectHost(host.URI_QEMU_SSH_SYSTEM, chi.URLParam(r, "hostname"))
if err != nil {
http.Error(w, fmt.Sprintf("error while getting host: %s", err), http.StatusInternalServerError)
return
}
defer rhost.Close()
log.Println("Rendering HostInfo", view.HostInfo(rhost).Render(context.Background(), w))
})
})
log.Println(http.ListenAndServe(":3000", r)) log.Println(http.ListenAndServe(":3000", r))
} }

View File

@ -822,6 +822,14 @@ span>a:visited {
position: static; position: static;
} }
.absolute {
position: absolute;
}
.bottom-0 {
bottom: 0px;
}
.order-2 { .order-2 {
order: 2; order: 2;
} }
@ -830,6 +838,10 @@ span>a:visited {
order: 3; order: 3;
} }
.m-1 {
margin: 0.25rem;
}
.mx-4 { .mx-4 {
margin-left: 1rem; margin-left: 1rem;
margin-right: 1rem; margin-right: 1rem;
@ -857,6 +869,18 @@ span>a:visited {
height: 16rem; height: 16rem;
} }
.size-full {
width: 100%;
height: 100%;
}
.size-max {
width: -moz-max-content;
width: max-content;
height: -moz-max-content;
height: max-content;
}
.h-28 { .h-28 {
height: 7rem; height: 7rem;
} }
@ -869,6 +893,51 @@ span>a:visited {
height: 100%; height: 100%;
} }
.h-lvh {
height: 100lvh;
}
.h-svh {
height: 100svh;
}
.h-dvh {
height: 100dvh;
}
.h-max {
height: -moz-max-content;
height: max-content;
}
.h-48 {
height: 12rem;
}
.h-screen {
height: 100vh;
}
.min-h-80 {
min-height: 20rem;
}
.w-1\/4 {
width: 25%;
}
.w-3\/4 {
width: 75%;
}
.w-full {
width: 100%;
}
.w-1\/6 {
width: 16.666667%;
}
.flex-auto { .flex-auto {
flex: 1 1 auto; flex: 1 1 auto;
} }
@ -901,6 +970,10 @@ span>a:visited {
list-style-image: url("/static/icons/list-possible.svg"); list-style-image: url("/static/icons/list-possible.svg");
} }
.flex-row {
flex-direction: row;
}
.flex-col { .flex-col {
flex-direction: column; flex-direction: column;
} }
@ -917,6 +990,10 @@ span>a:visited {
align-items: center; align-items: center;
} }
.justify-end {
justify-content: flex-end;
}
.justify-between { .justify-between {
justify-content: space-between; justify-content: space-between;
} }
@ -8943,6 +9020,10 @@ span>a:visited {
border-color: rgb(51 51 30 / 0.95); border-color: rgb(51 51 30 / 0.95);
} }
.justify-self-end {
justify-self: end;
}
.rounded { .rounded {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
@ -8951,6 +9032,35 @@ span>a:visited {
border-radius: 9999px; border-radius: 9999px;
} }
.rounded-none {
border-radius: 0px;
}
.border-2 {
border-width: 2px;
}
.border {
border-width: 1px;
}
.border-solid {
border-style: solid;
}
.border-dashed {
border-style: dashed;
}
.border-dotted {
border-style: dotted;
}
.border-red-500 {
--tw-border-opacity: 1;
border-color: rgb(239 68 68 / var(--tw-border-opacity));
}
.border-uiblue-100 { .border-uiblue-100 {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(221 231 248 / var(--tw-border-opacity)); border-color: rgb(221 231 248 / var(--tw-border-opacity));
@ -138560,6 +138670,20 @@ span>a:visited {
padding: 0.5rem; padding: 0.5rem;
} }
.p-1 {
padding: 0.25rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.text-2xl { .text-2xl {
font-size: 1.5rem; font-size: 1.5rem;
line-height: 2rem; line-height: 2rem;

View File

@ -1,21 +0,0 @@
package components
import (
"fmt"
"git.staur.ca/stobbsm/clustvirt/lib/host"
)
// HostInfo is meant to be an HTMX response
templ HostInfo(h *host.Host) {
<body>
<div class={ "size-64" }>
@templ.Raw(h.ChartMemory())
</div>
<ul>
<li>Free: { fmt.Sprintf("%d MB", h.NodeMemory.Free / 1024) }</li>
<li>Cached: { fmt.Sprintf("%d MB", h.NodeMemory.Cached / 1024) }</li>
<li>Buffers: { fmt.Sprintf("%d MB", h.NodeMemory.Buffers / 1024) }</li>
<li>Total: { fmt.Sprintf("%d MB", h.NodeMemory.Total / 1024) }</li>
</ul>
</body>
}

View File

@ -1,118 +0,0 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.598
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import "context"
import "io"
import "bytes"
import (
"fmt"
"git.staur.ca/stobbsm/clustvirt/lib/host"
)
// HostInfo is meant to be an HTMX response
func HostInfo(h *host.Host) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 = []any{"size-64"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var2).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(h.ChartMemory()).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><ul><li>Free: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d MB", h.NodeMemory.Free/1024))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/components/hostinfo.templ`, Line: 14, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Cached: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d MB", h.NodeMemory.Cached/1024))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/components/hostinfo.templ`, Line: 15, Col: 65}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Buffers: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d MB", h.NodeMemory.Buffers/1024))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/components/hostinfo.templ`, Line: 16, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Total: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d MB", h.NodeMemory.Total/1024))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/components/hostinfo.templ`, Line: 17, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li></ul></body>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}

51
view/hostinfo.templ Normal file
View File

@ -0,0 +1,51 @@
package view
import (
"git.staur.ca/stobbsm/clustvirt/lib/host"
bf "github.com/labstack/gommon/bytes"
"git.staur.ca/stobbsm/clustvirt/view/components"
"git.staur.ca/stobbsm/clustvirt/view/layouts"
)
// MemChart get's the memory pi chart from the host
templ MemChart(h *host.Host) {
<div class={ "flex" , "flex-row" }>
<div class={ "size-64" }>
@templ.Raw(h.ChartMemory())
</div>
<ul>
<li>Free: { bf.Format(int64(h.NodeMemory.Free*1024)) }</li>
<li>Cached: { bf.Format(int64(h.NodeMemory.Cached*1024)) }</li>
<li>Buffers: { bf.Format(int64(h.NodeMemory.Buffers*1024)) }</li>
<li>Total: { bf.Format(int64(h.NodeMemory.Total*1024)) }</li>
</ul>
</div>
}
// HostConnect is the page that allows us to select a host to get information from
templ HostMain(navBarItems []components.NavItem) {
@layouts.Manager("ClustVirt", "Cluster Manager", navBarItems) {
<div class={ "flex" , "flex-row" , "h-full" }>
<div id="sysNavBar" class={ "w-1/6" , "border-uigrey-600" , "border" , "rounded" , "border-dotted" , "p-1" }>
<ul>
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/venus.staur.ca">venus.staur.ca</a></li>
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/earth.staur.ca">earth.staur.ca</a></li>
<li><a href="#" hx-target="#sysContent" hx-get="/htmx/host/mars.staur.ca">mars.staur.ca</a></li>
</ul>
</div>
<div id="sysContent" class={ "w-3/4" , "px-2" }>
<p>This is where you can see a system overview of all available hosts</p>
<p>
For now, there is just this simple box to choose a host to connect to
and push the button to load the system information via HTMX
</p>
</div>
</div>
}
}
// HostInfo is meant to be an HTMX response
templ HostInfo(h *host.Host) {
<h3>{ h.HostName }</h3>
@MemChart(h)
}

262
view/hostinfo_templ.go Normal file
View File

@ -0,0 +1,262 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.598
package view
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import "context"
import "io"
import "bytes"
import (
"git.staur.ca/stobbsm/clustvirt/lib/host"
"git.staur.ca/stobbsm/clustvirt/view/components"
"git.staur.ca/stobbsm/clustvirt/view/layouts"
bf "github.com/labstack/gommon/bytes"
)
// MemChart get's the memory pi chart from the host
func MemChart(h *host.Host) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{"flex", "flex-row"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var2).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 = []any{"size-64"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var3).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(h.ChartMemory()).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><ul><li>Free: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Free * 1024)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 16, Col: 55}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Cached: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Cached * 1024)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 17, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Buffers: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Buffers * 1024)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 18, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li><li>Total: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(bf.Format(int64(h.NodeMemory.Total * 1024)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 19, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</li></ul></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
// HostConnect is the page that allows us to select a host to get information from
func HostMain(navBarItems []components.NavItem) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var9 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
var templ_7745c5c3_Var10 = []any{"flex", "flex-row", "h-full"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var10).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 = []any{"w-1/6", "border-uigrey-600", "border", "rounded", "border-dotted", "p-1"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"sysNavBar\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var11).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><ul><li><a href=\"#\" hx-target=\"#sysContent\" hx-get=\"/htmx/host/venus.staur.ca\">venus.staur.ca</a></li><li><a href=\"#\" hx-target=\"#sysContent\" hx-get=\"/htmx/host/earth.staur.ca\">earth.staur.ca</a></li><li><a href=\"#\" hx-target=\"#sysContent\" hx-get=\"/htmx/host/mars.staur.ca\">mars.staur.ca</a></li></ul></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 = []any{"w-3/4", "px-2"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"sysContent\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var12).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><p>This is where you can see a system overview of all available hosts</p><p>For now, there is just this simple box to choose a host to connect to and push the button to load the system information via HTMX</p></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = layouts.Manager("ClustVirt", "Cluster Manager", navBarItems).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}
// HostInfo is meant to be an HTMX response
func HostInfo(h *host.Host) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
if !templ_7745c5c3_IsBuffer {
templ_7745c5c3_Buffer = templ.GetBuffer()
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var13 := templ.GetChildren(ctx)
if templ_7745c5c3_Var13 == nil {
templ_7745c5c3_Var13 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(h.HostName)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 48, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = MemChart(h).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
}
return templ_7745c5c3_Err
})
}

View File

@ -3,21 +3,27 @@ package layouts
import "git.staur.ca/stobbsm/clustvirt/view/components" import "git.staur.ca/stobbsm/clustvirt/view/components"
templ Manager(title string, subtitle string, navBarItem []components.NavItem) { templ Manager(title string, subtitle string, navBarItem []components.NavItem) {
<!DOCTYPE html> <!DOCTYPE html>
<html class={ "text-slate-50", "bg-slate-900" }> <html class={ "text-slate-50" , "bg-slate-900" }>
<head> <head>
<title>ClustVirt</title> <title>ClustVirt</title>
<link href="/static/css/style.css" type="text/css" rel="stylesheet" /> <link href="/static/css/style.css" type="text/css" rel="stylesheet"/>
</head> </head>
<body>
<body> <div class={ "flex" , "flex-col" , "h-screen" }>
<header class={"mx-4"}> <header class={ "px-4" }>
@header(title, subtitle, navBarItem) @header(title, subtitle, navBarItem)
</header> </header>
<main class={ "px-4" , "h-full" }>
<footer class={"mx-4"}> { children... }
@footer() </main>
</footer> <footer class={ "px-4" , "bottom-0", "w-full" , "justify-self-end" }>
</body> @footer()
</html> </footer>
</div>
<!-- Load HTMX -->
<script src=" https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous">
</script>
</body>
</html>
} }

View File

@ -46,16 +46,33 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var3 = []any{"mx-4"} var templ_7745c5c3_Var3 = []any{"flex", "flex-col", "h-screen"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...) templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var3).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 = []any{"px-4"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header class=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header class=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var3).String())) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var4).String()))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -71,8 +88,33 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var4 = []any{"mx-4"} var templ_7745c5c3_Var5 = []any{"px-4", "h-full"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...) templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<main class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var5).String()))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</main>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 = []any{"px-4", "bottom-0", "w-full", "justify-self-end"}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -80,7 +122,7 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var4).String())) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var6).String()))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -92,7 +134,7 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</footer></body></html>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</footer></div><!-- Load HTMX --><script src=\" https://unpkg.com/htmx.org@1.9.11\" integrity=\"sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0\" crossorigin=\"anonymous\">\n </script></body></html>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }