i18n: Englisch als Hauptsprache, Sprachpakete fuer Desktop und WebUI (#661)
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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
69718122f3
commit
ad71682c2d
@@ -111,6 +111,7 @@ public partial class App : Application
|
||||
_managed = CommandLine.IsManaged(desktop.Args);
|
||||
|
||||
ApplySavedThemeEarly();
|
||||
ApplySavedLanguageEarly();
|
||||
|
||||
desktop.ShutdownRequested += async (_, _) =>
|
||||
{
|
||||
@@ -156,6 +157,23 @@ public partial class App : Application
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setzt die gespeicherte Sprache, bevor das erste Fenster erscheint.
|
||||
/// </summary>
|
||||
private static void ApplySavedLanguageEarly()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = new SettingsManager();
|
||||
settings.Load();
|
||||
LocalizationManager.Instance.SetLanguage(settings.AppSettings.Language);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
LocalizationManager.Instance.SetLanguage(LocalizationManager.DefaultLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartAsync(IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var result = await AppHost.StartAsync(new AppHost.Callbacks
|
||||
@@ -183,6 +201,7 @@ public partial class App : Application
|
||||
}
|
||||
|
||||
_host = result.Host;
|
||||
LocalizationManager.Instance.SetLanguage(_host.Settings.AppSettings.Language);
|
||||
|
||||
HookErrorReporting(_host);
|
||||
HookLicenseWatch(_host, desktop);
|
||||
@@ -664,27 +683,28 @@ public partial class App : Application
|
||||
=> await Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
var completion = new TaskCompletionSource<StandaloneSwitchChoice>();
|
||||
var l = LocalizationManager.Instance;
|
||||
|
||||
var managerBtn = new Button
|
||||
{
|
||||
Content = "Instanzmanager starten (Empfohlen)",
|
||||
Content = l["desktop.startMode.managerBtn"],
|
||||
Classes = { "primary" }
|
||||
};
|
||||
|
||||
var switchBtn = new Button
|
||||
{
|
||||
Content = "Instanz trotzdem wechseln"
|
||||
Content = l["desktop.standaloneSwitch.switchAnyway"]
|
||||
};
|
||||
|
||||
var cancelBtn = new Button
|
||||
{
|
||||
Content = "Abbrechen",
|
||||
Content = l["common.cancel"],
|
||||
IsCancel = true
|
||||
};
|
||||
|
||||
var window = new Window
|
||||
{
|
||||
Title = "ClawdDotNet – Instanzwechsel (Standalone)",
|
||||
Title = l["desktop.standaloneSwitch.title"],
|
||||
Width = 540,
|
||||
SizeToContent = SizeToContent.Height,
|
||||
CanResize = false,
|
||||
@@ -698,15 +718,12 @@ public partial class App : Application
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = "Achtung: Standalone-Modus",
|
||||
Text = l["desktop.standaloneSwitch.warning"],
|
||||
Classes = { "h1" }
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = "Diese Instanz läuft eigenständig ohne Instanzmanager.\n\n"
|
||||
+ "Wenn du die Instanz hier wechselst, wird diese Instanz vollständig beendet "
|
||||
+ "und alle laufenden Agenten und Hintergrunddienste werden gestoppt.\n\n"
|
||||
+ "Empfehlung: Starte stattdessen den Instanzmanager, um mehrere Instanzen gleichzeitig und unabhängig voneinander zu betreiben.",
|
||||
Text = l["desktop.standaloneSwitch.text"],
|
||||
TextWrapping = TextWrapping.Wrap
|
||||
},
|
||||
new StackPanel
|
||||
@@ -752,27 +769,28 @@ public partial class App : Application
|
||||
=> await Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
var completion = new TaskCompletionSource<StartModeChoice>();
|
||||
var l = LocalizationManager.Instance;
|
||||
|
||||
var managerBtn = new Button
|
||||
{
|
||||
Content = "Instanzmanager starten (Empfohlen)",
|
||||
Content = l["desktop.startMode.managerBtn"],
|
||||
Classes = { "primary" }
|
||||
};
|
||||
|
||||
var standaloneBtn = new Button
|
||||
{
|
||||
Content = "Als Standalone-Instanz starten"
|
||||
Content = l["desktop.startMode.standaloneBtn"]
|
||||
};
|
||||
|
||||
var cancelBtn = new Button
|
||||
{
|
||||
Content = "Abbrechen",
|
||||
Content = l["common.cancel"],
|
||||
IsCancel = true
|
||||
};
|
||||
|
||||
var window = new Window
|
||||
{
|
||||
Title = "ClawdDotNet – Startmodus wählen",
|
||||
Title = l["desktop.startMode.title"],
|
||||
Width = 540,
|
||||
SizeToContent = SizeToContent.Height,
|
||||
CanResize = false,
|
||||
@@ -785,16 +803,12 @@ public partial class App : Application
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = "Wie möchtest du ClawdDotNet starten?",
|
||||
Text = l["desktop.startMode.question"],
|
||||
Classes = { "h1" }
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = "• Instanzmanager (Empfohlen):\n"
|
||||
+ " Startet den zentralen Hintergrund-Manager und öffnet die Verwaltung im Browser. "
|
||||
+ "Ermöglicht den stabilen Dauerbetrieb mehrerer Instanzen parallel ohne Absturzrisiko.\n\n"
|
||||
+ "• Standalone-Modus:\n"
|
||||
+ " Startet genau eine Instanz direkt als einzelnes Desktop-Fenster.",
|
||||
Text = l["desktop.startMode.explanation"],
|
||||
TextWrapping = TextWrapping.Wrap
|
||||
},
|
||||
new StackPanel
|
||||
@@ -948,7 +962,7 @@ public partial class App : Application
|
||||
var completion = new TaskCompletionSource<string>();
|
||||
|
||||
var input = new TextBox();
|
||||
var ok = new Button { Content = "OK", IsDefault = true };
|
||||
var ok = new Button { Content = LocalizationManager.Instance["common.ok"], IsDefault = true };
|
||||
|
||||
var window = new Window
|
||||
{
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
<BuiltInComInteropSupport>false</BuiltInComInteropSupport>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="ClawdDotNet.Desktop.Services" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="12.1.1" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="12.1.1" />
|
||||
@@ -38,6 +42,13 @@
|
||||
<Content Include="setup.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="i18n\*.json" />
|
||||
<None Update="i18n\*.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ClawdDotNet.App\ClawdDotNet.App.csproj" />
|
||||
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Services;
|
||||
|
||||
public sealed record LanguageOption(string Code, string Name)
|
||||
{
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages application localization for Avalonia UI.
|
||||
/// Supports JSON language packs with fallback to English, dynamic language switching,
|
||||
/// and live UI re-binding via indexer property notification.
|
||||
/// </summary>
|
||||
public sealed class LocalizationManager : INotifyPropertyChanged
|
||||
{
|
||||
public static LocalizationManager Instance { get; } = new();
|
||||
|
||||
public const string DefaultLanguage = "en";
|
||||
public const string FallbackLanguage = "en";
|
||||
|
||||
private readonly Dictionary<string, string> _fallbackStrings = new(StringComparer.OrdinalIgnoreCase);
|
||||
private Dictionary<string, string> _activeStrings = new(StringComparer.OrdinalIgnoreCase);
|
||||
private string _currentLanguage = DefaultLanguage;
|
||||
|
||||
public IReadOnlyList<LanguageOption> AvailableLanguages { get; } =
|
||||
[
|
||||
new("en", "English"),
|
||||
new("de", "Deutsch")
|
||||
];
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
public event Action? LanguageChanged;
|
||||
|
||||
public string CurrentLanguage
|
||||
{
|
||||
get => _currentLanguage;
|
||||
private set
|
||||
{
|
||||
if (_currentLanguage != value)
|
||||
{
|
||||
_currentLanguage = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[IndexerName("Item")]
|
||||
public string this[string key] => Get(key);
|
||||
|
||||
private LocalizationManager()
|
||||
{
|
||||
LoadFallbackPack();
|
||||
SetLanguage(DefaultLanguage);
|
||||
}
|
||||
|
||||
private void LoadFallbackPack()
|
||||
{
|
||||
_fallbackStrings.Clear();
|
||||
var json = LoadLanguageJson(FallbackLanguage);
|
||||
if (!string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
ParseJsonIntoDictionary(json, _fallbackStrings);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLanguage(string? languageCode)
|
||||
{
|
||||
var target = string.IsNullOrWhiteSpace(languageCode) ? DefaultLanguage : languageCode.Trim().ToLowerInvariant();
|
||||
|
||||
if (target == FallbackLanguage)
|
||||
{
|
||||
_activeStrings = _fallbackStrings;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pack = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
var json = LoadLanguageJson(target);
|
||||
if (!string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
ParseJsonIntoDictionary(json, pack);
|
||||
}
|
||||
_activeStrings = pack;
|
||||
}
|
||||
|
||||
CurrentLanguage = target;
|
||||
|
||||
// Notify indexer bindings so Avalonia refreshes all localized strings on screen
|
||||
OnPropertyChanged("Item");
|
||||
OnPropertyChanged("Item[]");
|
||||
LanguageChanged?.Invoke();
|
||||
}
|
||||
|
||||
public string Get(string key, params object[] args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return "";
|
||||
|
||||
string? template = null;
|
||||
if (!_activeStrings.TryGetValue(key, out template))
|
||||
{
|
||||
_fallbackStrings.TryGetValue(key, out template);
|
||||
}
|
||||
|
||||
template ??= key;
|
||||
|
||||
if (args.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(template, args);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
private static string? LoadLanguageJson(string langCode)
|
||||
{
|
||||
// 1. Try file on disk in AppContext.BaseDirectory/i18n/{langCode}.json
|
||||
var localPath = Path.Combine(AppContext.BaseDirectory, "i18n", $"{langCode}.json");
|
||||
if (File.Exists(localPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.ReadAllText(localPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fall through to embedded resource
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try embedded resource in ClawdDotNet assembly
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = assembly.GetManifestResourceNames()
|
||||
.FirstOrDefault(r => r.EndsWith($"i18n.{langCode}.json", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (resourceName is not null)
|
||||
{
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream is not null)
|
||||
{
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ParseJsonIntoDictionary(string json, Dictionary<string, string> dict)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
FlattenElement("", doc.RootElement, dict);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Invalid JSON ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static void FlattenElement(string prefix, JsonElement element, Dictionary<string, string> dict)
|
||||
{
|
||||
switch (element.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Object:
|
||||
foreach (var prop in element.EnumerateObject())
|
||||
{
|
||||
var childPrefix = string.IsNullOrEmpty(prefix) ? prop.Name : $"{prefix}.{prop.Name}";
|
||||
FlattenElement(childPrefix, prop.Value, dict);
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonValueKind.String:
|
||||
dict[prefix] = element.GetString() ?? "";
|
||||
break;
|
||||
|
||||
case JsonValueKind.Number:
|
||||
case JsonValueKind.True:
|
||||
case JsonValueKind.False:
|
||||
dict[prefix] = element.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Markup extension for Avalonia XAML:
|
||||
/// Usage: Text="{services:Localize nav.chat}"
|
||||
/// Updates automatically when language changes.
|
||||
/// </summary>
|
||||
public sealed class LocalizeExtension : MarkupExtension
|
||||
{
|
||||
public string Key { get; set; } = "";
|
||||
|
||||
public LocalizeExtension() { }
|
||||
|
||||
public LocalizeExtension(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
return new Binding($"[{Key}]")
|
||||
{
|
||||
Source = LocalizationManager.Instance,
|
||||
Mode = BindingMode.OneWay
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -47,13 +47,13 @@ public sealed partial class AddAgentViewModel : ViewModelBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(AgentId))
|
||||
{
|
||||
StatusMessage = "Bitte eine Agenten-ID eingeben.";
|
||||
StatusMessage = "Please enter an Agent ID.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(DisplayName))
|
||||
{
|
||||
StatusMessage = "Bitte einen Anzeigenamen eingeben.";
|
||||
StatusMessage = "Please enter a display name.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public sealed partial class AddJobViewModel : ViewModelBase
|
||||
private string _cronExpression = "0 * * * *";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _taskMessage = "Führe deine zugewiesenen Aufgaben aus.";
|
||||
private string _taskMessage = "Execute your assigned tasks.";
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _runOnStart;
|
||||
@@ -79,13 +79,13 @@ public sealed partial class AddJobViewModel : ViewModelBase
|
||||
{
|
||||
if (SelectedAgent is null)
|
||||
{
|
||||
StatusMessage = "Bitte einen Agenten auswählen.";
|
||||
StatusMessage = "Please select an agent.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(CronExpression))
|
||||
{
|
||||
StatusMessage = "Bitte einen Cron-Ausdruck angeben.";
|
||||
StatusMessage = "Please enter a cron expression.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,13 +38,13 @@ public sealed partial class AddServiceViewModel : ViewModelBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ServiceName))
|
||||
{
|
||||
StatusMessage = "Bitte einen Dienstnamen eingeben.";
|
||||
StatusMessage = "Please enter a service name.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServicePort <= 0 || ServicePort > 65535)
|
||||
{
|
||||
StatusMessage = "Gültigen Port zwischen 1 und 65535 eingeben.";
|
||||
StatusMessage = "Please enter a valid port between 1 and 65535.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public sealed partial class AgentChatsPageViewModel : PageViewModel
|
||||
|
||||
public AgentChatsPageViewModel() : this(null) { }
|
||||
|
||||
public AgentChatsPageViewModel(AppHost? host) : base("Agenten-Chats")
|
||||
public AgentChatsPageViewModel(AppHost? host) : base("nav.agentChats")
|
||||
{
|
||||
if (host is null)
|
||||
{
|
||||
@@ -85,10 +85,8 @@ public sealed partial class AgentChatsPageViewModel : PageViewModel
|
||||
Messages.Clear();
|
||||
|
||||
EmptyText = Agents.Count < 2
|
||||
? "Für einen Verlauf braucht es mindestens zwei Agenten in dieser Instanz."
|
||||
: "Noch keine Nachrichten aufgezeichnet. Agenten können sich bereits gegenseitig "
|
||||
+ "erreichen; mitgeschrieben wird der Wortlaut erst, wenn der Nachrichtenspeicher "
|
||||
+ "aus docs/Agentenkommunikation-Konzept.md steht.";
|
||||
? LocalizationManager.Instance["desktop.agentChats.needTwo"]
|
||||
: LocalizationManager.Instance["desktop.agentChats.empty"];
|
||||
|
||||
IsEmpty = Messages.Count == 0;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ClawdDotNet.Desktop.ViewModels;
|
||||
|
||||
public sealed partial class ToolItemViewModel : ObservableObject
|
||||
public sealed partial class ToolItemViewModel : ViewModelBase
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed partial class ToolItemViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class AgentItemViewModel : ObservableObject
|
||||
public sealed partial class AgentItemViewModel : ViewModelBase
|
||||
{
|
||||
public AgentConfig Config { get; }
|
||||
|
||||
@@ -210,7 +210,7 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
|
||||
public AgentsPageViewModel() : this(null) { }
|
||||
|
||||
public AgentsPageViewModel(AppHost? host) : base("Agenten")
|
||||
public AgentsPageViewModel(AppHost? host) : base("nav.agents")
|
||||
{
|
||||
_host = host;
|
||||
|
||||
@@ -233,8 +233,10 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "Entwurfsmodus";
|
||||
StatusText = LocalizationManager.Instance["desktop.status.design"];
|
||||
}
|
||||
|
||||
LocalizationManager.Instance.LanguageChanged += () => OnPropertyChanged(nameof(AllowedToolsHeader));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -274,11 +276,16 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
SelectedAgent = Agents.FirstOrDefault(a => a.AgentId == previous) ?? Agents.FirstOrDefault();
|
||||
}
|
||||
|
||||
public string AllowedToolsHeader => SelectedAgent is not null
|
||||
? LocalizationManager.Instance.Get("desktop.agents.allowedToolsFor", SelectedAgent.DisplayName)
|
||||
: "";
|
||||
|
||||
partial void OnSelectedAgentChanged(AgentItemViewModel? value)
|
||||
{
|
||||
// Die Werkzeugliste unten gehört zum gewählten Agenten — bei einem Wechsel darf
|
||||
// dort nicht die Auswahl des vorigen stehen bleiben.
|
||||
SelectedTool = value?.AvailableTools.FirstOrDefault();
|
||||
OnPropertyChanged(nameof(AllowedToolsHeader));
|
||||
}
|
||||
|
||||
partial void OnSelectedToolChanged(ToolItemViewModel? value)
|
||||
@@ -352,14 +359,14 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
|
||||
if (_host.Engine is null)
|
||||
{
|
||||
StatusText = "Agent-Engine ist nicht aktiv (kein API-Key).";
|
||||
StatusText = LocalizationManager.Instance["desktop.chat.noApiKey"];
|
||||
return;
|
||||
}
|
||||
|
||||
var config = SelectedAgent.Config;
|
||||
|
||||
IsRunning = true;
|
||||
StatusText = $"Führe '{config.DisplayName}' aus…";
|
||||
StatusText = $"Running '{config.DisplayName}'…";
|
||||
|
||||
try
|
||||
{
|
||||
@@ -369,7 +376,7 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
StatusText = outcome.Message;
|
||||
|
||||
if (!outcome.Ok)
|
||||
_logger?.LogWarning("Handlauf des Agenten fehlgeschlagen: {Grund}", outcome.Message);
|
||||
_logger?.LogWarning("Agent execution failed: {Reason}", outcome.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -394,8 +401,8 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
|
||||
var isIdentity = field == AgentTextField.Identity;
|
||||
var title = isIdentity
|
||||
? $"Identity bearbeiten — {SelectedAgent.DisplayName}"
|
||||
: $"Soul bearbeiten — {SelectedAgent.DisplayName}";
|
||||
? $"Edit Identity — {SelectedAgent.DisplayName}"
|
||||
: $"Edit Soul — {SelectedAgent.DisplayName}";
|
||||
|
||||
var current = isIdentity ? SelectedAgent.Identity : SelectedAgent.Soul;
|
||||
|
||||
@@ -418,7 +425,7 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
StatusText = $"Ordner nicht gefunden: {path}";
|
||||
StatusText = $"Folder not found: {path}";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -458,8 +465,8 @@ public sealed partial class AgentsPageViewModel : PageViewModel
|
||||
ApplyPendingEdits();
|
||||
_host.AgentAdmin.Save();
|
||||
|
||||
_logger?.LogInformation("Agenten-Konfiguration gespeichert.");
|
||||
StatusText = "Agenten-Konfiguration gespeichert.";
|
||||
_logger?.LogInformation("Agents configuration saved.");
|
||||
StatusText = LocalizationManager.Instance["desktop.agents.saved"];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -74,7 +74,7 @@ public sealed partial class BackupPageViewModel : PageViewModel
|
||||
private int _keepCount = 10;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _statusText = "Bereit";
|
||||
private string _statusText = LocalizationManager.Instance["common.ready"];
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isBusy;
|
||||
@@ -88,7 +88,7 @@ public sealed partial class BackupPageViewModel : PageViewModel
|
||||
|
||||
public BackupPageViewModel() : this(null) { }
|
||||
|
||||
public BackupPageViewModel(AppHost? host) : base("Sicherung")
|
||||
public BackupPageViewModel(AppHost? host) : base("nav.backup")
|
||||
{
|
||||
_host = host;
|
||||
|
||||
|
||||
@@ -35,11 +35,11 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
private bool _isSending;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _statusText = "Bereit";
|
||||
private string _statusText = "Ready";
|
||||
|
||||
public ChatPageViewModel() : this(null) { }
|
||||
|
||||
public ChatPageViewModel(AppHost? host) : base("Chat")
|
||||
public ChatPageViewModel(AppHost? host) : base("nav.chat")
|
||||
{
|
||||
_host = host;
|
||||
|
||||
@@ -57,7 +57,7 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "Entwurfsmodus";
|
||||
StatusText = "Design Mode";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,14 +77,14 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
var isUser = entry.Role.Equals("user", StringComparison.OrdinalIgnoreCase);
|
||||
ChatEntries.Add(new ChatEntryItemViewModel(
|
||||
entry.Role,
|
||||
isUser ? "Du" : SelectedAgent.DisplayName,
|
||||
isUser ? "You" : SelectedAgent.DisplayName,
|
||||
entry.Content,
|
||||
entry.Timestamp,
|
||||
isUser
|
||||
));
|
||||
}
|
||||
|
||||
StatusText = $"Chat-Verlauf für '{SelectedAgent.DisplayName}' geladen ({ChatEntries.Count} Nachrichten).";
|
||||
StatusText = $"Chat history for '{SelectedAgent.DisplayName}' loaded ({ChatEntries.Count} messages).";
|
||||
}
|
||||
|
||||
private void OnEngineChatEntryAdded(string agentId, string role, string text, string? toolName)
|
||||
@@ -94,7 +94,7 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
var isUser = role.Equals("user", StringComparison.OrdinalIgnoreCase);
|
||||
var sender = isUser ? "Du" : (string.IsNullOrWhiteSpace(toolName) ? SelectedAgent.DisplayName : $"Tool: {toolName}");
|
||||
var sender = isUser ? "You" : (string.IsNullOrWhiteSpace(toolName) ? SelectedAgent.DisplayName : $"Tool: {toolName}");
|
||||
|
||||
ChatEntries.Add(new ChatEntryItemViewModel(
|
||||
role, sender, text, DateTime.Now, isUser
|
||||
@@ -107,7 +107,7 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
{
|
||||
if (_host?.Engine is null || SelectedAgent is null)
|
||||
{
|
||||
StatusText = "Engine nicht aktiv oder kein Agent ausgewählt.";
|
||||
StatusText = "Engine not active or no agent selected.";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
|
||||
InputPrompt = "";
|
||||
IsSending = true;
|
||||
StatusText = $"{SelectedAgent.DisplayName} denkt nach…";
|
||||
StatusText = $"{SelectedAgent.DisplayName} is thinking…";
|
||||
|
||||
try
|
||||
{
|
||||
@@ -126,11 +126,11 @@ public sealed partial class ChatPageViewModel : PageViewModel
|
||||
var result = await Task.Run(() =>
|
||||
_host.Engine.ChatAsync(agent, text, instanceId, CancellationToken.None));
|
||||
|
||||
StatusText = $"{agent.DisplayName} fertig ({result.Status}, {result.TokensUsed:N0} Tokens).";
|
||||
StatusText = $"{agent.DisplayName} finished ({result.Status}, {result.TokensUsed:N0} tokens).";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText = $"Fehler: {ex.Message}";
|
||||
StatusText = $"Error: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed partial class InfoPageViewModel : PageViewModel
|
||||
|
||||
public InfoPageViewModel() : this(null) { }
|
||||
|
||||
public InfoPageViewModel(AppHost? host) : base("Info")
|
||||
public InfoPageViewModel(AppHost? host) : base("nav.info")
|
||||
{
|
||||
AppVersion = AppHost.AppVersion;
|
||||
BuildSummary = AppHost.BuildSummary;
|
||||
@@ -51,16 +51,16 @@ public sealed partial class InfoPageViewModel : PageViewModel
|
||||
InstancePath = host.InstancePath;
|
||||
LogDirectory = host.LogDirectory;
|
||||
OpenRouterStatus = host.Engine is null
|
||||
? "Deaktiviert (kein API-Key hinterlegt)"
|
||||
: "Aktiv (AgentEngine bereit)";
|
||||
? "Disabled (no API key configured)"
|
||||
: "Active (AgentEngine ready)";
|
||||
}
|
||||
else
|
||||
{
|
||||
InstanceName = "Entwurfsmodus";
|
||||
InstanceName = "Design Mode";
|
||||
InstanceId = "00000000-0000-0000-0000-000000000000";
|
||||
InstancePath = @"C:\ClawdDotNet\Instances\Default";
|
||||
LogDirectory = @"C:\ClawdDotNet\Logs";
|
||||
OpenRouterStatus = "Entwurf";
|
||||
OpenRouterStatus = "Design";
|
||||
}
|
||||
|
||||
LoadAssemblyBuildInfos();
|
||||
|
||||
@@ -28,10 +28,23 @@ public sealed class InstanceChoiceViewModel(InstanceInfo info, bool isCurrent)
|
||||
? Info.InstanceName[..2].ToUpperInvariant()
|
||||
: Info.InstanceName.ToUpperInvariant();
|
||||
|
||||
public string Summary => $"{Info.AgentCount} Agenten · API-Key {Info.ApiKeyStatus.ToLowerInvariant()}";
|
||||
public string Summary
|
||||
{
|
||||
get
|
||||
{
|
||||
var keyStatus = IsReady
|
||||
? LocalizationManager.Instance["desktop.instancePicker.apiKeyConfigured"]
|
||||
: LocalizationManager.Instance["desktop.instancePicker.apiKeyMissing"];
|
||||
return string.Format(
|
||||
LocalizationManager.Instance["desktop.instancePicker.agentsCount"],
|
||||
Info.AgentCount,
|
||||
keyStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Ohne API-Key kann die Instanz keine Agenten starten.</summary>
|
||||
public bool IsReady => Info.ApiKeyStatus.Equals("Konfiguriert", StringComparison.OrdinalIgnoreCase);
|
||||
public bool IsReady => Info.ApiKeyStatus.Equals("Konfiguriert", StringComparison.OrdinalIgnoreCase)
|
||||
|| Info.ApiKeyStatus.Equals("Configured", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>Die gerade laufende Instanz — traegt im Entwurf das Etikett „Aktiv".</summary>
|
||||
public bool IsCurrent { get; } = isCurrent;
|
||||
@@ -75,16 +88,19 @@ public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
/// </summary>
|
||||
public bool IsSwitchMode => _currentInstancePath is not null;
|
||||
|
||||
public string ConfirmLabel => IsSwitchMode ? "Wechseln" : "Starten";
|
||||
public string ConfirmLabel => IsSwitchMode
|
||||
? LocalizationManager.Instance["desktop.instancePicker.confirmSwitch"]
|
||||
: LocalizationManager.Instance["desktop.instancePicker.confirmStart"];
|
||||
|
||||
/// <summary>Ueberschrift des Dialogs — nicht aus ConfirmLabel zusammengesetzt,
|
||||
/// sonst stuende dort „Instanz Starten".</summary>
|
||||
public string Title => IsSwitchMode ? "Instanz wechseln" : "Instanz wählen";
|
||||
public string Title => IsSwitchMode
|
||||
? LocalizationManager.Instance["desktop.instancePicker.titleSwitch"]
|
||||
: LocalizationManager.Instance["desktop.instancePicker.titleSelect"];
|
||||
|
||||
public string Hint => IsSwitchMode
|
||||
? "Jede Instanz läuft unabhängig mit eigenen Agenten und Daten. "
|
||||
+ "Wechseln startet ClawdDotNet mit der gewählten Instanz neu."
|
||||
: "Jede Instanz läuft unabhängig mit eigenen Agenten und Daten.";
|
||||
? LocalizationManager.Instance["desktop.instancePicker.hintSwitch"]
|
||||
: LocalizationManager.Instance["desktop.instancePicker.hintSelect"];
|
||||
|
||||
/// <param name="currentInstancePath">
|
||||
/// Pfad der laufenden Instanz, oder <c>null</c> beim Start. Steuert Beschriftung und
|
||||
@@ -141,7 +157,7 @@ public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
ErrorText = "Bitte einen Instanznamen eingeben.";
|
||||
ErrorText = LocalizationManager.Instance["desktop.instancePicker.nameRequired"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,7 +175,9 @@ public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException
|
||||
or ArgumentException)
|
||||
{
|
||||
ErrorText = $"Instanz konnte nicht angelegt werden: {ex.Message}";
|
||||
ErrorText = string.Format(
|
||||
LocalizationManager.Instance["desktop.instancePicker.createFailed"],
|
||||
ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,15 +33,15 @@ public sealed partial class LogPageViewModel : PageViewModel
|
||||
|
||||
public ObservableCollection<LogLine> Lines { get; } = [];
|
||||
|
||||
public ObservableCollection<string> Modules { get; } = ["Alle"];
|
||||
public ObservableCollection<string> Modules { get; } = [LocalizationManager.Instance["common.all"]];
|
||||
|
||||
public IReadOnlyList<string> Levels { get; } = ["Alle", "Info", "Warn", "Error"];
|
||||
public IReadOnlyList<string> Levels { get; } = [LocalizationManager.Instance["common.all"], "Info", "Warn", "Error"];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _selectedModule = "Alle";
|
||||
private string _selectedModule = LocalizationManager.Instance["common.all"];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _selectedLevel = "Alle";
|
||||
private string _selectedLevel = LocalizationManager.Instance["common.all"];
|
||||
|
||||
/// <summary>
|
||||
/// Hängt die Ansicht am unteren Ende? Sobald jemand nach oben scrollt, soll nicht
|
||||
@@ -50,7 +50,7 @@ public sealed partial class LogPageViewModel : PageViewModel
|
||||
[ObservableProperty]
|
||||
private bool _followTail = true;
|
||||
|
||||
public LogPageViewModel(AppHost? host) : base("Logs")
|
||||
public LogPageViewModel(AppHost? host) : base("nav.logs")
|
||||
{
|
||||
_logDirectory = host?.LogDirectory ?? "";
|
||||
|
||||
@@ -68,7 +68,10 @@ public sealed partial class LogPageViewModel : PageViewModel
|
||||
{
|
||||
if (_tail is null) return;
|
||||
|
||||
var module = SelectedModule == "Alle" ? null : SelectedModule;
|
||||
var isAllModule = string.Equals(SelectedModule, LocalizationManager.Instance["common.all"], StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(SelectedModule, "All", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(SelectedModule, "Alle", StringComparison.OrdinalIgnoreCase);
|
||||
var module = isAllModule ? null : SelectedModule;
|
||||
var level = SelectedLevel switch
|
||||
{
|
||||
"Info" => LogLevelFilter.Info,
|
||||
@@ -96,15 +99,16 @@ public sealed partial class LogPageViewModel : PageViewModel
|
||||
if (_tail is null) return;
|
||||
|
||||
var current = SelectedModule;
|
||||
var allText = LocalizationManager.Instance["common.all"];
|
||||
|
||||
Modules.Clear();
|
||||
Modules.Add("Alle");
|
||||
Modules.Add(allText);
|
||||
|
||||
foreach (var module in _tail.AvailableModules())
|
||||
Modules.Add(module);
|
||||
|
||||
// Auswahl halten, wenn es das Modul noch gibt.
|
||||
SelectedModule = Modules.Contains(current) ? current : "Alle";
|
||||
SelectedModule = Modules.Contains(current) ? current : allText;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@@ -46,14 +46,19 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
// ─── Statusleiste ───
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(InstanceStatusLabel))]
|
||||
private string _instanceName = "—";
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isApiReachable;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ApiStatusDisplay))]
|
||||
private string _apiStatusText = "unbekannt";
|
||||
|
||||
public string InstanceStatusLabel => LocalizationManager.Instance.Get("desktop.mainWindow.instanceLabel", InstanceName);
|
||||
public string ApiStatusDisplay => LocalizationManager.Instance.Get("desktop.mainWindow.apiStatus", ApiStatusText);
|
||||
|
||||
/// <summary>Kurzinfo zu Tokens und Kosten der letzten Stunde bzw. 24 Stunden.</summary>
|
||||
[ObservableProperty]
|
||||
private string _usageText = "—";
|
||||
@@ -86,7 +91,9 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
|
||||
public string PageTitle => SelectedPage?.Title ?? "";
|
||||
|
||||
public string ThemeLabel => IsDarkTheme ? "Dunkelmodus" : "Hellmodus";
|
||||
public string ThemeLabel => IsDarkTheme
|
||||
? LocalizationManager.Instance["desktop.mainWindow.themeDark"]
|
||||
: LocalizationManager.Instance["desktop.mainWindow.themeLight"];
|
||||
|
||||
/// <summary>Fusszeile der Seitenleiste.</summary>
|
||||
public string VersionText => $"ClawdDotNet {AppHost.AppVersion} · Avalonia";
|
||||
@@ -128,20 +135,20 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
{ chat, agents, tasks, tokens, agentChats, backup, logs, settings, info })
|
||||
Pages.Add(page);
|
||||
|
||||
NavGroups.Add(new NavGroupViewModel("Arbeiten",
|
||||
NavGroups.Add(new NavGroupViewModel("desktop.nav.work",
|
||||
[
|
||||
new NavItemViewModel(this, chat, "IconChat"),
|
||||
new NavItemViewModel(this, agents, "IconAgents"),
|
||||
new NavItemViewModel(this, tasks, "IconTasks")
|
||||
]));
|
||||
|
||||
NavGroups.Add(new NavGroupViewModel("Analyse",
|
||||
NavGroups.Add(new NavGroupViewModel("desktop.nav.analytics",
|
||||
[
|
||||
new NavItemViewModel(this, tokens, "IconChart"),
|
||||
new NavItemViewModel(this, agentChats, "IconAgentChats")
|
||||
]));
|
||||
|
||||
NavGroups.Add(new NavGroupViewModel("System",
|
||||
NavGroups.Add(new NavGroupViewModel("desktop.nav.system",
|
||||
[
|
||||
new NavItemViewModel(this, backup, "IconBackup"),
|
||||
new NavItemViewModel(this, logs, "IconLogs"),
|
||||
@@ -149,6 +156,19 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
new NavItemViewModel(this, info, "IconInfo")
|
||||
]));
|
||||
|
||||
LocalizationManager.Instance.LanguageChanged += () =>
|
||||
{
|
||||
OnPropertyChanged(nameof(PageTitle));
|
||||
OnPropertyChanged(nameof(ThemeLabel));
|
||||
OnPropertyChanged(nameof(InstanceStatusLabel));
|
||||
OnPropertyChanged(nameof(ApiStatusDisplay));
|
||||
if (_host is null)
|
||||
{
|
||||
InstanceName = LocalizationManager.Instance["desktop.status.design"];
|
||||
ApiStatusText = LocalizationManager.Instance["desktop.status.design"];
|
||||
}
|
||||
};
|
||||
|
||||
// Die Leiste blendet sich aus, solange nichts anliegt — dafür muss die Ansicht
|
||||
// von Zu- und Abgängen erfahren, nicht nur von der Sammlung selbst.
|
||||
Notifications.CollectionChanged += (_, _) => OnPropertyChanged(nameof(HasNotifications));
|
||||
@@ -191,8 +211,8 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
if (host.Status is not { } status)
|
||||
{
|
||||
ApiStatusText = "kein API-Key";
|
||||
UsageText = "keine Nutzungsdaten";
|
||||
ApiStatusText = LocalizationManager.Instance["desktop.status.noApiKey"];
|
||||
UsageText = LocalizationManager.Instance["desktop.status.noUsageData"];
|
||||
CreditsText = "";
|
||||
return;
|
||||
}
|
||||
@@ -200,13 +220,15 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
void Update()
|
||||
{
|
||||
IsApiReachable = status.IsApiReachable;
|
||||
ApiStatusText = status.IsApiReachable ? "OK" : "nicht erreichbar";
|
||||
ApiStatusText = status.IsApiReachable
|
||||
? LocalizationManager.Instance["desktop.status.reachable"]
|
||||
: LocalizationManager.Instance["desktop.status.unreachable"];
|
||||
UsageText = status.CreditsText;
|
||||
UsageTooltip = status.CreditsTooltip;
|
||||
|
||||
CreditsText = status.CreditRemaining is { } remaining && status.CreditBalance is { } total
|
||||
? $"Credits: ${remaining:F2} von ${total:F2}"
|
||||
: "Credits: —";
|
||||
? LocalizationManager.Instance.Get("desktop.mainWindow.credits", remaining, total)
|
||||
: LocalizationManager.Instance["desktop.mainWindow.creditsNone"];
|
||||
}
|
||||
|
||||
status.OnStatusUpdated += () => Dispatcher.UIThread.Post(Update);
|
||||
@@ -294,15 +316,22 @@ public sealed partial class MainWindowViewModel : ViewModelBase
|
||||
}
|
||||
|
||||
/// <summary>Eine Gruppe der Navigation („Arbeiten", „Analyse", „System").</summary>
|
||||
public sealed partial class NavGroupViewModel(string title, IReadOnlyList<NavItemViewModel> items)
|
||||
: ObservableObject
|
||||
public sealed partial class NavGroupViewModel : ObservableObject
|
||||
{
|
||||
public string Title { get; } = title;
|
||||
public IReadOnlyList<NavItemViewModel> Items { get; } = items;
|
||||
private readonly string _titleKey;
|
||||
public string Title => LocalizationManager.Instance.Get(_titleKey);
|
||||
public IReadOnlyList<NavItemViewModel> Items { get; }
|
||||
|
||||
/// <summary>Im eingeklappten Zustand entfällt die Gruppenüberschrift.</summary>
|
||||
[ObservableProperty]
|
||||
private bool _isTitleVisible = true;
|
||||
|
||||
public NavGroupViewModel(string titleKey, IReadOnlyList<NavItemViewModel> items)
|
||||
{
|
||||
_titleKey = titleKey;
|
||||
Items = items;
|
||||
LocalizationManager.Instance.LanguageChanged += () => OnPropertyChanged(nameof(Title));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -313,14 +342,14 @@ public sealed partial class NavGroupViewModel(string title, IReadOnlyList<NavIte
|
||||
/// zwar, ist aber bei übersetzten Bindungen ein Ausdruck mit Typumwandlung, den man beim
|
||||
/// nächsten Lesen erst wieder entziffern muss.</para>
|
||||
/// </summary>
|
||||
public sealed partial class NavItemViewModel(
|
||||
MainWindowViewModel owner, PageViewModel page, string iconKey) : ObservableObject
|
||||
public sealed partial class NavItemViewModel : ObservableObject
|
||||
{
|
||||
public PageViewModel Page { get; } = page;
|
||||
private readonly MainWindowViewModel _owner;
|
||||
public PageViewModel Page { get; }
|
||||
public string Title => Page.Title;
|
||||
|
||||
/// <summary>Name der Geometrie in <c>Styles/Icons.axaml</c>.</summary>
|
||||
public string IconKey { get; } = iconKey;
|
||||
public string IconKey { get; }
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isSelected;
|
||||
@@ -328,8 +357,16 @@ public sealed partial class NavItemViewModel(
|
||||
[ObservableProperty]
|
||||
private bool _isCollapsed;
|
||||
|
||||
public NavItemViewModel(MainWindowViewModel owner, PageViewModel page, string iconKey)
|
||||
{
|
||||
_owner = owner;
|
||||
Page = page;
|
||||
IconKey = iconKey;
|
||||
LocalizationManager.Instance.LanguageChanged += () => OnPropertyChanged(nameof(Title));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Select() => owner.SelectedPage = Page;
|
||||
private void Select() => _owner.SelectedPage = Page;
|
||||
}
|
||||
|
||||
/// <summary>Eine Zeile der Benachrichtigungsleiste.</summary>
|
||||
@@ -346,7 +383,14 @@ public sealed partial class NotificationViewModel(
|
||||
}
|
||||
|
||||
/// <summary>Ein Bereich des Hauptfensters.</summary>
|
||||
public abstract partial class PageViewModel(string title) : ViewModelBase
|
||||
public abstract partial class PageViewModel : ViewModelBase
|
||||
{
|
||||
public string Title { get; } = title;
|
||||
private readonly string _titleKey;
|
||||
public string Title => LocalizationManager.Instance.Get(_titleKey);
|
||||
|
||||
protected PageViewModel(string titleKey)
|
||||
{
|
||||
_titleKey = titleKey;
|
||||
LocalizationManager.Instance.LanguageChanged += () => OnPropertyChanged(nameof(Title));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,15 @@ public sealed partial class RestoreBackupViewModel : ViewModelBase
|
||||
public bool NeedsPassphrase => _manifest.HasSecrets;
|
||||
|
||||
public string SecretsDescription => _manifest.HasSecrets
|
||||
? $"{_manifest.SecretCount}, mit Passphrase geschützt"
|
||||
? $"{_manifest.SecretCount}, passphrase protected"
|
||||
: _manifest.SecretCount > 0
|
||||
? $"{_manifest.SecretCount} entfernt"
|
||||
: "keine";
|
||||
? $"{_manifest.SecretCount} excluded"
|
||||
: "none";
|
||||
|
||||
public string InstanceInfoText => string.Format(L["desktop.dialog.backupInstance"], InstanceName);
|
||||
public string CreatedAtText => string.Format(L["desktop.dialog.backupCreated"], CreatedAt);
|
||||
public string FileCountText => string.Format(L["desktop.dialog.backupFiles"], FileCount);
|
||||
public string SecretsText => string.Format(L["desktop.dialog.backupSecrets"], SecretsDescription);
|
||||
|
||||
[ObservableProperty]
|
||||
private string _targetDirectory = "";
|
||||
@@ -50,13 +55,13 @@ public sealed partial class RestoreBackupViewModel : ViewModelBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(TargetDirectory))
|
||||
{
|
||||
StatusMessage = "Bitte einen Zielordner angeben.";
|
||||
StatusMessage = "Please specify a target directory.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (NeedsPassphrase && string.IsNullOrEmpty(Passphrase))
|
||||
{
|
||||
StatusMessage = "Bitte Passphrase für geschützte Zugangsdaten eingeben.";
|
||||
StatusMessage = "Please enter the passphrase for protected credentials.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using ClawdDotNet.App.Services;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ClawdDotNet.Desktop.Services;
|
||||
|
||||
namespace ClawdDotNet.Desktop.ViewModels;
|
||||
|
||||
@@ -107,13 +108,32 @@ public sealed partial class SettingsPageViewModel : PageViewModel
|
||||
[ObservableProperty]
|
||||
private string _statusText = "Bereit";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _selectedLanguage = LocalizationManager.DefaultLanguage;
|
||||
|
||||
public IReadOnlyList<LanguageOption> AvailableLanguages => LocalizationManager.Instance.AvailableLanguages;
|
||||
|
||||
public LanguageOption? SelectedLanguageOption
|
||||
{
|
||||
get => AvailableLanguages.FirstOrDefault(l => l.Code.Equals(SelectedLanguage, StringComparison.OrdinalIgnoreCase)) ?? AvailableLanguages.FirstOrDefault();
|
||||
set
|
||||
{
|
||||
if (value is not null && value.Code != SelectedLanguage)
|
||||
{
|
||||
SelectedLanguage = value.Code;
|
||||
OnPropertyChanged();
|
||||
LocalizationManager.Instance.SetLanguage(value.Code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> LogLevels { get; } = ["Debug", "Info", "Warn", "Error"];
|
||||
public List<string> UpdateChannels { get; } = ["prod", "beta", "dev"];
|
||||
public List<string> Environments { get; } = ["production", "development", "staging"];
|
||||
|
||||
public SettingsPageViewModel() : this(null) { }
|
||||
|
||||
public SettingsPageViewModel(AppHost? host) : base("Einstellungen")
|
||||
public SettingsPageViewModel(AppHost? host) : base("nav.settings")
|
||||
{
|
||||
_host = host;
|
||||
|
||||
@@ -124,7 +144,7 @@ public sealed partial class SettingsPageViewModel : PageViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "Entwurfsmodus";
|
||||
StatusText = LocalizationManager.Instance["desktop.status.design"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +167,8 @@ public sealed partial class SettingsPageViewModel : PageViewModel
|
||||
UpdateCheckEnabled = s.UpdateCheckEnabled;
|
||||
UpdateChannel = s.UpdateChannel;
|
||||
LicenseKey = s.LicenseKey;
|
||||
SelectedLanguage = s.Language ?? LocalizationManager.DefaultLanguage;
|
||||
OnPropertyChanged(nameof(SelectedLanguageOption));
|
||||
|
||||
var inst = _host.Instance;
|
||||
InstanceName = inst.InstanceName;
|
||||
@@ -177,8 +199,10 @@ public sealed partial class SettingsPageViewModel : PageViewModel
|
||||
s.UpdateCheckEnabled = UpdateCheckEnabled;
|
||||
s.UpdateChannel = UpdateChannel;
|
||||
s.LicenseKey = LicenseKey.Trim();
|
||||
s.Language = SelectedLanguage;
|
||||
|
||||
_host.Settings.Save();
|
||||
LocalizationManager.Instance.SetLanguage(SelectedLanguage);
|
||||
|
||||
var inst = _host.Instance;
|
||||
inst.InstanceName = InstanceName.Trim();
|
||||
@@ -190,13 +214,13 @@ public sealed partial class SettingsPageViewModel : PageViewModel
|
||||
|
||||
_host.SaveInstance(new InstanceChange(InstanceChangeKind.Settings));
|
||||
|
||||
_logger?.LogInformation("Einstellungen und Instanz-Konfiguration gespeichert.");
|
||||
_logger?.LogInformation("Settings and instance configuration saved.");
|
||||
|
||||
// Das Protokoll-Verzeichnis greift erst beim naechsten Start: Die
|
||||
// Protokollierung steht seit dem Aufbau des AppHost und schreibt bereits.
|
||||
StatusText = string.Equals(inst.LogDirectory, _logDirectoryAtLoad, StringComparison.Ordinal)
|
||||
? "Einstellungen erfolgreich gespeichert."
|
||||
: "Gespeichert. Das Protokoll-Verzeichnis gilt ab dem nächsten Start.";
|
||||
? LocalizationManager.Instance["desktop.settings.saved"]
|
||||
: LocalizationManager.Instance["desktop.settings.savedLogRestart"];
|
||||
|
||||
_logDirectoryAtLoad = inst.LogDirectory;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public sealed partial class TasksPageViewModel : PageViewModel
|
||||
|
||||
public TasksPageViewModel() : this(null) { }
|
||||
|
||||
public TasksPageViewModel(AppHost? host) : base("Aufgaben")
|
||||
public TasksPageViewModel(AppHost? host) : base("nav.tasks")
|
||||
{
|
||||
_host = host;
|
||||
|
||||
@@ -122,7 +122,7 @@ public sealed partial class TasksPageViewModel : PageViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "Entwurfsmodus";
|
||||
StatusText = LocalizationManager.Instance["desktop.status.design"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,15 +73,15 @@ public sealed partial class TokenUsagePageViewModel : PageViewModel
|
||||
|
||||
public TokenUsagePageViewModel() : this(null) { }
|
||||
|
||||
public TokenUsagePageViewModel(AppHost? host) : base("Tokennutzung")
|
||||
public TokenUsagePageViewModel(AppHost? host) : base("nav.usage")
|
||||
{
|
||||
_host = host;
|
||||
|
||||
if (host?.Usage is null)
|
||||
{
|
||||
StatusText = host is null
|
||||
? "Entwurfsmodus"
|
||||
: "Keine Verbrauchsdatenbank für diese Instanz.";
|
||||
? "Design mode"
|
||||
: "No usage database for this instance.";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ public sealed partial class TokenUsagePageViewModel : PageViewModel
|
||||
TotalRuns = daily.Sum(d => d.RunCount).ToString("N0");
|
||||
|
||||
IsEmpty = tokens == 0 && runs.Count == 0;
|
||||
StatusText = IsEmpty ? "In den letzten sieben Tagen ist kein Lauf verzeichnet." : "";
|
||||
StatusText = IsEmpty ? LocalizationManager.Instance["desktop.usage.empty"] : "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using ClawdDotNet.Desktop.Services;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace ClawdDotNet.Desktop.ViewModels;
|
||||
@@ -11,5 +12,11 @@ namespace ClawdDotNet.Desktop.ViewModels;
|
||||
/// mit Benachrichtigung. Das spart gegenüber der WinForms-Fassung, in der die
|
||||
/// Oberfläche bei jeder Änderung von Hand nachgezogen wurde
|
||||
/// (38 Stellen mit <c>Invoke</c>/<c>BeginInvoke</c>).
|
||||
///
|
||||
/// <para><see cref="L"/> macht die Sprachpakete in jeder Ansicht als
|
||||
/// <c>{Binding L[schluessel]}</c> erreichbar.</para>
|
||||
/// </summary>
|
||||
public abstract class ViewModelBase : ObservableObject;
|
||||
public abstract class ViewModelBase : ObservableObject
|
||||
{
|
||||
public LocalizationManager L => LocalizationManager.Instance;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Padding="16"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
Title="Neuen Agenten anlegen"
|
||||
Title="{Binding L[desktop.dialog.addAgent]}"
|
||||
x:Class="ClawdDotNet.Desktop.Views.AddAgentWindow"
|
||||
x:DataType="vm:AddAgentViewModel">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
<!-- Bottom Buttons -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="8" Margin="0,16,0,0">
|
||||
<Button Content="Abbrechen" Command="{Binding CancelCommand}" />
|
||||
<Button Content="Anlegen" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
<Button Content="{Binding L[common.cancel]}" Command="{Binding CancelCommand}" />
|
||||
<Button Content="{Binding L[common.create]}" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock DockPanel.Dock="Bottom" Text="{Binding StatusMessage}" Foreground="Red" Margin="0,8,0,0" />
|
||||
@@ -25,23 +25,23 @@
|
||||
<StackPanel Spacing="12">
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Agent-ID (eindeutiger Schlüssel):" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.agentId]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding AgentId}" PlaceholderText="z.B. dev-assistant" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Anzeigename:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.agentDisplayName]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding DisplayName}" PlaceholderText="z.B. Dev Assistant" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Standard-Modell:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.defaultModel]}" FontWeight="Bold" />
|
||||
<ComboBox ItemsSource="{Binding AvailableModels}" SelectedItem="{Binding SelectedModel}" HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Beschreibung / Rolle:" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding Description}" PlaceholderText="Kurze Beschreibung der Rolle..." AcceptsReturn="True" Height="60" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.roleDescription]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding Description}" PlaceholderText="Role description..." AcceptsReturn="True" Height="60" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Padding="16"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
Title="Job hinzufügen / bearbeiten"
|
||||
Title="{Binding L[desktop.dialog.addJobTitle]}"
|
||||
x:Class="ClawdDotNet.Desktop.Views.AddJobWindow"
|
||||
x:DataType="vm:AddJobViewModel">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
<!-- Bottom Buttons -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="8" Margin="0,16,0,0">
|
||||
<Button Content="Abbrechen" Command="{Binding CancelCommand}" />
|
||||
<Button Content="Speichern" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
<Button Content="{Binding L[common.cancel]}" Command="{Binding CancelCommand}" />
|
||||
<Button Content="{Binding L[common.save]}" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock DockPanel.Dock="Bottom" Text="{Binding StatusMessage}" Foreground="Red" Margin="0,8,0,0" />
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<!-- Agent Selection -->
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Agent:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.tasks.thAgent]}" FontWeight="Bold" />
|
||||
<ComboBox ItemsSource="{Binding AvailableAgents}" SelectedItem="{Binding SelectedAgent}" HorizontalAlignment="Stretch">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -39,38 +39,38 @@
|
||||
|
||||
<!-- Job Type RadioButtons -->
|
||||
<StackPanel Spacing="4" Margin="0,4,0,0">
|
||||
<TextBlock Text="Job-Typ:" FontWeight="Bold" />
|
||||
<RadioButton Content="Agent Wakeup (Periodische Ausführung)" IsChecked="{Binding IsAgentWakeup}" />
|
||||
<RadioButton Content="Tool Job (Werkzeug-spezifischer Job)" IsChecked="{Binding IsToolJob}" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.jobType]}" FontWeight="Bold" />
|
||||
<RadioButton Content="{Binding L[desktop.dialog.agentWakeup]}" IsChecked="{Binding IsAgentWakeup}" />
|
||||
<RadioButton Content="{Binding L[desktop.dialog.toolJob]}" IsChecked="{Binding IsToolJob}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Tool Job Details -->
|
||||
<StackPanel Spacing="8" IsVisible="{Binding IsToolJob}" Margin="12,4,0,0">
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Tool:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.thTool]}" FontWeight="Bold" />
|
||||
<ComboBox ItemsSource="{Binding AvailableTools}" SelectedItem="{Binding SelectedToolName}" HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Job-Typ-ID / Name:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.jobTypeId]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding JobTypeId}" PlaceholderText="z.B. PollMail" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Agent Wakeup Details -->
|
||||
<StackPanel Spacing="4" IsVisible="{Binding IsAgentWakeup}">
|
||||
<TextBlock Text="Aufgabenbeschreibung / Nachricht:" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding TaskMessage}" PlaceholderText="Nachricht an den Agenten..." AcceptsReturn="True" Height="60" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.taskMessage]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding TaskMessage}" PlaceholderText="Message to agent..." AcceptsReturn="True" Height="60" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Cron & Options -->
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Cron-Ausdruck:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.cronExpression]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding CronExpression}" PlaceholderText="0 * * * *" />
|
||||
<TextBlock Text="Syntax: Min Std Tag Mon Wochentag (z.B. '*/15 * * * *' alle 15 Minuten)" Classes="caption" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.cronHint]}" Classes="caption" />
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Content="Beim Anwendungsstart einmalig sofort ausführen" IsChecked="{Binding RunOnStart}" Margin="0,4,0,0" />
|
||||
<CheckBox Content="{Binding L[desktop.dialog.runOnStart]}" IsChecked="{Binding RunOnStart}" Margin="0,4,0,0" />
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Padding="16"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
Title="Dienst (Service) hinzufügen"
|
||||
Title="{Binding L[desktop.dialog.addServiceTitle]}"
|
||||
x:Class="ClawdDotNet.Desktop.Views.AddServiceWindow"
|
||||
x:DataType="vm:AddServiceViewModel">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
<!-- Bottom Buttons -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="8" Margin="0,16,0,0">
|
||||
<Button Content="Abbrechen" Command="{Binding CancelCommand}" />
|
||||
<Button Content="Hinzufügen" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
<Button Content="{Binding L[common.cancel]}" Command="{Binding CancelCommand}" />
|
||||
<Button Content="{Binding L[common.add]}" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock DockPanel.Dock="Bottom" Text="{Binding StatusMessage}" Foreground="Red" Margin="0,8,0,0" />
|
||||
@@ -25,25 +25,25 @@
|
||||
<StackPanel Spacing="12">
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Name des Dienstes:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.serviceName]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding ServiceName}" PlaceholderText="z.B. WebHookService" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto">
|
||||
<StackPanel Grid.Column="0" Spacing="4" Margin="0,0,4,0">
|
||||
<TextBlock Text="Typ:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.serviceType]}" FontWeight="Bold" />
|
||||
<ComboBox ItemsSource="{Binding AvailableServiceTypes}" SelectedItem="{Binding ServiceType}" HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1" Spacing="4" Margin="4,0,0,0">
|
||||
<TextBlock Text="Port:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.servicePort]}" FontWeight="Bold" />
|
||||
<NumericUpDown Value="{Binding ServicePort}" Minimum="1" Maximum="65535" FormatString="0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Beschreibung:" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding ServiceDescription}" PlaceholderText="Optionale Beschreibung..." AcceptsReturn="True" Height="60" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.serviceDesc]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding ServiceDescription}" PlaceholderText="Service description..." AcceptsReturn="True" Height="60" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
<!-- Wer mit wem -->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="10"
|
||||
Margin="0,0,0,16" VerticalAlignment="Center">
|
||||
<TextBlock Text="Agent A:" FontWeight="SemiBold" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding L[desktop.agentChats.agentA]}" FontWeight="SemiBold" VerticalAlignment="Center" />
|
||||
<ComboBox Width="220" ItemsSource="{Binding Agents}" SelectedItem="{Binding AgentA}" />
|
||||
|
||||
<TextBlock Text="Agent B:" FontWeight="SemiBold" VerticalAlignment="Center"
|
||||
<TextBlock Text="{Binding L[desktop.agentChats.agentB]}" FontWeight="SemiBold" VerticalAlignment="Center"
|
||||
Margin="8,0,0,0" />
|
||||
<ComboBox Width="220" ItemsSource="{Binding Agents}" SelectedItem="{Binding AgentB}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<Button Classes="toolbar" Command="{Binding AddAgentCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconPlus}" Width="14" Height="14" />
|
||||
<TextBlock Text="Agent" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.addAgent]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconMinus}" Width="14" Height="14" />
|
||||
<TextBlock Text="Agent" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.removeAgent]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
IsEnabled="{Binding !IsRunning}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconPlay}" Width="12" Height="12" IsFilled="True" />
|
||||
<TextBlock Text="Jetzt ausf." />
|
||||
<TextBlock Text="{Binding L[desktop.agents.runNow]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconPencil}" Width="14" Height="14" />
|
||||
<TextBlock Text="Identity" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.identity]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconPencil}" Width="14" Height="14" />
|
||||
<TextBlock Text="Soul" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.soul]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -80,23 +80,23 @@
|
||||
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconFolder}" Width="14" Height="14" />
|
||||
<TextBlock Text="Ordner" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.folder]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Classes="toolbar" Command="{Binding SaveAgentsCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconSave}" Width="14" Height="14" />
|
||||
<TextBlock Text="Speichern" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.save]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</WrapPanel>
|
||||
|
||||
<Border DockPanel.Dock="Top" Classes="thead">
|
||||
<Grid ColumnDefinitions="1.4*,1.6*,2*">
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="ANZEIGENAME" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="MODELL" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="KURZINFO" />
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.agents.thDisplayName]}" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.agents.thModel]}" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.agents.thSummary]}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -128,29 +128,29 @@
|
||||
<StackPanel Spacing="20" MaxWidth="640" HorizontalAlignment="Left">
|
||||
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Classes="kicker" Text="ALLGEMEIN & MODELL" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.agents.kickerGeneralModel]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding DisplayName}" />
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Agent-ID" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.agentId]}" />
|
||||
<TextBox Text="{Binding AgentId}" IsReadOnly="True" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Anzeigename" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.displayName]}" />
|
||||
<TextBox Text="{Binding DisplayName}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Modell" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.model]}" />
|
||||
<ComboBox HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).KnownModels}"
|
||||
SelectedItem="{Binding Model}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Prompt Caching" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.promptCaching]}" />
|
||||
<ComboBox HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).CachingOptions}"
|
||||
SelectedItem="{Binding PromptCaching}" />
|
||||
@@ -158,13 +158,13 @@
|
||||
</Grid>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Rolle / Beschreibung" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.roleDescription]}" />
|
||||
<TextBox Text="{Binding Description}" AcceptsReturn="True" Height="54"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="System-Prompt (zusätzliche Anweisungen)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.systemPrompt]}" />
|
||||
<TextBox Text="{Binding SystemPrompt}" AcceptsReturn="True" Height="70"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
@@ -173,38 +173,38 @@
|
||||
<Border Classes="hr" />
|
||||
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Classes="kicker" Text="GRENZEN" />
|
||||
<TextBlock Classes="h2" Text="Schutzgrenzen (LoopGuard & Budget)" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.agents.kickerLimits]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.agents.limitsTitle]}" />
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Max. Schritte pro Run" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.maxSteps]}" />
|
||||
<TextBox Text="{Binding MaxSteps}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Timeout (Sekunden)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.timeoutSeconds]}" />
|
||||
<TextBox Text="{Binding TimeoutSeconds}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Max. Kontext-Tokens" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.maxContextTokens]}" />
|
||||
<TextBox Text="{Binding MaxContextTokens}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Max. Tool-Ergebnis (Zeichen)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.maxToolResultChars]}" />
|
||||
<TextBox Text="{Binding MaxToolResultChars}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Tagesbudget ($ USD)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.dailyCost]}" />
|
||||
<TextBox Text="{Binding DailyCostUsd}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Tagesbudget (Tokens)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.agents.dailyTokens]}" />
|
||||
<TextBox Text="{Binding DailyTokens}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -225,13 +225,12 @@
|
||||
|
||||
<DockPanel Grid.Column="0" Margin="0,0,14,0">
|
||||
<TextBlock DockPanel.Dock="Top" Classes="kicker" Margin="0,4,0,8"
|
||||
Text="{Binding SelectedAgent.DisplayName,
|
||||
StringFormat='ZUGELASSENE WERKZEUGE FÜR {0}'}" />
|
||||
Text="{Binding AllowedToolsHeader}" />
|
||||
|
||||
<Border DockPanel.Dock="Top" Classes="thead">
|
||||
<Grid ColumnDefinitions="36,1.4*,2.4*">
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="WERKZEUG" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="BESCHREIBUNG" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.agents.thTool]}" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.agents.thDescription]}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -258,7 +257,7 @@
|
||||
|
||||
<DockPanel Grid.Column="2" Margin="4,0,0,0">
|
||||
<StackPanel DockPanel.Dock="Top" Spacing="2" Margin="0,4,0,10">
|
||||
<TextBlock Classes="kicker" Text="WERKZEUG-EINSTELLUNGEN" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.agents.toolSettingsKicker]}" />
|
||||
<DockPanel>
|
||||
<TextBlock Classes="h2" VerticalAlignment="Center"
|
||||
Text="{Binding SelectedTool.Name}" />
|
||||
@@ -267,7 +266,7 @@
|
||||
IsEnabled="{Binding ToolSettings, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconSave}" Width="14" Height="14" />
|
||||
<TextBlock Text="Übernehmen" />
|
||||
<TextBlock Text="{Binding L[desktop.agents.apply]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</DockPanel>
|
||||
|
||||
@@ -18,41 +18,41 @@
|
||||
|
||||
<!-- ══════════════════ Manuell ══════════════════ -->
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Classes="kicker" Text="MANUELL" />
|
||||
<TextBlock Classes="h2" Text="Sicherung erstellen" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.backup.kickerManual]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.backup.titleCreate]}" />
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto" VerticalAlignment="Bottom">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Zielordner" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.backup.targetFolder]}" />
|
||||
<TextBox Text="{Binding TargetFolder}"
|
||||
PlaceholderText="Zielordner für Sicherungen…" />
|
||||
PlaceholderText="{Binding L[desktop.backup.targetFolderPlaceholder]}" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1" Content="Durchsuchen…" Click="OnBrowseTargetFolder"
|
||||
<Button Grid.Column="1" Content="{Binding L[desktop.backup.browse]}" Click="OnBrowseTargetFolder"
|
||||
Margin="8,0,0,0" VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Classes="label" Text="Zugangsdaten" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.backup.credentials]}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="18">
|
||||
<RadioButton GroupName="secrets" Content="nicht mitsichern"
|
||||
<RadioButton GroupName="secrets" Content="{Binding L[desktop.backup.credentialsExclude]}"
|
||||
IsChecked="{Binding SecretsExclude}" />
|
||||
<RadioButton GroupName="secrets" Content="mit Passphrase schützen"
|
||||
<RadioButton GroupName="secrets" Content="{Binding L[desktop.backup.credentialsProtect]}"
|
||||
IsChecked="{Binding SecretsPassphrase}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="8" Margin="24,0,0,0" IsVisible="{Binding SecretsPassphrase}">
|
||||
<TextBox Text="{Binding Passphrase}" PasswordChar="•" Width="320"
|
||||
HorizontalAlignment="Left" PlaceholderText="Passphrase eingeben" />
|
||||
HorizontalAlignment="Left" PlaceholderText="{Binding L[desktop.backup.passphrase]}" />
|
||||
<TextBox Text="{Binding PassphraseRepeat}" PasswordChar="•" Width="320"
|
||||
HorizontalAlignment="Left" PlaceholderText="Passphrase wiederholen" />
|
||||
HorizontalAlignment="Left" PlaceholderText="{Binding L[desktop.backup.passphraseRepeat]}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Classes="label" Text="Umfang" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.backup.scope]}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="18">
|
||||
<CheckBox Content="Chatverläufe" IsChecked="{Binding IncludeChatHistory}" />
|
||||
<CheckBox Content="Protokolle" IsChecked="{Binding IncludeLogs}" />
|
||||
<CheckBox Content="{Binding L[desktop.backup.scopeChat]}" IsChecked="{Binding IncludeChatHistory}" />
|
||||
<CheckBox Content="{Binding L[desktop.backup.scopeLogs]}" IsChecked="{Binding IncludeLogs}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
Command="{Binding CreateBackupCommand}" IsEnabled="{Binding !IsBusy}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconPlay}" Width="12" Height="12" IsFilled="True" />
|
||||
<TextBlock Text="Sicherung jetzt erstellen" />
|
||||
<TextBlock Text="{Binding L[desktop.backup.createNow]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
@@ -69,36 +69,36 @@
|
||||
|
||||
<!-- ══════════════════ Automatik ══════════════════ -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Classes="kicker" Text="AUTOMATIK" />
|
||||
<TextBlock Classes="h2" Text="Automatische Sicherung" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.backup.kickerAuto]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.backup.titleAuto]}" />
|
||||
|
||||
<CheckBox Content="täglich sichern um" IsChecked="{Binding AutoBackupEnabled}" />
|
||||
<CheckBox Content="{Binding L[desktop.backup.autoDaily]}" IsChecked="{Binding AutoBackupEnabled}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="24" Margin="24,0,0,0"
|
||||
IsEnabled="{Binding AutoBackupEnabled}">
|
||||
<StackPanel Width="100">
|
||||
<TextBlock Classes="label" Text="Uhrzeit" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.backup.time]}" />
|
||||
<TextBox Text="{Binding AutoBackupTime}" PlaceholderText="03:00" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Width="160">
|
||||
<TextBlock Classes="label" Text="Aufbewahren" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.backup.keep]}" />
|
||||
<TextBox Text="{Binding KeepCount}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Classes="caption" Margin="24,0,0,0" TextWrapping="Wrap"
|
||||
Text="Die Automatik sichert ohne Zugangsdaten — eine gespeicherte Passphrase wäre wirkungslos." />
|
||||
Text="{Binding L[desktop.backup.autoHint]}" />
|
||||
</StackPanel>
|
||||
|
||||
<Border Classes="hr" />
|
||||
|
||||
<!-- ══════════════════ Bestand ══════════════════ -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Classes="kicker" Text="BESTAND" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.backup.kickerExisting]}" />
|
||||
|
||||
<DockPanel>
|
||||
<TextBlock Classes="h2" Text="Vorhandene Sicherungen" VerticalAlignment="Center" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.backup.titleExisting]}" VerticalAlignment="Center" />
|
||||
|
||||
<!-- Mindestabstand zur Ueberschrift links. Vorher stand hier Margin="0" und
|
||||
der Zwischenraum entstand nur, wenn das Fenster breit genug war; bei
|
||||
@@ -106,15 +106,15 @@
|
||||
beruehrte die Schaltflaeche "Aktualisieren". -->
|
||||
<WrapPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Classes="toolbar"
|
||||
Margin="16,0,0,0">
|
||||
<Button Classes="toolbar" Content="Aktualisieren"
|
||||
<Button Classes="toolbar" Content="{Binding L[desktop.backup.refresh]}"
|
||||
Command="{Binding RefreshBackupListCommand}" />
|
||||
<Button Classes="toolbar" Content="Ordner öffnen"
|
||||
<Button Classes="toolbar" Content="{Binding L[desktop.backup.openFolder]}"
|
||||
Command="{Binding ShowSelectedInFolderCommand}"
|
||||
IsEnabled="{Binding SelectedBackup, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<Button Classes="toolbar" Content="Löschen"
|
||||
<Button Classes="toolbar" Content="{Binding L[desktop.backup.delete]}"
|
||||
Command="{Binding DeleteSelectedCommand}"
|
||||
IsEnabled="{Binding SelectedBackup, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
<Button Classes="toolbar primary" Content="Wiederherstellen…"
|
||||
<Button Classes="toolbar primary" Content="{Binding L[desktop.backup.restore]}"
|
||||
Command="{Binding RestoreSelectedCommand}"
|
||||
IsEnabled="{Binding SelectedBackup, Converter={x:Static ObjectConverters.IsNotNull}}" />
|
||||
</WrapPanel>
|
||||
@@ -122,11 +122,11 @@
|
||||
|
||||
<Border Classes="thead">
|
||||
<Grid ColumnDefinitions="2.6*,1.5*,1.3*,0.9*,1.3*">
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="DATEINAME" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="ERSTELLT AM" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="INSTANZ" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="GRÖSSE" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="ZUGANGSDATEN" />
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.backup.thFilename]}" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.backup.thCreatedAt]}" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.backup.thInstance]}" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="{Binding L[desktop.backup.thSize]}" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="{Binding L[desktop.backup.thSecrets]}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<!-- Agentenauswahl und Verlaufsbefehle -->
|
||||
<StackPanel DockPanel.Dock="Top" Classes="toolbar" Margin="0,0,0,16">
|
||||
<TextBlock Text="Agent:" FontWeight="SemiBold" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding L[desktop.chat.agent]}" FontWeight="SemiBold" VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding AvailableAgents}" SelectedItem="{Binding SelectedAgent}"
|
||||
Width="220">
|
||||
<ComboBox.ItemTemplate>
|
||||
@@ -28,14 +28,14 @@
|
||||
<Button Classes="toolbar" Command="{Binding ClearHistoryCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconTrash}" Width="14" Height="14" />
|
||||
<TextBlock Text="Verlauf leeren" />
|
||||
<TextBlock Text="{Binding L[desktop.chat.clearHistory]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Classes="toolbar" Command="{Binding AbortCommand}" IsEnabled="{Binding IsSending}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconStop}" Width="12" Height="12" IsFilled="True" />
|
||||
<TextBlock Text="Abbrechen" />
|
||||
<TextBlock Text="{Binding L[desktop.chat.abort]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
@@ -47,11 +47,11 @@
|
||||
<!-- Eingabe -->
|
||||
<Grid DockPanel.Dock="Bottom" ColumnDefinitions="*,Auto" Margin="0,12,0,0">
|
||||
<TextBox Grid.Column="0" Text="{Binding InputPrompt}"
|
||||
PlaceholderText="Nachricht eingeben… (Strg+Eingabe zum Senden)"
|
||||
PlaceholderText="{Binding L[desktop.chat.inputPlaceholder]}"
|
||||
AcceptsReturn="True" Height="60" TextWrapping="Wrap"
|
||||
KeyDown="OnInputKeyDown" />
|
||||
|
||||
<Button Grid.Column="1" Classes="primary" Content="Senden" Width="100"
|
||||
<Button Grid.Column="1" Classes="primary" Content="{Binding L[desktop.chat.send]}" Width="100"
|
||||
Command="{Binding SendMessageCommand}" IsEnabled="{Binding !IsSending}"
|
||||
VerticalAlignment="Stretch" Margin="8,0,0,0" />
|
||||
</Grid>
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
|
||||
<!-- Anwendung -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Classes="kicker" Text="ANWENDUNG" />
|
||||
<TextBlock Classes="h2" Text="Build" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.info.kickerApp]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.info.build]}" />
|
||||
|
||||
<Grid ColumnDefinitions="170,*" RowDefinitions="Auto,Auto" >
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="label" Text="Version" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.version]}" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding AppVersion}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="label" Text="Build-Zusammenfassung"
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.buildSummary]}"
|
||||
Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding BuildSummary}"
|
||||
TextWrapping="Wrap" Margin="0,6,0,0" />
|
||||
@@ -43,36 +43,36 @@
|
||||
|
||||
<!-- Instanz -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Classes="kicker" Text="INSTANZ" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.info.kickerInstance]}" />
|
||||
|
||||
<DockPanel>
|
||||
<TextBlock Classes="h2" Text="Aktuelle Instanz" VerticalAlignment="Center" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.info.currentInstance]}" VerticalAlignment="Center" />
|
||||
<Button DockPanel.Dock="Right" HorizontalAlignment="Right" Classes="toolbar"
|
||||
Command="{Binding OpenInstanceFolderCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconFolder}" Width="14" Height="14" />
|
||||
<TextBlock Text="Instanz-Ordner öffnen" />
|
||||
<TextBlock Text="{Binding L[desktop.info.openFolder]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</DockPanel>
|
||||
|
||||
<Grid ColumnDefinitions="170,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="label" Text="Name" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.name]}" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding InstanceName}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="label" Text="ID" Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.id]}" Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Classes="mono" Text="{Binding InstanceId}"
|
||||
Margin="0,6,0,0" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Classes="label" Text="Pfad" Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.path]}" Margin="0,6,0,0" />
|
||||
<SelectableTextBlock Grid.Row="2" Grid.Column="1" Text="{Binding InstancePath}"
|
||||
TextWrapping="Wrap" Margin="0,6,0,0" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Classes="label" Text="Log-Ordner" Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.logDir]}" Margin="0,6,0,0" />
|
||||
<SelectableTextBlock Grid.Row="3" Grid.Column="1" Text="{Binding LogDirectory}"
|
||||
TextWrapping="Wrap" Margin="0,6,0,0" />
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Classes="label" Text="OpenRouter" Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Classes="label" Text="{Binding L[desktop.info.openRouter]}" Margin="0,6,0,0" />
|
||||
<TextBlock Grid.Row="4" Grid.Column="1" Text="{Binding OpenRouterStatus}" Margin="0,6,0,0" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
@@ -81,8 +81,8 @@
|
||||
|
||||
<!-- Baugruppen -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Classes="kicker" Text="MODULE" />
|
||||
<TextBlock Classes="h2" Text="Baugruppen" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.info.kickerModules]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.info.assemblies]}" />
|
||||
|
||||
<!-- Feste Breiten statt Sternanteilen fuer die drei schmalen Spalten.
|
||||
Sternbreiten teilen den Platz erst auf, NACHDEM die Mindestbreite jedes
|
||||
@@ -99,10 +99,10 @@
|
||||
Grenzfall nicht aneinanderstossen. -->
|
||||
<Border Classes="thead">
|
||||
<Grid ColumnDefinitions="170,60,150,*" ClipToBounds="True">
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="MODUL" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="BUILD" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="BUILD-DATUM" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="ÄNDERUNGEN" Margin="10,0,0,0" />
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.info.thModule]}" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.info.thBuild]}" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.info.thBuildDate]}" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="{Binding L[desktop.info.thChanges]}" Margin="10,0,0,0" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
<Border Classes="hr" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBox Grid.Column="0" Text="{Binding NewInstanceName}"
|
||||
PlaceholderText="Name der neuen Instanz" />
|
||||
PlaceholderText="{Binding L[desktop.instancePicker.newInstancePlaceholder]}" />
|
||||
<Button Grid.Column="1" Classes="primary" Margin="8,0,0,0"
|
||||
Command="{Binding CreateCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconPlus}" Width="14" Height="14" />
|
||||
<TextBlock Text="Anlegen" />
|
||||
<TextBlock Text="{Binding L[desktop.instancePicker.create]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
@@ -50,7 +50,7 @@
|
||||
<!-- Abschluss -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Spacing="8"
|
||||
HorizontalAlignment="Right" Margin="0,14,0,0">
|
||||
<Button Content="Abbrechen" Command="{Binding CancelCommand}" IsCancel="True" />
|
||||
<Button Content="{Binding L[common.cancel]}" Command="{Binding CancelCommand}" IsCancel="True" />
|
||||
<Button Classes="primary" Content="{Binding ConfirmLabel}" IsDefault="True"
|
||||
Command="{Binding StartCommand}" />
|
||||
</StackPanel>
|
||||
@@ -84,13 +84,13 @@
|
||||
Stroke="{DynamicResource SurfaceBrush}" StrokeThickness="2"
|
||||
Fill="{DynamicResource SuccessBrush}"
|
||||
IsVisible="{Binding IsReady}"
|
||||
ToolTip.Tip="API-Key hinterlegt" />
|
||||
ToolTip.Tip="{Binding $parent[ItemsControl].((vm:InstancePickerViewModel)DataContext).L[desktop.instancePicker.tooltipConfigured]}" />
|
||||
<Ellipse Width="10" Height="10" HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Stroke="{DynamicResource SurfaceBrush}" StrokeThickness="2"
|
||||
Fill="{DynamicResource Neutral500Brush}"
|
||||
IsVisible="{Binding !IsReady}"
|
||||
ToolTip.Tip="Kein API-Key — Agenten bleiben deaktiviert" />
|
||||
ToolTip.Tip="{Binding $parent[ItemsControl].((vm:InstancePickerViewModel)DataContext).L[desktop.instancePicker.tooltipMissing]}" />
|
||||
</Panel>
|
||||
|
||||
<Button DockPanel.Dock="Right" Classes="toolbar" VerticalAlignment="Center"
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<Border DockPanel.Dock="Right" Classes="tag ok" Margin="0,0,8,0"
|
||||
IsVisible="{Binding IsCurrent}">
|
||||
<TextBlock Text="Aktiv" />
|
||||
<TextBlock Text="{Binding $parent[ItemsControl].((vm:InstancePickerViewModel)DataContext).L[desktop.instancePicker.active]}" />
|
||||
</Border>
|
||||
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
x:Class="ClawdDotNet.Desktop.Views.LicenseWindow"
|
||||
x:DataType="vm:LicenseViewModel"
|
||||
Icon="/Assets/app.ico"
|
||||
Title="ClawdDotNet – Lizenz"
|
||||
Title="{Binding L[desktop.dialog.licenseTitle]}"
|
||||
Width="520" SizeToContent="Height"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
|
||||
<StackPanel Margin="20" Spacing="12">
|
||||
|
||||
<TextBlock Classes="heading" Text="Lizenzschlüssel" />
|
||||
<TextBlock Classes="heading" Text="{Binding L[desktop.dialog.licenseKey]}" />
|
||||
|
||||
<!-- Nur sichtbar, wenn es einen Grund gibt -->
|
||||
<Border Classes="card"
|
||||
@@ -28,15 +28,15 @@
|
||||
FontFamily="{DynamicResource ContentControlThemeFontFamily}" />
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Classes="caption" Text="Hardware-ID (für den Support):" />
|
||||
<TextBlock Classes="caption" Text="{Binding L[desktop.dialog.hardwareId]}" />
|
||||
<SelectableTextBlock Classes="caption"
|
||||
Text="{Binding HardwareId}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right">
|
||||
<Button Content="Beenden" Command="{Binding CancelCommand}" />
|
||||
<Button Content="Prüfen" Classes="accent" IsDefault="True"
|
||||
<Button Content="{Binding L[common.exit]}" Command="{Binding CancelCommand}" />
|
||||
<Button Content="{Binding L[desktop.dialog.verify]}" Classes="accent" IsDefault="True"
|
||||
Command="{Binding ConfirmCommand}" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
<!-- Werkzeugleiste -->
|
||||
<StackPanel DockPanel.Dock="Top" Classes="toolbar">
|
||||
|
||||
<TextBlock Text="Modul:" FontSize="12.5" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding L[desktop.logs.module]}" FontSize="12.5" VerticalAlignment="Center" />
|
||||
<ComboBox ItemsSource="{Binding Modules}" SelectedItem="{Binding SelectedModule}"
|
||||
Width="180" MinHeight="30" Padding="8,3" />
|
||||
|
||||
<TextBlock Text="Stufe:" FontSize="12.5" VerticalAlignment="Center" Margin="6,0,0,0" />
|
||||
<TextBlock Text="{Binding L[desktop.logs.level]}" FontSize="12.5" VerticalAlignment="Center" Margin="6,0,0,0" />
|
||||
<ComboBox ItemsSource="{Binding Levels}" SelectedItem="{Binding SelectedLevel}"
|
||||
Width="120" MinHeight="30" Padding="8,3" />
|
||||
|
||||
@@ -28,25 +28,25 @@
|
||||
<Button Classes="toolbar" Command="{Binding RefreshModulesCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
||||
<TextBlock Text="Aktualisieren" />
|
||||
<TextBlock Text="{Binding L[desktop.logs.refresh]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Classes="toolbar" Command="{Binding ClearCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconTrash}" Width="14" Height="14" />
|
||||
<TextBlock Text="Leeren" />
|
||||
<TextBlock Text="{Binding L[desktop.logs.clear]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Classes="toolbar" Command="{Binding OpenFolderCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconFolder}" Width="14" Height="14" />
|
||||
<TextBlock Text="Ordner öffnen" />
|
||||
<TextBlock Text="{Binding L[desktop.logs.openFolder]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<CheckBox Content="Mitlaufen" IsChecked="{Binding FollowTail}"
|
||||
<CheckBox Content="{Binding L[desktop.logs.follow]}" IsChecked="{Binding FollowTail}"
|
||||
VerticalAlignment="Center" Margin="8,0,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<Button DockPanel.Dock="Right" Classes="flat"
|
||||
Command="{Binding ToggleSidebarCommand}"
|
||||
ToolTip.Tip="Seitenleiste ein-/ausklappen"
|
||||
ToolTip.Tip="{Binding L[desktop.mainWindow.sidebarTooltip]}"
|
||||
Padding="4" VerticalAlignment="Center">
|
||||
<ctrl:StrokeIcon Width="14" Height="14"
|
||||
Data="{Binding IsSidebarCollapsed,
|
||||
@@ -60,7 +60,7 @@
|
||||
<Button DockPanel.Dock="Top" Classes="instance" Margin="12,12,12,0"
|
||||
Command="{Binding OpenInstanceManagerCommand}"
|
||||
IsEnabled="{Binding CanSwitchInstance}"
|
||||
ToolTip.Tip="Instanz wechseln">
|
||||
ToolTip.Tip="{Binding L[desktop.mainWindow.switchInstance]}">
|
||||
<DockPanel>
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconLogo}" Width="15" Height="15"
|
||||
DockPanel.Dock="Left" VerticalAlignment="Center" />
|
||||
@@ -70,7 +70,7 @@
|
||||
IsVisible="{Binding IsSidebarExpanded}" />
|
||||
|
||||
<StackPanel Margin="8,0,0,0" IsVisible="{Binding IsSidebarExpanded}">
|
||||
<TextBlock Text="INSTANZ" FontSize="9" LetterSpacing="1"
|
||||
<TextBlock Text="{Binding L[desktop.mainWindow.instance]}" FontSize="9" LetterSpacing="1"
|
||||
Foreground="{DynamicResource AccentBrush}" />
|
||||
<TextBlock Classes="h2" FontSize="13" Text="{Binding InstanceName}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
@@ -142,7 +142,7 @@
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Classes="caption" Text="{Binding ThemeLabel}" VerticalAlignment="Center" />
|
||||
<Button Classes="icon" Command="{Binding ToggleThemeCommand}"
|
||||
ToolTip.Tip="Dunkelmodus umschalten">
|
||||
ToolTip.Tip="{Binding L[desktop.mainWindow.themeToggle]}">
|
||||
<ctrl:StrokeIcon Width="16" Height="16"
|
||||
Data="{Binding ThemeIconKey,
|
||||
Converter={x:Static conv:IconConverter.Instance}}" />
|
||||
@@ -172,7 +172,7 @@
|
||||
Margin="0,0,10,0" />
|
||||
|
||||
<Button DockPanel.Dock="Right" Classes="flat" Padding="2"
|
||||
Command="{Binding DismissCommand}" ToolTip.Tip="Ausblenden"
|
||||
Command="{Binding DismissCommand}" ToolTip.Tip="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).L[desktop.mainWindow.dismiss]}"
|
||||
VerticalAlignment="Center">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconClose}" Width="13" Height="13" />
|
||||
</Button>
|
||||
@@ -190,7 +190,7 @@
|
||||
<Border DockPanel.Dock="Bottom" Classes="statusbar">
|
||||
<DockPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Classes="caption" Text="{Binding InstanceName, StringFormat='Instanz: {0}'}" />
|
||||
<TextBlock Classes="caption" Text="{Binding InstanceStatusLabel}" />
|
||||
<TextBlock Classes="caption" Text="·" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="5" VerticalAlignment="Center">
|
||||
@@ -200,7 +200,7 @@
|
||||
<Ellipse Width="7" Height="7" VerticalAlignment="Center"
|
||||
Fill="{DynamicResource DangerBrush}"
|
||||
IsVisible="{Binding !IsApiReachable}" />
|
||||
<TextBlock Classes="caption" Text="{Binding ApiStatusText, StringFormat='API {0}'}" />
|
||||
<TextBlock Classes="caption" Text="{Binding ApiStatusDisplay}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Classes="caption" Text="·"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Padding="16"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
Title="Sicherung wiederherstellen"
|
||||
Title="{Binding L[desktop.dialog.restoreTitle]}"
|
||||
x:Class="ClawdDotNet.Desktop.Views.RestoreBackupWindow"
|
||||
x:DataType="vm:RestoreBackupViewModel">
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
<!-- Buttons unten -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="8" Margin="0,16,0,0">
|
||||
<Button Content="Abbrechen" Command="{Binding CancelCommand}" />
|
||||
<Button Content="Wiederherstellen" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
<Button Content="{Binding L[common.cancel]}" Command="{Binding CancelCommand}" />
|
||||
<Button Content="{Binding L[desktop.backup.restore]}" Command="{Binding ConfirmCommand}" Classes="accent" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Statusmeldung unten -->
|
||||
@@ -29,34 +29,34 @@
|
||||
<!-- Information -->
|
||||
<Border Classes="card">
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Sicherungsinformationen" Classes="heading" />
|
||||
<TextBlock Text="{Binding InstanceName, StringFormat='Instanz: {0}'}" />
|
||||
<TextBlock Text="{Binding CreatedAt, StringFormat='Erstellt: {0:g}'}" />
|
||||
<TextBlock Text="{Binding FileCount, StringFormat='Dateien: {0}'}" />
|
||||
<TextBlock Text="{Binding SecretsDescription, StringFormat='Zugangsdaten: {0}'}" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.backupInfo]}" Classes="heading" />
|
||||
<TextBlock Text="{Binding InstanceInfoText}" />
|
||||
<TextBlock Text="{Binding CreatedAtText}" />
|
||||
<TextBlock Text="{Binding FileCountText}" />
|
||||
<TextBlock Text="{Binding SecretsText}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Zielordner -->
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Zielordner:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.targetDir]}" FontWeight="Bold" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBox Text="{Binding TargetDirectory}" Grid.Column="0" />
|
||||
<Button Content="Ordner wählen" Click="OnBrowseFolder" Grid.Column="1" Margin="8,0,0,0" />
|
||||
<Button Content="{Binding L[desktop.dialog.chooseFolder]}" Click="OnBrowseFolder" Grid.Column="1" Margin="8,0,0,0" />
|
||||
</Grid>
|
||||
<TextBlock Text="Hinweis: Es wird empfohlen, in einen neuen Ordner wiederherzustellen, um Konflikte mit laufenden Prozessen zu vermeiden."
|
||||
<TextBlock Text="{Binding L[desktop.dialog.restoreHint]}"
|
||||
Classes="caption" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Passphrase -->
|
||||
<StackPanel Spacing="4" IsVisible="{Binding NeedsPassphrase}">
|
||||
<TextBlock Text="Passphrase:" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.passphrase]}" FontWeight="Bold" />
|
||||
<TextBox Text="{Binding Passphrase}" PasswordChar="*" />
|
||||
<TextBlock Text="Diese Sicherung enthält geschützte Zugangsdaten." Classes="caption" />
|
||||
<TextBlock Text="{Binding L[desktop.dialog.passphraseProtected]}" Classes="caption" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Überschreiben -->
|
||||
<CheckBox Content="Vorhandene Dateien im Zielordner überschreiben" IsChecked="{Binding Overwrite}" Margin="0,8,0,0" />
|
||||
<CheckBox Content="{Binding L[desktop.dialog.overwriteExisting]}" IsChecked="{Binding Overwrite}" Margin="0,8,0,0" />
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
<Border DockPanel.Dock="Bottom" BorderBrush="{DynamicResource DividerBrush}"
|
||||
BorderThickness="0,1,0,0" Padding="0,12,0,0" Margin="0,16,0,0">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right">
|
||||
<Button Content="Verwerfen" Command="{Binding LoadFromHostCommand}" />
|
||||
<Button Content="{Binding L[desktop.settings.discard]}" Command="{Binding LoadFromHostCommand}" />
|
||||
<Button Classes="primary" Command="{Binding SaveSettingsCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconSave}" Width="14" Height="14" />
|
||||
<TextBlock Text="Speichern" />
|
||||
<TextBlock Text="{Binding L[desktop.settings.save]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
@@ -30,39 +30,39 @@
|
||||
|
||||
<!-- ══════════════════ Instanz ══════════════════ -->
|
||||
<StackPanel Spacing="14">
|
||||
<TextBlock Classes="kicker" Text="INSTANZ" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.settings.instance]}" />
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Instanz-Name" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.instanceName]}" />
|
||||
<TextBox Text="{Binding InstanceName}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="OpenRouter API-Key" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.apiKey]}" />
|
||||
<TextBox Text="{Binding OpenRouterApiKey}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<CheckBox IsChecked="{Binding AutostartByManager}"
|
||||
Content="Autostart durch Manager" />
|
||||
Content="{Binding L[desktop.settings.autostart]}" />
|
||||
<TextBlock Classes="caption" TextWrapping="Wrap" Margin="0,4,0,0"
|
||||
Text="Der Instanzmanager startet diese Instanz, wenn er hochkommt, und wieder, wenn sie abstürzt. Nach mehreren Neustarts in kurzer Folge setzt er aus und meldet es." />
|
||||
Text="{Binding L[desktop.settings.autostartHint]}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Protokoll-Verzeichnis" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.logDir]}" />
|
||||
<TextBox Text="{Binding LogDirectory}" />
|
||||
<TextBlock Classes="caption" TextWrapping="Wrap" Margin="0,4,0,0"
|
||||
Text="Gilt nur für diese Instanz. Leer heißt: Unterordner Logs im Instanzverzeichnis." />
|
||||
Text="{Binding L[desktop.settings.logDirHint]}" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="*,16,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Tagesbudget ($ USD)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.dailyCost]}" />
|
||||
<TextBox Text="{Binding InstanceDailyCostUsd}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Tagesbudget (Tokens)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.dailyTokens]}" />
|
||||
<TextBox Text="{Binding InstanceDailyTokens}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -72,21 +72,33 @@
|
||||
|
||||
<!-- ══════════════════ Allgemein ══════════════════ -->
|
||||
<StackPanel Spacing="14">
|
||||
<TextBlock Classes="kicker" Text="ALLGEMEIN" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.settings.general]}" />
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Instanzen-Verzeichnis" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.language]}" />
|
||||
<ComboBox ItemsSource="{Binding AvailableLanguages}" SelectedItem="{Binding SelectedLanguageOption}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.instancesDir]}" />
|
||||
<TextBox Text="{Binding InstancesDirectory}" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="*,16,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Minimaler Log-Level" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.minLogLevel]}" />
|
||||
<ComboBox ItemsSource="{Binding LogLevels}" SelectedItem="{Binding MinimumLogLevel}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="OpenRouter Base-URL" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.openRouterUrl]}" />
|
||||
<TextBox Text="{Binding OpenRouterBaseUrl}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -96,26 +108,26 @@
|
||||
|
||||
<!-- ══════════════════ Deploymentcenter ══════════════════ -->
|
||||
<StackPanel Spacing="14">
|
||||
<TextBlock Classes="kicker" Text="DEPLOYMENTCENTER & LIZENZ" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.settings.dcAndLicense]}" />
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Server-URL" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.dcUrl]}" />
|
||||
<TextBox Text="{Binding DeploymentcenterUrl}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Master-Token" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.dcToken]}" />
|
||||
<TextBox Text="{Binding DeploymentcenterToken}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="*,16,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Update-Kanal" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.updateChannel]}" />
|
||||
<ComboBox ItemsSource="{Binding UpdateChannels}" SelectedItem="{Binding UpdateChannel}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Umgebung" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.dcEnv]}" />
|
||||
<ComboBox ItemsSource="{Binding Environments}"
|
||||
SelectedItem="{Binding DeploymentcenterEnvironment}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
@@ -123,14 +135,14 @@
|
||||
</Grid>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Lizenzschlüssel" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.settings.licenseKey]}" />
|
||||
<TextBox Text="{Binding LicenseKey}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="10" Margin="0,4,0,0">
|
||||
<CheckBox Content="Fehler automatisch an Deploymentcenter melden"
|
||||
<CheckBox Content="{Binding L[desktop.settings.errorReporting]}"
|
||||
IsChecked="{Binding ErrorReportingEnabled}" />
|
||||
<CheckBox Content="Beim Start automatisch auf Updates prüfen"
|
||||
<CheckBox Content="{Binding L[desktop.settings.updateCheck]}"
|
||||
IsChecked="{Binding UpdateCheckEnabled}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
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"
|
||||
<ToggleButton Content="{Binding L[desktop.tasks.tabJobs]}" Margin="0,0,-1,0"
|
||||
IsChecked="{Binding IsJobsTab, Mode=OneWay}"
|
||||
Command="{Binding SelectTabCommand}" CommandParameter="Jobs" />
|
||||
<ToggleButton Content="Dienste" Margin="0,0,-1,0"
|
||||
<ToggleButton Content="{Binding L[desktop.tasks.tabServices]}" Margin="0,0,-1,0"
|
||||
IsChecked="{Binding IsServicesTab, Mode=OneWay}"
|
||||
Command="{Binding SelectTabCommand}" CommandParameter="Services" />
|
||||
<ToggleButton Content="Verlauf"
|
||||
<ToggleButton Content="{Binding L[desktop.tasks.tabHistory]}"
|
||||
IsChecked="{Binding IsHistoryTab, Mode=OneWay}"
|
||||
Command="{Binding SelectTabCommand}" CommandParameter="History" />
|
||||
</StackPanel>
|
||||
@@ -40,7 +40,7 @@
|
||||
<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" />
|
||||
<TextBlock Text="{Binding L[desktop.tasks.addJob]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
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" />
|
||||
<TextBlock Text="{Binding L[desktop.tasks.editJob]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
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" />
|
||||
<TextBlock Text="{Binding L[desktop.tasks.removeJob]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
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" />
|
||||
<TextBlock Text="{Binding L[desktop.tasks.toggleJob]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -74,27 +74,27 @@
|
||||
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" />
|
||||
<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="Aktualisieren" />
|
||||
<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="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" />
|
||||
<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>
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
<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" />
|
||||
<TextBlock Text="{Binding L[desktop.services.addService]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
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" />
|
||||
<TextBlock Text="{Binding L[desktop.services.removeService]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -152,25 +152,25 @@
|
||||
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" />
|
||||
<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="Aktualisieren" />
|
||||
<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="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" />
|
||||
<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>
|
||||
|
||||
@@ -206,19 +206,19 @@
|
||||
<Button Classes="toolbar" Command="{Binding RefreshJobHistoryCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
||||
<TextBlock Text="Verlauf aktualisieren" />
|
||||
<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="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" />
|
||||
<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>
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
<DockPanel>
|
||||
|
||||
<TextBlock x:Name="TitleText" DockPanel.Dock="Top" Classes="h1"
|
||||
Text="Text bearbeiten" Margin="0,0,0,12" TextWrapping="Wrap" />
|
||||
Text="Edit Text" Margin="0,0,0,12" TextWrapping="Wrap" />
|
||||
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Spacing="8"
|
||||
HorizontalAlignment="Right" Margin="0,14,0,0">
|
||||
<Button Content="Abbrechen" IsCancel="True" Click="OnCancel" />
|
||||
<Button Classes="primary" Content="Speichern" IsDefault="True" Click="OnSave" />
|
||||
<Button x:Name="CancelButton" Content="Cancel" IsCancel="True" Click="OnCancel" />
|
||||
<Button x:Name="SaveButton" Classes="primary" Content="Save" IsDefault="True" Click="OnSave" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBox x:Name="Editor" AcceptsReturn="True" TextWrapping="Wrap"
|
||||
|
||||
@@ -17,6 +17,9 @@ public partial class TextEditorWindow : Window
|
||||
public TextEditorWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Title = ClawdDotNet.Desktop.Services.LocalizationManager.Instance["desktop.dialog.textEditorTitle"] ?? "Edit Text";
|
||||
CancelButton.Content = ClawdDotNet.Desktop.Services.LocalizationManager.Instance["common.cancel"] ?? "Cancel";
|
||||
SaveButton.Content = ClawdDotNet.Desktop.Services.LocalizationManager.Instance["common.save"] ?? "Save";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,19 +15,19 @@
|
||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||
<Border Classes="card" MinWidth="160">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Classes="kicker" Text="TOKENS (7 TAGE)" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.usage.kickerTokens7d]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding TotalTokens}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Classes="card" MinWidth="160">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Classes="kicker" Text="KOSTEN (7 TAGE)" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.usage.kickerCost7d]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding TotalCost}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Classes="card" MinWidth="160">
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Classes="kicker" Text="RUNS (7 TAGE)" />
|
||||
<TextBlock Classes="kicker" Text="{Binding L[desktop.usage.kickerRuns7d]}" />
|
||||
<TextBlock Classes="h2" Text="{Binding TotalRuns}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
@@ -35,7 +35,7 @@
|
||||
<Button Classes="toolbar" Command="{Binding RefreshCommand}" VerticalAlignment="Bottom">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<ctrl:StrokeIcon Data="{StaticResource IconRefresh}" Width="14" Height="14" />
|
||||
<TextBlock Text="Aktualisieren" />
|
||||
<TextBlock Text="{Binding L[desktop.usage.refresh]}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
<!-- Tagesbalken -->
|
||||
<StackPanel Spacing="12" IsVisible="{Binding !IsEmpty}">
|
||||
<TextBlock Classes="h2" Text="Tokens pro Tag" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.usage.tokensPerDay]}" />
|
||||
|
||||
<Border BorderBrush="{DynamicResource DividerBrush}" BorderThickness="0,0,0,1"
|
||||
Padding="0,0,0,2">
|
||||
@@ -78,15 +78,15 @@
|
||||
<!-- Aufschlüsselung -->
|
||||
<StackPanel Spacing="10" MaxWidth="860" HorizontalAlignment="Left"
|
||||
IsVisible="{Binding !IsEmpty}">
|
||||
<TextBlock Classes="h2" Text="Aufschlüsselung nach Agent & Modell" />
|
||||
<TextBlock Classes="h2" Text="{Binding L[desktop.usage.breakdownTitle]}" />
|
||||
|
||||
<Border Classes="thead">
|
||||
<Grid ColumnDefinitions="2*,2*,1.2*,1.2*,0.8*">
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="AGENT" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="MODELL" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="TOKENS" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="KOSTEN" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="RUNS" />
|
||||
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.usage.thAgent]}" />
|
||||
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.usage.thModel]}" />
|
||||
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.usage.thTokens]}" />
|
||||
<TextBlock Grid.Column="3" Classes="th" Text="{Binding L[desktop.usage.thCost]}" />
|
||||
<TextBlock Grid.Column="4" Classes="th" Text="{Binding L[desktop.usage.thRuns]}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -23,25 +23,25 @@
|
||||
<StackPanel Spacing="12" IsVisible="{Binding ToolName,
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=FTP}">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Host" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.host]}" />
|
||||
<TextBox Text="{Binding FtpHost}" PlaceholderText="ftp.example.com" />
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Port" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.port]}" />
|
||||
<TextBox Text="{Binding FtpPort}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Benutzername" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.username]}" />
|
||||
<TextBox Text="{Binding FtpUsername}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Passwort" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.password]}" />
|
||||
<TextBox Text="{Binding FtpPassword}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Root-Pfad" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.rootPath]}" />
|
||||
<TextBox Text="{Binding FtpRootPath}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@@ -51,36 +51,36 @@
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=Mail}">
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Benutzername" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.username]}" />
|
||||
<TextBox Text="{Binding MailUsername}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Passwort" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.password]}" />
|
||||
<TextBox Text="{Binding MailPassword}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="IMAP-Host" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.imapHost]}" />
|
||||
<TextBox Text="{Binding MailImapHost}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="IMAP-Port" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.imapPort]}" />
|
||||
<TextBox Text="{Binding MailImapPort}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="SMTP-Host" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.smtpHost]}" />
|
||||
<TextBox Text="{Binding MailSmtpHost}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="SMTP-Port" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.smtpPort]}" />
|
||||
<TextBox Text="{Binding MailSmtpPort}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Erlaubte Empfänger" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.allowedRecipients]}" />
|
||||
<TextBox Text="{Binding MailAllowedRecipients}"
|
||||
PlaceholderText="adresse1@domain.de, adresse2@domain.de" />
|
||||
</StackPanel>
|
||||
@@ -90,21 +90,21 @@
|
||||
<StackPanel Spacing="12" IsVisible="{Binding ToolName,
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=Database}">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Typ" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.type]}" />
|
||||
<ComboBox ItemsSource="{Binding DbTypes}" SelectedItem="{Binding DbType}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Connection-String" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.connectionString]}" />
|
||||
<TextBox Text="{Binding DbConnectionString}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Zugriffsebene" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.accessLevel]}" />
|
||||
<ComboBox ItemsSource="{Binding DbAccessLevels}" SelectedItem="{Binding DbAccessLevel}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Erlaubte Tabellen" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.allowedTables]}" />
|
||||
<TextBox Text="{Binding DbAllowedTables}" PlaceholderText="tabelle1, tabelle2" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@@ -113,15 +113,15 @@
|
||||
<StackPanel Spacing="12" IsVisible="{Binding ToolName,
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=Telegram}">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Bot-Token" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.botToken]}" />
|
||||
<TextBox Text="{Binding TelegramBotToken}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Standard Chat-ID" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.defaultChatId]}" />
|
||||
<TextBox Text="{Binding TelegramDefaultChatId}" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Erlaubte Chat-IDs" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.allowedChatIds]}" />
|
||||
<TextBox Text="{Binding TelegramAllowedChatIds}" PlaceholderText="id1, id2" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@@ -131,20 +131,20 @@
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=DirectAPI}">
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Standard-Provider" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.defaultProvider]}" />
|
||||
<TextBox Text="{Binding DirectApiDefaultProvider}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Cache TTL (Sekunden)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.cacheTtl]}" />
|
||||
<TextBox Text="{Binding DirectApiCacheTtlSeconds}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Twelve Data Key" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.twelveDataKey]}" />
|
||||
<TextBox Text="{Binding DirectApiTwelveDataKey}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Alpha Vantage Key" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.alphaVantageKey]}" />
|
||||
<TextBox Text="{Binding DirectApiAlphaVantageKey}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@@ -153,17 +153,17 @@
|
||||
<StackPanel Spacing="12" IsVisible="{Binding ToolName,
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=WebFetch}">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Erlaubte Domains" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.allowedDomains]}" />
|
||||
<TextBox Text="{Binding WebFetchAllowedDomains}"
|
||||
PlaceholderText="reuters.com, coindesk.com" />
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Max. Antwortgröße (KB)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.maxResponseKb]}" />
|
||||
<TextBox Text="{Binding WebFetchMaxResponseKb}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="User Agent" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.userAgent]}" />
|
||||
<TextBox Text="{Binding WebFetchUserAgent}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -173,34 +173,34 @@
|
||||
<StackPanel Spacing="12" IsVisible="{Binding ToolName,
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=SocialMediaManager}">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="X (Twitter) API-Key" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.xApiKey]}" />
|
||||
<TextBox Text="{Binding SmmXApiKey}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="X Accounts" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.xAccounts]}" />
|
||||
<TextBox Text="{Binding SmmXWatchAccounts}" PlaceholderText="account1, account2" />
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="Subreddits" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.subreddits]}" />
|
||||
<TextBox Text="{Binding SmmRedditWatchSubreddits}" PlaceholderText="stocks, investing" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Reddit Post Limit" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.redditPostLimit]}" />
|
||||
<TextBox Text="{Binding SmmRedditPostLimit}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="OpenRouter Key" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.openRouterKey]}" />
|
||||
<TextBox Text="{Binding SmmOpenRouterApiKey}" PasswordChar="•" />
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Classes="label" Text="STT-Modell" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.sttModel]}" />
|
||||
<TextBox Text="{Binding SmmSttModel}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="YouTube-Kanäle" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.youtubeChannels]}" />
|
||||
<TextBox Text="{Binding SmmYoutubeChannels}" PlaceholderText="URL1, URL2" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -210,28 +210,28 @@
|
||||
<StackPanel Spacing="12" IsVisible="{Binding ToolName,
|
||||
Converter={x:Static conv:ToolMatchConverter.Instance}, ConverterParameter=FileRW}">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Erlaubte Dateiendungen (persönlich)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.fileRwPersonalExt]}" />
|
||||
<TextBox Text="{Binding FileRwPersonalAllowedExtensions}" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Zugriffsebene (geteilt)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.fileRwSharedAccess]}" />
|
||||
<ComboBox ItemsSource="{Binding FileRwAccessLevels}"
|
||||
SelectedItem="{Binding FileRwSharedAccessLevel}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Erlaubte Dateiendungen (geteilt)" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.fileRwSharedExt]}" />
|
||||
<TextBox Text="{Binding FileRwSharedAllowedExtensions}" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Geschützte Pfade" />
|
||||
<TextBlock Classes="label" Text="{Binding L[desktop.toolSettings.fileRwProtectedPaths]}" />
|
||||
<TextBox Text="{Binding FileRwProtectedPaths}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Werkzeuge ohne weitere Einstellungen -->
|
||||
<TextBlock Classes="muted" FontStyle="Italic" TextWrapping="Wrap"
|
||||
Text="Dieses Werkzeug benötigt keine weiteren Einstellungen."
|
||||
Text="{Binding L[desktop.toolSettings.noSettings]}"
|
||||
IsVisible="{Binding SettingsObject, Converter={x:Static ObjectConverters.IsNull}}" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
{
|
||||
"desktop.mainWindow.title": "ClawdDotNet",
|
||||
"desktop.mainWindow.sidebarTooltip": "Seitenleiste ein-/ausklappen",
|
||||
"desktop.mainWindow.switchInstance": "Instanz wechseln",
|
||||
"desktop.mainWindow.instance": "INSTANZ",
|
||||
"desktop.mainWindow.themeLight": "Hellmodus",
|
||||
"desktop.mainWindow.themeDark": "Dunkelmodus",
|
||||
"desktop.mainWindow.themeToggle": "Farbschema umschalten",
|
||||
"desktop.mainWindow.openInstanceFolder": "Instanz-Ordner öffnen",
|
||||
"desktop.mainWindow.instanceManager": "Instanzmanager",
|
||||
"desktop.mainWindow.exit": "Beenden",
|
||||
"desktop.mainWindow.instanceLabel": "Instanz: {0}",
|
||||
"desktop.mainWindow.apiStatus": "API {0}",
|
||||
"desktop.mainWindow.credits": "Credits: ${0:F2} von ${1:F2}",
|
||||
"desktop.mainWindow.creditsNone": "Credits: —",
|
||||
"desktop.mainWindow.dismiss": "Ausblenden",
|
||||
|
||||
"desktop.nav.work": "Arbeiten",
|
||||
"desktop.nav.analytics": "Analyse",
|
||||
"desktop.nav.system": "System",
|
||||
|
||||
"desktop.status.unknown": "unbekannt",
|
||||
"desktop.status.design": "Entwurf",
|
||||
"desktop.status.noApiKey": "kein API-Key",
|
||||
"desktop.status.noUsageData": "keine Nutzungsdaten",
|
||||
"desktop.status.ready": "Bereit",
|
||||
"desktop.status.reachable": "OK",
|
||||
"desktop.status.unreachable": "nicht erreichbar",
|
||||
|
||||
"desktop.chat.agent": "Agent:",
|
||||
"desktop.chat.clearHistory": "Verlauf leeren",
|
||||
"desktop.chat.abort": "Abbrechen",
|
||||
"desktop.chat.inputPlaceholder": "Nachricht eingeben… (Enter zum Senden, Shift+Enter für neue Zeile)",
|
||||
"desktop.chat.send": "Senden",
|
||||
"desktop.chat.statusReady": "Bereit",
|
||||
"desktop.chat.statusSending": "Sende…",
|
||||
"desktop.chat.statusDesign": "Entwurfsmodus",
|
||||
"desktop.chat.noApiKey": "OpenRouter API-Key ist nicht konfiguriert. Bitte in den Einstellungen hinterlegen.",
|
||||
"desktop.chat.noAgent": "Bitte einen Agenten auswählen.",
|
||||
"desktop.chat.emptyMessage": "Bitte eine Nachricht eingeben.",
|
||||
|
||||
"desktop.agents.addAgent": "Agent",
|
||||
"desktop.agents.removeAgent": "Agent",
|
||||
"desktop.agents.runNow": "Jetzt ausf.",
|
||||
"desktop.agents.identity": "Identity",
|
||||
"desktop.agents.soul": "Soul",
|
||||
"desktop.agents.folder": "Ordner",
|
||||
"desktop.agents.save": "Speichern",
|
||||
"desktop.agents.thDisplayName": "ANZEIGENAME",
|
||||
"desktop.agents.thModel": "MODELL",
|
||||
"desktop.agents.thSummary": "KURZINFO",
|
||||
"desktop.agents.kickerGeneralModel": "ALLGEMEIN & MODELL",
|
||||
"desktop.agents.agentId": "Agent-ID",
|
||||
"desktop.agents.displayName": "Anzeigename",
|
||||
"desktop.agents.model": "Modell",
|
||||
"desktop.agents.promptCaching": "Prompt Caching",
|
||||
"desktop.agents.roleDescription": "Rolle / Beschreibung",
|
||||
"desktop.agents.systemPrompt": "System-Prompt (zusätzliche Anweisungen)",
|
||||
"desktop.agents.kickerLimits": "GRENZEN",
|
||||
"desktop.agents.limitsTitle": "Schutzgrenzen (LoopGuard & Budget)",
|
||||
"desktop.agents.maxSteps": "Max. Schritte pro Run",
|
||||
"desktop.agents.timeoutSeconds": "Timeout (Sekunden)",
|
||||
"desktop.agents.maxContextTokens": "Max. Kontext-Tokens",
|
||||
"desktop.agents.maxToolResultChars": "Max. Tool-Ergebnis (Zeichen)",
|
||||
"desktop.agents.dailyCost": "Tagesbudget ($ USD)",
|
||||
"desktop.agents.dailyTokens": "Tagesbudget (Tokens)",
|
||||
"desktop.agents.allowedToolsFor": "ZUGELASSENE WERKZEUGE FÜR {0}",
|
||||
"desktop.agents.thTool": "WERKZEUG",
|
||||
"desktop.agents.thDescription": "BESCHREIBUNG",
|
||||
"desktop.agents.toolSettingsKicker": "WERKZEUG-EINSTELLUNGEN",
|
||||
"desktop.agents.apply": "Übernehmen",
|
||||
"desktop.agents.saved": "Agenten erfolgreich gespeichert.",
|
||||
|
||||
"desktop.tasks.tabJobs": "Geplante Jobs",
|
||||
"desktop.tasks.tabServices": "Dienste",
|
||||
"desktop.tasks.tabHistory": "Verlauf",
|
||||
"desktop.tasks.addJob": "Job hinzufügen",
|
||||
"desktop.tasks.editJob": "Bearbeiten",
|
||||
"desktop.tasks.removeJob": "Entfernen",
|
||||
"desktop.tasks.toggleJob": "Aktivieren/Deaktivieren",
|
||||
"desktop.tasks.runJobNow": "Jetzt ausführen",
|
||||
"desktop.tasks.refresh": "Aktualisieren",
|
||||
"desktop.tasks.thType": "TYP",
|
||||
"desktop.tasks.thAgent": "AGENT",
|
||||
"desktop.tasks.thTask": "TOOL / NACHRICHT",
|
||||
"desktop.tasks.thCron": "CRON",
|
||||
"desktop.tasks.thNextRun": "NÄCHSTER LAUF",
|
||||
"desktop.tasks.thLastRun": "LETZTER LAUF",
|
||||
"desktop.tasks.thStatus": "STATUS",
|
||||
|
||||
"desktop.services.addService": "Dienst hinzufügen",
|
||||
"desktop.services.removeService": "Entfernen",
|
||||
"desktop.services.toggleService": "Aktivieren/Deaktivieren",
|
||||
"desktop.services.thName": "DIENSTNAME",
|
||||
"desktop.services.thType": "TYP",
|
||||
"desktop.services.thPort": "PORT",
|
||||
"desktop.services.thStatus": "STATUS",
|
||||
"desktop.services.thDescription": "BESCHREIBUNG",
|
||||
|
||||
"desktop.history.refresh": "Verlauf aktualisieren",
|
||||
"desktop.history.thTime": "ZEITPUNKT",
|
||||
"desktop.history.thJob": "JOB",
|
||||
"desktop.history.thAgent": "AGENT",
|
||||
"desktop.history.thDescription": "BESCHREIBUNG",
|
||||
"desktop.history.thStatus": "STATUS",
|
||||
"desktop.history.thDetails": "DETAILS",
|
||||
|
||||
"desktop.usage.kickerTokens7d": "TOKENS (7 TAGE)",
|
||||
"desktop.usage.kickerCost7d": "KOSTEN (7 TAGE)",
|
||||
"desktop.usage.kickerRuns7d": "RUNS (7 TAGE)",
|
||||
"desktop.usage.refresh": "Aktualisieren",
|
||||
"desktop.usage.tokensPerDay": "Tokens pro Tag",
|
||||
"desktop.usage.breakdownTitle": "Aufschlüsselung nach Agent & Modell",
|
||||
"desktop.usage.thAgent": "AGENT",
|
||||
"desktop.usage.thModel": "MODELL",
|
||||
"desktop.usage.thTokens": "TOKENS",
|
||||
"desktop.usage.thCost": "KOSTEN",
|
||||
"desktop.usage.thRuns": "RUNS",
|
||||
"desktop.usage.empty": "Noch keine Tokennutzung aufgezeichnet.",
|
||||
|
||||
"desktop.agentChats.agentA": "Agent A:",
|
||||
"desktop.agentChats.agentB": "Agent B:",
|
||||
"desktop.agentChats.empty": "Noch keine Nachrichten zwischen diesen Agenten aufgezeichnet.",
|
||||
"desktop.agentChats.needTwo": "Für einen Verlauf braucht es mindestens zwei Agenten in dieser Instanz.",
|
||||
|
||||
"desktop.backup.kickerManual": "MANUELL",
|
||||
"desktop.backup.titleCreate": "Sicherung erstellen",
|
||||
"desktop.backup.targetFolder": "Zielordner",
|
||||
"desktop.backup.targetFolderPlaceholder": "Zielordner für Sicherungen…",
|
||||
"desktop.backup.browse": "Durchsuchen…",
|
||||
"desktop.backup.credentials": "Zugangsdaten",
|
||||
"desktop.backup.credentialsExclude": "nicht mitsichern",
|
||||
"desktop.backup.credentialsProtect": "mit Passphrase schützen",
|
||||
"desktop.backup.passphrase": "Passphrase eingeben",
|
||||
"desktop.backup.passphraseRepeat": "Passphrase wiederholen",
|
||||
"desktop.backup.scope": "Umfang",
|
||||
"desktop.backup.scopeChat": "Chatverläufe",
|
||||
"desktop.backup.scopeLogs": "Protokolle",
|
||||
"desktop.backup.createNow": "Sicherung jetzt erstellen",
|
||||
"desktop.backup.kickerAuto": "AUTOMATIK",
|
||||
"desktop.backup.titleAuto": "Automatische Sicherung",
|
||||
"desktop.backup.autoDaily": "täglich sichern um",
|
||||
"desktop.backup.time": "Uhrzeit",
|
||||
"desktop.backup.keep": "Aufbewahren",
|
||||
"desktop.backup.autoHint": "Die Automatik sichert ohne Zugangsdaten — eine gespeicherte Passphrase wäre wirkungslos.",
|
||||
"desktop.backup.kickerExisting": "BESTAND",
|
||||
"desktop.backup.titleExisting": "Vorhandene Sicherungen",
|
||||
"desktop.backup.refresh": "Aktualisieren",
|
||||
"desktop.backup.openFolder": "Ordner öffnen",
|
||||
"desktop.backup.delete": "Löschen",
|
||||
"desktop.backup.restore": "Wiederherstellen…",
|
||||
"desktop.backup.thFilename": "DATEINAME",
|
||||
"desktop.backup.thCreatedAt": "ERSTELLT AM",
|
||||
"desktop.backup.thInstance": "INSTANZ",
|
||||
"desktop.backup.thSize": "GRÖSSE",
|
||||
"desktop.backup.thSecrets": "ZUGANGSDATEN",
|
||||
|
||||
"desktop.logs.module": "Modul:",
|
||||
"desktop.logs.level": "Stufe:",
|
||||
"desktop.logs.refresh": "Aktualisieren",
|
||||
"desktop.logs.clear": "Leeren",
|
||||
"desktop.logs.openFolder": "Ordner öffnen",
|
||||
"desktop.logs.follow": "Mitlaufen",
|
||||
|
||||
"desktop.settings.discard": "Verwerfen",
|
||||
"desktop.settings.save": "Speichern",
|
||||
"desktop.settings.instance": "INSTANZ",
|
||||
"desktop.settings.instanceName": "Instanz-Name",
|
||||
"desktop.settings.apiKey": "OpenRouter API-Key",
|
||||
"desktop.settings.autostart": "Autostart durch Manager",
|
||||
"desktop.settings.autostartHint": "Der Instanzmanager startet diese Instanz, wenn er hochkommt, und wieder, wenn sie abstürzt. Nach mehreren Neustarts in kurzer Folge setzt er aus und meldet es.",
|
||||
"desktop.settings.logDir": "Protokoll-Verzeichnis",
|
||||
"desktop.settings.logDirHint": "Gilt nur für diese Instanz. Leer heißt: Unterordner Logs im Instanzverzeichnis.",
|
||||
"desktop.settings.dailyCost": "Tagesbudget ($ USD)",
|
||||
"desktop.settings.dailyTokens": "Tagesbudget (Tokens)",
|
||||
"desktop.settings.general": "ALLGEMEIN",
|
||||
"desktop.settings.instancesDir": "Instanzen-Verzeichnis",
|
||||
"desktop.settings.minLogLevel": "Minimaler Log-Level",
|
||||
"desktop.settings.openRouterUrl": "OpenRouter Base-URL",
|
||||
"desktop.settings.language": "Sprache",
|
||||
"desktop.settings.dcAndLicense": "DEPLOYMENTCENTER & LIZENZ",
|
||||
"desktop.settings.dcUrl": "Server-URL",
|
||||
"desktop.settings.dcToken": "Master-Token",
|
||||
"desktop.settings.dcEnv": "Umgebung",
|
||||
"desktop.settings.updateChannel": "Update-Kanal",
|
||||
"desktop.settings.licenseKey": "Lizenzschlüssel",
|
||||
"desktop.settings.errorReporting": "Fehler automatisch an Deploymentcenter melden",
|
||||
"desktop.settings.updateCheck": "Beim Start automatisch auf Updates prüfen",
|
||||
"desktop.settings.saved": "Einstellungen und Instanz-Konfiguration gespeichert.",
|
||||
"desktop.settings.savedLogRestart": "Gespeichert. Das Protokoll-Verzeichnis gilt ab dem nächsten Start.",
|
||||
|
||||
"desktop.info.kickerApp": "ANWENDUNG",
|
||||
"desktop.info.build": "Build",
|
||||
"desktop.info.version": "Version",
|
||||
"desktop.info.buildSummary": "Build-Zusammenfassung",
|
||||
"desktop.info.kickerInstance": "INSTANZ",
|
||||
"desktop.info.currentInstance": "Aktuelle Instanz",
|
||||
"desktop.info.openFolder": "Instanz-Ordner öffnen",
|
||||
"desktop.info.name": "Name",
|
||||
"desktop.info.id": "ID",
|
||||
"desktop.info.path": "Pfad",
|
||||
"desktop.info.logDir": "Log-Ordner",
|
||||
"desktop.info.openRouter": "OpenRouter",
|
||||
"desktop.info.kickerModules": "MODULE",
|
||||
"desktop.info.assemblies": "Baugruppen",
|
||||
"desktop.info.thModule": "MODUL",
|
||||
"desktop.info.thBuild": "BUILD",
|
||||
"desktop.info.thBuildDate": "BUILD-DATUM",
|
||||
"desktop.info.thChanges": "ÄNDERUNGEN",
|
||||
|
||||
"desktop.dialog.addAgent": "Neuen Agenten anlegen",
|
||||
"desktop.dialog.agentId": "Agent-ID (eindeutiger Schlüssel):",
|
||||
"desktop.dialog.agentDisplayName": "Anzeigename:",
|
||||
"desktop.dialog.defaultModel": "Standard-Modell:",
|
||||
"desktop.dialog.roleDescription": "Beschreibung / Rolle:",
|
||||
"desktop.dialog.addJobTitle": "Job hinzufügen / bearbeiten",
|
||||
"desktop.dialog.jobType": "Job-Typ:",
|
||||
"desktop.dialog.agentWakeup": "Agent Wakeup (Periodische Ausführung)",
|
||||
"desktop.dialog.toolJob": "Tool Job (Werkzeug-spezifischer Job)",
|
||||
"desktop.dialog.jobTypeId": "Job-Typ-ID / Name:",
|
||||
"desktop.dialog.taskMessage": "Aufgabenbeschreibung / Nachricht:",
|
||||
"desktop.dialog.cronExpression": "Cron-Ausdruck:",
|
||||
"desktop.dialog.cronHint": "Syntax: Min Std Tag Mon Wochentag (z.B. '*/15 * * * *' alle 15 Minuten)",
|
||||
"desktop.dialog.runOnStart": "Beim Anwendungsstart einmalig sofort ausführen",
|
||||
"desktop.dialog.addServiceTitle": "Dienst (Service) hinzufügen",
|
||||
"desktop.dialog.serviceName": "Name des Dienstes:",
|
||||
"desktop.dialog.serviceType": "Typ:",
|
||||
"desktop.dialog.servicePort": "Port:",
|
||||
"desktop.dialog.serviceDesc": "Beschreibung:",
|
||||
"desktop.dialog.restoreTitle": "Sicherung wiederherstellen",
|
||||
"desktop.dialog.backupInfo": "Sicherungsinformationen",
|
||||
"desktop.dialog.backupInstance": "Instanz: {0}",
|
||||
"desktop.dialog.backupCreated": "Erstellt: {0:g}",
|
||||
"desktop.dialog.backupFiles": "Dateien: {0}",
|
||||
"desktop.dialog.backupSecrets": "Zugangsdaten: {0}",
|
||||
"desktop.dialog.targetDir": "Zielordner:",
|
||||
"desktop.dialog.chooseFolder": "Ordner wählen",
|
||||
"desktop.dialog.restoreHint": "Hinweis: Es wird empfohlen, in einen neuen Ordner wiederherzustellen, um Konflikte mit laufenden Prozessen zu vermeiden.",
|
||||
"desktop.dialog.passphrase": "Passphrase:",
|
||||
"desktop.dialog.passphraseProtected": "Diese Sicherung enthält geschützte Zugangsdaten.",
|
||||
"desktop.dialog.overwriteExisting": "Vorhandene Dateien im Zielordner überschreiben",
|
||||
"desktop.dialog.licenseTitle": "ClawdDotNet – Lizenz",
|
||||
"desktop.dialog.licenseKey": "Lizenzschlüssel",
|
||||
"desktop.dialog.hardwareId": "Hardware-ID (für den Support):",
|
||||
"desktop.dialog.verify": "Prüfen",
|
||||
"desktop.dialog.textEditorTitle": "Text bearbeiten",
|
||||
|
||||
"desktop.instancePicker.titleSwitch": "Instanz wechseln",
|
||||
"desktop.instancePicker.titleSelect": "Instanz wählen",
|
||||
"desktop.instancePicker.hintSwitch": "Jede Instanz läuft unabhängig mit eigenen Agenten und Daten. Wechseln startet ClawdDotNet mit der gewählten Instanz neu.",
|
||||
"desktop.instancePicker.hintSelect": "Jede Instanz läuft unabhängig mit eigenen Agenten und Daten.",
|
||||
"desktop.instancePicker.confirmSwitch": "Wechseln",
|
||||
"desktop.instancePicker.confirmStart": "Starten",
|
||||
"desktop.instancePicker.newInstancePlaceholder": "Name der neuen Instanz",
|
||||
"desktop.instancePicker.create": "Anlegen",
|
||||
"desktop.instancePicker.active": "Aktiv",
|
||||
"desktop.instancePicker.dirLabel": "Verzeichnis: {0}",
|
||||
"desktop.instancePicker.agentsCount": "{0} Agenten · API-Key {1}",
|
||||
"desktop.instancePicker.apiKeyConfigured": "konfiguriert",
|
||||
"desktop.instancePicker.apiKeyMissing": "fehlt",
|
||||
"desktop.instancePicker.tooltipConfigured": "API-Key hinterlegt",
|
||||
"desktop.instancePicker.tooltipMissing": "Kein API-Key — Agenten bleiben deaktiviert",
|
||||
"desktop.instancePicker.nameRequired": "Bitte einen Instanznamen eingeben.",
|
||||
"desktop.instancePicker.createFailed": "Instanz konnte nicht angelegt werden: {0}",
|
||||
|
||||
"desktop.startMode.title": "ClawdDotNet – Startmodus wählen",
|
||||
"desktop.startMode.question": "Wie möchtest du ClawdDotNet starten?",
|
||||
"desktop.startMode.managerBtn": "Instanzmanager starten (Empfohlen)",
|
||||
"desktop.startMode.standaloneBtn": "Als Standalone-Instanz starten",
|
||||
"desktop.startMode.explanation": "• Instanzmanager (Empfohlen):\n Startet den zentralen Hintergrund-Manager und öffnet die Verwaltung im Browser. Ermöglicht den stabilen Dauerbetrieb mehrerer Instanzen parallel ohne Absturzrisiko.\n\n• Standalone-Modus:\n Startet genau eine Instanz direkt als einzelnes Desktop-Fenster.",
|
||||
|
||||
"desktop.standaloneSwitch.title": "ClawdDotNet – Instanzwechsel (Standalone)",
|
||||
"desktop.standaloneSwitch.warning": "Achtung: Standalone-Modus",
|
||||
"desktop.standaloneSwitch.text": "Diese Instanz läuft eigenständig ohne Instanzmanager.\n\nWenn du die Instanz hier wechselst, wird diese Instanz vollständig beendet und alle laufenden Agenten und Hintergrunddienste werden gestoppt.\n\nEmpfehlung: Starte stattdessen den Instanzmanager, um mehrere Instanzen gleichzeitig und unabhängig voneinander zu betreiben.",
|
||||
"desktop.standaloneSwitch.switchAnyway": "Instanz trotzdem wechseln",
|
||||
|
||||
"desktop.toolSettings.noSettings": "Dieses Werkzeug benötigt keine weiteren Einstellungen.",
|
||||
"desktop.toolSettings.host": "Host",
|
||||
"desktop.toolSettings.port": "Port",
|
||||
"desktop.toolSettings.username": "Benutzername",
|
||||
"desktop.toolSettings.password": "Passwort",
|
||||
"desktop.toolSettings.rootPath": "Root-Pfad",
|
||||
"desktop.toolSettings.imapHost": "IMAP-Host",
|
||||
"desktop.toolSettings.imapPort": "IMAP-Port",
|
||||
"desktop.toolSettings.smtpHost": "SMTP-Host",
|
||||
"desktop.toolSettings.smtpPort": "SMTP-Port",
|
||||
"desktop.toolSettings.allowedRecipients": "Erlaubte Empfänger",
|
||||
"desktop.toolSettings.type": "Typ",
|
||||
"desktop.toolSettings.connectionString": "Connection-String",
|
||||
"desktop.toolSettings.accessLevel": "Zugriffsebene",
|
||||
"desktop.toolSettings.allowedTables": "Erlaubte Tabellen",
|
||||
"desktop.toolSettings.botToken": "Bot-Token",
|
||||
"desktop.toolSettings.defaultChatId": "Standard Chat-ID",
|
||||
"desktop.toolSettings.allowedChatIds": "Erlaubte Chat-IDs",
|
||||
"desktop.toolSettings.defaultProvider": "Standard-Provider",
|
||||
"desktop.toolSettings.cacheTtl": "Cache TTL (Sekunden)",
|
||||
"desktop.toolSettings.twelveDataKey": "Twelve Data Key",
|
||||
"desktop.toolSettings.alphaVantageKey": "Alpha Vantage Key",
|
||||
"desktop.toolSettings.allowedDomains": "Erlaubte Domains",
|
||||
"desktop.toolSettings.maxResponseKb": "Max. Antwortgröße (KB)",
|
||||
"desktop.toolSettings.userAgent": "User Agent",
|
||||
"desktop.toolSettings.xApiKey": "X (Twitter) API-Key",
|
||||
"desktop.toolSettings.xAccounts": "X Accounts",
|
||||
"desktop.toolSettings.subreddits": "Subreddits",
|
||||
"desktop.toolSettings.redditPostLimit": "Reddit Post Limit",
|
||||
"desktop.toolSettings.openRouterKey": "OpenRouter Key",
|
||||
"desktop.toolSettings.sttModel": "STT-Modell",
|
||||
"desktop.toolSettings.youtubeChannels": "YouTube-Kanäle",
|
||||
"desktop.toolSettings.fileRwPersonalExt": "Erlaubte Dateiendungen (persönlich)",
|
||||
"desktop.toolSettings.fileRwSharedAccess": "Zugriffsebene (geteilt)",
|
||||
"desktop.toolSettings.fileRwSharedExt": "Erlaubte Dateiendungen (geteilt)",
|
||||
"desktop.toolSettings.fileRwProtectedPaths": "Geschützte Pfade",
|
||||
|
||||
"nav.chat": "Chat",
|
||||
"nav.agents": "Agenten",
|
||||
"nav.tasks": "Aufgaben",
|
||||
"nav.usage": "Tokennutzung",
|
||||
"nav.agentChats": "Agenten-Chats",
|
||||
"nav.backup": "Sicherung",
|
||||
"nav.logs": "Protokoll",
|
||||
"nav.settings": "Einstellungen",
|
||||
"nav.info": "Info",
|
||||
|
||||
"common.all": "Alle",
|
||||
"common.save": "Speichern",
|
||||
"common.cancel": "Abbrechen",
|
||||
"common.delete": "Löschen",
|
||||
"common.edit": "Bearbeiten",
|
||||
"common.refresh": "Aktualisieren",
|
||||
"common.close": "Schließen",
|
||||
"common.discard": "Verwerfen",
|
||||
"common.ready": "Bereit",
|
||||
"common.loading": "Lade…",
|
||||
"common.create": "Anlegen",
|
||||
"common.add": "Hinzufügen",
|
||||
"common.apply": "Übernehmen",
|
||||
"common.ok": "OK",
|
||||
"common.exit": "Beenden"
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
{
|
||||
"desktop.mainWindow.title": "ClawdDotNet",
|
||||
"desktop.mainWindow.sidebarTooltip": "Toggle sidebar",
|
||||
"desktop.mainWindow.switchInstance": "Switch instance",
|
||||
"desktop.mainWindow.instance": "INSTANCE",
|
||||
"desktop.mainWindow.themeLight": "Light Mode",
|
||||
"desktop.mainWindow.themeDark": "Dark Mode",
|
||||
"desktop.mainWindow.themeToggle": "Toggle theme",
|
||||
"desktop.mainWindow.openInstanceFolder": "Open Instance Folder",
|
||||
"desktop.mainWindow.instanceManager": "Instance Manager",
|
||||
"desktop.mainWindow.exit": "Exit",
|
||||
"desktop.mainWindow.instanceLabel": "Instance: {0}",
|
||||
"desktop.mainWindow.apiStatus": "API {0}",
|
||||
"desktop.mainWindow.credits": "Credits: ${0:F2} of ${1:F2}",
|
||||
"desktop.mainWindow.creditsNone": "Credits: —",
|
||||
"desktop.mainWindow.dismiss": "Dismiss",
|
||||
|
||||
"desktop.nav.work": "Work",
|
||||
"desktop.nav.analytics": "Analytics",
|
||||
"desktop.nav.system": "System",
|
||||
|
||||
"desktop.status.unknown": "unknown",
|
||||
"desktop.status.design": "Design",
|
||||
"desktop.status.noApiKey": "no API key",
|
||||
"desktop.status.noUsageData": "no usage data",
|
||||
"desktop.status.ready": "Ready",
|
||||
"desktop.status.reachable": "OK",
|
||||
"desktop.status.unreachable": "unreachable",
|
||||
|
||||
"desktop.chat.agent": "Agent:",
|
||||
"desktop.chat.clearHistory": "Clear History",
|
||||
"desktop.chat.abort": "Abort",
|
||||
"desktop.chat.inputPlaceholder": "Type message… (Enter to send, Shift+Enter for new line)",
|
||||
"desktop.chat.send": "Send",
|
||||
"desktop.chat.statusReady": "Ready",
|
||||
"desktop.chat.statusSending": "Sending…",
|
||||
"desktop.chat.statusDesign": "Design Mode",
|
||||
"desktop.chat.noApiKey": "OpenRouter API key is not configured. Please enter the key in Settings.",
|
||||
"desktop.chat.noAgent": "Please select an agent.",
|
||||
"desktop.chat.emptyMessage": "Please enter a message.",
|
||||
|
||||
"desktop.agents.addAgent": "Agent",
|
||||
"desktop.agents.removeAgent": "Agent",
|
||||
"desktop.agents.runNow": "Run Now",
|
||||
"desktop.agents.identity": "Identity",
|
||||
"desktop.agents.soul": "Soul",
|
||||
"desktop.agents.folder": "Folder",
|
||||
"desktop.agents.save": "Save",
|
||||
"desktop.agents.thDisplayName": "DISPLAY NAME",
|
||||
"desktop.agents.thModel": "MODEL",
|
||||
"desktop.agents.thSummary": "SUMMARY",
|
||||
"desktop.agents.kickerGeneralModel": "GENERAL & MODEL",
|
||||
"desktop.agents.agentId": "Agent ID",
|
||||
"desktop.agents.displayName": "Display Name",
|
||||
"desktop.agents.model": "Model",
|
||||
"desktop.agents.promptCaching": "Prompt Caching",
|
||||
"desktop.agents.roleDescription": "Role / Description",
|
||||
"desktop.agents.systemPrompt": "System Prompt (additional instructions)",
|
||||
"desktop.agents.kickerLimits": "LIMITS",
|
||||
"desktop.agents.limitsTitle": "Guardrails (LoopGuard & Budget)",
|
||||
"desktop.agents.maxSteps": "Max Steps per Run",
|
||||
"desktop.agents.timeoutSeconds": "Timeout (seconds)",
|
||||
"desktop.agents.maxContextTokens": "Max Context Tokens",
|
||||
"desktop.agents.maxToolResultChars": "Max Tool Result (chars)",
|
||||
"desktop.agents.dailyCost": "Daily Budget ($ USD)",
|
||||
"desktop.agents.dailyTokens": "Daily Budget (Tokens)",
|
||||
"desktop.agents.allowedToolsFor": "ALLOWED TOOLS FOR {0}",
|
||||
"desktop.agents.thTool": "TOOL",
|
||||
"desktop.agents.thDescription": "DESCRIPTION",
|
||||
"desktop.agents.toolSettingsKicker": "TOOL SETTINGS",
|
||||
"desktop.agents.apply": "Apply",
|
||||
"desktop.agents.saved": "Agents saved successfully.",
|
||||
|
||||
"desktop.tasks.tabJobs": "Scheduled Jobs",
|
||||
"desktop.tasks.tabServices": "Services",
|
||||
"desktop.tasks.tabHistory": "History",
|
||||
"desktop.tasks.addJob": "Add Job",
|
||||
"desktop.tasks.editJob": "Edit",
|
||||
"desktop.tasks.removeJob": "Remove",
|
||||
"desktop.tasks.toggleJob": "Enable/Disable",
|
||||
"desktop.tasks.runJobNow": "Run Now",
|
||||
"desktop.tasks.refresh": "Refresh",
|
||||
"desktop.tasks.thType": "TYPE",
|
||||
"desktop.tasks.thAgent": "AGENT",
|
||||
"desktop.tasks.thTask": "TOOL / MESSAGE",
|
||||
"desktop.tasks.thCron": "CRON",
|
||||
"desktop.tasks.thNextRun": "NEXT RUN",
|
||||
"desktop.tasks.thLastRun": "LAST RUN",
|
||||
"desktop.tasks.thStatus": "STATUS",
|
||||
|
||||
"desktop.services.addService": "Add Service",
|
||||
"desktop.services.removeService": "Remove",
|
||||
"desktop.services.toggleService": "Enable/Disable",
|
||||
"desktop.services.thName": "SERVICE NAME",
|
||||
"desktop.services.thType": "TYPE",
|
||||
"desktop.services.thPort": "PORT",
|
||||
"desktop.services.thStatus": "STATUS",
|
||||
"desktop.services.thDescription": "DESCRIPTION",
|
||||
|
||||
"desktop.history.refresh": "Refresh History",
|
||||
"desktop.history.thTime": "TIMESTAMP",
|
||||
"desktop.history.thJob": "JOB",
|
||||
"desktop.history.thAgent": "AGENT",
|
||||
"desktop.history.thDescription": "DESCRIPTION",
|
||||
"desktop.history.thStatus": "STATUS",
|
||||
"desktop.history.thDetails": "DETAILS",
|
||||
|
||||
"desktop.usage.kickerTokens7d": "TOKENS (7 DAYS)",
|
||||
"desktop.usage.kickerCost7d": "COST (7 DAYS)",
|
||||
"desktop.usage.kickerRuns7d": "RUNS (7 DAYS)",
|
||||
"desktop.usage.refresh": "Refresh",
|
||||
"desktop.usage.tokensPerDay": "Tokens per Day",
|
||||
"desktop.usage.breakdownTitle": "Breakdown by Agent & Model",
|
||||
"desktop.usage.thAgent": "AGENT",
|
||||
"desktop.usage.thModel": "MODEL",
|
||||
"desktop.usage.thTokens": "TOKENS",
|
||||
"desktop.usage.thCost": "COST",
|
||||
"desktop.usage.thRuns": "RUNS",
|
||||
"desktop.usage.empty": "No token usage recorded yet.",
|
||||
|
||||
"desktop.agentChats.agentA": "Agent A:",
|
||||
"desktop.agentChats.agentB": "Agent B:",
|
||||
"desktop.agentChats.empty": "No messages between these agents yet.",
|
||||
"desktop.agentChats.needTwo": "At least two agents are required in this instance to view a conversation history.",
|
||||
|
||||
"desktop.backup.kickerManual": "MANUAL",
|
||||
"desktop.backup.titleCreate": "Create Backup",
|
||||
"desktop.backup.targetFolder": "Target Folder",
|
||||
"desktop.backup.targetFolderPlaceholder": "Target folder for backups…",
|
||||
"desktop.backup.browse": "Browse…",
|
||||
"desktop.backup.credentials": "Credentials",
|
||||
"desktop.backup.credentialsExclude": "do not include",
|
||||
"desktop.backup.credentialsProtect": "protect with passphrase",
|
||||
"desktop.backup.passphrase": "Enter passphrase",
|
||||
"desktop.backup.passphraseRepeat": "Repeat passphrase",
|
||||
"desktop.backup.scope": "Scope",
|
||||
"desktop.backup.scopeChat": "Chat history",
|
||||
"desktop.backup.scopeLogs": "Logs",
|
||||
"desktop.backup.createNow": "Create Backup Now",
|
||||
"desktop.backup.kickerAuto": "AUTOMATIC",
|
||||
"desktop.backup.titleAuto": "Automatic Backup",
|
||||
"desktop.backup.autoDaily": "daily backup at",
|
||||
"desktop.backup.time": "Time",
|
||||
"desktop.backup.keep": "Keep Count",
|
||||
"desktop.backup.autoHint": "Automatic backup excludes credentials — a saved passphrase would be ineffective.",
|
||||
"desktop.backup.kickerExisting": "EXISTING",
|
||||
"desktop.backup.titleExisting": "Existing Backups",
|
||||
"desktop.backup.refresh": "Refresh",
|
||||
"desktop.backup.openFolder": "Open Folder",
|
||||
"desktop.backup.delete": "Delete",
|
||||
"desktop.backup.restore": "Restore…",
|
||||
"desktop.backup.thFilename": "FILENAME",
|
||||
"desktop.backup.thCreatedAt": "CREATED AT",
|
||||
"desktop.backup.thInstance": "INSTANCE",
|
||||
"desktop.backup.thSize": "SIZE",
|
||||
"desktop.backup.thSecrets": "CREDENTIALS",
|
||||
|
||||
"desktop.logs.module": "Module:",
|
||||
"desktop.logs.level": "Level:",
|
||||
"desktop.logs.refresh": "Refresh",
|
||||
"desktop.logs.clear": "Clear",
|
||||
"desktop.logs.openFolder": "Open Folder",
|
||||
"desktop.logs.follow": "Follow Tail",
|
||||
|
||||
"desktop.settings.discard": "Discard",
|
||||
"desktop.settings.save": "Save",
|
||||
"desktop.settings.instance": "INSTANCE",
|
||||
"desktop.settings.instanceName": "Instance Name",
|
||||
"desktop.settings.apiKey": "OpenRouter API Key",
|
||||
"desktop.settings.autostart": "Autostart by Manager",
|
||||
"desktop.settings.autostartHint": "The instance manager starts this instance on launch and restarts it if it crashes.",
|
||||
"desktop.settings.logDir": "Log Directory",
|
||||
"desktop.settings.logDirHint": "Applies only to this instance. Empty means: Logs subfolder in instance directory.",
|
||||
"desktop.settings.dailyCost": "Daily Budget ($ USD)",
|
||||
"desktop.settings.dailyTokens": "Daily Budget (Tokens)",
|
||||
"desktop.settings.general": "GENERAL",
|
||||
"desktop.settings.instancesDir": "Instances Directory",
|
||||
"desktop.settings.minLogLevel": "Minimum Log Level",
|
||||
"desktop.settings.openRouterUrl": "OpenRouter Base URL",
|
||||
"desktop.settings.language": "Language",
|
||||
"desktop.settings.dcAndLicense": "DEPLOYMENTCENTER & LICENSE",
|
||||
"desktop.settings.dcUrl": "Server URL",
|
||||
"desktop.settings.dcToken": "Master Token",
|
||||
"desktop.settings.dcEnv": "Environment",
|
||||
"desktop.settings.updateChannel": "Update Channel",
|
||||
"desktop.settings.licenseKey": "License Key",
|
||||
"desktop.settings.errorReporting": "Automatically report errors to Deploymentcenter",
|
||||
"desktop.settings.updateCheck": "Check for updates automatically on startup",
|
||||
"desktop.settings.saved": "Settings and instance configuration saved successfully.",
|
||||
"desktop.settings.savedLogRestart": "Saved. The log directory will take effect upon next restart.",
|
||||
|
||||
"desktop.info.kickerApp": "APPLICATION",
|
||||
"desktop.info.build": "Build",
|
||||
"desktop.info.version": "Version",
|
||||
"desktop.info.buildSummary": "Build Summary",
|
||||
"desktop.info.kickerInstance": "INSTANCE",
|
||||
"desktop.info.currentInstance": "Current Instance",
|
||||
"desktop.info.openFolder": "Open Instance Folder",
|
||||
"desktop.info.name": "Name",
|
||||
"desktop.info.id": "ID",
|
||||
"desktop.info.path": "Path",
|
||||
"desktop.info.logDir": "Log Directory",
|
||||
"desktop.info.openRouter": "OpenRouter",
|
||||
"desktop.info.kickerModules": "MODULES",
|
||||
"desktop.info.assemblies": "Assemblies",
|
||||
"desktop.info.thModule": "MODULE",
|
||||
"desktop.info.thBuild": "BUILD",
|
||||
"desktop.info.thBuildDate": "BUILD DATE",
|
||||
"desktop.info.thChanges": "CHANGES",
|
||||
|
||||
"desktop.dialog.addAgent": "Create New Agent",
|
||||
"desktop.dialog.agentId": "Agent ID (unique key):",
|
||||
"desktop.dialog.agentDisplayName": "Display Name:",
|
||||
"desktop.dialog.defaultModel": "Default Model:",
|
||||
"desktop.dialog.roleDescription": "Description / Role:",
|
||||
"desktop.dialog.addJobTitle": "Add / Edit Job",
|
||||
"desktop.dialog.jobType": "Job Type:",
|
||||
"desktop.dialog.agentWakeup": "Agent Wakeup (Periodic Execution)",
|
||||
"desktop.dialog.toolJob": "Tool Job (Tool-specific Job)",
|
||||
"desktop.dialog.jobTypeId": "Job Type ID / Name:",
|
||||
"desktop.dialog.taskMessage": "Task Description / Message:",
|
||||
"desktop.dialog.cronExpression": "Cron Expression:",
|
||||
"desktop.dialog.cronHint": "Syntax: Min Hour Day Month Weekday (e.g. '*/15 * * * *' every 15 minutes)",
|
||||
"desktop.dialog.runOnStart": "Run once immediately on application startup",
|
||||
"desktop.dialog.addServiceTitle": "Add Service",
|
||||
"desktop.dialog.serviceName": "Service Name:",
|
||||
"desktop.dialog.serviceType": "Type:",
|
||||
"desktop.dialog.servicePort": "Port:",
|
||||
"desktop.dialog.serviceDesc": "Description:",
|
||||
"desktop.dialog.restoreTitle": "Restore Backup",
|
||||
"desktop.dialog.backupInfo": "Backup Information",
|
||||
"desktop.dialog.backupInstance": "Instance: {0}",
|
||||
"desktop.dialog.backupCreated": "Created: {0:g}",
|
||||
"desktop.dialog.backupFiles": "Files: {0}",
|
||||
"desktop.dialog.backupSecrets": "Credentials: {0}",
|
||||
"desktop.dialog.targetDir": "Target Directory:",
|
||||
"desktop.dialog.chooseFolder": "Choose Folder",
|
||||
"desktop.dialog.restoreHint": "Note: It is recommended to restore into a new folder to avoid conflicts with running processes.",
|
||||
"desktop.dialog.passphrase": "Passphrase:",
|
||||
"desktop.dialog.passphraseProtected": "This backup contains protected credentials.",
|
||||
"desktop.dialog.overwriteExisting": "Overwrite existing files in target folder",
|
||||
"desktop.dialog.licenseTitle": "ClawdDotNet – License",
|
||||
"desktop.dialog.licenseKey": "License Key",
|
||||
"desktop.dialog.hardwareId": "Hardware ID (for support):",
|
||||
"desktop.dialog.verify": "Verify",
|
||||
"desktop.dialog.textEditorTitle": "Edit Text",
|
||||
|
||||
"desktop.instancePicker.titleSwitch": "Switch Instance",
|
||||
"desktop.instancePicker.titleSelect": "Choose Instance",
|
||||
"desktop.instancePicker.hintSwitch": "Each instance runs independently with its own agents and data. Switching restarts ClawdDotNet with the selected instance.",
|
||||
"desktop.instancePicker.hintSelect": "Each instance runs independently with its own agents and data.",
|
||||
"desktop.instancePicker.confirmSwitch": "Switch",
|
||||
"desktop.instancePicker.confirmStart": "Start",
|
||||
"desktop.instancePicker.newInstancePlaceholder": "Name of new instance",
|
||||
"desktop.instancePicker.create": "Create",
|
||||
"desktop.instancePicker.active": "Active",
|
||||
"desktop.instancePicker.dirLabel": "Directory: {0}",
|
||||
"desktop.instancePicker.agentsCount": "{0} Agents · API Key {1}",
|
||||
"desktop.instancePicker.apiKeyConfigured": "configured",
|
||||
"desktop.instancePicker.apiKeyMissing": "missing",
|
||||
"desktop.instancePicker.tooltipConfigured": "API key configured",
|
||||
"desktop.instancePicker.tooltipMissing": "No API key — agents remain inactive",
|
||||
"desktop.instancePicker.nameRequired": "Please enter an instance name.",
|
||||
"desktop.instancePicker.createFailed": "Instance could not be created: {0}",
|
||||
|
||||
"desktop.startMode.title": "ClawdDotNet – Select Start Mode",
|
||||
"desktop.startMode.question": "How would you like to start ClawdDotNet?",
|
||||
"desktop.startMode.managerBtn": "Launch Instance Manager (Recommended)",
|
||||
"desktop.startMode.standaloneBtn": "Start as Standalone Instance",
|
||||
"desktop.startMode.explanation": "• Instance Manager (Recommended):\n Starts the central background manager and opens management in your browser. Enables stable parallel operation of multiple instances without crash risks.\n\n• Standalone Mode:\n Starts exactly one instance directly as a single desktop window.",
|
||||
|
||||
"desktop.standaloneSwitch.title": "ClawdDotNet – Instance Switch (Standalone)",
|
||||
"desktop.standaloneSwitch.warning": "Attention: Standalone Mode",
|
||||
"desktop.standaloneSwitch.text": "This instance runs standalone without the Instance Manager.\n\nIf you switch instances here, this instance will be fully stopped and all running agents and background services will end.\n\nRecommendation: Launch the Instance Manager instead to run multiple instances concurrently and independently.",
|
||||
"desktop.standaloneSwitch.switchAnyway": "Switch Instance Anyway",
|
||||
|
||||
"desktop.toolSettings.noSettings": "This tool does not require additional settings.",
|
||||
"desktop.toolSettings.host": "Host",
|
||||
"desktop.toolSettings.port": "Port",
|
||||
"desktop.toolSettings.username": "Username",
|
||||
"desktop.toolSettings.password": "Password",
|
||||
"desktop.toolSettings.rootPath": "Root Path",
|
||||
"desktop.toolSettings.imapHost": "IMAP Host",
|
||||
"desktop.toolSettings.imapPort": "IMAP Port",
|
||||
"desktop.toolSettings.smtpHost": "SMTP Host",
|
||||
"desktop.toolSettings.smtpPort": "SMTP Port",
|
||||
"desktop.toolSettings.allowedRecipients": "Allowed Recipients",
|
||||
"desktop.toolSettings.type": "Type",
|
||||
"desktop.toolSettings.connectionString": "Connection String",
|
||||
"desktop.toolSettings.accessLevel": "Access Level",
|
||||
"desktop.toolSettings.allowedTables": "Allowed Tables",
|
||||
"desktop.toolSettings.botToken": "Bot Token",
|
||||
"desktop.toolSettings.defaultChatId": "Default Chat ID",
|
||||
"desktop.toolSettings.allowedChatIds": "Allowed Chat IDs",
|
||||
"desktop.toolSettings.defaultProvider": "Default Provider",
|
||||
"desktop.toolSettings.cacheTtl": "Cache TTL (seconds)",
|
||||
"desktop.toolSettings.twelveDataKey": "Twelve Data Key",
|
||||
"desktop.toolSettings.alphaVantageKey": "Alpha Vantage Key",
|
||||
"desktop.toolSettings.allowedDomains": "Allowed Domains",
|
||||
"desktop.toolSettings.maxResponseKb": "Max Response Size (KB)",
|
||||
"desktop.toolSettings.userAgent": "User Agent",
|
||||
"desktop.toolSettings.xApiKey": "X (Twitter) API Key",
|
||||
"desktop.toolSettings.xAccounts": "X Accounts",
|
||||
"desktop.toolSettings.subreddits": "Subreddits",
|
||||
"desktop.toolSettings.redditPostLimit": "Reddit Post Limit",
|
||||
"desktop.toolSettings.openRouterKey": "OpenRouter Key",
|
||||
"desktop.toolSettings.sttModel": "STT Model",
|
||||
"desktop.toolSettings.youtubeChannels": "YouTube Channels",
|
||||
"desktop.toolSettings.fileRwPersonalExt": "Allowed File Extensions (personal)",
|
||||
"desktop.toolSettings.fileRwSharedAccess": "Access Level (shared)",
|
||||
"desktop.toolSettings.fileRwSharedExt": "Allowed File Extensions (shared)",
|
||||
"desktop.toolSettings.fileRwProtectedPaths": "Protected Paths",
|
||||
|
||||
"nav.chat": "Chat",
|
||||
"nav.agents": "Agents",
|
||||
"nav.tasks": "Tasks",
|
||||
"nav.usage": "Token Usage",
|
||||
"nav.agentChats": "Agent Chats",
|
||||
"nav.backup": "Backup",
|
||||
"nav.logs": "Logs",
|
||||
"nav.settings": "Settings",
|
||||
"nav.info": "Info",
|
||||
|
||||
"common.all": "All",
|
||||
"common.save": "Save",
|
||||
"common.cancel": "Cancel",
|
||||
"common.delete": "Delete",
|
||||
"common.edit": "Edit",
|
||||
"common.refresh": "Refresh",
|
||||
"common.close": "Close",
|
||||
"common.discard": "Discard",
|
||||
"common.ready": "Ready",
|
||||
"common.loading": "Loading…",
|
||||
"common.create": "Create",
|
||||
"common.add": "Add",
|
||||
"common.apply": "Apply",
|
||||
"common.ok": "OK",
|
||||
"common.exit": "Exit"
|
||||
}
|
||||
Reference in New Issue
Block a user