v0.28.0 3cb3770

folders.go RawHistoryFolder

1package homepage
2
3import (
4	"context"
5	"encoding/json"
6
7	"github.com/bnema/dumber/internal/application/port"
8	"github.com/bnema/dumber/internal/domain/entity"
9	"github.com/bnema/dumber/internal/infrastructure/webkit"
10	"github.com/bnema/dumber/internal/logging"
11)
12
13// FolderHandlers handles folder-related messages from the homepage.
14type FolderHandlers struct {
15	favoritesUC port.HomepageFavorites
16}
17
18// NewFolderHandlers creates a new FolderHandlers instance.
19func NewFolderHandlers(favoritesUC port.HomepageFavorites) *FolderHandlers {
20	return &FolderHandlers{favoritesUC: favoritesUC}
21}
22
23// HandleList handles folder_list messages.
24func (h *FolderHandlers) HandleList() webkit.MessageHandler {
25	return webkit.MessageHandlerFunc(func(ctx context.Context, _ webkit.WebViewID, payload json.RawMessage) (any, error) {
26		log := logging.FromContext(ctx)
27
28		requestID := ParseRequestID(payload)
29
30		log.Debug().
31			Str("request_id", requestID).
32			Msg("handling folder_list")
33
34		folders, err := h.favoritesUC.GetAllFolders(ctx)
35		if err != nil {
36			return NewErrorResponse(requestID, err), nil
37		}
38
39		return NewSuccessResponse(requestID, folders), nil
40	})
41}
42
43// createFolderRequest is the payload for folder_create messages.
44type createFolderRequest struct {
45	RequestID string  `json:"requestId"`
46	Name      string  `json:"name"`
47	Icon      *string `json:"icon"`
48}
49
50// HandleCreate handles folder_create messages.
51func (h *FolderHandlers) HandleCreate() webkit.MessageHandler {
52	return webkit.MessageHandlerFunc(func(ctx context.Context, _ webkit.WebViewID, payload json.RawMessage) (any, error) {
53		log := logging.FromContext(ctx)
54
55		var req createFolderRequest
56		if err := json.Unmarshal(payload, &req); err != nil {
57			return NewErrorResponse("", err), nil
58		}
59
60		log.Debug().
61			Str("request_id", req.RequestID).
62			Str("name", req.Name).
63			Msg("handling folder_create")
64
65		folder, err := h.favoritesUC.CreateFolder(ctx, req.Name, nil)
66		if err != nil {
67			return NewErrorResponse(req.RequestID, err), nil
68		}
69
70		// Set icon if provided and persist it
71		if req.Icon != nil && *req.Icon != "" {
72			folder.Icon = *req.Icon
73			if err := h.favoritesUC.UpdateFolder(ctx, folder.ID, folder.Name, folder.Icon); err != nil {
74				return NewErrorResponse(req.RequestID, err), nil
75			}
76		}
77
78		return NewSuccessResponse(req.RequestID, folder), nil
79	})
80}
81
82// deleteFolderRequest is the payload for folder_delete messages.
83type deleteFolderRequest struct {
84	RequestID string `json:"requestId"`
85	ID        int64  `json:"id"`
86}
87
88// HandleDelete handles folder_delete messages.
89func (h *FolderHandlers) HandleDelete() webkit.MessageHandler {
90	return webkit.MessageHandlerFunc(func(ctx context.Context, _ webkit.WebViewID, payload json.RawMessage) (any, error) {
91		log := logging.FromContext(ctx)
92
93		var req deleteFolderRequest
94		if err := json.Unmarshal(payload, &req); err != nil {
95			return NewErrorResponse("", err), nil
96		}
97
98		log.Debug().
99			Str("request_id", req.RequestID).
100			Int64("id", req.ID).
101			Msg("handling folder_delete")
102
103		if err := h.favoritesUC.DeleteFolder(ctx, entity.FolderID(req.ID)); err != nil {
104			return NewErrorResponse(req.RequestID, err), nil
105		}
106
107		return NewSuccessResponse(req.RequestID, nil), nil
108	})
109}
110
111// updateFolderRequest is the payload for folder_update messages.
112type updateFolderRequest struct {
113	RequestID string  `json:"requestId"`
114	ID        int64   `json:"id"`
115	Name      string  `json:"name"`
116	Icon      *string `json:"icon"`
117}
118
119// HandleUpdate handles folder_update messages.
120// It delegates to the port.HomepageFavorites interface's UpdateFolder method.
121func (h *FolderHandlers) HandleUpdate() webkit.MessageHandler {
122	return webkit.MessageHandlerFunc(func(ctx context.Context, _ webkit.WebViewID, payload json.RawMessage) (any, error) {
123		log := logging.FromContext(ctx)
124
125		var req updateFolderRequest
126		if err := json.Unmarshal(payload, &req); err != nil {
127			return NewErrorResponse("", err), nil
128		}
129
130		log.Debug().
131			Str("request_id", req.RequestID).
132			Int64("id", req.ID).
133			Str("name", req.Name).
134			Msg("handling folder_update")
135
136		icon := ""
137		if req.Icon != nil {
138			icon = *req.Icon
139		}
140
141		if err := h.favoritesUC.UpdateFolder(ctx, entity.FolderID(req.ID), req.Name, icon); err != nil {
142			return NewErrorResponse(req.RequestID, err), nil
143		}
144
145		return NewSuccessResponse(req.RequestID, nil), nil
146	})
147}

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