Umbau durch Gemini Flash, Durchsicht und Nacharbeit durch Claude. Umfang: - Desktop: LocalizationManager (JSON-Pakete, Rueckfall auf Englisch, Umschalten zur Laufzeit), Localize-Markup-Erweiterung, Sprachwahl in den Einstellungen (AppSettings.Language, Vorgabe "en"); 317 Schluessel je Sprache - WebUI: alle Ansichten auf t()/data-i18n, 656 Schluessel je Sprache - Agenten-Werkzeuge: Beschreibungen, Schemata und Meldungen auf Englisch - Tests an die englischen Meldungen angepasst, keine Pruefung abgeschwaecht Nacharbeit bei der Durchsicht: - ~25 Kommentarbloecke mit Begruendungen waren ersatzlos entfallen, darunter sicherheitsrelevante (NTFS-Datenstrom beim shared:-Praefix, Bremse gegen Agentenschleifen, doppelter POST beim Anlegen einer Instanz). Wieder eingesetzt: auf Englisch, wo die Datei umgestellt ist, sonst im Wortlaut. - Drei WebUI-Schluessel fehlten (logs.paused, instances.instanceOfflineError, instances.noInstanceActiveError). Weil t() bei fehlendem Schluessel den Schluessel selbst liefert, griff der "|| err.message"-Rueckfall nie — die Oberflaeche haette den Schluesselnamen angezeigt. Geprueft: Schluesselgleichheit en/de, Platzhalter je Schluessel, jeder im Code benutzte Schluessel vorhanden, node --check fuer alle Module, 1.220 Tests gruen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
258 lines
14 KiB
XML
258 lines
14 KiB
XML
<UserControl xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
xmlns:vm="using:ClawdDotNet.Desktop.ViewModels"
|
|
xmlns:models="using:ClawdDotNet.App.Models"
|
|
xmlns:ctrl="using:ClawdDotNet.Desktop.Controls"
|
|
xmlns:conv="using:ClawdDotNet.Desktop.Converters"
|
|
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="740"
|
|
x:Class="ClawdDotNet.Desktop.Views.TasksPageView"
|
|
x:DataType="vm:TasksPageViewModel">
|
|
|
|
<DockPanel>
|
|
|
|
<!-- Segmentleiste statt Registerkarten. Die Knöpfe überlappen sich um einen
|
|
Bildpunkt, damit zwischen ihnen nur eine Linie steht und nicht zwei. -->
|
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"
|
|
HorizontalAlignment="Left" Margin="0,0,0,14">
|
|
<ToggleButton Content="{Binding L[desktop.tasks.tabJobs]}" Margin="0,0,-1,0"
|
|
IsChecked="{Binding IsJobsTab, Mode=OneWay}"
|
|
Command="{Binding SelectTabCommand}" CommandParameter="Jobs" />
|
|
<ToggleButton Content="{Binding L[desktop.tasks.tabServices]}" Margin="0,0,-1,0"
|
|
IsChecked="{Binding IsServicesTab, Mode=OneWay}"
|
|
Command="{Binding SelectTabCommand}" CommandParameter="Services" />
|
|
<ToggleButton Content="{Binding L[desktop.tasks.tabHistory]}"
|
|
IsChecked="{Binding IsHistoryTab, Mode=OneWay}"
|
|
Command="{Binding SelectTabCommand}" CommandParameter="History" />
|
|
</StackPanel>
|
|
|
|
<!-- Statuszeile des Bereichs -->
|
|
<TextBlock DockPanel.Dock="Bottom" Classes="caption" Margin="0,10,0,0"
|
|
Text="{Binding StatusText}" TextWrapping="Wrap" />
|
|
|
|
<Panel>
|
|
|
|
<!-- ══════════════════ Geplante Jobs ══════════════════ -->
|
|
<DockPanel IsVisible="{Binding IsJobsTab}">
|
|
|
|
<WrapPanel DockPanel.Dock="Top" Classes="toolbar">
|
|
<Button Classes="toolbar primary" Command="{Binding AddJobCommand}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconPlus}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.addJob]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Button Classes="toolbar" Command="{Binding EditJobCommand}"
|
|
IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconPencil}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.editJob]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Button Classes="toolbar" Command="{Binding RemoveJobCommand}"
|
|
IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconTrash}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.removeJob]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Button Classes="toolbar" Command="{Binding ToggleJobEnabledCommand}"
|
|
IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconPower}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.toggleJob]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Border Classes="sep" />
|
|
|
|
<Button Classes="toolbar" Command="{Binding RunJobNowCommand}"
|
|
IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconPlay}" Width="12" Height="12" IsFilled="True" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.runJobNow]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Button Classes="toolbar" Command="{Binding RefreshJobListCommand}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.refresh]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
</WrapPanel>
|
|
|
|
<Border DockPanel.Dock="Top" Classes="thead">
|
|
<Grid ColumnDefinitions="1.1*,1.3*,2.2*,1.1*,1.3*,1.3*,0.9*">
|
|
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.tasks.thType]}" />
|
|
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.tasks.thAgent]}" />
|
|
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.tasks.thTask]}" />
|
|
<TextBlock Grid.Column="3" Classes="th" Text="{Binding L[desktop.tasks.thCron]}" />
|
|
<TextBlock Grid.Column="4" Classes="th" Text="{Binding L[desktop.tasks.thNextRun]}" />
|
|
<TextBlock Grid.Column="5" Classes="th" Text="{Binding L[desktop.tasks.thLastRun]}" />
|
|
<TextBlock Grid.Column="6" Classes="th" Text="{Binding L[desktop.tasks.thStatus]}" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<ListBox Classes="table" ItemsSource="{Binding JobEntries}"
|
|
SelectedItem="{Binding SelectedJob}">
|
|
<ListBox.ItemTemplate>
|
|
<DataTemplate DataType="vm:JobDisplayItemViewModel">
|
|
<Border Classes="tr" Padding="7">
|
|
<Grid ColumnDefinitions="1.1*,1.3*,2.2*,1.1*,1.3*,1.3*,0.9*">
|
|
<TextBlock Grid.Column="0" Classes="td" Text="{Binding JobType}" />
|
|
<TextBlock Grid.Column="1" Classes="td" Text="{Binding AgentName}" />
|
|
<TextBlock Grid.Column="2" Classes="td" Text="{Binding TaskMessage}" />
|
|
<TextBlock Grid.Column="3" Classes="td mono" Text="{Binding CronExpression}" />
|
|
<TextBlock Grid.Column="4" Classes="td" Text="{Binding NextRun}" />
|
|
<TextBlock Grid.Column="5" Classes="td" Text="{Binding LastRun}" />
|
|
|
|
<Border Grid.Column="6" Classes="tag"
|
|
Classes.ok="{Binding Status,
|
|
Converter={x:Static conv:StringEqualsConverter.Instance},
|
|
ConverterParameter=Aktiv}">
|
|
<TextBlock Text="{Binding Status}" />
|
|
</Border>
|
|
</Grid>
|
|
</Border>
|
|
</DataTemplate>
|
|
</ListBox.ItemTemplate>
|
|
</ListBox>
|
|
</DockPanel>
|
|
|
|
<!-- ══════════════════ Dienste ══════════════════ -->
|
|
<DockPanel IsVisible="{Binding IsServicesTab}">
|
|
|
|
<WrapPanel DockPanel.Dock="Top" Classes="toolbar">
|
|
<Button Classes="toolbar primary" Command="{Binding AddServiceCommand}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconPlus}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.services.addService]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Button Classes="toolbar" Command="{Binding RemoveServiceCommand}"
|
|
IsEnabled="{Binding SelectedService, Converter={x:Static ObjectConverters.IsNotNull}}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconTrash}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.services.removeService]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Border Classes="sep" />
|
|
|
|
<!-- Der Entwurf zeigt hier „Start"/„Stop". Umgelegt wird aber das Kennzeichen
|
|
in der Konfiguration, nicht ein laufender Prozess — deshalb die ehrlichere
|
|
Beschriftung. -->
|
|
<Button Classes="toolbar" Command="{Binding ToggleServiceEnabledCommand}"
|
|
IsEnabled="{Binding SelectedService, Converter={x:Static ObjectConverters.IsNotNull}}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconPower}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.services.toggleService]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
|
|
<Button Classes="toolbar" Command="{Binding RefreshServiceListCommand}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.tasks.refresh]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
</WrapPanel>
|
|
|
|
<Border DockPanel.Dock="Top" Classes="thead">
|
|
<Grid ColumnDefinitions="1.8*,1*,0.7*,1*,3*">
|
|
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.services.thName]}" />
|
|
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.services.thType]}" />
|
|
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.services.thPort]}" />
|
|
<TextBlock Grid.Column="3" Classes="th" Text="{Binding L[desktop.services.thStatus]}" />
|
|
<TextBlock Grid.Column="4" Classes="th" Text="{Binding L[desktop.services.thDescription]}" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<ListBox Classes="table" ItemsSource="{Binding ServiceEntries}"
|
|
SelectedItem="{Binding SelectedService}">
|
|
<ListBox.ItemTemplate>
|
|
<DataTemplate DataType="vm:ServiceDisplayItemViewModel">
|
|
<Border Classes="tr" Padding="7">
|
|
<Grid ColumnDefinitions="1.8*,1*,0.7*,1*,3*">
|
|
<TextBlock Grid.Column="0" Classes="td" FontWeight="SemiBold" Text="{Binding Name}" />
|
|
<TextBlock Grid.Column="1" Classes="td" Text="{Binding Type}" />
|
|
<TextBlock Grid.Column="2" Classes="td" Text="{Binding Port}" />
|
|
|
|
<Border Grid.Column="3" Classes="tag"
|
|
Classes.ok="{Binding Status,
|
|
Converter={x:Static conv:StringEqualsConverter.Instance},
|
|
ConverterParameter=Bereit}">
|
|
<TextBlock Text="{Binding Status}" />
|
|
</Border>
|
|
|
|
<TextBlock Grid.Column="4" Classes="td dim" Text="{Binding Description}" />
|
|
</Grid>
|
|
</Border>
|
|
</DataTemplate>
|
|
</ListBox.ItemTemplate>
|
|
</ListBox>
|
|
</DockPanel>
|
|
|
|
<!-- ══════════════════ Verlauf ══════════════════ -->
|
|
<DockPanel IsVisible="{Binding IsHistoryTab}">
|
|
|
|
<StackPanel DockPanel.Dock="Top" Classes="toolbar">
|
|
<Button Classes="toolbar" Command="{Binding RefreshJobHistoryCommand}">
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
|
<TextBlock Text="{Binding L[desktop.history.refresh]}" />
|
|
</StackPanel>
|
|
</Button>
|
|
</StackPanel>
|
|
|
|
<Border DockPanel.Dock="Top" Classes="thead">
|
|
<Grid ColumnDefinitions="1.3*,1.6*,1.4*,2*,0.9*,2.4*">
|
|
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.history.thTime]}" />
|
|
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.history.thJob]}" />
|
|
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.history.thAgent]}" />
|
|
<TextBlock Grid.Column="3" Classes="th" Text="{Binding L[desktop.history.thDescription]}" />
|
|
<TextBlock Grid.Column="4" Classes="th" Text="{Binding L[desktop.history.thStatus]}" />
|
|
<TextBlock Grid.Column="5" Classes="th" Text="{Binding L[desktop.history.thDetails]}" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<ItemsControl ItemsSource="{Binding JobHistoryEntries}">
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate DataType="models:JobHistoryEntry">
|
|
<Border Classes="tr" Padding="7">
|
|
<Grid ColumnDefinitions="1.3*,1.6*,1.4*,2*,0.9*,2.4*">
|
|
<TextBlock Grid.Column="0" Classes="td"
|
|
Text="{Binding Time, StringFormat='{}{0:dd.MM. HH:mm}'}" />
|
|
<TextBlock Grid.Column="1" Classes="td" Text="{Binding JobName}" />
|
|
<TextBlock Grid.Column="2" Classes="td" Text="{Binding Agent}" />
|
|
<TextBlock Grid.Column="3" Classes="td dim" Text="{Binding JobDescription}" />
|
|
|
|
<Border Grid.Column="4" Classes="tag"
|
|
Classes.ok="{Binding Status,
|
|
Converter={x:Static conv:StringEqualsConverter.Instance},
|
|
ConverterParameter=Success}"
|
|
Classes.bad="{Binding Status,
|
|
Converter={x:Static conv:StringEqualsConverter.Instance},
|
|
ConverterParameter=Error}">
|
|
<TextBlock Text="{Binding Status}" />
|
|
</Border>
|
|
|
|
<TextBlock Grid.Column="5" Classes="td dim" Text="{Binding Info}" />
|
|
</Grid>
|
|
</Border>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</DockPanel>
|
|
|
|
</Panel>
|
|
</DockPanel>
|
|
|
|
</UserControl>
|