From c25b6e30c27c6d190a0bf75cee7f3a4a050108f5 Mon Sep 17 00:00:00 2001 From: Mees Frensel <33722705+meesfrensel@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:34:30 +0200 Subject: [PATCH] refactor(web): rating shortcuts action (#31804) --- i18n/en.json | 4 +- .../asset-viewer/AssetViewerNavBar.svelte | 6 --- .../asset-viewer/actions/RatingAction.svelte | 54 ------------------- web/src/lib/modals/ShortcutsModal.svelte | 2 +- web/src/lib/services/asset.service.ts | 30 +++++++++++ 5 files changed, 33 insertions(+), 63 deletions(-) delete mode 100644 web/src/lib/components/asset-viewer/actions/RatingAction.svelte diff --git a/i18n/en.json b/i18n/en.json index f4ed1fa12..77ea86f7c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1751,7 +1751,8 @@ "purchase_settings_server_activated": "The server product key is managed by the admin", "query_asset_id": "Query Asset ID", "queue_status": "Queuing {count}/{total}", - "rate_asset": "Rate Asset", + "rate_asset": "Rate asset", + "rate_asset_description": "Use the keys from 1 to 5 to quickly rate an asset, and 0 to clear the rating", "rating": "Star rating", "rating_clear": "Clear rating", "rating_count": "{count, plural, =0 {Unrated} one {# star} other {# stars}}", @@ -2368,6 +2369,5 @@ "you": "You", "you_dont_have_any_shared_links": "You don't have any shared links", "your_wifi_name": "Your Wi-Fi name", - "zero_to_clear_rating": "press 0 to clear asset rating", "zoom_image": "Zoom Image" } diff --git a/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte b/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte index 1a6970f8d..4f6bfcb3b 100644 --- a/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte +++ b/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte @@ -3,7 +3,6 @@ import type { OnAction, PreAction } from '$lib/components/asset-viewer/actions/action'; import ArchiveAction from '$lib/components/asset-viewer/actions/ArchiveAction.svelte'; import DeleteAction from '$lib/components/asset-viewer/actions/DeleteAction.svelte'; - import RatingAction from '$lib/components/asset-viewer/actions/RatingAction.svelte'; import RestoreAction from '$lib/components/asset-viewer/actions/RestoreAction.svelte'; import SetVisibilityAction from '$lib/components/asset-viewer/actions/SetVisibilityAction.svelte'; import LoadingDots from '$lib/components/LoadingDots.svelte'; @@ -116,11 +115,6 @@ - - {#if isOwner} - - {/if} - {#if isOwner} diff --git a/web/src/lib/components/asset-viewer/actions/RatingAction.svelte b/web/src/lib/components/asset-viewer/actions/RatingAction.svelte deleted file mode 100644 index 056a932a1..000000000 --- a/web/src/lib/components/asset-viewer/actions/RatingAction.svelte +++ /dev/null @@ -1,54 +0,0 @@ - - - rateAsset(null) }, - ...[1, 2, 3, 4, 5].map((rating) => ({ - shortcut: { key: String(rating) }, - onShortcut: () => rateAsset(rating), - })), - ] - : []} -/> diff --git a/web/src/lib/modals/ShortcutsModal.svelte b/web/src/lib/modals/ShortcutsModal.svelte index 899f70ed9..bb818fa73 100644 --- a/web/src/lib/modals/ShortcutsModal.svelte +++ b/web/src/lib/modals/ShortcutsModal.svelte @@ -46,7 +46,7 @@ { key: ['Space'], action: $t('play_or_pause_video') }, { key: ['Del'], action: $t('trash_delete_asset'), info: $t('shift_to_permanent_delete') }, ...(authManager.authenticated && authManager.preferences.ratings.enabled - ? [{ key: ['1-5'], action: $t('rate_asset'), info: $t('zero_to_clear_rating') }] + ? [{ key: ['0-5'], action: $t('rate_asset'), info: $t('rate_asset_description') }] : []), ], }, diff --git a/web/src/lib/services/asset.service.ts b/web/src/lib/services/asset.service.ts index d6535c560..fc52b18e2 100644 --- a/web/src/lib/services/asset.service.ts +++ b/web/src/lib/services/asset.service.ts @@ -200,6 +200,14 @@ export const getAssetActions = ( shortcuts: [{ key: 'f' }], }; + const Rate: ActionItem = { + title: $t('rate_asset'), + description: $t('rate_asset_description'), + $if: () => isOwner && authManager.preferences.ratings.enabled, + onAction: ({ event }) => handleRate(asset, event instanceof KeyboardEvent ? Number(event.key) : NaN), + shortcuts: [0, 1, 2, 3, 4, 5].map((key) => ({ key: String(key) })), + }; + const AddToAlbum: ActionItem = { title: $t('add_to_album'), icon: mdiPlus, @@ -340,6 +348,7 @@ export const getAssetActions = ( Info, Favorite, Unfavorite, + Rate, PlayMotionPhoto, StopMotionPhoto, PlaySlideshow, @@ -435,6 +444,27 @@ const handleUnfavorite = async (asset: AssetResponseDto) => { } }; +const handleRate = async (asset: AssetResponseDto, rating: number) => { + const $t = await getFormatter(); + + if (Number.isNaN(rating)) { + toastManager.info($t('rate_asset_description')); + return; + } + + const newRating = rating === 0 ? null : rating; + if (asset.exifInfo && asset.exifInfo.rating === newRating) { + return; + } + + try { + const response = await updateAsset({ id: asset.id, updateAssetDto: { rating: newRating } }); + eventManager.emit('AssetUpdate', response); + } catch (error) { + handleError(error, $t('errors.unable_to_set_rating')); + } +}; + const handleBulkRemoveAssetsFromAlbum = async (assetIds: string[], album: AlbumResponseDto) => { const $t = await getFormatter();