Skip to content

Commit edc8f57

Browse files
committed
Enhance UI/UX and refactor for maintainability
- Redesigned hero section and footer in MainLayout.razor. - Added security tips, toast notifications, and improved API key management in ApiKeys.razor. - Refactored platform download buttons in Downloads.razor. - Revamped "About," "Features," and added "How It Works" sections in Home.razor. - Improved accessibility and added raw plugin download links in PluginsDetails.razor. - Updated app.css with new primary color, form styles, and `.btn-xs` class. - Focused on improving user experience, visual design, and code maintainability. #46
1 parent a1d4a8e commit edc8f57

6 files changed

Lines changed: 393 additions & 91 deletions

File tree

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,17 @@
6767
<section class="py-1">
6868
<div class="container px-5">
6969
<div class="row gx-5 align-items-center justify-content-center hero-content">
70-
<div class="col-lg-12 col-xl-12 col-xxl-12">
71-
<div class="my-5 text-center text-xl-start">
72-
<h1 class="display-5 fw-bolder text-dark mb-2">Official FlowSynx plugin registry</h1>
73-
<p class="lead fw-normal text-dark mb-4">Discover, Extend, AutomatePower Up Your FlowSynx Workflows With Seamless Plugin Integration</p>
70+
<div class="col-lg-12 col-xl-12 col-xxl-12 text-center">
71+
<div class="my-5">
72+
<h1 class="display-3 fw-bold mb-3">FlowSynx Plugin Registry</h1>
73+
<p class="lead fw-normal mb-4">
74+
Extend your automation capabilities with a powerful ecosystem of plugins.
75+
Discover, share, and deploy components that accelerate your workflow.
76+
</p>
77+
<div class="d-grid gap-3 d-sm-flex justify-content-sm-center">
78+
<a class="btn btn-dark btn-lg px-4 me-sm-3" href="/plugins">Explore Plugins</a>
79+
<a class="btn btn-outline-dark btn-lg px-4" href="#about">Learn More</a>
80+
</div>
7481
</div>
7582
</div>
7683
</div>
@@ -90,6 +97,8 @@
9097
</div>
9198
<div class="col-auto">
9299
<ul class="list-inline small mb-0">
100+
<li class="list-inline-item"><a href="/downloads" class="text-decoration-none text-muted">Downloads</a></li>
101+
<li class="list-inline-item">•</li>
93102
<li class="list-inline-item"><a href="/policies/privacy" class="text-decoration-none text-muted">Privacy Policy</a></li>
94103
<li class="list-inline-item">•</li>
95104
<li class="list-inline-item"><a href="/policies/terms" class="text-decoration-none text-muted">Terms of Service</a></li>

src/FlowSynx.Pluginregistry/Components/Pages/Account/ApiKeys.razor

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,21 @@
2020

