mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix(web): show relevant navbar options for partner assets (#24832)
* fix(web): show relevant navbar options for partner * fix(web): AssetSelectControlBar on photos & search routes * chore: remove duplicate AssetSelectControlBar from search * chore: formatting fix * chore: change let to const
This commit is contained in:
parent
5e3f5f2b55
commit
afe925a55e
3 changed files with 116 additions and 151 deletions
|
|
@ -27,7 +27,7 @@
|
||||||
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
|
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||||
import { getAssetJobName, withoutIcons } from '$lib/utils';
|
import { getAssetJobName, getSharedLink, withoutIcons } from '$lib/utils';
|
||||||
import type { OnUndoDelete } from '$lib/utils/actions';
|
import type { OnUndoDelete } from '$lib/utils/actions';
|
||||||
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
|
|
@ -114,6 +114,7 @@
|
||||||
|
|
||||||
const { Share, Download, SharedLinkDownload, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } =
|
const { Share, Download, SharedLinkDownload, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } =
|
||||||
$derived(getAssetActions($t, asset));
|
$derived(getAssetActions($t, asset));
|
||||||
|
const sharedLink = getSharedLink();
|
||||||
|
|
||||||
// TODO: Enable when edits are ready for release
|
// TODO: Enable when edits are ready for release
|
||||||
// let showEditorButton = $derived(
|
// let showEditorButton = $derived(
|
||||||
|
|
@ -185,7 +186,9 @@
|
||||||
|
|
||||||
{#if isOwner}
|
{#if isOwner}
|
||||||
<DeleteAction {asset} {onAction} {preAction} {onUndoDelete} />
|
<DeleteAction {asset} {onAction} {preAction} {onUndoDelete} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !sharedLink}
|
||||||
<ButtonContextMenu direction="left" align="top-right" color="secondary" title={$t('more')} icon={mdiDotsVertical}>
|
<ButtonContextMenu direction="left" align="top-right" color="secondary" title={$t('more')} icon={mdiDotsVertical}>
|
||||||
{#if showSlideshow && !isLocked}
|
{#if showSlideshow && !isLocked}
|
||||||
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
||||||
|
|
@ -214,17 +217,19 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if album}
|
{/if}
|
||||||
<SetAlbumCoverAction {asset} {album} />
|
{#if album}
|
||||||
{/if}
|
<SetAlbumCoverAction {asset} {album} />
|
||||||
{#if person}
|
{/if}
|
||||||
<SetFeaturedPhotoAction {asset} {person} {onAction} />
|
{#if person}
|
||||||
{/if}
|
<SetFeaturedPhotoAction {asset} {person} {onAction} />
|
||||||
{#if asset.type === AssetTypeEnum.Image && !isLocked}
|
{/if}
|
||||||
<SetProfilePictureAction {asset} />
|
{#if asset.type === AssetTypeEnum.Image && !isLocked}
|
||||||
{/if}
|
<SetProfilePictureAction {asset} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if !isLocked}
|
{#if !isLocked}
|
||||||
|
{#if isOwner}
|
||||||
<ArchiveAction {asset} {onAction} {preAction} />
|
<ArchiveAction {asset} {onAction} {preAction} />
|
||||||
<MenuOption
|
<MenuOption
|
||||||
icon={mdiUpload}
|
icon={mdiUpload}
|
||||||
|
|
@ -238,28 +243,29 @@
|
||||||
text={$t('view_in_timeline')}
|
text={$t('view_in_timeline')}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !asset.isArchived && !asset.isTrashed && smartSearchEnabled}
|
|
||||||
<MenuOption
|
|
||||||
icon={mdiCompare}
|
|
||||||
onClick={() =>
|
|
||||||
goto(resolve(`${AppRoute.SEARCH}?query={"queryAssetId":"${stack?.primaryAssetId ?? asset.id}"}`))}
|
|
||||||
text={$t('view_similar_photos')}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if !asset.isArchived && !asset.isTrashed && smartSearchEnabled}
|
||||||
{#if !asset.isTrashed}
|
|
||||||
<SetVisibilityAction asset={toTimelineAsset(asset)} {onAction} {preAction} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if asset.type === AssetTypeEnum.Video}
|
|
||||||
<MenuOption
|
<MenuOption
|
||||||
icon={mdiVideoOutline}
|
icon={mdiCompare}
|
||||||
onClick={() => setPlayOriginalVideo(!playOriginalVideo)}
|
onClick={() =>
|
||||||
text={playOriginalVideo ? $t('play_transcoded_video') : $t('play_original_video')}
|
goto(resolve(`${AppRoute.SEARCH}?query={"queryAssetId":"${stack?.primaryAssetId ?? asset.id}"}`))}
|
||||||
|
text={$t('view_similar_photos')}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !asset.isTrashed && isOwner}
|
||||||
|
<SetVisibilityAction asset={toTimelineAsset(asset)} {onAction} {preAction} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if asset.type === AssetTypeEnum.Video}
|
||||||
|
<MenuOption
|
||||||
|
icon={mdiVideoOutline}
|
||||||
|
onClick={() => setPlayOriginalVideo(!playOriginalVideo)}
|
||||||
|
text={playOriginalVideo ? $t('play_transcoded_video') : $t('play_original_video')}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if isOwner}
|
||||||
<hr />
|
<hr />
|
||||||
<MenuOption
|
<MenuOption
|
||||||
icon={mdiHeadSyncOutline}
|
icon={mdiHeadSyncOutline}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@
|
||||||
|
|
||||||
return assetInteraction.isAllUserOwned && (isLivePhoto || isLivePhotoCandidate);
|
return assetInteraction.isAllUserOwned && (isLivePhoto || isLivePhotoCandidate);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isAllUserOwned = $derived($user && selectedAssets.every((asset) => asset.ownerId === $user.id));
|
||||||
|
|
||||||
const handleEscape = () => {
|
const handleEscape = () => {
|
||||||
if ($showAssetViewer) {
|
if ($showAssetViewer) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -130,45 +133,51 @@
|
||||||
<AddToAlbum />
|
<AddToAlbum />
|
||||||
<AddToAlbum shared />
|
<AddToAlbum shared />
|
||||||
</ButtonContextMenu>
|
</ButtonContextMenu>
|
||||||
<FavoriteAction
|
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
{#if isAllUserOwned}
|
||||||
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
<FavoriteAction
|
||||||
></FavoriteAction>
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
|
||||||
<DownloadAction menuItem />
|
/>
|
||||||
{#if assetInteraction.selectedAssets.length > 1 || isAssetStackSelected}
|
|
||||||
<StackAction
|
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||||
unstack={isAssetStackSelected}
|
<DownloadAction menuItem />
|
||||||
onStack={(result) => updateStackedAssetInTimeline(timelineManager, result)}
|
{#if assetInteraction.selectedAssets.length > 1 || isAssetStackSelected}
|
||||||
onUnstack={(assets) => updateUnstackedAssetInTimeline(timelineManager, assets)}
|
<StackAction
|
||||||
/>
|
unstack={isAssetStackSelected}
|
||||||
{/if}
|
onStack={(result) => updateStackedAssetInTimeline(timelineManager, result)}
|
||||||
{#if isLinkActionAvailable}
|
onUnstack={(assets) => updateUnstackedAssetInTimeline(timelineManager, assets)}
|
||||||
<LinkLivePhotoAction
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if isLinkActionAvailable}
|
||||||
|
<LinkLivePhotoAction
|
||||||
|
menuItem
|
||||||
|
unlink={assetInteraction.selectedAssets.length === 1}
|
||||||
|
onLink={handleLink}
|
||||||
|
onUnlink={handleUnlink}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<ChangeDate menuItem />
|
||||||
|
<ChangeDescription menuItem />
|
||||||
|
<ChangeLocation menuItem />
|
||||||
|
<ArchiveAction
|
||||||
menuItem
|
menuItem
|
||||||
unlink={assetInteraction.selectedAssets.length === 1}
|
onArchive={(ids, visibility) => timelineManager.update(ids, (asset) => (asset.visibility = visibility))}
|
||||||
onLink={handleLink}
|
|
||||||
onUnlink={handleUnlink}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{#if $preferences.tags.enabled}
|
||||||
<ChangeDate menuItem />
|
<TagAction menuItem />
|
||||||
<ChangeDescription menuItem />
|
{/if}
|
||||||
<ChangeLocation menuItem />
|
<DeleteAssets
|
||||||
<ArchiveAction
|
menuItem
|
||||||
menuItem
|
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
||||||
onArchive={(ids, visibility) => timelineManager.update(ids, (asset) => (asset.visibility = visibility))}
|
onUndoDelete={(assets) => timelineManager.upsertAssets(assets)}
|
||||||
/>
|
/>
|
||||||
{#if $preferences.tags.enabled}
|
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||||
<TagAction menuItem />
|
<hr />
|
||||||
{/if}
|
<AssetJobActions />
|
||||||
<DeleteAssets
|
</ButtonContextMenu>
|
||||||
menuItem
|
{:else}
|
||||||
onAssetDelete={(assetIds) => timelineManager.removeAssets(assetIds)}
|
<DownloadAction />
|
||||||
onUndoDelete={(assets) => timelineManager.upsertAssets(assets)}
|
{/if}
|
||||||
/>
|
|
||||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
|
||||||
<hr />
|
|
||||||
<AssetJobActions />
|
|
||||||
</ButtonContextMenu>
|
|
||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
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 { lang, locale } from '$lib/stores/preferences.store';
|
import { lang, locale } from '$lib/stores/preferences.store';
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences, user } from '$lib/stores/user.store';
|
||||||
import { handlePromiseError } from '$lib/utils';
|
import { handlePromiseError } from '$lib/utils';
|
||||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||||
import { parseUtcDate } from '$lib/utils/date-time';
|
import { parseUtcDate } from '$lib/utils/date-time';
|
||||||
|
|
@ -71,6 +71,10 @@
|
||||||
let smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch);
|
let smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch);
|
||||||
let terms = $derived(searchQuery ? JSON.parse(searchQuery) : {});
|
let terms = $derived(searchQuery ? JSON.parse(searchQuery) : {});
|
||||||
|
|
||||||
|
const isAllUserOwned = $derived(
|
||||||
|
$user && assetInteraction.selectedAssets.every((asset) => asset.ownerId === $user.id),
|
||||||
|
);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
// we want this to *only* be reactive on `terms`
|
// we want this to *only* be reactive on `terms`
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||||
|
|
@ -258,64 +262,6 @@
|
||||||
<svelte:window bind:scrollY />
|
<svelte:window bind:scrollY />
|
||||||
<svelte:document use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: onEscape }} />
|
<svelte:document use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: onEscape }} />
|
||||||
|
|
||||||
<section>
|
|
||||||
{#if assetInteraction.selectionActive}
|
|
||||||
<div class="fixed top-0 start-0 w-full">
|
|
||||||
<AssetSelectControlBar
|
|
||||||
assets={assetInteraction.selectedAssets}
|
|
||||||
clearSelect={() => cancelMultiselect(assetInteraction)}
|
|
||||||
>
|
|
||||||
<CreateSharedLink />
|
|
||||||
<IconButton
|
|
||||||
shape="round"
|
|
||||||
color="secondary"
|
|
||||||
variant="ghost"
|
|
||||||
aria-label={$t('select_all')}
|
|
||||||
icon={mdiSelectAll}
|
|
||||||
onclick={handleSelectAll}
|
|
||||||
/>
|
|
||||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
|
||||||
<AddToAlbum {onAddToAlbum} />
|
|
||||||
<AddToAlbum shared {onAddToAlbum} />
|
|
||||||
</ButtonContextMenu>
|
|
||||||
<FavoriteAction
|
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
|
||||||
onFavorite={(assetIds, isFavorite) => {
|
|
||||||
for (const assetId of assetIds) {
|
|
||||||
const asset = searchResultAssets.find((searchAsset) => searchAsset.id === assetId);
|
|
||||||
if (asset) {
|
|
||||||
asset.isFavorite = isFavorite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
|
||||||
<DownloadAction menuItem />
|
|
||||||
<ChangeDate menuItem />
|
|
||||||
<ChangeLocation menuItem />
|
|
||||||
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} />
|
|
||||||
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
|
|
||||||
<TagAction menuItem />
|
|
||||||
{/if}
|
|
||||||
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
|
|
||||||
<hr />
|
|
||||||
<AssetJobActions />
|
|
||||||
</ButtonContextMenu>
|
|
||||||
</AssetSelectControlBar>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div class="fixed top-0 start-0 w-full">
|
|
||||||
<ControlAppBar onClose={() => goto(previousRoute)} backIcon={mdiArrowLeft}>
|
|
||||||
<div class="absolute bg-light"></div>
|
|
||||||
<div class="w-full flex-1 ps-4">
|
|
||||||
<SearchBar grayTheme={false} value={terms?.query ?? ''} searchQuery={terms} />
|
|
||||||
</div>
|
|
||||||
</ControlAppBar>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{#if terms}
|
{#if terms}
|
||||||
<section
|
<section
|
||||||
id="search-chips"
|
id="search-chips"
|
||||||
|
|
@ -419,34 +365,38 @@
|
||||||
<AddToAlbum {onAddToAlbum} />
|
<AddToAlbum {onAddToAlbum} />
|
||||||
<AddToAlbum shared {onAddToAlbum} />
|
<AddToAlbum shared {onAddToAlbum} />
|
||||||
</ButtonContextMenu>
|
</ButtonContextMenu>
|
||||||
<FavoriteAction
|
{#if isAllUserOwned}
|
||||||
removeFavorite={assetInteraction.isAllFavorite}
|
<FavoriteAction
|
||||||
onFavorite={(ids, isFavorite) => {
|
removeFavorite={assetInteraction.isAllFavorite}
|
||||||
for (const id of ids) {
|
onFavorite={(ids, isFavorite) => {
|
||||||
const asset = searchResultAssets.find((asset) => asset.id === id);
|
for (const id of ids) {
|
||||||
if (asset) {
|
const asset = searchResultAssets.find((asset) => asset.id === id);
|
||||||
asset.isFavorite = isFavorite;
|
if (asset) {
|
||||||
|
asset.isFavorite = isFavorite;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
|
||||||
<DownloadAction menuItem />
|
<DownloadAction menuItem />
|
||||||
<ChangeDate menuItem />
|
<ChangeDate menuItem />
|
||||||
<ChangeDescription menuItem />
|
<ChangeDescription menuItem />
|
||||||
<ChangeLocation menuItem />
|
<ChangeLocation menuItem />
|
||||||
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} />
|
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} />
|
||||||
{#if assetInteraction.isAllUserOwned}
|
{#if assetInteraction.isAllUserOwned}
|
||||||
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
|
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
|
||||||
<TagAction menuItem />
|
<TagAction menuItem />
|
||||||
{/if}
|
{/if}
|
||||||
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
|
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
|
||||||
<hr />
|
<hr />
|
||||||
<AssetJobActions />
|
<AssetJobActions />
|
||||||
</ButtonContextMenu>
|
</ButtonContextMenu>
|
||||||
|
{:else}
|
||||||
|
<DownloadAction />
|
||||||
|
{/if}
|
||||||
</AssetSelectControlBar>
|
</AssetSelectControlBar>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue