notice.go RawHistoryFolder

1package domain
2
3import "time"
4
5// NoticeSeverity ranks a user-facing notification.
6//
7// Its numeric values persist in JSON notice records and are a protocol/domain
8// contract. Add values only at the end; never reorder existing values.
9type NoticeSeverity uint8
10
11const (
12	NoticeInfo NoticeSeverity = iota
13	NoticeWarn
14	NoticeError
15)
16
17// NoticeCode identifies a failure meaning, not a call site.
18//
19// Its numeric values persist in JSON notice records and are a protocol/domain
20// contract. Add values only at the end; never reorder existing values.
21type NoticeCode uint16
22
23const (
24	NoticeInternal NoticeCode = iota
25	NoticePaneSpawn
26	NoticeTabSpawn
27	NoticeFloatingSpawn
28	NoticeSessionSpawn
29	NoticeLayoutTooSmall
30	NoticePaneNotFound
31	NoticeSessionUnavailable
32	NoticePersistDisabled
33	NoticeSnapshotWrite
34	NoticeSnapshotRestore
35	NoticeSnapshotSaturated
36	NoticePersistDelete
37	NoticeConfigReload
38	NoticeInputDropped
39	NoticeResizeFailed
40	NoticeClipboard
41	NoticeClipboardTooLarge
42	NoticeAutoResume
43	NoticeConnection
44	NoticeUser
45	NoticeNavigationInventory
46	NoticeRemoteObservation
47	NoticeSessionKill
48
49	// noticeCodeLimit is an append-only declaration sentinel, not a persisted
50	// valid notice code. Keep it last when adding a NoticeCode.
51	noticeCodeLimit
52)
53
54var noticeSlugs = map[NoticeCode]string{
55	NoticeInternal:            "internal",
56	NoticePaneSpawn:           "pane-spawn",
57	NoticeTabSpawn:            "tab-spawn",
58	NoticeFloatingSpawn:       "floating-spawn",
59	NoticeSessionSpawn:        "session-spawn",
60	NoticeLayoutTooSmall:      "layout-too-small",
61	NoticePaneNotFound:        "pane-not-found",
62	NoticeSessionUnavailable:  "session-unavailable",
63	NoticePersistDisabled:     "persist-disabled",
64	NoticeSnapshotWrite:       "snapshot-write",
65	NoticeSnapshotRestore:     "snapshot-restore",
66	NoticeSnapshotSaturated:   "snapshot-saturated",
67	NoticePersistDelete:       "persist-delete",
68	NoticeConfigReload:        "config-reload",
69	NoticeInputDropped:        "input-dropped",
70	NoticeResizeFailed:        "resize-failed",
71	NoticeClipboard:           "clipboard",
72	NoticeClipboardTooLarge:   "clipboard-too-large",
73	NoticeAutoResume:          "auto-resume",
74	NoticeConnection:          "connection",
75	NoticeUser:                "user",
76	NoticeNavigationInventory: "navigation-inventory",
77	NoticeRemoteObservation:   "remote-observation",
78	NoticeSessionKill:         "session-kill",
79}
80
81func (c NoticeCode) String() string {
82	if s, ok := noticeSlugs[c]; ok {
83		return s
84	}
85	return "unknown"
86}
87
88// UserError is an error whose message is written for the attached user.
89// The wrapped cause is shown only in yank details, never in the toast.
90type UserError struct {
91	Code     NoticeCode
92	Severity NoticeSeverity
93	Msg      string
94	Err      error
95}
96
97func (e *UserError) Error() string {
98	if e.Err == nil {
99		return e.Msg
100	}
101	return e.Msg + ": " + e.Err.Error()
102}
103
104func (e *UserError) Unwrap() error { return e.Err }
105
106// UserErr wraps err as an error-severity user-facing failure.
107func UserErr(code NoticeCode, msg string, err error) *UserError {
108	return &UserError{Code: code, Severity: NoticeError, Msg: msg, Err: err}
109}
110
111// UserWarn wraps err as a warn-severity user-facing failure.
112func UserWarn(code NoticeCode, msg string, err error) *UserError {
113	return &UserError{Code: code, Severity: NoticeWarn, Msg: msg, Err: err}
114}
115
116// Notification is one entry in the daemon's user-facing notice history.
117type Notification struct {
118	Code      NoticeCode
119	Severity  NoticeSeverity
120	Message   string
121	Details   string // formatted error chain for yank
122	Time      time.Time
123	Count     int       // >1 when coalesced
124	SessionID SessionID // "" = daemon-global
125	// Scope narrows the subject below the session, such as one remote host.
126	// Notices with the same code, session, and scope replace each other.
127	Scope string `json:",omitempty"`
128}
129
130// Subject is the stable identity of what a notice is about. Client toasts
131// use it so a newer notice for the same subject replaces the visible one;
132// the daemon's notice coalescing keeps its own rule (daemon toastNoticeID).
133func (n Notification) Subject() string {
134	return n.Code.String() + "/" + string(n.SessionID) + "/" + n.Scope
135}

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 12

Tags 11

↑↓ moveenter openesc close