2121
<div class="row mb-4">
2222
<div class="col-md-12">
23-
<button class="btn btn-primary" @onclick="ShowCreateDialog">
23+
<div class="alert alert-info">
24+
<strong><i class="bi bi-shield-check"></i> Security Best Practices:</strong>
25+
<ul class="mb-0 mt-2">
26+
<li>Store API keys securely in environment variables or secret managers</li>
27+
<li>Rotate keys regularly and revoke unused ones</li>
28+
<li>Use separate keys for different environments (dev, staging, production)</li>
29+
<li>Set expiration dates to limit key lifespan</li>
30+
</ul>
31+
</div>
32+
</div>
33+
</div>
34+
35+
<div class="row mb-4">
36+
<div class="col-md-12">
37+
<button class="btn btn-sm btn-primary" @onclick="ShowCreateDialog">
2438
<i class="bi bi-plus-circle"></i> Create New API Key
2539
</button>
2640
</div>
@@ -39,14 +53,16 @@
3953
}
4054
else if (_error != null)
4155
{
42-
<div class="alert alert-danger" role="alert">
43-
<i class="bi bi-exclamation-triangle-fill"></i> @_error
56+
<div class="alert alert-danger alert-dismissible fade show" role="alert">
57+
<i class="bi bi-exclamation-triangle-fill"></i>
58+
<strong>Error:</strong> @_error
59+
<button type="button" class="btn-close" @onclick="() => _error = null"></button>
4460
</div>
4561
}
4662
else if (_apiKeys?.Any() == true)
4763
{
4864
<div class="table-responsive">
49-
<table class="table table-striped table-hover">
65+
<table class="table table-sm table-hover table-border">
5066
<thead>
5167
<tr>
5268
<th>Name</th>
@@ -64,8 +80,6 @@
6480
<td>
6581
<div>
6682
<strong>@key.Name</strong>
67-
<br />
68-
<small class="text-muted font-monospace">@key.Key[..8]...</small>
6983
</div>
7084
</td>
7185
<td>
@@ -85,11 +99,11 @@
8599
<td>
86100
@if (key.CanPushNewPlugins)
87101
{
88-
<span class="badge bg-info me-1">New Plugins</span>
102+
<span class="badge border border-secondary text-secondary me-1">New Plugins</span>
89103
}
90104
@if (key.CanPushPluginVersions)
91105
{
92-
<span class="badge bg-info me-1">Versions</span>
106+
<span class="badge border border-secondary text-secondary me-1">Versions</span>
93107
}
94108
@if (key.AssignedPlugins.Any())
95109
{
@@ -100,7 +114,15 @@
100114
<td>
101115
@if (key.ExpiresAt.HasValue)
102116
{
103-
@key.ExpiresAt.Value.ToString("yyyy-MM-dd")
117+
var daysUntilExpiry = (key.ExpiresAt.Value - DateTime.UtcNow).Days;
118+
<span class="@(daysUntilExpiry <= 7 ? "text-danger fw-bold" : "")">
119+
@key.ExpiresAt.Value.ToString("yyyy-MM-dd")
120+
@if (daysUntilExpiry <= 7 && daysUntilExpiry > 0)
121+
{
122+
<i class="bi bi-exclamation-triangle-fill text-warning ms-1"
123+
title="Expires in @daysUntilExpiry days"></i>
124+
}
125+
</span>
104126
}
105127
else
106128
{
@@ -110,7 +132,7 @@
110132
<td>
111133
@if (key.IsActive)
112134
{
113-
<button class="btn btn-sm btn-danger" @onclick="() => ConfirmRevoke(key.Id)">
135+
<button class="btn btn-xs btn-danger" @onclick="() => ConfirmRevoke(key.Id)">
114136
<i class="bi bi-trash"></i> Revoke
115137
</button>
116138
}
@@ -128,6 +150,9 @@
128150
<i class="bi bi-key" style="font-size: 3rem; color: #6c757d;"></i>
129151
<h5 class="mt-3">No API Keys</h5>
130152
<p class="text-muted">Create your first API key to start uploading plugins programmatically.</p>
153+
<button class="btn btn-sm btn-primary mt-3" @onclick="ShowCreateDialog">
154+
<i class="bi bi-plus-circle"></i> Create Your First API Key
155+
</button>
131156
</div>
132157
</div>
133158
}
@@ -170,8 +195,16 @@
170195
<label class="form-label fw-bold">API Key</label>
171196
<div class="input-group">
172197
<input type="text" class="form-control font-monospace" value="@_newRawKey" readonly />
173-
<button class="btn btn-outline-secondary" type="button" @onclick="CopyToClipboard">
174-
<i class="bi bi-clipboard"></i> Copy
198+
<button class="btn btn-outline-secondary" type="button" @onclick="CopyToClipboard" disabled="@_copying">
199+
@if (_copying)
200+
{
201+
<span class="spinner-border spinner-border-sm" role="status"></span>
202+
}
203+
else
204+
{
205+
<i class="bi bi-clipboard"></i>
206+
}
207+
Copy
175208
</button>
176209
</div>
177210
</div>
@@ -220,6 +253,21 @@
220253
</div>
221254
}
222255

256+
@if (_showToast)
257+
{
258+
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
259+
<div class="toast fade show" role="alert" aria-live="assertive" aria-atomic="true">
260+
<div class="toast-header">
261+
<strong class="me-auto">API Key Status</strong>
262+
<button type="button" class="btn-close" @onclick="() => _showToast = false" aria-label="Close"></button>
263+
</div>
264+
<div class="toast-body">
265+
@_toastMessage
266+
</div>
267+
</div>
268+
</div>
269+
}
270+
223271
@code {
224272
private List<ApiKeyViewModel>? _apiKeys;
225273
private bool _loading = true;
@@ -230,6 +278,10 @@
230278
private bool _revoking;
231279
private string _newRawKey = string.Empty;
232280
private Guid _keyToRevoke;
281+
private string? _toastMessage;
282+
private bool _showToast;
283+
private string? _successMessage;
284+
private bool _copying = false;
233285

234286
protected override async Task OnInitializedAsync()
235287
{
@@ -288,14 +340,26 @@
288340

289341
private async Task CopyToClipboard()
290342
{
343+
_copying = true;
344+
StateHasChanged();
345+
291346
try
292347
{
293348
await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", _newRawKey);
294-
await JSRuntime.InvokeVoidAsync("alert", "API key copied to clipboard!");
349+
_toastMessage = "API key copied to clipboard!";
350+
_showToast = true;
351+
StateHasChanged();
352+
await Task.Delay(3000);
353+
_showToast = false;
295354
}
296355
catch
297356
{
298-
await JSRuntime.InvokeVoidAsync("alert", "Failed to copy to clipboard");
357+
_toastMessage = "Failed to copy to clipboard. Please copy manually.";
358+
_showToast = true;
359+
}
360+
finally
361+
{
362+
_copying = false;
299363
}
300364
}
301365

@@ -319,6 +383,7 @@
319383
var result = await ApiKeyService.RevokeApiKeyAsync(_keyToRevoke);
320384
if (result?.Succeeded == true)
321385
{
386+
_successMessage = "API key revoked successfully.";
322387
await LoadApiKeys();
323388
HideConfirmDialog();
324389
}

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

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,32 +62,9 @@
6262
data-bs-parent="#releasesAccordion">
6363
<div class="accordion-body">
6464
<div class="mb-2">
65-
@if (!string.IsNullOrEmpty(release.WindowsDownloadUrl))
66-
{
67-
<a href="@release.WindowsDownloadUrl"
68-
class="btn btn-outline-primary me-2"
69-
target="_blank">
70-
<i class="bi bi-windows"></i> Download for Windows
71-
</a>
72-
}
73-
74-
@if (!string.IsNullOrEmpty(release.LinuxDownloadUrl))
75-
{
76-
<a href="@release.LinuxDownloadUrl"
77-
class="btn btn-outline-primary me-2"
78-
target="_blank">
79-
<i class="bi bi-tux"></i> Download for Linux
80-
</a>
81-
}
82-
83-
@if (!string.IsNullOrEmpty(release.MacOsDownloadUrl))
84-
{
85-
<a href="@release.MacOsDownloadUrl"
86-
class="btn btn-outline-primary"
87-
target="_blank">
88-
<i class="bi bi-apple"></i> Download for macOS
89-
</a>
90-
}
65+
@RenderDownloadButton(release.WindowsDownloadUrl, "windows", "Windows")
66+
@RenderDownloadButton(release.LinuxDownloadUrl, "tux", "Linux")
67+
@RenderDownloadButton(release.MacOsDownloadUrl, "apple", "macOS")
9168

9269
@if (string.IsNullOrEmpty(release.WindowsDownloadUrl) &&
9370
string.IsNullOrEmpty(release.LinuxDownloadUrl) &&
@@ -114,4 +91,17 @@
11491
{
11592
releases = await gitHubReleaseService.GetAllReleasesAsync();
11693
}
94+
95+
private RenderFragment RenderDownloadButton(string? url, string icon, string platform) => __builder =>
96+
{
97+
if (!string.IsNullOrEmpty(url))
98+
{
99+
<a href="@url"
100+
class="btn btn-sm btn-outline-primary me-2"
101+
target="_blank"
102+
rel="noopener noreferrer">
103+
<i class="bi bi-@icon"></i> Download for @platform
104+
</a>
105+
}
106+
};
117107
}

0 commit comments

Comments
 (0)