From 0486a4f0700249ec2c1d2319b44543c754f09291 Mon Sep 17 00:00:00 2001 From: Muppetteer Date: Sun, 14 Dec 2025 15:08:43 +1100 Subject: [PATCH] fix: Consistent dialogs (#1842) * fix/consistent-dialogs * fix: enforce consistent mobile dialog width * fix: cover search dialog image size --- .../book-browser/BookDialogHelperService.ts | 158 +++++++------ .../book-browser/book-browser.component.ts | 2 +- .../book-card/book-card.component.ts | 59 +---- .../book-table/book-table.component.ts | 2 - .../series-page/series-page.component.ts | 2 +- .../shelf-assigner.component.ts | 2 +- .../service/library-shelf-menu.service.ts | 55 +---- .../bookdrop-file-review.component.ts | 13 +- .../dashboard-settings.component.scss | 4 +- .../main-dashboard.component.ts | 10 +- .../library-creator.component.ts | 19 +- .../metadata-editor.component.scss | 4 + .../metadata-editor.component.ts | 21 +- .../metadata-viewer.component.ts | 50 +--- .../metadata-review-dialog-component.html | 5 - .../email-v2-provider.component.ts | 15 +- .../email-v2-recipient.component.ts | 15 +- .../user-management.component.ts | 14 +- .../metadata-progress-widget-component.ts | 14 +- .../layout-menu/app.menu.component.ts | 21 +- .../layout-menu/app.menuitem.component.ts | 6 +- .../layout-topbar/app.topbar.component.ts | 5 +- .../app/shared/service/icon-picker.service.ts | 20 +- .../services/dialog-launcher.service.ts | 222 +++++++++++++----- .../src/assets/layout/styles/global.scss | 15 ++ 25 files changed, 333 insertions(+), 420 deletions(-) diff --git a/booklore-ui/src/app/features/book/components/book-browser/BookDialogHelperService.ts b/booklore-ui/src/app/features/book/components/book-browser/BookDialogHelperService.ts index ad8700cc..8ad16f61 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/BookDialogHelperService.ts +++ b/booklore-ui/src/app/features/book/components/book-browser/BookDialogHelperService.ts @@ -1,5 +1,6 @@ import {inject, Injectable} from '@angular/core'; -import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; +import {DynamicDialogRef} from 'primeng/dynamicdialog'; +import {DialogLauncherService} from '../../../../shared/services/dialog-launcher.service'; import {ShelfAssignerComponent} from '../shelf-assigner/shelf-assigner.component'; import {LockUnlockMetadataDialogComponent} from './lock-unlock-metadata-dialog/lock-unlock-metadata-dialog.component'; import {MetadataRefreshType} from '../../../metadata/model/request/metadata-refresh-type.enum'; @@ -8,50 +9,61 @@ import {MultiBookMetadataEditorComponent} from '../../../metadata/component/mult import {MultiBookMetadataFetchComponent} from '../../../metadata/component/multi-book-metadata-fetch/multi-book-metadata-fetch-component'; import {FileMoverComponent} from '../../../../shared/components/file-mover/file-mover-component'; import {ShelfCreatorComponent} from '../shelf-creator/shelf-creator.component'; +import {BookSenderComponent} from '../book-sender/book-sender.component'; +import {MetadataFetchOptionsComponent} from '../../../metadata/component/metadata-options-dialog/metadata-fetch-options/metadata-fetch-options.component'; +import {BookMetadataCenterComponent} from '../../../metadata/component/book-metadata-center/book-metadata-center.component'; +import {CoverSearchComponent} from '../../../metadata/component/cover-search/cover-search.component'; +import {Book} from '../../model/book.model'; +import {AdditionalFileUploaderComponent} from '../additional-file-uploader/additional-file-uploader.component'; @Injectable({providedIn: 'root'}) export class BookDialogHelperService { - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); + + private openDialog(component: any, options: {}): DynamicDialogRef | null { + return this.dialogLauncherService.openDialog(component, options); + } - openShelfAssigner(bookIds: Set): DynamicDialogRef | null { - return this.dialogService.open(ShelfAssignerComponent, { - showHeader: false, - modal: true, - closable: true, - contentStyle: {overflow: 'hidden'}, - styleClass: 'dynamic-dialog-minimal', - baseZIndex: 10, + openBookDetailsDialog(bookId: number): DynamicDialogRef | null { + return this.openDialog(BookMetadataCenterComponent, { + header: 'Book Details', + styleClass: 'book-details-dialog dialog-maximal', data: { - isMultiBooks: true, - bookIds, + bookId: bookId, }, }); } - openShelfCreator(): DynamicDialogRef { - return this.dialogService.open(ShelfCreatorComponent, { + openShelfAssignerDialog(book: Book | null, bookIds: Set | null): DynamicDialogRef | null { + const data:any = {}; + if (book !== null) { + data.isMultiBooks = false; + data.book = book; + } else if (bookIds !== null) { + data.isMultiBooks = true; + data.bookIds = bookIds; + } else { + return null; + } + return this.openDialog(ShelfAssignerComponent, { + showHeader: false, + data: data, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openShelfCreatorDialog(): DynamicDialogRef { + return this.openDialog(ShelfCreatorComponent, { showHeader: false, - modal: true, - draggable: false, - dismissableMask: true, - closable: true, - contentStyle: {overflow: 'auto'}, styleClass: 'dynamic-dialog-minimal', - baseZIndex: 10, - style: { - position: 'absolute', - top: '15%', - }, })!; } openLockUnlockMetadataDialog(bookIds: Set): DynamicDialogRef | null { const count = bookIds.size; - return this.dialogService.open(LockUnlockMetadataDialogComponent, { + return this.openDialog(LockUnlockMetadataDialogComponent, { header: `Lock or Unlock Metadata for ${count} Selected Book${count > 1 ? 's' : ''}`, - modal: true, - closable: true, data: { bookIds: Array.from(bookIds), }, @@ -59,70 +71,82 @@ export class BookDialogHelperService { } openMetadataRefreshDialog(bookIds: Set): DynamicDialogRef | null { - return this.dialogService.open(MultiBookMetadataFetchComponent, { + return this.openDialog(MultiBookMetadataFetchComponent, { header: 'Metadata Refresh Options', - modal: true, - closable: true, data: { bookIds: Array.from(bookIds), metadataRefreshType: MetadataRefreshType.BOOKS, }, + styleClass: 'dialog-maximal', }); } openBulkMetadataEditDialog(bookIds: Set): DynamicDialogRef | null { - return this.dialogService.open(BulkMetadataUpdateComponent, { + return this.openDialog(BulkMetadataUpdateComponent, { header: 'Bulk Edit Metadata', - modal: true, - closable: true, - style: { - width: '90vw', - maxWidth: '1200px', - position: 'absolute' - }, data: { - bookIds: Array.from(bookIds) + bookIds: Array.from(bookIds), }, + styleClass: 'dialog-maximal', }); } openMultibookMetadataEditorDialog(bookIds: Set): DynamicDialogRef | null { - return this.dialogService.open(MultiBookMetadataEditorComponent, { - header: 'Bulk Edit Metadata', - showHeader: false, - modal: true, - closable: true, - closeOnEscape: true, - dismissableMask: true, - style: { - width: '95vw', - overflow: 'none', - }, + return this.openDialog(MultiBookMetadataEditorComponent, { + header: 'Multi-Book Metadata Editor', data: { - bookIds: Array.from(bookIds) + bookIds: Array.from(bookIds), }, + styleClass: 'dialog-maximal', }); } - openFileMoverDialog(selectedBooks: Set) { - const count = selectedBooks.size; - return this.dialogService.open(FileMoverComponent, { + openFileMoverDialog(bookIds: Set): DynamicDialogRef | null { + const count = bookIds.size; + return this.openDialog(FileMoverComponent, { header: `Organize Book Files (${count} book${count !== 1 ? 's' : ''})`, - showHeader: true, - maximizable: true, - modal: true, - closable: true, - closeOnEscape: false, - dismissableMask: false, - style: { - width: '95vw', - maxWidth: '97.5vw', - height: '90vh', - maxHeight: '95vh' - }, data: { - bookIds: selectedBooks + bookIds: Array.from(bookIds), }, + styleClass: 'dialog-maximal', + }); + } + + openCustomSendDialog(bookId: number): DynamicDialogRef | null { + return this.openDialog(BookSenderComponent, { + header: 'Send Book to Email', + data: { + bookId: bookId, + } + }); + } + + openCoverSearchDialog(bookId: number): DynamicDialogRef | null { + return this.openDialog(CoverSearchComponent, { + header: "Search Cover", + data: { + bookId: bookId, + }, + styleClass: 'dialog-maximal', + }); + } + + openMetadataFetchOptionsDialog(bookId: number): DynamicDialogRef | null { + return this.openDialog(MetadataFetchOptionsComponent, { + header: 'Metadata Refresh Options', + data: { + bookIds: [bookId], + metadataRefreshType: MetadataRefreshType.BOOKS, + } + }); + } + + openAdditionalFileUploaderDialog(book: Book): DynamicDialogRef | null { + return this.openDialog(AdditionalFileUploaderComponent, { + header: 'Upload Additional File', + data: { + book: book, + } }); } } diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-browser.component.ts b/booklore-ui/src/app/features/book/components/book-browser/book-browser.component.ts index b340a379..15af2c4f 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-browser.component.ts +++ b/booklore-ui/src/app/features/book/components/book-browser/book-browser.component.ts @@ -639,7 +639,7 @@ export class BookBrowserComponent implements OnInit, AfterViewInit { } openShelfAssigner(): void { - this.dynamicDialogRef = this.dialogHelperService.openShelfAssigner(this.selectedBooks); + this.dynamicDialogRef = this.dialogHelperService.openShelfAssignerDialog(null, this.selectedBooks); } lockUnlockMetadata(): void { diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.ts b/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.ts index 659879ef..12b0ec1b 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.ts +++ b/booklore-ui/src/app/features/book/components/book-browser/book-card/book-card.component.ts @@ -4,8 +4,6 @@ import {AdditionalFile, Book, ReadStatus} from '../../../model/book.model'; import {Button} from 'primeng/button'; import {MenuModule} from 'primeng/menu'; import {ConfirmationService, MenuItem, MessageService} from 'primeng/api'; -import {DialogService} from 'primeng/dynamicdialog'; -import {ShelfAssignerComponent} from '../../shelf-assigner/shelf-assigner.component'; import {BookService} from '../../../service/book.service'; import {CheckboxChangeEvent, CheckboxModule} from 'primeng/checkbox'; import {FormsModule} from '@angular/forms'; @@ -16,16 +14,13 @@ import {UserService} from '../../../../settings/user-management/user.service'; import {filter, Subject} from 'rxjs'; import {EmailService} from '../../../../settings/email-v2/email.service'; import {TieredMenu} from 'primeng/tieredmenu'; -import {BookSenderComponent} from '../../book-sender/book-sender.component'; import {Router} from '@angular/router'; import {ProgressBar} from 'primeng/progressbar'; -import {BookMetadataCenterComponent} from '../../../../metadata/component/book-metadata-center/book-metadata-center.component'; import {take, takeUntil} from 'rxjs/operators'; import {readStatusLabels} from '../book-filter/book-filter.component'; import {ResetProgressTypes} from '../../../../../shared/constants/reset-progress-type'; import {ReadStatusHelper} from '../../../helpers/read-status.helper'; import {BookDialogHelperService} from '../BookDialogHelperService'; -import {MetadataFetchOptionsComponent} from '../../../../metadata/component/metadata-options-dialog/metadata-fetch-options/metadata-fetch-options.component'; import {TaskHelperService} from '../../../../settings/task-management/task-helper.service'; @Component({ @@ -59,7 +54,6 @@ export class BookCardComponent implements OnInit, OnChanges, OnDestroy { private bookService = inject(BookService); private taskHelperService = inject(TaskHelperService); - private dialogService = inject(DialogService); private userService = inject(UserService); private emailService = inject(EmailService); private messageService = inject(MessageService); @@ -293,18 +287,7 @@ export class BookCardComponent implements OnInit, OnChanges, OnDestroy { label: 'Custom Send', icon: 'pi pi-envelope', command: () => { - this.dialogService.open(BookSenderComponent, { - header: 'Send Book to Email', - modal: true, - closable: true, - style: { - position: 'absolute', - top: '15%', - }, - data: { - bookId: this.book.id, - } - }); + this.bookDialogHelperService.openCustomSendDialog(this.book.id); } } ] @@ -341,15 +324,7 @@ export class BookCardComponent implements OnInit, OnChanges, OnDestroy { label: 'Custom Fetch', icon: 'pi pi-sync', command: () => { - this.dialogService.open(MetadataFetchOptionsComponent, { - header: 'Metadata Refresh Options', - modal: true, - closable: true, - data: { - bookIds: [this.book!.id], - metadataRefreshType: MetadataRefreshType.BOOKS, - }, - }); + this.bookDialogHelperService.openMetadataRefreshDialog(new Set([this.book!.id])) }, } ] @@ -457,19 +432,7 @@ export class BookCardComponent implements OnInit, OnChanges, OnDestroy { } private openShelfDialog(): void { - this.dialogService.open(ShelfAssignerComponent, { - header: `Update Book's Shelves`, - showHeader: false, - modal: true, - dismissableMask: true, - closable: true, - contentStyle: {overflow: 'hidden'}, - styleClass: 'dynamic-dialog-minimal', - baseZIndex: 10, - data: { - book: this.book, - }, - }); + this.bookDialogHelperService.openShelfAssignerDialog(this.book, null); } openSeriesInfo(): void { @@ -488,21 +451,7 @@ export class BookCardComponent implements OnInit, OnChanges, OnDestroy { queryParams: {tab: 'view'} }); } else { - this.dialogService.open(BookMetadataCenterComponent, { - width: '90%', - height: '90%', - data: {bookId: book.id}, - modal: true, - dismissableMask: true, - showHeader: true, - closable: true, - closeOnEscape: true, - draggable: false, - maximizable: false, - resizable: false, - header: 'Book Details', - styleClass: 'book-details-dialog' - }); + this.bookDialogHelperService.openBookDetailsDialog(book.id); } } diff --git a/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.ts b/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.ts index 21b66898..b7b2dc7f 100644 --- a/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.ts +++ b/booklore-ui/src/app/features/book/components/book-browser/book-table/book-table.component.ts @@ -13,8 +13,6 @@ import {MessageService} from 'primeng/api'; import {Router, RouterLink} from '@angular/router'; import {filter, Subject} from 'rxjs'; import {UserService} from '../../../../settings/user-management/user.service'; -import {BookMetadataCenterComponent} from '../../../../metadata/component/book-metadata-center/book-metadata-center.component'; -import {DialogService} from 'primeng/dynamicdialog'; import {take, takeUntil} from 'rxjs/operators'; import {ReadStatusHelper} from '../../../helpers/read-status.helper'; diff --git a/booklore-ui/src/app/features/book/components/series-page/series-page.component.ts b/booklore-ui/src/app/features/book/components/series-page/series-page.component.ts index 543f839e..ccb24120 100644 --- a/booklore-ui/src/app/features/book/components/series-page/series-page.component.ts +++ b/booklore-ui/src/app/features/book/components/series-page/series-page.component.ts @@ -13,7 +13,7 @@ import { Tab, TabList, TabPanel, TabPanels, Tabs } from "primeng/tabs"; import { Tag } from "primeng/tag"; import { VirtualScrollerModule } from "@iharbeck/ngx-virtual-scroller"; import { ProgressSpinner } from "primeng/progressspinner"; -import { DialogService, DynamicDialogRef } from "primeng/dynamicdialog"; +import { DynamicDialogRef } from "primeng/dynamicdialog"; import { Router } from "@angular/router"; @Component({ diff --git a/booklore-ui/src/app/features/book/components/shelf-assigner/shelf-assigner.component.ts b/booklore-ui/src/app/features/book/components/shelf-assigner/shelf-assigner.component.ts index 68e7d97d..aa8b279f 100644 --- a/booklore-ui/src/app/features/book/components/shelf-assigner/shelf-assigner.component.ts +++ b/booklore-ui/src/app/features/book/components/shelf-assigner/shelf-assigner.component.ts @@ -91,7 +91,7 @@ export class ShelfAssignerComponent implements OnInit { } createShelfDialog(): void { - const dialogRef = this.bookDialogHelper.openShelfCreator(); + const dialogRef = this.bookDialogHelper.openShelfCreatorDialog(); dialogRef.onClose.subscribe((created: boolean) => { if (created) { diff --git a/booklore-ui/src/app/features/book/service/library-shelf-menu.service.ts b/booklore-ui/src/app/features/book/service/library-shelf-menu.service.ts index 33e69671..d860d916 100644 --- a/booklore-ui/src/app/features/book/service/library-shelf-menu.service.ts +++ b/booklore-ui/src/app/features/book/service/library-shelf-menu.service.ts @@ -5,19 +5,13 @@ import {LibraryService} from './library.service'; import {ShelfService} from './shelf.service'; import {Library} from '../model/library.model'; import {Shelf} from '../model/shelf.model'; -import {DialogService} from 'primeng/dynamicdialog'; import {MetadataRefreshType} from '../../metadata/model/request/metadata-refresh-type.enum'; -import {LibraryCreatorComponent} from '../../library-creator/library-creator.component'; -import {ShelfEditDialogComponent} from '../components/shelf-edit-dialog/shelf-edit-dialog.component'; import {MagicShelf, MagicShelfService} from '../../magic-shelf/service/magic-shelf.service'; -import {MetadataFetchOptionsComponent} from '../../metadata/component/metadata-options-dialog/metadata-fetch-options/metadata-fetch-options.component'; -import {MagicShelfComponent} from '../../magic-shelf/component/magic-shelf-component'; -import {TaskCreateRequest, TaskType} from '../../settings/task-management/task.service'; -import {MetadataRefreshRequest} from '../../metadata/model/request/metadata-refresh-request.model'; import {TaskHelperService} from '../../settings/task-management/task-helper.service'; import {UserService} from "../../settings/user-management/user.service"; import {LoadingService} from '../../../core/services/loading.service'; import {finalize} from 'rxjs'; +import {DialogLauncherService} from '../../../shared/services/dialog-launcher.service'; @Injectable({ providedIn: 'root', @@ -30,7 +24,7 @@ export class LibraryShelfMenuService { private shelfService = inject(ShelfService); private taskHelperService = inject(TaskHelperService); private router = inject(Router); - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); private magicShelfService = inject(MagicShelfService); private userService = inject(UserService); private loadingService = inject(LoadingService); @@ -44,17 +38,7 @@ export class LibraryShelfMenuService { label: 'Edit Library', icon: 'pi pi-pen-to-square', command: () => { - this.dialogService.open(LibraryCreatorComponent, { - header: 'Edit Library', - modal: true, - closable: true, - showHeader: false, - styleClass: 'dynamic-dialog-minimal', - data: { - mode: 'edit', - libraryId: entity?.id - } - }); + this.dialogLauncherService.openLibraryEditDialog(entity?.id); } }, { @@ -93,15 +77,7 @@ export class LibraryShelfMenuService { label: 'Custom Fetch Metadata', icon: 'pi pi-sync', command: () => { - this.dialogService.open(MetadataFetchOptionsComponent, { - header: 'Metadata Refresh Options', - modal: true, - closable: true, - data: { - libraryId: entity?.id, - metadataRefreshType: MetadataRefreshType.LIBRARY - } - }) + this.dialogLauncherService.openLibraryMetadataFetchDialog(entity?.id); } }, { @@ -168,16 +144,7 @@ export class LibraryShelfMenuService { label: 'Edit Shelf', icon: 'pi pi-pen-to-square', command: () => { - this.dialogService.open(ShelfEditDialogComponent, { - header: 'Edit Shelf', - modal: true, - closable: true, - showHeader: false, - styleClass: 'dynamic-dialog-minimal', - data: { - shelfId: entity?.id - }, - }) + this.dialogLauncherService.openShelfEditDialog(entity?.id); } }, { @@ -230,17 +197,7 @@ export class LibraryShelfMenuService { icon: 'pi pi-pen-to-square', disabled: disableOptions, command: () => { - this.dialogService.open(MagicShelfComponent, { - header: 'Edit Magic Shelf', - modal: true, - closable: true, - showHeader: false, - styleClass: 'dynamic-dialog-minimal', - data: { - id: entity?.id, - editMode: true, - } - }) + this.dialogLauncherService.openMagicShelfEditDialog(entity?.id); } }, { diff --git a/booklore-ui/src/app/features/bookdrop/component/bookdrop-file-review/bookdrop-file-review.component.ts b/booklore-ui/src/app/features/bookdrop/component/bookdrop-file-review/bookdrop-file-review.component.ts index d1aa6c64..24945bba 100644 --- a/booklore-ui/src/app/features/bookdrop/component/bookdrop-file-review/bookdrop-file-review.component.ts +++ b/booklore-ui/src/app/features/bookdrop/component/bookdrop-file-review/bookdrop-file-review.component.ts @@ -18,7 +18,6 @@ import {Observable, Subscription} from 'rxjs'; import {AppSettings} from '../../../../shared/model/app-settings.model'; import {AppSettingsService} from '../../../../shared/service/app-settings.service'; -import {DialogService} from 'primeng/dynamicdialog'; import {BookMetadata} from '../../../book/model/book.model'; import {UrlHelperService} from '../../../../shared/service/url-helper.service'; import {Checkbox} from 'primeng/checkbox'; @@ -26,7 +25,7 @@ import {NgClass, NgStyle} from '@angular/common'; import {Paginator} from 'primeng/paginator'; import {ActivatedRoute} from '@angular/router'; import {BookdropFileMetadataPickerComponent} from '../bookdrop-file-metadata-picker/bookdrop-file-metadata-picker.component'; -import {BookdropFinalizeResultDialogComponent} from '../bookdrop-finalize-result-dialog/bookdrop-finalize-result-dialog-component'; +import {DialogLauncherService} from '../../../../shared/services/dialog-launcher.service'; export interface BookdropFileUI { file: BookdropFile; @@ -64,7 +63,7 @@ export class BookdropFileReviewComponent implements OnInit { private readonly libraryService = inject(LibraryService); private readonly confirmationService = inject(ConfirmationService); private readonly destroyRef = inject(DestroyRef); - private readonly dialogService = inject(DialogService); + private readonly dialogLauncherService = inject(DialogLauncherService); private readonly appSettingsService = inject(AppSettingsService); private readonly messageService = inject(MessageService); private readonly urlHelper = inject(UrlHelperService); @@ -494,13 +493,7 @@ export class BookdropFileReviewComponent implements OnInit { detail: 'Import process finished. See details below.', }); - this.dialogService.open(BookdropFinalizeResultDialogComponent, { - header: 'Import Summary', - modal: true, - closable: true, - closeOnEscape: true, - data: {result: result}, - }); + this.dialogLauncherService.openBookdropFinalizeResultDialog(result); const finalizedIds = new Set(files.map(f => f.fileId)); Object.keys(this.fileUiCache).forEach(idStr => { diff --git a/booklore-ui/src/app/features/dashboard/components/dashboard-settings/dashboard-settings.component.scss b/booklore-ui/src/app/features/dashboard/components/dashboard-settings/dashboard-settings.component.scss index caad078d..4f7ead61 100644 --- a/booklore-ui/src/app/features/dashboard/components/dashboard-settings/dashboard-settings.component.scss +++ b/booklore-ui/src/app/features/dashboard/components/dashboard-settings/dashboard-settings.component.scss @@ -1,13 +1,11 @@ .dashboard-settings { - width: 1000px; - max-width: 1200px; + max-width: 600px; min-height: 300px; padding: 2rem 1rem 0 1rem; margin: 0 auto; @media (max-width: 768px) { width: 100%; - max-width: 100%; padding: 3rem 1rem 0 1rem; box-sizing: border-box; } diff --git a/booklore-ui/src/app/features/dashboard/components/main-dashboard/main-dashboard.component.ts b/booklore-ui/src/app/features/dashboard/components/main-dashboard/main-dashboard.component.ts index 73fb0eeb..74d29a4a 100644 --- a/booklore-ui/src/app/features/dashboard/components/main-dashboard/main-dashboard.component.ts +++ b/booklore-ui/src/app/features/dashboard/components/main-dashboard/main-dashboard.component.ts @@ -14,7 +14,6 @@ import {ProgressSpinner} from 'primeng/progressspinner'; import {TooltipModule} from 'primeng/tooltip'; import {DashboardConfigService} from '../../services/dashboard-config.service'; import {ScrollerConfig, ScrollerType} from '../../models/dashboard-config.model'; -import {DashboardSettingsComponent} from '../dashboard-settings/dashboard-settings.component'; import {MagicShelfService} from '../../../magic-shelf/service/magic-shelf.service'; import {BookRuleEvaluatorService} from '../../../magic-shelf/service/book-rule-evaluator.service'; import {GroupRule} from '../../../magic-shelf/component/magic-shelf-component'; @@ -39,7 +38,6 @@ const DEFAULT_MAX_ITEMS = 20; standalone: true }) export class MainDashboardComponent implements OnInit { - ref: DynamicDialogRef | undefined | null; private bookService = inject(BookService); private dialogLauncher = inject(DialogLauncherService); @@ -203,14 +201,10 @@ export class MainDashboardComponent implements OnInit { } openDashboardSettings(): void { - this.ref = this.dialogLauncher.open({ - component: DashboardSettingsComponent, - header: 'Configure Dashboard', - showHeader: false - }); + this.dialogLauncher.openDashboardSettingsDialog(); } createNewLibrary() { - this.dialogLauncher.openLibraryCreatorDialog(); + this.dialogLauncher.openLibraryCreateDialog(); } } diff --git a/booklore-ui/src/app/features/library-creator/library-creator.component.ts b/booklore-ui/src/app/features/library-creator/library-creator.component.ts index 4ee1e495..5c5ac6f0 100644 --- a/booklore-ui/src/app/features/library-creator/library-creator.component.ts +++ b/booklore-ui/src/app/features/library-creator/library-creator.component.ts @@ -1,6 +1,5 @@ import {Component, inject, OnInit} from '@angular/core'; -import {DialogService, DynamicDialogConfig, DynamicDialogRef} from 'primeng/dynamicdialog'; -import {DirectoryPickerComponent} from '../../shared/components/directory-picker/directory-picker.component'; +import {DynamicDialogConfig, DynamicDialogRef} from 'primeng/dynamicdialog'; import {MessageService} from 'primeng/api'; import {Router} from '@angular/router'; import {LibraryService} from '../book/service/library.service'; @@ -15,6 +14,7 @@ import {IconPickerService, IconSelection} from '../../shared/service/icon-picker import {Select} from 'primeng/select'; import {Button} from 'primeng/button'; import {IconDisplayComponent} from '../../shared/components/icon-display/icon-display.component'; +import {DialogLauncherService} from '../../shared/services/dialog-launcher.service'; @Component({ selector: 'app-library-creator', @@ -31,7 +31,6 @@ export class LibraryCreatorComponent implements OnInit { mode!: string; library!: Library | undefined; editModeLibraryName: string = ''; - directoryPickerDialogRef!: DynamicDialogRef | null; watch: boolean = false; scanMode: LibraryScanMode = 'FILE_AS_BOOK'; defaultBookFormat: BookFileType | undefined = undefined; @@ -48,7 +47,7 @@ export class LibraryCreatorComponent implements OnInit { {label: 'CBX/CBZ/CBR', value: 'CBX'} ]; - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); private dynamicDialogRef = inject(DynamicDialogRef); private dynamicDialogConfig = inject(DynamicDialogConfig); private libraryService = inject(LibraryService); @@ -85,16 +84,8 @@ export class LibraryCreatorComponent implements OnInit { } openDirectoryPicker(): void { - this.directoryPickerDialogRef = this.dialogService.open(DirectoryPickerComponent, { - header: 'Select Media Directory', - showHeader: false, - modal: true, - closable: true, - styleClass: 'dynamic-dialog-minimal', - contentStyle: {overflow: 'hidden'}, - baseZIndex: 10 - }); - this.directoryPickerDialogRef?.onClose.subscribe((selectedFolders: string[] | null) => { + const ref = this.dialogLauncherService.openDirectoryPickerDialog(); + ref?.onClose.subscribe((selectedFolders: string[] | null) => { if (selectedFolders && selectedFolders.length > 0) { selectedFolders.forEach(folder => { if (!this.folders.includes(folder)) { diff --git a/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.scss b/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.scss index aa6e675c..c592618c 100644 --- a/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.scss +++ b/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.scss @@ -10,6 +10,10 @@ width: 250px; } +::ng-deep .cover-item p-image { + width: 150px; +} + ::ng-deep p-image img { margin: 0 auto; } diff --git a/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.ts b/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.ts index 6c806316..645df8af 100644 --- a/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.ts +++ b/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-editor/metadata-editor.component.ts @@ -14,7 +14,6 @@ import {BookService} from "../../../../book/service/book.service"; import {ProgressSpinner} from "primeng/progressspinner"; import {Tooltip} from "primeng/tooltip"; import {filter, take} from "rxjs/operators"; -import {DialogService} from "primeng/dynamicdialog"; import {takeUntilDestroyed} from "@angular/core/rxjs-interop"; import {MetadataRefreshType} from "../../../model/request/metadata-refresh-type.enum"; import {AutoComplete} from "primeng/autocomplete"; @@ -22,8 +21,8 @@ import {DatePicker} from "primeng/datepicker"; import {Textarea} from "primeng/textarea"; import {Image} from "primeng/image"; import {LazyLoadImageModule} from "ng-lazyload-image"; -import {CoverSearchComponent} from '../../cover-search/cover-search.component'; import {TaskHelperService} from '../../../../settings/task-management/task-helper.service'; +import {BookDialogHelperService} from "../../../../book/components/book-browser/BookDialogHelperService"; @Component({ selector: "app-metadata-editor", @@ -61,7 +60,7 @@ export class MetadataEditorComponent implements OnInit { private bookService = inject(BookService); private taskHelperService = inject(TaskHelperService); protected urlHelper = inject(UrlHelperService); - private dialogService = inject(DialogService); + private bookDialogHelperService = inject(BookDialogHelperService); private destroyRef = inject(DestroyRef); metadataForm: FormGroup; @@ -684,21 +683,7 @@ export class MetadataEditorComponent implements OnInit { } openCoverSearch() { - const ref = this.dialogService.open(CoverSearchComponent, { - header: "Search Cover", - modal: true, - closable: true, - data: { - bookId: [this.currentBookId], - }, - style: { - width: "90vw", - height: "90vh", - maxWidth: "1200px", - position: "absolute", - }, - }); - + const ref = this.bookDialogHelperService.openCoverSearchDialog(this.currentBookId); ref?.onClose.subscribe((result) => { if (result) { this.metadataForm.get("thumbnailUrl")?.setValue(result); diff --git a/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-viewer/metadata-viewer.component.ts b/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-viewer/metadata-viewer.component.ts index c2b900d0..c56659e9 100644 --- a/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-viewer/metadata-viewer.component.ts +++ b/booklore-ui/src/app/features/metadata/component/book-metadata-center/metadata-viewer/metadata-viewer.component.ts @@ -10,10 +10,8 @@ import {UrlHelperService} from '../../../../../shared/service/url-helper.service import {UserService} from '../../../../settings/user-management/user.service'; import {SplitButton} from 'primeng/splitbutton'; import {ConfirmationService, MenuItem, MessageService} from 'primeng/api'; -import {BookSenderComponent} from '../../../../book/components/book-sender/book-sender.component'; -import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; +import {DynamicDialogRef} from 'primeng/dynamicdialog'; import {EmailService} from '../../../../settings/email-v2/email.service'; -import {ShelfAssignerComponent} from '../../../../book/components/shelf-assigner/shelf-assigner.component'; import {Tooltip} from 'primeng/tooltip'; import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; import {Editor} from 'primeng/editor'; @@ -29,13 +27,10 @@ import {DatePicker} from 'primeng/datepicker'; import {Tab, TabList, TabPanel, TabPanels, Tabs} from 'primeng/tabs'; import {BookReviewsComponent} from '../../../../book/components/book-reviews/book-reviews.component'; import {ProgressSpinner} from 'primeng/progressspinner'; - import {TieredMenu} from 'primeng/tieredmenu'; -import {AdditionalFileUploaderComponent} from '../../../../book/components/additional-file-uploader/additional-file-uploader.component'; import {Image} from 'primeng/image'; import {BookDialogHelperService} from '../../../../book/components/book-browser/BookDialogHelperService'; import {TagColor, TagComponent} from '../../../../../shared/components/tag/tag.component'; -import {MetadataFetchOptionsComponent} from '../../metadata-options-dialog/metadata-fetch-options/metadata-fetch-options.component'; import {BookNotesComponent} from '../../../../book/components/book-notes/book-notes-component'; import {TaskHelperService} from '../../../../settings/task-management/task-helper.service'; import { @@ -57,7 +52,7 @@ export class MetadataViewerComponent implements OnInit, OnChanges { @ViewChild(Editor) quillEditor!: Editor; private originalRecommendedBooks: BookRecommendation[] = []; - private dialogService = inject(DialogService); + private bookDialogHelperService = inject(BookDialogHelperService) private emailService = inject(EmailService); private messageService = inject(MessageService); private bookService = inject(BookService); @@ -65,7 +60,6 @@ export class MetadataViewerComponent implements OnInit, OnChanges { protected urlHelper = inject(UrlHelperService); protected userService = inject(UserService); private confirmationService = inject(ConfirmationService); - private bookDialogHelperService = inject(BookDialogHelperService); private router = inject(Router); private destroyRef = inject(DestroyRef); @@ -105,13 +99,7 @@ export class MetadataViewerComponent implements OnInit, OnChanges { { label: 'Custom Send', command: () => { - this.dialogService.open(BookSenderComponent, { - header: 'Send Book to Email', - modal: true, - closable: true, - style: {position: 'absolute', top: '20%'}, - data: {bookId: metadata.bookId} - }); + this.bookDialogHelperService.openCustomSendDialog(metadata.bookId); } } ]) @@ -124,15 +112,7 @@ export class MetadataViewerComponent implements OnInit, OnChanges { label: 'Custom Fetch', icon: 'pi pi-sync', command: () => { - this.dialogService.open(MetadataFetchOptionsComponent, { - header: 'Metadata Refresh Options', - modal: true, - closable: true, - data: { - bookIds: [book.id], - metadataRefreshType: MetadataRefreshType.BOOKS, - }, - }); + this.bookDialogHelperService.openMetadataFetchOptionsDialog(book.id); } } ]) @@ -197,16 +177,7 @@ export class MetadataViewerComponent implements OnInit, OnChanges { label: 'Upload File', icon: 'pi pi-upload', command: () => { - this.dialogService.open(AdditionalFileUploaderComponent, { - header: 'Upload Additional File', - modal: true, - closable: true, - style: { - position: 'absolute', - top: '10%', - }, - data: {book} - }); + this.bookDialogHelperService.openAdditionalFileUploaderDialog(book); }, }, { @@ -425,16 +396,7 @@ export class MetadataViewerComponent implements OnInit, OnChanges { } assignShelf(bookId: number) { - this.dialogService.open(ShelfAssignerComponent, { - header: `Update Book's Shelves`, - showHeader: false, - dismissableMask: true, - modal: true, - closable: true, - contentStyle: {overflow: 'hidden'}, - baseZIndex: 10, - data: {book: this.bookService.getBookByIdFromState(bookId)} - }); + this.bookDialogHelperService.openShelfAssignerDialog(this.bookService.getBookByIdFromState(bookId), null); } updateReadStatus(status: ReadStatus): void { diff --git a/booklore-ui/src/app/features/metadata/component/metadata-review-dialog/metadata-review-dialog-component.html b/booklore-ui/src/app/features/metadata/component/metadata-review-dialog/metadata-review-dialog-component.html index f566117c..fe947ba5 100644 --- a/booklore-ui/src/app/features/metadata/component/metadata-review-dialog/metadata-review-dialog-component.html +++ b/booklore-ui/src/app/features/metadata/component/metadata-review-dialog/metadata-review-dialog-component.html @@ -1,10 +1,5 @@ @if (!loading) {
- -
-

Review Metadata Proposal

-
-
@if (currentProposal?.metadataJson; as proposed) { { if (result) { this.loadEmailProviders(); diff --git a/booklore-ui/src/app/features/settings/email-v2/email-v2-recipient/email-v2-recipient.component.ts b/booklore-ui/src/app/features/settings/email-v2/email-v2-recipient/email-v2-recipient.component.ts index c162a0e9..cd3f7ec5 100644 --- a/booklore-ui/src/app/features/settings/email-v2/email-v2-recipient/email-v2-recipient.component.ts +++ b/booklore-ui/src/app/features/settings/email-v2/email-v2-recipient/email-v2-recipient.component.ts @@ -1,15 +1,14 @@ import {Component, inject, OnInit} from '@angular/core'; import {Button} from 'primeng/button'; - import {MessageService, PrimeTemplate} from 'primeng/api'; import {RadioButton} from 'primeng/radiobutton'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {TableModule} from 'primeng/table'; import {Tooltip} from 'primeng/tooltip'; -import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; +import {DynamicDialogRef} from 'primeng/dynamicdialog'; import {EmailV2RecipientService} from './email-v2-recipient.service'; import {EmailRecipient} from '../email-recipient.model'; -import {CreateEmailRecipientDialogComponent} from '../create-email-recipient-dialog/create-email-recipient-dialog.component'; +import {DialogLauncherService} from '../../../../shared/services/dialog-launcher.service'; @Component({ selector: 'app-email-v2-recipient', @@ -29,7 +28,7 @@ export class EmailV2RecipientComponent implements OnInit { recipientEmails: EmailRecipient[] = []; editingRecipientIds: number[] = []; ref: DynamicDialogRef | undefined | null; - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); private emailRecipientService = inject(EmailV2RecipientService); private messageService = inject(MessageService); defaultRecipientId: any; @@ -111,13 +110,7 @@ export class EmailV2RecipientComponent implements OnInit { } openAddRecipientDialog() { - this.ref = this.dialogService.open(CreateEmailRecipientDialogComponent, { - header: 'Add New Recipient', - modal: true, - closable: true, - showHeader: false, - styleClass: 'dynamic-dialog-minimal', - }); + this.ref = this.dialogLauncherService.openEmailRecipientDialog(); this.ref?.onClose.subscribe((result) => { if (result) { this.loadRecipientEmails(); diff --git a/booklore-ui/src/app/features/settings/user-management/user-management.component.ts b/booklore-ui/src/app/features/settings/user-management/user-management.component.ts index 17d7e77a..835e8ff9 100644 --- a/booklore-ui/src/app/features/settings/user-management/user-management.component.ts +++ b/booklore-ui/src/app/features/settings/user-management/user-management.component.ts @@ -1,8 +1,7 @@ import {Component, inject, OnDestroy, OnInit} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {Button} from 'primeng/button'; -import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; -import {CreateUserDialogComponent} from './create-user-dialog/create-user-dialog.component'; +import {DynamicDialogRef} from 'primeng/dynamicdialog'; import {TableModule} from 'primeng/table'; import {LowerCasePipe, TitleCasePipe} from '@angular/common'; import {User, UserService} from './user.service'; @@ -16,6 +15,7 @@ import {Password} from 'primeng/password'; import {filter, take, takeUntil} from 'rxjs/operators'; import {Subject} from 'rxjs'; import {Tooltip} from 'primeng/tooltip'; +import {DialogLauncherService} from '../../../shared/services/dialog-launcher.service'; @Component({ selector: 'app-user-management', @@ -36,7 +36,7 @@ import {Tooltip} from 'primeng/tooltip'; }) export class UserManagementComponent implements OnInit, OnDestroy { ref: DynamicDialogRef | undefined | null; - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); private userService = inject(UserService); private libraryService = inject(LibraryService); private messageService = inject(MessageService); @@ -105,13 +105,7 @@ export class UserManagementComponent implements OnInit, OnDestroy { } openCreateUserDialog() { - this.ref = this.dialogService.open(CreateUserDialogComponent, { - header: 'Create New User', - showHeader: false, - modal: true, - closable: true, - styleClass: 'dynamic-dialog-minimal', - }); + this.ref = this.dialogLauncherService.openCreateUserDialog(); this.ref?.onClose.subscribe((result) => { if (result) { this.loadUsers(); diff --git a/booklore-ui/src/app/shared/components/metadata-progress-widget/metadata-progress-widget-component.ts b/booklore-ui/src/app/shared/components/metadata-progress-widget/metadata-progress-widget-component.ts index 381fc889..cfe99f23 100644 --- a/booklore-ui/src/app/shared/components/metadata-progress-widget/metadata-progress-widget-component.ts +++ b/booklore-ui/src/app/shared/components/metadata-progress-widget/metadata-progress-widget-component.ts @@ -6,15 +6,14 @@ import {ProgressBarModule} from 'primeng/progressbar'; import {ButtonModule} from 'primeng/button'; import {Divider} from 'primeng/divider'; import {Tooltip} from 'primeng/tooltip'; -import {DialogService} from 'primeng/dynamicdialog'; import {MessageService} from 'primeng/api'; import {MetadataBatchProgressNotification, MetadataBatchStatus, MetadataBatchStatusLabels} from '../../model/metadata-batch-progress.model'; import {MetadataProgressService} from '../../service/metadata-progress-service'; -import {MetadataReviewDialogComponent} from '../../../features/metadata/component/metadata-review-dialog/metadata-review-dialog-component'; import {MetadataTaskService} from '../../../features/book/service/metadata-task'; import {Tag} from 'primeng/tag'; import {TaskService} from '../../../features/settings/task-management/task.service'; +import {DialogLauncherService} from '../../services/dialog-launcher.service'; @Component({ selector: 'app-metadata-progress-widget', @@ -27,7 +26,7 @@ export class MetadataProgressWidgetComponent implements OnInit, OnDestroy { activeTasks: { [taskId: string]: MetadataBatchProgressNotification } = {}; private destroy$ = new Subject(); - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); private metadataProgressService = inject(MetadataProgressService); private metadataTaskService = inject(MetadataTaskService); private taskService = inject(TaskService); @@ -102,14 +101,7 @@ export class MetadataProgressWidgetComponent implements OnInit, OnDestroy { } reviewTask(taskId: string): void { - this.dialogService.open(MetadataReviewDialogComponent, { - showHeader: false, - width: '90vw', - height: '90vh', - data: {taskId}, - closable: false, - modal: true - }); + this.dialogLauncherService.openMetadataReviewDialog(taskId); } cancelTask(taskId: string): void { diff --git a/booklore-ui/src/app/shared/layout/component/layout-menu/app.menu.component.ts b/booklore-ui/src/app/shared/layout/component/layout-menu/app.menu.component.ts index d42f23af..ba4d2993 100644 --- a/booklore-ui/src/app/shared/layout/component/layout-menu/app.menu.component.ts +++ b/booklore-ui/src/app/shared/layout/component/layout-menu/app.menu.component.ts @@ -9,10 +9,10 @@ import {ShelfService} from '../../../../features/book/service/shelf.service'; import {BookService} from '../../../../features/book/service/book.service'; import {LibraryShelfMenuService} from '../../../../features/book/service/library-shelf-menu.service'; import {AppVersion, VersionService} from '../../../service/version.service'; -import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; -import {VersionChangelogDialogComponent} from './version-changelog-dialog/version-changelog-dialog.component'; +import {DynamicDialogRef} from 'primeng/dynamicdialog'; import {UserService} from '../../../../features/settings/user-management/user.service'; import {MagicShelfService, MagicShelfState} from '../../../../features/magic-shelf/service/magic-shelf.service'; +import {DialogLauncherService} from '../../../services/dialog-launcher.service'; @Component({ selector: 'app-menu', @@ -34,7 +34,7 @@ export class AppMenuComponent implements OnInit { private bookService = inject(BookService); private versionService = inject(VersionService); private libraryShelfMenuService = inject(LibraryShelfMenuService); - private dialogService = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); private userService = inject(UserService); private magicShelfService = inject(MagicShelfService); @@ -198,20 +198,7 @@ export class AppMenuComponent implements OnInit { } openChangelogDialog() { - const isMobile = window.innerWidth <= 768; - this.dynamicDialogRef = this.dialogService.open(VersionChangelogDialogComponent, { - header: 'What’s New', - modal: true, - closable: true, - style: { - position: 'absolute', - top: '10%', - bottom: '10%', - width: isMobile ? '90vw' : '800px', - maxWidth: isMobile ? '90vw' : '800px', - minWidth: isMobile ? '90vw' : '800px', - }, - }); + this.dialogLauncherService.openVersionChangelogDialog(); } getVersionUrl(version: string | undefined): string { diff --git a/booklore-ui/src/app/shared/layout/component/layout-menu/app.menuitem.component.ts b/booklore-ui/src/app/shared/layout/component/layout-menu/app.menuitem.component.ts index 7ed172a0..235a0a94 100644 --- a/booklore-ui/src/app/shared/layout/component/layout-menu/app.menuitem.component.ts +++ b/booklore-ui/src/app/shared/layout/component/layout-menu/app.menuitem.component.ts @@ -155,13 +155,13 @@ export class AppMenuitemComponent implements OnInit, OnDestroy { openDialog(item: any) { if (item.type === 'library' && this.canManipulateLibrary) { - this.dialogLauncher.openLibraryCreatorDialog(); + this.dialogLauncher.openLibraryCreateDialog(); } if (item.type === 'magicShelf') { - this.dialogLauncher.openMagicShelfDialog(); + this.dialogLauncher.openMagicShelfCreateDialog(); } if (item.type === 'shelf') { - this.bookDialogHelperService.openShelfCreator(); + this.bookDialogHelperService.openShelfCreatorDialog(); } } diff --git a/booklore-ui/src/app/shared/layout/component/layout-topbar/app.topbar.component.ts b/booklore-ui/src/app/shared/layout/component/layout-topbar/app.topbar.component.ts index 2a40c78e..6e1fe88c 100644 --- a/booklore-ui/src/app/shared/layout/component/layout-topbar/app.topbar.component.ts +++ b/booklore-ui/src/app/shared/layout/component/layout-topbar/app.topbar.component.ts @@ -2,7 +2,7 @@ import {Component, ElementRef, OnDestroy, ViewChild} from '@angular/core'; import {MenuItem} from 'primeng/api'; import {LayoutService} from '../layout-main/service/app.layout.service'; import {Router, RouterLink} from '@angular/router'; -import {DialogService as PrimeDialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; +import {DynamicDialogRef} from 'primeng/dynamicdialog'; import {TooltipModule} from 'primeng/tooltip'; import {FormsModule} from '@angular/forms'; import {InputTextModule} from 'primeng/inputtext'; @@ -72,7 +72,6 @@ export class AppTopBarComponent implements OnDestroy { constructor( public layoutService: LayoutService, - public dialogService: PrimeDialogService, private notificationService: NotificationEventService, private router: Router, private authService: AuthService, @@ -120,7 +119,7 @@ export class AppTopBarComponent implements OnDestroy { } openLibraryCreatorDialog(): void { - this.dialogLauncher.openLibraryCreatorDialog(); + this.dialogLauncher.openLibraryCreateDialog(); } openFileUploadDialog(): void { diff --git a/booklore-ui/src/app/shared/service/icon-picker.service.ts b/booklore-ui/src/app/shared/service/icon-picker.service.ts index e837cc65..056db3ba 100644 --- a/booklore-ui/src/app/shared/service/icon-picker.service.ts +++ b/booklore-ui/src/app/shared/service/icon-picker.service.ts @@ -1,7 +1,6 @@ import {inject, Injectable} from '@angular/core'; -import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog'; -import {IconPickerComponent} from '../components/icon-picker/icon-picker-component'; import {Observable} from 'rxjs'; +import {DialogLauncherService} from '../services/dialog-launcher.service'; export interface IconSelection { type: 'PRIME_NG' | 'CUSTOM_SVG'; @@ -10,23 +9,10 @@ export interface IconSelection { @Injectable({providedIn: 'root'}) export class IconPickerService { - private dialog = inject(DialogService); + private dialogLauncherService = inject(DialogLauncherService); open(): Observable { - const isMobile = window.innerWidth <= 768; - const ref: DynamicDialogRef | null = this.dialog.open(IconPickerComponent, { - header: 'Choose an Icon', - modal: true, - closable: true, - style: { - position: 'absolute', - top: '10%', - bottom: '10%', - width: isMobile ? '90vw' : '800px', - maxWidth: isMobile ? '90vw' : '800px', - minWidth: isMobile ? '90vw' : '800px', - } - }); + const ref = this.dialogLauncherService.openIconPickerDialog(); return ref!.onClose as Observable; } } diff --git a/booklore-ui/src/app/shared/services/dialog-launcher.service.ts b/booklore-ui/src/app/shared/services/dialog-launcher.service.ts index acd71839..68c3aa8b 100644 --- a/booklore-ui/src/app/shared/services/dialog-launcher.service.ts +++ b/booklore-ui/src/app/shared/services/dialog-launcher.service.ts @@ -5,6 +5,19 @@ import {LibraryCreatorComponent} from '../../features/library-creator/library-cr import {BookUploaderComponent} from '../components/book-uploader/book-uploader.component'; import {UserProfileDialogComponent} from '../../features/settings/user-profile-dialog/user-profile-dialog.component'; import {MagicShelfComponent} from '../../features/magic-shelf/component/magic-shelf-component'; +import {DashboardSettingsComponent} from '../../features/dashboard/components/dashboard-settings/dashboard-settings.component'; +import {VersionChangelogDialogComponent} from '../layout/component/layout-menu/version-changelog-dialog/version-changelog-dialog.component'; +import {CreateUserDialogComponent} from '../../features/settings/user-management/create-user-dialog/create-user-dialog.component'; +import {CreateEmailRecipientDialogComponent} from '../../features/settings/email-v2/create-email-recipient-dialog/create-email-recipient-dialog.component'; +import {CreateEmailProviderDialogComponent} from '../../features/settings/email-v2/create-email-provider-dialog/create-email-provider-dialog.component'; +import {DirectoryPickerComponent} from '../components/directory-picker/directory-picker.component'; +import {BookdropFinalizeResultDialogComponent} from '../../features/bookdrop/component/bookdrop-finalize-result-dialog/bookdrop-finalize-result-dialog-component'; +import {BookdropFinalizeResult} from '../../features/bookdrop/service/bookdrop.service'; +import {MetadataReviewDialogComponent} from '../../features/metadata/component/metadata-review-dialog/metadata-review-dialog-component'; +import {MetadataRefreshType} from '../../features/metadata/model/request/metadata-refresh-type.enum'; +import {MetadataFetchOptionsComponent} from '../../features/metadata/component/metadata-options-dialog/metadata-fetch-options/metadata-fetch-options.component'; +import {ShelfEditDialogComponent} from '../../features/book/components/shelf-edit-dialog/shelf-edit-dialog.component'; +import {IconPickerComponent} from '../components/icon-picker/icon-picker-component'; @Injectable({ providedIn: 'root', @@ -13,73 +26,164 @@ export class DialogLauncherService { dialogService = inject(DialogService); - open(options: { component: any; header: string; top?: string; width?: string; showHeader?: boolean; styleClass?: string }): DynamicDialogRef | null { - const isMobile = window.innerWidth <= 768; - const {component, header, top, width, showHeader = true, styleClass} = options; + private defaultDialogOptions = { + baseZIndex: 10, + closable: true, + dismissableMask: true, + draggable: false, + modal: true, + resizable: false, + showHeader: true, + } + + openDialog(component: any, options: {}): DynamicDialogRef | null { return this.dialogService.open(component, { - header, - showHeader, - modal: true, - closable: true, - styleClass: styleClass, - style: { - position: 'absolute', - ...(top ? {top} : {}), - ...(isMobile - ? { - width: '90vw', - maxWidth: '90vw', - minWidth: '90vw', - } - : width - ? {width} - : {}), + ...this.defaultDialogOptions, + ...options, + }); + } + + openDashboardSettingsDialog(): DynamicDialogRef | null { + return this.openDialog(DashboardSettingsComponent, { + header: 'Configure Dashboard', + }); + } + + openGithubSupportDialog(): DynamicDialogRef | null { + return this.openDialog(GithubSupportDialog, { + header: 'Support Booklore', + }); + } + + openLibraryCreateDialog(): DynamicDialogRef | null { + return this.openDialog(LibraryCreatorComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openDirectoryPickerDialog(): DynamicDialogRef | null { + return this.openDialog(DirectoryPickerComponent, { + header: 'Select Media Directory', + styleClass: 'dynamic-dialog-minimal', + }); + } + + openLibraryEditDialog(libraryId: number): DynamicDialogRef | null { + return this.openDialog(LibraryCreatorComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + data: { + mode: 'edit', + libraryId: libraryId + } + }); + } + + openLibraryMetadataFetchDialog(libraryId: number): DynamicDialogRef | null { + return this.openDialog(MetadataFetchOptionsComponent, { + header: 'Metadata Refresh Options', + data: { + libraryId: libraryId, + metadataRefreshType: MetadataRefreshType.LIBRARY, + } + }); + } + + openShelfEditDialog(shelfId: number): DynamicDialogRef | null { + return this.openDialog(ShelfEditDialogComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + data: { + shelfId: shelfId + }, + }) + } + + openFileUploadDialog(): DynamicDialogRef | null { + return this.openDialog(BookUploaderComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openCreateUserDialog(): DynamicDialogRef | null { + return this.openDialog(CreateUserDialogComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openUserProfileDialog(): DynamicDialogRef | null { + return this.openDialog(UserProfileDialogComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openMagicShelfCreateDialog(): DynamicDialogRef | null { + return this.openDialog(MagicShelfComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openMagicShelfEditDialog(shelfId: number): DynamicDialogRef | null { + return this.openDialog(MagicShelfComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + data: { + id: shelfId, + editMode: true, + } + }) + } + + openVersionChangelogDialog(): DynamicDialogRef | null { + return this.openDialog(VersionChangelogDialogComponent, { + header: "What's New", + styleClass: 'dialog-maximal', + }); + } + + openEmailRecipientDialog(): DynamicDialogRef | null { + return this.openDialog(CreateEmailRecipientDialogComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openEmailProviderDialog(): DynamicDialogRef | null { + return this.openDialog(CreateEmailProviderDialogComponent, { + showHeader: false, + styleClass: 'dynamic-dialog-minimal', + }); + } + + openBookdropFinalizeResultDialog(result: BookdropFinalizeResult): DynamicDialogRef | null { + return this.openDialog(BookdropFinalizeResultDialogComponent, { + header: 'Import Summary', + data: { + result: result, }, }); } - openGithubSupportDialog(): void { - this.open({ - component: GithubSupportDialog, - header: 'Support Booklore', - showHeader: true, - top: '15%' + openMetadataReviewDialog(taskId: string): DynamicDialogRef | null { + return this.openDialog(MetadataReviewDialogComponent, { + header: 'Review Metadata Proposal', + data: { + taskId, + }, + styleClass: 'dialog-maximal', }); } - openLibraryCreatorDialog(): void { - this.open({ - component: LibraryCreatorComponent, - header: 'Create New Library', - styleClass: 'dynamic-dialog-minimal', - showHeader: false + openIconPickerDialog(): DynamicDialogRef | null { + return this.openDialog(IconPickerComponent, { + header: 'Choose an Icon', + styleClass: 'dialog-maximal', }); } - openFileUploadDialog(): void { - this.open({ - component: BookUploaderComponent, - header: 'Book Uploader', - showHeader: false, - styleClass: 'dynamic-dialog-minimal' - }); - } - - openUserProfileDialog(): void { - this.open({ - component: UserProfileDialogComponent, - header: 'User Profile Information', - styleClass: 'dynamic-dialog-minimal', - showHeader: false - }); - } - - openMagicShelfDialog(): void { - this.open({ - component: MagicShelfComponent, - header: 'Magic Shelf Creator', - styleClass: 'dynamic-dialog-minimal', - showHeader: false - }); - } -} +} \ No newline at end of file diff --git a/booklore-ui/src/assets/layout/styles/global.scss b/booklore-ui/src/assets/layout/styles/global.scss index 4274a346..7c42dddf 100644 --- a/booklore-ui/src/assets/layout/styles/global.scss +++ b/booklore-ui/src/assets/layout/styles/global.scss @@ -4,6 +4,14 @@ display: none; } +.p-dialog { + @media (max-width: 768px) { + width: 95vw !important; + max-width: 95vw !important; + max-height: 95vh !important; + } +} + .dynamic-dialog-minimal.p-dialog { border: none; @@ -12,6 +20,13 @@ } } +.dialog-maximal.p-dialog { + width: 95vw; + max-width: 1200px; + height: 95vh; + max-height: 95vh; +} + .gradient-divider { min-height: 1px; height: 1px;