refactor: view shared link (#23766)
parent
a4e65a7ea8
commit
45304f1211
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import SharedLinkCopy from '$lib/components/sharedlinks-page/actions/shared-link-copy.svelte';
|
import SharedLinkCopy from '$lib/components/sharedlinks-page/actions/shared-link-copy.svelte';
|
||||||
|
import { handleViewSharedLinkQrCode } from '$lib/services/shared-link.service';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import type { AlbumResponseDto, SharedLinkResponseDto } from '@immich/sdk';
|
import type { AlbumResponseDto, SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { IconButton, Text } from '@immich/ui';
|
import { IconButton, Text } from '@immich/ui';
|
||||||
|
|
@ -10,10 +11,9 @@
|
||||||
type Props = {
|
type Props = {
|
||||||
album: AlbumResponseDto;
|
album: AlbumResponseDto;
|
||||||
sharedLink: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
onViewQrCode: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const { album, sharedLink, onViewQrCode }: Props = $props();
|
const { album, sharedLink }: Props = $props();
|
||||||
|
|
||||||
const getShareProperties = () =>
|
const getShareProperties = () =>
|
||||||
[
|
[
|
||||||
|
|
@ -46,8 +46,8 @@
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
icon={mdiQrcode}
|
icon={mdiQrcode}
|
||||||
onclick={onViewQrCode}
|
onclick={() => handleViewSharedLinkQrCode(sharedLink)}
|
||||||
/>
|
/>
|
||||||
<SharedLinkCopy link={sharedLink} />
|
<SharedLinkCopy {sharedLink} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import AlbumEditModal from '$lib/modals/AlbumEditModal.svelte';
|
import AlbumEditModal from '$lib/modals/AlbumEditModal.svelte';
|
||||||
import AlbumShareModal from '$lib/modals/AlbumShareModal.svelte';
|
import AlbumShareModal from '$lib/modals/AlbumShareModal.svelte';
|
||||||
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
|
|
||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { handleConfirmAlbumDelete, handleDownloadAlbum } from '$lib/services/album.service';
|
import { handleConfirmAlbumDelete, handleDownloadAlbum } from '$lib/services/album.service';
|
||||||
|
import { handleViewSharedLinkQrCode } from '$lib/services/shared-link.service';
|
||||||
import {
|
import {
|
||||||
AlbumFilter,
|
AlbumFilter,
|
||||||
AlbumGroupBy,
|
AlbumGroupBy,
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
} from '$lib/stores/preferences.store';
|
} from '$lib/stores/preferences.store';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { userInteraction } from '$lib/stores/user.svelte';
|
import { userInteraction } from '$lib/stores/user.svelte';
|
||||||
import { makeSharedLinkUrl } from '$lib/utils';
|
|
||||||
import { getSelectedAlbumGroupOption, sortAlbums, stringToSortOrder, type AlbumGroup } from '$lib/utils/album-utils';
|
import { getSelectedAlbumGroupOption, sortAlbums, stringToSortOrder, type AlbumGroup } from '$lib/utils/album-utils';
|
||||||
import type { ContextMenuPosition } from '$lib/utils/context-menu';
|
import type { ContextMenuPosition } from '$lib/utils/context-menu';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
|
@ -259,7 +258,7 @@
|
||||||
const sharedLink = await modalManager.show(SharedLinkCreateModal, { albumId: selectedAlbum.id });
|
const sharedLink = await modalManager.show(SharedLinkCreateModal, { albumId: selectedAlbum.id });
|
||||||
if (sharedLink) {
|
if (sharedLink) {
|
||||||
handleSharedLinkCreated(selectedAlbum);
|
handleSharedLinkCreated(selectedAlbum);
|
||||||
await modalManager.show(QrCodeModal, { title: $t('view_link'), value: makeSharedLinkUrl(sharedLink) });
|
await handleViewSharedLinkQrCode(sharedLink);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
|
|
||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { makeSharedLinkUrl } from '$lib/utils';
|
import { handleViewSharedLinkQrCode } from '$lib/services/shared-link.service';
|
||||||
import type { AssetResponseDto } from '@immich/sdk';
|
import type { AssetResponseDto } from '@immich/sdk';
|
||||||
import { IconButton, modalManager } from '@immich/ui';
|
import { IconButton, modalManager } from '@immich/ui';
|
||||||
import { mdiShareVariantOutline } from '@mdi/js';
|
import { mdiShareVariantOutline } from '@mdi/js';
|
||||||
|
|
@ -15,9 +14,8 @@
|
||||||
|
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
const sharedLink = await modalManager.show(SharedLinkCreateModal, { assetIds: [asset.id] });
|
const sharedLink = await modalManager.show(SharedLinkCreateModal, { assetIds: [asset.id] });
|
||||||
|
|
||||||
if (sharedLink) {
|
if (sharedLink) {
|
||||||
await modalManager.show(QrCodeModal, { title: $t('view_link'), value: makeSharedLinkUrl(sharedLink) });
|
await handleViewSharedLinkQrCode(sharedLink);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,21 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
import { copyToClipboard, makeSharedLinkUrl } from '$lib/utils';
|
import { handleCopySharedLinkUrl } from '$lib/services/shared-link.service';
|
||||||
import type { SharedLinkResponseDto } from '@immich/sdk';
|
import type { SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { IconButton } from '@immich/ui';
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiContentCopy } from '@mdi/js';
|
import { mdiContentCopy } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
link: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
menuItem?: boolean;
|
menuItem?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { link, menuItem = false }: Props = $props();
|
let { sharedLink, menuItem = false }: Props = $props();
|
||||||
|
|
||||||
const handleCopy = async () => {
|
|
||||||
await copyToClipboard(makeSharedLinkUrl(link));
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
<MenuOption text={$t('copy_link')} icon={mdiContentCopy} onClick={handleCopy} />
|
<MenuOption text={$t('copy_link')} icon={mdiContentCopy} onClick={() => handleCopySharedLinkUrl(sharedLink)} />
|
||||||
{:else}
|
{:else}
|
||||||
<IconButton
|
<IconButton
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
|
@ -27,6 +23,6 @@
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
aria-label={$t('copy_link')}
|
aria-label={$t('copy_link')}
|
||||||
icon={mdiContentCopy}
|
icon={mdiContentCopy}
|
||||||
onclick={handleCopy}
|
onclick={() => handleCopySharedLinkUrl(sharedLink)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ vi.mock('$lib/utils');
|
||||||
describe('ShareCover component', () => {
|
describe('ShareCover component', () => {
|
||||||
it('renders an image when the shared link is an album', () => {
|
it('renders an image when the shared link is an album', () => {
|
||||||
const component = render(ShareCover, {
|
const component = render(ShareCover, {
|
||||||
link: sharedLinkFactory.build({ album: albumFactory.build({ albumName: '123' }) }),
|
sharedLink: sharedLinkFactory.build({ album: albumFactory.build({ albumName: '123' }) }),
|
||||||
preload: false,
|
preload: false,
|
||||||
class: 'text',
|
class: 'text',
|
||||||
});
|
});
|
||||||
|
|
@ -23,7 +23,7 @@ describe('ShareCover component', () => {
|
||||||
it('renders an image when the shared link is an individual share', () => {
|
it('renders an image when the shared link is an individual share', () => {
|
||||||
vi.mocked(getAssetThumbnailUrl).mockReturnValue('/asdf');
|
vi.mocked(getAssetThumbnailUrl).mockReturnValue('/asdf');
|
||||||
const component = render(ShareCover, {
|
const component = render(ShareCover, {
|
||||||
link: sharedLinkFactory.build({ assets: [assetFactory.build({ id: 'someId' })] }),
|
sharedLink: sharedLinkFactory.build({ assets: [assetFactory.build({ id: 'someId' })] }),
|
||||||
preload: false,
|
preload: false,
|
||||||
class: 'text',
|
class: 'text',
|
||||||
});
|
});
|
||||||
|
|
@ -37,7 +37,7 @@ describe('ShareCover component', () => {
|
||||||
|
|
||||||
it('renders an image when the shared link has no album or assets', () => {
|
it('renders an image when the shared link has no album or assets', () => {
|
||||||
const component = render(ShareCover, {
|
const component = render(ShareCover, {
|
||||||
link: sharedLinkFactory.build(),
|
sharedLink: sharedLinkFactory.build(),
|
||||||
preload: false,
|
preload: false,
|
||||||
class: 'text',
|
class: 'text',
|
||||||
});
|
});
|
||||||
|
|
@ -48,9 +48,9 @@ describe('ShareCover component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('renders fallback image when asset is not resized', () => {
|
it.skip('renders fallback image when asset is not resized', () => {
|
||||||
const link = sharedLinkFactory.build({ assets: [assetFactory.build()] });
|
const sharedLink = sharedLinkFactory.build({ assets: [assetFactory.build()] });
|
||||||
render(ShareCover, {
|
render(ShareCover, {
|
||||||
link,
|
sharedLink,
|
||||||
preload: false,
|
preload: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,29 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { SharedLinkResponseDto } from '@immich/sdk';
|
|
||||||
import AlbumCover from '$lib/components/album-page/album-cover.svelte';
|
import AlbumCover from '$lib/components/album-page/album-cover.svelte';
|
||||||
import NoCover from '$lib/components/sharedlinks-page/covers/no-cover.svelte';
|
|
||||||
import AssetCover from '$lib/components/sharedlinks-page/covers/asset-cover.svelte';
|
import AssetCover from '$lib/components/sharedlinks-page/covers/asset-cover.svelte';
|
||||||
|
import NoCover from '$lib/components/sharedlinks-page/covers/no-cover.svelte';
|
||||||
import { getAssetThumbnailUrl } from '$lib/utils';
|
import { getAssetThumbnailUrl } from '$lib/utils';
|
||||||
|
import type { SharedLinkResponseDto } from '@immich/sdk';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
link: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
preload?: boolean;
|
preload?: boolean;
|
||||||
class?: string;
|
class?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { link, preload = false, class: className = '' }: Props = $props();
|
let { sharedLink, preload = false, class: className = '' }: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative shrink-0 size-24">
|
<div class="relative shrink-0 size-24">
|
||||||
{#if link?.album}
|
{#if sharedLink?.album}
|
||||||
<AlbumCover album={link.album} class={className} {preload} />
|
<AlbumCover album={sharedLink.album} class={className} {preload} />
|
||||||
{:else if link.assets[0]}
|
{:else if sharedLink.assets[0]}
|
||||||
<AssetCover
|
<AssetCover
|
||||||
alt={$t('individual_share')}
|
alt={$t('individual_share')}
|
||||||
class={className}
|
class={className}
|
||||||
{preload}
|
{preload}
|
||||||
src={getAssetThumbnailUrl(link.assets[0].id)}
|
src={getAssetThumbnailUrl(sharedLink.assets[0].id)}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<NoCover alt={$t('unnamed_share')} class={className} {preload} />
|
<NoCover alt={$t('unnamed_share')} class={className} {preload} />
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
link: SharedLinkResponseDto;
|
sharedLink: SharedLinkResponseDto;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { link, onDelete }: Props = $props();
|
let { sharedLink, onDelete }: Props = $props();
|
||||||
|
|
||||||
let now = DateTime.now();
|
let now = DateTime.now();
|
||||||
let expiresAt = $derived(link.expiresAt ? DateTime.fromISO(link.expiresAt) : undefined);
|
let expiresAt = $derived(sharedLink.expiresAt ? DateTime.fromISO(sharedLink.expiresAt) : undefined);
|
||||||
let isExpired = $derived(expiresAt ? now > expiresAt : false);
|
let isExpired = $derived(expiresAt ? now > expiresAt : false);
|
||||||
|
|
||||||
const getCountDownExpirationDate = (expiresAtDate: DateTime, now: DateTime) => {
|
const getCountDownExpirationDate = (expiresAtDate: DateTime, now: DateTime) => {
|
||||||
|
|
@ -41,10 +41,10 @@
|
||||||
>
|
>
|
||||||
<svelte:element
|
<svelte:element
|
||||||
this={isExpired ? 'div' : 'a'}
|
this={isExpired ? 'div' : 'a'}
|
||||||
href={isExpired ? undefined : `${AppRoute.SHARE}/${link.key}`}
|
href={isExpired ? undefined : `${AppRoute.SHARE}/${sharedLink.key}`}
|
||||||
class="flex gap-4 w-full py-4"
|
class="flex gap-4 w-full py-4"
|
||||||
>
|
>
|
||||||
<ShareCover class="transition-all duration-300 hover:shadow-lg" {link} />
|
<ShareCover class="transition-all duration-300 hover:shadow-lg" {sharedLink} />
|
||||||
|
|
||||||
<div class="flex flex-col justify-between">
|
<div class="flex flex-col justify-between">
|
||||||
<div class="info-top">
|
<div class="info-top">
|
||||||
|
|
@ -62,34 +62,34 @@
|
||||||
|
|
||||||
<div class="text-sm pb-2">
|
<div class="text-sm pb-2">
|
||||||
<p class="flex place-items-center gap-2 text-primary break-all uppercase">
|
<p class="flex place-items-center gap-2 text-primary break-all uppercase">
|
||||||
{#if link.type === SharedLinkType.Album}
|
{#if sharedLink.type === SharedLinkType.Album}
|
||||||
{link.album?.albumName}
|
{sharedLink.album?.albumName}
|
||||||
{:else if link.type === SharedLinkType.Individual}
|
{:else if sharedLink.type === SharedLinkType.Individual}
|
||||||
{$t('individual_share')}
|
{$t('individual_share')}
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="text-sm">{link.description ?? ''}</p>
|
<p class="text-sm">{sharedLink.description ?? ''}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-2 text-xl">
|
<div class="flex flex-wrap gap-2 text-xl">
|
||||||
{#if link.allowUpload}
|
{#if sharedLink.allowUpload}
|
||||||
<Badge rounded="full"><span class="text-xs px-1">{$t('upload')}</span></Badge>
|
<Badge rounded="full"><span class="text-xs px-1">{$t('upload')}</span></Badge>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if link.allowDownload}
|
{#if sharedLink.allowDownload}
|
||||||
<Badge rounded="full"><span class="text-xs px-1">{$t('download')}</span></Badge>
|
<Badge rounded="full"><span class="text-xs px-1">{$t('download')}</span></Badge>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if link.showMetadata}
|
{#if sharedLink.showMetadata}
|
||||||
<Badge rounded="full"><span class="uppercase text-xs px-1">{$t('exif')}</span></Badge>
|
<Badge rounded="full"><span class="uppercase text-xs px-1">{$t('exif')}</span></Badge>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if link.password}
|
{#if sharedLink.password}
|
||||||
<Badge rounded="full"><span class="text-xs px-1">{$t('password')}</span></Badge>
|
<Badge rounded="full"><span class="text-xs px-1">{$t('password')}</span></Badge>
|
||||||
{/if}
|
{/if}
|
||||||
{#if link.slug}
|
{#if sharedLink.slug}
|
||||||
<Badge rounded="full"><span class="text-xs px-1">{$t('custom_url')}</span></Badge>
|
<Badge rounded="full"><span class="text-xs px-1">{$t('custom_url')}</span></Badge>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -97,8 +97,8 @@
|
||||||
</svelte:element>
|
</svelte:element>
|
||||||
<div class="flex flex-auto flex-col place-content-center place-items-end text-end ms-4">
|
<div class="flex flex-auto flex-col place-content-center place-items-end text-end ms-4">
|
||||||
<div class="sm:flex hidden">
|
<div class="sm:flex hidden">
|
||||||
<SharedLinkEdit sharedLink={link} />
|
<SharedLinkEdit {sharedLink} />
|
||||||
<SharedLinkCopy {link} />
|
<SharedLinkCopy {sharedLink} />
|
||||||
<SharedLinkDelete {onDelete} />
|
<SharedLinkDelete {onDelete} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -110,8 +110,8 @@
|
||||||
size="large"
|
size="large"
|
||||||
hideContent
|
hideContent
|
||||||
>
|
>
|
||||||
<SharedLinkEdit menuItem sharedLink={link} />
|
<SharedLinkEdit menuItem {sharedLink} />
|
||||||
<SharedLinkCopy menuItem {link} />
|
<SharedLinkCopy menuItem {sharedLink} />
|
||||||
<SharedLinkDelete menuItem {onDelete} />
|
<SharedLinkDelete menuItem {onDelete} />
|
||||||
</ButtonContextMenu>
|
</ButtonContextMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||||
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
|
|
||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { makeSharedLinkUrl } from '$lib/utils';
|
import { handleViewSharedLinkQrCode } from '$lib/services/shared-link.service';
|
||||||
import { IconButton, modalManager } from '@immich/ui';
|
import { IconButton, modalManager } from '@immich/ui';
|
||||||
import { mdiShareVariantOutline } from '@mdi/js';
|
import { mdiShareVariantOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
@ -15,7 +14,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sharedLink) {
|
if (sharedLink) {
|
||||||
await modalManager.show(QrCodeModal, { title: $t('view_link'), value: makeSharedLinkUrl(sharedLink) });
|
await handleViewSharedLinkQrCode(sharedLink);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
import AlbumSharedLink from '$lib/components/album-page/album-shared-link.svelte';
|
import AlbumSharedLink from '$lib/components/album-page/album-shared-link.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import Dropdown from '$lib/elements/Dropdown.svelte';
|
import Dropdown from '$lib/elements/Dropdown.svelte';
|
||||||
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
|
|
||||||
import { makeSharedLinkUrl } from '$lib/utils';
|
|
||||||
import {
|
import {
|
||||||
AlbumUserRole,
|
AlbumUserRole,
|
||||||
getAllSharedLinks,
|
getAllSharedLinks,
|
||||||
|
|
@ -13,7 +11,7 @@
|
||||||
type SharedLinkResponseDto,
|
type SharedLinkResponseDto,
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { Button, Icon, Link, Modal, ModalBody, modalManager, Stack, Text } from '@immich/ui';
|
import { Button, Icon, Link, Modal, ModalBody, Stack, Text } from '@immich/ui';
|
||||||
import { mdiCheck, mdiEye, mdiLink, mdiPencil } from '@mdi/js';
|
import { mdiCheck, mdiEye, mdiLink, mdiPencil } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
@ -29,13 +27,6 @@
|
||||||
let users: UserResponseDto[] = $state([]);
|
let users: UserResponseDto[] = $state([]);
|
||||||
let selectedUsers: Record<string, { user: UserResponseDto; role: AlbumUserRole }> = $state({});
|
let selectedUsers: Record<string, { user: UserResponseDto; role: AlbumUserRole }> = $state({});
|
||||||
|
|
||||||
const handleViewQrCode = async (sharedLink: SharedLinkResponseDto) => {
|
|
||||||
await modalManager.show(QrCodeModal, {
|
|
||||||
title: $t('view_link'),
|
|
||||||
value: makeSharedLinkUrl(sharedLink),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const roleOptions: Array<{ title: string; value: AlbumUserRole | 'none'; icon?: string }> = [
|
const roleOptions: Array<{ title: string; value: AlbumUserRole | 'none'; icon?: string }> = [
|
||||||
{ title: $t('role_editor'), value: AlbumUserRole.Editor, icon: mdiPencil },
|
{ title: $t('role_editor'), value: AlbumUserRole.Editor, icon: mdiPencil },
|
||||||
{ title: $t('role_viewer'), value: AlbumUserRole.Viewer, icon: mdiEye },
|
{ title: $t('role_viewer'), value: AlbumUserRole.Viewer, icon: mdiEye },
|
||||||
|
|
@ -174,7 +165,7 @@
|
||||||
|
|
||||||
<Stack gap={4}>
|
<Stack gap={4}>
|
||||||
{#each sharedLinks as sharedLink (sharedLink.id)}
|
{#each sharedLinks as sharedLink (sharedLink.id)}
|
||||||
<AlbumSharedLink {album} {sharedLink} onViewQrCode={() => handleViewQrCode(sharedLink)} />
|
<AlbumSharedLink {album} {sharedLink} />
|
||||||
{/each}
|
{/each}
|
||||||
</Stack>
|
</Stack>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
|
||||||
|
import { serverConfig } from '$lib/stores/server-config.store';
|
||||||
|
import { copyToClipboard } from '$lib/utils';
|
||||||
|
import { getFormatter } from '$lib/utils/i18n';
|
||||||
|
import type { SharedLinkResponseDto } from '@immich/sdk';
|
||||||
|
import { modalManager } from '@immich/ui';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
|
||||||
|
const makeSharedLinkUrl = (sharedLink: SharedLinkResponseDto) => {
|
||||||
|
const path = sharedLink.slug ? `s/${sharedLink.slug}` : `share/${sharedLink.key}`;
|
||||||
|
return new URL(path, get(serverConfig).externalDomain || globalThis.location.origin).href;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleViewSharedLinkQrCode = async (sharedLink: SharedLinkResponseDto) => {
|
||||||
|
const $t = await getFormatter();
|
||||||
|
await modalManager.show(QrCodeModal, { title: $t('view_link'), value: makeSharedLinkUrl(sharedLink) });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleCopySharedLinkUrl = async (sharedLink: SharedLinkResponseDto) => {
|
||||||
|
await copyToClipboard(makeSharedLinkUrl(sharedLink));
|
||||||
|
};
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { defaultLang, langs, locales } from '$lib/constants';
|
import { defaultLang, langs, locales } from '$lib/constants';
|
||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { lang } from '$lib/stores/preferences.store';
|
import { lang } from '$lib/stores/preferences.store';
|
||||||
import { serverConfig } from '$lib/stores/server-config.store';
|
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import {
|
import {
|
||||||
AssetJobName,
|
AssetJobName,
|
||||||
|
|
@ -269,11 +268,6 @@ export const copyToClipboard = async (secret: string) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const makeSharedLinkUrl = (sharedLink: SharedLinkResponseDto) => {
|
|
||||||
const path = sharedLink.slug ? `s/${sharedLink.slug}` : `share/${sharedLink.key}`;
|
|
||||||
return new URL(path, get(serverConfig).externalDomain || globalThis.location.origin).href;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const oauth = {
|
export const oauth = {
|
||||||
isCallback: (location: Location) => {
|
isCallback: (location: Location) => {
|
||||||
const search = location.search;
|
const search = location.search;
|
||||||
|
|
|
||||||
|
|
@ -34,15 +34,15 @@
|
||||||
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
||||||
import AlbumShareModal from '$lib/modals/AlbumShareModal.svelte';
|
import AlbumShareModal from '$lib/modals/AlbumShareModal.svelte';
|
||||||
import AlbumUsersModal from '$lib/modals/AlbumUsersModal.svelte';
|
import AlbumUsersModal from '$lib/modals/AlbumUsersModal.svelte';
|
||||||
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
|
|
||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { handleConfirmAlbumDelete, handleDownloadAlbum } from '$lib/services/album.service';
|
import { handleConfirmAlbumDelete, handleDownloadAlbum } from '$lib/services/album.service';
|
||||||
|
import { handleViewSharedLinkQrCode } from '$lib/services/shared-link.service';
|
||||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences, user } from '$lib/stores/user.store';
|
||||||
import { handlePromiseError, makeSharedLinkUrl } from '$lib/utils';
|
import { handlePromiseError } from '$lib/utils';
|
||||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
|
@ -388,7 +388,7 @@
|
||||||
const sharedLink = await modalManager.show(SharedLinkCreateModal, { albumId: album.id });
|
const sharedLink = await modalManager.show(SharedLinkCreateModal, { albumId: album.id });
|
||||||
if (sharedLink) {
|
if (sharedLink) {
|
||||||
await refreshAlbum();
|
await refreshAlbum();
|
||||||
await modalManager.show(QrCodeModal, { title: $t('view_link'), value: makeSharedLinkUrl(sharedLink) });
|
await handleViewSharedLinkQrCode(sharedLink);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,8 @@
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
{#each filteredSharedLinks as link (link.id)}
|
{#each filteredSharedLinks as sharedLink (sharedLink.id)}
|
||||||
<SharedLinkCard {link} onDelete={() => handleDeleteLink(link.id)} />
|
<SharedLinkCard {sharedLink} onDelete={() => handleDeleteLink(sharedLink.id)} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue