hub: shared host_detail_body sub-template + customer Host tab (v0.47.0 part 3)
- host_detail_body.html: {{define}}'d body sections extracted from
host_detail.html; the standalone page is now chrome + the sub-template
- hosts.go: hostDetailData(host, r) view-model builder extracted from
handleHostDetail (reused by both surfaces)
- store: ListHostsByCustomer (host_id order; the Host tab is a list by
design - N hosts for a future HA cluster)
- customer Host tab renders one host_detail_body per host + cross-link;
empty state when no host is enrolled
- tests: TestTemplates_CustomerHostTab(+_Empty), TestListHostsByCustomer
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vvz1NCu22p8dGkRCpeX9re
This commit is contained in:
@@ -86,6 +86,33 @@ func TestGetHostByCustomer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// v0.47.0 Host tab: ListHostsByCustomer returns ONLY the customer's hosts, ordered by
|
||||
// host_id, and leaves other customers' hosts out (isolation).
|
||||
func TestListHostsByCustomer(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
for _, h := range []Host{
|
||||
{HostID: "c1-bbb", CustomerID: "c1", APIKey: "k2"},
|
||||
{HostID: "c1-aaa", CustomerID: "c1", APIKey: "k1"},
|
||||
{HostID: "c2-zzz", CustomerID: "c2", APIKey: "k3"},
|
||||
} {
|
||||
h := h
|
||||
if err := s.UpsertHost(&h); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
got, err := s.ListHostsByCustomer("c1")
|
||||
if err != nil {
|
||||
t.Fatalf("ListHostsByCustomer: %v", err)
|
||||
}
|
||||
if len(got) != 2 || got[0].HostID != "c1-aaa" || got[1].HostID != "c1-bbb" {
|
||||
t.Fatalf("c1 hosts = %+v (want [c1-aaa c1-bbb])", got)
|
||||
}
|
||||
none, err := s.ListHostsByCustomer("c3")
|
||||
if err != nil || len(none) != 0 {
|
||||
t.Fatalf("c3 hosts = %+v / %v (want empty)", none, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveHostReport_BumpsRealityPreservesIntent(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
if err := s.UpsertHost(&Host{HostID: "h1", CustomerID: "c1", APIKey: "k1"}); err != nil {
|
||||
|
||||
@@ -1597,6 +1597,27 @@ func (s *Store) GetHostByCustomer(customerID string) (*Host, error) {
|
||||
return h, err
|
||||
}
|
||||
|
||||
// ListHostsByCustomer returns the customer's hosts ordered by host_id (v0.47.0 — the
|
||||
// customer page's Host tab is a LIST by design: 1 host today, N for a later HA cluster).
|
||||
// Uses the idx_hosts_customer index.
|
||||
func (s *Store) ListHostsByCustomer(customerID string) ([]Host, error) {
|
||||
rows, err := s.db.Query(`SELECT `+hostSelectCols+
|
||||
` FROM hosts WHERE customer_id = ? ORDER BY host_id`, customerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var hosts []Host
|
||||
for rows.Next() {
|
||||
h, err := scanHost(rows.Scan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hosts = append(hosts, *h)
|
||||
}
|
||||
return hosts, rows.Err()
|
||||
}
|
||||
|
||||
// ListHosts returns all hosts (debug / host-domain views).
|
||||
func (s *Store) ListHosts() ([]Host, error) {
|
||||
rows, err := s.db.Query(`SELECT ` + hostSelectCols + ` FROM hosts ORDER BY host_id`)
|
||||
|
||||
Reference in New Issue
Block a user