< Summary

Information
Class: Chronicis.Client.Pages.PathResolver
Assembly: Chronicis.Client
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Client/Pages/PathResolver.razor
Line coverage
100%
Covered lines: 46
Uncovered lines: 0
Coverable lines: 46
Total lines: 128
Line coverage: 100%
Branch coverage
97%
Covered branches: 35
Total branches: 36
Branch coverage: 97.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
SelectLayout(...)100%22100%
GetDetailComponentType(...)100%1010100%
RenderResolution(...)100%11100%
AddComponentAttributes(...)95.83%2424100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Client/Pages/PathResolver.razor

#LineLine coverage
 1@page "/{*Path}"
 2@layout PassthroughLayout
 3@using Microsoft.AspNetCore.Components.Authorization
 4@using Microsoft.AspNetCore.Components.Rendering
 5@using Chronicis.Client.Pages
 6@using Chronicis.Client.Pages.Maps
 7@using Chronicis.Client.Services.Routing
 8@using Chronicis.Shared.Routing
 9@inject IPathApiService PathApi
 10@inject IClientReservedSlugProvider ReservedSlugs
 11@inject NavigationManager Navigation
 12@inject AuthenticationStateProvider AuthStateProvider
 13
 14<LayoutView Layout="@_layoutType">
 15    @if (_isLoading)
 16    {
 17        <LoadingSkeleton />
 18    }
 19    else if (_resolution == null && _hasResolved)
 20    {
 21        <NotFoundAlert Message="Page not found" />
 22    }
 23    else if (_resolution != null)
 24    {
 25        @RenderResolution(_resolution)
 26    }
 27</LayoutView>
 28
 29@code {
 30    [Parameter]
 31    public string? Path { get; set; }
 32
 1833    private Type _layoutType = typeof(PublicLayout);
 34    private bool _isLoading;
 35    private bool _hasResolved;
 36    private SlugPathResolution? _resolution;
 37
 38    internal static Type SelectLayout(bool isAuthenticated) =>
 2039        isAuthenticated ? typeof(AuthenticatedLayout) : typeof(PublicLayout);
 40
 2141    internal static Type? GetDetailComponentType(ResolvedEntityKind kind) => kind switch
 2142    {
 243        ResolvedEntityKind.World       => typeof(WorldDetail),
 244        ResolvedEntityKind.Campaign    => typeof(CampaignDetail),
 245        ResolvedEntityKind.Arc         => typeof(ArcDetail),
 246        ResolvedEntityKind.Session     => typeof(SessionDetail),
 347        ResolvedEntityKind.SessionNote => typeof(ArticleDetail),
 348        ResolvedEntityKind.WikiArticle => typeof(ArticleDetail),
 149        ResolvedEntityKind.Tutorial    => typeof(ArticleDetail),
 250        ResolvedEntityKind.MapListing  => typeof(MapListing),
 251        ResolvedEntityKind.Map         => typeof(MapDetail),
 252        _                              => null
 2153    };
 54
 55    protected override async Task OnParametersSetAsync()
 56    {
 57        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
 58        _layoutType = SelectLayout(authState.User.Identity?.IsAuthenticated == true);
 59
 60        var segments = Path?.Split('/', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
 61
 62        if (segments.Length == 0)
 63            return;
 64
 65        // Tutorials are handled by PathApi (tutorials is also reserved to block world name collisions)
 66        if (!segments[0].Equals("tutorials", StringComparison.OrdinalIgnoreCase)
 67            && ReservedSlugs.IsReserved(segments[0]))
 68        {
 69            Navigation.NavigateTo("/dashboard", replace: true);
 70            return;
 71        }
 72
 73        _isLoading = true;
 74        _hasResolved = false;
 75        StateHasChanged();
 76
 77        _resolution = await PathApi.ResolveAsync(Path!, CancellationToken.None);
 78        _isLoading = false;
 79        _hasResolved = true;
 80    }
 81
 1282    private RenderFragment RenderResolution(SlugPathResolution resolution) => builder =>
 1283    {
 1284        var componentType = GetDetailComponentType(resolution.Kind);
 1285        if (componentType == null)
 1286            return;
 1287
 1288        builder.OpenComponent(0, componentType);
 1289        AddComponentAttributes(builder, resolution);
 1290        builder.CloseComponent();
 1291    };
 92
 93    private static void AddComponentAttributes(RenderTreeBuilder builder, SlugPathResolution resolution)
 94    {
 1195        switch (resolution.Kind)
 96        {
 97            case ResolvedEntityKind.World:
 98            case ResolvedEntityKind.MapListing:
 299                if (resolution.WorldId.HasValue)
 2100                    builder.AddAttribute(1, "WorldId", resolution.WorldId.Value);
 2101                break;
 102            case ResolvedEntityKind.Campaign:
 1103                if (resolution.CampaignId.HasValue)
 1104                    builder.AddAttribute(1, "CampaignId", resolution.CampaignId.Value);
 1105                break;
 106            case ResolvedEntityKind.Arc:
 1107                if (resolution.ArcId.HasValue)
 1108                    builder.AddAttribute(1, "ArcId", resolution.ArcId.Value);
 1109                break;
 110            case ResolvedEntityKind.Session:
 1111                if (resolution.SessionId.HasValue)
 1112                    builder.AddAttribute(1, "SessionId", resolution.SessionId.Value);
 1113                break;
 114            case ResolvedEntityKind.Map:
 1115                if (resolution.WorldId.HasValue)
 1116                    builder.AddAttribute(1, "WorldId", resolution.WorldId.Value);
 1117                if (resolution.MapId.HasValue)
 1118                    builder.AddAttribute(2, "MapId", resolution.MapId.Value);
 1119                break;
 120            case ResolvedEntityKind.SessionNote:
 121            case ResolvedEntityKind.WikiArticle:
 122            case ResolvedEntityKind.Tutorial:
 5123                if (resolution.ArticleId.HasValue)
 5124                    builder.AddAttribute(1, "ArticleId", resolution.ArticleId.Value);
 125                break;
 126        }
 5127    }
 128}