Skip to content

Commit 45c6ecd

Browse files
authored
Codex (#2730)
* Codex upgrade * dotnet format * Fix
1 parent 4c2cef0 commit 45c6ecd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+703
-509
lines changed

src/Elastic.Codex/Building/CodexBuildService.cs

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
using Elastic.Codex.Sourcing;
99
using Elastic.Documentation;
1010
using Elastic.Documentation.Configuration;
11+
using Elastic.Documentation.Configuration.Codex;
1112
using Elastic.Documentation.Diagnostics;
1213
using Elastic.Documentation.Isolated;
1314
using Elastic.Documentation.Links.CrossLinks;
1415
using Elastic.Documentation.Navigation;
1516
using Elastic.Documentation.Navigation.Isolated.Node;
1617
using Elastic.Documentation.Services;
18+
using Elastic.Documentation.Site;
1719
using Elastic.Documentation.Site.Navigation;
1820
using Elastic.Markdown.Exporters;
1921
using Elastic.Markdown.IO;
@@ -44,8 +46,13 @@ public async Task<CodexBuildResult> BuildAll(
4446
IReadOnlySet<Exporter>? exporters = null)
4547
{
4648
var outputDir = context.OutputDirectory;
47-
if (!outputDir.Exists)
48-
outputDir.Create();
49+
if (outputDir.Exists)
50+
{
51+
_logger.LogInformation("Cleaning target output directory: {Directory}", outputDir.FullName);
52+
outputDir.Delete(true);
53+
}
54+
55+
outputDir.Create();
4956

5057
_logger.LogInformation("Building {Count} documentation sets to {Directory}",
5158
cloneResult.Checkouts.Count, outputDir.FullName);
@@ -97,11 +104,14 @@ public async Task<CodexBuildResult> BuildAll(
97104
await Task.WhenAll(stopTasks);
98105
}
99106

100-
// Phase 4: Generate codex landing and category pages
107+
// Phase 4: Generate codex landing and group pages
108+
CodexGenerator? codexGenerator = null;
101109
if (buildContexts.Count > 0)
102-
await GenerateCodexPages(context, buildContexts[0].BuildContext, codexNavigation, ctx);
110+
{
111+
codexGenerator = await GenerateCodexPages(context, buildContexts[0].BuildContext, codexNavigation, ctx);
112+
}
103113

104-
return new CodexBuildResult(codexNavigation, buildContexts.Select(b => b.DocumentationSet).ToList());
114+
return new CodexBuildResult(codexNavigation, buildContexts.Select(b => b.DocumentationSet).ToList(), codexGenerator);
105115
}
106116

107117
private async Task<CodexDocumentationSetBuildContext?> LoadDocumentationSet(
@@ -187,13 +197,16 @@ private async Task BuildDocumentationSet(
187197

188198
try
189199
{
200+
var reference = buildContext.Checkout.Reference;
201+
var codexBreadcrumbs = ResolveCodexBreadcrumbs(context, reference);
202+
190203
_ = await isolatedBuildService.BuildDocumentationSet(
191204
buildContext.DocumentationSet,
192205
null, // Use doc set's navigation for traversal
193206
null, // Use default navigation HTML writer (doc set's navigation)
194207
ExportOptions.Default,
195208
sharedExporters,
196-
pageViewFactory: new CodexPageViewFactory(context.Configuration.Title),
209+
pageViewFactory: new CodexPageViewFactory(context.Configuration.Title, codexBreadcrumbs),
197210
ctx);
198211
}
199212
catch (Exception ex)
@@ -204,7 +217,27 @@ private async Task BuildDocumentationSet(
204217
}
205218
}
206219

207-
private async Task GenerateCodexPages(
220+
private static IReadOnlyList<CodexBreadcrumb> ResolveCodexBreadcrumbs(
221+
CodexContext context,
222+
CodexDocumentationSetReference reference)
223+
{
224+
var sitePrefix = context.Configuration.SitePrefix?.Trim('/') ?? "";
225+
var repoName = reference.ResolvedRepoName;
226+
var groupId = reference.Group;
227+
var homeUrl = string.IsNullOrEmpty(sitePrefix) ? "/" : $"/{sitePrefix}/";
228+
var docSetUrl = string.IsNullOrEmpty(sitePrefix) ? $"/r/{repoName}" : $"/{sitePrefix}/r/{repoName}";
229+
var docSetTitle = reference.DisplayName ?? repoName;
230+
231+
if (string.IsNullOrEmpty(groupId))
232+
return [new CodexBreadcrumb("Home", homeUrl), new CodexBreadcrumb(docSetTitle, docSetUrl)];
233+
234+
var groupUrl = string.IsNullOrEmpty(sitePrefix) ? $"/g/{groupId}" : $"/{sitePrefix}/g/{groupId}";
235+
var groupDef = context.Configuration.Groups.FirstOrDefault(g => g.Id == groupId);
236+
var groupTitle = groupDef?.Name ?? groupId;
237+
return [new CodexBreadcrumb("Home", homeUrl), new CodexBreadcrumb(groupTitle, groupUrl), new CodexBreadcrumb(docSetTitle, docSetUrl)];
238+
}
239+
240+
private async Task<CodexGenerator> GenerateCodexPages(
208241
CodexContext context,
209242
BuildContext docSetBuildContext,
210243
CodexNavigation codexNavigation,
@@ -230,6 +263,7 @@ private async Task GenerateCodexPages(
230263
// Use CodexGenerator to render the codex pages to the codex's output directory
231264
var codexGenerator = new CodexGenerator(logFactory, codexBuildContext, context.OutputDirectory);
232265
await codexGenerator.Generate(codexNavigation, ctx);
266+
return codexGenerator;
233267
}
234268
}
235269

@@ -238,9 +272,11 @@ private async Task GenerateCodexPages(
238272
/// </summary>
239273
/// <param name="Navigation">The codex navigation structure.</param>
240274
/// <param name="DocumentationSets">The built documentation sets.</param>
275+
/// <param name="CodexGenerator">Generator for re-rendering codex pages (e.g. for dev server).</param>
241276
public record CodexBuildResult(
242277
CodexNavigation Navigation,
243-
IReadOnlyList<DocumentationSet> DocumentationSets);
278+
IReadOnlyList<DocumentationSet> DocumentationSets,
279+
CodexGenerator? CodexGenerator = null);
244280

245281
/// <summary>
246282
/// Build context for a single documentation set within the codex.

src/Elastic.Codex/Category/CategoryView.cshtml

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/Elastic.Codex/Category/CategoryViewModel.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/Elastic.Codex/CodexViewModel.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public abstract class CodexViewModel(CodexRenderContext context)
4646
/// <summary>
4747
/// Creates the global layout model for the page.
4848
/// </summary>
49-
public GlobalLayoutViewModel CreateGlobalLayoutModel()
49+
public GlobalLayoutViewModel CreateGlobalLayoutModel(IReadOnlyList<CodexBreadcrumb>? codexBreadcrumbs = null)
5050
{
5151
var rootPath = BuildContext.SiteRootPath ?? GetDefaultRootPath(BuildContext.UrlPathPrefix);
5252
return new()
@@ -66,7 +66,8 @@ public GlobalLayoutViewModel CreateGlobalLayoutModel()
6666
Optimizely = new OptimizelyConfiguration(),
6767
Features = new FeatureFlags([]),
6868
StaticFileContentHashProvider = StaticFileContentHashProvider,
69-
BuildType = BuildContext.BuildType
69+
BuildType = BuildContext.BuildType,
70+
CodexBreadcrumbs = codexBreadcrumbs
7071
};
7172
}
7273

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
@inherits RazorSliceHttpResult<Elastic.Codex.Group.GroupLandingViewModel>
2+
@using System.Linq
23
@using Elastic.Codex.Group
4+
@using Elastic.Codex.Landing
35
@using Elastic.Codex.Navigation
4-
@implements IUsesLayout<Elastic.Codex._Layout, GlobalLayoutViewModel>
6+
@implements IUsesLayout<Elastic.Codex._GroupLayout, GlobalLayoutViewModel>
57
@functions {
6-
public GlobalLayoutViewModel LayoutModel => Model.CreateGlobalLayoutModel();
8+
public GlobalLayoutViewModel LayoutModel => Model.CreateGlobalLayoutModel(
9+
codexBreadcrumbs: [new CodexBreadcrumb("Home", Model.BuildContext.SiteRootPath ?? "/"), new CodexBreadcrumb(Model.Group.DisplayTitle, Model.Group.Url)]);
710
}
8-
<section id="elastic-docs-v3" class="codex-group-page">
9-
<div class="codex-header py-8">
10-
<h1 class="text-3xl font-bold mb-4">@Model.Group.DisplayTitle</h1>
11-
<p class="text-gray-60">Documentation sets in this group</p>
11+
<section id="elastic-docs-v3" class="codex-landing min-h-screen">
12+
<div class="pt-8 max-w-7xl mx-auto">
13+
<h1 class="text-5xl font-medium text-black">@Model.Group.DisplayTitle</h1>
14+
@if (!string.IsNullOrEmpty(Model.Group.Description))
15+
{
16+
<p class="mt-2 text-lg text-subdued">@Model.Group.Description</p>
17+
}
1218
</div>
13-
14-
<div class="codex-grid grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8">
19+
<div id="codex-grid" class="pt-8 max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
1520
@foreach (var docSet in Model.DocumentationSets.OrderBy(ds => ds.Title))
1621
{
17-
<a href="@docSet.Url"
18-
hx-select-oob="#main-container"
19-
preload="mousedown"
20-
class="codex-card block p-6 rounded-lg border border-gray-20 hover:border-blue-40 hover:shadow-md transition-all">
21-
<div class="codex-card-content">
22-
<h3 class="text-xl font-medium mb-2 text-gray-80">@docSet.Title</h3>
23-
<div class="codex-card-meta text-sm text-gray-50">
24-
<span>@docSet.PageCount pages</span>
25-
</div>
26-
</div>
27-
</a>
22+
@(await RenderPartialAsync(_CodexCard.Create(new CodexCardModel
23+
{
24+
Url = docSet.Url,
25+
Title = docSet.Title ?? docSet.Name,
26+
Description = docSet.Description,
27+
Icon = docSet.Icon,
28+
PageCount = docSet.PageCount
29+
})))
2830
}
2931
</div>
3032
</section>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
namespace Elastic.Codex.Landing;
6+
7+
/// <summary>
8+
/// Model for a codex landing page card (used for both group cards and docset cards).
9+
/// </summary>
10+
public record CodexCardModel
11+
{
12+
public required string Url { get; init; }
13+
public required string Title { get; init; }
14+
public string? Description { get; init; }
15+
public string? Icon { get; init; }
16+
public int PageCount { get; init; }
17+
}

0 commit comments

Comments
 (0)