Skip to content

Commit 007c987

Browse files
committed
Add plugin version management and UI enhancements
Introduced enable/disable functionality for plugin versions, including new methods in `MediatorExtensions`, handlers, and API endpoints. Updated `PluginDetails` to display active status and added UI controls for owners to toggle visibility. Enhanced the UI with improved navigation, footer, and button styles. Added new pages for Privacy Policy, Terms of Service, and Contact information. Updated `app.css` with a new primary color and styling improvements. Implemented `AuthorizationMessageHandler` for secure cookie handling in HTTP requests. Extended `IApiClient` with a `PutAsync` method and updated `StatsApiService` for plugin version management. Replaced the hero banner image and performed minor refactoring for code consistency. #44
1 parent adf6905 commit 007c987

25 files changed

Lines changed: 1173 additions & 48 deletions

File tree

src/FlowSynx.PluginRegistry.Application/Extensions/MediatorExtensions.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using FlowSynx.PluginRegistry.Application.Features.Plugins.Query.PluginDetails;
1+
using FlowSynx.PluginRegistry.Application.Features.Plugins.Command.SetPluginVersionActiveStatus;
2+
using FlowSynx.PluginRegistry.Application.Features.Plugins.Query.PluginDetails;
23
using FlowSynx.PluginRegistry.Application.Features.Plugins.Query.PluginIcon;
34
using FlowSynx.PluginRegistry.Application.Features.Plugins.Query.PluginLocation;
45
using FlowSynx.PluginRegistry.Application.Features.Plugins.Query.PluginReadme;
@@ -88,6 +89,34 @@ public static Task<Result<PluginLocationResponse>> PluginLocation(
8889
PluginVersion = pluginVersion
8990
}, cancellationToken);
9091
}
92+
93+
public static Task<Result<bool>> EnablePluginVersion(
94+
this IMediator mediator,
95+
string pluginType,
96+
string pluginVersion,
97+
CancellationToken cancellationToken)
98+
{
99+
return mediator.Send(new SetPluginVersionActiveStatusRequest
100+
{
101+
PluginType = pluginType,
102+
PluginVersion = pluginVersion,
103+
IsActive = true
104+
}, cancellationToken);
105+
}
106+
107+
public static Task<Result<bool>> DisablePluginVersion(
108+
this IMediator mediator,
109+
string pluginType,
110+
string pluginVersion,
111+
CancellationToken cancellationToken)
112+
{
113+
return mediator.Send(new SetPluginVersionActiveStatusRequest
114+
{
115+
PluginType = pluginType,
116+
PluginVersion = pluginVersion,
117+
IsActive = false
118+
}, cancellationToken);
119+
}
91120
#endregion
92121

