Repository navigation
Put the APIs in the assembler navigation tree - #4737
Conversation
A toc entry such as `api: elasticsearch` now mounts a floating section: a set of pages that owns its URL root and sidebar and is not made of Markdown files. A provider resolves the section before navigation is built, and it renders as an island. `CreateLinkReference()` skips these nodes instead of casting them to `MarkdownFile`. No provider is registered yet, so a build that uses the entry reports an error. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…entries The site assembler dropped every root child of a mounted docset and warned that it was undeclared, so an `api:` entry vanished from the assembled navigation. Floating section roots now carry a marker interface and the assembler keeps them. An `api:` entry that also sets `children:`, `file:` or other keys now reports an error instead of silently dropping them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A floating section root now exists as soon as the toc mounts it, with its landing URL and title, so layout code can link to it. The children come later from `ResolveAsync`, which `DocumentationSet.ResolveFloatingSectionsAsync` runs before generation. The children keep their own numbering, so filling them never renumbers the surrounding navigation. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The narrative root copied only leaf items into the site tree, so an `- api: <key>` entry in its toc resolved and then vanished. The root now keeps floating section roots next to its leaves. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ResolveDirectoryTree now fills floating sections, so DocumentationGenerator, the assembler and the codex build see their pages without a separate call. The test goes through ResolveDirectoryTree and checks resolution runs once. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An `api: <key>` toc entry now resolves to an API section. Its root exists when the toc is read, and `ResolveAsync` fills it with the version trees before generation. The generator builds each API's trees once and renders from them, so mounting a section adds no second fetch or build. Only the current version is visible. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The docset now fills floating sections itself, so a build run with `--skip-api` resolves an `api:` entry without a generator. The section stays empty and hidden instead of failing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ip-api A spec that fails to build no longer stops the Markdown build: the section reports the error and hides. The section also hides when no main version resolved, and a hidden API no longer appears in the section dropdown. The generation state records --skip-api, so toggling it triggers a full build. The docs now say that only the isolated build accepts api: entries. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The floating section no longer emits its own error when tree building fails, because the generator awaits the same cached task and already reports it with the stack trace. The no-main test now makes main unreadable without throwing, so it proves released versions loaded. A new build-twice test covers toggling --skip-api over unchanged pages. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A mounted API now publishes its pages in `links.json` under `floating`, one entry per page path with a bit mask of the versions that contain it. A cross-link such as `elasticsearch://api/elasticsearch/v8/operation/operation-search` resolves through hash lookups and a bit test, and a page missing in that version is an error. The resolver builds the final URL from the site root, because API pages sit outside every repository path prefix. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An alias now belongs to the versions that list it, so a link to an alias in a version without it fails, and an alias can name different pages in different versions. A cross-link to an API page keeps its #fragment. CodexAwareUriResolver sends API pages to the published site instead of a repository path. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A fragment stays on the resolved URL and the build does not check the anchor. Aliases of a collapsed operation resolve only in the versions that list them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A floating link section no longer assumes how a kind routes its URLs. Each version names its root, and whether it is hidden or current, so a reader joins a root and a page path and never adds a `v` segment. A cross-link picks a version by its name, and aliases are listed under their canonical path, which writes that path once however many aliases it has. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An API page called `main` or `8` was read as a version, so the link reached the landing page. A page of the current version now takes precedence, so adding a version never changes where an existing link points. The current version's bit is cached instead of scanned for on every unversioned link. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The lookups of a section are built on first use. The copy that a `with` expression makes carried them over, so replacing the versions or the aliases kept answering from the old data, and a test failed only when another test had used the shared fixture first. A copy now keeps the data and none of the lookups. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A `section: APIs` with `floating: api` in navigation.yml now mounts every declared API under a hub, so the sitemap walk and the llms.txt listing read the APIs from the tree like any other page. The roots exist when the navigation is built and the OpenAPI step fills them from the trees it renders from. GenerateApiSection and its catalog side door are gone, and the walk skips links to a heading inside a page. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ML exports The hub URL has no trailing slash, so the sitemap filter now matches it exactly. The top navigation tab for a floating section without external: links the hub instead of the first child. API sections are only mounted when the HTML export, and with it the API build step, runs. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The exporter guard sat inline in the build service, so no test reached it. It now lives in AssemblerApiSections.For, and a test checks that an LLM-only build gets no API sections while an HTML build keeps them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The APIs hub and the root of each API take a place in the global navigation order, so the pager walked into them. In the preview navigation the Reference page had the Logstash API as its previous page, and the last page of the docs had the APIs as its next page. The previous and next links now skip the hub and every floating root. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
| var tabUrl = section.FloatingKind is not null | ||
| ? sectionNav.Url |
There was a problem hiding this comment.
Severity: P3 (Low)
For a floating APIs section without external:, the tab gets the hub URL but is still assigned SectionId: sectionNav.Id below. API pages and the catalog retain their own navigation roots, so that ID never matches; the header's URL-based active-state fallback also excludes links with a section ID. Consequently, the newly supported tab never becomes active on its own pages. Leave the section ID unset for floating hubs or otherwise associate the rendered API roots with the tab, and cover active-state matching in the test.
Generated by Libra. React with 👍 or 👎 to give feedback on this comment.
| @@ -1,322 +1,3 @@ | |||
| // Licensed to Elasticsearch B.V under one or more agreements. | |||
| // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. | |||
| // See the LICENSE file in the project root for more information | |||
There was a problem hiding this comment.
Severity: P3 (Low)
This PR deletes every test in SitemapTests.cs and leaves only the license header. That removes all coverage of SitemapBuilder.Generate: XML output, ordering, the entry-count limit and the /docs/api/ exclusion. It also removes coverage of EsSitemapReader.BuildSearchBody, and nothing else in tests/ covers either one. The PR also changes the sitemap filter in this same PR (it now drops the /docs/api hub URL as well), and no test covers that change. The deletion looks accidental. Please restore the file and add a case for the exact /docs/api key.
Generated by Libra. Specialist: libra-complexity. React with 👍 or 👎 to give feedback on this comment.
Docs preview (local build)Handbook preview: https://docs-v3-preview.elastic.dev/elastic/docs-builder/pull/4737/ Sample changed pages: |
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A
section: APIswithfloating: apiinnavigation.ymlnow mounts every declared API in the assembler navigation tree, so the sitemap walk and thellms.txtlisting read the APIs from the tree like any other page. A build that does not render the API Explorer is unchanged.Affects: Assembler builds, Navigation, Content export
Prompt summary: Make API pages part of the navigation tree in isolated and assembler builds, because the sitemap and
llms.txtread that tree and the API pages were a side door next to it. The roots must exist when the navigation is built, with the details filled in later. This is the fourth step of the design in RFC: Floating sections in the navigation tree, and it implements the acceptance criteria of docs-eng-team#825.Why
The assembler renders API pages after the Markdown build and
SiteNavigationnever sees them.llms.txthas to append the API catalog by hand inGenerateApiSection, and the sitemap walk cannot reach the pages.What
The APIs section
SiteNavigationmounts asection:that hasfloating: <kind>as a hub. Its children are the roots of every floating section of that kind the build offers, and its URL is the hub page of the kind,/docs/api. A section without any such sections keeps its other behaviour. TheAPIstab of the navigation preview keeps itsexternal:link either way.navigation.ymlgets anAPIssection, and the preview file getsfloating: apion its existing tab.Roots first, children later
AssemblerApiSectionsfinds the repositories that declare APIs when the build starts, and offers one section per API in key order. Their roots exist when the navigation is built.AssemblerOpenApiBuildStepattaches a generator to each owner and fills the sections from the same trees it renders the pages from, so nothing is fetched or built twice. A root takes the spec title once the spec is read, as the API hub does. A failed API hides its root.llms.txtand the sitemapThe
llms.txtlisting walks the tree, andGenerateApiSectionis deleted. It still links the Markdown export of each API, as before, so its output does not change. The sitemap walk skips links to a heading inside a page. The/docs/api/filter stays until docs-eng-team#725.Reading order
The hub and the root of each API take a place in the navigation order, so the previous and next links would walk into them: the last page of the docs would point to the APIs, and in the preview navigation the Reference page would have the Logstash API as its previous page. The pager now skips the hub and every floating root, so paging through the docs does not change.
Docs
docs/documentation/assembler/navigation.mddocumentsfloating:.Stack: 4 of 5, on top of #4731.
Out of scope: replacing the link check in #4653, attaching every declared API without a toc entry, publishing the assembler's APIs in
links.json, and removing the sitemap filter. The assembler,serveand Codex builds still reject anapi:entry in a docset toc.Verify
The integration test needs network access to CloudFront. It builds a docset with the Elasticsearch API, runs the assembler step, and checks the hub, the sitemap walk and the
llms.txtlisting.🤖 Generated with Claude Code