Browse Source

add button to copy/clone ffmpeg profile (#183)

pull/184/head
Jason Dove 5 years ago committed by GitHub
parent
commit
198e595bc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfile.cs
  2. 37
      ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfileHandler.cs
  3. 1
      ErsatzTV.Core/Interfaces/Repositories/IFFmpegProfileRepository.cs
  4. 27
      ErsatzTV.Infrastructure/Data/Repositories/FFmpegProfileRepository.cs
  5. 39
      ErsatzTV/Pages/FFmpeg.razor
  6. 70
      ErsatzTV/Shared/CopyFFmpegProfileDialog.razor

9
ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfile.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.FFmpegProfiles.Commands
{
public record CopyFFmpegProfile
(int FFmpegProfileId, string Name) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
}

37
ErsatzTV.Application/FFmpegProfiles/Commands/CopyFFmpegProfileHandler.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using static ErsatzTV.Application.FFmpegProfiles.Mapper;
namespace ErsatzTV.Application.FFmpegProfiles.Commands
{
public class
CopyFFmpegProfileHandler : IRequestHandler<CopyFFmpegProfile, Either<BaseError, FFmpegProfileViewModel>>
{
private readonly IFFmpegProfileRepository _ffmpegProfileRepository;
public CopyFFmpegProfileHandler(IFFmpegProfileRepository ffmpegProfileRepository) =>
_ffmpegProfileRepository = ffmpegProfileRepository;
public Task<Either<BaseError, FFmpegProfileViewModel>> Handle(
CopyFFmpegProfile request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(PerformCopy)
.Bind(v => v.ToEitherAsync());
private Task<FFmpegProfileViewModel> PerformCopy(CopyFFmpegProfile request) =>
_ffmpegProfileRepository.Copy(request.FFmpegProfileId, request.Name)
.Map(ProjectToViewModel);
private Task<Validation<BaseError, CopyFFmpegProfile>> Validate(CopyFFmpegProfile request) =>
ValidateName(request).AsTask().MapT(_ => request);
private Validation<BaseError, string> ValidateName(CopyFFmpegProfile request) =>
request.NotEmpty(x => x.Name)
.Bind(_ => request.NotLongerThan(50)(x => x.Name));
}
}

1
ErsatzTV.Core/Interfaces/Repositories/IFFmpegProfileRepository.cs

@ -12,5 +12,6 @@ namespace ErsatzTV.Core.Interfaces.Repositories @@ -12,5 +12,6 @@ namespace ErsatzTV.Core.Interfaces.Repositories
Task<List<FFmpegProfile>> GetAll();
Task Update(FFmpegProfile ffmpegProfile);
Task Delete(int ffmpegProfileId);
Task<FFmpegProfile> Copy(int ffmpegProfileId, string name);
}
}

27
ErsatzTV.Infrastructure/Data/Repositories/FFmpegProfileRepository.cs

@ -5,14 +5,20 @@ using ErsatzTV.Core.Domain; @@ -5,14 +5,20 @@ using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace ErsatzTV.Infrastructure.Data.Repositories
{
public class FFmpegProfileRepository : IFFmpegProfileRepository
{
private readonly TvContext _dbContext;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public FFmpegProfileRepository(TvContext dbContext) => _dbContext = dbContext;
public FFmpegProfileRepository(IDbContextFactory<TvContext> dbContextFactory, TvContext dbContext)
{
_dbContextFactory = dbContextFactory;
_dbContext = dbContext;
}
public async Task<FFmpegProfile> Add(FFmpegProfile ffmpegProfile)
{
@ -44,5 +50,24 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @@ -44,5 +50,24 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
_dbContext.FFmpegProfiles.Remove(ffmpegProfile);
await _dbContext.SaveChangesAsync();
}
public async Task<FFmpegProfile> Copy(int ffmpegProfileId, string name)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
FFmpegProfile ffmpegProfile = await dbContext.FFmpegProfiles.FindAsync(ffmpegProfileId);
PropertyValues values = dbContext.Entry(ffmpegProfile).CurrentValues.Clone();
values["Id"] = 0;
var clone = new FFmpegProfile();
await dbContext.AddAsync(clone);
dbContext.Entry(clone).CurrentValues.SetValues(values);
clone.Name = name;
await dbContext.SaveChangesAsync();
await dbContext.Entry(clone).Reference(f => f.Resolution).LoadAsync();
return clone;
}
}
}

39
ErsatzTV/Pages/FFmpeg.razor

