feat(F2+T4.13): ChangeNetworkParent dialog + PackageFeature checkbox matrix
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 2m32s

F2: ChangeNetworkParent UI
- Add ChangeParentDialog with parent ID, leg, reason fields
- Add 'تغییر والد' button to UserNetworkInfo operations

T4.13: PackageFeature checkbox matrix
- Update NuGet to v0.0.188
- Add ClubFeature checkbox list to CreateDialog and UpdateDialog
- Load features via ConfigClient.GetClubFeaturesAsync
- Sync selected FeatureIds to proto request on save
This commit is contained in:
masoodafar-web
2026-02-26 22:00:20 +03:30
parent 8be98ae33e
commit e0203541bf
8 changed files with 258 additions and 1 deletions
+1 -1
View File
@@ -138,7 +138,7 @@
<!-- CMS Protobuf NuGet package (used for both local dev and Docker builds) -->
<ItemGroup>
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.187" />
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.188" />
</ItemGroup>
<!-- ============================================================ -->
@@ -0,0 +1,78 @@
@using CMSMicroservice.Protobuf.Protos.NetworkMembership
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.SwapHoriz" Class="ml-1" />
تغییر والد در شبکه
</MudText>
</TitleContent>
<DialogContent>
<MudAlert Severity="Severity.Warning" Dense="true" Class="mb-4">
⚠️ این عملیات حساس است و ساختار درخت شبکه را تغییر می‌دهد.
تاریخچه تغییر ثبت خواهد شد.
</MudAlert>
<MudForm @ref="_form">
<MudStack Spacing="3">
<MudTextField T="string"
Label="کاربر فعلی"
Value="@UserDisplayName"
ReadOnly="true"
Variant="Variant.Outlined"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Person" />
<MudNumericField T="long"
@bind-Value="_newParentId"
Label="شناسه والد جدید"
Required="true"
RequiredError="شناسه والد جدید الزامی است"
Variant="Variant.Outlined"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.PersonSearch"
Min="1" />
<MudSelect T="int"
@bind-Value="_newLeg"
Label="ساق جدید"
Required="true"
Variant="Variant.Outlined"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.AccountTree">
<MudSelectItem T="int" Value="0">چپ (تیم اول)</MudSelectItem>
<MudSelectItem T="int" Value="1">راست (تیم دوم)</MudSelectItem>
</MudSelect>
<MudTextField T="string"
@bind-Value="_reason"
Label="دلیل تغییر"
Required="true"
RequiredError="دلیل تغییر الزامی است"
Variant="Variant.Outlined"
Lines="3"
Placeholder="دلیل جابجایی کاربر در شبکه را وارد کنید..."
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Description" />
</MudStack>
</MudForm>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel" Color="Color.Default">انصراف</MudButton>
<MudButton OnClick="Submit"
Color="Color.Error"
Variant="Variant.Filled"
Disabled="_isSubmitting"
StartIcon="@Icons.Material.Filled.SwapHoriz">
@if (_isSubmitting)
{
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="ml-2" />
<span>در حال انجام...</span>
}
else
{
<span>تغییر والد</span>
}
</MudButton>
</DialogActions>
</MudDialog>
@@ -0,0 +1,66 @@
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace BackOffice.Pages.Network.Components;
public partial class ChangeParentDialog
{
[Parameter] public long UserId { get; set; }
[Parameter] public string UserDisplayName { get; set; } = "";
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
[Inject] public NetworkMembershipContract.NetworkMembershipContractClient NetworkContract { get; set; } = default!;
private MudForm _form = default!;
private long _newParentId;
private int _newLeg;
private string _reason = "";
private bool _isSubmitting;
private async Task Submit()
{
await _form.Validate();
if (!_form.IsValid)
return;
if (_newParentId == UserId)
{
Snackbar.Add("والد جدید نمی‌تواند خود کاربر باشد.", Severity.Error);
return;
}
_isSubmitting = true;
StateHasChanged();
try
{
var request = new ChangeNetworkParentRequest
{
UserId = UserId,
NewParentId = _newParentId,
NewLeg = _newLeg,
Reason = _reason
};
await NetworkContract.ChangeNetworkParentAsync(request);
Snackbar.Add("والد کاربر با موفقیت تغییر کرد.", Severity.Success);
MudDialog.Close(DialogResult.Ok(true));
}
catch (Grpc.Core.RpcException ex)
{
Snackbar.Add($"خطا: {ex.Status.Detail}", Severity.Error);
}
catch (Exception ex)
{
Snackbar.Add($"خطا در تغییر والد: {ex.Message}", Severity.Error);
}
finally
{
_isSubmitting = false;
StateHasChanged();
}
}
private void Cancel() => MudDialog.Cancel();
}
@@ -434,6 +434,12 @@
OnClick="@(() => NavigationManager.NavigateTo($"/commission/payouts?userId={UserId}"))">
پرداخت‌های کاربر
</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Warning"
StartIcon="@Icons.Material.Filled.SwapHoriz"
OnClick="OpenChangeParentDialog">
تغییر والد
</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Secondary"
StartIcon="@Icons.Material.Filled.Refresh"
@@ -537,4 +543,28 @@
_ => "نامشخص"
};
}
private async Task OpenChangeParentDialog()
{
var displayName = $"{_userInfo.UserName} (ID: {UserId})";
var parameters = new DialogParameters<Network.Components.ChangeParentDialog>
{
{ x => x.UserId, UserId },
{ x => x.UserDisplayName, displayName }
};
var options = new DialogOptions
{
MaxWidth = MaxWidth.Small,
FullWidth = true,
CloseOnEscapeKey = true
};
var dialog = await DialogService.ShowAsync<Network.Components.ChangeParentDialog>("تغییر والد شبکه", parameters, options);
var result = await dialog.Result;
if (result is { Canceled: false })
{
await LoadUserInfo();
await LoadNetworkHistory();
}
}
}
@@ -1,4 +1,5 @@
@using CMSMicroservice.Protobuf.Protos.Package
@using CMSMicroservice.Protobuf.Protos.Configuration
@using BackOffice.Common.BaseComponents
@using Microsoft.AspNetCore.Components.Forms
@using Tizzani.MudBlazor.HtmlEditor
@@ -93,6 +94,22 @@
</MudItem>
</MudStack>
@if (_features.Any())
{
<MudText Typo="Typo.subtitle1" Class="mt-4 mb-2"><strong>ویژگی‌های پکیج</strong></MudText>
<MudStack Row="true" Wrap="Wrap.Wrap">
@foreach (var feature in _features)
{
<MudCheckBox T="bool"
Value="@(_selectedFeatureIds.Contains(feature.Id))"
ValueChanged="@((bool v) => ToggleFeature(feature.Id, v))"
Disabled="_isLoading"
Label="@feature.Title"
Color="Color.Primary" />
}
</MudStack>
}
<MudItem xs="12">
<MudHtmlEditor @bind-Html="Model.Description" MinHeight="300px">
<MudHtmlToolbarOptions InsertImage="false" />
File diff suppressed because one or more lines are too long
@@ -1,4 +1,5 @@
@using CMSMicroservice.Protobuf.Protos.Package
@using CMSMicroservice.Protobuf.Protos.Configuration
@using BackOffice.Common.BaseComponents
@using Microsoft.AspNetCore.Components.Forms
@using Tizzani.MudBlazor.HtmlEditor
@@ -94,6 +95,22 @@
</MudItem>
</MudStack>
@if (_features.Any())
{
<MudText Typo="Typo.subtitle1" Class="mt-4 mb-2"><strong>ویژگی‌های پکیج</strong></MudText>
<MudStack Row="true" Wrap="Wrap.Wrap">
@foreach (var feature in _features)
{
<MudCheckBox T="bool"
Value="@(_selectedFeatureIds.Contains(feature.Id))"
ValueChanged="@((bool v) => ToggleFeature(feature.Id, v))"
Disabled="_isLoading"
Label="@feature.Title"
Color="Color.Primary" />
}
</MudStack>
}
<MudItem xs="12">
<MudHtmlEditor @bind-Html="Model.Description" MinHeight="300px">
<MudHtmlToolbarOptions InsertImage="false" />
File diff suppressed because one or more lines are too long