UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag. Oberflaeche - Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml (eigene ControlThemes statt Fluent umzufaerben). - Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite statt eigenem Fenster, Texteditor-Fenster. - ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt. Rocket.Chat - Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird nur, wenn wirklich etwas anliegt. - send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist. - Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei Annahmen waren falsch und sind korrigiert. Deploymentcenter - DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json) erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke. - AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,100 +3,255 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:ClawdDotNet.Desktop.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="700"
|
||||
Padding="16"
|
||||
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>
|
||||
|
||||
<!-- Statusbar unten -->
|
||||
<Border Classes="statusbar" DockPanel.Dock="Bottom">
|
||||
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center" />
|
||||
</Border>
|
||||
<!-- 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="Geplante Jobs" Margin="0,0,-1,0"
|
||||
IsChecked="{Binding IsJobsTab, Mode=OneWay}"
|
||||
Command="{Binding SelectTabCommand}" CommandParameter="Jobs" />
|
||||
<ToggleButton Content="Dienste" Margin="0,0,-1,0"
|
||||
IsChecked="{Binding IsServicesTab, Mode=OneWay}"
|
||||
Command="{Binding SelectTabCommand}" CommandParameter="Services" />
|
||||
<ToggleButton Content="Verlauf"
|
||||
IsChecked="{Binding IsHistoryTab, Mode=OneWay}"
|
||||
Command="{Binding SelectTabCommand}" CommandParameter="History" />
|
||||
</StackPanel>
|
||||
|
||||
<TabControl>
|
||||
<!-- Statuszeile des Bereichs -->
|
||||
<TextBlock DockPanel.Dock="Bottom" Classes="caption" Margin="0,10,0,0"
|
||||
Text="{Binding StatusText}" TextWrapping="Wrap" />
|
||||
|
||||
<!-- TAB 1: Jobs (Scheduled / Worker) -->
|
||||
<TabItem Header="Geplante Jobs">
|
||||
<DockPanel Margin="0,8,0,0">
|
||||
<Panel>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<StackPanel Classes="toolbar" DockPanel.Dock="Top">
|
||||
<Button Content="Job hinzufügen" Command="{Binding AddJobCommand}" Classes="accent" />
|
||||
<Button Content="Bearbeiten" Command="{Binding EditJobCommand}" IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<Button Content="Entfernen" Command="{Binding RemoveJobCommand}" IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<Button Content="▶ Jetzt ausführen" Command="{Binding RunJobNowCommand}" IsEnabled="{Binding SelectedJob, Converter={x:Static ObjectConverters.IsNotNull}}" Margin="12,0,0,0" />
|
||||
<Button Content="Aktualisieren" Command="{Binding RefreshJobListCommand}" />
|
||||
</StackPanel>
|
||||
<!-- ══════════════════ Geplante Jobs ══════════════════ -->
|
||||
<DockPanel IsVisible="{Binding IsJobsTab}">
|
||||
|
||||
<!-- Jobs DataGrid -->
|
||||
<DataGrid ItemsSource="{Binding JobEntries}" SelectedItem="{Binding SelectedJob}" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="Horizontal">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Typ" Binding="{Binding JobType}" Width="120" />
|
||||
<DataGridTextColumn Header="Agent" Binding="{Binding AgentName}" Width="150" />
|
||||
<DataGridTextColumn Header="Tool / Nachricht" Binding="{Binding TaskMessage}" Width="*" />
|
||||
<DataGridTextColumn Header="Cron-Ausdruck" Binding="{Binding CronExpression}" Width="120" />
|
||||
<DataGridTextColumn Header="Nächster Lauf" Binding="{Binding NextRun}" Width="140" />
|
||||
<DataGridTextColumn Header="Letzter Lauf" Binding="{Binding LastRun}" Width="140" />
|
||||
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="100" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<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="Job hinzufügen" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
<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="Bearbeiten" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- TAB 2: Dienste (Services) -->
|
||||
<TabItem Header="Dienste (Services)">
|
||||
<DockPanel Margin="0,8,0,0">
|
||||
<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="Entfernen" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<StackPanel Classes="toolbar" DockPanel.Dock="Top">
|
||||
<Button Content="Dienst hinzufügen" Command="{Binding AddServiceCommand}" Classes="accent" />
|
||||
<Button Content="Entfernen" Command="{Binding RemoveServiceCommand}" IsEnabled="{Binding SelectedService, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<Button Content="Aktualisieren" Command="{Binding RefreshServiceListCommand}" />
|
||||
</StackPanel>
|
||||
<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="Aktivieren/Deaktivieren" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Services DataGrid -->
|
||||
<DataGrid ItemsSource="{Binding ServiceEntries}" SelectedItem="{Binding SelectedService}" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="Horizontal">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Dienstname" Binding="{Binding Name}" Width="180" />
|
||||
<DataGridTextColumn Header="Typ" Binding="{Binding Type}" Width="100" />
|
||||
<DataGridTextColumn Header="Port" Binding="{Binding Port}" Width="80" />
|
||||
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="110" />
|
||||
<DataGridTextColumn Header="Beschreibung" Binding="{Binding Description}" Width="*" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<Border Classes="sep" />
|
||||
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
<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="Jetzt ausführen" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- TAB 3: Verlauf (Job History) -->
|
||||
<TabItem Header="Verlauf (History)">
|
||||
<DockPanel Margin="0,8,0,0">
|
||||
<Button Classes="toolbar" Command="{Binding RefreshJobListCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
||||
<TextBlock Text="Aktualisieren" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</WrapPanel>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<StackPanel Classes="toolbar" DockPanel.Dock="Top">
|
||||
<Button Content="Verlauf aktualisieren" Command="{Binding RefreshJobHistoryCommand}" />
|
||||
</StackPanel>
|
||||
<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="TYP" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="AGENT" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="TOOL / NACHRICHT" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="CRON" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="NÄCHSTER LAUF" />
|
||||
<TextBlock Grid.Column="5" Classes="th" Text="LETZTER LAUF" />
|
||||
<TextBlock Grid.Column="6" Classes="th" Text="STATUS" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- History DataGrid -->
|
||||
<DataGrid ItemsSource="{Binding JobHistoryEntries}" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="Horizontal">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Zeitpunkt" Binding="{Binding Time, StringFormat='{}{0:g}'}" Width="140" />
|
||||
<DataGridTextColumn Header="Job-Name" Binding="{Binding JobName}" Width="140" />
|
||||
<DataGridTextColumn Header="Agent" Binding="{Binding Agent}" Width="140" />
|
||||
<DataGridTextColumn Header="Beschreibung" Binding="{Binding JobDescription}" Width="220" />
|
||||
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="100" />
|
||||
<DataGridTextColumn Header="Details / Info" Binding="{Binding Info}" Width="*" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<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}" />
|
||||
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
<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>
|
||||
|
||||
</TabControl>
|
||||
<!-- ══════════════════ 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="Dienst hinzufügen" />
|
||||
</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="Entfernen" />
|
||||
</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="Aktivieren/Deaktivieren" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Classes="toolbar" Command="{Binding RefreshServiceListCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
||||
<TextBlock Text="Aktualisieren" />
|
||||
</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="DIENSTNAME" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="TYP" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="PORT" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="STATUS" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="BESCHREIBUNG" />
|
||||
</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="Verlauf aktualisieren" />
|
||||
</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="ZEITPUNKT" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="JOB" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="AGENT" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="BESCHREIBUNG" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="STATUS" />
|
||||
<TextBlock Grid.Column="5" Classes="th" Text="DETAILS" />
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user