From addf3758e41531e405b6640e0da2928c91f0e2fc Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 14 Jul 2025 14:27:40 +0200 Subject: [PATCH 1/3] API landing page now contains a listing of all API's for ease of reference --- .../Landing/LandingView.cshtml | 84 +++++++++- .../Operations/OperationView.cshtml | 5 +- .../Assets/api-docs.css | 150 +++++++++++++----- .../docs-builder/Http/DocumentationWebHost.cs | 3 + .../Http/ReloadableGeneratorState.cs | 2 + 5 files changed, 197 insertions(+), 47 deletions(-) diff --git a/src/Elastic.ApiExplorer/Landing/LandingView.cshtml b/src/Elastic.ApiExplorer/Landing/LandingView.cshtml index 767bf996d..880d23948 100644 --- a/src/Elastic.ApiExplorer/Landing/LandingView.cshtml +++ b/src/Elastic.ApiExplorer/Landing/LandingView.cshtml @@ -1,10 +1,92 @@ @inherits RazorSliceHttpResult +@using Elastic.ApiExplorer.Landing +@using Elastic.ApiExplorer.Operations +@using Elastic.Documentation.Site.Navigation @implements IUsesLayout @functions { public GlobalLayoutViewModel LayoutModel => Model.CreateGlobalLayoutModel(); + + private IHtmlContent RenderOp(IReadOnlyCollection endpointOperations) + { + + + return HtmlString.Empty; + } + + private IHtmlContent RenderProduct(INavigationItem item) + { + if (item is INodeNavigationItem node) + { + foreach (var navigationItem in node.NavigationItems) + { + if (navigationItem is ClassificationNavigationItem classification) + { + +

@(classification.NavigationTitle)

+ + @RenderProduct(classification) + } + else if (navigationItem is TagNavigationItem tag) + { + +

@(tag.NavigationTitle)

+ + @RenderProduct(tag) + } + else if (navigationItem is EndpointNavigationItem endpoint) + { + var endpointOperations = + endpoint is { NavigationItems.Count: > 0 } && endpoint.NavigationItems.All(n => n.Hidden) + ? endpoint.NavigationItems + : []; + if (endpointOperations.Count > 0) + { + + @(endpoint.NavigationTitle) + @RenderOp(endpointOperations) + + } + else + { + @RenderProduct(endpoint) + } + } + else if (navigationItem is OperationNavigationItem operation) + { + + @(operation.NavigationTitle) + @RenderOp([operation]) + + } + else + { + throw new Exception($"Unexpected type: {item.GetType().FullName}"); + } + } + } + + return HtmlString.Empty; + + } }

@Model.ApiInfo.Title

@Model.ApiInfo.Description

-

License: @Model.ApiInfo.License?.Identifier

+

License: @Model.ApiInfo.License?.Name

