detached f46f039

fix(ui): reset WebRTC indicator for floating panes on navigation

commit
f46f0399343cf398e14deb4f85e941f199615e95
author
brice · · 2026-10-04 09:48 UTC
parent
6fcb6f0
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
refs
feat/cef-permission-prompts
2 files · +42 -15
M internal/ui/app.go +19 -15
@@ -3644,22 +3644,26 @@ func (a *App) wireWebRTCPermissionIndicator() {
36443644 })
36453645
36463646 // Reset the owning window's indicator when that pane navigates away.
3647- a.contentCoord.SetOnActiveNavigationCommitted(func(paneID entity.PaneID, uri string) {
3648- bw := a.browserWindowForPane(paneID)
3649- if bw == nil || bw.webrtcIndicator == nil {
3650- return
3651- }
3652- newOrigin, err := urlutil.ExtractOrigin(uri)
3653- if err != nil {
3654- bw.webrtcIndicator.Reset()
3655- return
3656- }
3647+ a.contentCoord.SetOnActiveNavigationCommitted(a.resetWebRTCIndicatorOnNavigation)
3648+}
36573649
3658- currentOrigin := bw.webrtcIndicator.Origin()
3659- if currentOrigin != "" && currentOrigin != newOrigin {
3660- bw.webrtcIndicator.Reset()
3661- }
3662- })
3650+// resetWebRTCIndicatorOnNavigation resets the indicator of the window owning the
3651+// pane (workspace or floating) when the pane navigates to a different origin.
3652+func (a *App) resetWebRTCIndicatorOnNavigation(paneID entity.PaneID, uri string) {
3653+ bw := a.browserWindowForAnyPane(paneID)
3654+ if bw == nil || bw.webrtcIndicator == nil {
3655+ return
3656+ }
3657+ newOrigin, err := urlutil.ExtractOrigin(uri)
3658+ if err != nil {
3659+ bw.webrtcIndicator.Reset()
3660+ return
3661+ }
3662+
3663+ currentOrigin := bw.webrtcIndicator.Origin()
3664+ if currentOrigin != "" && currentOrigin != newOrigin {
3665+ bw.webrtcIndicator.Reset()
3666+ }
36633667 }
36643668
36653669 func (a *App) wireBrowserWindowPermissionIndicator(bw *browserWindow) {
@@ -3644,22 +3644,26 @@ func (a *App) wireWebRTCPermissionIndicator() {
3644 })3644 })
3645 3645
3646 // Reset the owning window's indicator when that pane navigates away.3646 // Reset the owning window's indicator when that pane navigates away.
3647- a.contentCoord.SetOnActiveNavigationCommitted(func(paneID entity.PaneID, uri string) {3647+ a.contentCoord.SetOnActiveNavigationCommitted(a.resetWebRTCIndicatorOnNavigation)
3648- bw := a.browserWindowForPane(paneID)3648+}
3649- if bw == nil || bw.webrtcIndicator == nil {
3650- return
3651- }
3652- newOrigin, err := urlutil.ExtractOrigin(uri)
3653- if err != nil {
3654- bw.webrtcIndicator.Reset()
3655- return
3656- }
3657 3649
3658- currentOrigin := bw.webrtcIndicator.Origin()3650+// resetWebRTCIndicatorOnNavigation resets the indicator of the window owning the
3659- if currentOrigin != "" && currentOrigin != newOrigin {3651+// pane (workspace or floating) when the pane navigates to a different origin.
3660- bw.webrtcIndicator.Reset()3652+func (a *App) resetWebRTCIndicatorOnNavigation(paneID entity.PaneID, uri string) {
3661- }3653+ bw := a.browserWindowForAnyPane(paneID)
3662- })3654+ if bw == nil || bw.webrtcIndicator == nil {
3655+ return
3656+ }
3657+ newOrigin, err := urlutil.ExtractOrigin(uri)
3658+ if err != nil {
3659+ bw.webrtcIndicator.Reset()
3660+ return
3661+ }
3662+
3663+ currentOrigin := bw.webrtcIndicator.Origin()
3664+ if currentOrigin != "" && currentOrigin != newOrigin {
3665+ bw.webrtcIndicator.Reset()
3666+ }
3663 }3667 }
3664 3668
3665 func (a *App) wireBrowserWindowPermissionIndicator(bw *browserWindow) {3669 func (a *App) wireBrowserWindowPermissionIndicator(bw *browserWindow) {
M internal/ui/browser_window_test.go +23 -0
@@ -1186,3 +1186,26 @@ func TestApp_PermissionDialogForPane(t *testing.T) {
11861186 owner.permissionDialog = nil
11871187 assert.Nil(t, app.permissionDialogForPane(tabPane), "window without dialog")
11881188 }
1189+
1190+func TestApp_ResetWebRTCIndicatorOnNavigationCoversFloatingPanes(t *testing.T) {
1191+ tab := entity.NewTab(entity.TabID("tab-1"), entity.WorkspaceID("workspace-1"), entity.NewPane(entity.PaneID("pane-1")))
1192+ tabs := entity.NewTabList()
1193+ tabs.Add(tab)
1194+ indicator := &component.WebRTCPermissionIndicator{}
1195+ bw := &browserWindow{id: "window-1", tabs: tabs, webrtcIndicator: indicator}
1196+ floatingPaneID := entity.PaneID("floating-pane")
1197+ app := &App{
1198+ browserWindows: map[string]*browserWindow{bw.id: bw},
1199+ windowForTab: map[entity.TabID]*browserWindow{tab.ID: bw},
1200+ floatingSessions: map[floatingSessionKey]*floatingWorkspaceSession{
1201+ {tabID: tab.ID, sessionID: "profile:one"}: {paneID: floatingPaneID},
1202+ },
1203+ }
1204+
1205+ indicator.SetOrigin("https://old.example")
1206+ app.resetWebRTCIndicatorOnNavigation(floatingPaneID, "https://old.example/page")
1207+ assert.Equal(t, "https://old.example", indicator.Origin(), "same-origin navigation keeps the indicator")
1208+
1209+ app.resetWebRTCIndicatorOnNavigation(floatingPaneID, "https://new.example/")
1210+ assert.Empty(t, indicator.Origin(), "cross-origin navigation in a floating pane resets the indicator")
1211+}
@@ -1186,3 +1186,26 @@ func TestApp_PermissionDialogForPane(t *testing.T) {
1186 owner.permissionDialog = nil1186 owner.permissionDialog = nil
1187 assert.Nil(t, app.permissionDialogForPane(tabPane), "window without dialog")1187 assert.Nil(t, app.permissionDialogForPane(tabPane), "window without dialog")
1188 }1188 }
1189+
1190+func TestApp_ResetWebRTCIndicatorOnNavigationCoversFloatingPanes(t *testing.T) {
1191+ tab := entity.NewTab(entity.TabID("tab-1"), entity.WorkspaceID("workspace-1"), entity.NewPane(entity.PaneID("pane-1")))
1192+ tabs := entity.NewTabList()
1193+ tabs.Add(tab)
1194+ indicator := &component.WebRTCPermissionIndicator{}
1195+ bw := &browserWindow{id: "window-1", tabs: tabs, webrtcIndicator: indicator}
1196+ floatingPaneID := entity.PaneID("floating-pane")
1197+ app := &App{
1198+ browserWindows: map[string]*browserWindow{bw.id: bw},
1199+ windowForTab: map[entity.TabID]*browserWindow{tab.ID: bw},
1200+ floatingSessions: map[floatingSessionKey]*floatingWorkspaceSession{
1201+ {tabID: tab.ID, sessionID: "profile:one"}: {paneID: floatingPaneID},
1202+ },
1203+ }
1204+
1205+ indicator.SetOrigin("https://old.example")
1206+ app.resetWebRTCIndicatorOnNavigation(floatingPaneID, "https://old.example/page")
1207+ assert.Equal(t, "https://old.example", indicator.Origin(), "same-origin navigation keeps the indicator")
1208+
1209+ app.resetWebRTCIndicatorOnNavigation(floatingPaneID, "https://new.example/")
1210+ assert.Empty(t, indicator.Origin(), "cross-origin navigation in a floating pane resets the indicator")
1211+}

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