Device and wall-socket views now highlight connected ports

Extracted shared _port_list.html partial with connected-port checking,
loaded into every page's template set. DeviceView and WallSocket handlers
now load connection data and pass it to the template. Removed duplicate
inline port_list definition from rack.html.
master
Joca 2026-06-09 18:52:32 -03:00
parent 3e20caa2d9
commit d9e7fb1ab1
Signed by: jocadbz
GPG Key ID: B1836DCE2F50BDF7
7 changed files with 81 additions and 69 deletions

View File

@ -9,8 +9,8 @@ import (
type DeviceViewData struct {
Device models.Device
Connections []models.Connection
ConnectionTypes []models.ConnectionType
AllPorts []models.DevicePort
Error string
}
@ -28,6 +28,7 @@ func (h *Handlers) DeviceView(w http.ResponseWriter, r *http.Request) {
return
}
conns := h.connectionsForDevice(device)
connTypes, _ := h.Store.ConnectionTypeGetAll()
if connTypes == nil {
connTypes = []models.ConnectionType{}
@ -35,10 +36,29 @@ func (h *Handlers) DeviceView(w http.ResponseWriter, r *http.Request) {
h.render(w, "device.html", DeviceViewData{
Device: *device,
Connections: conns,
ConnectionTypes: connTypes,
})
}
func (h *Handlers) connectionsForDevice(device *models.Device) []models.Connection {
if device == nil {
return []models.Connection{}
}
var allConns []models.Connection
for _, p := range device.Ports {
conn, err := h.Store.ConnectionGetByPortID(p.ID)
if err != nil || conn == nil {
continue
}
allConns = append(allConns, *conn)
}
if allConns == nil {
return []models.Connection{}
}
return allConns
}
func (h *Handlers) DeviceCreate(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
@ -135,6 +155,7 @@ func (h *Handlers) renderDeviceError(w http.ResponseWriter, device models.Device
}
h.render(w, "device.html", DeviceViewData{
Device: device,
Connections: h.connectionsForDevice(&device),
ConnectionTypes: connTypes,
Error: errMsg,
})

View File

@ -52,7 +52,10 @@ func New(store *db.Store) *Handlers {
baseFiles := []string{filepath.Join("templates", "base.html")}
for _, page := range pages {
files := append(baseFiles, filepath.Join("templates", page))
files := append(baseFiles,
filepath.Join("templates", page),
filepath.Join("templates", "_port_list.html"),
)
t, err := template.New("base.html").Funcs(funcMap).ParseFiles(files...)
if err != nil {
panic(fmt.Errorf("parse %s: %w", page, err))

View File

@ -8,9 +8,10 @@ import (
)
type WallSocketData struct {
Sockets []models.Device
Models []models.DeviceModel
Error string
Sockets []models.Device
Connections []models.Connection
Models []models.DeviceModel
Error string
}
func (h *Handlers) WallSockets(w http.ResponseWriter, r *http.Request) {
@ -30,9 +31,24 @@ func (h *Handlers) WallSockets(w http.ResponseWriter, r *http.Request) {
wallModels = []models.DeviceModel{}
}
var conns []models.Connection
for _, s := range sockets {
for _, p := range s.Ports {
conn, err := h.Store.ConnectionGetByPortID(p.ID)
if err != nil || conn == nil {
continue
}
conns = append(conns, *conn)
}
}
if conns == nil {
conns = []models.Connection{}
}
h.render(w, "wall_sockets.html", WallSocketData{
Sockets: sockets,
Models: wallModels,
Sockets: sockets,
Connections: conns,
Models: wallModels,
})
}

32
templates/_port_list.html Normal file
View File

@ -0,0 +1,32 @@
{{define "port_list"}}
<div class="ports">
<div class="port-column">
<h5>Front</h5>
{{range .Device.Ports}}{{if eq .Side "front"}}
{{$pid := .ID}}
<span class="port {{range $.Connections}}{{if and .Port1 .Port2}}{{if eq .Port1.ID $pid}}connected{{else if eq .Port2.ID $pid}}connected{{end}}{{end}}{{end}}"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"
onclick="openModal()"
title="{{.Name}}">
{{.Name}}
</span>
{{end}}{{end}}
</div>
<div class="port-column">
<h5>Back</h5>
{{range .Device.Ports}}{{if eq .Side "back"}}
{{$pid := .ID}}
<span class="port {{range $.Connections}}{{if and .Port1 .Port2}}{{if eq .Port1.ID $pid}}connected{{else if eq .Port2.ID $pid}}connected{{end}}{{end}}{{end}}"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"
onclick="openModal()"
title="{{.Name}}">
{{.Name}}
</span>
{{end}}{{end}}
</div>
</div>
{{end}}

View File

@ -35,32 +35,5 @@
</div>
<h3>Ports</h3>
<div class="ports">
<div class="port-column">
<h4>Front</h4>
{{range .Device.Ports}}{{if eq .Side "front"}}
<span class="port"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"
onclick="openModal()"
title="{{.Name}}">
{{.Name}}
</span>
{{end}}{{end}}
</div>
<div class="port-column">
<h4>Back</h4>
{{range .Device.Ports}}{{if eq .Side "back"}}
<span class="port"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"
onclick="openModal()"
title="{{.Name}}">
{{.Name}}
</span>
{{end}}{{end}}
</div>
</div>
{{template "port_list" .}}
{{end}}

View File

@ -113,36 +113,3 @@
</div>
</details>
{{end}}
{{define "port_list"}}
<div class="ports">
<div class="port-column">
<h5>Front</h5>
{{range .Device.Ports}}{{if eq .Side "front"}}
{{$pid := .ID}}
<span class="port {{range $.Connections}}{{if and .Port1 .Port2}}{{if eq .Port1.ID $pid}}connected{{else if eq .Port2.ID $pid}}connected{{end}}{{end}}{{end}}"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"
onclick="openModal()"
title="{{.Name}}">
{{.Name}}
</span>
{{end}}{{end}}
</div>
<div class="port-column">
<h5>Back</h5>
{{range .Device.Ports}}{{if eq .Side "back"}}
{{$pid := .ID}}
<span class="port {{range $.Connections}}{{if and .Port1 .Port2}}{{if eq .Port1.ID $pid}}connected{{else if eq .Port2.ID $pid}}connected{{end}}{{end}}{{end}}"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"
onclick="openModal()"
title="{{.Name}}">
{{.Name}}
</span>
{{end}}{{end}}
</div>
</div>
{{end}}

View File

@ -13,7 +13,7 @@
<td>{{.Comment}}</td>
<td>
{{range .Ports}}
<span class="port"
<span class="port {{$pid := .ID}}{{range $.Connections}}{{if and .Port1 .Port2}}{{if eq .Port1.ID $pid}}connected{{else if eq .Port2.ID $pid}}connected{{end}}{{end}}{{end}}"
hx-get="/connections/{{.ID}}"
hx-target="#modal-content"
hx-trigger="click"