+
+ + @RenderProduct(Model.CurrentNavigationItem.NavigationRoot) +
+
diff --git a/src/Elastic.ApiExplorer/Operations/OperationView.cshtml b/src/Elastic.ApiExplorer/Operations/OperationView.cshtml index a6e80d120..0c9977f23 100644 --- a/src/Elastic.ApiExplorer/Operations/OperationView.cshtml +++ b/src/Elastic.ApiExplorer/Operations/OperationView.cshtml @@ -7,10 +7,9 @@ public GlobalLayoutViewModel LayoutModel => Model.CreateGlobalLayoutModel(); } @{ - var parent = Model.CurrentNavigationItem.Parent as EndpointNavigationItem; var self = Model.CurrentNavigationItem as OperationNavigationItem; var allOperations = - parent is not null && parent.NavigationItems.Count > 0 && parent.NavigationItems.All(n => n.Hidden) + Model.CurrentNavigationItem.Parent is EndpointNavigationItem { NavigationItems.Count: > 0 } parent && parent.NavigationItems.All(n => n.Hidden) ? parent.NavigationItems : self is not null ? [self] @@ -87,4 +86,4 @@ - \ No newline at end of file + diff --git a/src/Elastic.Documentation.Site/Assets/api-docs.css b/src/Elastic.Documentation.Site/Assets/api-docs.css index 15bd423e8..f5ffcb737 100644 --- a/src/Elastic.Documentation.Site/Assets/api-docs.css +++ b/src/Elastic.Documentation.Site/Assets/api-docs.css @@ -42,6 +42,12 @@ @apply border-grey-30 text-grey-120 bg-white; font-weight: bold; } + a.api-url-list-item-landing { + font-weight: normal !important; + } + a.api-url-list-item-landing:hover { + font-weight: normal !important; + } } li:only-child { a.current { @@ -51,53 +57,111 @@ @apply border-grey-20 bg-white; } } - .api-method { - @apply rounded-sm border; - padding-left: var(--spacing); - padding-right: var(--spacing); - font-family: var( - --default-mono-font-family, - ui-monospace, - SFMono-Regular, - Menlo, - Monaco, - Consolas, - 'Liberation Mono', - 'Courier New', - monospace - ); - font-feature-settings: var( - --default-mono-font-feature-settings, - normal - ); - font-variation-settings: var( - --default-mono-font-variation-settings, - normal - ); - font-size: 0.8em; - display: inline-block; - font-weight: bold; - } - .api-method-get { - @apply border-blue-elastic-30 bg-blue-elastic-10 text-blue-elastic; - } - .api-method-put { - @apply border-yellow-30 bg-yellow-10 text-yellow-90; - } - .api-method-post { - @apply border-green-30 bg-green-10 text-green-90; - } - .api-method-delete { - @apply border-red-30 bg-red-10 text-red-90; - } - .api-url { - margin-left: calc(var(--spacing) * 2); - display: inline-block; - } .api-url-list-item { @apply mt-4; } } +.api-overview { + .api-url-listing { + @apply mt-1; + } + .api-url-list-item { + @apply mt-1; + } + li { + a { + @apply text-grey-80 inline-block w-full p-2 pr-2 pl-2 no-underline; + @apply border-white rounded-sm border; + } + a:hover { + @apply bg-grey-10; + @apply border-grey-20; + } + a.current { + @apply text-grey-80 inline-block w-full p-2 pr-2 pl-2 no-underline; + @apply border-white rounded-sm border; + } + a.current:hover { + @apply bg-grey-10; + @apply border-grey-20; + } + } + li:only-child { + a.current { + @apply text-grey-80 inline-block w-full p-2 pr-2 pl-2 no-underline; + @apply border-white rounded-sm border; + } + a.current:hover { + @apply bg-grey-10; + } + } + table { + td { + text-align: left; + vertical-align: top; + } + td:has(h2) { + } + td:has(h3) { + @apply border-b-grey-20 border-b-1 pb-2 mb-2; + } + td.api-name { + @apply pr-2; + text-align: left; + font-weight: bold; + } + tr:has(td.api-name) { + @apply border-b-grey-10 border-b-1; + } + tr:has(td.api-name) td { + @apply pt-4 mt-4 pb-4 mb-4; + } + } +} + +.api-method { + @apply rounded-sm border; + padding-left: var(--spacing); + padding-right: var(--spacing); + font-family: var( + --default-mono-font-family, + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + 'Liberation Mono', + 'Courier New', + monospace + ); + font-feature-settings: var( + --default-mono-font-feature-settings, + normal + ); + font-variation-settings: var( + --default-mono-font-variation-settings, + normal + ); + font-size: 0.8em; + display: inline-block; + font-weight: bold; +} +.api-method-get { + @apply border-blue-elastic-30 bg-blue-elastic-10 text-blue-elastic; +} +.api-method-put { + @apply border-yellow-30 bg-yellow-10 text-yellow-90; +} +.api-method-post { + @apply border-green-30 bg-green-10 text-green-90; +} +.api-method-delete { + @apply border-red-30 bg-red-10 text-red-90; +} +.api-url { + margin-left: calc(var(--spacing) * 2); + display: inline-block; +} #elastic-api-v3 { dt a { @apply no-underline; diff --git a/src/tooling/docs-builder/Http/DocumentationWebHost.cs b/src/tooling/docs-builder/Http/DocumentationWebHost.cs index cbd856b70..307433250 100644 --- a/src/tooling/docs-builder/Http/DocumentationWebHost.cs +++ b/src/tooling/docs-builder/Http/DocumentationWebHost.cs @@ -165,6 +165,9 @@ await context.Response.WriteAsync(@" private async Task ServeApiFile(ReloadableGeneratorState holder, string slug, Cancel ctx) { +#if DEBUG + await holder.ReloadApiReferences(ctx); +#endif var path = Path.Combine(holder.ApiPath.FullName, slug.Trim('/'), "index.html"); var info = _writeFileSystem.FileInfo.New(path); if (info.Exists) diff --git a/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs b/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs index 971cf6979..ef931880d 100644 --- a/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs +++ b/src/tooling/docs-builder/Http/ReloadableGeneratorState.cs @@ -40,6 +40,8 @@ public async Task ReloadAsync(Cancel ctx) await ReloadApiReferences(generator.MarkdownStringRenderer, ctx); } + public async Task ReloadApiReferences(Cancel ctx) => await ReloadApiReferences(_generator.MarkdownStringRenderer, ctx); + private async Task ReloadApiReferences(IMarkdownStringRenderer markdownStringRenderer, Cancel ctx) { if (ApiPath.Exists) From 234bd0d28badd2017043d19a96c78f150250c783 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 14 Jul 2025 16:21:29 +0200 Subject: [PATCH 2/3] simplify navigation if using tag groups --- .../Landing/LandingNavigationItem.cs | 4 +- .../Landing/LandingView.cshtml | 2 +- .../Navigation/_TocTree.cshtml | 86 +++++++++---------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/Elastic.ApiExplorer/Landing/LandingNavigationItem.cs b/src/Elastic.ApiExplorer/Landing/LandingNavigationItem.cs index 28ef25b87..9fb5c00ef 100644 --- a/src/Elastic.ApiExplorer/Landing/LandingNavigationItem.cs +++ b/src/Elastic.ApiExplorer/Landing/LandingNavigationItem.cs @@ -52,7 +52,7 @@ public LandingNavigationItem(string url) } /// - public bool IsUsingNavigationDropdown => NavigationItems.OfType().Any(); + public bool IsUsingNavigationDropdown => false; } public interface IApiGroupingNavigationItem : INodeNavigationItem @@ -106,7 +106,7 @@ public class ClassificationNavigationItem(ApiClassification classification, Land public override string Id { get; } = ShortId.Create(classification.Name); /// - public bool IsUsingNavigationDropdown => true; + public bool IsUsingNavigationDropdown => false; } public class TagNavigationItem(ApiTag tag, IRootNavigationItem rootNavigation, INodeNavigationItem parent) diff --git a/src/Elastic.ApiExplorer/Landing/LandingView.cshtml b/src/Elastic.ApiExplorer/Landing/LandingView.cshtml index 880d23948..8d81b5502 100644 --- a/src/Elastic.ApiExplorer/Landing/LandingView.cshtml +++ b/src/Elastic.ApiExplorer/Landing/LandingView.cshtml @@ -82,7 +82,7 @@ }

