Add user-specific persistent grid/band layouts support
Implemented user-customizable, persistent grid and band layouts for CatalogsGrid and MassDataGrid. Added backend API, database entity, and repository for storing layouts per user. Refactored grids to support dynamic band/column rendering, layout management UI, and per-user storage via localStorage and the new API. Registered all necessary services and updated data context. Enables flexible, user-specific grid experiences with saved layouts.
This commit is contained in:
94
DbFirst.API/Controllers/LayoutsController.cs
Normal file
94
DbFirst.API/Controllers/LayoutsController.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.Text;
|
||||
using DbFirst.Application.Repositories;
|
||||
using DbFirst.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DbFirst.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class LayoutsController : ControllerBase
|
||||
{
|
||||
private readonly ILayoutRepository _repository;
|
||||
|
||||
public LayoutsController(ILayoutRepository repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<LayoutDto>> Get([FromQuery] string layoutType, [FromQuery] string layoutKey, [FromQuery] string userName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(layoutType) || string.IsNullOrWhiteSpace(layoutKey) || string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
return BadRequest("layoutType, layoutKey und userName sind erforderlich.");
|
||||
}
|
||||
|
||||
var entity = await _repository.GetAsync(layoutType, layoutKey, userName, cancellationToken);
|
||||
if (entity == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Ok(Map(entity));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<LayoutDto>> Upsert(LayoutDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(dto.LayoutType) || string.IsNullOrWhiteSpace(dto.LayoutKey) || string.IsNullOrWhiteSpace(dto.UserName))
|
||||
{
|
||||
return BadRequest("LayoutType, LayoutKey und UserName sind erforderlich.");
|
||||
}
|
||||
|
||||
var data = string.IsNullOrWhiteSpace(dto.LayoutData)
|
||||
? Array.Empty<byte>()
|
||||
: Encoding.UTF8.GetBytes(dto.LayoutData);
|
||||
|
||||
try
|
||||
{
|
||||
var entity = await _repository.UpsertAsync(dto.LayoutType, dto.LayoutKey, dto.UserName, data, cancellationToken);
|
||||
return Ok(Map(entity));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var detail = ex.InnerException?.Message ?? ex.Message;
|
||||
return Problem(detail: detail, statusCode: StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> Delete([FromQuery] string layoutType, [FromQuery] string layoutKey, [FromQuery] string userName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(layoutType) || string.IsNullOrWhiteSpace(layoutKey) || string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
return BadRequest("layoutType, layoutKey und userName sind erforderlich.");
|
||||
}
|
||||
|
||||
var deleted = await _repository.DeleteAsync(layoutType, layoutKey, userName, cancellationToken);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
|
||||
private static LayoutDto Map(SmfLayout entity)
|
||||
{
|
||||
var layoutData = entity.LayoutData.Length == 0
|
||||
? string.Empty
|
||||
: Encoding.UTF8.GetString(entity.LayoutData);
|
||||
|
||||
return new LayoutDto
|
||||
{
|
||||
LayoutType = entity.LayoutType,
|
||||
LayoutKey = entity.LayoutKey,
|
||||
UserName = entity.UserName,
|
||||
LayoutData = layoutData
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class LayoutDto
|
||||
{
|
||||
public string LayoutType { get; set; } = string.Empty;
|
||||
public string LayoutKey { get; set; } = string.Empty;
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public string LayoutData { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user