Forge
csharp3407750f
1using AgentForge.Abstractions;
2using AgentForge.Plugin.Grouping.Core;
3using AgentForge.Plugin.Grouping.Repositories.Axes;
4using AgentForge.Plugin.Grouping.Repositories.Enrichers;
5using AgentForge.Plugin.View;
6using Microsoft.Extensions.DependencyInjection;
7
8namespace AgentForge.Plugin.Grouping.Repositories;
9
10public sealed class ForgeOrgCatalogGroupingService(
11 ForgeGroupingAxisCatalog<IForgeCatalogGroupingAxis, ForgeCatalogGroupingRepoRow> axes,
12 IEnumerable<IForgeCatalogGroupingRepoEnricher> enrichers) : IForgeOrgCatalogGrouping
13{
14 public IReadOnlyList<string> ParseGroupStack(string? groupStackQuery) =>
15 axes.ParseStack(groupStackQuery);
16
17 public int ParseEditorRowCount(string? groupStackRowsQuery, int stackCount) =>
18 ForgeGroupingStackOptions.ParseEditorRowCount(groupStackRowsQuery, stackCount);
19
20 public string BuildCatalogUrl(
21 in ForgeOrgCatalogViewContext context,
22 string? groupPath = null,
23 IReadOnlyList<string>? groupStack = null,
24 int? editorRowCount = null)
25 {
26 var parts = new List<string>();
27 var activeGroupPath = groupPath ?? context.ActiveGroupPath;
28 if (!string.IsNullOrWhiteSpace(activeGroupPath))
29 parts.Add($"group={Uri.EscapeDataString(ForgeRepoGroupPath.ToUrlPath(activeGroupPath))}");
30
31 var stack = groupStack ?? context.GroupStack;
32 if (stack.Count > 0)
33 parts.Add($"groupStack={Uri.EscapeDataString(string.Join(',', stack))}");
34
35 var rows = editorRowCount ?? context.EditorRowCount;
36 if (rows > 0 && ForgeGroupingStackOptions.ShouldEmitEditorRowCountQuery(rows, stack.Count))
37 parts.Add($"groupStackRows={rows}");
38
39 return parts.Count == 0
40 ? context.CatalogBasePath
41 : $"{context.CatalogBasePath}?{string.Join('&', parts)}";
42 }
43
44 public string RenderToolbar(in ForgeOrgCatalogViewContext context) =>
45 ForgeViewCatalogGroupingToolbar.Render(this, axes, context);
46
47 public void AppendRepoNodes(
48 ICollection<string> childNodes,
49 IReadOnlyList<ForgeOrgCatalogRepoItem> repos,
50 in ForgeOrgCatalogViewContext context)
51 {
52 if (repos.Count == 0)
53 return;
54
55 if (context.GroupStack.Count == 0)
56 {
57 foreach (var repo in repos)
58 childNodes.Add(ForgeViewCatalogRepoNode.Render(repo));
59 return;
60 }
61
62 var body = RenderRepoBody(repos, context);
63 if (!string.IsNullOrEmpty(body))
64 childNodes.Add(ForgeHtml.Li("org-repo-grouped", body));
65 }
66
67 public string RenderRepoBody(
68 IReadOnlyList<ForgeOrgCatalogRepoItem> repos,
69 in ForgeOrgCatalogViewContext context)
70 {
71 if (repos.Count == 0)
72 return "";
73
74 if (context.GroupStack.Count == 0)
75 return ForgeHtml.Ul("plain org-repo-tree-children", [.. repos.Select(ForgeViewCatalogRepoNode.Render)]);
76
77 var rows = BuildRows(repos);
78 var nested = ForgeGroupingNestedRenderer.Render(
79 axes,
80 rows,
81 context.GroupStack,
82 static row => ForgeViewCatalogRepoNode.Render(row.Item),
83 listClass: "plain org-repo-tree-children");
84
85 return string.IsNullOrEmpty(nested)
86 ? ForgeHtml.Ul("plain org-repo-tree-children", [.. repos.Select(ForgeViewCatalogRepoNode.Render)])
87 : nested;
88 }
89
90 private List<ForgeCatalogGroupingRepoRow> BuildRows(IReadOnlyList<ForgeOrgCatalogRepoItem> repos)
91 {
92 var rows = repos
93 .Select(repo => new ForgeCatalogGroupingRepoRow { Item = repo })
94 .ToList();
95
96 foreach (var enricher in enrichers)
97 enricher.Enrich(repos, rows);
98
99 return rows;
100 }
101
102 internal static void RegisterAxes(IServiceCollection services)
103 {
104 services.AddSingleton<IForgeCatalogGroupingAxis, VisibilityCatalogGroupingAxis>();
105 services.AddSingleton<IForgeCatalogGroupingAxis, DriveModeCatalogGroupingAxis>();
106 services.AddSingleton<IForgeCatalogGroupingAxis, LastCommitCatalogGroupingAxis>();
107 services.AddSingleton<IForgeCatalogGroupingAxis, CreatedAtCatalogGroupingAxis>();
108 services.AddSingleton<IForgeCatalogGroupingAxis, OrgCatalogGroupingAxis>();
109 services.AddSingleton<IForgeCatalogGroupingAxis, GroupCatalogGroupingAxis>();
110 services.AddSingleton<IForgeCatalogGroupingRepoEnricher, LastCommitRepoEnricher>();
111 services.AddSingleton<ForgeGroupingAxisCatalog<IForgeCatalogGroupingAxis, ForgeCatalogGroupingRepoRow>>(sp =>
112 new(sp.GetServices<IForgeCatalogGroupingAxis>(), "repository"));
113 }
114}
115
View only · write via MCP/CIDE