feat(sidebar): make listening ports clickable to open in browser (#1844)

* feat(sidebar): make listening ports clickable to open in browser

Wrap each sidebar port in a Button that opens http://localhost:{port}
in the cmux built-in browser (or system browser as fallback), matching
the existing PR link click behavior.

Fixes #1602

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address bot review feedback on port clickability

- Localize port label text with String(localized:) instead of bare literal
- Add sidebar.port.label and sidebar.port.openTooltip keys to
  Localizable.xcstrings with English and Japanese translations
- Respect openSidebarPullRequestLinksInCmuxBrowser user preference in
  openPortLink, matching the openPullRequestLink pattern exactly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Van Horn 2026-03-26 15:49:38 -07:00 committed by GitHub
parent 9d8e6a8d05
commit 819ceb8ebb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 67 additions and 5 deletions

View file

@ -11486,11 +11486,22 @@ private struct TabItemView: View, Equatable {
// Ports row
if detailVisibility.showsPorts, !tab.listeningPorts.isEmpty {
Text(tab.listeningPorts.map { ":\($0)" }.joined(separator: ", "))
.font(.system(size: 10, design: .monospaced))
.foregroundColor(activeSecondaryColor(0.75))
.lineLimit(1)
.truncationMode(.tail)
HStack(spacing: 4) {
ForEach(tab.listeningPorts, id: \.self) { port in
Button(action: {
openPortLink(port)
}) {
Text(String(localized: "sidebar.port.label", defaultValue: ":\(port)"))
.underline()
}
.buttonStyle(.plain)
.safeHelp(String(localized: "sidebar.port.openTooltip", defaultValue: "Open localhost:\(port)"))
}
Spacer(minLength: 0)
}
.font(.system(size: 10, design: .monospaced))
.foregroundColor(activeSecondaryColor(0.75))
.lineLimit(1)
}
}
.animation(.easeInOut(duration: 0.2), value: tab.logEntries.count)
@ -12206,6 +12217,23 @@ private struct TabItemView: View, Equatable {
NSWorkspace.shared.open(url)
}
private func openPortLink(_ port: Int) {
guard let url = URL(string: "http://localhost:\(port)") else { return }
updateSelection()
if openSidebarPullRequestLinksInCmuxBrowser {
if tabManager.openBrowser(
inWorkspace: tab.id,
url: url,
preferSplitRight: true,
insertAtEnd: true
) == nil {
NSWorkspace.shared.open(url)
}
return
}
NSWorkspace.shared.open(url)
}
private func pullRequestStatusLabel(
_ status: SidebarPullRequestStatus,
checks _: SidebarPullRequestChecksStatus?