Organigramm: Lage je Abteilung in der Teamuebersicht (#688)
- TeamMember: Laeufe und Kosten heute, offene und blockierte Aufgaben je Agent (eine Abfrage fuer alle, nicht eine je Agent) - TeamUnit: dieselben Werte samt Untereinheiten, offene Vorgaenge aus der Einheit, heutige Kostenmeldung (#699) - team.js: Lagezeile auf jeder Karte und in der Seitenleiste, Instanz summiert; Spruenge zu Kosten je Einheit und zu den Vorgaengen; i18n en/de - Tests: TeamOverviewTests (+2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
888369698d
commit
f649f2fd7a
@@ -186,4 +186,63 @@ public sealed class TeamOverviewTests
|
||||
TeamOverview.Readable(elsewhere, configured).ShouldBe(elsewhere);
|
||||
TeamOverview.Readable(elsewhere, []).ShouldBe(elsewhere);
|
||||
}
|
||||
|
||||
// ═══════════════════ the department's situation (#688) ═══════════════════
|
||||
|
||||
[Fact]
|
||||
public void A_departments_day_is_added_up_along_the_tree()
|
||||
{
|
||||
var units = TeamOverview.RollUp(Shop(),
|
||||
[
|
||||
Member("marketing-lead", "marketing", TeamState.Idle) with { RunsToday = 2, CostToday = 0.5m, OpenTasks = 1 },
|
||||
Member("ads", "amazon", TeamState.Idle) with { RunsToday = 5, CostToday = 1.25m, OpenTasks = 3, BlockedTasks = 1 }
|
||||
]);
|
||||
|
||||
var marketing = units.Single(u => u.Id == "marketing");
|
||||
marketing.RunsToday.ShouldBe(7);
|
||||
marketing.CostToday.ShouldBe(1.75m);
|
||||
marketing.OpenTasks.ShouldBe(4);
|
||||
marketing.BlockedTasks.ShouldBe(1);
|
||||
units.Single(u => u.Id == "amazon").CostToday.ShouldBe(1.25m);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task The_snapshot_carries_runs_cost_tasks_cases_and_the_cost_alert_of_today()
|
||||
{
|
||||
var directory = Path.Combine(Path.GetTempPath(), "clawd-tests", "team-" + Guid.NewGuid().ToString("N")[..8]);
|
||||
try
|
||||
{
|
||||
var storage = new Core.Storage.SqliteStorage(Path.Combine(directory, "state.db"));
|
||||
var usage = new Core.Accounting.SqliteUsageRepository(storage);
|
||||
var board = new Core.Tasks.TaskboardService(new Core.Tasks.SqliteTaskRepository(storage), Path.Combine(directory, "tasks"));
|
||||
var cases = new Core.Cases.SqliteCaseRepository(storage);
|
||||
await usage.RecordAsync(new Core.Accounting.RunUsage { AgentId = "ads", Model = "m", CostUsd = 0.4m, CostIsKnown = true, Status = "Completed", OccurredAt = DateTime.Now }, default);
|
||||
await board.CreateAsync(new Core.Tasks.TaskItem { Title = "Bid for spring", Assignee = "@ads" }, default);
|
||||
await board.CreateAsync(new Core.Tasks.TaskItem { Title = "Waiting", Assignee = "@ads", Status = Core.Tasks.TaskItemStatus.Blocked }, default);
|
||||
await cases.SaveAsync(new Core.Cases.CaseRecord { Id = "c-1", Subject = "Field", OpenedBy = "ads", OpenedUnitId = "amazon", OpenedAt = DateTime.UtcNow }, default);
|
||||
var today = DateOnly.FromDateTime(DateTime.Now).ToString("yyyy-MM-dd");
|
||||
|
||||
var overview = new TeamOverview(null, null, null, usage, () => Shop().Agents.ToList(),
|
||||
organisation: Shop, board: board, cases: cases,
|
||||
costAlerts: _ => Task.FromResult<IReadOnlyList<Core.Accounting.RaisedCostAlert>>(
|
||||
[new Core.Accounting.RaisedCostAlert(today, "amazon", Core.Accounting.CostAlertKind.Deviation, "x", DateTime.UtcNow)]));
|
||||
|
||||
var snapshot = await overview.SnapshotAsync(default);
|
||||
|
||||
var ads = snapshot.Members.Single(m => m.AgentId == "ads");
|
||||
ads.RunsToday.ShouldBe(1);
|
||||
ads.CostToday.ShouldBe(0.4m);
|
||||
ads.OpenTasks.ShouldBe(1);
|
||||
ads.BlockedTasks.ShouldBe(1);
|
||||
var marketing = snapshot.Units!.Single(u => u.Id == "marketing");
|
||||
marketing.OpenCases.ShouldBe(1, "a case raised in amazon lies inside marketing");
|
||||
snapshot.Units!.Single(u => u.Id == "amazon").CostAlert.ShouldBe("Deviation");
|
||||
marketing.CostAlert.ShouldBeNull("the alert was raised on amazon, not on marketing");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Core.Storage.SqliteStorage.ReleasePooledConnections(directory);
|
||||
try { Directory.Delete(directory, recursive: true); } catch { /* cleanup is secondary */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user