Skip to content

Commit

Permalink
Another set of improvements to PR page (#4349)
Browse files Browse the repository at this point in the history
  • Loading branch information
premun authored Jan 21, 2025
1 parent df07f03 commit 3c5ee43
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public TrackedPullRequest(bool sourceEnabled, DateTimeOffset lastUpdate, DateTim
public string Url { get; set; }

[JsonProperty("channel")]
public string Channel { get; set; }
public Models.Channel Channel { get; set; }

[JsonProperty("targetBranch")]
public string TargetBranch { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ public async Task UntrackPullRequestAsync(
)
{

if (string.IsNullOrEmpty(id))
{
throw new ArgumentNullException(nameof(id));
}

const string apiVersion = "2020-02-20";

var _baseUri = Client.Options.BaseUri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.DotNet.DarcLib.Helpers;
using Microsoft.EntityFrameworkCore;
using ProductConstructionService.Api.Configuration;
using ProductConstructionService.Api.v2020_02_20.Models;
using ProductConstructionService.Common;
using ProductConstructionService.DependencyFlow;

Expand Down Expand Up @@ -109,7 +110,7 @@ public async Task<IActionResult> GetTrackedPullRequests()
prs.Add(new TrackedPullRequest(
key.Replace(keyPrefix, null, StringComparison.InvariantCultureIgnoreCase),
TurnApiUrlToWebsite(pr.Url, org, repoName),
sampleSub?.Channel?.Name,
sampleSub?.Channel != null ? new Channel(sampleSub?.Channel) : null,
sampleSub?.TargetBranch,
sampleSub?.SourceEnabled ?? false,
pr.LastUpdate,
Expand Down Expand Up @@ -161,7 +162,7 @@ private static string TurnApiUrlToWebsite(string url, string? orgName, string? r
private record TrackedPullRequest(
string Id,
string Url,
string? Channel,
Channel? Channel,
string? TargetBranch,
bool SourceEnabled,
DateTime LastUpdate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public static class RepoUrlConverter
return null;
}

private static readonly Regex _repoUrlGitHubRegex = new(@"^https:\/\/github\.com\/(?<org>[^\/]+)\/(?<repoPath>.*)$");
private static readonly Regex _repoUrlAzureDevOpsRegex = new(@"^https:\/\/dev\.azure\.com\/(?<org>[^\/]+)\/(?<project>[^\/]+)\/_git\/(?<repoPath>.*)$");
private static readonly Regex _repoUrlGitHubRegex = new(@"^https:\/\/github\.com\/(?<org>[^\/]+)\/(?<repoPath>[^\/\?]+)");
private static readonly Regex _repoUrlAzureDevOpsRegex = new(@"^https:\/\/dev\.azure\.com\/(?<org>[^\/]+)\/(?<project>[^\/]+)\/_git\/(?<repoPath>[^\/\?]+)");

public static string? RepoUrlToSlug(string? repoUrl)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
@inject IProductConstructionServiceApi PcsApi
@inject IToastService ToastService
@inject UserRoleManager UserRoleManager
@inject NavigationManager NavigationManager

<FluentButton Id="@("more_" + PullRequest.Id)"
Appearance="Appearance.Lightweight"
Expand All @@ -22,6 +23,19 @@
</span>
</FluentMenuItem>

@if (PullRequest.Channel != null)
{
@foreach (var update in PullRequest.Updates)
{
<FluentMenuItem OnClick="@(() => NavigationManager.NavigateTo(ProductConstructionService.BarViz.Pages.PullRequests.GetBuildLink(update.SourceRepository, PullRequest!.Channel, update.BuildId)))">
Show build @update.BuildId details
<span slot="start">
<FluentIcon Value="@(new Icons.Regular.Size16.Flashlight())" Color="@Color.Neutral" />
</span>
</FluentMenuItem>
}
}

<FluentMenuItem OnClick="@UntrackPullRequest" Disabled="@(!_isAdmin)">
Untrack
<span slot="start">
Expand Down Expand Up @@ -51,12 +65,13 @@
try
{
await PcsApi.PullRequest.UntrackPullRequestAsync(PullRequest.Id);
await Refresh.Invoke();
ToastService.ShowSuccess("PR untracked");
await Refresh.Invoke();
}
catch (Exception e)
{
ToastService.ShowError("Failed to untrack the PR: " + e.ToString());
ToastService.ShowError("Failed to untrack the PR");
Console.WriteLine(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,92 @@
@using Microsoft.DotNet.ProductConstructionService.Client.Models
@using Microsoft.FluentUI.AspNetCore.Components.Extensions
@using System.Linq.Expressions
@using ProductConstructionService.BarViz.Code.Helpers
@using ProductConstructionService.BarViz.Components
@inject IProductConstructionServiceApi PcsApi

<style>
.hover:not([row-type='header'],[row-type='sticky-header'],.loading-content-row):hover[b-upi3f9mbnn] {
cursor: default;
}
</style>

<PageTitle>Tracked Pull Requests</PageTitle>

<div style="float: right">
<FluentSwitch Label="Auto-refresh"
CheckedMessage="30s"
UncheckedMessage="off"
Value="@_autoRefresh"
ValueChanged="@SetAutoRefresh" />
CheckedMessage="30s"
UncheckedMessage="off"
Value="@_autoRefresh"
ValueChanged="@SetAutoRefresh" />
</div>

<GridViewTemplate Title="@($"Pull Requests ({TrackedPullRequests?.Count().ToString() ?? "0"})")" ShowSkeleton="TrackedPullRequests == null">
<Content>
<FluentDataGrid Id="pullRequestsGrid" Items="@TrackedPullRequests" GridTemplateColumns="3fr 2fr 2fr 1fr 1fr 60px" TGridItem=TrackedPullRequest Style="width: 100%">
<FluentDataGrid Id="pullRequestsGrid"
Items="@TrackedPullRequests"
AutoFit="true"
TGridItem=TrackedPullRequest
ShowHover="true"
ResizableColumns="true"
Style="width: 100%">
<EmptyContent>
<FluentLabel>No pull requests found</FluentLabel>
</EmptyContent>
<ChildContent>
<TemplateColumn Sortable="true" SortBy="SortBy(pr => pr.Url)" Align="Align.Start" Title="Pull request">
<FluentAnchor Href="@context.Url" Target="_blank" Appearance="Appearance.Hypertext">@context.Url</FluentAnchor>
</TemplateColumn>
<TemplateColumn Sortable="true" SortBy="SortBy(pr => pr.Channel)" Align="Align.Center" Title="Channel">
<FluentLabel>@(context.Channel ?? "N/A")</FluentLabel>
</TemplateColumn>
<TemplateColumn Sortable="true" SortBy="SortBy(pr => pr.TargetBranch)" Align="Align.Center" Title="Target branch">
<FluentLabel>@(context.TargetBranch ?? "N/A")</FluentLabel>
</TemplateColumn>
<TemplateColumn Sortable="true" SortBy="SortBy(pr => pr.LastUpdate.ToString())" Align="Align.Center" Title="Last Update">
<FluentLabel Id="@("lastUpdate_" + context.Id)" Style="@(context.Updates.Count > 0 ? "text-decoration:underline; text-decoration-style: dotted" : null)">
@(context.LastUpdate == default ? "N/A" : (DateTime.UtcNow - context.LastUpdate).ToTimeAgo())
</FluentLabel>
<FluentAnchor Href="@context.Url" Target="_blank" Appearance="Appearance.Hypertext" Id="@("prUrl_" + context.Id)">@context.Url</FluentAnchor>
@if (context.Updates.Count > 0)
{
<FluentTooltip Anchor="@("lastUpdate_" + context.Id)">
<FluentTooltip Anchor="@("prUrl_" + context.Id)">
<h4>In this PR</h4>
@foreach (var update in context.Updates)
{
<div>
<h5>@update.SourceRepository</h5>
<strong>Build ID:</strong> @update.BuildId<br />
<strong>Subscription ID:</strong> @update.SubscriptionId<br />
<strong>Build ID:</strong> @update.BuildId
<br />
<strong>Subscription ID:</strong> @update.SubscriptionId
<br />
@if (context.Channel != null)
{
<FluentAnchor Href="@GetBuildLink(update.SourceRepository, context.Channel, update.BuildId)" Appearance="Appearance.Hypertext">Build details</FluentAnchor>
}
<FluentDivider />
</div>
}
</FluentTooltip>
}
</TemplateColumn>
<TemplateColumn Title="Channel" Sortable="true" SortBy="SortBy(pr => pr.Channel != null ? pr.Channel.Name : string.Empty)" Align="Align.Center">
<FluentLabel>@(context.Channel?.Name ?? "N/A")</FluentLabel>
</TemplateColumn>
<TemplateColumn Title="Target branch" Sortable="true" SortBy="SortBy(pr => pr.TargetBranch)" Align="Align.Center">
<FluentLabel>@(context.TargetBranch ?? "N/A")</FluentLabel>
</TemplateColumn>
<TemplateColumn Title="Last Update" Sortable="true" SortBy="SortBy(pr => pr.LastUpdate.ToString())" Align="Align.Center">
<FluentLabel Title="@(context.LastUpdate == default ? "N/A" : context.LastUpdate.ToString("f"))">
@(context.LastUpdate == default ? "N/A" : (DateTime.UtcNow - context.LastUpdate).ToTimeAgo())
</FluentLabel>
</TemplateColumn>
<TemplateColumn Sortable="true" SortBy="SortBy(pr => pr.LastCheck.ToString())" Align="Align.Center" Title="Last Check">
<FluentLabel>
<FluentLabel Id="@("lastCheck_" + context.Id)">
@(context.LastCheck == default ? "N/A" : (DateTime.UtcNow - context.LastCheck).ToTimeAgo())
@if (DateTime.UtcNow - context.LastCheck > TimeSpan.FromHours(1))
{
<FluentIcon Value="@(new Icons.Filled.Size20.Warning())"
Color="Color.Warning"
Title="PR has not been checked on by PCS in a while" />
Color="Color.Warning"
Title="PR has not been checked on by PCS in a while" />
}
@if (!context.NextCheck.HasValue)
{
<FluentIcon Value="@(new Icons.Filled.Size20.Warning())"
Color="Color.Warning"
Title="No future check set for this PR" />
Color="Color.Warning"
Title="No future check set for this PR" />
}
</FluentLabel>
</TemplateColumn>
<TemplateColumn>
<TemplateColumn Style="width:60px">
<PullRequestContextMenu PullRequest="@context" Refresh="@LoadDataAsync" />
</TemplateColumn>
</ChildContent>
Expand All @@ -90,8 +111,16 @@

async Task LoadDataAsync()
{
TrackedPullRequests = (await PcsApi.PullRequest.GetTrackedPullRequestsAsync()).AsQueryable();
await InvokeAsync(StateHasChanged);
if (_autoRefresh)
{
TrackedPullRequests = (await PcsApi.PullRequest.GetTrackedPullRequestsAsync()).AsQueryable();
await InvokeAsync(StateHasChanged);
}
}

public static string GetBuildLink(string repoUrl, Microsoft.DotNet.ProductConstructionService.Client.Models.Channel channel, int buildId)
{
return $"/channel/{channel.Id}/{RepoUrlConverter.RepoUrlToSlug(repoUrl)}/build/{buildId}";
}

void SetAutoRefresh(bool value)
Expand Down

0 comments on commit 3c5ee43

Please sign in to comment.