mirror of https://github.com/ErsatzTV/ErsatzTV.git
25 changed files with 261 additions and 26 deletions
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.Libraries |
||||||
|
{ |
||||||
|
public record LocalLibraryPathViewModel(int Id, string Path); |
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.Libraries |
||||||
|
{ |
||||||
|
public record LocalLibraryViewModel(int Id, string Name, string MediaKind); |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
using ErsatzTV.Core.Domain; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Libraries |
||||||
|
{ |
||||||
|
internal static class Mapper |
||||||
|
{ |
||||||
|
public static LocalLibraryViewModel ProjectToViewModel(LocalLibrary library) => |
||||||
|
new(library.Id, library.Name, library.MediaKind.ToString()); |
||||||
|
|
||||||
|
public static LocalLibraryPathViewModel ProjectToViewModel(LibraryPath libraryPath) => |
||||||
|
new(libraryPath.Id, libraryPath.Path); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using MediatR; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Libraries.Queries |
||||||
|
{ |
||||||
|
public record GetLocalLibraries : IRequest<List<LocalLibraryViewModel>>; |
||||||
|
} |
||||||
@ -0,0 +1,22 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ErsatzTV.Core.Interfaces.Repositories; |
||||||
|
using LanguageExt; |
||||||
|
using MediatR; |
||||||
|
using static ErsatzTV.Application.Libraries.Mapper; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Libraries.Queries |
||||||
|
{ |
||||||
|
public class GetLocalLibrariesHandler : IRequestHandler<GetLocalLibraries, List<LocalLibraryViewModel>> |
||||||
|
{ |
||||||
|
private readonly ILibraryRepository _libraryRepository; |
||||||
|
|
||||||
|
public GetLocalLibrariesHandler(ILibraryRepository libraryRepository) => _libraryRepository = libraryRepository; |
||||||
|
|
||||||
|
public Task<List<LocalLibraryViewModel>> |
||||||
|
Handle(GetLocalLibraries request, CancellationToken cancellationToken) => |
||||||
|
_libraryRepository.GetAllLocal().Map(list => list.Map(ProjectToViewModel).ToList()); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using MediatR; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Libraries.Queries |
||||||
|
{ |
||||||
|
public record GetLocalLibraryPaths(int LocalLibraryId) : IRequest<List<LocalLibraryPathViewModel>>; |
||||||
|
} |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ErsatzTV.Core.Interfaces.Repositories; |
||||||
|
using LanguageExt; |
||||||
|
using MediatR; |
||||||
|
using static ErsatzTV.Application.Libraries.Mapper; |
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Libraries.Queries |
||||||
|
{ |
||||||
|
public class GetLocalLibraryPathsHandler : IRequestHandler<GetLocalLibraryPaths, List<LocalLibraryPathViewModel>> |
||||||
|
{ |
||||||
|
private readonly ILibraryRepository _libraryRepository; |
||||||
|
|
||||||
|
public GetLocalLibraryPathsHandler(ILibraryRepository libraryRepository) => |
||||||
|
_libraryRepository = libraryRepository; |
||||||
|
|
||||||
|
public Task<List<LocalLibraryPathViewModel>> Handle( |
||||||
|
GetLocalLibraryPaths request, |
||||||
|
CancellationToken cancellationToken) => |
||||||
|
_libraryRepository.GetLocalPaths(request.LocalLibraryId) |
||||||
|
.Map(list => list.Map(ProjectToViewModel).ToList()); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,82 @@ |
|||||||
|
@page "/media/libraries" |
||||||
|
@using ErsatzTV.Application.Libraries |
||||||
|
@using ErsatzTV.Application.Libraries.Queries |
||||||
|
@implements IDisposable |
||||||
|
@inject IMediator Mediator |
||||||
|
@inject IEntityLocker Locker |
||||||
|
|
||||||
|
<MudContainer MaxWidth="MaxWidth.ExtraLarge"> |
||||||
|
<MudTable Hover="true" Items="_libraries" Dense="true"> |
||||||
|
<ToolBarContent> |
||||||
|
<MudText Typo="Typo.h6">Libraries</MudText> |
||||||
|
</ToolBarContent> |
||||||
|
<ColGroup> |
||||||
|
<col/> |
||||||
|
<col/> |
||||||
|
<col/> |
||||||
|
<col style="width: 120px;"/> |
||||||
|
</ColGroup> |
||||||
|
<HeaderContent> |
||||||
|
<MudTh>Library Kind</MudTh> |
||||||
|
<MudTh>Name</MudTh> |
||||||
|
<MudTh>Media Kind</MudTh> |
||||||
|
<MudTh/> |
||||||
|
</HeaderContent> |
||||||
|
<RowTemplate> |
||||||
|
<MudTd DataLabel="Library Kind">Local</MudTd> |
||||||
|
<MudTd DataLabel="Name">@context.Name</MudTd> |
||||||
|
<MudTd DataLabel="Media Kind">@context.MediaKind</MudTd> |
||||||
|
<MudTd> |
||||||
|
<div style="align-items: center; display: flex;"> |
||||||
|
@if (Locker.IsLibraryLocked(context.Id)) |
||||||
|
{ |
||||||
|
<div style="align-items: center; display: flex; height: 48px; justify-content: center; width: 48px;"> |
||||||
|
<MudProgressCircular Color="Color.Primary" Size="Size.Small" Indeterminate="true"/> |
||||||
|
</div> |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
<MudTooltip Text="Scan Library"> |
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Refresh" |
||||||
|
Disabled="@Locker.IsLibraryLocked(context.Id)" |
||||||
|
OnClick="@(_ => ScanLibrary(context))"> |
||||||
|
</MudIconButton> |
||||||
|
</MudTooltip> |
||||||
|
} |
||||||
|
@if (context is LocalLibraryViewModel) |
||||||
|
{ |
||||||
|
<MudTooltip Text="Edit Library"> |
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Edit" |
||||||
|
Disabled="@Locker.IsLibraryLocked(context.Id)" |
||||||
|
Link="@($"/media/libraries/local/{context.Id}")"> |
||||||
|
</MudIconButton> |
||||||
|
</MudTooltip> |
||||||
|
} |
||||||
|
</div> |
||||||
|
</MudTd> |
||||||
|
</RowTemplate> |
||||||
|
</MudTable> |
||||||
|
</MudContainer> |
||||||
|
|
||||||
|
@code { |
||||||
|
private IList<LocalLibraryViewModel> _libraries; |
||||||
|
|
||||||
|
protected override void OnInitialized() => |
||||||
|
Locker.OnLibraryChanged += LockChanged; |
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() => await LoadLibraries(); |
||||||
|
|
||||||
|
private async Task LoadLibraries() => |
||||||
|
_libraries = await Mediator.Send(new GetLocalLibraries()); |
||||||
|
|
||||||
|
private Task ScanLibrary(LocalLibraryViewModel library) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
private void LockChanged(object sender, EventArgs e) => |
||||||
|
InvokeAsync(StateHasChanged); |
||||||
|
|
||||||
|
void IDisposable.Dispose() => Locker.OnLibraryChanged -= LockChanged; |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
@page "/media/libraries/local/{Id:int}" |
||||||
|
@using ErsatzTV.Application.Libraries |
||||||
|
@using ErsatzTV.Application.Libraries.Queries |
||||||
|
@inject IMediator Mediator |
||||||
|
|
||||||
|
<MudContainer MaxWidth="MaxWidth.ExtraLarge"> |
||||||
|
<MudTable Hover="true" Items="_libraryPaths" Dense="true"> |
||||||
|
<ToolBarContent> |
||||||
|
<MudText Typo="Typo.h6">Library Paths</MudText> |
||||||
|
</ToolBarContent> |
||||||
|
<ColGroup> |
||||||
|
<col/> |
||||||
|
<col style="width: 60px;"/> |
||||||
|
</ColGroup> |
||||||
|
<HeaderContent> |
||||||
|
<MudTh>Path</MudTh> |
||||||
|
<MudTh/> |
||||||
|
</HeaderContent> |
||||||
|
<RowTemplate> |
||||||
|
<MudTd DataLabel="Path">@context.Path</MudTd> |
||||||
|
<MudTd> |
||||||
|
<div style="align-items: center; display: flex;"> |
||||||
|
<MudTooltip Text="Delete Library Path"> |
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Delete" |
||||||
|
OnClick="@(() => DeleteLibraryPath(context))"> |
||||||
|
</MudIconButton> |
||||||
|
</MudTooltip> |
||||||
|
</div> |
||||||
|
</MudTd> |
||||||
|
</RowTemplate> |
||||||
|
</MudTable> |
||||||
|
</MudContainer> |
||||||
|
|
||||||
|
@code { |
||||||
|
|
||||||
|
[Parameter] |
||||||
|
public int Id { get; set; } |
||||||
|
|
||||||
|
private IList<LocalLibraryPathViewModel> _libraryPaths; |
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync() => await LoadLibraryPaths(); |
||||||
|
|
||||||
|
private async Task LoadLibraryPaths() => |
||||||
|
_libraryPaths = await Mediator.Send(new GetLocalLibraryPaths(Id)); |
||||||
|
|
||||||
|
private Task DeleteLibraryPath(LocalLibraryPathViewModel libraryPath) => Task.CompletedTask; |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue