Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/data/openapi/api-explorer.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ specs per product are not currently supported.

Product pages show an API product switcher in the left navigation. The list includes every declared API and a Back to hub option.

Assembler API pages also show a Jump to API box at the top of that sidebar. The box searches API operations only. Isolated and air-gapped builds omit the box. Markdown docs pages do not get it back.

## Remote spec resolution

When `spec:` does not resolve to a file on disk, {{dbuild}} resolves the current (`main`) version
Expand Down
4 changes: 4 additions & 0 deletions src/Elastic.ApiExplorer/Infrastructure/ApiViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public record ApiLayoutViewModel : GlobalLayoutViewModel
public required ApiBreadcrumbTrail Breadcrumbs { get; init; }
public IReadOnlyList<ApiVersionSwitcherItem> VersionSwitcherItems { get; init; } = [];
public IReadOnlyList<ApiVersionSwitcherItem> HubSwitcherItems { get; init; } = [];

/// <summary>Assembler builds host Jump to API unless the site is air-gapped.</summary>
public bool ShowJumpToPage => BuildType == BuildType.Assembler && !Features.AirGappedEnabled;

public required string MarkdownUrl { get; init; }

/// <summary>
Expand Down
39 changes: 23 additions & 16 deletions src/Elastic.ApiExplorer/_Partials/Layout/_ApiPagesNav.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,33 @@
id="pages-nav"
@(Model.Features.NavigationPreviewEnabled ? "hx-preserve" : "")
class="sidebar-nav h-full simple-scrollbar">
@if (Model.HubSwitcherItems.Count > 0)
@if (Model.ShowJumpToPage || Model.HubSwitcherItems.Count > 0)
{
<div class="sticky top-0 z-10 bg-white px-4 pt-4 pb-2 flex flex-col gap-2">
<label for="api-hub-switcher" class="sr-only">API product</label>
<select
id="api-hub-switcher"
class="w-full border border-grey-20 rounded-sm font-sans font-semibold text-sm pl-3 pr-8 py-2 bg-white hover:border-grey-40 focus:outline-none focus:ring-2 focus:ring-blue-elastic-50 cursor-pointer"
onchange="window.location.href = this.value">
@foreach (var item in Model.HubSwitcherItems)
{
if (item.Selected)
@if (Model.ShowJumpToPage)
{
<navigation-search type="api" placeholder="Jump to API"></navigation-search>
}
@if (Model.HubSwitcherItems.Count > 0)
{
<label for="api-hub-switcher" class="sr-only">API product</label>
<select
id="api-hub-switcher"
class="w-full border border-grey-20 rounded-sm font-sans font-semibold text-sm pl-3 pr-8 py-2 bg-white hover:border-grey-40 focus:outline-none focus:ring-2 focus:ring-blue-elastic-50 cursor-pointer"
onchange="window.location.href = this.value">
@foreach (var item in Model.HubSwitcherItems)
{
<option value="@item.Url" selected>@item.Label</option>
if (item.Selected)
{
<option value="@item.Url" selected>@item.Label</option>
}
else
{
<option value="@item.Url">@item.Label</option>
}
}
else
{
<option value="@item.Url">@item.Label</option>
}
}
</select>
</select>
}
</div>
}
<ul class="hidden md:flex items-center gap-4 px-4 pt-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const loadWebComponents = createWebComponentLoader({
'version-dropdown': () => import('./VersionDropdown'),
'applies-to-popover': () => import('./AppliesToPopover'),
'page-feedback': () => import('./PageFeedback'),
'navigation-search': () =>
import('./NavigationSearch/NavigationSearchComponent'),
'diagnostics-panel': () => import('./Diagnostics/DiagnosticsComponent'),
'storybook-story': () => import('./StorybookStory/StorybookStoryComponent'),
'vector-sizing-calculator': () =>
Expand Down
55 changes: 54 additions & 1 deletion tests/Elastic.ApiExplorer.Tests/ApiPagesNavRenderingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,64 @@ public async Task Render_PreservesTheNavAcrossHtmxSwapsWhenPreviewEnabled()
html.Should().Contain("hx-preserve");
}

[Fact]
public async Task Render_ShowsJumpToPageOnAssemblerBuilds()
{
var model = CreateLayoutModel("/api/doc/elasticsearch/", "/api/doc/elasticsearch.md", buildType: BuildType.Assembler);

var html = await _ApiPagesNav.Create(model).RenderAsync(cancellationToken: TestContext.Current.CancellationToken);

html.Should().Contain("<navigation-search type=\"api\" placeholder=\"Jump to API\"></navigation-search>");
}

[Fact]
public async Task Render_ShowsJumpToPageWhenNavigationPreviewIsOn()
{
var model = CreateLayoutModel(
"/api/doc/elasticsearch/",
"/api/doc/elasticsearch.md",
features: new FeatureFlags(new Dictionary<string, bool> { ["navigation-preview"] = true }),
buildType: BuildType.Assembler
);

var html = await _ApiPagesNav.Create(model).RenderAsync(cancellationToken: TestContext.Current.CancellationToken);

html.Should().Contain("<navigation-search type=\"api\" placeholder=\"Jump to API\"></navigation-search>");
html.Should().Contain("hx-preserve");
}

[Fact]
public async Task Render_OmitsJumpToPageOnIsolatedBuilds()
{
var model = CreateLayoutModel("/api/doc/elasticsearch/", "/api/doc/elasticsearch.md", buildType: BuildType.Isolated);

var html = await _ApiPagesNav.Create(model).RenderAsync(cancellationToken: TestContext.Current.CancellationToken);

html.Should().NotContain("navigation-search");
}

[Fact]
public async Task Render_OmitsJumpToPageWhenAirGapped()
{
var model = CreateLayoutModel(
"/api/doc/elasticsearch/",
"/api/doc/elasticsearch.md",
features: new FeatureFlags(new Dictionary<string, bool> { ["air-gapped"] = true }),
buildType: BuildType.Assembler
);

var html = await _ApiPagesNav.Create(model).RenderAsync(cancellationToken: TestContext.Current.CancellationToken);

html.Should().NotContain("navigation-search");
}

private static ApiLayoutViewModel CreateLayoutModel(
string navigationUrl,
string markdownUrl,
IReadOnlyList<ApiVersionSwitcherItem>? versionSwitcherItems = null,
IReadOnlyList<ApiVersionSwitcherItem>? hubSwitcherItems = null,
FeatureFlags? features = null
FeatureFlags? features = null,
BuildType buildType = BuildType.Isolated
)
{
var fs = new FileSystem();
Expand Down Expand Up @@ -120,6 +172,7 @@ private static ApiLayoutViewModel CreateLayoutModel(
Breadcrumbs = ApiBreadcrumbTrail.Empty,
VersionSwitcherItems = versionSwitcherItems ?? [],
HubSwitcherItems = hubSwitcherItems ?? [],
BuildType = buildType,
};
}

Expand Down
Loading