@Model.ApiInfo.Title

-

@Model.ApiInfo.Description

+

@Model.RenderMarkdown(Model.ApiInfo.Description)

License: @Model.ApiInfo.License?.Name

diff --git a/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml b/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml index ac5386eb1..d54da09ea 100644 --- a/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml +++ b/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml @@ -6,44 +6,44 @@ var currentTopLevelItem = Model.TopLevelItems.FirstOrDefault(i => i.Id == Model.Tree.Id) ?? Model.Tree; } @if (Model.IsUsingNavigationDropdown && currentTopLevelItem is { Index: not null }) - { -
-
- + { +
+
+
@@ -57,16 +57,16 @@ @Model.Title } - -
    - @await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem - { - IsPrimaryNavEnabled = Model.IsPrimaryNavEnabled, - IsGlobalAssemblyBuild = Model.IsGlobalAssemblyBuild, - Level = 0, - SubTree = Model.Tree, - RootNavigationId = Model.Tree.Id, - MaxLevel = Model.MaxLevel - })) -
+ +
    + @await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem + { + IsPrimaryNavEnabled = Model.IsPrimaryNavEnabled, + IsGlobalAssemblyBuild = Model.IsGlobalAssemblyBuild, + Level = 0, + SubTree = Model.Tree, + RootNavigationId = Model.Tree.Id, + MaxLevel = Model.MaxLevel + })) +
