diff --git a/mac/VibeTunnel/Assets.xcassets/menubar.imageset/menubar@2x.png b/mac/VibeTunnel/Assets.xcassets/menubar.imageset/menubar@2x.png index 3682b057..cc84904f 100644 Binary files a/mac/VibeTunnel/Assets.xcassets/menubar.imageset/menubar@2x.png and b/mac/VibeTunnel/Assets.xcassets/menubar.imageset/menubar@2x.png differ diff --git a/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift b/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift index 38759028..1b9469d1 100644 --- a/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift +++ b/mac/VibeTunnel/Presentation/Views/Settings/DashboardSettingsView.swift @@ -434,6 +434,45 @@ private struct ServerConfigurationSection: View { } header: { Text("Server Configuration") .font(.headline) + } footer: { + // Dashboard URL display + if accessMode == .localhost { + HStack(spacing: 5) { + Text("Dashboard available at") + .font(.caption) + .foregroundStyle(.secondary) + + if let url = URL(string: "http://127.0.0.1:\(serverPort)") { + Link(url.absoluteString, destination: url) + .font(.caption) + .foregroundStyle(.blue) + } + } + .frame(maxWidth: .infinity) + .multilineTextAlignment(.center) + } else if accessMode == .network { + if let ip = localIPAddress { + HStack(spacing: 5) { + Text("Dashboard available at") + .font(.caption) + .foregroundStyle(.secondary) + + if let url = URL(string: "http://\(ip):\(serverPort)") { + Link(url.absoluteString, destination: url) + .font(.caption) + .foregroundStyle(.blue) + } + } + .frame(maxWidth: .infinity) + .multilineTextAlignment(.center) + } else { + Text("Fetching local IP address...") + .font(.caption) + .foregroundStyle(.secondary) + .frame(maxWidth: .infinity) + .multilineTextAlignment(.center) + } + } } } } @@ -646,6 +685,7 @@ private struct NgrokIntegrationSection: View { } footer: { Text("ngrok creates secure tunnels to your dashboard from anywhere.") .font(.caption) + .frame(maxWidth: .infinity) .multilineTextAlignment(.center) } } diff --git a/web/src/client/components/session-list.ts b/web/src/client/components/session-list.ts index e82bf27c..10bd62c0 100644 --- a/web/src/client/components/session-list.ts +++ b/web/src/client/components/session-list.ts @@ -24,6 +24,7 @@ import type { AuthClient } from '../services/auth-client.js'; import './session-create-form.js'; import './session-card.js'; import { createLogger } from '../utils/logger.js'; +import { formatPathForDisplay } from '../utils/path-utils.js'; const logger = createLogger('session-list'); @@ -281,22 +282,16 @@ export class SessionList extends LitElement { ${session.name || session.command}
- ${session.workingDir} + ${formatPathForDisplay(session.workingDir)}
- -
- ${session.status} -
+
${session.status === 'running' || session.status === 'exited' ? html` + ${this.renderUtilityAndKillButtons(runningSessions)} ${this.renderExitedToggleButton(exitedSessions, true)} - ${this.renderActionButtons(exitedSessions, runningSessions, true)} + ${!this.hideExited && exitedSessions.length > 0 + ? html` + + ` + : ''}
@@ -113,30 +116,27 @@ export class SidebarHeader extends HeaderBase { `; } - private renderActionButtons( - exitedSessions: Session[], - runningSessions: Session[], - compact: boolean - ) { - const buttonClass = compact - ? 'btn-ghost font-mono text-xs px-3 py-1.5 w-full' - : 'btn-ghost font-mono text-xs px-4 py-2'; - + private renderUtilityAndKillButtons(runningSessions: Session[]) { return html` - ${!this.hideExited && exitedSessions.length > 0 - ? html` - - ` - : ''} - ${runningSessions.length > 0 && !this.killingAll - ? html` - - ` - : ''} +
+ + ${runningSessions.length > 0 && !this.killingAll + ? html` + + ` + : ''} +
`; } }