Skip to content

Commit 3faa5f6

Browse files
committed
feat: add prune tasks to tasks ui
1 parent b98115c commit 3faa5f6

13 files changed

Lines changed: 457 additions & 17 deletions

‎GitProtect.Client/Components/ProviderBackupView.razor‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ else
295295
};
296296

297297
private bool IsProviderBackupRunning => tasks.Any(task =>
298-
task.Provider == Provider
298+
task.TaskType == BackupTaskType.Backup
299+
&& task.Provider == Provider
299300
&& task.RepositoryId is null
300301
&& IsTaskActive(task.Status));
301302

@@ -305,7 +306,8 @@ else
305306
|| repoBackupRequests.Contains(repoId)
306307
|| IsProviderBackupRunning
307308
|| tasks.Any(task =>
308-
task.Provider == Provider
309+
task.TaskType == BackupTaskType.Backup
310+
&& task.Provider == Provider
309311
&& task.RepositoryId == repoId
310312
&& IsTaskActive(task.Status));
311313
}

‎GitProtect.Client/Models/ApiContracts.cs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ public enum BackupTaskStatus
2323
Failed = 3
2424
}
2525

26+
public enum BackupTaskType
27+
{
28+
Backup = 0,
29+
Prune = 1
30+
}
31+
32+
public enum BackupTaskTrigger
33+
{
34+
Manual = 0,
35+
Scheduled = 1
36+
}
37+
2638
public sealed record SetupStatusDto(bool StorageConfigured, bool StorageVerified, IReadOnlyList<ProviderStatusDto> Providers);
2739

2840
public sealed record ProviderStatusDto(
@@ -62,9 +74,11 @@ public sealed record RepositoryDto(
6274
public sealed record BackupTaskDto(
6375
int Id,
6476
string Name,
65-
ProviderType Provider,
77+
ProviderType? Provider,
6678
int? RepositoryId,
6779
BackupTaskStatus Status,
80+
BackupTaskType TaskType,
81+
BackupTaskTrigger Trigger,
6882
int Progress,
6983
DateTime CreatedAt,
7084
DateTime? StartedAt,

‎GitProtect.Client/Pages/Tasks.razor‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ else
3434
<tr>
3535
<th>Task</th>
3636
<th>Status</th>
37+
<th>Type</th>
3738
<th>Progress</th>
3839
<th>Started</th>
3940
</tr>
@@ -57,6 +58,7 @@ else
5758
@GetStatusBadge(task.Status)
5859
}
5960
</td>
61+
<td>@GetTriggerLabel(task.Trigger)</td>
6062
<td>@task.Progress%</td>
6163
<td>@(task.StartedAt?.ToLocalTime().ToString("g") ?? "-")</td>
6264
</tr>
@@ -181,6 +183,9 @@ else
181183
builder.CloseElement();
182184
};
183185

186+
private static string GetTriggerLabel(BackupTaskTrigger trigger)
187+
=> trigger == BackupTaskTrigger.Scheduled ? "Scheduled" : "Manual";
188+
184189
public ValueTask DisposeAsync()
185190
{
186191
refreshCts?.Cancel();

‎GitProtect/Data/GitProtectDbContext.cs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
4545
modelBuilder.Entity<BackupTask>()
4646
.Property(t => t.Status)
4747
.HasConversion<string>();
48+
49+
modelBuilder.Entity<BackupTask>()
50+
.Property(t => t.TaskType)
51+
.HasConversion<string>();
52+
53+
modelBuilder.Entity<BackupTask>()
54+
.Property(t => t.Trigger)
55+
.HasConversion<string>();
4856
}
4957
}

