Skip to content

Commit

Permalink
Fix: navigation next/prev stories, docs, and components didn't work
Browse files Browse the repository at this point in the history
  • Loading branch information
jsakamoto committed Apr 7, 2024
1 parent 8fad770 commit a58d578
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,57 +46,23 @@
}
}

private ValueTask OnPreviousComponent() => this.MoveComponent(delta: -1);
private ValueTask OnPreviousComponent() => this.MoveComponent(navigateToNext: false);

private ValueTask OnNextComponent() => this.MoveComponent(delta: +1);
private ValueTask OnNextComponent() => this.MoveComponent(navigateToNext: true);

private ValueTask MoveComponent(int delta)
private ValueTask MoveComponent(bool navigateToNext)
{
var navigationPath = this.RouteData?.Parameter;

var currentComponent = default(NavigationTreeItem);
foreach (var item in this.NavigationRoot.EnumAll())
{
if (item.Type == NavigationItemType.Component) currentComponent = item;
if (item.NavigationPath == navigationPath) break;
}
if (currentComponent == null) return ValueTask.CompletedTask;

var componentItems = this.NavigationRoot.EnumAll()
.Where(item => item.Type == NavigationItemType.Component)
.ToArray();

var index = Array.IndexOf<NavigationTreeItem>(componentItems, currentComponent);
var indexMoveTo = index + delta;
if (indexMoveTo < 0 || componentItems.Length <= indexMoveTo) return ValueTask.CompletedTask;

var componentMoveTo = componentItems[index + delta];
var itemMoveTo = componentMoveTo.SubItems.FirstOrDefault();
if (itemMoveTo == null) return ValueTask.CompletedTask;

this.NavigationRoot.EnsureExpandedTo(itemMoveTo);

this._NavigationService?.NavigateTo(itemMoveTo);
this._NavigationService.NavigateToNextComponentItem(this.RouteData, navigateToNext);
return ValueTask.CompletedTask;
}

private ValueTask OnPreviousStory() => this.MoveStory(delta: -1);
private ValueTask OnPreviousStory() => this.MoveStory(navigateToNext: false);

private ValueTask OnNextStory() => this.MoveStory(delta: +1);
private ValueTask OnNextStory() => this.MoveStory(navigateToNext: true);

private ValueTask MoveStory(int delta)
private ValueTask MoveStory(bool navigateToNext)
{
var storyItems = this.NavigationRoot.EnumAll()
.Where(item => item.Type == NavigationItemType.Story)
.ToArray();
var index = Array.FindIndex<NavigationTreeItem>(storyItems, item => this.RouteData?.Parameter == item.NavigationPath);
var indexMoveTo = index + delta;
if (indexMoveTo < 0 || storyItems.Length <= indexMoveTo) return ValueTask.CompletedTask;

var itemMoveTo = storyItems[index + delta];
this.NavigationRoot.EnsureExpandedTo(itemMoveTo);

this._NavigationService?.NavigateTo(itemMoveTo);
this._NavigationService.NavigateToNextDocsOrStory(this.RouteData, navigateToNext);
return ValueTask.CompletedTask;
}

