Skip to content

Commit 905604e

Browse files
authored
Merge branch 'neozhu:main' into main
2 parents 33a24f5 + 7c76ddc commit 905604e

28 files changed

Lines changed: 441 additions & 433 deletions

File tree

src/Application/Common/Extensions/DateTimeExtensions.cs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
public static class DateTimeExtensions
1+
public static class DateTimeExtensions
22
{
33
/// <summary>
44
/// Gets a date range based on the provided keyword, similar to Salesforce date keywords.
@@ -151,21 +151,37 @@ public static DateTime StartOfMonth(this DateTime dt, TimeSpan timeZoneOffset =
151151

152152

153153
/// <summary>
154-
/// Converts the given UTC DateTime? to local time based on the provided time offset, and formats the result.
154+
/// Converts a nullable UTC DateTime to a formatted local time string.
155+
/// If localTimeOffset is provided, it is treated as a fixed offset from UTC (e.g. +08:00).
156+
/// If localTimeOffset is null, the system's local time zone (with DST) is used.
157+
/// Returns null if utcTime is null.
155158
/// </summary>
156-
/// <param name="utcTime">The UTC time to be converted. This is a nullable DateTime.</param>
157-
/// <param name="localTimeOffset">The local time offset, typically derived from the user's profile.</param>
158-
/// <param name="formatter">The date/time format string. Defaults to "yyyy-MM-dd HH:mm:ss".</param>
159-
/// <returns>The converted and formatted local time as a string. If the input is null, it returns null.</returns>
159+
/// <param name="utcTime">UTC timestamp (Kind should ideally be Utc; if Unspecified it is assumed UTC).</param>
160+
/// <param name="localTimeOffset">Optional fixed offset (e.g. TimeSpan.FromHours(8)). If null, TimeZoneInfo.Local is used.</param>
161+
/// <param name="formatter">Output format. Default "yyyy-MM-dd HH:mm:ss".</param>
160162
public static string? ToLocalTime(this DateTime? utcTime, TimeSpan? localTimeOffset, string formatter = "yyyy-MM-dd HH:mm:ss")
161163
{
162-
if (utcTime == null || localTimeOffset==null)
163-
return null;
164+
if (utcTime is null) return null;
164165

165-
// Add the local time offset to the UTC time to get the local time
166-
var localTime = utcTime.Value + localTimeOffset;
166+
// Ensure we treat the source as UTC
167+
DateTime utc = utcTime.Value.Kind == DateTimeKind.Utc
168+
? utcTime.Value
169+
: DateTime.SpecifyKind(utcTime.Value, DateTimeKind.Utc);
167170

168-
// Format the local time according to the given formatter
169-
return localTime.Value.ToString(formatter);
171+
DateTime local;
172+
173+
if (localTimeOffset.HasValue)
174+
{
175+
// Use a fixed offset (no DST handling)
176+
var dto = new DateTimeOffset(utc, TimeSpan.Zero).ToOffset(localTimeOffset.Value);
177+
local = dto.DateTime;
178+
}
179+
else
180+
{
181+
// Use system local time zone (handles DST)
182+
local = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);
183+
}
184+
185+
return local.ToString(formatter, CultureInfo.InvariantCulture);
170186
}
171187
}

