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
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class FolderNavigation<TModel>(
public INodeNavigationItem<INavigationModel, INavigationItem>? Parent { get; set; } = parent;

/// <inheritdoc />
public bool Hidden { get; }
public bool Hidden { get; private set; }

/// <inheritdoc />
public int NavigationIndex { get; set; }
Expand All @@ -50,6 +50,7 @@ internal void SetNavigationItems(IReadOnlyCollection<INavigationItem> navigation
{
var indexNavigation = navigationItems.QueryIndex<TModel>(this, $"{FolderPath}/index.md", out navigationItems);
Index = indexNavigation;
Hidden = Index.Hidden;
// Include NavigationRoot.Id to ensure uniqueness across docsets in assembler builds
// (URLs alone aren't unique until path prefixes are applied by SiteNavigation)
Id = ShortId.Create(NavigationRoot.Id, Index.Url);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ INavigationHomeProvider homeProvider
public INavigationHomeProvider HomeProvider { get; set; }

/// <inheritdoc />
public bool Hidden { get; }
public bool Hidden { get; private set; }

/// <inheritdoc />
public int NavigationIndex { get; set; }
Expand All @@ -104,6 +104,7 @@ internal void SetNavigationItems(IReadOnlyCollection<INavigationItem> navigation
{
var indexNavigation = navigationItems.QueryIndex<TModel>(this, $"{ParentPath}/index.md", out navigationItems);
Index = indexNavigation;
Hidden = Index.Hidden;
// Include NavigationRoot.Id to ensure uniqueness across docsets in assembler builds
Id = ShortId.Create(NavigationRoot.Id, Index.Url);
NavigationItems = navigationItems;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ this IReadOnlyCollection<INavigationItem> items, INodeNavigationItem<INavigation
)
where TModel : class, IDocumentationFile
{
var index = LookupIndex();
var index = LookupIndex(preferVisible: true);
index ??= LookupIndex(preferVisible: false);
ArgumentNullException.ThrowIfNull(index);

children = items.Except([index]).ToArray();

return index;

ILeafNavigationItem<TModel> LookupIndex()
ILeafNavigationItem<TModel>? LookupIndex(bool preferVisible)
{
foreach (var item in items)
{
if (preferVisible && item.Hidden)
continue;

// Check for the exact type match
if (item is ILeafNavigationItem<TModel> leaf)
return leaf;
Expand All @@ -35,6 +40,9 @@ ILeafNavigationItem<TModel> LookupIndex()
return nodeItem.Index;
}

if (preferVisible)
return null;

// If no index is found, throw an exception
throw new InvalidOperationException($"No index found for navigation node '{node.GetType().Name}' at path '{fallbackPath}'");
}
Expand Down
52 changes: 52 additions & 0 deletions tests/Navigation.Tests/Isolation/DynamicUrlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,58 @@ public void FolderWithoutIndexUsesFirstChildUrl()
folder!.Url.Should().Be("/guides/getting-started");
}

[Fact]
public void FolderWithoutIndexUsesFirstVisibleChildUrlWhenHiddenChildComesFirst()
{
// language=yaml
var yaml = """
project: 'test-project'
toc:
- folder: guides
children:
- hidden: autopilot.md
- file: getting-started.md
""";

var fileSystem = new MockFileSystem();
fileSystem.AddDirectory("/docs");
var context = CreateContext();
var docSet = DocumentationSetFile.LoadAndResolve(context.Collector, yaml, fileSystem.NewDirInfo("docs"));

var navigation = new DocumentationSetNavigation<IDocumentationFile>(docSet, context, GenericDocumentationFileFactory.Instance);
var folder = navigation.NavigationItems.First().Should().BeOfType<FolderNavigation<IDocumentationFile>>().Subject;

folder.Hidden.Should().BeFalse();
folder.NavigationTitle.Should().Be("getting-started");
folder.Url.Should().Be("/guides/getting-started");
folder.NavigationItems.Should().ContainSingle().Which.Hidden.Should().BeTrue();
}

[Fact]
public void FolderWithoutIndexAndOnlyHiddenChildrenIsHidden()
{
// language=yaml
var yaml = """
project: 'test-project'
toc:
- folder: guides
children:
- hidden: autopilot.md
""";

var fileSystem = new MockFileSystem();
fileSystem.AddDirectory("/docs");
var context = CreateContext();
var docSet = DocumentationSetFile.LoadAndResolve(context.Collector, yaml, fileSystem.NewDirInfo("docs"));

var navigation = new DocumentationSetNavigation<IDocumentationFile>(docSet, context, GenericDocumentationFileFactory.Instance);
var folder = navigation.NavigationItems.First().Should().BeOfType<FolderNavigation<IDocumentationFile>>().Subject;

folder.Hidden.Should().BeTrue();
folder.Index.Hidden.Should().BeTrue();
folder.NavigationItems.Should().BeEmpty();
}

[Fact]
public void FolderWithNestedChildren()
{
Expand Down
Loading