Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,26 @@
Title="Single-agent mode"
Message="All messages route to the default agent. Add bindings for multi-agent routing."/>

<ListView x:Name="BindingsList" SelectionMode="None">
<InfoBar x:Name="ConnectionInfoBar"
IsOpen="False" IsClosable="False"
Severity="Warning"
Title="Gateway disconnected"
Message="Connect to a gateway to load bindings.">
<InfoBar.ActionButton>
<Button Content="Open Connection" Click="OnOpenConnectionClick"/>
</InfoBar.ActionButton>
</InfoBar>

<StackPanel x:Name="LoadingState" Orientation="Horizontal" Spacing="12"
HorizontalAlignment="Center" Padding="0,24,0,16"
Visibility="Collapsed">
<ProgressRing IsActive="True" Width="20" Height="20"/>
<TextBlock Text="Loading bindings..."
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>

<ListView x:Name="BindingsList" SelectionMode="None" Visibility="Collapsed">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
Expand Down
80 changes: 73 additions & 7 deletions src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using OpenClawTray.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.Json;
Expand All @@ -11,6 +12,7 @@ public sealed partial class BindingsPage : Page
{
private static App CurrentApp => (App)Microsoft.UI.Xaml.Application.Current;
private AppState? _appState;
private readonly AsyncListLoadingState _bindingsLoading = new();

public BindingsPage()
{
Expand All @@ -23,16 +25,39 @@ public BindingsPage()

public void Initialize()
{
if (_appState != null) _appState.PropertyChanged -= OnAppStateChanged;
_appState = CurrentApp.AppState;
_appState.PropertyChanged += OnAppStateChanged;
// Use cached config if available
if (_appState?.Config.HasValue == true)
{
ParseBindings(_appState.Config.Value);
_bindingsLoading.BeginRefresh();
UpdateLoadingVisuals();
}
else
{
_bindingsLoading.BeginInitialRefresh();
UpdateLoadingVisuals();
}
// Request fresh config
if (CurrentApp.GatewayClient != null)
_ = CurrentApp.GatewayClient.RequestConfigAsync();
var client = CurrentApp.GatewayClient;
if (client != null)
{
ConnectionInfoBar.IsOpen = false;
_ = client.RequestConfigAsync();
}
else
{
_bindingsLoading.Fail();
ShowDisconnected();
UpdateLoadingVisuals();
}
}

private void OnOpenConnectionClick(object sender, RoutedEventArgs e)
=> ((IAppCommands)CurrentApp).Navigate("connection");

private void OnAppStateChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
Expand Down Expand Up @@ -79,28 +104,69 @@ private void ParseBindings(JsonElement config)
}
}
}
catch { }
catch (Exception ex)
{
_bindingsLoading.Fail();
ShowLoadFailure(ex);
UpdateLoadingVisuals();
return;
}

if (bindings.Count == 0)
{
SingleAgentInfoBar.IsOpen = true;
BindingsList.ItemsSource = null;
}
else
{
SingleAgentInfoBar.IsOpen = false;
BindingsList.ItemsSource = bindings;
}

_bindingsLoading.Complete(bindings.Count);
UpdateLoadingVisuals();
}

private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
if (CurrentApp.GatewayClient != null)
var client = CurrentApp.GatewayClient;
if (client != null)
{
ConnectionInfoBar.IsOpen = false;
_bindingsLoading.BeginRefresh();
UpdateLoadingVisuals();
_ = client.RequestConfigAsync();
}
else
{
_ = CurrentApp.GatewayClient.RequestConfigAsync();
_bindingsLoading.Fail();
ShowDisconnected();
UpdateLoadingVisuals();
}
}

private void UpdateLoadingVisuals()
{
LoadingState.Visibility = _bindingsLoading.ShouldShowLoading ? Visibility.Visible : Visibility.Collapsed;
BindingsList.Visibility = _bindingsLoading.ShouldShowContent ? Visibility.Visible : Visibility.Collapsed;
SingleAgentInfoBar.IsOpen = _bindingsLoading.ShouldShowEmpty;
RefreshButton.IsEnabled = CurrentApp.GatewayClient != null && _bindingsLoading.CanEdit;
}

private void ShowDisconnected()
{
ConnectionInfoBar.Title = "Gateway disconnected";
ConnectionInfoBar.Message = "Connect to a gateway to load bindings.";
ConnectionInfoBar.Severity = InfoBarSeverity.Warning;
ConnectionInfoBar.IsOpen = true;
}

