Skip to content

Commit a21f7e6

Browse files
committed
Migrate LrmCloud.Web from MudBlazor to Radzen Blazor
- Replace all MudBlazor components with Radzen equivalents - Update MainLayout with RadzenProfileMenu and proper Click handling - Add RadzenTheme to AuthLayout for consistent theming - Fix editor grid UX: row click opens side panel, checkboxes for multi-select - Remove duplicate icons from RadzenAlert components - Update CSS from .mud-* to .rz-* selectors - Add profile menu width fixes and theme dropdown layout - Add new dialog components for various operations
1 parent d123345 commit a21f7e6

78 files changed

Lines changed: 10295 additions & 11842 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cloud/src/LrmCloud.Shared/Constants/OrganizationRole.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,19 @@ public static bool IsValid(string role)
4141
/// <summary>
4242
/// Check if a role has admin privileges (owner or admin)
4343
/// </summary>
44-
public static bool IsAdminOrOwner(string role)
44+
public static bool IsAdminOrOwner(string? role)
4545
{
46-
return role == Owner || role == Admin;
46+
if (string.IsNullOrEmpty(role)) return false;
47+
return string.Equals(role, Owner, StringComparison.OrdinalIgnoreCase) ||
48+
string.Equals(role, Admin, StringComparison.OrdinalIgnoreCase);
4749
}
4850

4951
/// <summary>
5052
/// Check if a role is owner
5153
/// </summary>
52-
public static bool IsOwner(string role)
54+
public static bool IsOwner(string? role)
5355
{
54-
return role == Owner;
56+
if (string.IsNullOrEmpty(role)) return false;
57+
return string.Equals(role, Owner, StringComparison.OrdinalIgnoreCase);
5558
}
5659
}

cloud/src/LrmCloud.Web/App.razor

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@
66
<RedirectToLogin />
77
</NotAuthorized>
88
<Authorizing>
9-
<MudContainer Class="d-flex align-center justify-center" Style="min-height: 100vh;">
10-
<MudStack AlignItems="AlignItems.Center" Spacing="4">
11-
<MudProgressCircular Size="Size.Large" Indeterminate="true" />
12-
<MudText>Loading...</MudText>
13-
</MudStack>
14-
</MudContainer>
9+
<div style="min-height: 100vh; display: flex; align-items: center; justify-content: center;">
10+
<RadzenStack AlignItems="Radzen.AlignItems.Center" Gap="1rem">
11+
<RadzenProgressBarCircular ShowValue="false" Mode="ProgressBarMode.Indeterminate" Size="ProgressBarCircularSize.Large" />
12+
<RadzenText>Loading...</RadzenText>
13+
</RadzenStack>
14+
</div>
1515
</Authorizing>
1616
</AuthorizeRouteView>
1717
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
1818
</Found>
1919
<NotFound>
2020
<PageTitle>Not found</PageTitle>
2121
<LayoutView Layout="@typeof(MainLayout)">
22-
<MudContainer Class="mt-16">
23-
<MudText Typo="Typo.h3" Align="Align.Center" GutterBottom="true">404 - Not Found</MudText>
24-
<MudText Align="Align.Center">Sorry, there's nothing at this address.</MudText>
25-
<MudStack Row="true" Justify="Justify.Center" Class="mt-4">
26-
<MudButton Variant="Variant.Filled" Color="Color.Primary" Href="">Go Home</MudButton>
27-
</MudStack>
28-
</MudContainer>
22+
<div style="margin-top: 4rem;">
23+
<RadzenText TextStyle="TextStyle.H3" TextAlign="TextAlign.Center" class="rz-mb-4">404 - Not Found</RadzenText>
24+
<RadzenText TextAlign="TextAlign.Center">Sorry, there's nothing at this address.</RadzenText>
25+
<RadzenStack Orientation="Radzen.Orientation.Horizontal" JustifyContent="JustifyContent.Center" class="rz-mt-4">
26+
<RadzenButton Variant="Radzen.Variant.Filled" ButtonStyle="ButtonStyle.Primary" Text="Go Home" Click="@(() => { })" />
27+
</RadzenStack>
28+
</div>
2929
</LayoutView>
3030
</NotFound>
3131
</Router>

