diff --git a/src/OpenClaw.Tray.WinUI/Helpers/NavOriginLabels.cs b/src/OpenClaw.Tray.WinUI/Helpers/NavOriginLabels.cs
new file mode 100644
index 000000000..25d6f7143
--- /dev/null
+++ b/src/OpenClaw.Tray.WinUI/Helpers/NavOriginLabels.cs
@@ -0,0 +1,45 @@
+namespace OpenClawTray.Helpers;
+
+///
+/// Maps HubWindow nav tags to localised page labels for cross-page
+/// "Back to {origin}" affordances. Reuses the sidebar
+/// HubWindow_NavigationViewItem_*.Content resw entries so page names
+/// are translated once and stay in sync with the sidebar.
+///
+internal static class NavOriginLabels
+{
+ public static string DisplayLabel(string? tag)
+ {
+ if (string.IsNullOrWhiteSpace(tag)) return string.Empty;
+ var resourceKey = tag switch
+ {
+ "chat" => "HubWindow_NavigationViewItem_82.Content",
+ "connection" => "HubWindow_NavigationViewItem_88.Content",
+ "sessions" => "HubWindow_NavigationViewItem_91.Content",
+ "skills" => "HubWindow_NavigationViewItem_97.Content",
+ "channels" => "HubWindow_NavigationViewItem_109.Content",
+ "instances" or "nodes" => "HubWindow_NavigationViewItem_112.Content",
+ "agentevents" => "HubWindow_NavigationViewItem_94.Content",
+ "bindings" => "HubWindow_NavigationViewItem_115.Content",
+ "config" => "HubWindow_NavigationViewItem_118.Content",
+ "usage" => "HubWindow_NavigationViewItem_121.Content",
+ "cron" => "HubWindow_NavigationViewItem_124.Content",
+ "voice" => "HubWindow_NavigationViewItem_Voice.Content",
+ "settings" => "HubWindow_NavigationViewItem_133.Content",
+ "permissions" => "HubWindow_NavigationViewItem_136.Content",
+ "sandbox" => "HubWindow_NavigationViewItem_Sandbox.Content",
+ "debug" => "HubWindow_NavigationViewItem_145.Content",
+ "info" or "about" => "HubWindow_NavigationViewItem_148.Content",
+ _ => null,
+ };
+ return resourceKey == null
+ ? char.ToUpperInvariant(tag![0]) + tag.Substring(1)
+ : LocalizationHelper.GetString(resourceKey);
+ }
+
+ public static string BackToLabel(string? tag) =>
+ LocalizationHelper.Format("BackToOriginFormat", DisplayLabel(tag));
+}
+
+
+
diff --git a/src/OpenClaw.Tray.WinUI/Pages/AboutPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/AboutPage.xaml.cs
index d9f9f0eae..d57c4b534 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/AboutPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/AboutPage.xaml.cs
@@ -138,7 +138,7 @@ private void OnCheckUpdatesClick(object sender, RoutedEventArgs e)
private void OnMoreDiagnosticsClick(object sender, RoutedEventArgs e)
{
- ((IAppCommands)CurrentApp).Navigate("debug");
+ ((IAppCommands)CurrentApp).Navigate("debug", "info");
}
private void OnDocumentationClick(object sender, RoutedEventArgs e)
diff --git a/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs
index 6f68d2b29..aab9fb29f 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs
@@ -56,7 +56,7 @@ public void Initialize()
}
private void OnOpenConnectionClick(object sender, RoutedEventArgs e)
- => ((IAppCommands)CurrentApp).Navigate("connection");
+ => ((IAppCommands)CurrentApp).Navigate("connection", "bindings");
private void OnAppStateChanged(object? sender, PropertyChangedEventArgs e)
{
diff --git a/src/OpenClaw.Tray.WinUI/Pages/ChannelsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/ChannelsPage.xaml.cs
index fc8e18542..fea4c4a1d 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/ChannelsPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/ChannelsPage.xaml.cs
@@ -1346,7 +1346,7 @@ private FrameworkElement BuildInlineConfigForm(ChannelRecord record)
{
Content = "Open Config page",
};
- openConfigBtn.Click += (_, _) => ((IAppCommands)CurrentApp).Navigate("config");
+ openConfigBtn.Click += (_, _) => ((IAppCommands)CurrentApp).Navigate("config", "channels");
actionRow.Children.Add(saveBtn);
actionRow.Children.Add(openConfigBtn);
stack.Children.Add(actionRow);
@@ -1946,7 +1946,7 @@ private FrameworkElement BuildConfigPlaceholder(ChannelRecord record)
};
btn.Click += (_, _) =>
{
- ((IAppCommands)CurrentApp).Navigate("config");
+ ((IAppCommands)CurrentApp).Navigate("config", "channels");
};
stack.Children.Add(btn);
return stack;
diff --git a/src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml.cs
index 37aaa0f53..9a8ebb9d0 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml.cs
@@ -266,7 +266,7 @@ private void ShowFunctionalSurface()
onStopSpeaking: () => app?.StopChatSpeaking(),
onVoiceRequest: VoiceTranscribeAsync,
onAttachClick: OnAttachClicked,
- onSettingsClick: () => _hub?.NavigateTo("voice"),
+ onSettingsClick: () => _hub?.NavigateTo("voice", "chat"),
onSpeakerMuteChanged: muted => (App.Current as App)?.SetChatSpeakerMuted(muted),
initialMuted: CurrentApp.Settings?.VoiceTtsEnabled == false,
suppressAutoDispose: true);
@@ -771,7 +771,7 @@ private async Task ShowVoiceSettingsDialogAsync(string title, string message, Ac
private void NavigateToVoiceSettings()
{
if (_hub is not null)
- _hub.NavigateTo("voice");
+ _hub.NavigateTo("voice", "chat");
else
(App.Current as App)?.ShowHub("voice");
}
diff --git a/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml b/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml
index d49cd0bb6..28b60b60e 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml
+++ b/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml
@@ -17,8 +17,19 @@
-
-
+
+
+
+
+
+
+
+
+
@@ -45,6 +56,7 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs
index c1ffb3156..ab4a3301d 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs
@@ -157,6 +157,31 @@ public void Initialize()
UpdatePairingRequests(existingNode);
if (_appState?.DevicePairList is { } existingDevice)
UpdateDevicePairingRequests(existingDevice);
+
+ RefreshBackOriginLink();
+ }
+
+ private string? _backOriginTag;
+
+ private void RefreshBackOriginLink()
+ {
+ var hub = CurrentApp.ActiveHubWindow as OpenClawTray.Windows.HubWindow;
+ var origin = hub?.LastNavigationOrigin;
+ if (string.IsNullOrEmpty(origin))
+ {
+ _backOriginTag = null;
+ BackOriginLink.Visibility = Visibility.Collapsed;
+ return;
+ }
+ _backOriginTag = origin;
+ BackOriginText.Text = Helpers.NavOriginLabels.BackToLabel(origin);
+ BackOriginLink.Visibility = Visibility.Visible;
+ }
+
+ private void OnBackOriginClicked(object sender, RoutedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(_backOriginTag))
+ ((IAppCommands)CurrentApp).Navigate(_backOriginTag);
}
private void OnPageUnloaded(object sender, RoutedEventArgs e)
diff --git a/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs
index 2928e827a..1e948124a 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs
@@ -80,7 +80,7 @@ public void Initialize()
}
private void OnOpenConnectionClick(object sender, RoutedEventArgs e)
- => ((IAppCommands)CurrentApp).Navigate("connection");
+ => ((IAppCommands)CurrentApp).Navigate("connection", "cron");
private void OnRefreshClick(object sender, RoutedEventArgs e)
{
diff --git a/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml b/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml
index 57f61e3e0..e9cd20659 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml
+++ b/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml
@@ -50,6 +50,18 @@
Padding="24,24,24,24"
Spacing="{StaticResource DiagSettingsCardSpacing}">
+
+
+
+
+
+
+
+
((IAppCommands)CurrentApp).Navigate("connection");
+ => ((IAppCommands)CurrentApp).Navigate("connection", "debug");
// ── Detail view (recent log) ─────────────────────────────────────
diff --git a/src/OpenClaw.Tray.WinUI/Pages/InstancesPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/InstancesPage.xaml.cs
index d08d486f4..342941f57 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/InstancesPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/InstancesPage.xaml.cs
@@ -126,7 +126,7 @@ private void UpdatePendingPairBanner()
}
private void OnPendingPairBannerClicked(object sender, RoutedEventArgs e)
- => ((IAppCommands)CurrentApp).Navigate("connection");
+ => ((IAppCommands)CurrentApp).Navigate("connection", "instances");
public void UpdateNodes(GatewayNodeInfo[] nodes)
{
diff --git a/src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs
index d8d165de5..fc81ce036 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs
@@ -362,7 +362,7 @@ private void UpdateSttEngineHint()
private void OnSttMoreSettingsClick(object sender, RoutedEventArgs e)
{
- ((IAppCommands)CurrentApp).Navigate("voice");
+ ((IAppCommands)CurrentApp).Navigate("voice", "permissions");
}
// ── Text-to-Speech card ──────────────────────────────────────────
diff --git a/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs
index f47d80935..17d481239 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs
@@ -246,7 +246,8 @@ private void OnOpenChat(object sender, RoutedEventArgs e)
{
hub.PendingChatSessionKey = key;
}
- ((IAppCommands)CurrentApp).Navigate("chat", "sessions");
+ // No origin tag: opening chat should not surface a "Back to Sessions" link.
+ ((IAppCommands)CurrentApp).Navigate("chat");
}
}
diff --git a/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs
index c2ad6b89c..7d9576a2b 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs
+++ b/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs
@@ -168,7 +168,7 @@ private void RequestRefresh(IOperatorGatewayClient client)
}
private void OnOpenConnectionClick(object sender, RoutedEventArgs e)
- => ((IAppCommands)CurrentApp).Navigate("connection");
+ => ((IAppCommands)CurrentApp).Navigate("connection", "usage");
private void OnAppStateChanged(object? sender, PropertyChangedEventArgs e)
{
diff --git a/src/OpenClaw.Tray.WinUI/Pages/VoiceSettingsPage.xaml b/src/OpenClaw.Tray.WinUI/Pages/VoiceSettingsPage.xaml
index c38639ec0..529666d79 100644
--- a/src/OpenClaw.Tray.WinUI/Pages/VoiceSettingsPage.xaml
+++ b/src/OpenClaw.Tray.WinUI/Pages/VoiceSettingsPage.xaml
@@ -8,6 +8,18 @@
+
+
+
+
+
+
+
+
diff --git a/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw
index 8f22d4729..9481d5477 100644
--- a/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw
+++ b/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw
@@ -3255,6 +3255,14 @@ On your gateway host (Mac/Linux), run:
Back to Connection
+
+ Back to {0}
+ Format string for cross-page back link text. {0} is the localised name of the page the user came from (reused from the sidebar HubWindow_NavigationViewItem_* labels).
+
+
+ Back
+ Fallback label for the inline back link when the origin page is unknown. Normally not shown — the link is hidden when there is no origin.
+
🔗 Pending Operator/Node Pairing
diff --git a/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw
index 10d0ab868..e3b9c87ce 100644
--- a/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw
+++ b/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw
@@ -3207,6 +3207,14 @@ Sur votre hôte passerelle (Mac/Linux), exécutez :
Retour à la connexion
+
+ Retour à {0}
+ Format string for cross-page back link text. {0} is the localised name of the page the user came from (reused from the sidebar HubWindow_NavigationViewItem_* labels).
+
+
+ Retour
+ Fallback label for the inline back link when the origin page is unknown. Normally not shown — the link is hidden when there is no origin.
+
🔗 Pending Operator/Node Pairing
diff --git a/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw
index 251ef4f01..f8563b416 100644
--- a/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw
+++ b/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw
@@ -3208,6 +3208,14 @@ Voer op uw gateway-host (Mac/Linux) uit:
Terug naar verbinding
+
+ Terug naar {0}
+ Format string for cross-page back link text. {0} is the localised name of the page the user came from (reused from the sidebar HubWindow_NavigationViewItem_* labels).
+
+
+ Terug
+ Fallback label for the inline back link when the origin page is unknown. Normally not shown — the link is hidden when there is no origin.
+
🔗 Pending Operator/Node Pairing
diff --git a/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw
index 889455944..fd88a35db 100644
--- a/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw
+++ b/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw
@@ -3207,6 +3207,14 @@
返回连接
+
+ 返回 {0}
+ Format string for cross-page back link text. {0} is the localised name of the page the user came from (reused from the sidebar HubWindow_NavigationViewItem_* labels).
+
+
+ 返回
+ Fallback label for the inline back link when the origin page is unknown. Normally not shown — the link is hidden when there is no origin.
+
🔗 Pending Operator/Node Pairing
diff --git a/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw
index 4e8bbefdc..42583420e 100644
--- a/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw
+++ b/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw
@@ -3207,6 +3207,14 @@
返回連線
+
+ 返回 {0}
+ Format string for cross-page back link text. {0} is the localised name of the page the user came from (reused from the sidebar HubWindow_NavigationViewItem_* labels).
+
+
+ 返回
+ Fallback label for the inline back link when the origin page is unknown. Normally not shown — the link is hidden when there is no origin.
+
🔗 Pending Operator/Node Pairing
diff --git a/tests/OpenClaw.Tray.Tests/AsyncListLoadingPageWiringTests.cs b/tests/OpenClaw.Tray.Tests/AsyncListLoadingPageWiringTests.cs
index 13bc3d647..29aefe39c 100644
--- a/tests/OpenClaw.Tray.Tests/AsyncListLoadingPageWiringTests.cs
+++ b/tests/OpenClaw.Tray.Tests/AsyncListLoadingPageWiringTests.cs
@@ -41,7 +41,8 @@ public void BigListPages_SurfaceDisconnectedState(string fileName)
var source = ReadSource("src", "OpenClaw.Tray.WinUI", "Pages", fileName);
Assert.Contains("ShowDisconnected", source);
- Assert.Contains("Navigate(\"connection\")", source);
+ // Match both Navigate("connection") and Navigate("connection", "").
+ Assert.Contains("Navigate(\"connection\"", source);
Assert.Contains(".Fail()", source);
}