From a48896fc17aad2321fa4f7dc2b76ffba73bb6739 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 14 Jul 2025 16:27:35 +0200 Subject: [PATCH 3/3] lint and only reload API on debug --- .../Assets/api-docs.css | 15 ++++++--------- .../docs-builder/Http/DocumentationWebHost.cs | 4 +++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Elastic.Documentation.Site/Assets/api-docs.css b/src/Elastic.Documentation.Site/Assets/api-docs.css index f5ffcb737..5e0bf16e7 100644 --- a/src/Elastic.Documentation.Site/Assets/api-docs.css +++ b/src/Elastic.Documentation.Site/Assets/api-docs.css @@ -71,7 +71,7 @@ li { a { @apply text-grey-80 inline-block w-full p-2 pr-2 pl-2 no-underline; - @apply border-white rounded-sm border; + @apply rounded-sm border border-white; } a:hover { @apply bg-grey-10; @@ -79,7 +79,7 @@ } a.current { @apply text-grey-80 inline-block w-full p-2 pr-2 pl-2 no-underline; - @apply border-white rounded-sm border; + @apply rounded-sm border border-white; } a.current:hover { @apply bg-grey-10; @@ -89,7 +89,7 @@ li:only-child { a.current { @apply text-grey-80 inline-block w-full p-2 pr-2 pl-2 no-underline; - @apply border-white rounded-sm border; + @apply rounded-sm border border-white; } a.current:hover { @apply bg-grey-10; @@ -103,7 +103,7 @@ td:has(h2) { } td:has(h3) { - @apply border-b-grey-20 border-b-1 pb-2 mb-2; + @apply border-b-grey-20 mb-2 border-b-1 pb-2; } td.api-name { @apply pr-2; @@ -114,7 +114,7 @@ @apply border-b-grey-10 border-b-1; } tr:has(td.api-name) td { - @apply pt-4 mt-4 pb-4 mb-4; + @apply mt-4 mb-4 pt-4 pb-4; } } } @@ -134,10 +134,7 @@ 'Courier New', monospace ); - font-feature-settings: var( - --default-mono-font-feature-settings, - normal - ); + font-feature-settings: var(--default-mono-font-feature-settings, normal); font-variation-settings: var( --default-mono-font-variation-settings, normal diff --git a/src/tooling/docs-builder/Http/DocumentationWebHost.cs b/src/tooling/docs-builder/Http/DocumentationWebHost.cs index 307433250..cd93f081f 100644 --- a/src/tooling/docs-builder/Http/DocumentationWebHost.cs +++ b/src/tooling/docs-builder/Http/DocumentationWebHost.cs @@ -166,7 +166,9 @@ await context.Response.WriteAsync(@" private async Task ServeApiFile(ReloadableGeneratorState holder, string slug, Cancel ctx) { #if DEBUG - await holder.ReloadApiReferences(ctx); + // only reload when actually debugging + if (System.Diagnostics.Debugger.IsAttached) + await holder.ReloadApiReferences(ctx); #endif var path = Path.Combine(holder.ApiPath.FullName, slug.Trim('/'), "index.html"); var info = _writeFileSystem.FileInfo.New(path);