Merge pull request #269 from RattleSN4K3/feature/MediaMultiselectDelete
Option to delete selected Media entries
This commit is contained in:
commit
56bd6fd76d
4 changed files with 119 additions and 51 deletions
|
|
@ -34,5 +34,7 @@ namespace LANCommander.Server.Services.Abstractions
|
|||
Task<T> UpdateAsync(T entity);
|
||||
|
||||
Task DeleteAsync(T entity);
|
||||
// TODO: Add IBaseDatabaseService<>.DeleteRangeAsync
|
||||
//Task DeleteRangeAsync(IEnumerable<T> entities);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,17 @@ namespace LANCommander.Server.Services
|
|||
await base.DeleteAsync(entity);
|
||||
}
|
||||
|
||||
public override async Task DeleteRangeAsync(IEnumerable<Media> entities)
|
||||
{
|
||||
DeleteLocalMediaFiles(entities);
|
||||
|
||||
var gameIds = entities.Select(x => x.GameId).Distinct();
|
||||
var expirationTasks = gameIds.Select(gameId => cache.ExpireGameCacheAsync(gameId));
|
||||
await Task.WhenAll(expirationTasks);
|
||||
|
||||
await base.DeleteRangeAsync(entities);
|
||||
}
|
||||
|
||||
public static bool FileExists(Media entity)
|
||||
{
|
||||
var path = GetMediaPath(entity);
|
||||
|
|
@ -264,6 +275,14 @@ namespace LANCommander.Server.Services
|
|||
FileHelpers.DeleteIfExists(GetThumbnailPath(media));
|
||||
}
|
||||
|
||||
public void DeleteLocalMediaFiles(IEnumerable<Media> medias)
|
||||
{
|
||||
foreach (var media in medias)
|
||||
{
|
||||
DeleteLocalMediaFile(media);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Media> DownloadMediaAsync(string sourceUrl, Media media)
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
|
|
|
|||
|
|
@ -340,7 +340,25 @@ namespace LANCommander.Server.Services
|
|||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task DeleteRangeAsync(IEnumerable<T> entities)
|
||||
{
|
||||
try
|
||||
{
|
||||
await cache.ExpireAsync($"{typeof(T).FullName}");
|
||||
|
||||
using var context = await dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
context.Set<T>().RemoveRange(entities);
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<User?> GetCurrentUserAsync(DatabaseContext context)
|
||||
{
|
||||
var httpContext = httpContextAccessor?.HttpContext;
|
||||
|
|
|
|||
|
|
@ -6,60 +6,74 @@
|
|||
@inject ILogger<MediaEditor> Logger
|
||||
|
||||
<Flex Vertical Gap="FlexGap.Large" Style="width: 100%" Class="media-editor">
|
||||
<Table TItem="Media" DataSource="@Values" RowKey="c => c.Id" HidePagination="true" Responsive>
|
||||
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
|
||||
@if (MediaService.FileExists(context))
|
||||
{
|
||||
string originalPath = $"/api/Media/{context.Id}/Download?fileId={context.FileId}";
|
||||
string thumbnailPath = context.Thumbnail != null
|
||||
? $"/api/Media/{context.Thumbnail?.Id}/Download?fileId={context.Thumbnail?.FileId}"
|
||||
: $"/api/Media/{context.Id}/Thumbnail?fileId={context.FileId}";
|
||||
|
||||
if (context.Type == MediaType.Manual)
|
||||
<Table @ref="ResultsTable" TItem="Media" DataSource="@Values" RowKey="c => c.Id" @bind-SelectedRows="Selected" HidePagination="true" Responsive>
|
||||
<TitleTemplate>
|
||||
<Flex Justify="FlexJustify.End" Align="FlexAlign.Center" Gap="@("10")">
|
||||
@if (Selected.Any())
|
||||
{
|
||||
<Image Width="100px" Src="@thumbnailPath" PreviewVisible="false" OnClick="() => OpenManual(context)" />
|
||||
<span>@Selected.Count() selected</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Image Width="100px" Src="@thumbnailPath" PreviewSrc="@originalPath" />
|
||||
}
|
||||
}
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="p => p.Type">
|
||||
<Select @key="context.Id" @bind-Value="context.Type" TItem="MediaType" TItemValue="MediaType" DataSource="AllowedMediaTypes" />
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="p => p.Name">
|
||||
@if (context.Type == MediaType.Manual)
|
||||
{
|
||||
<Input @bind-Value="context.Name" OnBlur="() => Update(context)"/>
|
||||
}
|
||||
</PropertyColumn>
|
||||
<ActionColumn>
|
||||
<Flex Gap="FlexGap.Small" Justify="FlexJustify.End">
|
||||
@{
|
||||
var fileInputId = Guid.NewGuid();
|
||||
}
|
||||
<InputFile id="@fileInputId" OnChange="(e) => UploadMedia(e, context)" hidden accept=".jpg,.jpeg,.png,.gif,.pdf,.ico"/>
|
||||
<label class="ant-btn ant-btn-text ant-btn-icon-only" for="@fileInputId">
|
||||
<Icon Type="@IconType.Outline.Upload"/>
|
||||
</label>
|
||||
|
||||
@if (String.IsNullOrWhiteSpace(Settings.Media.SteamGridDbApiKey))
|
||||
{
|
||||
<Popconfirm OnConfirm="() => NavigateToSettings()" Title="Invalid SteamGridDB credentials. Setup now?">
|
||||
<Button Type="ButtonType.Text" Icon="@IconType.Outline.Search"/>
|
||||
</Popconfirm>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Button OnClick="() => SearchMedia(context)" Type="ButtonType.Text" Icon="@IconType.Outline.Search"/>
|
||||
}
|
||||
|
||||
<Popconfirm OnConfirm="() => RemoveMedia(context)" Title="Are you sure you want to delete this media?">
|
||||
<Button Type="ButtonType.Text" Danger Icon="@IconType.Outline.Close"/>
|
||||
<Popconfirm Disabled="!Selected.Any()" OnConfirm="DeleteAll" Title="Are you sure you want to delete all selected media?">
|
||||
<Button Disabled="!Selected.Any()" Danger>Delete</Button>
|
||||
</Popconfirm>
|
||||
</Flex>
|
||||
</ActionColumn>
|
||||
</TitleTemplate>
|
||||
<ColumnDefinitions Context="row">
|
||||
<Selection Type="SelectionType.Checkbox" />
|
||||
<PropertyColumn Property="p => p.Id" Title="Preview" Width="100px" Align="ColumnAlign.Center">
|
||||
@if (MediaService.FileExists(row))
|
||||
{
|
||||
string originalPath = $"/api/Media/{row.Id}/Download?fileId={row.FileId}";
|
||||
string thumbnailPath = row.Thumbnail != null
|
||||
? $"/api/Media/{row.Thumbnail?.Id}/Download?fileId={row.Thumbnail?.FileId}"
|
||||
: $"/api/Media/{row.Id}/Thumbnail?fileId={row.FileId}";
|
||||
|
||||
if (row.Type == MediaType.Manual)
|
||||
{
|
||||
<Image Width="100px" Src="@thumbnailPath" PreviewVisible="false" OnClick="() => OpenManual(row)" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<Image Width="100px" Src="@thumbnailPath" PreviewSrc="@originalPath" />
|
||||
}
|
||||
}
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="p => p.Type">
|
||||
<Select @key="row.Id" @bind-Value="row.Type" TItem="MediaType" TItemValue="MediaType" DataSource="AllowedMediaTypes" />
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="p => p.Name">
|
||||
@if (row.Type == MediaType.Manual)
|
||||
{
|
||||
<Input @bind-Value="row.Name" OnBlur="() => Update(row)" />
|
||||
}
|
||||
</PropertyColumn>
|
||||
<ActionColumn>
|
||||
<Flex Gap="FlexGap.Small" Justify="FlexJustify.End">
|
||||
@{
|
||||
var fileInputId = Guid.NewGuid();
|
||||
}
|
||||
<InputFile id="@fileInputId" OnChange="(e) => UploadMedia(e, row)" hidden accept=".jpg,.jpeg,.png,.gif,.pdf,.ico"/>
|
||||
<label class="ant-btn ant-btn-text ant-btn-icon-only" for="@fileInputId">
|
||||
<Icon Type="@IconType.Outline.Upload"/>
|
||||
</label>
|
||||
|
||||
@if (String.IsNullOrWhiteSpace(Settings.Media.SteamGridDbApiKey))
|
||||
{
|
||||
<Popconfirm OnConfirm="() => NavigateToSettings()" Title="Invalid SteamGridDB credentials. Setup now?">
|
||||
<Button Type="ButtonType.Text" Icon="@IconType.Outline.Search"/>
|
||||
</Popconfirm>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Button OnClick="() => SearchMedia(row)" Type="ButtonType.Text" Icon="@IconType.Outline.Search"/>
|
||||
}
|
||||
|
||||
<Popconfirm OnConfirm="() => RemoveMedia(row)" Title="Are you sure you want to delete this media?">
|
||||
<Button Type="ButtonType.Text" Danger Icon="@IconType.Outline.Close"/>
|
||||
</Popconfirm>
|
||||
</Flex>
|
||||
</ActionColumn>
|
||||
</ColumnDefinitions>
|
||||
</Table>
|
||||
|
||||
<GridRow Justify="RowJustify.End">
|
||||
|
|
@ -76,6 +90,9 @@
|
|||
[Parameter] public Guid GameId { get; set; }
|
||||
[Parameter] public string GameTitle { get; set; }
|
||||
|
||||
IEnumerable<Media> Selected = new List<Media>();
|
||||
ITable? ResultsTable;
|
||||
|
||||
Settings Settings = SettingService.GetSettings();
|
||||
|
||||
MediaType[] AllowedMediaTypes = new MediaType[]
|
||||
|
|
@ -237,6 +254,18 @@
|
|||
await ValuesChanged.InvokeAsync(Values);
|
||||
}
|
||||
|
||||
private async Task DeleteAll()
|
||||
{
|
||||
if (!Selected.Any())
|
||||
return;
|
||||
|
||||
Values = Values.Except(Selected).ToList();
|
||||
await MediaService.DeleteRangeAsync(Selected);
|
||||
|
||||
Selected = [];
|
||||
ResultsTable.ReloadData();
|
||||
}
|
||||
|
||||
private async Task RemoveMedia(Media media)
|
||||
{
|
||||
Values.Remove(media);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue