Linked Series (#1230)
* Implemented the ability to link different series together through Edit Series. CSS pending. * Fixed up the css for related cards to show the relation * Working on making all tabs in edit seris modal save in one go. Taking a break. * Some fixes for Robbie to help with styling on * Linked series pill, center library * Centering library detail and related pill spacing - Library detail cards are now centered if total number of items is > 6 or if mobile. - Added ability to determine if mobile (viewport width <= 480px - Fixed related card spacing - Fixed related card pill spacing * Updating relation form spacing * Fixed a bug in card detail layout when there is no pagination, we create one in a way that all items render at once. * Only auto-close side nav on phones, not tablets * Fixed a bug where we had flipped state on sideNavCollapsed$ * Cleaned up some misleading comments * Implemented RBS back in and now if you have a relationship besides prequel/sequel, the target series will show a link back to it's parent. * Added Parentto pipe * Missed a relationship type Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
parent
7253765f1d
commit
4206ae3e22
47 changed files with 2571 additions and 195 deletions
|
@ -84,7 +84,6 @@ public class CollectionTagRepository : ICollectionTagRepository
|
|||
public async Task<IEnumerable<CollectionTagDto>> GetAllTagDtosAsync()
|
||||
{
|
||||
return await _context.CollectionTag
|
||||
.Select(c => c)
|
||||
.OrderBy(c => c.NormalizedTitle)
|
||||
.AsNoTracking()
|
||||
.ProjectTo<CollectionTagDto>(_mapper.ConfigurationProvider)
|
||||
|
|
|
@ -11,6 +11,7 @@ using API.DTOs.Filtering;
|
|||
using API.DTOs.Metadata;
|
||||
using API.DTOs.ReadingLists;
|
||||
using API.DTOs.Search;
|
||||
using API.DTOs.SeriesDetail;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
|
@ -24,6 +25,17 @@ using Microsoft.EntityFrameworkCore;
|
|||
|
||||
namespace API.Data.Repositories;
|
||||
|
||||
[Flags]
|
||||
public enum SeriesIncludes
|
||||
{
|
||||
None = 1,
|
||||
Volumes = 2,
|
||||
Metadata = 4,
|
||||
Related = 8,
|
||||
//Related = 16,
|
||||
//UserPreferences = 32
|
||||
}
|
||||
|
||||
internal class RecentlyAddedSeries
|
||||
{
|
||||
public int LibraryId { get; init; }
|
||||
|
@ -68,7 +80,7 @@ public interface ISeriesRepository
|
|||
Task<IEnumerable<Series>> GetSeriesForLibraryIdAsync(int libraryId);
|
||||
Task<SeriesDto> GetSeriesDtoByIdAsync(int seriesId, int userId);
|
||||
Task<bool> DeleteSeriesAsync(int seriesId);
|
||||
Task<Series> GetSeriesByIdAsync(int seriesId);
|
||||
Task<Series> GetSeriesByIdAsync(int seriesId, SeriesIncludes includes = SeriesIncludes.Volumes | SeriesIncludes.Metadata);
|
||||
Task<IList<Series>> GetSeriesByIdsAsync(IList<int> seriesIds);
|
||||
Task<int[]> GetChapterIdsForSeriesAsync(IList<int> seriesIds);
|
||||
Task<IDictionary<int, IList<int>>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds);
|
||||
|
@ -96,6 +108,9 @@ public interface ISeriesRepository
|
|||
Task<IList<LanguageDto>> GetAllLanguagesForLibrariesAsync(List<int> libraryIds);
|
||||
IEnumerable<PublicationStatusDto> GetAllPublicationStatusesDtosForLibrariesAsync(List<int> libraryIds);
|
||||
Task<IEnumerable<GroupedSeriesDto>> GetRecentlyUpdatedSeries(int userId, int pageSize = 30);
|
||||
Task<RelatedSeriesDto> GetRelatedSeries(int userId, int seriesId);
|
||||
|
||||
Task<IEnumerable<SeriesDto>> GetSeriesForRelationKind(int userId, int seriesId, RelationKind kind);
|
||||
}
|
||||
|
||||
public class SeriesRepository : ISeriesRepository
|
||||
|
@ -376,19 +391,35 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// </summary>
|
||||
/// <param name="seriesId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Series> GetSeriesByIdAsync(int seriesId)
|
||||
public async Task<Series> GetSeriesByIdAsync(int seriesId, SeriesIncludes includes = SeriesIncludes.Volumes | SeriesIncludes.Metadata)
|
||||
{
|
||||
return await _context.Series
|
||||
.Include(s => s.Volumes)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.CollectionTags)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Genres)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.People)
|
||||
var query = _context.Series
|
||||
.Where(s => s.Id == seriesId)
|
||||
.AsSplitQuery()
|
||||
.SingleOrDefaultAsync();
|
||||
.AsSplitQuery();
|
||||
|
||||
if (includes.HasFlag(SeriesIncludes.Volumes))
|
||||
{
|
||||
query = query.Include(s => s.Volumes);
|
||||
}
|
||||
|
||||
if (includes.HasFlag(SeriesIncludes.Related))
|
||||
{
|
||||
query = query.Include(s => s.Relations)
|
||||
.ThenInclude(r => r.TargetSeries)
|
||||
.Include(s => s.RelationOf);
|
||||
}
|
||||
|
||||
if (includes.HasFlag(SeriesIncludes.Metadata))
|
||||
{
|
||||
query = query.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.CollectionTags)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Genres)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.People);
|
||||
}
|
||||
|
||||
return await query.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -939,6 +970,79 @@ public class SeriesRepository : ISeriesRepository
|
|||
return seriesMap.Values.AsEnumerable();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SeriesDto>> GetSeriesForRelationKind(int userId, int seriesId, RelationKind kind)
|
||||
{
|
||||
var libraryIds = _context.AppUser
|
||||
.Where(u => u.Id == userId)
|
||||
.SelectMany(l => l.Libraries.Select(lib => lib.Id));
|
||||
var usersSeriesIds = _context.Series
|
||||
.Where(s => libraryIds.Contains(s.LibraryId))
|
||||
.Select(s => s.Id);
|
||||
|
||||
var targetSeries = _context.SeriesRelation
|
||||
.Where(sr =>
|
||||
sr.SeriesId == seriesId && sr.RelationKind == kind && usersSeriesIds.Contains(sr.TargetSeriesId))
|
||||
.Include(sr => sr.TargetSeries)
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.Select(sr => sr.TargetSeriesId);
|
||||
|
||||
return await _context.Series
|
||||
.Where(s => targetSeries.Contains(s.Id))
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<RelatedSeriesDto> GetRelatedSeries(int userId, int seriesId)
|
||||
{
|
||||
var libraryIds = _context.AppUser
|
||||
.Where(u => u.Id == userId)
|
||||
.SelectMany(l => l.Libraries.Select(lib => lib.Id));
|
||||
var usersSeriesIds = _context.Series
|
||||
.Where(s => libraryIds.Contains(s.LibraryId))
|
||||
.Select(s => s.Id);
|
||||
|
||||
return new RelatedSeriesDto()
|
||||
{
|
||||
SourceSeriesId = seriesId,
|
||||
Adaptations = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Adaptation),
|
||||
Characters = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Character),
|
||||
Prequels = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Prequel),
|
||||
Sequels = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Sequel),
|
||||
Contains = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Contains),
|
||||
SideStories = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.SideStory),
|
||||
SpinOffs = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.SpinOff),
|
||||
Others = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Other),
|
||||
AlternativeSettings = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.AlternativeSetting),
|
||||
AlternativeVersions = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.AlternativeVersion),
|
||||
Doujinshis = await GetRelatedSeriesQuery(seriesId, usersSeriesIds, RelationKind.Doujinshi),
|
||||
Parent = await _context.Series
|
||||
.SelectMany(s =>
|
||||
s.RelationOf.Where(r => r.TargetSeriesId == seriesId
|
||||
&& usersSeriesIds.Contains(r.TargetSeriesId)
|
||||
&& r.RelationKind != RelationKind.Prequel
|
||||
&& r.RelationKind != RelationKind.Sequel)
|
||||
.Select(sr => sr.Series))
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync()
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SeriesDto>> GetRelatedSeriesQuery(int seriesId, IEnumerable<int> usersSeriesIds, RelationKind kind)
|
||||
{
|
||||
return await _context.Series.SelectMany(s =>
|
||||
s.Relations.Where(sr => sr.RelationKind == kind && sr.SeriesId == seriesId && usersSeriesIds.Contains(sr.TargetSeriesId))
|
||||
.Select(sr => sr.TargetSeries))
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<RecentlyAddedSeries>> GetRecentlyAddedChaptersQuery(int userId, int maxRecords = 3000)
|
||||
{
|
||||
var libraries = await _context.AppUser
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue