onSelect?.({ event, item: action })}
+/>
diff --git a/web/src/lib/components/album-page/album-shared-link.svelte b/web/src/lib/components/album-page/album-shared-link.svelte
index 580a865ae6..1b6db6ff69 100644
--- a/web/src/lib/components/album-page/album-shared-link.svelte
+++ b/web/src/lib/components/album-page/album-shared-link.svelte
@@ -1,10 +1,9 @@
@@ -40,14 +41,7 @@
{getShareProperties()}
-
handleShowSharedLinkQrCode(sharedLink)}
- />
-
+
+
diff --git a/web/src/lib/components/shared-components/search-bar/search-bar.svelte b/web/src/lib/components/shared-components/search-bar/search-bar.svelte
index 8c1d2c5d08..ea1147fe06 100644
--- a/web/src/lib/components/shared-components/search-bar/search-bar.svelte
+++ b/web/src/lib/components/shared-components/search-bar/search-bar.svelte
@@ -92,7 +92,7 @@
}
const result = modalManager.open(SearchFilterModal, { searchQuery });
- close = () => result.close(undefined);
+ close = () => result.close();
closeDropdown();
const searchResult = await result.onClose;
diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte
deleted file mode 100644
index 06369e7792..0000000000
--- a/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-{#if menuItem}
- handleCopySharedLinkUrl(sharedLink)} />
-{:else}
- handleCopySharedLinkUrl(sharedLink)}
- />
-{/if}
diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte
deleted file mode 100644
index f844d8483e..0000000000
--- a/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-{#if menuItem}
-
-{:else}
-
-{/if}
diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte
deleted file mode 100644
index 7482c1b6eb..0000000000
--- a/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-{#if menuItem}
-
-{:else}
-
-{/if}
diff --git a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte
index f811f60e77..b2c6cf296d 100644
--- a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte
+++ b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte
@@ -1,23 +1,19 @@
diff --git a/web/src/lib/managers/event-manager.svelte.ts b/web/src/lib/managers/event-manager.svelte.ts
index 44ee524658..e7d50f026d 100644
--- a/web/src/lib/managers/event-manager.svelte.ts
+++ b/web/src/lib/managers/event-manager.svelte.ts
@@ -10,6 +10,7 @@ export type Events = {
ThemeChange: [ThemeSetting];
SharedLinkCreate: [SharedLinkResponseDto];
SharedLinkUpdate: [SharedLinkResponseDto];
+ SharedLinkDelete: [SharedLinkResponseDto];
};
type Listener, K extends keyof EventMap> = (...params: EventMap[K]) => void;
diff --git a/web/src/lib/services/shared-link.service.ts b/web/src/lib/services/shared-link.service.ts
index 529b6b23b4..a48f0b5965 100644
--- a/web/src/lib/services/shared-link.service.ts
+++ b/web/src/lib/services/shared-link.service.ts
@@ -1,3 +1,5 @@
+import { goto } from '$app/navigation';
+import { AppRoute } from '$lib/constants';
import { eventManager } from '$lib/managers/event-manager.svelte';
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
import { serverConfig } from '$lib/stores/server-config.store';
@@ -6,15 +8,58 @@ import { handleError } from '$lib/utils/handle-error';
import { getFormatter } from '$lib/utils/i18n';
import {
createSharedLink,
+ removeSharedLink,
updateSharedLink,
type SharedLinkCreateDto,
type SharedLinkEditDto,
type SharedLinkResponseDto,
} from '@immich/sdk';
-import { modalManager, toastManager } from '@immich/ui';
+import { MenuItemType, menuManager, modalManager, toastManager, type MenuItem } from '@immich/ui';
+import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiDotsVertical, mdiQrcode } from '@mdi/js';
+import type { MessageFormatter } from 'svelte-i18n';
import { get } from 'svelte/store';
-const makeSharedLinkUrl = (sharedLink: SharedLinkResponseDto) => {
+export const getSharedLinkActions = ($t: MessageFormatter, sharedLink: SharedLinkResponseDto) => {
+ const Edit: MenuItem = {
+ title: $t('edit_link'),
+ icon: mdiCircleEditOutline,
+ onSelect: () => void goto(`${AppRoute.SHARED_LINKS}/${sharedLink.id}`),
+ };
+
+ const Delete: MenuItem = {
+ title: $t('delete_link'),
+ icon: mdiDelete,
+ color: 'danger',
+ onSelect: () => void handleDeleteSharedLink(sharedLink),
+ };
+
+ const Copy: MenuItem = {
+ title: $t('copy_link'),
+ icon: mdiContentCopy,
+ onSelect: () => void copyToClipboard(asUrl(sharedLink)),
+ };
+
+ const ViewQrCode: MenuItem = {
+ title: $t('view_qr_code'),
+ icon: mdiQrcode,
+ onSelect: () => void handleShowSharedLinkQrCode(sharedLink),
+ };
+
+ const ContextMenu: MenuItem = {
+ title: $t('shared_link_options'),
+ icon: mdiDotsVertical,
+ onSelect: ({ event }) =>
+ void menuManager.show({
+ target: event.currentTarget as HTMLElement,
+ position: 'top-right',
+ items: [Edit, Copy, MenuItemType.Divider, Delete],
+ }),
+ };
+
+ return { Edit, Delete, Copy, ViewQrCode, ContextMenu };
+};
+
+const asUrl = (sharedLink: SharedLinkResponseDto) => {
const path = sharedLink.slug ? `s/${sharedLink.slug}` : `share/${sharedLink.key}`;
return new URL(path, get(serverConfig).externalDomain || globalThis.location.origin).href;
};
@@ -54,11 +99,34 @@ export const handleUpdateSharedLink = async (sharedLink: SharedLinkResponseDto,
}
};
-export const handleShowSharedLinkQrCode = async (sharedLink: SharedLinkResponseDto) => {
+export const handleDeleteSharedLink = async (sharedLink: SharedLinkResponseDto): Promise => {
const $t = await getFormatter();
- await modalManager.show(QrCodeModal, { title: $t('view_link'), value: makeSharedLinkUrl(sharedLink) });
+
+ const success = await modalManager.showDialog({
+ title: $t('delete_shared_link'),
+ prompt: $t('confirm_delete_shared_link'),
+ confirmText: $t('delete'),
+ });
+
+ if (!success) {
+ return false;
+ }
+
+ try {
+ await removeSharedLink({ id: sharedLink.id });
+
+ eventManager.emit('SharedLinkDelete', sharedLink);
+
+ toastManager.success($t('deleted_shared_link'));
+
+ return true;
+ } catch (error) {
+ handleError(error, $t('errors.unable_to_delete_shared_link'));
+ return false;
+ }
};
-export const handleCopySharedLinkUrl = async (sharedLink: SharedLinkResponseDto) => {
- await copyToClipboard(makeSharedLinkUrl(sharedLink));
+const handleShowSharedLinkQrCode = async (sharedLink: SharedLinkResponseDto) => {
+ const $t = await getFormatter();
+ await modalManager.show(QrCodeModal, { title: $t('view_link'), value: asUrl(sharedLink) });
};
diff --git a/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte b/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte
index 4b63ce71a1..e0239a2a43 100644
--- a/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte
+++ b/web/src/routes/(user)/shared-links/[[id=id]]/+page.svelte
@@ -7,9 +7,7 @@
import { AppRoute } from '$lib/constants';
import GroupTab from '$lib/elements/GroupTab.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
- import { handleError } from '$lib/utils/handle-error';
- import { getAllSharedLinks, removeSharedLink, SharedLinkType, type SharedLinkResponseDto } from '@immich/sdk';
- import { modalManager, toastManager } from '@immich/ui';
+ import { getAllSharedLinks, SharedLinkType, type SharedLinkResponseDto } from '@immich/sdk';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@@ -31,26 +29,6 @@
await refresh();
});
- const handleDeleteLink = async (id: string) => {
- const isConfirmed = await modalManager.showDialog({
- title: $t('delete_shared_link'),
- prompt: $t('confirm_delete_shared_link'),
- confirmText: $t('delete'),
- });
-
- if (!isConfirmed) {
- return;
- }
-
- try {
- await removeSharedLink({ id });
- toastManager.success($t('deleted_shared_link'));
- await refresh();
- } catch (error) {
- handleError(error, $t('errors.unable_to_delete_shared_link'));
- }
- };
-
type Filter = 'all' | 'album' | 'individual';
const filterMap: Record = {
@@ -87,9 +65,13 @@
sharedLinks[index] = sharedLink;
}
};
+
+ const onSharedLinkDelete = (sharedLink: SharedLinkResponseDto) => {
+ sharedLinks = sharedLinks.filter(({ id }) => id !== sharedLink.id);
+ };
-
+
{#snippet buttons()}
@@ -108,7 +90,7 @@
{:else}
{#each filteredSharedLinks as sharedLink (sharedLink.id)}
- handleDeleteLink(sharedLink.id)} />
+
{/each}
{/if}