detached a3edf91

fix(history): tighten final sidebar review issues

commit
a3edf9178a83d500decb44ec790f575107206234
author
brice · · 2026-06-13 08:02 UTC
parent
0acad67
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +9 -7
M internal/ui/browser_window_history_sidebar.go +4 -0
@@ -146,6 +146,10 @@ func (a *App) toggleHistorySidebarAction(ctx context.Context) error {
146146 if bw.historySidebar == nil {
147147 return fmt.Errorf("history sidebar unavailable: native sidebar not initialized")
148148 }
149+ if bw.sidebarVisible {
150+ a.hideAndRestoreFocusForBrowserWindow(bw)
151+ return nil
152+ }
149153 bw.toggleHistorySidebar()
150154 return nil
151155 }
@@ -146,6 +146,10 @@ func (a *App) toggleHistorySidebarAction(ctx context.Context) error {
146 if bw.historySidebar == nil {146 if bw.historySidebar == nil {
147 return fmt.Errorf("history sidebar unavailable: native sidebar not initialized")147 return fmt.Errorf("history sidebar unavailable: native sidebar not initialized")
148 }148 }
149+ if bw.sidebarVisible {
150+ a.hideAndRestoreFocusForBrowserWindow(bw)
151+ return nil
152+ }
149 bw.toggleHistorySidebar()153 bw.toggleHistorySidebar()
150 return nil154 return nil
151 }155 }
M internal/ui/component/history_sidebar_keyboard.go +2 -2
@@ -196,7 +196,7 @@ func (hs *HistorySidebar) applyDeletedEntryLocked(url string, entryID int64, nex
196196 hs.loadGen++
197197 hs.isLoading = false
198198 hs.loadStarted = false
199- hs.removeFromAllEntries(url, entryID)
199+ hs.removeFromAllEntries(entryID)
200200 hs.totalLoaded = len(hs.allEntries)
201201 hs.removeFromSearchResults(entryID)
202202 hs.rebuildLocalGroups()
@@ -229,7 +229,7 @@ func (hs *HistorySidebar) rebuildLocalGroups() {
229229
230230 // removeFromAllEntries removes all history entries matching the given URL or ID
231231 // from hs.allEntries. Must be called with hs.mu write lock held.
232-func (hs *HistorySidebar) removeFromAllEntries(_ string, id int64) {
232+func (hs *HistorySidebar) removeFromAllEntries(id int64) {
233233 filtered := make([]*entity.HistoryEntry, 0, len(hs.allEntries))
234234 for _, e := range hs.allEntries {
235235 if e != nil && e.ID == id {
@@ -196,7 +196,7 @@ func (hs *HistorySidebar) applyDeletedEntryLocked(url string, entryID int64, nex
196 hs.loadGen++196 hs.loadGen++
197 hs.isLoading = false197 hs.isLoading = false
198 hs.loadStarted = false198 hs.loadStarted = false
199- hs.removeFromAllEntries(url, entryID)199+ hs.removeFromAllEntries(entryID)
200 hs.totalLoaded = len(hs.allEntries)200 hs.totalLoaded = len(hs.allEntries)
201 hs.removeFromSearchResults(entryID)201 hs.removeFromSearchResults(entryID)
202 hs.rebuildLocalGroups()202 hs.rebuildLocalGroups()
@@ -229,7 +229,7 @@ func (hs *HistorySidebar) rebuildLocalGroups() {
229 229
230 // removeFromAllEntries removes all history entries matching the given URL or ID230 // removeFromAllEntries removes all history entries matching the given URL or ID
231 // from hs.allEntries. Must be called with hs.mu write lock held.231 // from hs.allEntries. Must be called with hs.mu write lock held.
232-func (hs *HistorySidebar) removeFromAllEntries(_ string, id int64) {232+func (hs *HistorySidebar) removeFromAllEntries(id int64) {
233 filtered := make([]*entity.HistoryEntry, 0, len(hs.allEntries))233 filtered := make([]*entity.HistoryEntry, 0, len(hs.allEntries))
234 for _, e := range hs.allEntries {234 for _, e := range hs.allEntries {
235 if e != nil && e.ID == id {235 if e != nil && e.ID == id {
M internal/ui/component/history_sidebar_loading_search.go +1 -3
@@ -197,9 +197,7 @@ func (hs *HistorySidebar) restoreScrollAndSelection() {
197197 if hs.prevScrollValue > maxVal {
198198 hs.prevScrollValue = maxVal
199199 }
200- if hs.prevScrollValue >= 0 {
201- vadj.SetValue(hs.prevScrollValue)
202- }
200+ vadj.SetValue(hs.prevScrollValue)
203201 }
204202 }
205203
@@ -197,9 +197,7 @@ func (hs *HistorySidebar) restoreScrollAndSelection() {
197 if hs.prevScrollValue > maxVal {197 if hs.prevScrollValue > maxVal {
198 hs.prevScrollValue = maxVal198 hs.prevScrollValue = maxVal
199 }199 }
200- if hs.prevScrollValue >= 0 {200+ vadj.SetValue(hs.prevScrollValue)
201- vadj.SetValue(hs.prevScrollValue)
202- }
203 }201 }
204 }202 }
205 203
M internal/ui/component/history_sidebar_search_test.go +2 -2
@@ -3,6 +3,7 @@ package component
33 import (
44 "context"
55 "errors"
6+ "fmt"
67 "sync"
78 "testing"
89 "time"
@@ -168,8 +169,7 @@ func (f *fakeHistorySidebarHistory) GetRecent(ctx context.Context, limit, offset
168169 if f.getRecentFn != nil {
169170 return f.getRecentFn(ctx, limit, offset)
170171 }
171- <-make(chan struct{})
172- return nil, nil
172+ return nil, fmt.Errorf("unexpected GetRecent call in fakeHistorySidebarHistory")
173173 }
174174
175175 func (f *fakeHistorySidebarHistory) Search(ctx context.Context, input dto.HistorySearchInput) (*dto.HistorySearchOutput, error) {
@@ -3,6 +3,7 @@ package component
3 import (3 import (
4 "context"4 "context"
5 "errors"5 "errors"
6+ "fmt"
6 "sync"7 "sync"
7 "testing"8 "testing"
8 "time"9 "time"
@@ -168,8 +169,7 @@ func (f *fakeHistorySidebarHistory) GetRecent(ctx context.Context, limit, offset
168 if f.getRecentFn != nil {169 if f.getRecentFn != nil {
169 return f.getRecentFn(ctx, limit, offset)170 return f.getRecentFn(ctx, limit, offset)
170 }171 }
171- <-make(chan struct{})172+ return nil, fmt.Errorf("unexpected GetRecent call in fakeHistorySidebarHistory")
172- return nil, nil
173 }173 }
174 174
175 func (f *fakeHistorySidebarHistory) Search(ctx context.Context, input dto.HistorySearchInput) (*dto.HistorySearchOutput, error) {175 func (f *fakeHistorySidebarHistory) Search(ctx context.Context, input dto.HistorySearchInput) (*dto.HistorySearchOutput, error) {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close