From 22eef5f3c5d531758514c17a903e13a21a8bd2df Mon Sep 17 00:00:00 2001 From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> Date: Thu, 12 Jun 2025 00:32:49 +0200 Subject: [PATCH] chore: more flexible modal manager types (#19123) * fix: required argument in onClose modal function * chore: more flexible modal manager types --- .../settings/auth/auth-settings.svelte | 2 +- .../components/asset-viewer/slideshow-bar.svelte | 2 +- .../actions/change-description-action.svelte | 2 +- .../lib/components/photos-page/asset-grid.svelte | 2 +- .../gallery-viewer/gallery-viewer.svelte | 3 +-- .../navigation-bar/account-info-panel.svelte | 2 +- .../side-bar/purchase-info.svelte | 2 +- web/src/lib/managers/modal-manager.svelte.ts | 16 +++++++++++----- .../[[assetId=id]]/+page.svelte | 2 +- .../routes/admin/library-management/+page.svelte | 2 +- web/src/routes/admin/users/+page.svelte | 2 +- 11 files changed, 21 insertions(+), 16 deletions(-) diff --git a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte index d7af26688a..a5384e9b41 100644 --- a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte +++ b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte @@ -36,7 +36,7 @@ const handleSave = async (skipConfirm: boolean) => { const allMethodsDisabled = !config.oauth.enabled && !config.passwordLogin.enabled; if (allMethodsDisabled && !skipConfirm) { - const isConfirmed = await modalManager.show(AuthDisableLoginConfirmModal, {}); + const isConfirmed = await modalManager.show(AuthDisableLoginConfirmModal); if (!isConfirmed) { return; } diff --git a/web/src/lib/components/asset-viewer/slideshow-bar.svelte b/web/src/lib/components/asset-viewer/slideshow-bar.svelte index 135da12d26..0bb81ea44b 100644 --- a/web/src/lib/components/asset-viewer/slideshow-bar.svelte +++ b/web/src/lib/components/asset-viewer/slideshow-bar.svelte @@ -104,7 +104,7 @@ if (document.fullscreenElement) { await document.exitFullscreen(); } - await modalManager.show(SlideshowSettingsModal, {}); + await modalManager.show(SlideshowSettingsModal); }; diff --git a/web/src/lib/components/photos-page/actions/change-description-action.svelte b/web/src/lib/components/photos-page/actions/change-description-action.svelte index 129d327fb9..740bed78ef 100644 --- a/web/src/lib/components/photos-page/actions/change-description-action.svelte +++ b/web/src/lib/components/photos-page/actions/change-description-action.svelte @@ -18,7 +18,7 @@ const { clearSelect, getOwnedAssets } = getAssetControlContext(); const handleUpdateDescription = async () => { - const description = await modalManager.show(AssetUpdateDecriptionConfirmModal, {}); + const description = await modalManager.show(AssetUpdateDecriptionConfirmModal); if (description) { const ids = getSelectedAssets(getOwnedAssets(), $user); diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 2dd9ef3ac7..ce2b1ca096 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -703,7 +703,7 @@ } isShortcutModalOpen = true; - await modalManager.show(ShortcutsModal, {}); + await modalManager.show(ShortcutsModal); isShortcutModalOpen = false; }; diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index 1c4d888cb8..09998ed060 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -5,11 +5,10 @@ import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import { AppRoute, AssetAction } from '$lib/constants'; import { modalManager } from '$lib/managers/modal-manager.svelte'; + import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types'; import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; - import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; - import type { Viewport } from '$lib/managers/timeline-manager/types'; import { showDeleteModal } from '$lib/stores/preferences.store'; import { featureFlags } from '$lib/stores/server-config.store'; import { handlePromiseError } from '$lib/utils'; diff --git a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte index 40ae672e0c..b079ecb241 100644 --- a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte @@ -51,7 +51,7 @@ shape="round" onclick={async () => { onClose(); - await modalManager.show(AvatarEditModal, {}); + await modalManager.show(AvatarEditModal); }} /> diff --git a/web/src/lib/components/shared-components/side-bar/purchase-info.svelte b/web/src/lib/components/shared-components/side-bar/purchase-info.svelte index 665c620563..5a984e94be 100644 --- a/web/src/lib/components/shared-components/side-bar/purchase-info.svelte +++ b/web/src/lib/components/shared-components/side-bar/purchase-info.svelte @@ -27,7 +27,7 @@ const { isPurchased } = purchaseStore; const openPurchaseModal = async () => { - await modalManager.show(PurchaseModal, {}); + await modalManager.show(PurchaseModal); showMessage = false; }; diff --git a/web/src/lib/managers/modal-manager.svelte.ts b/web/src/lib/managers/modal-manager.svelte.ts index 46363a105b..f5612d072d 100644 --- a/web/src/lib/managers/modal-manager.svelte.ts +++ b/web/src/lib/managers/modal-manager.svelte.ts @@ -6,15 +6,21 @@ type OnCloseData = T extends { onClose: (data?: infer R) => void } : T extends { onClose: (data: infer R) => void } ? R : never; -type ExtendsEmptyObject = keyof T extends never ? Record : T; +type ExtendsEmptyObject = keyof T extends never ? never : T; type StripValueIfOptional = T extends undefined ? undefined : T; +// if the modal does not expect any props, makes the props param optional but also allows passing `{}` and `undefined` +type OptionalParamIfEmpty = ExtendsEmptyObject extends never ? [] | [Record | undefined] : [T]; + class ModalManager { - show(Component: Component, props: ExtendsEmptyObject>) { - return this.open(Component, props).onClose; + show(Component: Component, ...props: OptionalParamIfEmpty>) { + return this.open(Component, ...props).onClose; } - open>(Component: Component, props: ExtendsEmptyObject>) { + open>( + Component: Component, + ...props: OptionalParamIfEmpty> + ) { let modal: object = {}; let onClose: (...args: [StripValueIfOptional]) => Promise; @@ -27,7 +33,7 @@ class ModalManager { modal = mount(Component, { target: document.body, props: { - ...(props as T), + ...((props?.[0] ?? {}) as T), onClose, }, }); diff --git a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte index 22fc8dac01..42da091997 100644 --- a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -200,7 +200,7 @@ icon={mdiInformationOutline} aria-label={$t('deduplication_info')} size="small" - onclick={() => modalManager.show(DuplicatesInformationModal, {})} + onclick={() => modalManager.show(DuplicatesInformationModal)} /> diff --git a/web/src/routes/admin/library-management/+page.svelte b/web/src/routes/admin/library-management/+page.svelte index 450e0d8c8d..3d8792749c 100644 --- a/web/src/routes/admin/library-management/+page.svelte +++ b/web/src/routes/admin/library-management/+page.svelte @@ -207,7 +207,7 @@ }; const onCreateNewLibraryClicked = async () => { - const result = await modalManager.show(LibraryUserPickerModal, {}); + const result = await modalManager.show(LibraryUserPickerModal); if (result) { await handleCreate(result); } diff --git a/web/src/routes/admin/users/+page.svelte b/web/src/routes/admin/users/+page.svelte index 87846b9542..3ebc67dabf 100644 --- a/web/src/routes/admin/users/+page.svelte +++ b/web/src/routes/admin/users/+page.svelte @@ -58,7 +58,7 @@ }; const handleCreate = async () => { - await modalManager.show(UserCreateModal, {}); + await modalManager.show(UserCreateModal); await refresh(); };