93122
#region Profile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using FlowSynx.PluginRegistry.Application.Wrapper;
2+
using FlowSynx.PluginRegistry.Domain.Plugin;
3+
using MediatR;
4+
using Microsoft.Extensions.Logging;
5+
6+
namespace FlowSynx.PluginRegistry.Application.Features.Plugins.Command.SetPluginVersionActiveStatus;
7+
8+
internal class SetPluginVersionActiveStatusHandler : IRequestHandler<SetPluginVersionActiveStatusRequest, Result<bool>>
9+
{
10+
private readonly ILogger<SetPluginVersionActiveStatusHandler> _logger;
11+
private readonly IPluginVersionService _pluginVersionService;
12+
13+
public SetPluginVersionActiveStatusHandler(
14+
ILogger<SetPluginVersionActiveStatusHandler> logger,
15+
IPluginVersionService pluginVersionService)
16+
{
17+
ArgumentNullException.ThrowIfNull(logger);
18+
ArgumentNullException.ThrowIfNull(pluginVersionService);
19+
_logger = logger;
20+
_pluginVersionService = pluginVersionService;
21+
}
22+
23+
public async Task<Result<bool>> Handle(SetPluginVersionActiveStatusRequest request, CancellationToken cancellationToken)
24+
{
25+
try
26+
{
27+
var result = await _pluginVersionService.SetActiveStatus(
28+
request.PluginType,
29+
request.PluginVersion,
30+
request.IsActive,
31+
cancellationToken);
32+
33+
if (!result)
34+
{
35+
return await Result<bool>.FailAsync("Plugin version not found");
36+
}
37+
38+
var statusText = request.IsActive ? "enabled" : "disabled";
39+
return await Result<bool>.SuccessAsync(true, $"Plugin version {statusText} successfully");
40+
}
41+
catch (Exception ex)
42+
{
43+
_logger.LogError(ex, "Error setting plugin version active status");
44+
return await Result<bool>.FailAsync($"Error: {ex.Message}");
45+
}
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using FlowSynx.PluginRegistry.Application.Wrapper;
2+
using MediatR;
3+
4+
namespace FlowSynx.PluginRegistry.Application.Features.Plugins.Command.SetPluginVersionActiveStatus;
5+
6+
public class SetPluginVersionActiveStatusRequest : IRequest<Result<bool>>
7+
{
8+
public required string PluginType { get; set; } = default!;
9+
public string PluginVersion { get; set; } = default!;
10+
public bool IsActive { get; set; }
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using FluentValidation;
2+
3+
namespace FlowSynx.PluginRegistry.Application.Features.Plugins.Command.SetPluginVersionActiveStatus;
4+
5+
public class SetPluginVersionActiveStatusValidator : AbstractValidator<SetPluginVersionActiveStatusRequest>
6+
{
7+
public SetPluginVersionActiveStatusValidator()
8+
{
9+
RuleFor(x => x.PluginType)
10+
.NotNull()
11+
.NotEmpty()
12+
.WithMessage("Plugin type must have value!");
13+
14+
RuleFor(x => x.PluginVersion)
15+
.NotNull()
16+
.NotEmpty()
17+
.WithMessage("Plugin version must have value!");
18+
}
19+
}

src/FlowSynx.PluginRegistry.Application/Features/Plugins/Query/PluginDetails/PluginDetailsHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public async Task<Result<PluginDetailsResponse>> Handle(PluginDetailsRequest req
4545
TotalDownload = plugin.Statistics.Count,
4646
Checksum = plugin.Checksum,
4747
IsTrusted = plugin.Plugin.IsTrusted,
48+
IsActive = plugin.IsActive,
4849
Tags = plugin.PluginVersionTags.Select(x=>x.Tag!.Name),
4950
MinimumFlowSynxVersion = plugin.MinimumFlowSynxVersion,
5051
TargetFlowSynxVersion = plugin.TargetFlowSynxVersion,

src/FlowSynx.PluginRegistry.Application/Features/Plugins/Query/PluginDetails/PluginDetailsResponse.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class PluginDetailsResponse
1717
public DateTime LastUpdated { get; set; }
1818
public int TotalDownload { get; set; } = 0;
1919
public bool IsTrusted { get; set; } = false;
20+
public bool IsActive { get; set; } = false;
2021
public IEnumerable<string> Tags { get; set; } = new List<string>();
2122
public IEnumerable<string> Versions { get; set; } = new List<string>();
2223
public IEnumerable<string> Owners { get; set; } = new List<string>();

src/FlowSynx.PluginRegistry.Domain/Plugin/IPluginVersionService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ public interface IPluginVersionService
99
Task AddTagsToPluginVersionAsync(Guid pluginVersionId, List<string> tagNames, CancellationToken cancellationToken);
1010
Task Update(PluginVersionEntity pluginVersionEntity, CancellationToken cancellationToken);
1111
Task<bool> Delete(PluginVersionEntity pluginVersionEntity, CancellationToken cancellationToken);
12+
Task<bool> SetActiveStatus(string pluginType, string pluginVersion, bool isActive, CancellationToken cancellationToken);
1213
}

src/FlowSynx.PluginRegistry.Infrastructure/Services/PluginVersionService.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,32 @@ await context
208208
throw new Exception(ex.Message);
209209
}
210210
}
211+
212+
public async Task<bool> SetActiveStatus(string pluginType, string pluginVersion, bool isActive, CancellationToken cancellationToken)
213+
{
214+
try
215+
{
216+
await using var context = await _appContextFactory.CreateDbContextAsync(cancellationToken);
217+
var version = await context.PluginVersions
218+
.Include(pv => pv.Plugin)
219+
.FirstOrDefaultAsync(pv =>
220+
pv.Plugin != null &&
221+
pv.Plugin.Type.ToLower() == pluginType.ToLower() &&
222+
pv.Version.ToLower() == pluginVersion.ToLower() &&
223+
!pv.IsDeleted,
224+
cancellationToken)
225+
.ConfigureAwait(false);
226+
227+
if (version == null)
228+
return false;
229+
230+
version.IsActive = isActive;
231+
await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
232+
return true;
233+
}
234+
catch (Exception ex)
235+
{
236+
throw new Exception(ex.Message);
237+
}
238+
}
211239
}

