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
4 changes: 3 additions & 1 deletion docs/data/openapi/api-explorer.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Authored API Markdown pages can use [`meta_title`](../../syntax/frontmatter.md#m

The assembler also writes a combined **Elastic APIs** page at `/docs/api/`, on its own layout with no API sidebar. The cards match the ones on the [docs landing page](https://www.elastic.co/docs): a rounded box with the product icon, a bold title, and a short description. The whole card is one link to the API. The title sits on a full-width band with one line of text under it that says which deployments the APIs cover. Two small labels group the APIs into two full-width rows. **Elastic Stack** shows Elasticsearch, Kibana and Logstash as three equal large cards, with the Serverless variants of Elasticsearch and Kibana as small compact cards directly under their parents. **Orchestration** shows the five Elastic Cloud APIs three across, in the same compact card as the Serverless variants but without the attachment. An API that is in neither group follows them, sorted by title. Each API appears once. If only one group has APIs, the label is dropped. If fewer than two of Elasticsearch, Kibana and Logstash are present, the group has no larger cards.

Under the line of text sits the same finder as in the API sidebar, labelled **Press ❲/❳ to find API**. It looks up operations across every API, so you can jump to an endpoint without knowing which product it belongs to. Press <kbd>/</kbd> anywhere on the page, outside a text field, to jump to it. Like the sidebar finder, it is omitted on isolated and air-gapped builds.

The cards for APIs that are in neither group show the API's deployments as small pills taken from `catalog.categories`. They use the same look as `applies_to` badges and the same names (**Self-managed**, **ECE**, **ECH**, **Serverless**), but show the name only: the catalog knows the deployment, not a lifecycle or version. The grouped cards leave them out, and an API with no categories shows no pills. The description is a short plain-text summary of `info.description` (the first paragraph with Markdown removed). JSON, YAML, and Markdown downloads stay on each API's landing page and in the `/docs/api.md` export.

The API title comes from `info.title` in the spec, so fix naming and description copy in the spec.
Expand Down Expand Up @@ -152,7 +154,7 @@ Each product key in the `api:` block must have **exactly one** entry, with **exa
`spec:`. The build fails if a product sequence is empty or has more than one entry. Multiple
specs per product are not currently supported.

On assembler builds a bar under the site header says which API you are reading: `[logo] Elasticsearch API ⇅ [main ▾]`. The API name opens a switcher that lists every API whose spec loaded (each with its logo, plus an **All APIs** link back to the catalog), and the version picker sits right beside it. Each switcher row uses that spec's title (`info.title`), the same text as the landing page heading. On the right, the **Download OpenAPI spec** button downloads the whole spec as JSON or YAML; on narrow screens it shows only its icon. The page itself starts with the full breadcrumb, which begins at Docs. The bar looks the same whether or not `navigation-preview` is on. The catalog page has no API, so it has no bar.
On assembler builds a bar under the site header says which API you are reading: `[logo] Elasticsearch API ⇅ [main ▾]`. The API name opens a switcher that lists every API whose spec loaded (each with its logo, plus an **All APIs** link back to the catalog), and the version picker sits right beside it. Each switcher row uses that spec's title (`info.title`), the same text as the landing page heading. On the right, the **Download OpenAPI spec** button downloads the whole spec as JSON or YAML; on narrow screens it shows only its icon. The page itself starts with the full breadcrumb, which begins at Docs. The bar looks the same whether or not `navigation-preview` is on. The catalog page has no API, so it has no bar; its finder sits in the title band instead.

The left navigation starts with a finder, labelled **Press ❲/❳ to find API**. It looks up operations by title across every API, not only the one you are reading, and shows the matches in a list; it does not filter the navigation tree. It is not the site-wide search. Press <kbd>/</kbd> anywhere on the page, outside a text field, to jump to the box, as on GitHub. The shortcut is off on narrow screens, where the navigation sits in a drawer. Isolated and air-gapped builds omit it. Isolated builds have no site header and no bar, so they put the API name, switcher and version picker at the top of the left navigation instead. Markdown docs pages do not get the filter box back.

Expand Down
8 changes: 8 additions & 0 deletions src/Elastic.ApiExplorer/Landing/ApiCatalogView.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<p class="landing__eyebrow">Reference</p>
<h1 class="landing__title">@ApiCatalog.PageTitle</h1>
<p class="landing__lead">@ApiCatalog.PageLede</p>
@if (LayoutModel.ShowJumpToPage)
{
<div class="api-catalog-finder"><navigation-search type="api" variant="sidebar"></navigation-search></div>
}
</div>
</section>
return Task.CompletedTask;
Expand All @@ -31,6 +35,10 @@
<h1>@ApiCatalog.PageTitle</h1>
</div>
<p class="api-catalog-lede">@ApiCatalog.PageLede</p>
@if (LayoutModel.ShowJumpToPage)
{
<div class="api-catalog-finder"><navigation-search type="api" variant="sidebar"></navigation-search></div>
}
</div>
</section>
</div>
Expand Down
31 changes: 31 additions & 0 deletions src/Elastic.Documentation.Site/Assets/api-docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -3199,6 +3199,37 @@ button.example-response-tab:focus-visible {
text-wrap: balance;
}

/* The finder is the same box as the API sidebar's, so it looks up operations across every API. It sits
under the lede, as wide as the lede, and its results open below it. Both heroes use it, and the
navigation-preview one sits outside `.api-catalog`, so the rule stands alone. */
.api-catalog-finder {
max-width: 36rem;
margin: 20px auto 0;
text-align: left;
}

/* The box is added by script. min-height is its height (20px line, 12px padding, 2px border), so what sits
below it, the sidebar tree or the catalog cards, does not jump when it loads. */
navigation-search[variant='sidebar'] {
display: block;
min-height: 34px;
}

.api-catalog-finder navigation-search {
width: 100%;
}

/* EUI caps an input popover at 400px unless it is told to be full width. The cap left the box at the left
edge of the finder instead of filling it. */
.api-catalog-finder .euiInputPopover {
max-width: none;
}

/* The navigation-preview hero is left-aligned, so the finder lines up with its title and lede. */
.landing__hero-text .api-catalog-finder {
margin-inline: 0;
}

@media (max-width: 640px) {
.api-catalog .hub-hero.api-catalog-hero {
padding: 36px 0 32px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ public async Task GenerateCatalog_CategoriesDeclared_RendersOneListWithDeploymen
}

[Test]
public async Task GenerateCatalog_RendersTheTitleBandOutsideTheContainerAndNoSearchField()
public async Task GenerateCatalog_RendersTheTitleBandOutsideTheContainer()
{
var outputRoot = Path.Join(Paths.WorkingDirectoryRoot.FullName, $"api-catalog-split-{Guid.NewGuid():N}");
var context = CreateGenerateContext(outputRoot);
Expand All @@ -423,9 +423,38 @@ await generator.GenerateCatalog(
html.IndexOf("id=\"content-container\"", StringComparison.Ordinal),
"the band is rendered outside the width-limited container"
);
html.Should().NotContain("navigation-search", "the catalog has no search field");
}

[Test]
[Arguments(BuildType.Assembler, true)]
[Arguments(BuildType.Isolated, false)]
public async Task GenerateCatalog_Finder_AppearsOnlyWhereTheSidebarHasOne(BuildType buildType, bool expected)
{
var outputRoot = Path.Join(Paths.WorkingDirectoryRoot.FullName, $"api-catalog-split-{Guid.NewGuid():N}");
var context = CreateGenerateContext(outputRoot, buildType: buildType);
using var versionIndexClient = new VersionIndexClient(BaseUri, MultiVersionHandler(), sleep: (_, _) => Task.CompletedTask);
var generator = new OpenApiGenerator(NullLoggerFactory.Instance, context, NoopMarkdownStringRenderer.Instance, versionIndexClient);

await generator.GenerateCatalog(
[new("elasticsearch", "Elasticsearch", "/docs/api/doc/elasticsearch", "elasticsearch")],
TestContext.Current!.Execution.CancellationToken
);

var html = await context
.WriteFileSystem
.File
.ReadAllTextAsync(Path.Join(outputRoot, "api", "index.html"), TestContext.Current!.Execution.CancellationToken);
if (expected)
{
html.Should().Contain("<navigation-search type=\"api\" variant=\"sidebar\"></navigation-search>");
Count(html, "<navigation-search").Should().Be(1);
}
else
html.Should().NotContain("navigation-search");
}

private static int Count(string html, string value) => html.Split(value).Length - 1;

[Test]
public async Task GenerateCatalog_CloudHostedAndEnterprise_ShowCloudMarksNotTheGenericGlyph()
{
Expand All @@ -450,7 +479,12 @@ public async Task GenerateCatalog_CloudHostedAndEnterprise_ShowCloudMarksNotTheG
html.Should().NotContain("M13.5 5 10.5 19", "that is the generic fallback glyph");
}

private static BuildContext CreateGenerateContext(string outputRoot, string? docsetYaml = null, string? displayName = null)
private static BuildContext CreateGenerateContext(
string outputRoot,
string? docsetYaml = null,
string? displayName = null,
BuildType buildType = BuildType.Isolated
)
{
var collector = new DiagnosticsCollector([]);
var stack = TestHelpers.CreateStackVersionsConfiguration(currentMajor: 9);
Expand Down Expand Up @@ -501,7 +535,7 @@ private static BuildContext CreateGenerateContext(string outputRoot, string? doc
),
configurationContext
)
{ UrlPathPrefix = "docs" };
{ UrlPathPrefix = "docs", BuildType = buildType };
}

private static OpenApiDocument SpecDocument(string title) =>
Expand Down
Loading