Improve bookdrop UI (#1768)

* Improve bookdrop UI

* Rename resetAll as it doesn't apply to all now

* Fix display of copied metadata fields
This commit is contained in:
Muppetteer
2025-12-07 03:16:42 +11:00
committed by GitHub
parent 474e95c4f2
commit 51fa54bed3
6 changed files with 298 additions and 188 deletions

View File

@@ -1,11 +1,13 @@
@if (fetchedMetadata) {
<form [formGroup]="metadataForm" class="flex flex-col h-[35rem] w-full">
@if (fetchedMetadata && fetchedMetadata.title) {
<form [formGroup]="metadataForm" class="metapicker flex flex-col w-full">
<div class="flex-grow overflow-auto">
<div class="relative flex items-center justify-between pb-3">
<div class="absolute left-1/2 transform -translate-x-1/2 flex items-center pl-24">
<p class="pr-6">Current Metadata</p>
<div>
<div class="metaheader relative flex items-center">
<label class="w-[12%]"></label>
<div class="flex w-full items-center">
<p class="!w-1/2 pr-3" style="text-align:right">Current Metadata</p>
<div class="midbuttons">
<p-button
size="small"
severity="success"
icon="pi pi-angle-left"
class="mx-2"
@@ -15,6 +17,7 @@
(onClick)="copyMissing()"
></p-button>
<p-button
size="small"
severity="success"
icon="pi pi-angle-double-left"
class="mx-2"
@@ -24,27 +27,29 @@
(onClick)="copyAll()"
></p-button>
</div>
<p class="pl-6">Fetched Metadata</p>
<p class="!w-1/2 pl-3">Fetched Metadata</p>
</div>
<div class="ml-auto">
<div class="ml-auto absolute" style="right:1rem">
<p-button
severity="danger"
size="small"
severity="warn"
icon="pi pi-refresh"
label="Reset"
[outlined]="true"
pTooltip="Reset all fields to original values"
tooltipPosition="bottom"
(onClick)="resetAll()"
(onClick)="confirmReset()"
></p-button>
</div>
</div>
<div>
<div class="metacontent">
<div class="flex items-center py-1">
<label class="w-[6.5%]"></label>
<label class="w-[12%] text-sm">Cover</label>
<div class="flex w-full items-center justify-center">
<p-image class="thumbnail" [src]="metadataForm.get('thumbnailUrl')?.value" alt="Image" appendTo="body" lazyLoad [preview]="true"></p-image>
<input type="hidden" id="thumbnailUrl" formControlName="thumbnailUrl" class="!w-1/2"/>
<p-button
size="small"
[icon]="isValueSaved('thumbnailUrl') ? 'pi pi-check' : (hoveredFields['thumbnailUrl'] && isValueCopied('thumbnailUrl') ? 'pi pi-times' : 'pi pi-arrow-left')"
[outlined]="true"
[ngClass]="
@@ -62,7 +67,7 @@
</div>
@for (field of metadataFieldsTop; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[6.5%]">{{ field.label }}</label>
<label for="{{field.controlName}}" class="w-[12%] text-sm">{{ field.label }}</label>
<div class="flex w-full">
<input
pSize="small"
@@ -76,6 +81,7 @@
}"
/>
<p-button
size="small"
[icon]="isValueSaved(field.controlName) ? 'pi pi-check' : (hoveredFields[field.controlName] && isValueCopied(field.controlName) ? 'pi pi-times' : 'pi pi-arrow-left')"
[outlined]="true"
[ngClass]="
@@ -93,15 +99,20 @@
}
@for (field of metadataChips; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[6.5%]">{{ field.label }}</label>
<label for="{{field.controlName}}" class="w-[12%] text-sm">{{ field.label }}</label>
<div class="flex w-full items-center">
<div class="w-full"
[ngClass]="{
'outlined-input-green': isValueCopied(field.controlName) && !hoveredFields[field.controlName],
}">
<p-autoComplete formControlName="{{field.controlName}}" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" class="w-full" (onBlur)="onAutoCompleteBlur(field.controlName, $event)"></p-autoComplete>
</div>
<p-autoComplete
size="small"
formControlName="{{field.controlName}}"
[multiple]="true"
[typeahead]="false"
[dropdown]="false"
[forceSelection]="false"
class="w-full"
[ngClass]="{'outlined-input-green': isValueCopied(field.controlName) && !hoveredFields[field.controlName]}"
(onBlur)="onAutoCompleteBlur(field.controlName, $event)"/>
<p-button
size="small"
[icon]="isValueSaved(field.controlName) ? 'pi pi-check' : (hoveredFields[field.controlName] && isValueCopied(field.controlName) ? 'pi pi-times' : 'pi pi-arrow-left')"
[outlined]="true"
[ngClass]="
@@ -113,28 +124,34 @@
(click)="hoveredFields[field.controlName] && isValueCopied(field.controlName) ? resetField(field.controlName) : copyFetchedToCurrent(field.controlName)"
(mouseenter)="onMouseEnter(field.controlName)"
(mouseleave)="onMouseLeave(field.controlName)"/>
<div class="w-full">
<p-autoComplete
[ngModel]="fetchedMetadata[field.fetchedKey] ?? []"
[ngModelOptions]="{ standalone: true }"
[disabled]="true"
[multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" class="w-full">
</p-autoComplete>
</div>
<p-autoComplete
size="small"
[ngModel]="fetchedMetadata[field.fetchedKey] ?? []"
[ngModelOptions]="{standalone:true}"
[disabled]="true"
[multiple]="true"
[typeahead]="false"
[dropdown]="false"
[forceSelection]="false"
class="w-full"/>
</div>
</div>
}
@for (field of metadataDescription; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[6.5%]">{{ field.label }}</label>
<label for="{{field.controlName}}" class="w-[12%] text-sm">{{ field.label }}</label>
<div class="flex w-full items-center">
<textarea rows="2" pTextarea id="{{field.controlName}}" formControlName="{{field.controlName}}" class="!w-1/2"
[ngClass]="{
'outlined-input-green': isValueCopied(field.controlName) && !hoveredFields[field.controlName],
}"
></textarea>
<textarea
rows="2"
pSize="small"
pTextarea
id="{{field.controlName}}"
formControlName="{{field.controlName}}"
class="!w-1/2"
[ngClass]="{'outlined-input-green': isValueCopied(field.controlName) && !hoveredFields[field.controlName]}"
></textarea>
<p-button
size="small"
[icon]="isValueSaved(field.controlName) ? 'pi pi-check' : (hoveredFields[field.controlName] && isValueCopied(field.controlName) ? 'pi pi-times' : 'pi pi-arrow-left')"
[outlined]="true"
[ngClass]="
@@ -146,13 +163,19 @@
(click)="hoveredFields[field.controlName] && isValueCopied(field.controlName) ? resetField(field.controlName) : copyFetchedToCurrent(field.controlName)"
(mouseenter)="onMouseEnter(field.controlName)"
(mouseleave)="onMouseLeave(field.controlName)"/>
<textarea rows="2" pInputText [value]="fetchedMetadata[field.fetchedKey] ?? null" class="!w-1/2" readonly></textarea>
<textarea
rows="2"
pSize="small"
pInputText
[value]="fetchedMetadata[field.fetchedKey] ?? null"
class="!w-1/2"
readonly></textarea>
</div>
</div>
}
@for (field of metadataFieldsBottom; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[6.5%]">{{ field.label }}</label>
<label for="{{field.controlName}}" class="w-[12%] text-sm">{{ field.label }}</label>
<div class="flex w-full">
<input pInputText pSize="small" id="{{field.controlName}}" formControlName="{{field.controlName}}" class="!w-1/2"
[ngClass]="{
@@ -160,6 +183,7 @@
}"
/>
<p-button
size="small"
[icon]="isValueSaved(field.controlName) ? 'pi pi-check' : (hoveredFields[field.controlName] && isValueCopied(field.controlName) ? 'pi pi-times' : 'pi pi-arrow-left')"
[outlined]="true"
[ngClass]="
@@ -179,68 +203,86 @@
</div>
</form>
} @else {
<form [formGroup]="metadataForm" class="flex h-[30rem] w-full">
<div class="flex-grow overflow-auto pr-4">
<p class="pb-2">Current Metadata:</p>
@for (field of metadataFieldsTop; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%]">{{ field.label }}</label>
<div class="flex w-full">
<input
pSize="small"
fluid
pInputText
id="{{field.controlName}}"
formControlName="{{field.controlName}}"
/>
</div>
</div>
}
@for (field of metadataChips; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%]">{{ field.label }}</label>
<div class="flex w-full">
<p-autoComplete formControlName="{{field.controlName}}" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" class="w-full" (onBlur)="onAutoCompleteBlur(field.controlName, $event)"></p-autoComplete>
</div>
</div>
}
@for (field of metadataDescription; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%]">{{ field.label }}</label>
<div class="flex w-full">
<textarea fluid rows="2" pTextarea id="{{field.controlName}}" formControlName="{{field.controlName}}"></textarea>
</div>
</div>
}
@for (field of metadataFieldsBottom; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%]">{{ field.label }}</label>
<div class="flex w-full">
<input
fluid
pInputText
pSize="small"
id="{{field.controlName}}"
formControlName="{{field.controlName}}"
/>
</div>
</div>
}
</div>
<div class="w-[20%] h-full flex items-start justify-center p-4">
<div class="w-full h-full">
<img
[src]="metadataForm.get('thumbnailUrl')?.value"
alt="Book Thumbnail"
class="w-full h-full object-contain"
/>
<input type="hidden" id="thumbnailUrl" formControlName="thumbnailUrl"/>
<form [formGroup]="metadataForm" class="metapicker flex w-full">
<div class="flex-grow overflow-auto">
<div class="metaheader relative flex items-center">
<p class="text-sm flex items-center" style="gap: 0.5rem">
<i class="pi metadata-status pi-exclamation-triangle not-applied"></i>
Unable to fetch new metadata for this file
</p>
<p-button
size="small"
severity="warn"
icon="pi pi-refresh"
label="Reset"
[outlined]="true"
pTooltip="Reset all fields to original values"
tooltipPosition="bottom"
(onClick)="confirmReset()"
></p-button>
</div>
<div class="flex flex-row">
<div class="w-[25%] h-full flex items-start justify-center pl-4">
<div class="w-full h-full">
<img
[src]="metadataForm.get('thumbnailUrl')?.value"
alt="Book Thumbnail"
class="w-full h-full object-contain"
/>
<input type="hidden" id="thumbnailUrl" formControlName="thumbnailUrl"/>
</div>
</div>
<div class="metacontent w-[75%]">
@for (field of metadataFieldsTop; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%] text-sm">{{ field.label }}</label>
<div class="flex w-full">
<input
pSize="small"
fluid
pInputText
id="{{field.controlName}}"
formControlName="{{field.controlName}}"
/>
</div>
</div>
}
@for (field of metadataChips; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%] text-sm">{{ field.label }}</label>
<div class="flex w-full">
<p-autoComplete formControlName="{{field.controlName}}" [multiple]="true" [typeahead]="false" [dropdown]="false" [forceSelection]="false" class="w-full" (onBlur)="onAutoCompleteBlur(field.controlName, $event)"></p-autoComplete>
</div>
</div>
}
@for (field of metadataDescription; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%] text-sm">{{ field.label }}</label>
<div class="flex w-full">
<textarea fluid rows="2" pTextarea id="{{field.controlName}}" formControlName="{{field.controlName}}"></textarea>
</div>
</div>
}
@for (field of metadataFieldsBottom; track field) {
<div class="flex items-center py-1">
<label for="{{field.controlName}}" class="w-[15%] text-sm">{{ field.label }}</label>
<div class="flex w-full">
<input
fluid
pInputText
pSize="small"
id="{{field.controlName}}"
formControlName="{{field.controlName}}"
/>
</div>
</div>
}
</div>
</div>
</div>
</form>
}