Expand Down
24 changes: 24 additions & 0 deletions BlazingStory/Internals/Services/Navigation/NavigationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,30 @@ internal bool TryGetActiveNavigationItem(QueryRouteData? routeData, [NotNullWhen
return true;
}

internal void NavigateToNextComponentItem(QueryRouteData? routeData, bool navigateToNext)
{
if (!this.TryGetActiveNavigationItem(routeData, out var activeItem, out var _)) return;
var allComponents = this._Root.EnumAll().Where(item => item.Type is NavigationItemType.Component).ToList();
var ativeComponentIndex = allComponents.FindIndex(item => item.EnumAll().Contains(activeItem));
var nextComponentIndex = ativeComponentIndex + (navigateToNext ? +1 : -1);
if (nextComponentIndex < 0 || allComponents.Count <= nextComponentIndex) return;
var nextComponent = allComponents[nextComponentIndex];
var nextItem = nextComponent.EnumAll().Where(item => item.Type is NavigationItemType.Story or NavigationItemType.Docs).FirstOrDefault();
if (nextItem == null) return;
this.NavigateTo(nextItem);
}

internal void NavigateToNextDocsOrStory(QueryRouteData? routeData, bool navigateToNext)
{
if (!this.TryGetActiveNavigationItem(routeData, out var activeItem, out var _)) return;
var allItems = this._Root.EnumAll().Where(item => item.Type is NavigationItemType.Docs or NavigationItemType.Story).ToList();
var ativeIndex = allItems.FindIndex(item => item == activeItem);
var nextIndex = ativeIndex + (navigateToNext ? +1 : -1);
if (nextIndex < 0 || allItems.Count <= nextIndex) return;
var nextItem = allItems[nextIndex];
this.NavigateTo(allItems[nextIndex]);
}

internal void NotifyLastVisitedWasUnknown()
{
this._LastNavigatedWasunknown = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BlazingStory.Internals.Services.Navigation;
using BlazingStory.Test._Fixtures;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;

namespace BlazingStory.Test.Internals.Services.Navigation;
Expand Down Expand Up @@ -65,4 +66,86 @@ public async Task Search_Hit_by_Caption_of_Component_Test()
// Then
searchResults.Dump().Is("Component | Button | Examples");
}

[Test]
public async Task NavigateToNextComponentItem_Test()
{
// Given
await using var host = new TestHost();
var navMan = host.Services.GetRequiredService<NavigationManager>();
var navService = host.Services.GetRequiredService<NavigationService>();
navService.BuildNavigationTree(TestHelper.GetExampleStories1(host.Services), null);

navService.NavigateToNextComponentItem(new("story", "examples-button--default-button"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/docs/examples-select--docs");

navService.NavigateToNextComponentItem(new("docs", "examples-select--docs"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/docs/examples-select--docs");
}

[Test]
public async Task NavigateToPrevComponentItem_Test()
{
// Given
await using var host = new TestHost();
var navMan = host.Services.GetRequiredService<NavigationManager>();
var navService = host.Services.GetRequiredService<NavigationService>();
navService.BuildNavigationTree(TestHelper.GetExampleStories1(host.Services), null);

navService.NavigateToNextComponentItem(new("docs", "examples-select--docs"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/docs/examples-button--docs");

navService.NavigateToNextComponentItem(new("story", "examples-button--primary-button"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/docs/examples-button--docs");
}

[Test]
public async Task NavigateToNextDocsOrStory_Test()
{
// Given
await using var host = new TestHost();
var navMan = host.Services.GetRequiredService<NavigationManager>();
var navService = host.Services.GetRequiredService<NavigationService>();
navService.BuildNavigationTree(TestHelper.GetExampleStories1(host.Services), null);

navService.NavigateToNextDocsOrStory(new("docs", "examples-button--docs"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/story/examples-button--default-button");

navService.NavigateToNextDocsOrStory(new("story", "examples-button--default-button"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/story/examples-button--primary-button");

navService.NavigateToNextDocsOrStory(new("story", "examples-button--primary-button"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/docs/examples-select--docs");

navService.NavigateToNextDocsOrStory(new("docs", "examples-select--docs"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/story/examples-select--select");

navService.NavigateToNextDocsOrStory(new("story", "examples-select--select"), navigateToNext: true);
navMan.Uri.Is("http://localhost/?path=/story/examples-select--select");
}

[Test]
public async Task NavigateToPrevDocsOrStory_Test()
{
// Given
await using var host = new TestHost();
var navMan = host.Services.GetRequiredService<NavigationManager>();
var navService = host.Services.GetRequiredService<NavigationService>();
navService.BuildNavigationTree(TestHelper.GetExampleStories1(host.Services), null);

navService.NavigateToNextDocsOrStory(new("story", "examples-select--select"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/docs/examples-select--docs");

navService.NavigateToNextDocsOrStory(new("docs", "examples-select--docs"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/story/examples-button--primary-button");

navService.NavigateToNextDocsOrStory(new("story", "examples-button--primary-button"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/story/examples-button--default-button");

navService.NavigateToNextDocsOrStory(new("story", "examples-button--default-button"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/docs/examples-button--docs");

navService.NavigateToNextDocsOrStory(new("docs", "examples-button--docs"), navigateToNext: false);
navMan.Uri.Is("http://localhost/?path=/docs/examples-button--docs");
}
}
3 changes: 2 additions & 1 deletion Tests/BlazingStory.Test/_Fixtures/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using RazorClassLib1.Components.Button;
using RazorClassLib1.Components.Select;
using Toolbelt.Diagnostics;

namespace BlazingStory.Test._Fixtures;
Expand Down Expand Up @@ -36,7 +37,7 @@ internal static IEnumerable<StoryContainer> GetExampleStories1(IServiceProvider
CreateStory<Button>(title: "Examples/Button", name: "Default Button"),
CreateStory<Button>(title: "Examples/Button", name: "Primary Button"),
}},
new(typeof(Button), null, new(typeof(Select_stories), new("Examples/Select")), services) { Stories = {
new(typeof(Select), null, new(typeof(Select_stories), new("Examples/Select")), services) { Stories = {
CreateStory<Button>(title: "Examples/Select", name: "Select"),
}}
];
Expand Down
7 changes: 6 additions & 1 deletion Tests/BlazingStory.Test/_Fixtures/TestHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ internal class TestHost : IAsyncDisposable
{
private readonly IServiceScope _Scope;

private readonly Bunit.TestContext _bUnitContext;

internal IServiceProvider Services { get; }

public TestHost(Action<IServiceCollection>? configureServices = null)
{
this._bUnitContext = new Bunit.TestContext();

var services = new ServiceCollection();
services.AddScoped(_ => Mock.Of<IJSRuntime>());
services.AddScoped(_ => Mock.Of<NavigationManager>());
services.AddScoped<NavigationManager>(_ => new Bunit.TestDoubles.FakeNavigationManager(this._bUnitContext));
services.AddScoped<HelperScript>();
services.AddScoped<NavigationService>();
services.AddScoped(typeof(ILogger<>), typeof(NullLogger<>));
Expand All @@ -35,5 +39,6 @@ public TestHost(Action<IServiceCollection>? configureServices = null)
public async ValueTask DisposeAsync()
{
if (this._Scope is IAsyncDisposable scope) await scope.DisposeAsync();
this._bUnitContext.Dispose();
}
}

0 comments on commit a58d578

Please sign in to comment.