‎GitProtect/Endpoints/ApiContracts.cs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,11 @@ public sealed record RepositoryDto(
6363
public sealed record BackupTaskDto(
6464
int Id,
6565
string Name,
66-
ProviderType Provider,
66+
ProviderType? Provider,
6767
int? RepositoryId,
6868
BackupTaskStatus Status,
69+
BackupTaskType TaskType,
70+
BackupTaskTrigger Trigger,
6971
int Progress,
7072
DateTime CreatedAt,
7173
DateTime? StartedAt,

‎GitProtect/Endpoints/ApiEndpoints.cs‎

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ public static IEndpointRouteBuilder MapGitProtectApi(this IEndpointRouteBuilder
161161
Provider = providerType,
162162
Name = $"{providerType} Backup",
163163
Status = BackupTaskStatus.Pending,
164+
TaskType = BackupTaskType.Backup,
165+
Trigger = BackupTaskTrigger.Manual,
164166
Progress = 0
165167
};
166168

@@ -200,6 +202,8 @@ public static IEndpointRouteBuilder MapGitProtectApi(this IEndpointRouteBuilder
200202
RepositoryId = repoId,
201203
Name = $"{repo.FullName} Backup",
202204
Status = BackupTaskStatus.Pending,
205+
TaskType = BackupTaskType.Backup,
206+
Trigger = BackupTaskTrigger.Manual,
203207
Progress = 0
204208
};
205209

@@ -362,10 +366,46 @@ public static IEndpointRouteBuilder MapGitProtectApi(this IEndpointRouteBuilder
362366
return Results.BadRequest(new { message = "Storage is not configured." });
363367
}
364368

365-
var cutoff = DateTimeOffset.UtcNow.AddDays(-policy.RetentionDays);
366-
var deleted = await storageService.DeleteBackupsOlderThanAsync(storage, cutoff, cancellationToken);
369+
var task = new BackupTask
370+
{
371+
Name = "Retention Prune",
372+
Status = BackupTaskStatus.Running,
373+
TaskType = BackupTaskType.Prune,
374+
Trigger = BackupTaskTrigger.Manual,
375+
Progress = 0,
376+
StartedAt = DateTime.UtcNow
377+
};
378+
379+
db.BackupTasks.Add(task);
380+
await db.SaveChangesAsync(cancellationToken);
381+
382+
try
383+
{
384+
var cutoff = DateTimeOffset.UtcNow.AddDays(-policy.RetentionDays);
385+
var deleted = await storageService.DeleteBackupsOlderThanAsync(storage, cutoff, cancellationToken);
386+
387+
task.Status = BackupTaskStatus.Success;
388+
task.Progress = 100;
389+
task.CompletedAt = DateTime.UtcNow;
390+
task.Message = deleted > 0
391+
? $"Deleted {deleted} backup object(s) older than {cutoff.UtcDateTime:g}."
392+
: "No expired backups were found.";
367393

368-
return Results.Ok(new RetentionPruneResultDto(deleted, cutoff.UtcDateTime));
394+
await db.SaveChangesAsync(cancellationToken);
395+
396+
return Results.Ok(new RetentionPruneResultDto(deleted, cutoff.UtcDateTime));
397+
}
398+
catch (Exception ex)
399+
{
400+
task.Status = BackupTaskStatus.Failed;
401+
task.Progress = 100;
402+
task.CompletedAt = DateTime.UtcNow;
403+
task.Message = ex.Message;
404+
405+
await db.SaveChangesAsync(cancellationToken);
406+
407+
return Results.Problem("Retention prune failed.");
408+
}
369409
});
370410

371411
api.MapGet("/dashboard", async (GitProtectDbContext db, CancellationToken cancellationToken) =>
@@ -434,6 +474,8 @@ private static BackupTaskDto ToTaskDto(BackupTask task)
434474
task.Provider,
435475
task.RepositoryId,
436476
task.Status,
477+
task.TaskType,
478+
task.Trigger,
437479
task.Progress,
438480
task.CreatedAt,
439481
task.StartedAt,
@@ -501,7 +543,8 @@ private static async Task<ProviderConfig> GetOrCreateProviderAsync(GitProtectDbC
501543
private static Task<bool> IsProviderBackupInProgressAsync(GitProtectDbContext db, ProviderType provider, CancellationToken cancellationToken)
502544
{
503545
return db.BackupTasks.AnyAsync(t =>
504-
t.Provider == provider
546+
t.TaskType == BackupTaskType.Backup
547+
&& t.Provider == provider
505548
&& t.RepositoryId == null
506549
&& (t.Status == BackupTaskStatus.Pending || t.Status == BackupTaskStatus.Running),
507550
cancellationToken);
@@ -510,7 +553,8 @@ private static Task<bool> IsProviderBackupInProgressAsync(GitProtectDbContext db
510553
private static Task<bool> IsRepositoryBackupInProgressAsync(GitProtectDbContext db, ProviderType provider, int repoId, CancellationToken cancellationToken)
511554
{
512555
return db.BackupTasks.AnyAsync(t =>
513-
t.Provider == provider
556+
t.TaskType == BackupTaskType.Backup
557+
&& t.Provider == provider
514558
&& t.RepositoryId == repoId
515559
&& (t.Status == BackupTaskStatus.Pending || t.Status == BackupTaskStatus.Running),
516560
cancellationToken);

0 commit comments

Comments
 (0)