View File

@@ -22,10 +22,49 @@
--p-button-outlined-primary-color: #E32636;
}
.outlined-input-green {
border: 0.75px solid forestgreen !important;
input.outlined-input-green,
textarea.outlined-input-green,
::ng-deep p-autocomplete.outlined-input-green ul.p-autocomplete-input-multiple {
border: 1px solid forestgreen !important;
}
::ng-deep .p-inputchips {
width: 100% !important;
}
::ng-deep .p-autocomplete .p-chip .p-chip-label {
font-size: 12px;
}
.metapicker {
box-sizing: border-box;
}
.metaheader {
border-bottom: 1px solid var(--border-color);
padding: 1rem;
margin-bottom: 1rem;
justify-content: space-between;
}
.metaheader .midbuttons {
white-space: nowrap;
}
.metacontent {
padding: 0 1rem 1rem;
}
.metadata-status {
&.copied {
color: rgb(34, 197, 94);
}
&.no-metadata {
color: rgb(59, 130, 246);
}
&.not-applied {
color: rgb(239, 68, 68);
}
}

View File

@@ -10,6 +10,7 @@ import {Textarea} from 'primeng/textarea';
import {AutoComplete} from 'primeng/autocomplete';
import {Image} from 'primeng/image';
import {LazyLoadImageModule} from 'ng-lazyload-image';
import {ConfirmationService} from 'primeng/api';
@Component({
selector: 'app-bookdrop-file-metadata-picker-component',
@@ -30,6 +31,8 @@ import {LazyLoadImageModule} from 'ng-lazyload-image';
})
export class BookdropFileMetadataPickerComponent {
private readonly confirmationService = inject(ConfirmationService);
@Input() fetchedMetadata!: BookMetadata;
@Input() originalMetadata?: BookMetadata;
@Input() metadataForm!: FormGroup;
@@ -97,10 +100,10 @@ export class BookdropFileMetadataPickerComponent {
});
}
copyAll() {
copyAll(includeCover: boolean = true): void {
if (this.fetchedMetadata) {
Object.keys(this.fetchedMetadata).forEach((field) => {
if (this.fetchedMetadata[field] && field !== 'thumbnailUrl') {
if (this.fetchedMetadata[field] && (includeCover || field !== 'thumbnailUrl')) {
this.copyFetchedToCurrent(field);
}
});
@@ -164,6 +167,16 @@ export class BookdropFileMetadataPickerComponent {
}
}
confirmReset(): void {
this.confirmationService.confirm({
message: 'Are you sure you want to reset all metadata changes made to this file?',
header: 'Reset Metadata Changes?',
icon: 'pi pi-exclamation-triangle',
acceptButtonStyleClass: 'p-button-danger',
accept: () => this.resetAll()
});
}
resetAll() {
if (this.originalMetadata) {
this.metadataForm.patchValue({

View File

@@ -20,7 +20,7 @@
<div class="header-actions">
<p-button
label="Rescan Bookdrop"
label="Rescan"
icon="pi pi-refresh"
severity="primary"
outlined
@@ -56,72 +56,53 @@
@if (bookdropFileUis.length !== 0) {
<div class="controls-row">
<div class="default-controls">
<span>Library for All Files:</span>
<p-select
size="small"
[options]="libraryOptions"
optionLabel="label"
optionValue="value"
placeholder="Select Default Library"
[(ngModel)]="defaultLibraryId">
</p-select>
<span>Subpath for All Files:</span>
<p-select
size="small"
[options]="selectedLibraryPaths"
optionLabel="label"
optionValue="value"
placeholder="Select Default Subpath"
[(ngModel)]="defaultPathId">
</p-select>
<p-button
size="small"
label="Apply to All"
icon="pi pi-check"
[disabled]="!canApplyDefaults"
(click)="applyDefaultsToAll()"
pTooltip="Apply selected library and subpath to all files"
tooltipPosition="top">
</p-button>
</div>
<div class="action-buttons">
<p-button
size="small"
outlined
severity="info"
label="Apply (w/ Cover)"
label="Import&nbsp;Metadata"
icon="pi pi-copy"
(click)="copyAll(true)"
pTooltip="For all files, replace current metadata with fetched metadata, including cover images"
(click)="copyAll()"
pTooltip="Replace current metadata with fetched metadata on all files"
tooltipPosition="top">
</p-button>
<span pTooltip="Include book covers when importing fetched metadata"><p-checkbox
inputId="includecovers"
[binary]="true"
[(ngModel)]="includeCoversOnCopy">
</p-checkbox>
<label for="includecovers" class="text-sm" style="margin-left: 0.5em;">Covers</label></span>
</div>
<div class="default-controls">
<p-select
size="small"
[options]="libraryOptions"
optionLabel="label"
optionValue="value"
placeholder="Default Library"
[(ngModel)]="defaultLibraryId">
</p-select>
<p-select
size="small"
[options]="selectedLibraryPaths"
optionLabel="label"
optionValue="value"
placeholder="Default Subpath"
[(ngModel)]="defaultPathId">
</p-select>
<p-button
size="small"
outlined
severity="info"
label="Apply (no Cover)"
icon="pi pi-copy"
(click)="copyAll(false)"
pTooltip="For all files, replace current metadata with fetched metadata, excluding cover images"
label="Apply"
icon="pi pi-check"
[disabled]="!canApplyDefaults"
(click)="applyDefaultsToAll()"
pTooltip="Apply selected library and subpath to all files"
tooltipPosition="top">
</p-button>
<p-button
size="small"
outlined
severity="warn"
label="Reset"
icon="pi pi-refresh"
(click)="resetAll()"
pTooltip="Reset all metadata changes"
tooltipPosition="left">
</p-button>
</div>
</div>
}
@@ -182,7 +163,7 @@
}"
[pTooltip]="copiedFlags[file.file.id]
? 'Fetched metadata has been applied.'
: !file.file.fetchedMetadata
: (!file.file.fetchedMetadata || !file.file.fetchedMetadata.title)
? 'No fetched metadata available. Original metadata will be used.'
: 'Fetched metadata hasnt been applied yet. Open metadata picker to review.'"
tooltipPosition="top">
@@ -242,7 +223,7 @@
<div class="footer-left">
@if (bookdropFileUis.length > 0) {
<p-button
label="Select All"
label="Select&nbsp;All"
icon="pi pi-check-square"
severity="info"
(click)="selectAll(true)"
@@ -252,7 +233,7 @@
</p-button>
<p-button
label="Clear All"
label="Clear"
icon="pi pi-times-circle"
severity="warn"
(click)="selectAll(false)"
@@ -271,14 +252,26 @@
[totalRecords]="totalRecords"
[first]="currentPage * pageSize"
(onPageChange)="loadPage($event.page ?? 0)"
[showCurrentPageReport]="true"
currentPageReportTemplate="Showing files {first} - {last} of {totalRecords}">
[showJumpToPageDropdown]="true"
[showPageLinks]="false"
[showFirstLastIcon]="false"
currentPageReportTemplate="Page {currentPage} of {totalPages}">
</p-paginator>
</div>
<div class="footer-right">
<p-button
[label]="'Delete ' + selectedCount + ' File' + (selectedCount !== 1 ? 's' : '')"
[label]="'Reset ' + selectedCount"
icon="pi pi-refresh"
severity="warn"
[disabled]="!hasSelectedFiles"
outlined
(click)="confirmReset()"
pTooltip="Discard all changes made to metadata of selected files"
tooltipPosition="top">
</p-button>
<p-button
[label]="'Delete ' + selectedCount"
icon="pi pi-times"
severity="danger"
[disabled]="!hasSelectedFiles"
@@ -288,7 +281,7 @@
tooltipPosition="top">
</p-button>
<p-button
[label]="saving ? ('Finalizing ' + selectedCount + ' File' + (selectedCount !== 1 ? 's' : '') + '...') : ('Finalize ' + selectedCount + ' File' + (selectedCount !== 1 ? 's' : ''))"
[label]="saving ? ('Finalizing ' + selectedCount + '...') : ('Finalize ' + selectedCount)"
[icon]="saving ? 'pi pi-spin pi-spinner' : 'pi pi-save'"
severity="success"
outlined

View File

@@ -9,12 +9,8 @@
border-radius: 0.75rem;
overflow: hidden;
background: var(--card-background);
min-width: 100rem;
min-width: 60rem;
border: 1px solid var(--p-content-border-color);
> * + * {
margin: 0.25rem;
}
}
.header {
@@ -96,7 +92,9 @@
}
.controls-section {
padding: 0 1.5rem 0.5rem;
padding: 0 1.5rem 1.5rem;
margin: 0;
border-bottom: 1px solid var(--p-content-border-color);
}
.saving-overlay {
@@ -145,12 +143,6 @@
gap: 1rem;
align-items: center;
span {
font-size: 0.875rem;
color: rgb(209, 213, 219);
font-weight: 500;
}
p-select {
min-width: 8rem;
max-width: 16rem;
@@ -160,20 +152,23 @@
.action-buttons {
display: flex;
gap: 1rem;
align-items: center;
span {
font-size: 0.875rem;
color: rgb(209, 213, 219);
font-weight: 500;
}
}
.content-area {
flex: 1;
overflow-y: auto;
padding: 1rem 1rem 1rem;
padding: 1rem;
> * + * {
margin-top: 0.5rem;
}
@media (min-width: 768px) {
padding: 1rem 1.5rem 1rem;
}
}
.empty-state {
@@ -249,7 +244,6 @@
}
.details-section {
padding: 2rem 3rem;
border-left: 1px solid var(--border-color);
border-right: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);

View File

@@ -86,6 +86,7 @@ export class BookdropFileReviewComponent implements OnInit {
copiedFlags: Record<number, boolean> = {};
loading = true;
saving = false;
includeCoversOnCopy = true;
pageSize = 50;
totalRecords = 0;
@@ -231,13 +232,13 @@ export class BookdropFileReviewComponent implements OnInit {
});
}
copyAll(includeThumbnail: boolean): void {
copyAll(): void {
Object.values(this.fileUiCache).forEach(fileUi => {
const fetched = fileUi.file.fetchedMetadata;
const form = fileUi.metadataForm;
if (!fetched) return;
for (const key of Object.keys(fetched)) {
if (!includeThumbnail && key === 'thumbnailUrl') continue;
if (!this.includeCoversOnCopy && key === 'thumbnailUrl') continue;
const value = fetched[key as keyof typeof fetched];
if (value != null) {
form.get(key)?.setValue(value);
@@ -248,8 +249,16 @@ export class BookdropFileReviewComponent implements OnInit {
});
}
resetAll(): void {
Object.values(this.fileUiCache).forEach(fileUi => {
resetMetadata(): void {
const selectedFiles = Object.values(this.fileUiCache).filter(file => {
if (this.selectAllAcrossPages) {
return !this.excludedFiles.has(file.file.id);
} else {
return file.selected;
}
});
const files = selectedFiles.map(fileUi => {
const original = fileUi.file.originalMetadata;
fileUi.metadataForm.patchValue({
title: original?.title || null,
@@ -283,8 +292,8 @@ export class BookdropFileReviewComponent implements OnInit {
});
fileUi.copiedFields = {};
fileUi.savedFields = {};
this.copiedFlags[fileUi.file.id] = false;
});
this.copiedFlags = {};
}
selectAll(selected: boolean): void {
@@ -317,6 +326,26 @@ export class BookdropFileReviewComponent implements OnInit {
this.syncCurrentPageSelection();
}
confirmReset(): void {
const selectedCount = this.selectedCount;
if (selectedCount === 0) {
this.messageService.add({
severity: 'warn',
summary: 'No files selected',
detail: 'Please select files to reset metadata.',
});
return;
}
this.confirmationService.confirm({
message: 'Are you sure you want to reset all metadata changes made to the selected files?',
header: 'Confirm Reset',
icon: 'pi pi-exclamation-triangle',
acceptButtonStyleClass: 'p-button-danger',
accept: () => this.resetMetadata()
});
}
confirmFinalize(): void {
const selectedCount = this.selectedCount;
if (selectedCount === 0) {
@@ -332,8 +361,7 @@ export class BookdropFileReviewComponent implements OnInit {
message: `Are you sure you want to finalize the import of ${selectedCount} file${selectedCount !== 1 ? 's' : ''}?`,
header: 'Confirm Finalize',
icon: 'pi pi-exclamation-triangle',
acceptLabel: 'Yes',
rejectLabel: 'Cancel',
acceptButtonStyleClass: 'p-button-danger',
accept: () => this.finalizeImport(),
});
}
@@ -353,6 +381,7 @@ export class BookdropFileReviewComponent implements OnInit {
message: `Are you sure you want to delete ${selectedCount} selected Bookdrop file${selectedCount !== 1 ? 's' : ''}? This action cannot be undone.`,
header: 'Confirm Delete',
icon: 'pi pi-exclamation-triangle',
acceptButtonStyleClass: 'p-button-danger',
accept: () => {
const payload: any = {
selectAll: this.selectAllAcrossPages,