src/FlowSynx.Pluginregistry/Components/Layout/MainLayout.razor

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
@inject AuthenticationStateProvider AuthenticationStateProvider
99

1010
<main class="flex-shrink-0">
11-
<div class="hero-banner">
12-
<nav class="navbar navbar-expand-lg">
13-
<div class="container px-5">
11+
<div class="hero-banner pb-3">
12+
<div class="container px-5">
13+
<nav class="navbar navbar-expand-lg">
1414
<a class="navbar-brand pe-2" href="/">
1515
<img src="/images/logo.png" alt="Logo" width="24" height="24" class="d-inline-block align-text-top">
1616
Plugin Registry
@@ -47,8 +47,9 @@
4747
}
4848
</ul>
4949
</div>
50-
</div>
51-
</nav>
50+
</nav>
51+
</div>
52+
5253

5354
<div class="py-3">
5455
<div class="container px-5">
@@ -83,7 +84,18 @@
8384
<footer class="bg-light py-4 mt-auto">
8485
<div class="container px-5">
8586
<div class="row align-items-center justify-content-between flex-column flex-sm-row">
86-
<div class="col-auto"><div class="small m-0">Copyright &copy; <a href="https://flowsynx.io" target="_blank">FlowSynx</a> 2025</div></div>
87+
<div class="col-auto">
88+
<div class="small m-0">Copyright &copy; <a href="https://flowsynx.io" target="_blank">FlowSynx</a> 2025</div>
89+
</div>
90+
<div class="col-auto">
91+
<ul class="list-inline small mb-0">
92+
<li class="list-inline-item"><a href="/policies/privacy" class="text-decoration-none text-muted">Privacy Policy</a></li>
93+
<li class="list-inline-item">•</li>
94+
<li class="list-inline-item"><a href="/policies/terms" class="text-decoration-none text-muted">Terms of Service</a></li>
95+
<li class="list-inline-item">•</li>
96+
<li class="list-inline-item"><a href="/policies/contact" class="text-decoration-none text-muted">Contact</a></li>
97+
</ul>
98+
</div>
8799
</div>
88100
</div>
89101
</footer>

src/FlowSynx.Pluginregistry/Components/Pages/Downloads/Downloads.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
@if (!string.IsNullOrEmpty(release.WindowsDownloadUrl))
6666
{
6767
<a href="@release.WindowsDownloadUrl"
68-
class="btn btn-outline-dark me-2"
68+
class="btn btn-outline-primary me-2"
6969
target="_blank">
7070
<i class="bi bi-windows"></i> Download for Windows
7171
</a>
@@ -74,7 +74,7 @@
7474
@if (!string.IsNullOrEmpty(release.LinuxDownloadUrl))
7575
{
7676
<a href="@release.LinuxDownloadUrl"
77-
class="btn btn-outline-dark me-2"
77+
class="btn btn-outline-primary me-2"
7878
target="_blank">
7979
<i class="bi bi-tux"></i> Download for Linux
8080
</a>
@@ -83,7 +83,7 @@
8383
@if (!string.IsNullOrEmpty(release.MacOsDownloadUrl))
8484
{
8585
<a href="@release.MacOsDownloadUrl"
86-
class="btn btn-outline-dark"
86+
class="btn btn-outline-primary"
8787
target="_blank">
8888
<i class="bi bi-apple"></i> Download for macOS
8989
</a>

0 commit comments

Comments
 (0)