feat(ui): Settings-Tab fuer die Ticketsystem-Anbindung

This commit is contained in:
mika kuns
2026-08-27 13:29:49 +02:00
parent f0a3a186dd
commit 020f93d55e
5 changed files with 158 additions and 2 deletions
@@ -0,0 +1,92 @@
using ClaudeDo.Ui.Localization;
using ClaudeDo.Ui.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ClaudeDo.Ui.ViewModels.Modals.Settings;
public sealed partial class TicketSettingsTabViewModel : ViewModelBase
{
private readonly IWorkerClient _worker;
[ObservableProperty] private string _apiBaseUrl = "";
[ObservableProperty] private string _token = "";
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(TokenPlaceholder))]
private bool _tokenSet;
[ObservableProperty] private bool _isBusy;
[ObservableProperty] private string _statusMessage = "";
// Never shows the stored token — TicketSettingsDto only ever carries the bool.
public string TokenPlaceholder => TokenSet ? Loc.T("settings.tickets.tokenSet") : "";
public TicketSettingsTabViewModel(IWorkerClient worker) => _worker = worker;
public async Task LoadAsync()
{
var dto = await _worker.GetTicketSettingsAsync();
if (dto is null)
{
StatusMessage = Loc.T("vm.tickets.workerOffline");
return;
}
ApiBaseUrl = dto.ApiBaseUrl ?? "";
TokenSet = dto.TokenSet;
}
public async Task SaveAsync()
{
await _worker.SetTicketApiBaseUrlAsync(ApiBaseUrl);
if (!string.IsNullOrWhiteSpace(Token))
{
await _worker.SetTicketTokenAsync(Token);
Token = "";
TokenSet = true;
}
}
[RelayCommand]
private async Task TestConnection()
{
IsBusy = true;
StatusMessage = "";
try
{
await SaveAsync();
var result = await _worker.TestTicketConnectionAsync();
if (result is null || !result.Ok)
{
StatusMessage = result?.Error ?? Loc.T("vm.tickets.workerOffline");
return;
}
var missing = RequiredScopes.Where(s => !result.Scopes.Contains(s)).ToList();
StatusMessage = missing.Count == 0
? Loc.T("vm.tickets.connectionOk", result.UserName!)
: Loc.T("vm.tickets.connectionMissingScopes", result.UserName!, string.Join(", ", missing));
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task ClearToken()
{
await _worker.ClearTicketTokenAsync();
Token = "";
TokenSet = false;
StatusMessage = Loc.T("vm.tickets.tokenCleared");
}
// Ohne diese drei Scopes scheitert entweder der Import oder die Statusrueckmeldung —
// der mit Abstand haeufigste Konfigurationsfehler, deshalb wird er beim Testen benannt
// statt nur geloggt.
private static readonly string[] RequiredScopes =
[
"pat:projects:read",
"pat:board:read",
"pat:tickets:write",
];
}