On Deck + Misc Fixes and Changes (#1215)

* Added playwright and started writing e2e tests.

* To make things easy, disabled other browsers while I get confortable. Added a login flow (assumes my dev env)

* More tests on login page

* Lots more testing code, trying to figure out auth code.

* Ensure we don't track DBs inside config

* Added a new date property for when chapters are added to a series which helps with OnDeck calculations. Changed a lot of heavy api calls to use IEnumerable to stream repsonse to UI.

* Fixed OnDeck with a new field for when last chapter was added on Series. This is a streamlined way to query.

Updated Reading List with NormalizedTitle, CoverImage, CoverImageLocked.

* Implemented the ability to read a random item in the reading list and for the reading list to be intact for order.

* Tweaked the style for webtoon to not span the whole width, but use max width

* When we update a cover image just send an event so we don't need to have logic for when updates occur

* Fixed a bad name for entity type on cover updates

* Aligned the edit collection tag modal to align with new tab design

* Rewrote code for picking the first file for metadata to ensure it always picks the correct file, esp if the first chapter of a series starts with a float (1.1)

* Refactored setting LastChapterAdded to ensure we do it on the Series.

* Updated Chapter updating in scan loop to avoid nested for loop and an additional loop.

* Fixed a bug where locked person fields wouldn't persist between scans.

* Updated Contributing to reflect how to view the swagger api
This commit is contained in:
Joseph Milazzo 2022-04-11 17:43:40 -05:00 committed by GitHub
parent 912dfa8a80
commit 3bbb02f574
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 3397 additions and 343 deletions

View file

@ -19,5 +19,6 @@ export interface ReadingList {
title: string;
summary: string;
promoted: boolean;
coverImageLocked: boolean;
items: Array<ReadingListItem>;
}

View file

@ -32,7 +32,7 @@ export interface SeriesMetadata {
tagsLocked: boolean;
writersLocked: boolean;
coverArtistsLocked: boolean;
publishersLocked: boolean;
publisherLocked: boolean;
charactersLocked: boolean;
pencillersLocked: boolean;
inkersLocked: boolean;

View file

@ -460,7 +460,7 @@ export class ActionService implements OnDestroy {
}
editReadingList(readingList: ReadingList, callback?: ReadingListActionCallback) {
const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'md' });
const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'lg' });
readingListModalRef.componentInstance.readingList = readingList;
readingListModalRef.closed.pipe(take(1)).subscribe((list) => {
if (callback && list !== undefined) {

View file

@ -75,6 +75,10 @@ export class ImageService implements OnDestroy {
return this.baseUrl + 'image/collection-cover?collectionTagId=' + collectionTagId;
}
getReadingListCoverImage(readingListId: number) {
return this.baseUrl + 'image/readinglist-cover?readingListId=' + readingListId;
}
getChapterCoverImage(chapterId: number) {
return this.baseUrl + 'image/chapter-cover?chapterId=' + chapterId;
}

View file

@ -133,9 +133,6 @@ export class SeriesService {
getRecentlyUpdatedSeries() {
return this.httpClient.post<SeriesGroup[]>(this.baseUrl + 'series/recently-updated-series', {});
}
getRecentlyAddedChapters() {
return this.httpClient.post<RecentlyAddedItem[]>(this.baseUrl + 'series/recently-added-chapters', {});
}
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
const data = this.createSeriesFilter(filter);

View file

@ -30,6 +30,10 @@ export class UploadService {
return this.httpClient.post<number>(this.baseUrl + 'upload/collection', {id: tagId, url: this._cleanBase64Url(url)});
}
updateReadingListCoverImage(readingListId: number, url: string) {
return this.httpClient.post<number>(this.baseUrl + 'upload/reading-list', {id: readingListId, url: this._cleanBase64Url(url)});
}
updateChapterCoverImage(chapterId: number, url: string) {
return this.httpClient.post<number>(this.baseUrl + 'upload/chapter', {id: chapterId, url: this._cleanBase64Url(url)});
}

View file

@ -130,7 +130,7 @@
<span class="d-none d-sm-block">&nbsp;{{readingDirection === ReadingDirection.LeftToRight ? 'Previous' : 'Next'}}</span>
</button>
<button *ngIf="!this.adhocPageHistory.isEmpty()" class="btn btn-outline-secondary btn-icon col-2 col-xs-1" (click)="goBack()" title="Go Back"><i class="fa fa-reply" aria-hidden="true"></i><span class="d-none d-sm-block">&nbsp;Go Back</span></button>
<button class="btn btn-secondary col-2 col-xs-1" (click)="toggleDrawer()"><i class="fa fa-bars" aria-hidden="true"></i><span class="d-none d-sm-block">Settings {{drawerOpen}}</span></button>
<button class="btn btn-secondary col-2 col-xs-1" (click)="toggleDrawer()"><i class="fa fa-bars" aria-hidden="true"></i><span class="d-none d-sm-block">Settings</span></button>
<div class="book-title col-2 d-none d-sm-block">
<ng-container *ngIf="isLoading; else showTitle">
<div class="spinner-border spinner-border-sm text-primary" style="border-radius: 50%;" role="status">

View file

@ -5,16 +5,15 @@
</button>
</div>
<div class="modal-body">
<p>
This tag is currently {{tag?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
Promotion means that the tag can be seen server-wide, not just for admin users. All series that have this tag will still have user-access restrictions placed on them.
</p>
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs nav-pills">
<div class="modal-body {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? '' : 'd-flex'}}">
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-pills" orientation="{{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'horizontal' : 'vertical'}}" style="min-width: 135px;">
<li [ngbNavItem]="tabs[0]">
<a ngbNavLink>{{tabs[0]}}</a>
<ng-template ngbNavContent>
<p>
This tag is currently {{tag?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
Promotion means that the tag can be seen server-wide, not just for admin users. All series that have this tag will still have user-access restrictions placed on them.
</p>
<form [formGroup]="collectionTagForm">
<div class="mb-3">
<label for="summary" class="form-label">Summary</label>
@ -62,7 +61,7 @@
</ul>
<div [ngbNavOutlet]="nav" class="mt-3"></div>
<div [ngbNavOutlet]="nav" class="mt-3 ms-2"></div>
</div>
<div class="modal-footer">

View file

@ -4,6 +4,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { forkJoin } from 'rxjs';
import { ConfirmService } from 'src/app/shared/confirm.service';
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
import { SelectionModel } from 'src/app/typeahead/typeahead.component';
import { CollectionTag } from 'src/app/_models/collection-tag';
import { Pagination } from 'src/app/_models/pagination';
@ -14,6 +15,7 @@ import { LibraryService } from 'src/app/_services/library.service';
import { SeriesService } from 'src/app/_services/series.service';
import { UploadService } from 'src/app/_services/upload.service';
@Component({
selector: 'app-edit-collection-tags',
templateUrl: './edit-collection-tags.component.html',
@ -39,11 +41,15 @@ export class EditCollectionTagsComponent implements OnInit {
return this.selections != null && this.selections.hasSomeSelected();
}
get Breakpoint() {
return Breakpoint;
}
constructor(public modal: NgbActiveModal, private seriesService: SeriesService,
private collectionService: CollectionTagService, private toastr: ToastrService,
private confirmSerivce: ConfirmService, private libraryService: LibraryService,
private imageService: ImageService, private uploadService: UploadService) { }
private imageService: ImageService, private uploadService: UploadService,
public utilityService: UtilityService) { }
ngOnInit(): void {
if (this.pagination == undefined) {

View file

@ -192,8 +192,8 @@
<div class="mb-3">
<label for="publisher" class="form-label">Publisher</label>
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Publisher)" [settings]="getPersonsSettings(PersonRole.Publisher)"
[(locked)]="metadata.publishersLocked" (onUnlock)="metadata.publishersLocked = false"
(newItemAdded)="metadata.publishersLocked = true" (selectedData)="metadata.publishersLocked = true">
[(locked)]="metadata.publisherLocked" (onUnlock)="metadata.publisherLocked = false"
(newItemAdded)="metadata.publisherLocked = true" (selectedData)="metadata.publisherLocked = true">
<ng-template #badgeItem let-item let-position="idx">
{{item.name}}
</ng-template>

View file

@ -15,7 +15,6 @@
</ng-template>
</app-carousel-reel>
<!-- TODO: Refactor this so we can use series actions here -->
<app-carousel-reel [items]="recentlyUpdatedSeries" title="Recently Updated Series" (sectionClick)="handleSectionClick($event)">
<ng-template #carouselItem let-item let-position="idx">
<app-card-item [entity]="item" [title]="item.seriesName" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"
@ -27,11 +26,4 @@
<ng-template #carouselItem let-item let-position="idx">
<app-series-card [data]="item" [libraryId]="item.libraryId" (dataChanged)="loadRecentlyAddedSeries()"></app-series-card>
</ng-template>
</app-carousel-reel>
<!-- <app-carousel-reel [items]="recentlyAddedChapters" title="Recently Added" (sectionClick)="handleSectionClick($event)">
<ng-template #carouselItem let-item let-position="idx">
<app-card-item [entity]="item" [title]="item.title" [subtitle]="item.seriesName" [imageUrl]="imageService.getRecentlyAddedItem(item)"
[supressArchiveWarning]="true" (clicked)="handleRecentlyAddedChapterClick(item)"></app-card-item>
</ng-template>
</app-carousel-reel> -->
</app-carousel-reel>

View file

@ -29,7 +29,6 @@ export class LibraryComponent implements OnInit, OnDestroy {
isAdmin = false;
recentlyUpdatedSeries: SeriesGroup[] = [];
recentlyAddedChapters: RecentlyAddedItem[] = [];
inProgress: Series[] = [];
recentlyAddedSeries: Series[] = [];
@ -57,7 +56,6 @@ export class LibraryComponent implements OnInit, OnDestroy {
this.inProgress = this.inProgress.filter(item => item.id != seriesRemovedEvent.seriesId);
this.recentlyAddedSeries = this.recentlyAddedSeries.filter(item => item.id != seriesRemovedEvent.seriesId);
this.recentlyUpdatedSeries = this.recentlyUpdatedSeries.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
this.recentlyAddedChapters = this.recentlyAddedChapters.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
} else if (res.event === EVENTS.ScanSeries) {
// We don't have events for when series are updated, but we do get events when a scan update occurs. Refresh recentlyAdded at that time.
this.loadRecentlyAdded$.next();
@ -125,10 +123,6 @@ export class LibraryComponent implements OnInit, OnDestroy {
this.seriesService.getRecentlyUpdatedSeries().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
this.recentlyUpdatedSeries = updatedSeries;
});
this.seriesService.getRecentlyAddedChapters().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
this.recentlyAddedChapters = updatedSeries;
});
}
handleRecentlyAddedChapterClick(item: RecentlyAddedItem) {

View file

@ -27,13 +27,10 @@
img, .full-width {
width: 100% !important;
max-width: 100% !important;
height: auto;
}
// .img-container {
// overflow: auto;
// }
@keyframes move-up-down {

View file

@ -1,26 +1,41 @@
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Edit {{readingList.title}} Reading List</h4>
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
</button>
<button type="button" class="btn-close" aria-label="Close" (click)="close()"></button>
</div>
<div class="modal-body">
<p>
This list is currently {{readingList?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
Promotion means that the list can be seen server-wide, not just for admin users. All series that are within this list will still have user-access restrictions placed on them.
</p>
<form [formGroup]="reviewGroup">
<div class="mb-3">
<label for="title" class="form-label">Name</label>
<input id="title" class="form-control" formControlName="title" type="text">
</div>
<div class="mb-3">
<label for="summary" class="form-label">Summary</label>
<textarea id="summary" class="form-control" formControlName="summary" rows="3"></textarea>
</div>
</form>
<div class="modal-body {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? '' : 'd-flex'}}">
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-pills" orientation="{{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'horizontal' : 'vertical'}}" style="min-width: 135px;">
<li [ngbNavItem]="tabs[0]">
<a ngbNavLink>{{tabs[0].title}}</a>
<ng-template ngbNavContent>
<p>
This list is currently {{readingList?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
Promotion means that the list can be seen server-wide, not just for admin users. All series that are within this list will still have user-access restrictions placed on them.
</p>
<form [formGroup]="reviewGroup">
<div class="mb-3">
<label for="title" class="form-label">Name</label>
<input id="title" class="form-control" formControlName="title" type="text">
</div>
<div class="mb-3">
<label for="summary" class="form-label">Summary</label>
<textarea id="summary" class="form-control" formControlName="summary" rows="3"></textarea>
</div>
</form>
</ng-template>
</li>
<li [ngbNavItem]="tabs[1]">
<a ngbNavLink>{{tabs[1].title}}</a>
<ng-template ngbNavContent>
<p class="alert alert-primary" role="alert">
Upload and choose a new cover image. Press Save to upload and override the cover.
</p>
<app-cover-image-chooser [(imageUrls)]="imageUrls" (imageSelected)="updateSelectedIndex($event)" (selectedBase64Url)="updateSelectedImage($event)" [showReset]="readingList.coverImageLocked" (resetClicked)="handleReset()"></app-cover-image-chooser>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="nav" class="ms-2 mt-3"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="close()">Close</button>

View file

@ -1,8 +1,14 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { forkJoin } from 'rxjs';
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
import { ReadingList } from 'src/app/_models/reading-list';
import { ImageService } from 'src/app/_services/image.service';
import { ReadingListService } from 'src/app/_services/reading-list.service';
import { UploadService } from 'src/app/_services/upload.service';
@Component({
selector: 'app-edit-reading-list-modal',
@ -14,13 +20,33 @@ export class EditReadingListModalComponent implements OnInit {
@Input() readingList!: ReadingList;
reviewGroup!: FormGroup;
constructor(private ngModal: NgbActiveModal, private readingListService: ReadingListService) { }
coverImageIndex: number = 0;
/**
* Url of the selected cover
*/
selectedCover: string = '';
coverImageLocked: boolean = false;
imageUrls: Array<string> = [];
tabs = [{title: 'General', disabled: false}, {title: 'Cover', disabled: false}];
active = this.tabs[0];
get Breakpoint() {
return Breakpoint;
}
constructor(private ngModal: NgbActiveModal, private readingListService: ReadingListService,
public utilityService: UtilityService, private uploadService: UploadService, private toastr: ToastrService,
private imageService: ImageService) { }
ngOnInit(): void {
this.reviewGroup = new FormGroup({
title: new FormControl(this.readingList.title, [Validators.required]),
summary: new FormControl(this.readingList.summary, [])
});
this.imageUrls.push(this.imageService.randomize(this.imageService.getReadingListCoverImage(this.readingList.id)));
}
close() {
@ -29,12 +55,22 @@ export class EditReadingListModalComponent implements OnInit {
save() {
if (this.reviewGroup.value.title.trim() === '') return;
const model = {...this.reviewGroup.value, readingListId: this.readingList.id, promoted: this.readingList.promoted};
this.readingListService.update(model).subscribe(() => {
const model = {...this.reviewGroup.value, readingListId: this.readingList.id, promoted: this.readingList.promoted, coverImageLocked: this.coverImageLocked};
const apis = [this.readingListService.update(model)];
if (this.selectedCover !== '') {
apis.push(this.uploadService.updateReadingListCoverImage(this.readingList.id, this.selectedCover))
}
forkJoin(apis).subscribe(results => {
this.readingList.title = model.title;
this.readingList.summary = model.summary;
this.readingList.coverImageLocked = this.coverImageLocked;
this.ngModal.close(this.readingList);
this.toastr.success('Reading List updated');
});
}
@ -49,4 +85,16 @@ export class EditReadingListModalComponent implements OnInit {
});
}
updateSelectedIndex(index: number) {
this.coverImageIndex = index;
}
updateSelectedImage(url: string) {
this.selectedCover = url;
}
handleReset() {
this.coverImageLocked = false;
}
}

View file

@ -3,42 +3,48 @@
<span *ngIf="actions.length > 0">
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="readingList.title"></app-card-actionables>
</span>
{{readingList.title}}&nbsp;<span *ngIf="readingList?.promoted">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>&nbsp;
<span class="badge bg-primary rounded-pill" attr.aria-label="{{items.length}} total items">{{items.length}}</span>
{{readingList?.title}}&nbsp;<span *ngIf="readingList?.promoted">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>
</h2>
<h6 subtitle>{{items.length}} Items</h6>
</app-side-nav-companion-bar>
<div class="container-fluid mt-2" *ngIf="readingList">
<div class="mb-3">
<!-- Action row-->
<div class="row g-0">
<div class="col-auto me-2">
<button class="btn btn-primary" title="Read" (click)="read()">
<span>
<i class="fa fa-book-open" aria-hidden="true"></i>
<span class="read-btn--text">&nbsp;Read</span>
</span>
</button>
</div>
<div class="col-auto">
<button class="btn btn-secondary" (click)="removeRead()" [disabled]="readingList?.promoted && !this.isAdmin">
<div class="row mb-3">
<div class="col-md-2 col-xs-4 col-sm-6 d-none d-sm-block">
<app-image maxWidth="300px" [imageUrl]="readingListImage"></app-image>
</div>
<div class="col-md-10 col-xs-8 col-sm-6 mt-2">
<div class="row g-0 mb-3">
<div class="col-auto me-2">
<!-- Action row-->
<button class="btn btn-primary" title="Read" (click)="read()">
<span>
<i class="fa fa-check"></i>
<i class="fa fa-book-open" aria-hidden="true"></i>
<span class="read-btn--text">&nbsp;Read</span> <!-- IDEA: We can provide them the ability to read/continue like we do with a series -->
</span>
<span class="read-btn--text">&nbsp;Remove Read</span>
</button>
</div>
<div class="col-auto ms-2 mt-2" *ngIf="!(readingList?.promoted && !this.isAdmin)">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="accessibilit-mode" [value]="accessibilityMode" (change)="accessibilityMode = !accessibilityMode">
<label class="form-check-label" for="accessibilit-mode">Order Numbers</label>
</div>
<div class="col-auto">
<button class="btn btn-secondary" (click)="removeRead()" [disabled]="readingList?.promoted && !this.isAdmin">
<span>
<i class="fa fa-check"></i>
</span>
<span class="read-btn--text">&nbsp;Remove Read</span>
</button>
</div>
<div class="col-auto ms-2 mt-2" *ngIf="!(readingList?.promoted && !this.isAdmin)">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="accessibilit-mode" [value]="accessibilityMode" (change)="accessibilityMode = !accessibilityMode">
<label class="form-check-label" for="accessibilit-mode">Order Numbers</label>
</div>
</div>
</div>
<!-- Summary row-->
<div class="row g-0 mt-2">
<app-read-more [text]="readingListSummary" [maxLength]="250"></app-read-more>
</div>
</div>
<!-- Summary row-->
<div class="row g-0 mt-2">
<app-read-more [text]="readingListSummary" [maxLength]="250"></app-read-more>
</div>
</div>
<div *ngIf="items.length === 0">
No chapters added
@ -63,6 +69,8 @@
<span *ngIf="item.promoted">
<i class="fa fa-angle-double-up" aria-hidden="true"></i>
</span>
<br/>
<a href="javascript:void(0);" (click)="readChapter(item)">Read</a>
</div>
</div>
</ng-template>

View file

@ -15,6 +15,7 @@ import { ReadingListService } from 'src/app/_services/reading-list.service';
import { IndexUpdateEvent, ItemRemoveEvent } from '../dragable-ordered-list/dragable-ordered-list.component';
import { LibraryService } from '../../_services/library.service';
import { forkJoin } from 'rxjs';
import { ReaderService } from 'src/app/_services/reader.service';
@Component({
selector: 'app-reading-list-detail',
@ -38,6 +39,8 @@ export class ReadingListDetailComponent implements OnInit {
libraryTypes: {[key: number]: LibraryType} = {};
readingListImage: string = '';
get MangaFormat(): typeof MangaFormat {
return MangaFormat;
}
@ -45,7 +48,7 @@ export class ReadingListDetailComponent implements OnInit {
constructor(private route: ActivatedRoute, private router: Router, private readingListService: ReadingListService,
private actionService: ActionService, private actionFactoryService: ActionFactoryService, public utilityService: UtilityService,
public imageService: ImageService, private accountService: AccountService, private toastr: ToastrService,
private confirmService: ConfirmService, private libraryService: LibraryService) {}
private confirmService: ConfirmService, private libraryService: LibraryService, private readerService: ReaderService) {}
ngOnInit(): void {
const listId = this.route.snapshot.paramMap.get('id');
@ -57,6 +60,8 @@ export class ReadingListDetailComponent implements OnInit {
this.listId = parseInt(listId, 10);
this.readingListImage = this.imageService.randomize(this.imageService.getReadingListCoverImage(this.listId));
this.libraryService.getLibraries().subscribe(libs => {
});
@ -107,6 +112,15 @@ export class ReadingListDetailComponent implements OnInit {
}
}
readChapter(item: ReadingListItem) {
let reader = 'manga';
if (item.seriesFormat === MangaFormat.EPUB) {
reader = 'book;'
}
const params = this.readerService.getQueryParamsObject(false, true, this.readingList.id);
this.router.navigate(['library', item.libraryId, 'series', item.seriesId, 'book', item.chapterId], {queryParams: params});
}
handleReadingListActionCallback(action: Action, readingList: ReadingList) {
switch(action) {
case Action.Delete:

View file

@ -12,6 +12,7 @@ import { EditReadingListModalComponent } from './_modals/edit-reading-list-modal
import { PipeModule } from '../pipe/pipe.module';
import { SharedModule } from '../shared/shared.module';
import { SidenavModule } from '../sidenav/sidenav.module';
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
@ -31,7 +32,8 @@ import { SidenavModule } from '../sidenav/sidenav.module';
CardsModule,
PipeModule,
SharedModule,
SidenavModule
SidenavModule,
NgbNavModule
],
exports: [
AddToListModalComponent,

View file

@ -15,6 +15,6 @@
(pageChange)="onPageChange($event)"
>
<ng-template #cardItem let-item let-position="idx">
<app-card-item [title]="item.title" [entity]="item" [actions]="getActions(item)" [supressLibraryLink]="true" [imageUrl]="imageService.placeholderImage" (clicked)="handleClick(item)"></app-card-item>
<app-card-item [title]="item.title" [entity]="item" [actions]="getActions(item)" [supressLibraryLink]="true" [imageUrl]="imageService.getReadingListCoverImage(item.id)" (clicked)="handleClick(item)"></app-card-item>
</ng-template>
</app-card-detail-layout>