[CLAUDE] Api+App: Chunk B — PATCH /menus/{key} + DTO extend isVisible/displayLabel
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m49s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m49s
Session 20 turn 7 Chunk B. BE API cho admin Ẩn/Hiện + Đổi tên menu fe-user.
DTO (MenuDtos.cs):
- MenuNodeDto +IsVisible bool +DisplayLabel string?
- MenuItemDto +IsVisible bool +DisplayLabel string?
GetMyMenuTreeQueryHandler:
- Pass m.IsVisible + m.DisplayLabel vào MenuNodeDto record
- KHÔNG filter IsVisible server-side (FE 2 app tự filter — fe-admin
render hết, fe-user filter ẩn). Lý do: 1 endpoint serve cả 2 FE.
ListMenuItemsQueryHandler: +IsVisible +DisplayLabel trong Select projection.
NEW UpdateMenuItemCommand + Validator + Handler (PermissionFeatures.cs):
- Body: { Key, IsVisible, DisplayLabel? }
- Validator: Key required + max 50, DisplayLabel max 200
- Handler: load MenuItem by Key (NotFoundException nếu missing), set
IsVisible + DisplayLabel (whitespace → null normalize), SaveChangesAsync
MenusController +PATCH /api/menus/{key}:
- [Authorize(Policy = "Permissions.Update")] — reuse policy admin matrix
- Body: UpdateMenuItemRequest { IsVisible, DisplayLabel? }
- Send UpdateMenuItemCommand qua MediatR
- Return 204 NoContent
Verify:
- dotnet build SolutionErp.slnx — 0 err (1 warn cũ DocxRenderer không liên quan)
Pending Chunk C: FE Admin MenuVisibilityPage
Pending Chunk D: FE Layout fe-user filter + render displayLabel
Pending Chunk E: Docs S20 turn 7
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -19,4 +19,17 @@ public class MenusController(IMediator mediator) : ControllerBase
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<List<MenuItemDto>>> List(CancellationToken ct)
|
public async Task<ActionResult<List<MenuItemDto>>> List(CancellationToken ct)
|
||||||
=> Ok(await mediator.Send(new ListMenuItemsQuery(), ct));
|
=> Ok(await mediator.Send(new ListMenuItemsQuery(), ct));
|
||||||
|
|
||||||
|
// [Mig 27] Admin Ẩn/Hiện + Đổi tên hiển thị menu cho fe-user. Body shape khớp
|
||||||
|
// UpdateMenuItemCommand. Authorize policy "Permissions.Update" (admin matrix
|
||||||
|
// quản lý phân quyền — cùng scope).
|
||||||
|
public record UpdateMenuItemRequest(bool IsVisible, string? DisplayLabel);
|
||||||
|
|
||||||
|
[HttpPatch("{key}")]
|
||||||
|
[Authorize(Policy = "Permissions.Update")]
|
||||||
|
public async Task<IActionResult> Update(string key, [FromBody] UpdateMenuItemRequest body, CancellationToken ct)
|
||||||
|
{
|
||||||
|
await mediator.Send(new UpdateMenuItemCommand(key, body.IsVisible, body.DisplayLabel), ct);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,8 @@ public record MenuNodeDto(
|
|||||||
bool CanCreate,
|
bool CanCreate,
|
||||||
bool CanUpdate,
|
bool CanUpdate,
|
||||||
bool CanDelete,
|
bool CanDelete,
|
||||||
|
bool IsVisible, // [Mig 27] admin ẩn menu cho fe-user; fe-admin ignore filter này
|
||||||
|
string? DisplayLabel, // [Mig 27] override label cho fe-user; fe-admin luôn render Label gốc
|
||||||
List<MenuNodeDto> Children);
|
List<MenuNodeDto> Children);
|
||||||
|
|
||||||
public record PermissionDto(
|
public record PermissionDto(
|
||||||
@ -33,4 +35,6 @@ public record MenuItemDto(
|
|||||||
string Label,
|
string Label,
|
||||||
string? ParentKey,
|
string? ParentKey,
|
||||||
int Order,
|
int Order,
|
||||||
string? Icon);
|
string? Icon,
|
||||||
|
bool IsVisible,
|
||||||
|
string? DisplayLabel);
|
||||||
|
|||||||
@ -19,11 +19,44 @@ public class ListMenuItemsQueryHandler(IApplicationDbContext db) : IRequestHandl
|
|||||||
{
|
{
|
||||||
return await db.MenuItems.AsNoTracking()
|
return await db.MenuItems.AsNoTracking()
|
||||||
.OrderBy(m => m.Order)
|
.OrderBy(m => m.Order)
|
||||||
.Select(m => new MenuItemDto(m.Key, m.Label, m.ParentKey, m.Order, m.Icon))
|
.Select(m => new MenuItemDto(m.Key, m.Label, m.ParentKey, m.Order, m.Icon, m.IsVisible, m.DisplayLabel))
|
||||||
.ToListAsync(ct);
|
.ToListAsync(ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== Update menu visibility + display label (admin only) ==========
|
||||||
|
// Session 20 Mig 27: admin Ẩn/Hiện + Đổi tên hiển thị menu cho fe-user (eOffice).
|
||||||
|
// fe-admin sidebar luôn render Label gốc (KHÔNG dùng DisplayLabel) — user Q2=b.
|
||||||
|
public record UpdateMenuItemCommand(
|
||||||
|
string Key,
|
||||||
|
bool IsVisible,
|
||||||
|
string? DisplayLabel) : IRequest;
|
||||||
|
|
||||||
|
public class UpdateMenuItemCommandValidator : AbstractValidator<UpdateMenuItemCommand>
|
||||||
|
{
|
||||||
|
public UpdateMenuItemCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Key).NotEmpty().MaximumLength(50);
|
||||||
|
RuleFor(x => x.DisplayLabel).MaximumLength(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateMenuItemCommandHandler(IApplicationDbContext db) : IRequestHandler<UpdateMenuItemCommand>
|
||||||
|
{
|
||||||
|
public async Task Handle(UpdateMenuItemCommand request, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var menu = await db.MenuItems.FirstOrDefaultAsync(m => m.Key == request.Key, ct)
|
||||||
|
?? throw new NotFoundException("MenuItem", request.Key);
|
||||||
|
|
||||||
|
menu.IsVisible = request.IsVisible;
|
||||||
|
menu.DisplayLabel = string.IsNullOrWhiteSpace(request.DisplayLabel)
|
||||||
|
? null
|
||||||
|
: request.DisplayLabel.Trim();
|
||||||
|
|
||||||
|
await db.SaveChangesAsync(ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ========== List permissions by role (matrix edit) ==========
|
// ========== List permissions by role (matrix edit) ==========
|
||||||
|
|
||||||
public record ListPermissionsByRoleQuery(Guid RoleId) : IRequest<List<PermissionDto>>;
|
public record ListPermissionsByRoleQuery(Guid RoleId) : IRequest<List<PermissionDto>>;
|
||||||
|
|||||||
@ -85,6 +85,7 @@ public class GetMyMenuTreeQueryHandler(
|
|||||||
|
|
||||||
return new MenuNodeDto(m.Key, m.Label, m.ParentKey, m.Order, m.Icon,
|
return new MenuNodeDto(m.Key, m.Label, m.ParentKey, m.Order, m.Icon,
|
||||||
flags.Item1, flags.Item2, flags.Item3, flags.Item4,
|
flags.Item1, flags.Item2, flags.Item3, flags.Item4,
|
||||||
|
m.IsVisible, m.DisplayLabel,
|
||||||
BuildChildren(m.Key, nextInherit));
|
BuildChildren(m.Key, nextInherit));
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|||||||
Reference in New Issue
Block a user