fix(web): refresh text (#26071)

This commit is contained in:
Jason Rasmussen
2026-02-10 11:42:03 -05:00
committed by GitHub
parent 0886281dd8
commit e6e56d75e2
25 changed files with 115 additions and 106 deletions

View File

@@ -1,16 +1,6 @@
<script lang="ts" module>
import { createContext } from '$lib/utils/context';
import { setAssetControlContext } from '$lib/utils/context';
import { t } from 'svelte-i18n';
export interface AssetControlContext {
// Wrap assets in a function, because context isn't reactive.
getAssets: () => TimelineAsset[]; // All assets includes partners' assets
getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user
clearSelect: () => void;
}
const { get: getAssetControlContext, set: setContext } = createContext<AssetControlContext>();
export { getAssetControlContext };
</script>
<script lang="ts">
@@ -19,20 +9,20 @@
import type { Snippet } from 'svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
interface Props {
type Props = {
assets: TimelineAsset[];
clearSelect: () => void;
ownerId?: string | undefined;
children?: Snippet;
forceDark?: boolean;
}
};
let { assets, clearSelect, ownerId = undefined, children, forceDark }: Props = $props();
setContext({
setAssetControlContext({
getAssets: () => assets,
getOwnedAssets: () => (ownerId === undefined ? assets : assets.filter((asset) => asset.ownerId === ownerId)),
clearSelect,
clearSelect: () => clearSelect(),
});
</script>

View File

@@ -1,9 +1,9 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
import type { OnAddToAlbum } from '$lib/utils/actions';
import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { modalManager } from '@immich/ui';
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';
import { t } from 'svelte-i18n';

View File

@@ -1,12 +1,12 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import type { OnArchive } from '$lib/utils/actions';
import { archiveAssets } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { AssetVisibility } from '@immich/sdk';
import { IconButton } from '@immich/ui';
import { mdiArchiveArrowDownOutline, mdiArchiveArrowUpOutline, mdiTimerSand } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
interface Props {
onArchive?: OnArchive;

View File

@@ -1,37 +0,0 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { getAssetJobIcon, getAssetJobName } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { AssetJobName, runAssetJobs } from '@immich/sdk';
import { toastManager } from '@immich/ui';
import { t } from 'svelte-i18n';
interface Props {
jobs?: AssetJobName[];
}
let { jobs = [AssetJobName.RegenerateThumbnail, AssetJobName.RefreshMetadata, AssetJobName.TranscodeVideo] }: Props =
$props();
const { clearSelect, getOwnedAssets } = getAssetControlContext();
const isAllVideos = $derived([...getOwnedAssets()].every((asset) => asset.isVideo));
const handleRunJob = async (name: AssetJobName) => {
try {
const ids = [...getOwnedAssets()].map(({ id }) => id);
await runAssetJobs({ assetJobsDto: { assetIds: ids, name } });
toastManager.success(getAssetJobName($t, name));
clearSelect();
} catch (error) {
handleError(error, $t('errors.unable_to_submit_job'));
}
};
</script>
{#each jobs as job (job)}
{#if isAllVideos || job !== AssetJobName.TranscodeVideo}
<MenuOption text={getAssetJobName($t, job)} icon={getAssetJobIcon(job)} onClick={() => handleRunJob(job)} />
{/if}
{/each}

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AssetSelectionChangeDateModal from '$lib/modals/AssetSelectionChangeDateModal.svelte';
import { getAssetControlContext } from '$lib/utils/context';
import { fromTimelinePlainDateTime } from '$lib/utils/timeline-util';
import { modalManager } from '@immich/ui';
import { mdiCalendarEditOutline } from '@mdi/js';

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AssetUpdateDescriptionConfirmModal from '$lib/modals/AssetUpdateDescriptionConfirmModal.svelte';
import { user } from '$lib/stores/user.store';
import { getOwnedAssetsWithWarning } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { modalManager } from '@immich/ui';

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import ChangeLocation from '$lib/components/shared-components/change-location.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { user } from '$lib/stores/user.store';
import { getOwnedAssetsWithWarning } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { mdiMapMarkerMultipleOutline } from '@mdi/js';

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
import { getAssetControlContext } from '$lib/utils/context';
import { IconButton, modalManager } from '@immich/ui';
import { mdiShareVariantOutline } from '@mdi/js';
import { t } from 'svelte-i18n';

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import AssetDeleteConfirmModal from '$lib/modals/AssetDeleteConfirmModal.svelte';
import { showDeleteModal } from '$lib/stores/preferences.store';
import { type OnDelete, type OnUndoDelete, deleteAssets } from '$lib/utils/actions';
import { getAssetControlContext } from '$lib/utils/context';
import { IconButton, modalManager } from '@immich/ui';
import { mdiDeleteForeverOutline, mdiDeleteOutline, mdiTimerSand } from '@mdi/js';
import { t } from 'svelte-i18n';

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import { shortcut } from '$lib/actions/shortcut';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { handleDownloadAsset } from '$lib/services/asset.service';
import { downloadArchive } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { getAssetInfo } from '@immich/sdk';
import { IconButton } from '@immich/ui';
import { mdiDownload } from '@mdi/js';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import type { OnFavorite } from '$lib/utils/actions';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { IconButton, toastManager } from '@immich/ui';

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import type { OnLink, OnUnlink } from '$lib/utils/actions';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { toTimelineAsset } from '$lib/utils/timeline-util';
import { getAssetInfo, updateAsset } from '@immich/sdk';

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { getAlbumInfo, removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
import { IconButton, modalManager, toastManager } from '@immich/ui';

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { handleRemoveSharedLinkAssets } from '$lib/services/shared-link.service';
import { getAssetControlContext } from '$lib/utils/context';
import { type SharedLinkResponseDto } from '@immich/sdk';
import { IconButton } from '@immich/ui';
import { mdiDeleteOutline } from '@mdi/js';

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import type { OnRestore } from '$lib/utils/actions';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { restoreAssets } from '@immich/sdk';
import { Button, toastManager } from '@immich/ui';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import type { OnSetVisibility } from '$lib/utils/actions';
import { getAssetControlContext } from '$lib/utils/context';
import { handleError } from '$lib/utils/handle-error';
import { AssetVisibility, updateAssets } from '@immich/sdk';
import { Button, modalManager } from '@immich/ui';

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import type { OnStack, OnUnstack } from '$lib/utils/actions';
import { deleteStack, stackAssets } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { toTimelineAsset } from '$lib/utils/timeline-util';
import { mdiImageMultipleOutline, mdiImageOffOutline } from '@mdi/js';
import { t } from 'svelte-i18n';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { shortcut } from '$lib/actions/shortcut';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
import { getAssetControlContext } from '$lib/utils/context';
import { IconButton, modalManager } from '@immich/ui';
import { mdiTagMultipleOutline } from '@mdi/js';
import { t } from 'svelte-i18n';

View File

@@ -5,7 +5,8 @@ import { eventManager } from '$lib/managers/event-manager.svelte';
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
import { user as authUser, preferences } from '$lib/stores/user.store';
import { getAssetJobName, getSharedLink, sleep } from '$lib/utils';
import type { AssetControlContext } from '$lib/types';
import { getSharedLink, sleep } from '$lib/utils';
import { downloadUrl } from '$lib/utils/asset-utils';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import { handleError } from '$lib/utils/handle-error';
@@ -48,6 +49,44 @@ import {
import type { MessageFormatter } from 'svelte-i18n';
import { get } from 'svelte/store';
export const getAssetBulkActions = ($t: MessageFormatter, ctx: AssetControlContext) => {
const ownedAssets = ctx.getOwnedAssets();
const assetIds = ownedAssets.map((asset) => asset.id);
const isAllVideos = ownedAssets.every((asset) => asset.isVideo);
const onAction = async (name: AssetJobName) => {
await handleRunAssetJob({ name, assetIds });
ctx.clearSelect();
};
const RefreshFacesJob: ActionItem = {
title: $t('refresh_faces'),
icon: mdiHeadSyncOutline,
onAction: () => onAction(AssetJobName.RefreshFaces),
};
const RefreshMetadataJob: ActionItem = {
title: $t('refresh_metadata'),
icon: mdiDatabaseRefreshOutline,
onAction: () => onAction(AssetJobName.RefreshMetadata),
};
const RegenerateThumbnailJob: ActionItem = {
title: $t('refresh_thumbnails'),
icon: mdiImageRefreshOutline,
onAction: () => onAction(AssetJobName.RegenerateThumbnail),
};
const TranscodeVideoJob: ActionItem = {
title: $t('refresh_encoded_videos'),
icon: mdiCogRefreshOutline,
onAction: () => onAction(AssetJobName.TranscodeVideo),
$if: () => isAllVideos,
};
return { RefreshFacesJob, RefreshMetadataJob, RegenerateThumbnailJob, TranscodeVideoJob };
};
export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) => {
const sharedLink = getSharedLink();
const currentAuthUser = get(authUser);
@@ -186,25 +225,25 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
};
const RefreshFacesJob: ActionItem = {
title: getAssetJobName($t, AssetJobName.RefreshFaces),
title: $t('refresh_faces'),
icon: mdiHeadSyncOutline,
onAction: () => handleRunAssetJob({ name: AssetJobName.RefreshFaces, assetIds: [asset.id] }),
};
const RefreshMetadataJob: ActionItem = {
title: getAssetJobName($t, AssetJobName.RefreshMetadata),
title: $t('refresh_metadata'),
icon: mdiDatabaseRefreshOutline,
onAction: () => handleRunAssetJob({ name: AssetJobName.RefreshMetadata, assetIds: [asset.id] }),
};
const RegenerateThumbnailJob: ActionItem = {
title: getAssetJobName($t, AssetJobName.RegenerateThumbnail),
title: $t('refresh_thumbnails'),
icon: mdiImageRefreshOutline,
onAction: () => handleRunAssetJob({ name: AssetJobName.RegenerateThumbnail, assetIds: [asset.id] }),
};
const TranscodeVideoJob: ActionItem = {
title: getAssetJobName($t, AssetJobName.TranscodeVideo),
title: $t('refresh_encoded_videos'),
icon: mdiCogRefreshOutline,
onAction: () => handleRunAssetJob({ name: AssetJobName.TranscodeVideo, assetIds: [asset.id] }),
$if: () => asset.type === AssetTypeEnum.Video,
@@ -313,12 +352,23 @@ export const handleReplaceAsset = async (oldAssetId: string) => {
eventManager.emit('AssetReplace', { oldAssetId, newAssetId });
};
const getAssetJobMessage = ($t: MessageFormatter, job: AssetJobName) => {
const messages: Record<AssetJobName, string> = {
[AssetJobName.RefreshFaces]: $t('refreshing_faces'),
[AssetJobName.RefreshMetadata]: $t('refreshing_metadata'),
[AssetJobName.RegenerateThumbnail]: $t('regenerating_thumbnails'),
[AssetJobName.TranscodeVideo]: $t('refreshing_encoded_video'),
};
return messages[job];
};
const handleRunAssetJob = async (dto: AssetJobsDto) => {
const $t = await getFormatter();
try {
await runAssetJobs({ assetJobsDto: dto });
toastManager.success(getAssetJobName($t, dto.name));
toastManager.success(getAssetJobMessage($t, dto.name));
} catch (error) {
handleError(error, $t('errors.unable_to_submit_job'));
}

View File

@@ -1,3 +1,4 @@
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import type { QueueResponseDto, ServerVersionResponseDto } from '@immich/sdk';
import type { ActionItem } from '@immich/ui';
@@ -40,3 +41,10 @@ export enum OnboardingRole {
SERVER = 'server',
USER = 'user',
}
export type AssetControlContext = {
// Wrap assets in a function, because context isn't reactive.
getAssets: () => TimelineAsset[]; // All assets includes partners' assets
getOwnedAssets: () => TimelineAsset[]; // Only assets owned by the user
clearSelect: () => void;
};

View File

@@ -4,7 +4,6 @@ import { alwaysLoadOriginalFile, lang } from '$lib/stores/preferences.store';
import { isWebCompatibleImage } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import {
AssetJobName,
AssetMediaSize,
AssetTypeEnum,
MemoryType,
@@ -27,8 +26,7 @@ import {
type UserResponseDto,
} from '@immich/sdk';
import { toastManager, type ActionItem, type IfLike } from '@immich/ui';
import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiHeadSyncOutline, mdiImageRefreshOutline } from '@mdi/js';
import { init, register, t, type MessageFormatter } from 'svelte-i18n';
import { init, register, t } from 'svelte-i18n';
import { derived, get } from 'svelte/store';
interface DownloadRequestOptions<T = unknown> {
@@ -245,28 +243,6 @@ export const getProfileImageUrl = (user: UserResponseDto) =>
export const getPeopleThumbnailUrl = (person: PersonResponseDto, updatedAt?: string) =>
createUrl(getPeopleThumbnailPath(person.id), { updatedAt: updatedAt ?? person.updatedAt });
export const getAssetJobName = ($t: MessageFormatter, job: AssetJobName) => {
const messages: Record<AssetJobName, string> = {
[AssetJobName.RefreshFaces]: $t('refreshing_faces'),
[AssetJobName.RefreshMetadata]: $t('refreshing_metadata'),
[AssetJobName.RegenerateThumbnail]: $t('regenerating_thumbnails'),
[AssetJobName.TranscodeVideo]: $t('refreshing_encoded_video'),
};
return messages[job];
};
export const getAssetJobIcon = (job: AssetJobName) => {
const names: Record<AssetJobName, string> = {
[AssetJobName.RefreshFaces]: mdiHeadSyncOutline,
[AssetJobName.RefreshMetadata]: mdiDatabaseRefreshOutline,
[AssetJobName.RegenerateThumbnail]: mdiImageRefreshOutline,
[AssetJobName.TranscodeVideo]: mdiCogRefreshOutline,
};
return names[job];
};
export const copyToClipboard = async (secret: string) => {
const $t = get(t);

View File

@@ -1,3 +1,4 @@
import type { AssetControlContext } from '$lib/types';
import { getContext, setContext } from 'svelte';
export function createContext<T>(key: string | symbol = Symbol()) {
@@ -6,3 +7,5 @@ export function createContext<T>(key: string | symbol = Symbol()) {
set: (context: T) => setContext<T>(key, context),
};
}
export const { get: getAssetControlContext, set: setAssetControlContext } = createContext<AssetControlContext>();

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { afterNavigate, goto, invalidateAll } from '$app/navigation';
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
import UserPageLayout, { headerId } from '$lib/components/layouts/user-page-layout.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
@@ -9,7 +10,6 @@
import Sidebar from '$lib/components/sidebar/sidebar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import AssetJobActions from '$lib/components/timeline/actions/AssetJobActions.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
@@ -22,10 +22,12 @@
import SkipLink from '$lib/elements/SkipLink.svelte';
import type { Viewport } from '$lib/managers/timeline-manager/types';
import { Route } from '$lib/route';
import { getAssetBulkActions } from '$lib/services/asset.service';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { foldersStore } from '$lib/stores/folders.svelte';
import { preferences } from '$lib/stores/user.store';
import { cancelMultiselect } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { toTimelineAsset } from '$lib/utils/timeline-util';
import { joinPaths } from '$lib/utils/tree-utils';
import { IconButton, Text } from '@immich/ui';
@@ -117,6 +119,8 @@
assets={assetInteraction.selectedAssets}
clearSelect={() => cancelMultiselect(assetInteraction)}
>
{@const Actions = getAssetBulkActions($t, getAssetControlContext())}
<CreateSharedLink />
<IconButton
shape="round"
@@ -155,7 +159,10 @@
{/if}
<DeleteAssets menuItem onAssetDelete={triggerAssetUpdate} onUndoDelete={triggerAssetUpdate} />
<hr />
<AssetJobActions />
<ActionMenuItem action={Actions.RegenerateThumbnailJob} />
<ActionMenuItem action={Actions.RefreshMetadataJob} />
<ActionMenuItem action={Actions.TranscodeVideoJob} />
</ButtonContextMenu>
</AssetSelectControlBar>
</div>

View File

@@ -1,11 +1,11 @@
<script lang="ts">
import { beforeNavigate } from '$app/navigation';
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import AssetJobActions from '$lib/components/timeline/actions/AssetJobActions.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
@@ -23,6 +23,7 @@
import { AssetAction } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { Route } from '$lib/route';
import { getAssetBulkActions } from '$lib/services/asset.service';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
@@ -35,6 +36,7 @@
type OnLink,
type OnUnlink,
} from '$lib/utils/actions';
import { getAssetControlContext } from '$lib/utils/context';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import { getAltText } from '$lib/utils/thumbnail-util';
import { toTimelineAsset } from '$lib/utils/timeline-util';
@@ -128,6 +130,8 @@
assets={assetInteraction.selectedAssets}
clearSelect={() => assetInteraction.clearMultiselect()}
>
{@const Actions = getAssetBulkActions($t, getAssetControlContext())}
<CreateSharedLink />
<SelectAllAssets {timelineManager} {assetInteraction} />
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
@@ -175,7 +179,9 @@
/>
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
<hr />
<AssetJobActions />
<ActionMenuItem action={Actions.RegenerateThumbnailJob} />
<ActionMenuItem action={Actions.RefreshMetadataJob} />
<ActionMenuItem action={Actions.TranscodeVideoJob} />
</ButtonContextMenu>
{:else}
<DownloadAction />

View File

@@ -1,13 +1,13 @@
<script lang="ts">
import { afterNavigate, goto } from '$app/navigation';
import { page } from '$app/state';
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import AssetJobActions from '$lib/components/timeline/actions/AssetJobActions.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
@@ -22,11 +22,13 @@
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import type { Viewport } from '$lib/managers/timeline-manager/types';
import { Route } from '$lib/route';
import { getAssetBulkActions } from '$lib/services/asset.service';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { lang, locale } from '$lib/stores/preferences.store';
import { preferences, user } from '$lib/stores/user.store';
import { handlePromiseError } from '$lib/utils';
import { cancelMultiselect } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { parseUtcDate } from '$lib/utils/date-time';
import { handleError } from '$lib/utils/handle-error';
import { isAlbumsRoute, isPeopleRoute } from '$lib/utils/navigation';
@@ -326,6 +328,8 @@
assets={assetInteraction.selectedAssets}
clearSelect={() => cancelMultiselect(assetInteraction)}
>
{@const Actions = getAssetBulkActions($t, getAssetControlContext())}
<CreateSharedLink />
<IconButton
shape="round"
@@ -366,7 +370,9 @@
{/if}
<DeleteAssets menuItem {onAssetDelete} onUndoDelete={onSearchQueryUpdate} />
<hr />
<AssetJobActions />
<ActionMenuItem action={Actions.RegenerateThumbnailJob} />
<ActionMenuItem action={Actions.RefreshMetadataJob} />
<ActionMenuItem action={Actions.TranscodeVideoJob} />
</ButtonContextMenu>
{:else}
<DownloadAction />