mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-06-03 05:34:21 -04:00
Release Polish 3 (#3359)
This commit is contained in:
parent
dd3dec269f
commit
f812f61001
@ -42,10 +42,15 @@ public class PersonController : BaseApiController
|
|||||||
return Ok(await _unitOfWork.PersonRepository.GetPersonDtoByName(name, User.GetUserId()));
|
return Ok(await _unitOfWork.PersonRepository.GetPersonDtoByName(name, User.GetUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all roles for a Person
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="personId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("roles")]
|
[HttpGet("roles")]
|
||||||
public async Task<ActionResult<IEnumerable<PersonRole>>> GetRolesForPersonByName(string name)
|
public async Task<ActionResult<IEnumerable<PersonRole>>> GetRolesForPersonByName(int personId)
|
||||||
{
|
{
|
||||||
return Ok(await _unitOfWork.PersonRepository.GetRolesForPersonByName(name, User.GetUserId()));
|
return Ok(await _unitOfWork.PersonRepository.GetRolesForPersonByName(personId, User.GetUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -490,23 +490,27 @@ public class UploadController : BaseApiController
|
|||||||
[HttpPost("person")]
|
[HttpPost("person")]
|
||||||
public async Task<ActionResult> UploadPersonCoverImageFromUrl(UploadFileDto uploadFileDto)
|
public async Task<ActionResult> UploadPersonCoverImageFromUrl(UploadFileDto uploadFileDto)
|
||||||
{
|
{
|
||||||
// Check if Url is non-empty, request the image and place in temp, then ask image service to handle it.
|
|
||||||
// See if we can do this all in memory without touching underlying system
|
|
||||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
|
||||||
{
|
|
||||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var person = await _unitOfWork.PersonRepository.GetPersonById(uploadFileDto.Id);
|
var person = await _unitOfWork.PersonRepository.GetPersonById(uploadFileDto.Id);
|
||||||
if (person == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "person-doesnt-exist"));
|
if (person == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "person-doesnt-exist"));
|
||||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetPersonFormat(uploadFileDto.Id)}");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(filePath))
|
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||||
{
|
{
|
||||||
person.CoverImage = filePath;
|
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetPersonFormat(uploadFileDto.Id)}");
|
||||||
person.CoverImageLocked = true;
|
|
||||||
|
if (!string.IsNullOrEmpty(filePath))
|
||||||
|
{
|
||||||
|
person.CoverImage = filePath;
|
||||||
|
person.CoverImageLocked = true;
|
||||||
|
_imageService.UpdateColorScape(person);
|
||||||
|
_unitOfWork.PersonRepository.Update(person);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
person.CoverImage = string.Empty;
|
||||||
|
person.CoverImageLocked = false;
|
||||||
_imageService.UpdateColorScape(person);
|
_imageService.UpdateColorScape(person);
|
||||||
_unitOfWork.PersonRepository.Update(person);
|
_unitOfWork.PersonRepository.Update(person);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public interface IPersonRepository
|
|||||||
|
|
||||||
Task<string> GetCoverImageAsync(int personId);
|
Task<string> GetCoverImageAsync(int personId);
|
||||||
Task<string?> GetCoverImageByNameAsync(string name);
|
Task<string?> GetCoverImageByNameAsync(string name);
|
||||||
Task<IEnumerable<PersonRole>> GetRolesForPersonByName(string name, int userId);
|
Task<IEnumerable<PersonRole>> GetRolesForPersonByName(int personId, int userId);
|
||||||
Task<PagedList<BrowsePersonDto>> GetAllWritersAndSeriesCount(int userId, UserParams userParams);
|
Task<PagedList<BrowsePersonDto>> GetAllWritersAndSeriesCount(int userId, UserParams userParams);
|
||||||
Task<Person?> GetPersonById(int personId);
|
Task<Person?> GetPersonById(int personId);
|
||||||
Task<PersonDto?> GetPersonDtoByName(string name, int userId);
|
Task<PersonDto?> GetPersonDtoByName(string name, int userId);
|
||||||
@ -145,18 +145,28 @@ public class PersonRepository : IPersonRepository
|
|||||||
.SingleOrDefaultAsync();
|
.SingleOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<PersonRole>> GetRolesForPersonByName(string name, int userId)
|
public async Task<IEnumerable<PersonRole>> GetRolesForPersonByName(int personId, int userId)
|
||||||
{
|
{
|
||||||
// TODO: This will need to check both series and chapters (in cases where komf only updates series)
|
|
||||||
var normalized = name.ToNormalized();
|
|
||||||
var ageRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
var ageRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||||
|
|
||||||
return await _context.Person
|
// Query roles from ChapterPeople
|
||||||
.Where(p => p.NormalizedName == normalized)
|
var chapterRoles = await _context.Person
|
||||||
|
.Where(p => p.Id == personId)
|
||||||
.RestrictAgainstAgeRestriction(ageRating)
|
.RestrictAgainstAgeRestriction(ageRating)
|
||||||
.SelectMany(p => p.ChapterPeople.Select(cp => cp.Role))
|
.SelectMany(p => p.ChapterPeople.Select(cp => cp.Role))
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Query roles from SeriesMetadataPeople
|
||||||
|
var seriesRoles = await _context.Person
|
||||||
|
.Where(p => p.Id == personId)
|
||||||
|
.RestrictAgainstAgeRestriction(ageRating)
|
||||||
|
.SelectMany(p => p.SeriesMetadataPeople.Select(smp => smp.Role))
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Combine and return distinct roles
|
||||||
|
return chapterRoles.Union(seriesRoles).Distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PagedList<BrowsePersonDto>> GetAllWritersAndSeriesCount(int userId, UserParams userParams)
|
public async Task<PagedList<BrowsePersonDto>> GetAllWritersAndSeriesCount(int userId, UserParams userParams)
|
||||||
|
@ -1046,8 +1046,6 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
.Select(u => u.CollapseSeriesRelationships)
|
.Select(u => u.CollapseSeriesRelationships)
|
||||||
.SingleOrDefaultAsync();
|
.SingleOrDefaultAsync();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
query ??= _context.Series
|
query ??= _context.Series
|
||||||
.AsNoTracking();
|
.AsNoTracking();
|
||||||
|
|
||||||
@ -1064,7 +1062,6 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
|
|
||||||
query = ApplyWantToReadFilter(filter, query, userId);
|
query = ApplyWantToReadFilter(filter, query, userId);
|
||||||
|
|
||||||
|
|
||||||
query = await ApplyCollectionFilter(filter, query, userId, userRating);
|
query = await ApplyCollectionFilter(filter, query, userId, userRating);
|
||||||
|
|
||||||
|
|
||||||
@ -1136,6 +1133,7 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
var seriesIds = _context.AppUser.Where(u => u.Id == userId)
|
var seriesIds = _context.AppUser.Where(u => u.Id == userId)
|
||||||
.SelectMany(u => u.WantToRead)
|
.SelectMany(u => u.WantToRead)
|
||||||
.Select(s => s.SeriesId);
|
.Select(s => s.SeriesId);
|
||||||
|
|
||||||
if (bool.Parse(wantToReadStmt.Value))
|
if (bool.Parse(wantToReadStmt.Value))
|
||||||
{
|
{
|
||||||
query = query.Where(s => seriesIds.Contains(s.Id));
|
query = query.Where(s => seriesIds.Contains(s.Id));
|
||||||
@ -1152,6 +1150,7 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
{
|
{
|
||||||
var filterIncludeLibs = new List<int>();
|
var filterIncludeLibs = new List<int>();
|
||||||
var filterExcludeLibs = new List<int>();
|
var filterExcludeLibs = new List<int>();
|
||||||
|
|
||||||
if (filter.Statements != null)
|
if (filter.Statements != null)
|
||||||
{
|
{
|
||||||
foreach (var stmt in filter.Statements.Where(stmt => stmt.Field == FilterField.Libraries))
|
foreach (var stmt in filter.Statements.Where(stmt => stmt.Field == FilterField.Libraries))
|
||||||
@ -1993,17 +1992,25 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
public async Task<PagedList<SeriesDto>> GetWantToReadForUserV2Async(int userId, UserParams userParams, FilterV2Dto filter)
|
public async Task<PagedList<SeriesDto>> GetWantToReadForUserV2Async(int userId, UserParams userParams, FilterV2Dto filter)
|
||||||
{
|
{
|
||||||
var libraryIds = await _context.Library.GetUserLibraries(userId).ToListAsync();
|
var libraryIds = await _context.Library.GetUserLibraries(userId).ToListAsync();
|
||||||
var query = _context.AppUser
|
var seriesIds = await _context.AppUser
|
||||||
.Where(user => user.Id == userId)
|
.Where(user => user.Id == userId)
|
||||||
.SelectMany(u => u.WantToRead)
|
.SelectMany(u => u.WantToRead)
|
||||||
.Where(s => libraryIds.Contains(s.Series.LibraryId))
|
.Where(s => libraryIds.Contains(s.Series.LibraryId))
|
||||||
.Select(w => w.Series)
|
.Select(w => w.Series.Id)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var query = await CreateFilteredSearchQueryableV2(userId, filter, QueryContext.None);
|
||||||
|
|
||||||
|
// Apply the Want to Read filtering
|
||||||
|
query = query.Where(s => seriesIds.Contains(s.Id));
|
||||||
|
|
||||||
|
var retSeries = query
|
||||||
|
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
.AsNoTracking();
|
.AsNoTracking();
|
||||||
|
|
||||||
var filteredQuery = await CreateFilteredSearchQueryableV2(userId, filter, QueryContext.None, query);
|
return await PagedList<SeriesDto>.CreateAsync(retSeries, userParams.PageNumber, userParams.PageSize);
|
||||||
|
|
||||||
return await PagedList<SeriesDto>.CreateAsync(filteredQuery.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider), userParams.PageNumber, userParams.PageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IList<Series>> GetWantToReadForUserAsync(int userId)
|
public async Task<IList<Series>> GetWantToReadForUserAsync(int userId)
|
||||||
|
@ -259,8 +259,7 @@ public static class SeriesFilter
|
|||||||
.Where(p => p != null && p.AppUserId == userId)
|
.Where(p => p != null && p.AppUserId == userId)
|
||||||
.Sum(p => p != null ? (p.PagesRead * 1.0f / s.Pages) : 0) * 100
|
.Sum(p => p != null ? (p.PagesRead * 1.0f / s.Pages) : 0) * 100
|
||||||
})
|
})
|
||||||
.AsSplitQuery()
|
.AsSplitQuery();
|
||||||
.AsEnumerable();
|
|
||||||
|
|
||||||
switch (comparison)
|
switch (comparison)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,6 @@ public static class QueryableExtensions
|
|||||||
.Include(l => l.AppUsers)
|
.Include(l => l.AppUsers)
|
||||||
.Where(lib => lib.AppUsers.Any(user => user.Id == userId))
|
.Where(lib => lib.AppUsers.Any(user => user.Id == userId))
|
||||||
.IsRestricted(queryContext)
|
.IsRestricted(queryContext)
|
||||||
.AsNoTracking()
|
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
.Select(lib => lib.Id);
|
.Select(lib => lib.Id);
|
||||||
}
|
}
|
||||||
|
@ -585,6 +585,7 @@ public class ImageService : IImageService
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string CreateThumbnailFromBase64(string encodedImage, string fileName, EncodeFormat encodeFormat, int thumbnailWidth = ThumbnailWidth)
|
public string CreateThumbnailFromBase64(string encodedImage, string fileName, EncodeFormat encodeFormat, int thumbnailWidth = ThumbnailWidth)
|
||||||
{
|
{
|
||||||
|
// TODO: This code has no concept of cropping nor Thumbnail Size
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), thumbnailWidth);
|
using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), thumbnailWidth);
|
||||||
|
@ -334,7 +334,10 @@ public class SeriesService : ISeriesService
|
|||||||
private async Task HandlePeopleUpdateAsync(SeriesMetadata metadata, ICollection<PersonDto> peopleDtos, PersonRole role)
|
private async Task HandlePeopleUpdateAsync(SeriesMetadata metadata, ICollection<PersonDto> peopleDtos, PersonRole role)
|
||||||
{
|
{
|
||||||
// Normalize all names from the DTOs
|
// Normalize all names from the DTOs
|
||||||
var normalizedNames = peopleDtos.Select(p => Parser.Normalize(p.Name)).ToList();
|
var normalizedNames = peopleDtos
|
||||||
|
.Select(p => Parser.Normalize(p.Name))
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
// Bulk select people who already exist in the database
|
// Bulk select people who already exist in the database
|
||||||
var existingPeople = await _unitOfWork.PersonRepository.GetPeopleByNames(normalizedNames);
|
var existingPeople = await _unitOfWork.PersonRepository.GetPeopleByNames(normalizedNames);
|
||||||
|
@ -83,6 +83,7 @@ public class TaskScheduler : ITaskScheduler
|
|||||||
|
|
||||||
public static readonly ImmutableArray<string> ScanTasks =
|
public static readonly ImmutableArray<string> ScanTasks =
|
||||||
["ScannerService", "ScanLibrary", "ScanLibraries", "ScanFolder", "ScanSeries"];
|
["ScannerService", "ScanLibrary", "ScanLibraries", "ScanFolder", "ScanSeries"];
|
||||||
|
private static readonly ImmutableArray<string> NonCronOptions = ["disabled", "daily", "weekly"];
|
||||||
|
|
||||||
private static readonly Random Rnd = new Random();
|
private static readonly Random Rnd = new Random();
|
||||||
|
|
||||||
@ -122,10 +123,10 @@ public class TaskScheduler : ITaskScheduler
|
|||||||
public async Task ScheduleTasks()
|
public async Task ScheduleTasks()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Scheduling reoccurring tasks");
|
_logger.LogInformation("Scheduling reoccurring tasks");
|
||||||
var nonCronOptions = new List<string>(["disabled", "daily", "weekly"]);
|
|
||||||
|
|
||||||
var setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).Value;
|
var setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).Value;
|
||||||
if (setting == null || (!nonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting)))
|
if (IsInvalidCronSetting(setting))
|
||||||
{
|
{
|
||||||
_logger.LogError("Scan Task has invalid cron, defaulting to Daily");
|
_logger.LogError("Scan Task has invalid cron, defaulting to Daily");
|
||||||
RecurringJob.AddOrUpdate(ScanLibrariesTaskId, () => ScanLibraries(false),
|
RecurringJob.AddOrUpdate(ScanLibrariesTaskId, () => ScanLibraries(false),
|
||||||
@ -141,9 +142,9 @@ public class TaskScheduler : ITaskScheduler
|
|||||||
|
|
||||||
|
|
||||||
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Value;
|
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Value;
|
||||||
if (setting == null || (!nonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting)))
|
if (IsInvalidCronSetting(setting))
|
||||||
{
|
{
|
||||||
_logger.LogError("Backup Task has invalid cron, defaulting to Daily");
|
_logger.LogError("Backup Task has invalid cron, defaulting to Weekly");
|
||||||
RecurringJob.AddOrUpdate(BackupTaskId, () => _backupService.BackupDatabase(),
|
RecurringJob.AddOrUpdate(BackupTaskId, () => _backupService.BackupDatabase(),
|
||||||
Cron.Weekly, RecurringJobOptions);
|
Cron.Weekly, RecurringJobOptions);
|
||||||
}
|
}
|
||||||
@ -161,18 +162,18 @@ public class TaskScheduler : ITaskScheduler
|
|||||||
}
|
}
|
||||||
|
|
||||||
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskCleanup)).Value;
|
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskCleanup)).Value;
|
||||||
if (setting == null || (!nonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting)))
|
if (IsInvalidCronSetting(setting))
|
||||||
{
|
|
||||||
_logger.LogDebug("Scheduling Cleanup Task for {Setting}", setting);
|
|
||||||
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
|
||||||
CronConverter.ConvertToCronNotation(setting), RecurringJobOptions);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_logger.LogError("Cleanup Task has invalid cron, defaulting to Daily");
|
_logger.LogError("Cleanup Task has invalid cron, defaulting to Daily");
|
||||||
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
||||||
Cron.Daily, RecurringJobOptions);
|
Cron.Daily, RecurringJobOptions);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Scheduling Cleanup Task for {Setting}", setting);
|
||||||
|
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
||||||
|
CronConverter.ConvertToCronNotation(setting), RecurringJobOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RecurringJob.AddOrUpdate(RemoveFromWantToReadTaskId, () => _cleanupService.CleanupWantToRead(),
|
RecurringJob.AddOrUpdate(RemoveFromWantToReadTaskId, () => _cleanupService.CleanupWantToRead(),
|
||||||
@ -186,6 +187,11 @@ public class TaskScheduler : ITaskScheduler
|
|||||||
await ScheduleKavitaPlusTasks();
|
await ScheduleKavitaPlusTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsInvalidCronSetting(string setting)
|
||||||
|
{
|
||||||
|
return setting == null || (!NonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ScheduleKavitaPlusTasks()
|
public async Task ScheduleKavitaPlusTasks()
|
||||||
{
|
{
|
||||||
// KavitaPlus based (needs license check)
|
// KavitaPlus based (needs license check)
|
||||||
|
1
UI/Web/src/app/_models/default-modal-options.ts
Normal file
1
UI/Web/src/app/_models/default-modal-options.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const DefaultModalOptions = {scrollable: true, size: 'xl', fullscreen: 'xl'};
|
@ -1,6 +1,6 @@
|
|||||||
import {inject, Pipe, PipeTransform} from '@angular/core';
|
import {inject, Pipe, PipeTransform} from '@angular/core';
|
||||||
import { PersonRole } from '../_models/metadata/person';
|
import { PersonRole } from '../_models/metadata/person';
|
||||||
import {TranslocoService} from "@jsverse/transloco";
|
import {translate, TranslocoService} from "@jsverse/transloco";
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'personRole',
|
name: 'personRole',
|
||||||
@ -8,39 +8,38 @@ import {TranslocoService} from "@jsverse/transloco";
|
|||||||
})
|
})
|
||||||
export class PersonRolePipe implements PipeTransform {
|
export class PersonRolePipe implements PipeTransform {
|
||||||
|
|
||||||
translocoService = inject(TranslocoService);
|
|
||||||
transform(value: PersonRole): string {
|
transform(value: PersonRole): string {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case PersonRole.Artist:
|
case PersonRole.Artist:
|
||||||
return this.translocoService.translate('person-role-pipe.artist');
|
return translate('person-role-pipe.artist');
|
||||||
case PersonRole.Character:
|
case PersonRole.Character:
|
||||||
return this.translocoService.translate('person-role-pipe.character');
|
return translate('person-role-pipe.character');
|
||||||
case PersonRole.Colorist:
|
case PersonRole.Colorist:
|
||||||
return this.translocoService.translate('person-role-pipe.colorist');
|
return translate('person-role-pipe.colorist');
|
||||||
case PersonRole.CoverArtist:
|
case PersonRole.CoverArtist:
|
||||||
return this.translocoService.translate('person-role-pipe.artist');
|
return translate('person-role-pipe.artist');
|
||||||
case PersonRole.Editor:
|
case PersonRole.Editor:
|
||||||
return this.translocoService.translate('person-role-pipe.editor');
|
return translate('person-role-pipe.editor');
|
||||||
case PersonRole.Inker:
|
case PersonRole.Inker:
|
||||||
return this.translocoService.translate('person-role-pipe.inker');
|
return translate('person-role-pipe.inker');
|
||||||
case PersonRole.Letterer:
|
case PersonRole.Letterer:
|
||||||
return this.translocoService.translate('person-role-pipe.letterer');
|
return translate('person-role-pipe.letterer');
|
||||||
case PersonRole.Penciller:
|
case PersonRole.Penciller:
|
||||||
return this.translocoService.translate('person-role-pipe.penciller');
|
return translate('person-role-pipe.penciller');
|
||||||
case PersonRole.Publisher:
|
case PersonRole.Publisher:
|
||||||
return this.translocoService.translate('person-role-pipe.publisher');
|
return translate('person-role-pipe.publisher');
|
||||||
case PersonRole.Imprint:
|
case PersonRole.Imprint:
|
||||||
return this.translocoService.translate('person-role-pipe.imprint');
|
return translate('person-role-pipe.imprint');
|
||||||
case PersonRole.Writer:
|
case PersonRole.Writer:
|
||||||
return this.translocoService.translate('person-role-pipe.writer');
|
return translate('person-role-pipe.writer');
|
||||||
case PersonRole.Team:
|
case PersonRole.Team:
|
||||||
return this.translocoService.translate('person-role-pipe.team');
|
return translate('person-role-pipe.team');
|
||||||
case PersonRole.Location:
|
case PersonRole.Location:
|
||||||
return this.translocoService.translate('person-role-pipe.location');
|
return translate('person-role-pipe.location');
|
||||||
case PersonRole.Translator:
|
case PersonRole.Translator:
|
||||||
return this.translocoService.translate('person-role-pipe.translator');
|
return translate('person-role-pipe.translator');
|
||||||
case PersonRole.Other:
|
case PersonRole.Other:
|
||||||
return this.translocoService.translate('person-role-pipe.other');
|
return translate('person-role-pipe.other');
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import {FilterService} from "./filter.service";
|
|||||||
import {ReadingListService} from "./reading-list.service";
|
import {ReadingListService} from "./reading-list.service";
|
||||||
import {ChapterService} from "./chapter.service";
|
import {ChapterService} from "./chapter.service";
|
||||||
import {VolumeService} from "./volume.service";
|
import {VolumeService} from "./volume.service";
|
||||||
|
import {DefaultModalOptions} from "../_models/default-modal-options";
|
||||||
|
|
||||||
export type LibraryActionCallback = (library: Partial<Library>) => void;
|
export type LibraryActionCallback = (library: Partial<Library>) => void;
|
||||||
export type SeriesActionCallback = (series: Series) => void;
|
export type SeriesActionCallback = (series: Series) => void;
|
||||||
@ -121,7 +122,7 @@ export class ActionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
editLibrary(library: Partial<Library>, callback?: LibraryActionCallback) {
|
editLibrary(library: Partial<Library>, callback?: LibraryActionCallback) {
|
||||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, {size: 'xl', fullscreen: 'md'});
|
const modalRef = this.modalService.open(LibrarySettingsModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.library = library;
|
modalRef.componentInstance.library = library;
|
||||||
modalRef.closed.subscribe((closeResult: {success: boolean, library: Library, coverImageUpdate: boolean}) => {
|
modalRef.closed.subscribe((closeResult: {success: boolean, library: Library, coverImageUpdate: boolean}) => {
|
||||||
if (callback) callback(library)
|
if (callback) callback(library)
|
||||||
|
@ -16,7 +16,8 @@ export class JumpbarService {
|
|||||||
|
|
||||||
|
|
||||||
getResumeKey(key: string) {
|
getResumeKey(key: string) {
|
||||||
if (this.resumeKeys.hasOwnProperty(key)) return this.resumeKeys[key];
|
const k = key.toUpperCase();
|
||||||
|
if (this.resumeKeys.hasOwnProperty(k)) return this.resumeKeys[k];
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +27,8 @@ export class JumpbarService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveResumeKey(key: string, value: string) {
|
saveResumeKey(key: string, value: string) {
|
||||||
this.resumeKeys[key] = value;
|
const k = key.toUpperCase();
|
||||||
|
this.resumeKeys[k] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveResumePosition(url: string, value: number) {
|
saveResumePosition(url: string, value: number) {
|
||||||
@ -75,9 +77,11 @@ export class JumpbarService {
|
|||||||
|
|
||||||
_removeFirstPartOfJumpBar(midPoint: number, numberOfRemovals: number = 1, jumpBarKeys: Array<JumpKey>, jumpBarKeysToRender: Array<JumpKey>) {
|
_removeFirstPartOfJumpBar(midPoint: number, numberOfRemovals: number = 1, jumpBarKeys: Array<JumpKey>, jumpBarKeysToRender: Array<JumpKey>) {
|
||||||
const removedIndexes: Array<number> = [];
|
const removedIndexes: Array<number> = [];
|
||||||
|
|
||||||
for(let removal = 0; removal < numberOfRemovals; removal++) {
|
for(let removal = 0; removal < numberOfRemovals; removal++) {
|
||||||
let min = 100000000;
|
let min = 100000000;
|
||||||
let minIndex = -1;
|
let minIndex = -1;
|
||||||
|
|
||||||
for(let i = 1; i < midPoint; i++) {
|
for(let i = 1; i < midPoint; i++) {
|
||||||
if (jumpBarKeys[i].size < min && !removedIndexes.includes(i)) {
|
if (jumpBarKeys[i].size < min && !removedIndexes.includes(i)) {
|
||||||
min = jumpBarKeys[i].size;
|
min = jumpBarKeys[i].size;
|
||||||
@ -101,7 +105,7 @@ export class JumpbarService {
|
|||||||
getJumpKeys(data :Array<any>, keySelector: (data: any) => string) {
|
getJumpKeys(data :Array<any>, keySelector: (data: any) => string) {
|
||||||
const keys: {[key: string]: number} = {};
|
const keys: {[key: string]: number} = {};
|
||||||
data.forEach(obj => {
|
data.forEach(obj => {
|
||||||
let ch = keySelector(obj).charAt(0);
|
let ch = keySelector(obj).charAt(0).toUpperCase();
|
||||||
if (/\d|\#|!|%|@|\(|\)|\^|\.|_|\*/g.test(ch)) {
|
if (/\d|\#|!|%|@|\(|\)|\^|\.|_|\*/g.test(ch)) {
|
||||||
ch = '#';
|
ch = '#';
|
||||||
}
|
}
|
||||||
@ -111,10 +115,11 @@ export class JumpbarService {
|
|||||||
keys[ch] += 1;
|
keys[ch] += 1;
|
||||||
});
|
});
|
||||||
return Object.keys(keys).map(k => {
|
return Object.keys(keys).map(k => {
|
||||||
|
k = k.toUpperCase();
|
||||||
return {
|
return {
|
||||||
key: k,
|
key: k,
|
||||||
size: keys[k],
|
size: keys[k],
|
||||||
title: k.toUpperCase()
|
title: k
|
||||||
}
|
}
|
||||||
}).sort((a, b) => {
|
}).sort((a, b) => {
|
||||||
if (a.key < b.key) return -1;
|
if (a.key < b.key) return -1;
|
||||||
|
@ -29,8 +29,8 @@ export class PersonService {
|
|||||||
return this.httpClient.get<Person>(this.baseUrl + `person?name=${name}`);
|
return this.httpClient.get<Person>(this.baseUrl + `person?name=${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRolesForPerson(name: string) {
|
getRolesForPerson(personId: number) {
|
||||||
return this.httpClient.get<Array<PersonRole>>(this.baseUrl + `person/roles?name=${name}`);
|
return this.httpClient.get<Array<PersonRole>>(this.baseUrl + `person/roles?personId=${personId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSeriesMostKnownFor(personId: number) {
|
getSeriesMostKnownFor(personId: number) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="publisher-side publisher-front">
|
<div class="publisher-side publisher-front">
|
||||||
<div class="publisher-img-container d-inline-flex align-items-center me-2 position-relative">
|
<div class="publisher-img-container d-inline-flex align-items-center me-2 position-relative">
|
||||||
<app-image
|
<app-image
|
||||||
[imageUrl]="imageService.getPersonImage(currentPublisher!.id)"
|
[imageUrl]="imageService.getPublisherImage(currentPublisher!.name)"
|
||||||
[classes]="'me-2'"
|
[classes]="'me-2'"
|
||||||
[hideOnError]="true"
|
[hideOnError]="true"
|
||||||
width="32px"
|
width="32px"
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<div class="publisher-side publisher-back">
|
<div class="publisher-side publisher-back">
|
||||||
<div class="publisher-img-container d-inline-flex align-items-center me-2 position-relative">
|
<div class="publisher-img-container d-inline-flex align-items-center me-2 position-relative">
|
||||||
<app-image
|
<app-image
|
||||||
[imageUrl]="imageService.getPersonImage(nextPublisher!.id)"
|
[imageUrl]="imageService.getPublisherImage(nextPublisher!.name)"
|
||||||
[classes]="'me-2'"
|
[classes]="'me-2'"
|
||||||
[hideOnError]="true"
|
[hideOnError]="true"
|
||||||
width="32px"
|
width="32px"
|
||||||
|
@ -1,18 +1,33 @@
|
|||||||
//.publisher-flipper-container {
|
|
||||||
// perspective: 1000px;
|
|
||||||
//}
|
|
||||||
//
|
//
|
||||||
//.publisher-img-container {
|
//.publisher-img-container {
|
||||||
// transform-style: preserve-3d;
|
// background-color: var(--card-bg-color);
|
||||||
// transition: transform 0.5s;
|
// border-radius: 3px;
|
||||||
|
// padding: 2px 5px;
|
||||||
|
// font-size: 0.8rem;
|
||||||
|
// vertical-align: middle;
|
||||||
|
//
|
||||||
|
// div {
|
||||||
|
// min-height: 32px;
|
||||||
|
// line-height: 32px;
|
||||||
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
// Animation code
|
||||||
// jumpbar example
|
|
||||||
|
|
||||||
.publisher-wrapper {
|
.publisher-wrapper {
|
||||||
perspective: 1000px;
|
perspective: 1000px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
||||||
|
background-color: var(--card-bg-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
div {
|
||||||
|
min-height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.publisher-flipper {
|
.publisher-flipper {
|
||||||
@ -20,7 +35,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
transition: transform 0.6s;
|
transition: transform 0.6s ease;
|
||||||
transform-style: preserve-3d;
|
transform-style: preserve-3d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +48,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
transform-style: preserve-3d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.publisher-front {
|
.publisher-front {
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, Input, OnDestroy, OnInit} from '@angular/core';
|
import {
|
||||||
|
AfterViewChecked,
|
||||||
|
AfterViewInit,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
inject,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit
|
||||||
|
} from '@angular/core';
|
||||||
import {ImageComponent} from "../../shared/image/image.component";
|
import {ImageComponent} from "../../shared/image/image.component";
|
||||||
import {FilterField} from "../../_models/metadata/v2/filter-field";
|
import {FilterField} from "../../_models/metadata/v2/filter-field";
|
||||||
import {Person} from "../../_models/metadata/person";
|
import {Person} from "../../_models/metadata/person";
|
||||||
@ -19,7 +29,7 @@ const ANIMATION_TIME = 3000;
|
|||||||
styleUrl: './publisher-flipper.component.scss',
|
styleUrl: './publisher-flipper.component.scss',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class PublisherFlipperComponent implements OnInit, OnDestroy {
|
export class PublisherFlipperComponent implements OnInit, OnDestroy, AfterViewInit, AfterViewChecked {
|
||||||
|
|
||||||
protected readonly imageService = inject(ImageService);
|
protected readonly imageService = inject(ImageService);
|
||||||
private readonly filterUtilityService = inject(FilterUtilitiesService);
|
private readonly filterUtilityService = inject(FilterUtilitiesService);
|
||||||
@ -36,14 +46,26 @@ export class PublisherFlipperComponent implements OnInit, OnDestroy {
|
|||||||
isFlipped = false;
|
isFlipped = false;
|
||||||
private intervalId: any;
|
private intervalId: any;
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.publishers.length > 0) {
|
if (this.publishers.length > 0) {
|
||||||
this.currentPublisher = this.publishers[0];
|
this.currentPublisher = this.publishers[0];
|
||||||
this.nextPublisher = this.publishers[1] || this.publishers[0];
|
this.nextPublisher = this.publishers[1] || this.publishers[0];
|
||||||
if (this.publishers.length > 1) {
|
}
|
||||||
this.startFlipping();
|
}
|
||||||
}
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
if (this.publishers.length > 1) {
|
||||||
|
this.startFlipping(); // Start flipping cycle once the view is initialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewChecked() {
|
||||||
|
// This lifecycle hook will be called after Angular performs change detection in each cycle
|
||||||
|
if (this.isFlipped) {
|
||||||
|
// Only update publishers after the flip is complete
|
||||||
|
this.currentIndex = (this.currentIndex + 1) % this.publishers.length;
|
||||||
|
this.currentPublisher = this.publishers[this.currentIndex];
|
||||||
|
this.nextPublisher = this.publishers[(this.currentIndex + 1) % this.publishers.length];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,22 +77,9 @@ export class PublisherFlipperComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private startFlipping() {
|
private startFlipping() {
|
||||||
this.intervalId = setInterval(() => {
|
this.intervalId = setInterval(() => {
|
||||||
// First flip
|
// Toggle flip state, initiating the flip animation
|
||||||
this.isFlipped = true;
|
this.isFlipped = !this.isFlipped;
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.detectChanges(); // Explicitly detect changes to trigger re-render
|
||||||
|
|
||||||
// Update content after flip animation completes
|
|
||||||
setTimeout(() => {
|
|
||||||
// Update indices and content
|
|
||||||
this.currentIndex = (this.currentIndex + 1) % this.publishers.length;
|
|
||||||
this.currentPublisher = this.publishers[this.currentIndex];
|
|
||||||
this.nextPublisher = this.publishers[(this.currentIndex + 1) % this.publishers.length];
|
|
||||||
|
|
||||||
// Reset flip
|
|
||||||
this.isFlipped = false;
|
|
||||||
|
|
||||||
this.cdRef.markForCheck();
|
|
||||||
}, ANIMATION_TIME); // Full transition time to ensure flip completes
|
|
||||||
}, ANIMATION_TIME);
|
}, ANIMATION_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import {DefaultDatePipe} from "../../_pipes/default-date.pipe";
|
|||||||
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
||||||
import {TranslocoLocaleModule} from "@jsverse/transloco-locale";
|
import {TranslocoLocaleModule} from "@jsverse/transloco-locale";
|
||||||
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
||||||
|
import {DefaultModalOptions} from "../../_models/default-modal-options";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-manage-scrobble-errors',
|
selector: 'app-manage-scrobble-errors',
|
||||||
@ -111,7 +112,7 @@ export class ManageScrobbleErrorsComponent implements OnInit {
|
|||||||
|
|
||||||
editSeries(seriesId: number) {
|
editSeries(seriesId: number) {
|
||||||
this.seriesService.getSeries(seriesId).subscribe(series => {
|
this.seriesService.getSeries(seriesId).subscribe(series => {
|
||||||
const modalRef = this.modalService.open(EditSeriesModalComponent, { size: 'xl' });
|
const modalRef = this.modalService.open(EditSeriesModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.series = series;
|
modalRef.componentInstance.series = series;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
|||||||
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
|
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
|
||||||
import {ConfirmService} from "../../shared/confirm.service";
|
import {ConfirmService} from "../../shared/confirm.service";
|
||||||
import {SettingButtonComponent} from "../../settings/_components/setting-button/setting-button.component";
|
import {SettingButtonComponent} from "../../settings/_components/setting-button/setting-button.component";
|
||||||
|
import {DefaultModalOptions} from "../../_models/default-modal-options";
|
||||||
|
|
||||||
interface AdhocTask {
|
interface AdhocTask {
|
||||||
name: string;
|
name: string;
|
||||||
@ -128,7 +129,7 @@ export class ManageTasksSettingsComponent implements OnInit {
|
|||||||
this.toastr.info(translate('toasts.no-updates'));
|
this.toastr.info(translate('toasts.no-updates'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const modalRef = this.modalService.open(UpdateNotificationModalComponent, { scrollable: true, size: 'lg' });
|
const modalRef = this.modalService.open(UpdateNotificationModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.updateData = update;
|
modalRef.componentInstance.updateData = update;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -22,6 +22,7 @@ import {makeBindingParser} from "@angular/compiler";
|
|||||||
import {LoadingComponent} from "../../shared/loading/loading.component";
|
import {LoadingComponent} from "../../shared/loading/loading.component";
|
||||||
import {TimeAgoPipe} from "../../_pipes/time-ago.pipe";
|
import {TimeAgoPipe} from "../../_pipes/time-ago.pipe";
|
||||||
import {SentenceCasePipe} from "../../_pipes/sentence-case.pipe";
|
import {SentenceCasePipe} from "../../_pipes/sentence-case.pipe";
|
||||||
|
import {DefaultModalOptions} from "../../_models/default-modal-options";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-manage-users',
|
selector: 'app-manage-users',
|
||||||
@ -87,7 +88,7 @@ export class ManageUsersComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditUser(member: Member) {
|
openEditUser(member: Member) {
|
||||||
const modalRef = this.modalService.open(EditUserComponent, { scrollable: true, size: 'xl', fullscreen: 'md' });
|
const modalRef = this.modalService.open(EditUserComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.member = member;
|
modalRef.componentInstance.member = member;
|
||||||
modalRef.closed.subscribe(() => {
|
modalRef.closed.subscribe(() => {
|
||||||
this.loadMembers();
|
this.loadMembers();
|
||||||
@ -107,7 +108,7 @@ export class ManageUsersComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inviteUser() {
|
inviteUser() {
|
||||||
const modalRef = this.modalService.open(InviteUserComponent, {size: 'xl'});
|
const modalRef = this.modalService.open(InviteUserComponent, DefaultModalOptions);
|
||||||
modalRef.closed.subscribe((successful: boolean) => {
|
modalRef.closed.subscribe((successful: boolean) => {
|
||||||
this.loadMembers();
|
this.loadMembers();
|
||||||
});
|
});
|
||||||
@ -133,7 +134,7 @@ export class ManageUsersComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePassword(member: Member) {
|
updatePassword(member: Member) {
|
||||||
const modalRef = this.modalService.open(ResetPasswordModalComponent);
|
const modalRef = this.modalService.open(ResetPasswordModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.member = member;
|
modalRef.componentInstance.member = member;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ import {User} from "../../_models/user";
|
|||||||
import {ScrollService} from "../../_services/scroll.service";
|
import {ScrollService} from "../../_services/scroll.service";
|
||||||
import {ReaderService} from "../../_services/reader.service";
|
import {ReaderService} from "../../_services/reader.service";
|
||||||
import {SeriesFormatComponent} from "../../shared/series-format/series-format.component";
|
import {SeriesFormatComponent} from "../../shared/series-format/series-format.component";
|
||||||
|
import {DefaultModalOptions} from "../../_models/default-modal-options";
|
||||||
|
|
||||||
function deepClone(obj: any): any {
|
function deepClone(obj: any): any {
|
||||||
if (obj === null || typeof obj !== 'object') {
|
if (obj === null || typeof obj !== 'object') {
|
||||||
@ -278,7 +279,7 @@ export class SeriesCardComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditModal(data: Series) {
|
openEditModal(data: Series) {
|
||||||
const modalRef = this.modalService.open(EditSeriesModalComponent, { size: 'lg' });
|
const modalRef = this.modalService.open(EditSeriesModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.series = data;
|
modalRef.componentInstance.series = data;
|
||||||
modalRef.closed.subscribe((closeResult: {success: boolean, series: Series, coverImageUpdate: boolean}) => {
|
modalRef.closed.subscribe((closeResult: {success: boolean, series: Series, coverImageUpdate: boolean}) => {
|
||||||
if (closeResult.success) {
|
if (closeResult.success) {
|
||||||
|
@ -83,6 +83,7 @@ import {PublicationStatusPipe} from "../_pipes/publication-status.pipe";
|
|||||||
import {DefaultDatePipe} from "../_pipes/default-date.pipe";
|
import {DefaultDatePipe} from "../_pipes/default-date.pipe";
|
||||||
import {MangaFormatPipe} from "../_pipes/manga-format.pipe";
|
import {MangaFormatPipe} from "../_pipes/manga-format.pipe";
|
||||||
import {CoverImageComponent} from "../_single-module/cover-image/cover-image.component";
|
import {CoverImageComponent} from "../_single-module/cover-image/cover-image.component";
|
||||||
|
import {DefaultModalOptions} from "../_models/default-modal-options";
|
||||||
|
|
||||||
enum TabID {
|
enum TabID {
|
||||||
Related = 'related-tab',
|
Related = 'related-tab',
|
||||||
@ -317,7 +318,7 @@ export class ChapterDetailComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditModal() {
|
openEditModal() {
|
||||||
const ref = this.modalService.open(EditChapterModalComponent, { size: 'xl' });
|
const ref = this.modalService.open(EditChapterModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.chapter = this.chapter;
|
ref.componentInstance.chapter = this.chapter;
|
||||||
ref.componentInstance.libraryType = this.libraryType;
|
ref.componentInstance.libraryType = this.libraryType;
|
||||||
ref.componentInstance.libraryId = this.libraryId;
|
ref.componentInstance.libraryId = this.libraryId;
|
||||||
|
@ -42,6 +42,7 @@ import {SeriesCardComponent} from "../../../cards/series-card/series-card.compon
|
|||||||
import {ActionService} from "../../../_services/action.service";
|
import {ActionService} from "../../../_services/action.service";
|
||||||
import {KEY_CODES} from "../../../shared/_services/utility.service";
|
import {KEY_CODES} from "../../../shared/_services/utility.service";
|
||||||
import {WikiLink} from "../../../_models/wiki";
|
import {WikiLink} from "../../../_models/wiki";
|
||||||
|
import {DefaultModalOptions} from "../../../_models/default-modal-options";
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -153,7 +154,7 @@ export class AllCollectionsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case(Action.Edit):
|
case(Action.Edit):
|
||||||
const modalRef = this.modalService.open(EditCollectionTagsComponent, { size: 'lg', scrollable: true });
|
const modalRef = this.modalService.open(EditCollectionTagsComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.tag = collectionTag;
|
modalRef.componentInstance.tag = collectionTag;
|
||||||
modalRef.closed.subscribe((results: {success: boolean, coverImageUpdated: boolean}) => {
|
modalRef.closed.subscribe((results: {success: boolean, coverImageUpdated: boolean}) => {
|
||||||
if (results.success) {
|
if (results.success) {
|
||||||
|
@ -64,6 +64,7 @@ import {PromotedIconComponent} from "../../../shared/_components/promoted-icon/p
|
|||||||
import {
|
import {
|
||||||
SmartCollectionDrawerComponent
|
SmartCollectionDrawerComponent
|
||||||
} from "../../../_single-module/smart-collection-drawer/smart-collection-drawer.component";
|
} from "../../../_single-module/smart-collection-drawer/smart-collection-drawer.component";
|
||||||
|
import {DefaultModalOptions} from "../../../_models/default-modal-options";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-collection-detail',
|
selector: 'app-collection-detail',
|
||||||
@ -330,7 +331,7 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditCollectionTagModal(collectionTag: UserCollection) {
|
openEditCollectionTagModal(collectionTag: UserCollection) {
|
||||||
const modalRef = this.modalService.open(EditCollectionTagsComponent, { size: 'lg', scrollable: true });
|
const modalRef = this.modalService.open(EditCollectionTagsComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.tag = this.collectionTag;
|
modalRef.componentInstance.tag = this.collectionTag;
|
||||||
modalRef.closed.subscribe((results: {success: boolean, coverImageUpdated: boolean}) => {
|
modalRef.closed.subscribe((results: {success: boolean, coverImageUpdated: boolean}) => {
|
||||||
this.updateTag(this.collectionTag.id);
|
this.updateTag(this.collectionTag.id);
|
||||||
|
@ -26,6 +26,7 @@ import { SentenceCasePipe } from '../../../_pipes/sentence-case.pipe';
|
|||||||
import { CircularLoaderComponent } from '../../../shared/circular-loader/circular-loader.component';
|
import { CircularLoaderComponent } from '../../../shared/circular-loader/circular-loader.component';
|
||||||
import { NgClass, NgStyle, AsyncPipe } from '@angular/common';
|
import { NgClass, NgStyle, AsyncPipe } from '@angular/common';
|
||||||
import {TranslocoDirective} from "@jsverse/transloco";
|
import {TranslocoDirective} from "@jsverse/transloco";
|
||||||
|
import {DefaultModalOptions} from "../../../_models/default-modal-options";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-nav-events-toggle',
|
selector: 'app-nav-events-toggle',
|
||||||
@ -159,7 +160,7 @@ export class EventsWidgetComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
handleUpdateAvailableClick(message: NotificationProgressEvent | UpdateVersionEvent) {
|
handleUpdateAvailableClick(message: NotificationProgressEvent | UpdateVersionEvent) {
|
||||||
if (this.updateNotificationModalRef != null) { return; }
|
if (this.updateNotificationModalRef != null) { return; }
|
||||||
this.updateNotificationModalRef = this.modalService.open(UpdateNotificationModalComponent, { scrollable: true, size: 'lg' });
|
this.updateNotificationModalRef = this.modalService.open(UpdateNotificationModalComponent, DefaultModalOptions);
|
||||||
if (message.hasOwnProperty('body')) {
|
if (message.hasOwnProperty('body')) {
|
||||||
this.updateNotificationModalRef.componentInstance.updateData = (message as NotificationProgressEvent).body as UpdateVersionEvent;
|
this.updateNotificationModalRef.componentInstance.updateData = (message as NotificationProgressEvent).body as UpdateVersionEvent;
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,6 +38,7 @@ import {EditPersonModalComponent} from "./_modal/edit-person-modal/edit-person-m
|
|||||||
import {translate, TranslocoDirective} from "@jsverse/transloco";
|
import {translate, TranslocoDirective} from "@jsverse/transloco";
|
||||||
import {ChapterCardComponent} from "../cards/chapter-card/chapter-card.component";
|
import {ChapterCardComponent} from "../cards/chapter-card/chapter-card.component";
|
||||||
import {ThemeService} from "../_services/theme.service";
|
import {ThemeService} from "../_services/theme.service";
|
||||||
|
import {DefaultModalOptions} from "../_models/default-modal-options";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-person-detail',
|
selector: 'app-person-detail',
|
||||||
@ -109,7 +110,7 @@ export class PersonDetailComponent {
|
|||||||
this.themeService.setColorScape(person.primaryColor || '', person.secondaryColor);
|
this.themeService.setColorScape(person.primaryColor || '', person.secondaryColor);
|
||||||
|
|
||||||
// Fetch roles and process them
|
// Fetch roles and process them
|
||||||
this.roles$ = this.personService.getRolesForPerson(this.personName).pipe(
|
this.roles$ = this.personService.getRolesForPerson(this.person.id).pipe(
|
||||||
tap(roles => {
|
tap(roles => {
|
||||||
this.roles = roles;
|
this.roles = roles;
|
||||||
this.filter = this.createFilter(roles);
|
this.filter = this.createFilter(roles);
|
||||||
@ -187,7 +188,7 @@ export class PersonDetailComponent {
|
|||||||
handleAction(action: ActionItem<Person>, person: Person) {
|
handleAction(action: ActionItem<Person>, person: Person) {
|
||||||
switch (action.action) {
|
switch (action.action) {
|
||||||
case(Action.Edit):
|
case(Action.Edit):
|
||||||
const ref = this.modalService.open(EditPersonModalComponent, {scrollable: true, size: 'lg', fullscreen: 'md'});
|
const ref = this.modalService.open(EditPersonModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.person = this.person;
|
ref.componentInstance.person = this.person;
|
||||||
|
|
||||||
ref.closed.subscribe(r => {
|
ref.closed.subscribe(r => {
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
<app-image [imageUrl]="imageService.getPublisherImage(entity.publishers[0].name)" [classes]="'me-2'" [hideOnError]="true" width="32px" height="32px"
|
<app-image [imageUrl]="imageService.getPublisherImage(entity.publishers[0].name)" [classes]="'me-2'" [hideOnError]="true" width="32px" height="32px"
|
||||||
aria-hidden="true"></app-image>
|
aria-hidden="true"></app-image>
|
||||||
<div class="position-relative d-inline-block" (click)="openGeneric(FilterField.Publisher, entity.publishers[0].id)">{{entity.publishers[0].name}}</div>
|
<div class="position-relative d-inline-block" (click)="openGeneric(FilterField.Publisher, entity.publishers[0].id)">{{entity.publishers[0].name}}</div>
|
||||||
|
<!-- <app-publisher-flipper [publishers]="entity.publishers"></app-publisher-flipper>-->
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<!-- TODO: Figure out if I can implement this animation (ROBBIE)-->
|
|
||||||
<!-- <app-publisher-flipper [publishers]="entity.publishers"></app-publisher-flipper>-->
|
|
||||||
<span class="me-2">
|
<span class="me-2">
|
||||||
<app-age-rating-image [rating]="ageRating"></app-age-rating-image>
|
<app-age-rating-image [rating]="ageRating"></app-age-rating-image>
|
||||||
</span>
|
</span>
|
||||||
@ -17,7 +16,7 @@
|
|||||||
<app-series-format [format]="mangaFormat" [useTitle]="false"></app-series-format>
|
<app-series-format [format]="mangaFormat" [useTitle]="false"></app-series-format>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@if (libraryType === LibraryType.Book || libraryType === LibraryType.LightNovel) {
|
@if ((libraryType === LibraryType.Book || libraryType === LibraryType.LightNovel) && mangaFormat !== MangaFormat.PDF) {
|
||||||
<span class="word-count me-3">{{t('words-count', {num: readingTimeEntity.wordCount | compactNumber})}}</span>
|
<span class="word-count me-3">{{t('words-count', {num: readingTimeEntity.wordCount | compactNumber})}}</span>
|
||||||
} @else {
|
} @else {
|
||||||
<span class="word-count me-3">{{t('pages-count', {num: readingTimeEntity.pages | compactNumber})}}</span>
|
<span class="word-count me-3">{{t('pages-count', {num: readingTimeEntity.pages | compactNumber})}}</span>
|
||||||
|
@ -46,6 +46,8 @@ export class MetadataDetailRowComponent {
|
|||||||
private readonly filterUtilityService = inject(FilterUtilitiesService);
|
private readonly filterUtilityService = inject(FilterUtilitiesService);
|
||||||
|
|
||||||
protected readonly LibraryType = LibraryType;
|
protected readonly LibraryType = LibraryType;
|
||||||
|
protected readonly FilterField = FilterField;
|
||||||
|
protected readonly MangaFormat = MangaFormat;
|
||||||
|
|
||||||
@Input({required: true}) entity!: IHasCast;
|
@Input({required: true}) entity!: IHasCast;
|
||||||
@Input({required: true}) readingTimeEntity!: IHasReadingTime;
|
@Input({required: true}) readingTimeEntity!: IHasReadingTime;
|
||||||
@ -59,7 +61,4 @@ export class MetadataDetailRowComponent {
|
|||||||
if (queryParamName === FilterField.None) return;
|
if (queryParamName === FilterField.None) return;
|
||||||
this.filterUtilityService.applyFilter(['all-series'], queryParamName, FilterComparison.Equal, `${filter}`).subscribe();
|
this.filterUtilityService.applyFilter(['all-series'], queryParamName, FilterComparison.Equal, `${filter}`).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected readonly FilterField = FilterField;
|
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,7 @@ import {UserCollection} from "../../../_models/collection-tag";
|
|||||||
import {SeriesFormatComponent} from "../../../shared/series-format/series-format.component";
|
import {SeriesFormatComponent} from "../../../shared/series-format/series-format.component";
|
||||||
import {MangaFormatPipe} from "../../../_pipes/manga-format.pipe";
|
import {MangaFormatPipe} from "../../../_pipes/manga-format.pipe";
|
||||||
import {CoverImageComponent} from "../../../_single-module/cover-image/cover-image.component";
|
import {CoverImageComponent} from "../../../_single-module/cover-image/cover-image.component";
|
||||||
|
import {DefaultModalOptions} from "../../../_models/default-modal-options";
|
||||||
|
|
||||||
|
|
||||||
enum TabID {
|
enum TabID {
|
||||||
@ -1041,7 +1042,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditChapter(chapter: Chapter) {
|
openEditChapter(chapter: Chapter) {
|
||||||
const ref = this.modalService.open(EditChapterModalComponent, { size: 'xl' });
|
const ref = this.modalService.open(EditChapterModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.chapter = chapter;
|
ref.componentInstance.chapter = chapter;
|
||||||
ref.componentInstance.libraryType = this.libraryType;
|
ref.componentInstance.libraryType = this.libraryType;
|
||||||
ref.componentInstance.seriesId = this.series?.id;
|
ref.componentInstance.seriesId = this.series?.id;
|
||||||
@ -1055,7 +1056,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditVolume(volume: Volume) {
|
openEditVolume(volume: Volume) {
|
||||||
const ref = this.modalService.open(EditVolumeModalComponent, { size: 'xl' });
|
const ref = this.modalService.open(EditVolumeModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.volume = volume;
|
ref.componentInstance.volume = volume;
|
||||||
ref.componentInstance.libraryType = this.libraryType;
|
ref.componentInstance.libraryType = this.libraryType;
|
||||||
ref.componentInstance.seriesId = this.series?.id;
|
ref.componentInstance.seriesId = this.series?.id;
|
||||||
@ -1069,7 +1070,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditSeriesModal() {
|
openEditSeriesModal() {
|
||||||
const modalRef = this.modalService.open(EditSeriesModalComponent, { size: 'xl' });
|
const modalRef = this.modalService.open(EditSeriesModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.series = this.series;
|
modalRef.componentInstance.series = this.series;
|
||||||
modalRef.closed.subscribe((closeResult: EditSeriesModalCloseResult) => {
|
modalRef.closed.subscribe((closeResult: EditSeriesModalCloseResult) => {
|
||||||
if (closeResult.success) {
|
if (closeResult.success) {
|
||||||
@ -1088,7 +1089,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||||||
openReviewModal() {
|
openReviewModal() {
|
||||||
const userReview = this.getUserReview();
|
const userReview = this.getUserReview();
|
||||||
|
|
||||||
const modalRef = this.modalService.open(ReviewSeriesModalComponent, { scrollable: true, size: 'lg' });
|
const modalRef = this.modalService.open(ReviewSeriesModalComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.series = this.series;
|
modalRef.componentInstance.series = this.series;
|
||||||
if (userReview.length > 0) {
|
if (userReview.length > 0) {
|
||||||
modalRef.componentInstance.review = userReview[0];
|
modalRef.componentInstance.review = userReview[0];
|
||||||
|
@ -2,13 +2,16 @@
|
|||||||
<div class="tagbadge cursor clickable">
|
<div class="tagbadge cursor clickable">
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
@if (HasCoverImage) {
|
@if (HasCoverImage) {
|
||||||
<app-image height="24px" width="24px" [styles]="{'object-fit': 'contain'}"
|
<div class="mx-auto">
|
||||||
classes="align-self-center text-center mb-2"
|
<app-image height="24px" width="24px" [styles]="{'background': 'none', 'max-height': '48px', 'height': '48px', 'width': '48px', 'border-radius': '50%'}"
|
||||||
[imageUrl]="ImageUrl"
|
[imageUrl]="ImageUrl"
|
||||||
[errorImage]="imageService.noPersonImage">
|
[errorImage]="imageService.noPersonImage">
|
||||||
</app-image>
|
</app-image>
|
||||||
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<i class="fas fa-user mx-auto" aria-hidden="true"></i>
|
<div style="background: none; max-height: 48px; height: 48px; width: 48px; border-radius: 50%" class="mx-auto">
|
||||||
|
<i class="fas fa-user" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
font-size: .8rem;
|
font-size: .8rem;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100px;
|
width: 120px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
font-size: 2rem;
|
font-size: 2.96rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import {ScrobbleEventTypePipe} from "../../_pipes/scrobble-event-type.pipe";
|
|||||||
import {SortableHeader} from "../../_single-module/table/_directives/sortable-header.directive";
|
import {SortableHeader} from "../../_single-module/table/_directives/sortable-header.directive";
|
||||||
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
||||||
import {EditDeviceModalComponent} from "../_modals/edit-device-modal/edit-device-modal.component";
|
import {EditDeviceModalComponent} from "../_modals/edit-device-modal/edit-device-modal.component";
|
||||||
|
import {DefaultModalOptions} from "../../_models/default-modal-options";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-manage-devices',
|
selector: 'app-manage-devices',
|
||||||
@ -71,7 +72,7 @@ export class ManageDevicesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addDevice() {
|
addDevice() {
|
||||||
const ref = this.modalService.open(EditDeviceModalComponent, { scrollable: true, size: 'xl', fullscreen: 'md' });
|
const ref = this.modalService.open(EditDeviceModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.device = null;
|
ref.componentInstance.device = null;
|
||||||
|
|
||||||
ref.closed.subscribe((result: Device | null) => {
|
ref.closed.subscribe((result: Device | null) => {
|
||||||
@ -82,7 +83,7 @@ export class ManageDevicesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
editDevice(device: Device) {
|
editDevice(device: Device) {
|
||||||
const ref = this.modalService.open(EditDeviceModalComponent, { scrollable: true, size: 'xl', fullscreen: 'md' });
|
const ref = this.modalService.open(EditDeviceModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.device = device;
|
ref.componentInstance.device = device;
|
||||||
|
|
||||||
ref.closed.subscribe((result: Device | null) => {
|
ref.closed.subscribe((result: Device | null) => {
|
||||||
|
@ -31,6 +31,7 @@ import {Select2Module} from "ng-select2-component";
|
|||||||
import {LoadingComponent} from "../../shared/loading/loading.component";
|
import {LoadingComponent} from "../../shared/loading/loading.component";
|
||||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||||
import {PreviewImageModalComponent} from "../../shared/_components/carousel-modal/preview-image-modal.component";
|
import {PreviewImageModalComponent} from "../../shared/_components/carousel-modal/preview-image-modal.component";
|
||||||
|
import {DefaultModalOptions} from "../../_models/default-modal-options";
|
||||||
|
|
||||||
interface ThemeContainer {
|
interface ThemeContainer {
|
||||||
downloadable?: DownloadableSiteTheme;
|
downloadable?: DownloadableSiteTheme;
|
||||||
@ -191,7 +192,7 @@ export class ThemeManagerComponent {
|
|||||||
previewImage(imgUrl: string) {
|
previewImage(imgUrl: string) {
|
||||||
if (imgUrl === '') return;
|
if (imgUrl === '') return;
|
||||||
|
|
||||||
const ref = this.modalService.open(PreviewImageModalComponent, {size: 'xl', fullscreen: 'lg'});
|
const ref = this.modalService.open(PreviewImageModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.title = this.selectedTheme!.name;
|
ref.componentInstance.title = this.selectedTheme!.name;
|
||||||
ref.componentInstance.image = imgUrl;
|
ref.componentInstance.image = imgUrl;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ import {BulkOperationsComponent} from "../cards/bulk-operations/bulk-operations.
|
|||||||
import {DefaultDatePipe} from "../_pipes/default-date.pipe";
|
import {DefaultDatePipe} from "../_pipes/default-date.pipe";
|
||||||
import {MangaFormatPipe} from "../_pipes/manga-format.pipe";
|
import {MangaFormatPipe} from "../_pipes/manga-format.pipe";
|
||||||
import {CoverImageComponent} from "../_single-module/cover-image/cover-image.component";
|
import {CoverImageComponent} from "../_single-module/cover-image/cover-image.component";
|
||||||
|
import {DefaultModalOptions} from "../_models/default-modal-options";
|
||||||
|
|
||||||
enum TabID {
|
enum TabID {
|
||||||
|
|
||||||
@ -527,7 +528,7 @@ export class VolumeDetailComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditModal() {
|
openEditModal() {
|
||||||
const ref = this.modalService.open(EditVolumeModalComponent, { size: 'xl' });
|
const ref = this.modalService.open(EditVolumeModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.volume = this.volume;
|
ref.componentInstance.volume = this.volume;
|
||||||
ref.componentInstance.libraryType = this.libraryType;
|
ref.componentInstance.libraryType = this.libraryType;
|
||||||
ref.componentInstance.libraryId = this.libraryId;
|
ref.componentInstance.libraryId = this.libraryId;
|
||||||
@ -537,7 +538,7 @@ export class VolumeDetailComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openEditChapterModal(chapter: Chapter) {
|
openEditChapterModal(chapter: Chapter) {
|
||||||
const ref = this.modalService.open(EditChapterModalComponent, { size: 'xl' });
|
const ref = this.modalService.open(EditChapterModalComponent, DefaultModalOptions);
|
||||||
ref.componentInstance.chapter = chapter;
|
ref.componentInstance.chapter = chapter;
|
||||||
ref.componentInstance.libraryType = this.libraryType;
|
ref.componentInstance.libraryType = this.libraryType;
|
||||||
ref.componentInstance.libraryId = this.libraryId;
|
ref.componentInstance.libraryId = this.libraryId;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user