@ -2,10 +2,11 @@ @@ -2,10 +2,11 @@
@using ErsatzTV.Application.FFmpegProfiles
@using ErsatzTV.Application.FFmpegProfiles.Commands
@using ErsatzTV.Application.FFmpegProfiles.Queries
@inject IDialogService Dialog
@inject IMediator Mediator
@inject ILogger<FFmpeg> Logger
@inject ISnackbar Snackbar
@inject IDialogService _dialog
@inject IMediator _mediator
@inject ILogger<FFmpeg> _logger
@inject ISnackbar _snackbar
@inject NavigationManager _navigationManager
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudTable Hover="true" Items="_ffmpegProfiles">
@ -20,7 +21,7 @@ @@ -20,7 +21,7 @@
<col/>
<col/>
<col/>
<col style="width: 120px;"/>
<col style="width: 180px;"/>
</ColGroup>
<HeaderContent>
<MudTh>Name</MudTh>
@ -52,12 +53,17 @@ @@ -52,12 +53,17 @@
</MudTd>
<MudTd>
<div style="align-items: center; display: flex;">
<MudTooltip Text="Edit Channel">
<MudTooltip Text="Edit Profile">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Link="@($"/ffmpeg/{context.Id}")">
</MudIconButton>
</MudTooltip>
<MudTooltip Text="Delete Channel">
<MudTooltip Text="Copy Profile">
<MudIconButton Icon="@Icons.Material.Filled.ContentCopy"
OnClick="@(_ => CopyProfileAsync(context))">
</MudIconButton>
</MudTooltip>
<MudTooltip Text="Delete Profile">
<MudIconButton Icon="@Icons.Material.Filled.Delete"
OnClick="@(_ => DeleteProfileAsync(context))">
</MudIconButton>
@ -77,20 +83,33 @@ @@ -77,20 +83,33 @@
protected override async Task OnParametersSetAsync() => await LoadFFmpegProfilesAsync();
private async Task LoadFFmpegProfilesAsync() =>
_ffmpegProfiles = await Mediator.Send(new GetAllFFmpegProfiles());
_ffmpegProfiles = await _mediator.Send(new GetAllFFmpegProfiles());
private async Task DeleteProfileAsync(FFmpegProfileViewModel ffmpegProfile)
{
var parameters = new DialogParameters { { "EntityType", "ffmpeg profile" }, { "EntityName", ffmpegProfile.Name } };
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
IDialogReference dialog = Dialog.Show<DeleteDialog>("Delete FFmpeg Profile", parameters, options);
IDialogReference dialog = _dialog.Show<DeleteDialog>("Delete FFmpeg Profile", parameters, options);
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
await Mediator.Send(new DeleteFFmpegProfile(ffmpegProfile.Id));
await _mediator.Send(new DeleteFFmpegProfile(ffmpegProfile.Id));
await LoadFFmpegProfilesAsync();
}
}
private async Task CopyProfileAsync(FFmpegProfileViewModel ffmpegProfile)
{
var parameters = new DialogParameters { { "FFmpegProfileId", ffmpegProfile.Id } };
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
IDialogReference dialog = _dialog.Show<CopyFFmpegProfileDialog>("Copy FFmpeg Profile", parameters, options);
DialogResult dialogResult = await dialog.Result;
if (!dialogResult.Cancelled && dialogResult.Data is FFmpegProfileViewModel data)
{
_navigationManager.NavigateTo($"/ffmpeg/{data.Id}");
}
}
}

70
ErsatzTV/Shared/CopyFFmpegProfileDialog.razor

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
@using ErsatzTV.Application.FFmpegProfiles
@using ErsatzTV.Application.FFmpegProfiles.Commands
@inject IMediator _mediator
@inject ISnackbar _snackbar
@inject ILogger<AddToCollectionDialog> _logger
<MudDialog>
<DialogContent>
<EditForm Model="@_dummyModel" OnSubmit="@(_ => Submit())">
<MudContainer Class="mb-6">
<MudText>
Enter a name for the new FFmpeg Profile
</MudText>
</MudContainer>
<MudTextFieldString Label="New FFmpeg Profile Name"
@bind-Text="@_newFFmpegProfileName"
Class="mb-6 mx-4">
</MudTextFieldString>
</EditForm>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel" ButtonType="ButtonType.Reset">Cancel</MudButton>
<MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="Submit">
Copy Profile
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
[Parameter]
public int FFmpegProfileId { get; set; }
private record DummyModel;
private readonly DummyModel _dummyModel = new();
private string _newFFmpegProfileName;
private bool CanSubmit() => !string.IsNullOrWhiteSpace(_newFFmpegProfileName);
private async Task Submit()
{
if (!CanSubmit())
{
return;
}
Either<BaseError, FFmpegProfileViewModel> maybeResult =
await _mediator.Send(new CopyFFmpegProfile(FFmpegProfileId, _newFFmpegProfileName));
maybeResult.Match(
ffmpegProfile =>
{
MudDialog.Close(DialogResult.Ok(ffmpegProfile));
},
error =>
{
_snackbar.Add(error.Value, Severity.Error);
_logger.LogError("Error copying FFmpeg Profile: {Error}", error.Value);
MudDialog.Close(DialogResult.Cancel());
});
}
private void Cancel(MouseEventArgs e)
{
MudDialog.Cancel();
}
}
Loading…
Cancel
Save