cloud/src/LrmCloud.Web/Components/AddKeyDialog.razor

Lines changed: 63 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,68 @@
11
@inject ResourceService ResourceService
2-
@inject ISnackbar Snackbar
3-
4-
<MudDialog @bind-Visible="_visible" Options="_dialogOptions">
5-
<TitleContent>
6-
<MudText Typo="Typo.h6">
7-
<MudIcon Icon="@Icons.Material.Filled.Add" Class="mr-2" />
8-
Add New Key
9-
</MudText>
10-
</TitleContent>
11-
<DialogContent>
12-
<EditForm Model="_model" OnValidSubmit="HandleSubmit">
13-
<DataAnnotationsValidator />
14-
<MudStack Spacing="3">
15-
<MudTextField @bind-Value="_model.KeyName"
16-
Label="Key Name"
17-
Variant="Variant.Outlined"
18-
For="@(() => _model.KeyName)"
19-
Disabled="_isSubmitting"
20-
Required="true"
21-
HelperText="e.g., WelcomeMessage, Error.NotFound, Button.Save" />
22-
23-
<MudTextField @bind-Value="_model.Comment"
24-
Label="Comment (optional)"
25-
Variant="Variant.Outlined"
26-
Lines="2"
27-
For="@(() => _model.Comment)"
28-
Disabled="_isSubmitting"
29-
HelperText="Description to help translators" />
30-
31-
<MudSwitch @bind-Value="_model.IsPlural"
32-
Label="Plural key"
33-
Color="Color.Primary"
34-
Disabled="_isSubmitting" />
35-
36-
@if (_model.IsPlural)
37-
{
38-
<MudAlert Severity="Severity.Info" Dense="true">
39-
Plural keys support different forms for quantities (zero, one, few, many, other).
40-
</MudAlert>
41-
}
42-
43-
<MudTextField @bind-Value="_defaultValue"
44-
Label="Default Value"
45-
Variant="Variant.Outlined"
46-
Lines="2"
47-
Disabled="_isSubmitting"
48-
HelperText="Value for the default language" />
49-
50-
@if (!string.IsNullOrEmpty(_errorMessage))
51-
{
52-
<MudAlert Severity="Severity.Error" Dense="true">@_errorMessage</MudAlert>
53-
}
54-
</MudStack>
55-
</EditForm>
56-
</DialogContent>
57-
<DialogActions>
58-
<MudButton OnClick="Close" Disabled="_isSubmitting">Cancel</MudButton>
59-
<MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="HandleSubmit" Disabled="_isSubmitting">
60-
@if (_isSubmitting)
2+
@inject NotificationService NotificationService
3+
@inject Radzen.DialogService DialogService
4+
5+
<RadzenStack Gap="1rem">
6+
<RadzenTemplateForm TItem="CreateResourceKeyRequest" Data="_model" Submit="HandleSubmit">
7+
<RadzenStack Gap="1rem">
8+
<RadzenFormField Text="Key Name" Variant="Radzen.Variant.Outlined" Style="width: 100%;">
9+
<ChildContent>
10+
<RadzenTextBox @bind-Value="_model.KeyName" Placeholder="e.g., WelcomeMessage, Error.NotFound, Button.Save"
11+
Disabled="@_isSubmitting" Style="width: 100%;" Name="KeyName" />
12+
</ChildContent>
13+
<Helper>
14+
<RadzenText TextStyle="TextStyle.Caption" class="rz-color-secondary">e.g., WelcomeMessage, Error.NotFound, Button.Save</RadzenText>
15+
</Helper>
16+
</RadzenFormField>
17+
18+
<RadzenFormField Text="Comment (optional)" Variant="Radzen.Variant.Outlined" Style="width: 100%;">
19+
<ChildContent>
20+
<RadzenTextArea @bind-Value="_model.Comment" Placeholder="Description to help translators"
21+
Rows="2" Disabled="@_isSubmitting" Style="width: 100%;" />
22+
</ChildContent>
23+
<Helper>
24+
<RadzenText TextStyle="TextStyle.Caption" class="rz-color-secondary">Description to help translators</RadzenText>
25+
</Helper>
26+
</RadzenFormField>
27+
28+
<RadzenSwitch @bind-Value="_model.IsPlural" Disabled="@_isSubmitting">
29+
<Template>
30+
<RadzenText>Plural key</RadzenText>
31+
</Template>
32+
</RadzenSwitch>
33+
34+
@if (_model.IsPlural)
6135
{
62-
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
63-
<MudText Class="ms-2">Creating...</MudText>
36+
<RadzenAlert AlertStyle="AlertStyle.Info" Shade="Shade.Lighter" AllowClose="false" Size="AlertSize.Small">
37+
Plural keys support different forms for quantities (zero, one, few, many, other).
38+
</RadzenAlert>
6439
}
65-
else
40+
41+
<RadzenFormField Text="Default Value" Variant="Radzen.Variant.Outlined" Style="width: 100%;">
42+
<ChildContent>
43+
<RadzenTextArea @bind-Value="_defaultValue" Placeholder="Value for the default language"
44+
Rows="2" Disabled="@_isSubmitting" Style="width: 100%;" />
45+
</ChildContent>
46+
<Helper>
47+
<RadzenText TextStyle="TextStyle.Caption" class="rz-color-secondary">Value for the default language</RadzenText>
48+
</Helper>
49+
</RadzenFormField>
50+
51+
@if (!string.IsNullOrEmpty(_errorMessage))
6652
{
67-
<MudText>Add Key</MudText>
53+
<RadzenAlert AlertStyle="AlertStyle.Danger" Shade="Shade.Lighter" AllowClose="false" Size="AlertSize.Small">
54+
@_errorMessage
55+
</RadzenAlert>
6856
}
69-
</MudButton>
70-
</DialogActions>
71-
</MudDialog>
57+
</RadzenStack>
58+
</RadzenTemplateForm>
59+
60+
<RadzenStack Orientation="Radzen.Orientation.Horizontal" JustifyContent="JustifyContent.End" Gap="0.5rem">
61+
<RadzenButton Variant="Radzen.Variant.Text" Text="Cancel" Click="@Close" Disabled="@_isSubmitting" />
62+
<RadzenButton ButtonStyle="ButtonStyle.Primary" Text="@(_isSubmitting ? "Creating..." : "Add Key")"
63+
Click="@HandleSubmit" Disabled="@_isSubmitting" IsBusy="@_isSubmitting" />
64+
</RadzenStack>
65+
</RadzenStack>
7266

7367
@code {
7468
[Parameter]
@@ -77,31 +71,14 @@
7771
[Parameter]
7872
public EventCallback<ResourceKeyDto> OnKeyAdded { get; set; }
7973

80-
private bool _visible;
8174
private bool _isSubmitting;
8275
private string? _errorMessage;
8376
private string _defaultValue = string.Empty;
8477
private CreateResourceKeyRequest _model = new() { KeyName = "" };
8578

86-
private readonly DialogOptions _dialogOptions = new()
87-
{
88-
MaxWidth = MaxWidth.Small,
89-
FullWidth = true,
90-
CloseOnEscapeKey = true
91-
};
92-
93-
public void Open()
94-
{
95-
_model = new CreateResourceKeyRequest { KeyName = "" };
96-
_defaultValue = string.Empty;
97-
_errorMessage = null;
98-
_visible = true;
99-
StateHasChanged();
100-
}
101-
10279
private void Close()
10380
{
104-
_visible = false;
81+
DialogService.Close(null);
10582
}
10683

10784
private async Task HandleSubmit()
@@ -127,9 +104,9 @@
127104

128105
if (result.IsSuccess && result.Data != null)
129106
{
130-
Snackbar.Add($"Key '{result.Data.KeyName}' created successfully!", Severity.Success);
107+
NotificationService.Notify(NotificationSeverity.Success, "Success", $"Key '{result.Data.KeyName}' created successfully!");
131108
await OnKeyAdded.InvokeAsync(result.Data);
132-
Close();
109+
DialogService.Close(result.Data);
133110
}
134111
else
135112
{
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
@using LrmCloud.Shared.Constants
2+
@using LrmCloud.Shared.DTOs.Organizations
3+
@inject OrganizationService OrganizationService
4+
@inject NotificationService NotificationService
5+
@inject Radzen.DialogService DialogService
6+
7+
<RadzenStack Gap="1rem">
8+
<RadzenText>
9+
Change role for <strong>@(Member.DisplayName ?? Member.Email)</strong>
10+
</RadzenText>
11+
12+
<RadzenFormField Text="Role" Variant="Radzen.Variant.Outlined">
13+
<ChildContent>
14+
<RadzenDropDown @bind-Value="_newRole"
15+
Data="@_roles"
16+
TextProperty="Text"
17+
ValueProperty="Value"
18+
Disabled="@_isSubmitting"
19+
Style="width: 100%;" />
20+
</ChildContent>
21+
<Helper>
22+
<RadzenText TextStyle="TextStyle.Caption" class="rz-color-secondary">@GetRoleDescription(_newRole)</RadzenText>
23+
</Helper>
24+
</RadzenFormField>
25+
26+
@if (!string.IsNullOrEmpty(_errorMessage))
27+
{
28+
<RadzenAlert AlertStyle="AlertStyle.Danger" Shade="Shade.Lighter" AllowClose="false">
29+
@_errorMessage
30+
</RadzenAlert>
31+
}
32+
33+
<RadzenStack Orientation="Radzen.Orientation.Horizontal" JustifyContent="JustifyContent.End" Gap="0.5rem" class="rz-mt-4">
34+
<RadzenButton Variant="Radzen.Variant.Text" Text="Cancel" Click="@Cancel" Disabled="@_isSubmitting" />
35+
<RadzenButton ButtonStyle="ButtonStyle.Primary" Text="Update Role" Click="@ChangeRole" Disabled="@(_isSubmitting || _newRole == Member.Role)" IsBusy="@_isSubmitting" />
36+
</RadzenStack>
37+
</RadzenStack>
38+
39+
@code {
40+
[Parameter]
41+
public int OrganizationId { get; set; }
42+
43+
[Parameter]
44+
public OrganizationMemberDto Member { get; set; } = null!;
45+
46+
private string _newRole = OrganizationRole.Member;
47+
private bool _isSubmitting;
48+
private string? _errorMessage;
49+
50+
private readonly List<object> _roles = new()
51+
{
52+
new { Text = "Admin", Value = OrganizationRole.Admin },
53+
new { Text = "Member", Value = OrganizationRole.Member },
54+
new { Text = "Viewer", Value = OrganizationRole.Viewer }
55+
};
56+
57+
protected override void OnInitialized()
58+
{
59+
_newRole = Member.Role;
60+
}
61+
62+
private async Task ChangeRole()
63+
{
64+
_isSubmitting = true;
65+
_errorMessage = null;
66+
67+
try
68+
{
69+
var (success, error) = await OrganizationService.UpdateMemberRoleAsync(
70+
OrganizationId, Member.UserId, _newRole);
71+
72+
if (success)
73+
{
74+
NotificationService.Notify(NotificationSeverity.Success, "Success", "Role updated successfully");
75+
DialogService.Close(_newRole);
76+
}
77+
else
78+
{
79+
_errorMessage = error ?? "Failed to update role";
80+
}
81+
}
82+
catch (Exception ex)
83+
{
84+
_errorMessage = $"An error occurred: {ex.Message}";
85+
}
86+
finally
87+
{
88+
_isSubmitting = false;
89+
}
90+
}
91+
92+
private void Cancel()
93+
{
94+
DialogService.Close(null);
95+
}
96+
97+
private static string GetRoleDescription(string role) => role switch
98+
{
99+
OrganizationRole.Admin => "Can manage members, projects, and settings",
100+
OrganizationRole.Member => "Can view and edit projects",
101+
OrganizationRole.Viewer => "Read-only access to projects",
102+
_ => ""
103+
};
104+
}

0 commit comments

Comments
 (0)