detached a8b7d7d

fix(systemviews): satisfy lint checks

commit
a8b7d7defd2c87cef9a4279b9aef1feaaf85b3df
author
brice · · 2026-04-11 19:23 UTC
committer
brice · · 2026-04-12 04:52 UTC
parent
a021447
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
6 files · +97 -93
M internal/infrastructure/systemviewsbridge/client_test.go +2 -2
@@ -236,8 +236,8 @@ func TestClientCurrentAndDefaultDecodeConfigPayload(t *testing.T) {
236236 }
237237
238238 var msg port.WebUIMessage
239- if err := json.Unmarshal(currentClient.native.(*fakeTransport).last, &msg); err != nil {
240- t.Fatalf("unmarshal sent envelope: %v", err)
239+ if unmarshalErr := json.Unmarshal(currentClient.native.(*fakeTransport).last, &msg); unmarshalErr != nil {
240+ t.Fatalf("unmarshal sent envelope: %v", unmarshalErr)
241241 }
242242 if msg.Type != "/api/config" {
243243 t.Fatalf("sent type = %q, want %q", msg.Type, "/api/config")
@@ -236,8 +236,8 @@ func TestClientCurrentAndDefaultDecodeConfigPayload(t *testing.T) {
236 }236 }
237 237
238 var msg port.WebUIMessage238 var msg port.WebUIMessage
239- if err := json.Unmarshal(currentClient.native.(*fakeTransport).last, &msg); err != nil {239+ if unmarshalErr := json.Unmarshal(currentClient.native.(*fakeTransport).last, &msg); unmarshalErr != nil {
240- t.Fatalf("unmarshal sent envelope: %v", err)240+ t.Fatalf("unmarshal sent envelope: %v", unmarshalErr)
241 }241 }
242 if msg.Type != "/api/config" {242 if msg.Type != "/api/config" {
243 t.Fatalf("sent type = %q, want %q", msg.Type, "/api/config")243 t.Fatalf("sent type = %q, want %q", msg.Type, "/api/config")
M internal/ui/systemviews/app.go +88 -81
@@ -28,6 +28,8 @@ type App struct {
2828 renderedHTML string
2929 }
3030
31+const historyTimelineLimit = 25
32+
3133 func NewApp(deps Dependencies) *App {
3234 return &App{deps: deps, currentRoute: RouteUnknown}
3335 }
@@ -58,93 +60,98 @@ func (a *App) LoadInitial(ctx context.Context) error {
5860
5961 switch a.currentRoute {
6062 case RouteHistory:
61- if a.deps.History == nil {
62- a.historyEntries = nil
63- a.favorites = nil
64- a.folders = nil
65- a.tags = nil
66- a.renderedHTML = placeholderHTML(a.currentRoute)
67- return nil
68- }
69-
70- entries, err := a.deps.History.Timeline(ctx, 25, 0)
71- if err != nil {
72- return err
73- }
74- a.favorites = nil
75- a.folders = nil
76- a.tags = nil
77- a.historyEntries = entries
78- a.renderedHTML = historyHTML(entries)
79- return nil
63+ return a.loadHistoryRoute(ctx)
8064 case RouteFavorites:
81- if a.deps.Favorites == nil {
82- a.historyEntries = nil
83- a.favorites = nil
84- a.folders = nil
85- a.tags = nil
86- a.renderedHTML = placeholderHTML(a.currentRoute)
87- return nil
88- }
89-
90- favorites, err := a.deps.Favorites.List(ctx)
91- if err != nil {
92- return err
93- }
94- folders, err := a.deps.Favorites.ListFolders(ctx)
95- if err != nil {
96- return err
97- }
98- tags, err := a.deps.Favorites.ListTags(ctx)
99- if err != nil {
100- return err
101- }
102-
103- a.historyEntries = nil
104- a.favorites = favorites
105- a.folders = folders
106- a.tags = tags
107- a.renderedHTML = favoritesHTML(favorites, folders, tags)
108- return nil
65+ return a.loadFavoritesRoute(ctx)
10966 case RouteConfig:
110- if a.deps.Config == nil {
111- a.historyEntries = nil
112- a.favorites = nil
113- a.folders = nil
114- a.tags = nil
115- a.config = nil
116- a.keybindings = nil
117- a.renderedHTML = placeholderHTML(a.currentRoute)
118- return nil
119- }
120-
121- config, err := a.deps.Config.Current(ctx)
122- if err != nil {
123- return err
124- }
125- keybindings, err := a.deps.Config.GetKeybindings(ctx)
126- if err != nil {
127- return err
128- }
129-
130- a.historyEntries = nil
131- a.favorites = nil
132- a.folders = nil
133- a.tags = nil
134- a.config = &config
135- a.keybindings = keybindings
136- a.renderedHTML = configHTML(config, keybindings)
137- return nil
67+ return a.loadConfigRoute(ctx)
13868 default:
139- a.historyEntries = nil
140- a.favorites = nil
141- a.folders = nil
142- a.tags = nil
143- a.config = nil
144- a.keybindings = nil
69+ a.resetRouteState()
70+ a.renderedHTML = placeholderHTML(a.currentRoute)
71+ return nil
72+ }
73+}
74+
75+func (a *App) loadHistoryRoute(ctx context.Context) error {
76+ if a.deps.History == nil {
77+ a.resetRouteState()
78+ a.renderedHTML = placeholderHTML(a.currentRoute)
79+ return nil
80+ }
81+
82+ entries, err := a.deps.History.Timeline(ctx, historyTimelineLimit, 0)
83+ if err != nil {
84+ return err
85+ }
86+ a.favorites = nil
87+ a.folders = nil
88+ a.tags = nil
89+ a.historyEntries = entries
90+ a.renderedHTML = historyHTML(entries)
91+ return nil
92+}
93+
94+func (a *App) loadFavoritesRoute(ctx context.Context) error {
95+ if a.deps.Favorites == nil {
96+ a.resetRouteState()
97+ a.renderedHTML = placeholderHTML(a.currentRoute)
98+ return nil
99+ }
100+
101+ favorites, err := a.deps.Favorites.List(ctx)
102+ if err != nil {
103+ return err
104+ }
105+ folders, err := a.deps.Favorites.ListFolders(ctx)
106+ if err != nil {
107+ return err
108+ }
109+ tags, err := a.deps.Favorites.ListTags(ctx)
110+ if err != nil {
111+ return err
112+ }
113+
114+ a.historyEntries = nil
115+ a.favorites = favorites
116+ a.folders = folders
117+ a.tags = tags
118+ a.renderedHTML = favoritesHTML(favorites, folders, tags)
119+ return nil
120+}
121+
122+func (a *App) loadConfigRoute(ctx context.Context) error {
123+ if a.deps.Config == nil {
124+ a.resetRouteState()
145125 a.renderedHTML = placeholderHTML(a.currentRoute)
146126 return nil
147127 }
128+
129+ config, err := a.deps.Config.Current(ctx)
130+ if err != nil {
131+ return err
132+ }
133+ keybindings, err := a.deps.Config.GetKeybindings(ctx)
134+ if err != nil {
135+ return err
136+ }
137+
138+ a.historyEntries = nil
139+ a.favorites = nil
140+ a.folders = nil
141+ a.tags = nil
142+ a.config = &config
143+ a.keybindings = keybindings
144+ a.renderedHTML = configHTML(config, keybindings)
145+ return nil
146+}
147+
148+func (a *App) resetRouteState() {
149+ a.historyEntries = nil
150+ a.favorites = nil
151+ a.folders = nil
152+ a.tags = nil
153+ a.config = nil
154+ a.keybindings = nil
148155 }
149156
150157 func (a *App) CurrentRoute() Route {
@@ -28,6 +28,8 @@ type App struct {
28 renderedHTML string28 renderedHTML string
29 }29 }
30 30
31+const historyTimelineLimit = 25
32+
31 func NewApp(deps Dependencies) *App {33 func NewApp(deps Dependencies) *App {
32 return &App{deps: deps, currentRoute: RouteUnknown}34 return &App{deps: deps, currentRoute: RouteUnknown}
33 }35 }
@@ -58,93 +60,98 @@ func (a *App) LoadInitial(ctx context.Context) error {
58 60
59 switch a.currentRoute {61 switch a.currentRoute {
60 case RouteHistory:62 case RouteHistory:
61- if a.deps.History == nil {63+ return a.loadHistoryRoute(ctx)
62- a.historyEntries = nil
63- a.favorites = nil
64- a.folders = nil
65- a.tags = nil
66- a.renderedHTML = placeholderHTML(a.currentRoute)
67- return nil
68- }
69-
70- entries, err := a.deps.History.Timeline(ctx, 25, 0)
71- if err != nil {
72- return err
73- }
74- a.favorites = nil
75- a.folders = nil
76- a.tags = nil
77- a.historyEntries = entries
78- a.renderedHTML = historyHTML(entries)
79- return nil
80 case RouteFavorites:64 case RouteFavorites:
81- if a.deps.Favorites == nil {65+ return a.loadFavoritesRoute(ctx)
82- a.historyEntries = nil
83- a.favorites = nil
84- a.folders = nil
85- a.tags = nil
86- a.renderedHTML = placeholderHTML(a.currentRoute)
87- return nil
88- }
89-
90- favorites, err := a.deps.Favorites.List(ctx)
91- if err != nil {
92- return err
93- }
94- folders, err := a.deps.Favorites.ListFolders(ctx)
95- if err != nil {
96- return err
97- }
98- tags, err := a.deps.Favorites.ListTags(ctx)
99- if err != nil {
100- return err
101- }
102-
103- a.historyEntries = nil
104- a.favorites = favorites
105- a.folders = folders
106- a.tags = tags
107- a.renderedHTML = favoritesHTML(favorites, folders, tags)
108- return nil
109 case RouteConfig:66 case RouteConfig:
110- if a.deps.Config == nil {67+ return a.loadConfigRoute(ctx)
111- a.historyEntries = nil
112- a.favorites = nil
113- a.folders = nil
114- a.tags = nil
115- a.config = nil
116- a.keybindings = nil
117- a.renderedHTML = placeholderHTML(a.currentRoute)
118- return nil
119- }
120-
121- config, err := a.deps.Config.Current(ctx)
122- if err != nil {
123- return err
124- }
125- keybindings, err := a.deps.Config.GetKeybindings(ctx)
126- if err != nil {
127- return err
128- }
129-
130- a.historyEntries = nil
131- a.favorites = nil
132- a.folders = nil
133- a.tags = nil
134- a.config = &config
135- a.keybindings = keybindings
136- a.renderedHTML = configHTML(config, keybindings)
137- return nil
138 default:68 default:
139- a.historyEntries = nil69+ a.resetRouteState()
140- a.favorites = nil70+ a.renderedHTML = placeholderHTML(a.currentRoute)
141- a.folders = nil71+ return nil
142- a.tags = nil72+ }
143- a.config = nil73+}
144- a.keybindings = nil74+
75+func (a *App) loadHistoryRoute(ctx context.Context) error {
76+ if a.deps.History == nil {
77+ a.resetRouteState()
78+ a.renderedHTML = placeholderHTML(a.currentRoute)
79+ return nil
80+ }
81+
82+ entries, err := a.deps.History.Timeline(ctx, historyTimelineLimit, 0)
83+ if err != nil {
84+ return err
85+ }
86+ a.favorites = nil
87+ a.folders = nil
88+ a.tags = nil
89+ a.historyEntries = entries
90+ a.renderedHTML = historyHTML(entries)
91+ return nil
92+}
93+
94+func (a *App) loadFavoritesRoute(ctx context.Context) error {
95+ if a.deps.Favorites == nil {
96+ a.resetRouteState()
97+ a.renderedHTML = placeholderHTML(a.currentRoute)
98+ return nil
99+ }
100+
101+ favorites, err := a.deps.Favorites.List(ctx)
102+ if err != nil {
103+ return err
104+ }
105+ folders, err := a.deps.Favorites.ListFolders(ctx)
106+ if err != nil {
107+ return err
108+ }
109+ tags, err := a.deps.Favorites.ListTags(ctx)
110+ if err != nil {
111+ return err
112+ }
113+
114+ a.historyEntries = nil
115+ a.favorites = favorites
116+ a.folders = folders
117+ a.tags = tags
118+ a.renderedHTML = favoritesHTML(favorites, folders, tags)
119+ return nil
120+}
121+
122+func (a *App) loadConfigRoute(ctx context.Context) error {
123+ if a.deps.Config == nil {
124+ a.resetRouteState()
145 a.renderedHTML = placeholderHTML(a.currentRoute)125 a.renderedHTML = placeholderHTML(a.currentRoute)
146 return nil126 return nil
147 }127 }
128+
129+ config, err := a.deps.Config.Current(ctx)
130+ if err != nil {
131+ return err
132+ }
133+ keybindings, err := a.deps.Config.GetKeybindings(ctx)
134+ if err != nil {
135+ return err
136+ }
137+
138+ a.historyEntries = nil
139+ a.favorites = nil
140+ a.folders = nil
141+ a.tags = nil
142+ a.config = &config
143+ a.keybindings = keybindings
144+ a.renderedHTML = configHTML(config, keybindings)
145+ return nil
146+}
147+
148+func (a *App) resetRouteState() {
149+ a.historyEntries = nil
150+ a.favorites = nil
151+ a.folders = nil
152+ a.tags = nil
153+ a.config = nil
154+ a.keybindings = nil
148 }155 }
149 156
150 func (a *App) CurrentRoute() Route {157 func (a *App) CurrentRoute() Route {
M internal/ui/systemviews/app_test.go +1 -1
@@ -67,7 +67,7 @@ func TestAppLoadInitialHistoryRouteRendersEntries(t *testing.T) {
6767
6868 require.NoError(t, app.LoadInitial(context.Background()))
6969 assert.Equal(t, RouteHistory, app.CurrentRoute())
70- assert.Equal(t, 1, len(app.historyEntries))
70+ assert.Len(t, app.historyEntries, 1)
7171 assert.Contains(t, app.renderedHTML, "Example")
7272 assert.Contains(t, app.renderedHTML, "https://example.com")
7373 assert.True(t, history.called)
@@ -67,7 +67,7 @@ func TestAppLoadInitialHistoryRouteRendersEntries(t *testing.T) {
67 67
68 require.NoError(t, app.LoadInitial(context.Background()))68 require.NoError(t, app.LoadInitial(context.Background()))
69 assert.Equal(t, RouteHistory, app.CurrentRoute())69 assert.Equal(t, RouteHistory, app.CurrentRoute())
70- assert.Equal(t, 1, len(app.historyEntries))70+ assert.Len(t, app.historyEntries, 1)
71 assert.Contains(t, app.renderedHTML, "Example")71 assert.Contains(t, app.renderedHTML, "Example")
72 assert.Contains(t, app.renderedHTML, "https://example.com")72 assert.Contains(t, app.renderedHTML, "https://example.com")
73 assert.True(t, history.called)73 assert.True(t, history.called)
M internal/ui/systemviews/config_view.go +2 -2
@@ -39,7 +39,7 @@ func configHTML(cfg port.SystemviewConfigPayload, keybindings any) string {
3939 )
4040 }
4141
42-func summarizeKeybindings(keybindings any) (groups int, bindings int, loaded bool) {
42+func summarizeKeybindings(keybindings any) (groups, bindings int, loaded bool) {
4343 switch v := keybindings.(type) {
4444 case nil:
4545 return 0, 0, false
@@ -57,7 +57,7 @@ func summarizeKeybindings(keybindings any) (groups int, bindings int, loaded boo
5757 }
5858 }
5959
60-func countBridgeKeybindings(data map[string]any) (groups int, bindings int, loaded bool) {
60+func countBridgeKeybindings(data map[string]any) (groups, bindings int, loaded bool) {
6161 groupValue, ok := data["groups"]
6262 if !ok {
6363 return 1, 0, true
@@ -39,7 +39,7 @@ func configHTML(cfg port.SystemviewConfigPayload, keybindings any) string {
39 )39 )
40 }40 }
41 41
42-func summarizeKeybindings(keybindings any) (groups int, bindings int, loaded bool) {42+func summarizeKeybindings(keybindings any) (groups, bindings int, loaded bool) {
43 switch v := keybindings.(type) {43 switch v := keybindings.(type) {
44 case nil:44 case nil:
45 return 0, 0, false45 return 0, 0, false
@@ -57,7 +57,7 @@ func summarizeKeybindings(keybindings any) (groups int, bindings int, loaded boo
57 }57 }
58 }58 }
59 59
60-func countBridgeKeybindings(data map[string]any) (groups int, bindings int, loaded bool) {60+func countBridgeKeybindings(data map[string]any) (groups, bindings int, loaded bool) {
61 groupValue, ok := data["groups"]61 groupValue, ok := data["groups"]
62 if !ok {62 if !ok {
63 return 1, 0, true63 return 1, 0, true
M internal/ui/systemviews/favorites_view.go +3 -3
@@ -51,7 +51,7 @@ func favoriteItemsHTML(favorites []*entity.Favorite) string {
5151 if label == "" {
5252 label = favorite.URL
5353 }
54- items.WriteString(fmt.Sprintf(`<li><a href="%s">%s</a></li>`, html.EscapeString(favorite.URL), html.EscapeString(label)))
54+ _, _ = fmt.Fprintf(&items, `<li><a href="%s">%s</a></li>`, html.EscapeString(favorite.URL), html.EscapeString(label))
5555 }
5656 if items.Len() == 0 {
5757 return "<li>No favorites</li>"
@@ -69,7 +69,7 @@ func folderItemsHTML(folders []*entity.Folder) string {
6969 if folder == nil {
7070 continue
7171 }
72- items.WriteString(fmt.Sprintf("<li>%s</li>", html.EscapeString(folder.Name)))
72+ _, _ = fmt.Fprintf(&items, "<li>%s</li>", html.EscapeString(folder.Name))
7373 }
7474 if items.Len() == 0 {
7575 return "<li>No folders</li>"
@@ -87,7 +87,7 @@ func tagItemsHTML(tags []*entity.Tag) string {
8787 if tag == nil {
8888 continue
8989 }
90- items.WriteString(fmt.Sprintf("<li>%s</li>", html.EscapeString(tag.Name)))
90+ _, _ = fmt.Fprintf(&items, "<li>%s</li>", html.EscapeString(tag.Name))
9191 }
9292 if items.Len() == 0 {
9393 return "<li>No tags</li>"
@@ -51,7 +51,7 @@ func favoriteItemsHTML(favorites []*entity.Favorite) string {
51 if label == "" {51 if label == "" {
52 label = favorite.URL52 label = favorite.URL
53 }53 }
54- items.WriteString(fmt.Sprintf(`<li><a href="%s">%s</a></li>`, html.EscapeString(favorite.URL), html.EscapeString(label)))54+ _, _ = fmt.Fprintf(&items, `<li><a href="%s">%s</a></li>`, html.EscapeString(favorite.URL), html.EscapeString(label))
55 }55 }
56 if items.Len() == 0 {56 if items.Len() == 0 {
57 return "<li>No favorites</li>"57 return "<li>No favorites</li>"
@@ -69,7 +69,7 @@ func folderItemsHTML(folders []*entity.Folder) string {
69 if folder == nil {69 if folder == nil {
70 continue70 continue
71 }71 }
72- items.WriteString(fmt.Sprintf("<li>%s</li>", html.EscapeString(folder.Name)))72+ _, _ = fmt.Fprintf(&items, "<li>%s</li>", html.EscapeString(folder.Name))
73 }73 }
74 if items.Len() == 0 {74 if items.Len() == 0 {
75 return "<li>No folders</li>"75 return "<li>No folders</li>"
@@ -87,7 +87,7 @@ func tagItemsHTML(tags []*entity.Tag) string {
87 if tag == nil {87 if tag == nil {
88 continue88 continue
89 }89 }
90- items.WriteString(fmt.Sprintf("<li>%s</li>", html.EscapeString(tag.Name)))90+ _, _ = fmt.Fprintf(&items, "<li>%s</li>", html.EscapeString(tag.Name))
91 }91 }
92 if items.Len() == 0 {92 if items.Len() == 0 {
93 return "<li>No tags</li>"93 return "<li>No tags</li>"
M internal/ui/systemviews/history_view.go +1 -4
@@ -21,10 +21,7 @@ func historyHTML(entries []*entity.HistoryEntry) string {
2121 if label == "" {
2222 label = entry.URL
2323 }
24- items.WriteString(fmt.Sprintf(`<li><a href="%s">%s</a></li>`,
25- html.EscapeString(entry.URL),
26- html.EscapeString(label),
27- ))
24+ _, _ = fmt.Fprintf(&items, `<li><a href="%s">%s</a></li>`, html.EscapeString(entry.URL), html.EscapeString(label))
2825 }
2926 }
3027
@@ -21,10 +21,7 @@ func historyHTML(entries []*entity.HistoryEntry) string {
21 if label == "" {21 if label == "" {
22 label = entry.URL22 label = entry.URL
23 }23 }
24- items.WriteString(fmt.Sprintf(`<li><a href="%s">%s</a></li>`,24+ _, _ = fmt.Fprintf(&items, `<li><a href="%s">%s</a></li>`, html.EscapeString(entry.URL), html.EscapeString(label))
25- html.EscapeString(entry.URL),
26- html.EscapeString(label),
27- ))
28 }25 }
29 }26 }
30 27

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