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 { type DeviceViewData struct {
Device models.Device Device models.Device
Connections []models.Connection
ConnectionTypes []models.ConnectionType ConnectionTypes []models.ConnectionType
AllPorts []models.DevicePort
Error string Error string
} }
@ -28,6 +28,7 @@ func (h *Handlers) DeviceView(w http.ResponseWriter, r *http.Request) {
return return
} }
conns := h.connectionsForDevice(device)
connTypes, _ := h.Store.ConnectionTypeGetAll() connTypes, _ := h.Store.ConnectionTypeGetAll()
if connTypes == nil { if connTypes == nil {
connTypes = []models.ConnectionType{} connTypes = []models.ConnectionType{}
@ -35,10 +36,29 @@ func (h *Handlers) DeviceView(w http.ResponseWriter, r *http.Request) {
h.render(w, "device.html", DeviceViewData{ h.render(w, "device.html", DeviceViewData{
Device: *device, Device: *device,
Connections: conns,
ConnectionTypes: connTypes, 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) { func (h *Handlers) DeviceCreate(w http.ResponseWriter, r *http.Request) {
r.ParseForm() r.ParseForm()
@ -135,6 +155,7 @@ func (h *Handlers) renderDeviceError(w http.ResponseWriter, device models.Device
} }
h.render(w, "device.html", DeviceViewData{ h.render(w, "device.html", DeviceViewData{
Device: device, Device: device,
Connections: h.connectionsForDevice(&device),
ConnectionTypes: connTypes, ConnectionTypes: connTypes,
Error: errMsg, Error: errMsg,
}) })

View File

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

View File

@ -8,9 +8,10 @@ import (
) )
type WallSocketData struct { type WallSocketData struct {
Sockets []models.Device Sockets []models.Device
Models []models.DeviceModel Connections []models.Connection
Error string Models []models.DeviceModel
Error string
} }
func (h *Handlers) WallSockets(w http.ResponseWriter, r *http.Request) { 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{} 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{ h.render(w, "wall_sockets.html", WallSocketData{
Sockets: sockets, Sockets: sockets,
Models: wallModels, 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> </div>
<h3>Ports</h3> <h3>Ports</h3>
<div class="ports"> {{template "port_list" .}}
<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>
{{end}} {{end}}

View File

@ -113,36 +113,3 @@
</div> </div>
</details> </details>
{{end}} {{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>{{.Comment}}</td>
<td> <td>
{{range .Ports}} {{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-get="/connections/{{.ID}}"
hx-target="#modal-content" hx-target="#modal-content"
hx-trigger="click" hx-trigger="click"