feat(ui): complete Avalonia UI port with 7 main pages, tool settings & top MenuBar
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
using ClawdDotNet.Core.Config;
|
||||
using ClawdDotNet.Core.Scheduling;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ClawdDotNet.Core.Tasks;
|
||||
|
||||
/// <summary>
|
||||
/// Überführt die alten Scheduler-Konfigurationen ins Taskboard — der letzte Schritt, um
|
||||
/// die Alt-Scheduler abzulösen: alles Periodische ist danach ein Task.
|
||||
///
|
||||
/// - Ein <c>scheduler</c> (Agent nach Cron) → ein Task mit <c>when: cron</c> und Assignee
|
||||
/// <c>@new:<agent></c> (frischer Lauf, wie der alte AgentScheduler).
|
||||
/// - Jeder <c>toolJobs</c>-Eintrag (Poll) → ein Task vom Typ <c>tool_job</c>.
|
||||
///
|
||||
/// Einmalig und nicht-destruktiv: Existiert der Task (stabile Id) schon, wird er
|
||||
/// übersprungen — spätere Änderungen an der Task-Datei bleiben erhalten.
|
||||
/// </summary>
|
||||
public sealed class SchedulerTaskMigration
|
||||
{
|
||||
private readonly TaskboardService _board;
|
||||
private readonly ITaskRepository _repo;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public SchedulerTaskMigration(TaskboardService board, ITaskRepository repo, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_board = board;
|
||||
_repo = repo;
|
||||
_logger = loggerFactory.CreateLogger("ClawdDotNet.Core.Tasks.SchedulerMigration");
|
||||
}
|
||||
|
||||
public async Task<int> RunAsync(IEnumerable<AgentConfig> agents, CancellationToken ct)
|
||||
{
|
||||
// IANA-Schreibweise, nicht TimeZoneInfo.Local.Id: Unter Windows lieferte das
|
||||
// "W. Europe Standard Time", unter Linux "Europe/Berlin". Die erzeugten
|
||||
// Task-Dateien wandern zwischen Rechnern — sie brauchen die Form, die überall
|
||||
// gilt.
|
||||
var localTz = TimeZones.LocalIanaId;
|
||||
var created = 0;
|
||||
|
||||
foreach (var agent in agents)
|
||||
{
|
||||
if (agent.Scheduler is { } scheduler && !string.IsNullOrWhiteSpace(scheduler.Cron))
|
||||
created += await MigrateSchedulerAsync(agent, scheduler, localTz, ct);
|
||||
|
||||
foreach (var job in agent.ToolJobs)
|
||||
created += await MigrateToolJobAsync(agent, job, localTz, ct);
|
||||
}
|
||||
|
||||
if (created > 0)
|
||||
_logger.LogInformation("Scheduler-Migration: {Count} Task(s) aus Alt-Konfiguration angelegt", created);
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
private async Task<int> MigrateSchedulerAsync(
|
||||
AgentConfig agent, SchedulerConfig scheduler, string tz, CancellationToken ct)
|
||||
{
|
||||
var id = $"sched-{agent.AgentId}";
|
||||
if (await _repo.GetAsync(id, ct) is not null)
|
||||
return 0;
|
||||
|
||||
await _board.CreateAsync(new TaskItem
|
||||
{
|
||||
Id = id,
|
||||
Title = $"Geplanter Lauf: {Display(agent)}",
|
||||
Body = scheduler.TaskMessage,
|
||||
Status = TaskItemStatus.Todo,
|
||||
Type = TaskItemType.Work,
|
||||
Assignee = $"@new:{agent.AgentId}", // frischer Lauf, wie der alte AgentScheduler
|
||||
When = new TaskWhen { Kind = TaskWhenKind.Cron, Value = scheduler.Cron, TimeZone = tz }
|
||||
}, ct);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private async Task<int> MigrateToolJobAsync(
|
||||
AgentConfig agent, ToolJobConfig job, string tz, CancellationToken ct)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(job.Cron) || string.IsNullOrWhiteSpace(job.ToolName))
|
||||
return 0;
|
||||
|
||||
var id = $"tj-{agent.AgentId}-{job.JobId}";
|
||||
if (await _repo.GetAsync(id, ct) is not null)
|
||||
return 0;
|
||||
|
||||
await _board.CreateAsync(new TaskItem
|
||||
{
|
||||
Id = id,
|
||||
Title = $"Poll: {job.ToolName}/{job.JobTypeId} → {Display(agent)}",
|
||||
Body = $"Wiederkehrender {job.ToolName}-Poll ({job.JobTypeId}). Weckt {Display(agent)} bei einem Ereignis.",
|
||||
// Deaktivierte Jobs kommen als backlog — der Scanner nimmt nur todo/backlog...
|
||||
// backlog wird aber nicht geclaimt, also ruht der Poll, bis jemand ihn aktiviert.
|
||||
Status = job.Enabled ? TaskItemStatus.Todo : TaskItemStatus.Backlog,
|
||||
Type = TaskItemType.ToolJob,
|
||||
ToolName = job.ToolName,
|
||||
JobTypeId = job.JobTypeId,
|
||||
Assignee = $"@{agent.AgentId}", // Zielagent zum Wecken
|
||||
When = new TaskWhen { Kind = TaskWhenKind.Cron, Value = job.Cron, TimeZone = tz }
|
||||
}, ct);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static string Display(AgentConfig agent)
|
||||
=> string.IsNullOrWhiteSpace(agent.DisplayName) ? agent.AgentId : agent.DisplayName;
|
||||
}
|
||||
Reference in New Issue
Block a user