src/Application/Features/Contacts/Security/ContactsPermissions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//------------------------------------------------------------------------------
1+
//------------------------------------------------------------------------------
22
// <auto-generated>
33
// CleanArchitecture.Blazor - MIT Licensed.
44
// Author: neozhu
@@ -21,6 +21,8 @@ public static class Contacts
2121
public const string View = "Permissions.Contacts.View";
2222
[Description("Allows creating contact records.")]
2323
public const string Create = "Permissions.Contacts.Create";
24+
[Description("Allows cloning existing contact records.")]
25+
public const string Clone = "Permissions.Contacts.Clone";
2426
[Description("Allows modifying existing contact details.")]
2527
public const string Edit = "Permissions.Contacts.Edit";
2628
[Description("Allows deleting contact records.")]
@@ -40,6 +42,7 @@ public class ContactsAccessRights
4042
{
4143
public bool View { get; set; }
4244
public bool Create { get; set; }
45+
public bool Clone { get; set; }
4346
public bool Edit { get; set; }
4447
public bool Delete { get; set; }
4548
public bool Print { get; set; }

src/Application/Features/Identity/DTOs/ApplicationUserDto.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using CleanArchitecture.Blazor.Application.Features.Tenants.DTOs;
1+
using CleanArchitecture.Blazor.Application.Features.Tenants.DTOs;
22
using CleanArchitecture.Blazor.Domain.Identity;
33

44
namespace CleanArchitecture.Blazor.Application.Features.Identity.DTOs;
@@ -50,10 +50,10 @@ public class ApplicationUserDto
5050
: TimeZoneInfo.FindSystemTimeZoneById(TimeZoneId).BaseUtcOffset;
5151
[Description("Language")]
5252
public string? LanguageCode { get; set; }
53-
[Description("Last Modified DateTime")]
53+
[Description("Last Modified At")]
5454
public DateTime? LastModifiedAt { get; set; }
5555

56-
[Description("Created DateTime")]
56+
[Description("Created At")]
5757
public DateTime? CreatedAt { get; set; }
5858

5959

src/Server.UI/Components/Autocompletes/PickSuperiorIdAutocomplete.razor.cs renamed to src/Server.UI/Components/Autocompletes/PickSuperiorAutocomplete.razor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
using CleanArchitecture.Blazor.Application.Common.Interfaces.Identity;
1+
using CleanArchitecture.Blazor.Application.Common.Interfaces.Identity;
22
using CleanArchitecture.Blazor.Application.Features.Identity.DTOs;
33
using CleanArchitecture.Blazor.Infrastructure.Services.Identity;
44

55
namespace CleanArchitecture.Blazor.Server.UI.Components.Autocompletes;
66
#nullable disable warnings
7-
public class PickSuperiorIdAutocomplete<T> : MudAutocomplete<ApplicationUserDto>
7+
public class PickSuperiorAutocomplete<T> : MudAutocomplete<ApplicationUserDto>
88
{
9-
public PickSuperiorIdAutocomplete()
9+
public PickSuperiorAutocomplete()
1010
{
1111
SearchFunc = SearchKeyValues;
1212
ToStringFunc = dto => dto?.UserName;
@@ -24,9 +24,9 @@ public PickSuperiorIdAutocomplete()
2424
private Task<IEnumerable<ApplicationUserDto>> SearchKeyValues(string? value, CancellationToken cancellation)
2525
{
2626
var result = UserService.DataSource.Where(x =>
27-
x.TenantId != null && x.TenantId.Equals(TenantId) && !x.UserName.Equals(OwnerName));
27+
(x.TenantId != null && x.TenantId.Equals(TenantId) || TenantId==null) && !x.UserName.Equals(OwnerName));
2828
if (!string.IsNullOrWhiteSpace(value))
29-
result = UserService.DataSource.Where(x => x.TenantId.Equals(TenantId) && !x.UserName.Equals(OwnerName) &&
29+
result = UserService.DataSource.Where(x => (x.TenantId != null && x.TenantId.Equals(TenantId) || TenantId == null) && !x.UserName.Equals(OwnerName) &&
3030
(x.UserName.Contains(value,
3131
StringComparison.OrdinalIgnoreCase) ||
3232
x.Email.Contains(value, StringComparison.OrdinalIgnoreCase)));

src/Server.UI/Components/Security/SecurityRiskDashboard.razor

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@using CleanArchitecture.Blazor.Application.Features.LoginAudits.DTOs
1+
@using CleanArchitecture.Blazor.Application.Features.LoginAudits.DTOs
22
@using CleanArchitecture.Blazor.Application.Features.LoginAudits.Queries.GetRiskSummaryStatistics
33
@using CleanArchitecture.Blazor.Domain.Enums
44
@using MudBlazor
@@ -31,7 +31,7 @@
3131
<MudGrid>
3232
<!-- Total Users -->
3333
<MudItem xs="12" sm="6" md="3">
34-
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;" Elevation="4">
34+
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;" >
3535
<MudIcon Icon="@Icons.Material.Filled.People" Size="Size.Large" Color="Color.Inherit" Class="mb-2" />
3636
<MudText Typo="Typo.h4" Color="Color.Inherit">@_statistics.TotalUsers</MudText>
3737
<MudText Typo="Typo.body2" Color="Color.Inherit">@L["Total Users"]</MudText>
@@ -40,7 +40,7 @@
4040

4141
<!-- Low Risk -->
4242
<MudItem xs="12" sm="6" md="3">
43-
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;" Elevation="4">
43+
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
4444
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Size="Size.Large" Color="Color.Inherit" Class="mb-2" />
4545
<MudText Typo="Typo.h4" Color="Color.Inherit">@_statistics.LowRiskUsers</MudText>
4646
<MudText Typo="Typo.body2" Color="Color.Inherit">@L["Low Risk"]</MudText>
@@ -50,7 +50,7 @@
5050

5151
<!-- Medium Risk -->
5252
<MudItem xs="12" sm="6" md="3">
53-
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white;" Elevation="4">
53+
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white;" >
5454
<MudIcon Icon="@Icons.Material.Filled.Warning" Size="Size.Large" Color="Color.Inherit" Class="mb-2" />
5555
<MudText Typo="Typo.h4" Color="Color.Inherit">@_statistics.MediumRiskUsers</MudText>
5656
<MudText Typo="Typo.body2" Color="Color.Inherit">@L["Medium Risk"]</MudText>
@@ -60,7 +60,7 @@
6060

6161
<!-- High & Critical Risk -->
6262
<MudItem xs="12" sm="6" md="3">
63-
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); color: #333;" Elevation="4">
63+
<MudPaper Class="pa-4 text-center" Style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); color: #333;" >
6464
<MudIcon Icon="@Icons.Material.Filled.Error" Size="Size.Large" Color="Color.Error" Class="mb-2" />
6565
<MudText Typo="Typo.h4" Color="Color.Error">@(_statistics.HighRiskUsers + _statistics.CriticalRiskUsers)</MudText>
6666
<MudText Typo="Typo.body2" Color="Color.Error">@L["High Risk"]</MudText>

src/Server.UI/Components/Shared/Layout/AuthLayout.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@using CleanArchitecture.Blazor.Server.UI.Themes
1+
@using CleanArchitecture.Blazor.Server.UI.Themes
22
@using Microsoft.AspNetCore.Components.Authorization
33
@layout MainLayout
44
@inherits LayoutComponentBase
@@ -11,8 +11,8 @@
1111
<NotAuthorized>
1212
<MudContainer MaxWidth="MaxWidth.Small" Class="d-flex align-center" Style="height: 100vh;">
1313
<div class="d-flex flex-column mud-width-full">
14-
<MudPaper Elevation="25" Class="pa-8" Width="100%" MaxWidth="500px">
15-
<MudIcon Icon="@Icons.Custom.Brands.MudBlazor" Size="Size.Large" Style="width:100px; height:100px;" />
14+
<MudPaper Class="pa-8" Width="100%" MaxWidth="500px">
15+
<Logo Style="width:100px; height:100px;" />
1616
@Body
1717
</MudPaper>
1818
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@namespace CleanArchitecture.Blazor.Server.UI.Shared
2+
3+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1404 1404" class="@Class" style="@Style" role="img" aria-labelledby="logoTitle logoDesc">
4+
<title id="logoTitle">Brand Mark</title>
5+
<desc id="logoDesc">Refined solid logo based on the original paths</desc>
6+
<defs>
7+
<style>
8+
:root {
9+
--brand-primary: #6651ff;
10+
--brand-secondary: #4b39ff;
11+
}
12+
</style>
13+
</defs>
14+
15+
<path d="M406.89,219.14c-51.85,6.86-134.7-55.37-142.65-115.43-7.95-60.07,62.01-95.23,113.86-102.09,51.85-6.86,112.62,11.94,120.57,72.01,7.95,60.07-39.93,138.66-91.78,145.52Z" fill="var(--brand-primary)" />
16+
<path d="M1351.61,490.53c-29.26-77.07-70.13-149.81-121.87-214.05-34.85-43.28-74.24-83.06-118.5-116.66-51.13-38.82-107.18-74.24-169.52-89.6C659.86,.78,682.24,202.58,537.88,264.05c-144.35,61.47-316.15,4.62-409.08,131.03-38.73,52.69-76.68,109.42-100.97,170.37C5.41,621.7-2.93,684,1.05,744.27c7.77,117.64,64.46,245.62,162.39,314.92,34.64,24.51,91.9,55.27,131.4,25.76,19.29-14.41,31.2-37.27,39.96-59.15,25.29-63.2,31.63-134.4,35.72-201.73,4.09-67.39-8.86-285.66,4.07-323.91,10.1-29.89,34.98-51.3,65.12-59.55,37.46-10.25,84.85,1.44,112.4,28.99,11.98,11.98,21.72,26.39,29.24,43.17,7.49,16.78,16.01,38.08,25.62,63.86l55.76,156.52c4.8,13.19,9.9,26.68,15.31,40.45,5.38,13.81,11.24,26.42,17.55,37.79,6.28,11.4,12.88,20.69,19.76,27.9,6.89,7.17,13.96,10.79,21.14,10.79,5.99,0,12.01-3.17,18-9.45,5.99-6.31,11.85-14.7,17.55-25.21,5.7-10.47,11.37-22.61,17.07-36.42,5.7-13.8,11.24-28.47,16.65-44.07l60.28-162.83c8.39-22.77,16.33-42.57,23.83-59.35,7.5-16.78,16.21-30.59,26.07-41.38,9.9-10.79,21.75-18.9,35.55-24.31,13.77-5.38,31.48-8.07,53.07-8.07,16.78,0,31.32,1.63,43.62,4.93,12.3,3.3,22.32,9.77,30.14,19.34,14.5,17.77,17.58,45.82,20.66,68.01,6.54,46.97,1.82,95.87,1.82,143.32v272.45c0,23.37,1.14,47.05,0,70.39-.98,20.03-.76,40.4-10.45,58.74-8.84,16.71-25.19,30.07-43.97,32.23-24.29,2.79-43.71-15.61-52.61-36.6-4.2-9.9-7.05-19.79-8.55-29.69-1.5-9.9-2.24-17.84-2.24-23.83,0,0,10.01-267.01-33.46-261.48-8.83,1.12-28.92,49.45-34.66,61.45-30.1,60.21-107.26,230.27-122.13,251.82-12.03,17.43-28.81,35.72-50.55,39.92-15.19,2.94-29.82-2.71-41.65-12.12-29.45-23.43-42.28-66.81-56.1-100.93-11.3-27.91-84.23-310.38-138.19-317.77-7.14-.98-12.3,12.27-15.31,36.86-3.01,24.6-15.8,456.32,106.49,577.77,174.23,173.02,487.57,157.97,720.78-196.79,113.7-172.96,103.22-422.6,33.4-606.5Z" fill="var(--brand-primary)" />
17+
<path d="M369.84,537.14s-27.13,411.28-182.45,417.33c-116.75,4.55-168.93-122.4-176.64-144.99,20.77,97.3,72.69,193.09,152.7,249.7,34.64,24.51,91.9,55.26,131.4,25.76,19.29-14.41,31.2-37.27,39.96-59.15,25.29-63.2,31.63-134.4,35.72-201.73,3.34-55.09-4.69-210.9-.67-286.88v-.04Z" fill="var(--brand-secondary)" />
18+
</svg>
19+
20+
21+
@code
22+
{
23+
[Parameter] public string Style { get; set; } = string.Empty;
24+
[Parameter] public string Class { get; set; } = string.Empty;
25+
}

src/Server.UI/Components/Shared/Layout/MudBlazorLogo.razor

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/Server.UI/Components/Shared/Layout/NotificationMenu.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@using CleanArchitecture.Blazor.Server.UI.Services.Notifications
1+
@using CleanArchitecture.Blazor.Server.UI.Services.Notifications
22
@inherits MudComponentBase
33

44
@inject INotificationService NotificationService
@@ -26,7 +26,7 @@
2626
{
2727
<div class="d-flex justify-center align-center px-2 py-8 relative">
2828
<MudText Class="mud-text-secondary my-12">@L["Nothing new :("]</MudText>
29-
<MudBlazorLogo Class="docs-logo-filter mx-16 absolute" Style="filter: grayscale(1) opacity(.05);"/>
29+
<Logo Class="mx-16 absolute" Style="filter: grayscale(1) opacity(.05);"/>
3030
</div>
3131
}
3232
</MudMenu>

src/Server.UI/Components/Shared/Layout/TenantSelector.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@using CleanArchitecture.Blazor.Application.Common.Security
1+
@using CleanArchitecture.Blazor.Application.Common.Security
22
@using CleanArchitecture.Blazor.Application.Common.Interfaces.Identity
33
@using CleanArchitecture.Blazor.Application.Features.Tenants.DTOs
44
@using CleanArchitecture.Blazor.Application.Common.Interfaces
@@ -22,7 +22,7 @@
2222
}
2323
else
2424
{
25-
<MudIcon Class="ml-4 mr-2" Color="Color.Primary" Icon="@Icons.Custom.Brands.MudBlazor" Size="Size.Large" />
25+
<Logo Class="ml-4 mr-2" Style="width:32px;height32px" />
2626
}
2727

2828
<MudMenu AnchorOrigin="Origin.TopRight" TransformOrigin="Origin.BottomRight" LockScroll="true" Class="flex-grow-1"

0 commit comments

Comments
 (0)