private void ShowLoadFailure(Exception ex)
{
ConnectionInfoBar.Title = "Could not load bindings";
ConnectionInfoBar.Message = ex.Message;
ConnectionInfoBar.Severity = InfoBarSeverity.Error;
ConnectionInfoBar.IsOpen = true;
}

private class BindingViewModel
{
public string Channel { get; set; } = "";
Expand Down
67 changes: 47 additions & 20 deletions src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,26 @@
<StackPanel Grid.Row="0" Spacing="8" Margin="0,0,0,12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="⏱️ Cron Jobs" Style="{StaticResource TitleTextBlockStyle}" Grid.Column="0"/>
<TextBlock x:Name="JobCountText" Text="(0)" VerticalAlignment="Center" Grid.Column="1" Margin="8,0,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<Button x:Name="NewJobButton" Grid.Column="3" Click="OnNewJobClick" Padding="8,4">
<StackPanel Orientation="Horizontal" Spacing="4">
<FontIcon Glyph="&#xE710;" FontSize="14"/>
<TextBlock Text="New Job" FontSize="13"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="⏱️ Cron Jobs" Style="{StaticResource TitleTextBlockStyle}" Grid.Column="0"/>
<TextBlock x:Name="JobCountText" Text="(0)" VerticalAlignment="Center" Grid.Column="1" Margin="8,0,0,0"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<Button x:Name="RefreshButton" Grid.Column="3" Click="OnRefreshClick" Padding="8,4" Margin="0,0,8,0">
<StackPanel Orientation="Horizontal" Spacing="4">
<FontIcon Glyph="&#xE72C;" FontSize="14"/>
<TextBlock Text="Refresh" FontSize="13"/>
</StackPanel>
</Button>
<Button x:Name="NewJobButton" Grid.Column="4" Click="OnNewJobClick" Padding="8,4">
<StackPanel Orientation="Horizontal" Spacing="4">
<FontIcon Glyph="&#xE710;" FontSize="14"/>
<TextBlock Text="New Job" FontSize="13"/>
</StackPanel>
</Button>
</Grid>
Expand Down Expand Up @@ -60,8 +67,18 @@
</Border>
</StackPanel>

<!-- Store path (hidden, just for data) -->
<TextBlock x:Name="StorePathText" Visibility="Collapsed"/>
<!-- Store path (hidden, just for data) -->
<TextBlock x:Name="StorePathText" Visibility="Collapsed"/>

<InfoBar x:Name="ConnectionInfoBar" Grid.Row="1"
IsOpen="False" IsClosable="False" Severity="Warning"
Title="Gateway disconnected"
Message="Connect to a gateway to load cron jobs."
Margin="0,0,0,12">
<InfoBar.ActionButton>
<Button Content="Open Connection" Click="OnOpenConnectionClick"/>
</InfoBar.ActionButton>
</InfoBar>

<!-- Job creation/edit form -->
<Border x:Name="JobFormPanel" Grid.Row="2" Visibility="Collapsed"
Expand Down Expand Up @@ -263,12 +280,22 @@
<!-- Notification for completed one-shot jobs -->
<InfoBar x:Name="JobCompletedInfoBar" Grid.Row="3" IsOpen="False" Severity="Success" IsClosable="True" Margin="0,0,0,8"/>

<!-- Jobs list (manually managed for inline editing) -->
<StackPanel x:Name="JobsListPanel" Grid.Row="4" Spacing="4" Visibility="Collapsed"/>
<!-- Jobs list (manually managed for inline editing) -->
<StackPanel x:Name="JobsListPanel" Grid.Row="4" Spacing="4" Visibility="Collapsed"/>

<StackPanel x:Name="LoadingState" Grid.Row="4" Orientation="Horizontal" Spacing="12"
HorizontalAlignment="Center" VerticalAlignment="Center"
Visibility="Visible">
<ProgressRing IsActive="True" Width="22" Height="22"/>
<TextBlock Text="Loading cron jobs..."
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>

<!-- Empty state -->
<StackPanel x:Name="EmptyState" Grid.Row="4"
VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8">
<!-- Empty state -->
<StackPanel x:Name="EmptyState" Grid.Row="4"
VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"
Visibility="Collapsed">
<TextBlock Text="⏱️" FontSize="48" HorizontalAlignment="Center"/>
<TextBlock Text="No cron jobs configured"
Style="{StaticResource SubtitleTextBlockStyle}"
Expand Down
Loading
Loading