< Summary

Information
Class: UIBlazor.Components.ChatMessageView
Assembly: UIBlazor
File(s): /home/runner/work/InvAit/InvAit/UIBlazor/Components/ChatMessageView.razor
Tag: 71_26091983037
Line coverage
100%
Covered lines: 56
Uncovered lines: 0
Coverable lines: 56
Total lines: 162
Line coverage: 100%
Branch coverage
97%
Covered branches: 66
Total branches: 68
Branch coverage: 97%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_CommonSettingsProvider()100%11100%
get_Message()100%11100%
get_UserAvatarText()100%11100%
get_IsLoading()100%11100%
get_IsLast()100%11100%
get_OnToolApproval()100%11100%
get_OnExecutePlan()100%11100%
get_OnEdit()100%11100%
get_OnCancelEdit()100%11100%
get_OnSaveEdit()100%11100%
get_OnDelete()100%11100%
get_OnRegenerate()100%11100%
.ctor()100%11100%
ShouldRender()90%2020100%
OnAfterRender(...)100%11100%

File(s)

/home/runner/work/InvAit/InvAit/UIBlazor/Components/ChatMessageView.razor

#LineLine coverage
 1<div class="rz-chat-message rz-chat-message-@Message.Role" @key="Message.Id">
 2    <RadzenStack class="rz-chat-message-avatar" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Ga
 3        <span class="rz-chat-avatar-initials" >
 504            @if (Message.Role == ChatMessageRole.User)
 5            {
 296                @UserAvatarText
 7            }
 218            else if (Message.Role == ChatMessageRole.Assistant)
 9            {
 10                <RadzenIcon Icon="robot_2" IconStyle="IconStyle.Info" />
 11            }
 212            else if (Message.Role == ChatMessageRole.Tool)
 13            {
 14                <RadzenIcon Icon="design_services" />
 15            }
 16        </span>
 17    </RadzenStack>
 18    <RadzenStack Orientation="Orientation.Vertical" AlignItems="@(Message.Role == ChatMessageRole.User ? AlignItems.End 
 19        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="@(Message.Role 
 20            <div class="rz-chat-message-time">
 5021                @Message.Timestamp.ToString("HH:mm")
 22            </div>
 5023            @if (Message.Model != null)
 24            {
 125                <div class="rz-chat-message-time"> @Message.Model </div>
 26            }
 27        </RadzenStack>
 28            <div class="rz-chat-message-text" style="display: grid; width: 100%; position: relative;">
 29                <div class="message-content-wrapper @(Message.IsExpanded ? "expanded" : "collapsed")"
 30                     style="grid-area: 1/1; opacity: @(Message.IsEditing ? 0 : 1); visibility: @(Message.IsEditing ? "hi
 31
 32                    <MessageContent Message="@Message" OnToolApproval="@OnToolApproval" />
 33
 5034                    @if (Message.HasPlan)
 35                    {
 36                        <div class="plan-box rz-p-3 rz-mt-2 rz-mb-2" style="border: 1px solid var(--rz-primary-light); b
 37                            <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem
 38                                <RadzenIcon Icon="assignment" IconStyle="IconStyle.Primary" />
 439                                <RadzenText TextStyle="TextStyle.Subtitle2" Style="margin: 0; color: var(--rz-primary-li
 40                            </RadzenStack>
 41                            <MarkdownBlock Content="@Message.PlanContent" />
 442                            @if (!IsLoading)
 43                            {
 44                                <RadzenButton Text="@SharedResource.ExecutePlan" Icon="play_arrow" ButtonStyle="ButtonSt
 145                                              Click="@(() => OnExecutePlan.InvokeAsync(Message))" class="rz-mt-2" />
 46                            }
 47                        </div>
 48                    }
 49                </div>
 50
 5051                @if (!Message.IsEditing && !Message.IsExpanded && !Message.IsStreaming)
 52                {
 53                    <RadzenButton Text="@SharedResource.ShowMore" Icon="expand_more" ButtonStyle="ButtonStyle.Light" Siz
 154                                 class="show-more-button rz-align-self-center" Click="@(() => Message.IsExpanded = true)
 55                }
 56
 5057                @if (Message.IsEditing)
 58                {
 59                    <div style="grid-area: 1/1; display: flex; flex-direction: column; width: 100%; height: 100%;">
 60                        <RadzenTextArea @bind-Value="@Message.TempContent" AutoSize="true" Style="width: 100%; min-heigh
 61                        <RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" JustifyContent="JustifyContent.En
 162                            <RadzenButton Icon="close" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small" Click="@(
 163                            <RadzenButton Icon="check" ButtonStyle="ButtonStyle.Primary" Size="ButtonSize.Small" Click="
 64                        </RadzenStack>
 65                    </div>
 66                }
 67
 5068                @if (Message.IsStreaming)
 69                {
 70                    <RadzenIcon Icon="more_horiz" class="rz-chat-message-streaming-icon" />
 71                }
 72
 5073                @if (Message.IsRetrying)
 74                {
 75                    <div class="retry-countdown" style="margin-top: 0.5rem; color: var(--rz-warning); font-size: 0.85rem
 76                        <RadzenIcon Icon="autorenew" class="rz-spin" Style="font-size: 1rem;" />
 477                        <span>@SharedResource.RetryIn @Message.RetryCountdown... (@Message.RetryAttempt / @Message.MaxRe
 78                    </div>
 79                }
 80            </div>
 81
 82        <!-- Message Actions -->
 5083        @if (!Message.IsStreaming && !Message.IsEditing)
 84        {
 85            <RadzenStack Orientation="Orientation.Horizontal" JustifyContent="JustifyContent.End" Gap="0.25rem" class="r
 86                <RadzenButton Icon="edit" Variant="Variant.Text" ButtonStyle="ButtonStyle.Base" Size="ButtonSize.ExtraSm
 187                              Click="@(() => OnEdit.InvokeAsync(Message))" Title="@SharedResource.MessageEdit" />
 88                <RadzenButton Icon="delete" Variant="Variant.Text" ButtonStyle="ButtonStyle.Base" Size="ButtonSize.Extra
 189                              Click="@(() => OnDelete.InvokeAsync(Message))" Title="@SharedResource.MessageDelete" />
 3890                @if (!IsLoading && IsLast && Message.Role == ChatMessageRole.Assistant)
 91                {
 92                    <RadzenButton Icon="refresh" Variant="Variant.Text" ButtonStyle="ButtonStyle.Base" Size="ButtonSize.
 93                                  Click="@OnRegenerate" Title="@SharedResource.MessageRegenerate" />
 94                }
 95                <div class="message-badges">
 3896                    @if (CommonSettingsProvider.Current.ShowMessageTimings && Message.Timings is { FirstToken.TotalMilli
 97                    {
 98                        <RadzenBadge BadgeStyle="BadgeStyle.Light" title="@SharedResource.FirstToken">
 199                            <i class="fa-solid fa-arrow-right-arrow-left"></i> @Message.Timings.FirstToken.TotalSeconds.
 100                        </RadzenBadge>
 101                        <RadzenBadge BadgeStyle="BadgeStyle.Light" >
 1102                            <i class="fa-solid fa-gauge-high"></i> @Message.Timings.TokensInSec.ToString("F1") t/s
 103                        </RadzenBadge>
 104                        <RadzenBadge BadgeStyle="BadgeStyle.Light" >
 1105                            <i class="fa-solid fa-flag-checkered"></i> @Message.Timings.Total.TotalSeconds.ToString("F1"
 106                        </RadzenBadge>
 107                    }
 108                </div>
 109            </RadzenStack>
 110        }
 111    </RadzenStack>
 112</div>
 113
 114@code {
 85115    [Inject] private ICommonSettingsProvider CommonSettingsProvider { get; set; } = null!;
 1417116    [Parameter] public VisualChatMessage Message { get; set; } = null!;
 77117    [Parameter] public string UserAvatarText { get; set; } = "U"; // TODO сделать что-то поинтереснее
 98118    [Parameter] public bool IsLoading { get; set; }
 101119    [Parameter] public bool IsLast { get; set; }
 50120    [Parameter] public EventCallback<(string MessageId, string SegmentId, bool Approved)> OnToolApproval { get; set; }
 2121    [Parameter] public EventCallback<VisualChatMessage> OnExecutePlan { get; set; }
 2122    [Parameter] public EventCallback<VisualChatMessage> OnEdit { get; set; }
 2123    [Parameter] public EventCallback<VisualChatMessage> OnCancelEdit { get; set; }
 2124    [Parameter] public EventCallback<VisualChatMessage> OnSaveEdit { get; set; }
 2125    [Parameter] public EventCallback<VisualChatMessage> OnDelete { get; set; }
 3126    [Parameter] public EventCallback OnRegenerate { get; set; }
 127
 128    private bool _oldIsStreaming;
 129    private bool _oldIsEditing;
 130    private bool _oldIsLast;
 131    private bool _oldIsLoading;
 132    private bool _oldIsExpanded;
 133    private int _oldRetryCountdown;
 47134    private string _oldContent = string.Empty;
 135
 136    protected override bool ShouldRender()
 137    {
 138        // Проверяем, изменилось ли состояние загрузки конкретно для последнего (или только что переставшего быть послед
 6139        var isLoadingChangedForLast = (IsLast || _oldIsLast) && (_oldIsLoading != IsLoading);
 140
 6141        return Message.IsStreaming || _oldIsStreaming ||
 6142               Message.IsRetrying || _oldRetryCountdown != Message.RetryCountdown ||
 6143               Message.IsEditing || _oldIsEditing ||
 6144               _oldIsLast != IsLast ||
 6145               isLoadingChangedForLast ||
 6146               Message.IsExpanded != _oldIsExpanded ||
 6147               Message.Content != _oldContent;
 148    }
 149
 150    protected override void OnAfterRender(bool firstRender)
 151    {
 152        // Фиксируем состояния ПОСЛЕ рендера, чтобы в следующем цикле ShouldRender сравнение работало корректно
 50153        _oldIsLoading = IsLoading;
 50154        _oldIsLast = IsLast;
 155
 50156        _oldIsStreaming = Message.IsStreaming;
 50157        _oldRetryCountdown = Message.RetryCountdown;
 50158        _oldIsEditing = Message.IsEditing;
 50159        _oldIsExpanded = Message.IsExpanded;
 50160        _oldContent = Message.Content;
 50161    }
 162}