1
0

feat: add missing features

This commit is contained in:
Ca2didi 2025-05-20 01:20:13 +08:00
parent e6eb19aba6
commit 1a48cd1712
7 changed files with 216 additions and 15 deletions

View File

@ -205,6 +205,12 @@ namespace Flawless.Client.Remote
[Get("/api/repo/{userName}/{repositoryName}/get_users")]
Task<RepoUserRoleListingResponse> GetUsers(string userName, string repositoryName, CancellationToken cancellationToken = default);
/// <returns>OK</returns>
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
[Headers("Accept: text/plain, application/json, text/json")]
[Get("/api/repo/{userName}/{repositoryName}/stats")]
Task<RepoStatisticResponse> Stats(string userName, string repositoryName, CancellationToken cancellationToken = default);
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
[Headers("Content-Type: application/json")]
@ -406,6 +412,30 @@ namespace Flawless.Client.Remote
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class CommitByDayDetail
{
[JsonPropertyName("day")]
public System.DateTimeOffset Day { get; set; }
[JsonPropertyName("count")]
public int Count { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class CommitByPersonDetail
{
[JsonPropertyName("username")]
public string Username { get; set; }
[JsonPropertyName("count")]
public int Count { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class CommitManifest
{
@ -451,6 +481,18 @@ namespace Flawless.Client.Remote
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class DepotDetail
{
[JsonPropertyName("depotName")]
public string DepotName { get; set; }
[JsonPropertyName("depotSize")]
public long DepotSize { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class DepotLabel
{
@ -644,6 +686,21 @@ namespace Flawless.Client.Remote
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class RepoStatisticResponse
{
[JsonPropertyName("depots")]
public ICollection<DepotDetail> Depots { get; set; }
[JsonPropertyName("commitByPerson")]
public ICollection<CommitByPersonDetail> CommitByPerson { get; set; }
[JsonPropertyName("commitByDay")]
public ICollection<CommitByDayDetail> CommitByDay { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class RepoUserRole
{

View File

@ -1157,7 +1157,6 @@ public class RepositoryService : BaseService<RepositoryService>
catch (Exception e)
{
UIHelper.NotifyError(e);
Console.WriteLine(e);
return null;
}
}
@ -1182,7 +1181,6 @@ public class RepositoryService : BaseService<RepositoryService>
catch (Exception e)
{
UIHelper.NotifyError(e);
Console.WriteLine(e);
return null;
}
}

View File

@ -16,6 +16,10 @@ using Flawless.Client.Remote;
using Flawless.Client.Service;
using Flawless.Client.ViewModels.ModalBox;
using Flawless.Client.Views.ModalBox;
using LiveChartsCore;
using LiveChartsCore.Defaults;
using LiveChartsCore.Kernel.Sketches;
using LiveChartsCore.SkiaSharpView;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using Ursa.Controls;
@ -123,6 +127,13 @@ public class CommitTransitNode
public partial class RepositoryViewModel : RoutableViewModelBase
{
public class DepotStatsInfo
{
public string Id { get; set; }
public long Size { get; set; }
}
public RepositoryModel Repository { get; }
public RepositoryLocalDatabaseModel LocalDatabase { get; }
@ -133,18 +144,28 @@ public partial class RepositoryViewModel : RoutableViewModelBase
public FlatTreeDataGridSource<CommitTransitNode> Commits { get; }
public FlatTreeDataGridSource<DepotStatsInfo> Depots { get; }
public ObservableCollectionExtended<LocalChangesNode> LocalChangeSetRaw { get; } = new();
public ObservableCollectionExtended<LocalChangesNode> CurrentCommitFileTreeRaw { get; } = new();
public ObservableCollectionExtended<CommitTransitNode> CommitsRaw { get; } = new();
public ObservableCollection<DepotStatsInfo> DepotsStats { get; } = new();
public UserModel User { get; }
[Reactive] private bool _autoDetectChanges = true;
[Reactive] private bool _isOwnerRole, _isDeveloperRole, _isReporterRole, _isGuestRole, _showWebHook;
[Reactive] private ISeries[] _byDay = [new ColumnSeries<DateTimePoint>()];
public ICartesianAxis[] XAxesByDay { get; set; } = [
new DateTimeAxis(TimeSpan.FromDays(1), date => date.ToString("MMMM dd"))
];
private string _wsRoot;
public RepositoryViewModel(RepositoryModel repo, IScreen hostScreen) : base(hostScreen)
@ -234,6 +255,20 @@ public partial class RepositoryViewModel : RoutableViewModelBase
}
};
Depots = new FlatTreeDataGridSource<DepotStatsInfo>(DepotsStats)
{
Columns =
{
new TextColumn<DepotStatsInfo, string>(
"Id",
n => n.Id),
new TextColumn<DepotStatsInfo, string>(
"Size",
n => PathUtility.ConvertBytesToBestDisplay(n.Size)),
}
};
_ = StartupTasksAsync();
}
@ -242,6 +277,7 @@ public partial class RepositoryViewModel : RoutableViewModelBase
{
await RefreshRepositoryRoleInfoAsyncCommand.Execute();
await RefreshRepositoryIssuesAsyncCommand.Execute();
await RefreshStatisticDataCommand.Execute();
await RefreshWebhooksCommand.Execute();
await DetectLocalChangesAsyncCommand.Execute();
await RendererFileTreeAsync();
@ -745,4 +781,37 @@ public partial class RepositoryViewModel : RoutableViewModelBase
foreach (var n in LocalChangeSetRaw)
n.Included = false;
}
[ReactiveCommand]
private async Task RefreshStatisticData()
{
try
{
var api = Api.C;
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
{
api.ClearGateway();
return;
}
var rsp = await api.Gateway.Stats(Repository.OwnerName, Repository.Name);
DepotsStats.Clear();
foreach (var dp in rsp.Depots)
DepotsStats.Add(new DepotStatsInfo{ Id = dp.DepotName, Size = dp.DepotSize});
ByDay = new[]
{
new ColumnSeries<DateTimePoint>
{
Values = rsp.CommitByDay.Select(k => new DateTimePoint(k.Day.LocalDateTime, k.Count)).ToList(),
}
};
}
catch (Exception e)
{
UIHelper.NotifyError(e);
return;
}
}
}

View File

@ -13,6 +13,7 @@ using Flawless.Client.Remote;
using Flawless.Client.Service;
using Flawless.Client.ViewModels.ModalBox;
using Flawless.Client.Views.ModalBox;
using LiveChartsCore;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using Refit;
@ -82,14 +83,6 @@ public partial class SettingViewModel : RoutableViewModelBase
{
UIHelper.NotifyError(ex);
}
try
{
}
catch (Exception ex)
{
UIHelper.NotifyError(ex);
}
}
private async Task LoadClientSettingsAsync()

View File

@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="https://irihi.tech/ursa"
xmlns:vm="using:Flawless.Client.ViewModels"
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
xmlns:views="clr-namespace:Flawless.Client.Views"
x:DataType="vm:RepositoryViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@ -95,10 +96,23 @@
</u:Form>
</ScrollViewer>
</TabItem>
<TabItem Header="Statics" IsVisible="{Binding IsDeveloperRole}">
<StackPanel Width="600" HorizontalAlignment="Stretch">
</StackPanel>
<TabItem Header="Statics" IsVisible="{Binding IsOwnerRole}">
<ScrollViewer Width="600" HorizontalAlignment="Stretch">
<StackPanel Spacing="16" HorizontalAlignment="Stretch">
<StackPanel Orientation="Horizontal" Spacing="10">
<u:IconButton Content="Refresh" Icon="{StaticResource SemiIconRefresh}"
Command="{Binding RefreshWebhooksCommand}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Stretch" Orientation="Vertical">
<Label>Every Day Commits</Label>
<lvc:CartesianChart Series="{Binding ByDay}" XAxes="{Binding XAxesByDay}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Stretch" Orientation="Vertical">
<Label>Depot Sizes</Label>
<TreeDataGrid Source="{Binding Depots}"/>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</UserControl>

View File

@ -0,0 +1,31 @@
namespace Flawless.Communication.Response;
public struct RepoStatisticResponse
{
public struct DepotDetail
{
public string DepotName { get; set; }
public long DepotSize { get; set; }
}
public struct CommitByPersonDetail
{
public string Username { get; set; }
public int Count { get; set; }
}
public struct CommitByDayDetail
{
public DateTime Day { get; set; }
public int Count { get; set; }
}
public DepotDetail[] Depots { get; set; }
public CommitByPersonDetail[] CommitByPerson { get; set; }
public CommitByDayDetail[] CommitByDay { get; set; }
}

View File

@ -174,6 +174,45 @@ public class RepositoryInnieController(
return rp;
}
[HttpGet("stats")]
public async Task<ActionResult<RepoStatisticResponse>> GetStatisticAsync(string userName, string repositoryName)
{
var user = (await userManager.GetUserAsync(HttpContext.User))!;
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Owner);
if (grantIssue is not Repository rp) return (ActionResult) grantIssue;
var response = new RepoStatisticResponse();
// 获取Depot大小统计
response.Depots = rp.Depots
.Select(d => new RepoStatisticResponse.DepotDetail
{
DepotName = d.DepotId.ToString(),
DepotSize = d.Length
}).ToArray();
// 获取提交者提交数量统计
response.CommitByPerson = rp.Commits
.GroupBy(c => c.Author.UserName)
.Select(g => new RepoStatisticResponse.CommitByPersonDetail
{
Username = g.Key!,
Count = g.Count()
}).ToArray();
// 获取每日提交数量统计
response.CommitByDay = rp.Commits
.GroupBy(c => c.CommittedOn)
.Select(g => new RepoStatisticResponse.CommitByDayDetail
{
Day = g.Key,
Count = g.Count()
}).ToArray();
return Ok(response);
}
[HttpPost("webhooks/create")]
public async Task<IActionResult> CreateWebhook(