mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* start to add smart collections * add smart collection table; delete smart collection * overwrite smart collections * support scheduling smart collections * update changelogpull/356/head
55 changed files with 10201 additions and 52 deletions
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
using ErsatzTV.Core; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands |
||||
{ |
||||
public record CreateSmartCollection |
||||
(string Query, string Name) : IRequest<Either<BaseError, SmartCollectionViewModel>>; |
||||
} |
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ErsatzTV.Core; |
||||
using ErsatzTV.Core.Domain; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using static ErsatzTV.Application.MediaCollections.Mapper; |
||||
using static LanguageExt.Prelude; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands |
||||
{ |
||||
public class CreateSmartCollectionHandler : |
||||
IRequestHandler<CreateSmartCollection, Either<BaseError, SmartCollectionViewModel>> |
||||
{ |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
|
||||
public CreateSmartCollectionHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||
_dbContextFactory = dbContextFactory; |
||||
|
||||
public async Task<Either<BaseError, SmartCollectionViewModel>> Handle( |
||||
CreateSmartCollection request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||
Validation<BaseError, SmartCollection> validation = await Validate(dbContext, request); |
||||
return await validation.Apply(c => PersistCollection(dbContext, c)); |
||||
} |
||||
|
||||
private static async Task<SmartCollectionViewModel> PersistCollection( |
||||
TvContext dbContext, |
||||
SmartCollection smartCollection) |
||||
{ |
||||
await dbContext.SmartCollections.AddAsync(smartCollection); |
||||
await dbContext.SaveChangesAsync(); |
||||
return ProjectToViewModel(smartCollection); |
||||
} |
||||
|
||||
private static Task<Validation<BaseError, SmartCollection>> Validate( |
||||
TvContext dbContext, |
||||
CreateSmartCollection request) => |
||||
ValidateName(dbContext, request).MapT( |
||||
name => new SmartCollection |
||||
{ |
||||
Name = name, |
||||
Query = request.Query |
||||
}); |
||||
|
||||
private static async Task<Validation<BaseError, string>> ValidateName( |
||||
TvContext dbContext, |
||||
CreateSmartCollection createSmartCollection) |
||||
{ |
||||
List<string> allNames = await dbContext.SmartCollections |
||||
.Map(c => c.Name) |
||||
.ToListAsync(); |
||||
|
||||
Validation<BaseError, string> result1 = createSmartCollection.NotEmpty(c => c.Name) |
||||
.Bind(_ => createSmartCollection.NotLongerThan(50)(c => c.Name)); |
||||
|
||||
var result2 = Optional(createSmartCollection.Name) |
||||
.Filter(name => !allNames.Contains(name)) |
||||
.ToValidation<BaseError>("SmartCollection name must be unique"); |
||||
|
||||
return (result1, result2).Apply((_, _) => createSmartCollection.Name); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
using ErsatzTV.Core; |
||||
using LanguageExt; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands |
||||
{ |
||||
public record DeleteSmartCollection(int SmartCollectionId) : MediatR.IRequest<Either<BaseError, Unit>>; |
||||
} |
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ErsatzTV.Core; |
||||
using ErsatzTV.Core.Domain; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using ErsatzTV.Infrastructure.Extensions; |
||||
using LanguageExt; |
||||
using Microsoft.EntityFrameworkCore; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands |
||||
{ |
||||
public class DeleteSmartCollectionHandler : MediatR.IRequestHandler<DeleteSmartCollection, Either<BaseError, Unit>> |
||||
{ |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
|
||||
public DeleteSmartCollectionHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||
_dbContextFactory = dbContextFactory; |
||||
|
||||
public async Task<Either<BaseError, Unit>> Handle( |
||||
DeleteSmartCollection request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||
|
||||
Validation<BaseError, SmartCollection> validation = await SmartCollectionMustExist(dbContext, request); |
||||
return await validation.Apply(c => DoDeletion(dbContext, c)); |
||||
} |
||||
|
||||
private static Task<Unit> DoDeletion(TvContext dbContext, SmartCollection smartCollection) |
||||
{ |
||||
dbContext.SmartCollections.Remove(smartCollection); |
||||
return dbContext.SaveChangesAsync().ToUnit(); |
||||
} |
||||
|
||||
private static Task<Validation<BaseError, SmartCollection>> SmartCollectionMustExist( |
||||
TvContext dbContext, |
||||
DeleteSmartCollection request) => |
||||
dbContext.SmartCollections |
||||
.SelectOneAsync(c => c.Id, c => c.Id == request.SmartCollectionId) |
||||
.Map(o => o.ToValidation<BaseError>($"SmartCollection {request.SmartCollectionId} does not exist.")); |
||||
} |
||||
} |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
using ErsatzTV.Core; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
using Unit = LanguageExt.Unit; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands |
||||
{ |
||||
public record UpdateSmartCollection(int Id, string Query) : IRequest<Either<BaseError, Unit>>; |
||||
} |
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Channels; |
||||
using System.Threading.Tasks; |
||||
using ErsatzTV.Application.Playouts.Commands; |
||||
using ErsatzTV.Core; |
||||
using ErsatzTV.Core.Domain; |
||||
using ErsatzTV.Core.Interfaces.Repositories; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using ErsatzTV.Infrastructure.Extensions; |
||||
using LanguageExt; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using static LanguageExt.Prelude; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands |
||||
{ |
||||
public class UpdateSmartCollectionHandler : MediatR.IRequestHandler<UpdateSmartCollection, Either<BaseError, Unit>> |
||||
{ |
||||
private readonly ChannelWriter<IBackgroundServiceRequest> _channel; |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository; |
||||
|
||||
public UpdateSmartCollectionHandler( |
||||
IDbContextFactory<TvContext> dbContextFactory, |
||||
IMediaCollectionRepository mediaCollectionRepository, |
||||
ChannelWriter<IBackgroundServiceRequest> channel) |
||||
{ |
||||
_dbContextFactory = dbContextFactory; |
||||
_mediaCollectionRepository = mediaCollectionRepository; |
||||
_channel = channel; |
||||
} |
||||
|
||||
public async Task<Either<BaseError, Unit>> Handle( |
||||
UpdateSmartCollection request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||
Validation<BaseError, SmartCollection> validation = await Validate(dbContext, request); |
||||
return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request)); |
||||
} |
||||
|
||||
private async Task<Unit> ApplyUpdateRequest(TvContext dbContext, SmartCollection c, UpdateSmartCollection request) |
||||
{ |
||||
c.Query = request.Query; |
||||
|
||||
// rebuild playouts
|
||||
if (await dbContext.SaveChangesAsync() > 0) |
||||
{ |
||||
// rebuild all playouts that use this smart collection
|
||||
foreach (int playoutId in await _mediaCollectionRepository.PlayoutIdsUsingSmartCollection(request.Id)) |
||||
{ |
||||
await _channel.WriteAsync(new BuildPlayout(playoutId, true)); |
||||
} |
||||
} |
||||
|
||||
return Unit.Default; |
||||
} |
||||
|
||||
private static Task<Validation<BaseError, SmartCollection>> Validate( |
||||
TvContext dbContext, |
||||
UpdateSmartCollection request) => SmartCollectionMustExist(dbContext, request); |
||||
|
||||
private static Task<Validation<BaseError, SmartCollection>> SmartCollectionMustExist( |
||||
TvContext dbContext, |
||||
UpdateSmartCollection updateCollection) => |
||||
dbContext.SmartCollections |
||||
.SelectOneAsync(c => c.Id, c => c.Id == updateCollection.Id) |
||||
.Map(o => o.ToValidation<BaseError>("SmartCollection does not exist.")); |
||||
} |
||||
} |
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections |
||||
{ |
||||
public record PagedSmartCollectionsViewModel(int TotalCount, List<SmartCollectionViewModel> Page); |
||||
} |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
using System.Collections.Generic; |
||||
using MediatR; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries |
||||
{ |
||||
public record GetAllSmartCollections : IRequest<List<SmartCollectionViewModel>>; |
||||
} |
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using static ErsatzTV.Application.MediaCollections.Mapper; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries |
||||
{ |
||||
public class GetAllSmartCollectionsHandler : IRequestHandler<GetAllSmartCollections, List<SmartCollectionViewModel>> |
||||
{ |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
|
||||
public GetAllSmartCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||
_dbContextFactory = dbContextFactory; |
||||
|
||||
public async Task<List<SmartCollectionViewModel>> Handle( |
||||
GetAllSmartCollections request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||
return await dbContext.SmartCollections |
||||
.ToListAsync(cancellationToken) |
||||
.Map(list => list.Map(ProjectToViewModel).ToList()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
using MediatR; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries |
||||
{ |
||||
public record GetPagedSmartCollections(int PageNum, int PageSize) : IRequest<PagedSmartCollectionsViewModel>; |
||||
} |
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic; |
||||
using System.Data; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Dapper; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using LanguageExt; |
||||
using MediatR; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using static ErsatzTV.Application.MediaCollections.Mapper; |
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries |
||||
{ |
||||
public class GetPagedSmartCollectionsHandler : IRequestHandler<GetPagedSmartCollections, PagedSmartCollectionsViewModel> |
||||
{ |
||||
private readonly IDbConnection _dbConnection; |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
|
||||
public GetPagedSmartCollectionsHandler(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection) |
||||
{ |
||||
_dbContextFactory = dbContextFactory; |
||||
_dbConnection = dbConnection; |
||||
} |
||||
|
||||
public async Task<PagedSmartCollectionsViewModel> Handle( |
||||
GetPagedSmartCollections request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
int count = await _dbConnection.QuerySingleAsync<int>(@"SELECT COUNT (*) FROM SmartCollection"); |
||||
|
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||
List<SmartCollectionViewModel> page = await dbContext.SmartCollections.FromSqlRaw( |
||||
@"SELECT * FROM SmartCollection
|
||||
ORDER BY Name |
||||
COLLATE NOCASE |
||||
LIMIT {0} OFFSET {1}",
|
||||
request.PageSize, |
||||
request.PageNum * request.PageSize) |
||||
.ToListAsync(cancellationToken) |
||||
.Map(list => list.Map(ProjectToViewModel).ToList()); |
||||
|
||||
return new PagedSmartCollectionsViewModel(count, page); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
namespace ErsatzTV.Application.MediaCollections |
||||
{ |
||||
public record SmartCollectionViewModel(int Id, string Name, string Query); |
||||
} |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
namespace ErsatzTV.Core.Domain |
||||
{ |
||||
public class SmartCollection |
||||
{ |
||||
public int Id { get; set; } |
||||
public string Name { get; set; } |
||||
public string Query { get; set; } |
||||
} |
||||
} |
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
namespace ErsatzTV.Core.Search |
||||
{ |
||||
public record SearchItem(int Id); |
||||
public record SearchItem(string Type, int Id); |
||||
} |
||||
|
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
using ErsatzTV.Core.Domain; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders; |
||||
|
||||
namespace ErsatzTV.Infrastructure.Data.Configurations |
||||
{ |
||||
public class SmartCollectionConfiguration : IEntityTypeConfiguration<SmartCollection> |
||||
{ |
||||
public void Configure(EntityTypeBuilder<SmartCollection> builder) => builder.ToTable("SmartCollection"); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations |
||||
{ |
||||
public partial class Add_SmartCollection : Migration |
||||
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.CreateTable( |
||||
name: "SmartCollection", |
||||
columns: table => new |
||||
{ |
||||
Id = table.Column<int>(type: "INTEGER", nullable: false) |
||||
.Annotation("Sqlite:Autoincrement", true), |
||||
Name = table.Column<string>(type: "TEXT", nullable: true), |
||||
Query = table.Column<string>(type: "TEXT", nullable: true) |
||||
}, |
||||
constraints: table => |
||||
{ |
||||
table.PrimaryKey("PK_SmartCollection", x => x.Id); |
||||
}); |
||||
} |
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropTable( |
||||
name: "SmartCollection"); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations |
||||
{ |
||||
public partial class Add_ProgramScheduleItemSmartCollection : Migration |
||||
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.AddColumn<int>( |
||||
name: "SmartCollectionId", |
||||
table: "ProgramScheduleItem", |
||||
type: "INTEGER", |
||||
nullable: true); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_ProgramScheduleItem_SmartCollectionId", |
||||
table: "ProgramScheduleItem", |
||||
column: "SmartCollectionId"); |
||||
|
||||
migrationBuilder.AddForeignKey( |
||||
name: "FK_ProgramScheduleItem_SmartCollection_SmartCollectionId", |
||||
table: "ProgramScheduleItem", |
||||
column: "SmartCollectionId", |
||||
principalTable: "SmartCollection", |
||||
principalColumn: "Id", |
||||
onDelete: ReferentialAction.Restrict); |
||||
} |
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropForeignKey( |
||||
name: "FK_ProgramScheduleItem_SmartCollection_SmartCollectionId", |
||||
table: "ProgramScheduleItem"); |
||||
|
||||
migrationBuilder.DropIndex( |
||||
name: "IX_ProgramScheduleItem_SmartCollectionId", |
||||
table: "ProgramScheduleItem"); |
||||
|
||||
migrationBuilder.DropColumn( |
||||
name: "SmartCollectionId", |
||||
table: "ProgramScheduleItem"); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations |
||||
{ |
||||
public partial class Add_PlayoutProgramScheduleAnchorSmartCollection : Migration |
||||
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.AddColumn<int>( |
||||
name: "SmartCollectionId", |
||||
table: "PlayoutProgramScheduleAnchor", |
||||
type: "INTEGER", |
||||
nullable: true); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_PlayoutProgramScheduleAnchor_SmartCollectionId", |
||||
table: "PlayoutProgramScheduleAnchor", |
||||
column: "SmartCollectionId"); |
||||
|
||||
migrationBuilder.AddForeignKey( |
||||
name: "FK_PlayoutProgramScheduleAnchor_SmartCollection_SmartCollectionId", |
||||
table: "PlayoutProgramScheduleAnchor", |
||||
column: "SmartCollectionId", |
||||
principalTable: "SmartCollection", |
||||
principalColumn: "Id", |
||||
onDelete: ReferentialAction.Restrict); |
||||
} |
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropForeignKey( |
||||
name: "FK_PlayoutProgramScheduleAnchor_SmartCollection_SmartCollectionId", |
||||
table: "PlayoutProgramScheduleAnchor"); |
||||
|
||||
migrationBuilder.DropIndex( |
||||
name: "IX_PlayoutProgramScheduleAnchor_SmartCollectionId", |
||||
table: "PlayoutProgramScheduleAnchor"); |
||||
|
||||
migrationBuilder.DropColumn( |
||||
name: "SmartCollectionId", |
||||
table: "PlayoutProgramScheduleAnchor"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,119 @@
@@ -0,0 +1,119 @@
|
||||
@using Microsoft.Extensions.Caching.Memory |
||||
@using ErsatzTV.Application.MediaCollections |
||||
@using ErsatzTV.Application.MediaCollections.Commands |
||||
@using ErsatzTV.Application.MediaCollections.Queries |
||||
@inject IMediator _mediator |
||||
@inject IMemoryCache _memoryCache |
||||
@inject ISnackbar _snackbar |
||||
@inject ILogger<SaveAsSmartCollectionDialog> _logger |
||||
|
||||
<MudDialog> |
||||
<DialogContent> |
||||
<EditForm Model="@_dummyModel" OnSubmit="@(_ => Submit())"> |
||||
<MudContainer Class="mb-6"> |
||||
<MudText Class="mud-primary-text" |
||||
Style="background-color: transparent; font-weight: bold" |
||||
Text="Select the desired smart collection"/> |
||||
</MudContainer> |
||||
<MudSelect Label="Collection" @bind-Value="_selectedCollection" Class="mb-6 mx-4"> |
||||
@foreach (SmartCollectionViewModel collection in _collections) |
||||
{ |
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem> |
||||
} |
||||
</MudSelect> |
||||
<MudTextFieldString Label="New Collection Name" |
||||
Disabled="@(_selectedCollection != _newCollection)" |
||||
@bind-Text="@_newCollectionName" |
||||
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"> |
||||
Save As Smart Collection |
||||
</MudButton> |
||||
</DialogActions> |
||||
</MudDialog> |
||||
|
||||
|
||||
@code { |
||||
|
||||
[CascadingParameter] |
||||
MudDialogInstance MudDialog { get; set; } |
||||
|
||||
private readonly SmartCollectionViewModel _newCollection = new(-1, "(New Collection)", string.Empty); |
||||
private string _newCollectionName; |
||||
|
||||
private List<SmartCollectionViewModel> _collections; |
||||
|
||||
private SmartCollectionViewModel _selectedCollection; |
||||
|
||||
private record DummyModel; |
||||
|
||||
private readonly DummyModel _dummyModel = new(); |
||||
|
||||
private bool CanSubmit() => |
||||
_selectedCollection != null && (_selectedCollection != _newCollection || !string.IsNullOrWhiteSpace(_newCollectionName)); |
||||
|
||||
protected override async Task OnParametersSetAsync() |
||||
{ |
||||
_collections = await _mediator.Send(new GetAllSmartCollections()) |
||||
.Map(list => new[] { _newCollection }.Append(list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase)).ToList()); |
||||
|
||||
if (_memoryCache.TryGetValue("SaveAsSmartCollectionDialog.SelectedCollectionId", out int id)) |
||||
{ |
||||
_selectedCollection = _collections.SingleOrDefault(c => c.Id == id) ?? _newCollection; |
||||
} |
||||
else |
||||
{ |
||||
_selectedCollection = _newCollection; |
||||
} |
||||
} |
||||
|
||||
private async Task Submit() |
||||
{ |
||||
if (!CanSubmit()) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
if (_selectedCollection == _newCollection) |
||||
{ |
||||
Either<BaseError, SmartCollectionViewModel> maybeResult = |
||||
await _mediator.Send(new CreateSmartCollection(string.Empty, _newCollectionName)); |
||||
|
||||
maybeResult.Match( |
||||
collection => |
||||
{ |
||||
_memoryCache.Set("SaveAsSmartCollectionDialog.SelectedCollectionId", collection.Id); |
||||
MudDialog.Close(DialogResult.Ok(collection)); |
||||
}, |
||||
error => |
||||
{ |
||||
_snackbar.Add(error.Value, Severity.Error); |
||||
_logger.LogError("Error creating new collection: {Error}", error.Value); |
||||
MudDialog.Close(DialogResult.Cancel()); |
||||
}); |
||||
} |
||||
else |
||||
{ |
||||
_memoryCache.Set("SaveAsSmartCollectionDialog.SelectedCollectionId", _selectedCollection.Id); |
||||
MudDialog.Close(DialogResult.Ok(_selectedCollection)); |
||||
} |
||||
} |
||||
|
||||
private async Task Cancel(MouseEventArgs e) |
||||
{ |
||||
// this is gross, but [enter] seems to sometimes trigger cancel instead of submit |
||||
if (e.Detail == 0) |
||||
{ |
||||
await Submit(); |
||||
} |
||||
else |
||||
{ |
||||
MudDialog.Cancel(); |
||||
} |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue