From 2f97ee3d77120293bcc59b65817e7a459de40ddc Mon Sep 17 00:00:00 2001 From: habakan Date: Sat, 5 Sep 2026 09:45:29 +0900 Subject: [PATCH] Fix nvpair-tui panic when a table view seeds rows before its first resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every table-backed view built its table.Model via newTable(nil) and only set real columns inside SetSize (called on the first tea.WindowSizeMsg). Each view's Init() fires an RPC call at the same time, and if that reply arrives first — which happens reliably whenever the broker already holds one stored item at startup — SetRows runs on a zero-column table and bubbles/table.renderRow panics, killing the TUI. Seed real columns at construction time instead of nil, so SetRows never sees zero columns regardless of ordering. Bump nvpair-tui 0.7.2 -> 0.7.3 (PATCH) and product/installer 0.91.7 -> 0.91.8 accordingly. Signed-off-by: habakan --- services/nvpair-tui/ui/cluster.go | 4 ++++ services/nvpair-tui/ui/engines.go | 4 ++++ services/nvpair-tui/ui/errors.go | 6 +++++- services/nvpair-tui/ui/manualnodes.go | 4 ++++ services/nvpair-tui/ui/nodes.go | 4 ++++ services/nvpair-tui/ui/proxies.go | 4 ++++ services/nvpair-tui/ui/workloads.go | 4 ++++ services/versions.json | 6 +++--- 8 files changed, 32 insertions(+), 4 deletions(-) diff --git a/services/nvpair-tui/ui/cluster.go b/services/nvpair-tui/ui/cluster.go index ac334edf..9ed61f98 100644 --- a/services/nvpair-tui/ui/cluster.go +++ b/services/nvpair-tui/ui/cluster.go @@ -99,6 +99,10 @@ func newClusterView(client *rpc.Client) *clusterView { ti := textinput.New() v := &clusterView{client: client, input: ti} v.table = newTable(nil) + // Seed real columns before any RPC result can reach the table: a + // zero-column table panics (index out of range) in table.SetRows if + // data arrives before the first tea.WindowSizeMsg calls SetSize. + v.SetSize(0, 0) return v } diff --git a/services/nvpair-tui/ui/engines.go b/services/nvpair-tui/ui/engines.go index 809febfb..a9f17713 100644 --- a/services/nvpair-tui/ui/engines.go +++ b/services/nvpair-tui/ui/engines.go @@ -72,6 +72,10 @@ func newEnginesView(client *rpc.Client) *enginesView { ti.Placeholder = "model name (e.g. llama3.2)" v := &enginesView{client: client, byName: map[string]engineStatus{}, input: ti} v.table = newTable(nil) + // Seed real columns before any RPC result can reach the table: a + // zero-column table panics (index out of range) in table.SetRows if + // data arrives before the first tea.WindowSizeMsg calls SetSize. + v.SetSize(0, 0) return v } diff --git a/services/nvpair-tui/ui/errors.go b/services/nvpair-tui/ui/errors.go index 17e93e0e..51137bb6 100644 --- a/services/nvpair-tui/ui/errors.go +++ b/services/nvpair-tui/ui/errors.go @@ -47,7 +47,11 @@ var clearKey = key.NewBinding( func newErrorsView(client *rpc.Client) *errorsView { v := &errorsView{client: client} - v.table = newTable(nil) + // Seed real columns up front (not nil): errors:get-initial can return + // before the first tea.WindowSizeMsg reaches SetSize, and setErrors -> + // table.SetRows on a zero-column table panics (index out of range) as + // soon as the broker already has >=1 stored error at startup. + v.table = newTable(v.columns()) return v } diff --git a/services/nvpair-tui/ui/manualnodes.go b/services/nvpair-tui/ui/manualnodes.go index fa316806..63959aad 100644 --- a/services/nvpair-tui/ui/manualnodes.go +++ b/services/nvpair-tui/ui/manualnodes.go @@ -67,6 +67,10 @@ func newManualView(client *rpc.Client) *manualView { ti.Placeholder = "host" v := &manualView{client: client, input: ti} v.table = newTable(nil) + // Seed real columns before any RPC result can reach the table: a + // zero-column table panics (index out of range) in table.SetRows if + // data arrives before the first tea.WindowSizeMsg calls SetSize. + v.SetSize(0, 0) return v } diff --git a/services/nvpair-tui/ui/nodes.go b/services/nvpair-tui/ui/nodes.go index 8c8db2e7..af017310 100644 --- a/services/nvpair-tui/ui/nodes.go +++ b/services/nvpair-tui/ui/nodes.go @@ -69,6 +69,10 @@ var niInviteKey = key.NewBinding(key.WithKeys("i"), key.WithHelp("i", "invite to func newNodesView(client *rpc.Client) *nodesView { v := &nodesView{client: client} v.table = newTable(nil) + // Seed real columns before any RPC result can reach setNodes: a + // zero-column table panics (index out of range) in table.SetRows if + // data arrives before the first tea.WindowSizeMsg calls SetSize. + v.SetSize(0, 0) return v } diff --git a/services/nvpair-tui/ui/proxies.go b/services/nvpair-tui/ui/proxies.go index 072c1a8b..392744c5 100644 --- a/services/nvpair-tui/ui/proxies.go +++ b/services/nvpair-tui/ui/proxies.go @@ -94,6 +94,10 @@ func newProxiesView(client *rpc.Client) *proxiesView { {label: "LM Studio", prefix: "lmstudio-proxy", table: newTable(nil)}, }, } + // Seed real columns before any RPC result can reach these tables: a + // zero-column table panics (index out of range) in table.SetRows if + // data arrives before the first tea.WindowSizeMsg calls SetSize. + v.SetSize(0, 0) return v } diff --git a/services/nvpair-tui/ui/workloads.go b/services/nvpair-tui/ui/workloads.go index ea7931df..8b5f1650 100644 --- a/services/nvpair-tui/ui/workloads.go +++ b/services/nvpair-tui/ui/workloads.go @@ -41,6 +41,10 @@ type workloadsSubscribedMsg struct{ err error } func newWorkloadsView(client *rpc.Client) *workloadsView { v := &workloadsView{client: client, byKey: map[string]workload{}} v.table = newTable(nil) + // Seed real columns before any RPC result can reach the table: a + // zero-column table panics (index out of range) in table.SetRows if + // data arrives before the first tea.WindowSizeMsg calls SetSize. + v.SetSize(0, 0) return v } diff --git a/services/versions.json b/services/versions.json index 29d8c230..cc1375d9 100644 --- a/services/versions.json +++ b/services/versions.json @@ -1,7 +1,7 @@ { "$comment": "Single source of truth for all version numbers. See VERSIONING.md for bump rules.", - "product": "0.91.7", - "installer": "0.91.7", + "product": "0.91.8", + "installer": "0.91.8", "components": { "ollama-proxy": "0.26.2", "lmstudio-proxy": "0.16.2", @@ -15,6 +15,6 @@ "nvpair-engine-manager": "0.17.4", "nvpair-cluster-manager": "1.1.4", "nvpair-job-scheduler": "0.4.1", - "nvpair-tui": "0.7.2" + "nvpair-tui": "0.7.3" } }