< Summary

Information
Class: Chronicis.Client.Pages.Articles
Assembly: Chronicis.Client
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Client/Pages/Articles.razor
Line coverage
100%
Covered lines: 8
Uncovered lines: 0
Coverable lines: 8
Total lines: 113
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
BuildRenderTree(...)100%44100%
OnTreeStateChanged()100%11100%
Dispose()100%11100%

File(s)

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

#LineLine coverage
 1@page "/article/{*Path}"
 2@attribute [Authorize]
 3@inject ITreeStateService TreeStateService
 4@inject IArticleApiService ArticleApi
 5@inject IArticleCacheService ArticleCache
 6@inject IQuoteService QuoteService
 7@inject IAppContextService AppContext
 8@inject NavigationManager Navigation
 9@implements IDisposable
 10
 11@code {
 12    private readonly ILogger<Articles> _logger;
 13
 14    // Direct constructor injection
 1415    public Articles(ILogger<Articles> logger)
 16    {
 1417        _logger = logger;
 1418    }
 19}
 20
 421@if (TreeStateService.SelectedArticleId.HasValue && TreeStateService.SelectedArticleId.Value != Guid.Empty)
 22{
 23    <ArticleDetail />
 24}
 25else
 26{
 27    <MudPaper Elevation="2" Class="chronicis-article-card chronicis-fade-in">
 28        <h6>Loading article...</h6>
 29    </MudPaper>
 30}
 31
 32@code {
 33    [Parameter]
 34    public string? Path { get; set; }
 35
 36    protected override async Task OnInitializedAsync()
 37    {
 38        TreeStateService.OnStateChanged += OnTreeStateChanged;
 39
 40        // If URL has article path, load it
 41        if (!string.IsNullOrEmpty(Path))
 42        {
 43            await LoadArticleByPath(Path);
 44        }
 45    }
 46
 47    protected override async Task OnParametersSetAsync()
 48    {
 49        // Handle URL changes (browser back/forward)
 50        if (!string.IsNullOrEmpty(Path))
 51        {
 52            await LoadArticleByPath(Path);
 53        }
 54    }
 55
 56    private async Task LoadArticleByPath(string path)
 57    {
 58        try
 59        {
 60            var article = await ArticleApi.GetArticleByPathAsync(path);
 61
 62            if (article != null)
 63            {
 64                ArticleCache.CacheArticle(article);
 65
 66                if (article.WorldId.HasValue &&
 67                    article.WorldId.Value != Guid.Empty &&
 68                    AppContext.CurrentWorldId != article.WorldId.Value)
 69                {
 70                    await AppContext.SelectWorldAsync(article.WorldId.Value);
 71                }
 72
 73                if (article.Id != TreeStateService.SelectedArticleId)
 74                {
 75                    // Expand path to article and select it
 76                    TreeStateService.ExpandPathToAndSelect(article.Id);
 77                }
 78            }
 79            else
 80            {
 81                // Article not found - redirect to dashboard
 82                _logger.LogWarningSanitized("Article not found for path: {Path}", path);
 83                Navigation.NavigateTo("/dashboard", replace: true);
 84            }
 85        }
 86        catch (Exception ex)
 87        {
 88            _logger.LogErrorSanitized(ex, "Error loading article by path: {Path}", path);
 89            Navigation.NavigateTo("/dashboard", replace: true);
 90        }
 91    }
 92
 93    private async Task NavigateToArticle(Guid articleId)
 94    {
 95        // Get the full article details to build path from breadcrumbs
 96        var article = await ArticleApi.GetArticleDetailAsync(articleId);
 97        if (article != null && article.Breadcrumbs.Any())
 98        {
 99            var path = string.Join("/", article.Breadcrumbs.Select(b => b.Slug));
 100            Navigation.NavigateTo($"/article/{path}");
 101        }
 102    }
 103
 104    private void OnTreeStateChanged()
 105    {
 1106        InvokeAsync(StateHasChanged);
 1107    }
 108
 109    public void Dispose()
 110    {
 4111        TreeStateService.OnStateChanged -= OnTreeStateChanged;
 4112    }
 113}