Fix hidden root section restore

This commit is contained in:
Joe Julian
2026-03-30 09:24:41 -07:00
parent b7a4742ee6
commit 2db8a71704
2 changed files with 253 additions and 189 deletions
+43 -8
View File
@@ -26,8 +26,8 @@ import (
"gioui.org/widget" "gioui.org/widget"
"gioui.org/widget/material" "gioui.org/widget/material"
"git.julianfamily.org/keepassgo/api" "git.julianfamily.org/keepassgo/api"
"git.julianfamily.org/keepassgo/apiaudit"
"git.julianfamily.org/keepassgo/apiapproval" "git.julianfamily.org/keepassgo/apiapproval"
"git.julianfamily.org/keepassgo/apiaudit"
"git.julianfamily.org/keepassgo/apitokens" "git.julianfamily.org/keepassgo/apitokens"
"git.julianfamily.org/keepassgo/appstate" "git.julianfamily.org/keepassgo/appstate"
"git.julianfamily.org/keepassgo/clipboard" "git.julianfamily.org/keepassgo/clipboard"
@@ -156,6 +156,7 @@ type ui struct {
attachmentPath widget.Editor attachmentPath widget.Editor
exportAttachmentPath widget.Editor exportAttachmentPath widget.Editor
list widget.List list widget.List
groupList widget.List
detailList widget.List detailList widget.List
lifecycleList widget.List lifecycleList widget.List
copyUser widget.Clickable copyUser widget.Clickable
@@ -375,6 +376,9 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
list: widget.List{ list: widget.List{
List: layout.List{Axis: layout.Vertical}, List: layout.List{Axis: layout.Vertical},
}, },
groupList: widget.List{
List: layout.List{Axis: layout.Vertical},
},
detailList: widget.List{ detailList: widget.List{
List: layout.List{Axis: layout.Vertical}, List: layout.List{Axis: layout.Vertical},
}, },
@@ -508,7 +512,9 @@ func (u *ui) selectedAttachmentNames() []string {
func (u *ui) showEntriesSection() { func (u *ui) showEntriesSection() {
u.resetPasswordPeek() u.resetPasswordPeek()
preservedPath := append([]string(nil), u.currentPath...)
u.state.ShowSection(appstate.SectionEntries) u.state.ShowSection(appstate.SectionEntries)
u.restoreEntriesPath(preservedPath)
u.filter() u.filter()
} }
@@ -1213,6 +1219,28 @@ func (u *ui) restoreRecentRemoteGroup(baseURL, path string) {
u.enterHiddenVaultRoot() u.enterHiddenVaultRoot()
} }
func (u *ui) restoreEntriesPath(path []string) {
if len(path) == 0 {
u.enterHiddenVaultRoot()
return
}
model, err := u.state.Session.Current()
if err != nil {
u.enterHiddenVaultRoot()
return
}
root := u.hiddenVaultRoot()
if len(path) == 1 && root != "" && path[0] == root {
u.setCurrentPath(path)
return
}
if len(model.EntriesInPath(path)) > 0 || len(model.ChildGroups(path)) > 0 || hasExactGroup(model, path) {
u.setCurrentPath(path)
return
}
u.enterHiddenVaultRoot()
}
func (u *ui) displayPath() []string { func (u *ui) displayPath() []string {
path := append([]string(nil), u.currentPath...) path := append([]string(nil), u.currentPath...)
root := u.hiddenVaultRoot() root := u.hiddenVaultRoot()
@@ -3033,21 +3061,28 @@ func (u *ui) groupBar(gtx layout.Context) layout.Dimensions {
}), }),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
} }
for i, group := range groups {
idx := i
name := group
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions { children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
const maxGroupListHeight = 160
maxY := gtx.Dp(unit.Dp(maxGroupListHeight))
if gtx.Constraints.Max.Y > maxY {
gtx.Constraints.Max.Y = maxY
}
if gtx.Constraints.Min.Y > gtx.Constraints.Max.Y {
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
}
return material.List(u.theme, &u.groupList).Layout(gtx, len(groups), func(gtx layout.Context, i int) layout.Dimensions {
idx := i
name := groups[i]
return layout.Inset{Bottom: unit.Dp(6)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
for u.groupClicks[idx].Clicked(gtx) { for u.groupClicks[idx].Clicked(gtx) {
u.state.EnterGroup(name) u.state.EnterGroup(name)
u.currentPath = append([]string(nil), u.state.CurrentPath...) u.currentPath = append([]string(nil), u.state.CurrentPath...)
u.filter() u.filter()
} }
return tonedButton(gtx, u.theme, &u.groupClicks[idx], name) return tonedButton(gtx, u.theme, &u.groupClicks[idx], name)
})
})
})) }))
if i < len(groups)-1 {
children = append(children, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout))
}
}
return children return children
}()...) }()...)
} }
+29
View File
@@ -2198,6 +2198,35 @@ func TestUIAutoEntersSingleVaultRootGroupAndDisplaysSlashRoot(t *testing.T) {
} }
} }
func TestUIShowEntriesSectionRestoresHiddenRootAfterLeavingEntries(t *testing.T) {
t.Parallel()
u := newUIWithModel("desktop", vault.Model{
Entries: []vault.Entry{
{ID: "1", Title: "Git Server", Path: []string{"keepass", "Joe", "Internet"}},
{ID: "2", Title: "Home Assistant", Path: []string{"keepass", "Joe", "Home"}},
},
})
u.showEntriesSection()
if got := u.currentPath; !slices.Equal(got, []string{"keepass"}) {
t.Fatalf("currentPath after initial entries section = %v, want [keepass]", got)
}
u.showAPITokensSection()
u.showEntriesSection()
if got := u.currentPath; !slices.Equal(got, []string{"keepass"}) {
t.Fatalf("currentPath after returning to entries = %v, want [keepass]", got)
}
if got := u.displayPath(); len(got) != 0 {
t.Fatalf("displayPath() after returning to entries = %v, want root slash path", got)
}
if got := u.childGroups(); !slices.Equal(got, []string{"Joe"}) {
t.Fatalf("childGroups() after returning to entries = %v, want [Joe]", got)
}
}
func TestUINoteRecentVaultDeduplicatesAndOrdersMostRecentFirst(t *testing.T) { func TestUINoteRecentVaultDeduplicatesAndOrdersMostRecentFirst(t *testing.T) {
t.Parallel() t.Parallel()