Fix API token detail panel panic

This commit is contained in:
Joe Julian
2026-03-30 14:46:07 -07:00
parent 20f84ac58e
commit f9b58367da
2 changed files with 61 additions and 8 deletions
+40
View File
@@ -3,6 +3,7 @@ package main
import (
"bytes"
"errors"
"image"
"io"
"net/http"
"net/http/httptest"
@@ -15,6 +16,7 @@ import (
"gioui.org/io/key"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/unit"
"gioui.org/widget"
@@ -237,6 +239,44 @@ func TestUIAPITokenPolicyRulesCanBeAddedAndRemoved(t *testing.T) {
}
}
func TestUIAPITokenDetailPanelHandlesMissingRemoveClickables(t *testing.T) {
t.Parallel()
u := newUIWithSession("desktop", &session.Manager{})
u.masterPassword.SetText("correct horse battery staple")
if err := u.createVaultAction(); err != nil {
t.Fatalf("createVaultAction() error = %v", err)
}
u.showAPITokensSection()
u.apiTokenName.SetText("CLI")
u.apiTokenClientName.SetText("grpc-cli")
if err := u.issueAPITokenAction(); err != nil {
t.Fatalf("issueAPITokenAction() error = %v", err)
}
u.apiPolicyOperation.SetText(string(apitokens.OperationListEntries))
u.apiPolicyPath.SetText("Joe / codex")
u.apiPolicyAllow.Value = true
u.apiPolicyGroupScopeW.Value = true
if err := u.addAPIPolicyRuleAction(); err != nil {
t.Fatalf("addAPIPolicyRuleAction() error = %v", err)
}
u.apiPolicyRemoves = nil
ops := new(op.Ops)
gtx := layout.Context{
Ops: ops,
Constraints: layout.Exact(image.Pt(800, 600)),
}
defer func() {
if r := recover(); r != nil {
t.Fatalf("apiTokenDetailPanel() panicked: %v", r)
}
}()
_ = u.apiTokenDetailPanel(gtx)
}
func TestUIAPIAuditSectionShowsRecordedEvents(t *testing.T) {
t.Parallel()
+21 -8
View File
@@ -80,9 +80,9 @@ func (u *ui) loadSelectedAPITokenIntoEditor() {
u.apiPolicyOperation.SetText(string(apitokens.OperationListEntries))
u.apiPolicyPath.SetText(strings.Join(u.displayPath(), " / "))
u.apiPolicyEntryID.SetText("")
u.apiPolicyAllow.Value = true
u.apiPolicyGroupScope = true
u.apiPolicyGroupScopeW.Value = true
u.apiPolicyAllow.Value = true
u.apiPolicyGroupScope = true
u.apiPolicyGroupScopeW.Value = true
u.apiPolicyRemoves = nil
return
}
@@ -444,6 +444,9 @@ func (u *ui) apiAuditListPanel(gtx layout.Context) layout.Dimensions {
func (u *ui) apiTokenDetailPanel(gtx layout.Context) layout.Dimensions {
token, ok := u.selectedAPIToken()
if ok && len(u.apiPolicyRemoves) < len(token.Policies) {
u.apiPolicyRemoves = make([]widget.Clickable, len(token.Policies))
}
rows := []layout.Widget{
func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(20), "API Token")
@@ -505,15 +508,25 @@ func (u *ui) apiTokenDetailPanel(gtx layout.Context) layout.Dimensions {
layout.Spacer{Height: unit.Dp(10)}.Layout,
func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.saveAPIToken, "Save Token") }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.saveAPIToken, "Save Token")
}),
layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.rotateAPIToken, "Rotate") }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.rotateAPIToken, "Rotate")
}),
layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.disableAPIToken, "Disable") }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.disableAPIToken, "Disable")
}),
layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.revokeAPIToken, "Revoke") }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.revokeAPIToken, "Revoke")
}),
layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.deleteAPIToken, "Delete") }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.deleteAPIToken, "Delete")
}),
)
},
layout.Spacer{Height: unit.Dp(14)}.Layout,