@@ -410,12 +433,14 @@
{#if asset.exifInfo?.city && !asset.isReadOnly}
(isShowChangeLocation = true)}
- on:keydown={(event) => event.key === 'Enter' && (isShowChangeLocation = true)}
+ class="flex justify-between place-items-start gap-4 py-4"
+ on:click={() => (isOwner ? (isShowChangeLocation = true) : null)}
+ on:keydown={(event) => (isOwner ? event.key === 'Enter' && (isShowChangeLocation = true) : null)}
tabindex="0"
+ title={isOwner ? 'Edit location' : ''}
role="button"
- title="Edit location"
+ class:hover:dark:text-immich-dark-primary={isOwner}
+ class:hover:text-immich-primary={isOwner}
>
-
-
-
+ {#if isOwner}
+
+
+
+ {/if}
- {:else if !asset.exifInfo?.city && !asset.isReadOnly}
+ {:else if !asset.exifInfo?.city && !asset.isReadOnly && $user && asset.ownerId === $user.id}
(isShowChangeLocation = true)}
diff --git a/web/src/lib/components/photos-page/actions/change-date-action.svelte b/web/src/lib/components/photos-page/actions/change-date-action.svelte
index b917a36fe..8f9748261 100644
--- a/web/src/lib/components/photos-page/actions/change-date-action.svelte
+++ b/web/src/lib/components/photos-page/actions/change-date-action.svelte
@@ -5,6 +5,8 @@
import { DateTime } from 'luxon';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
+ import { user } from '$lib/stores/user.store';
+ import { getSelectedAssets } from '$lib/utils/asset-utils';
export let menuItem = false;
const { clearSelect, getOwnedAssets } = getAssetControlContext();
@@ -12,9 +14,7 @@
const handleConfirm = async (dateTimeOriginal: string) => {
isShowChangeDate = false;
- const ids = Array.from(getOwnedAssets())
- .filter((a) => !a.isExternal)
- .map((a) => a.id);
+ const ids = getSelectedAssets(getOwnedAssets(), $user);
try {
await api.assetApi.updateAssets({
diff --git a/web/src/lib/components/photos-page/actions/change-location-action.svelte b/web/src/lib/components/photos-page/actions/change-location-action.svelte
index b916d26c3..ac1e66d09 100644
--- a/web/src/lib/components/photos-page/actions/change-location-action.svelte
+++ b/web/src/lib/components/photos-page/actions/change-location-action.svelte
@@ -4,6 +4,8 @@
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import ChangeLocation from '$lib/components/shared-components/change-location.svelte';
import { handleError } from '../../../utils/handle-error';
+ import { user } from '$lib/stores/user.store';
+ import { getSelectedAssets } from '$lib/utils/asset-utils';
export let menuItem = false;
const { clearSelect, getOwnedAssets } = getAssetControlContext();
@@ -12,9 +14,7 @@
async function handleConfirm(point: { lng: number; lat: number }) {
isShowChangeLocation = false;
- const ids = Array.from(getOwnedAssets())
- .filter((a) => !a.isExternal)
- .map((a) => a.id);
+ const ids = getSelectedAssets(getOwnedAssets(), $user);
try {
await api.assetApi.updateAssets({
diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte
index 1e5304e8e..310b2d4de 100644
--- a/web/src/lib/components/photos-page/asset-grid.svelte
+++ b/web/src/lib/components/photos-page/asset-grid.svelte
@@ -8,7 +8,7 @@
import { locale } from '$lib/stores/preferences.store';
import { isSearchEnabled } from '$lib/stores/search.store';
import { formatGroupTitle, splitBucketIntoDateGroups } from '$lib/utils/timeline-util';
- import type { AlbumResponseDto, AssetResponseDto, UserResponseDto } from '@api';
+ import type { AlbumResponseDto, AssetResponseDto } from '@api';
import { DateTime } from 'luxon';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
@@ -27,7 +27,6 @@
export let removeAction: AssetAction | null = null;
export let withStacked = false;
export let isShared = false;
- export let user: UserResponseDto | null = null;
export let album: AlbumResponseDto | null = null;
$: isTrashEnabled = $featureFlags.loaded && $featureFlags.trash;
@@ -394,7 +393,6 @@
{#if $showAssetViewer}
= new Set();
@@ -103,6 +102,6 @@
{/if}
diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
index dc62bc8da..0aa51dfa9 100644
--- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
+++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
@@ -2,7 +2,7 @@
import { page } from '$app/stores';
import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte';
import { handleError } from '$lib/utils/handle-error';
- import { AssetResponseDto, ThumbnailFormat, UserResponseDto } from '@api';
+ import { AssetResponseDto, ThumbnailFormat } from '@api';
import AssetViewer from '../../asset-viewer/asset-viewer.svelte';
import { flip } from 'svelte/animate';
import { getThumbnailSize } from '$lib/utils/thumbnail-util';
@@ -13,7 +13,6 @@
export let selectedAssets: Set = new Set();
export let disableAssetSelect = false;
export let showArchiveIcon = false;
- export let user: UserResponseDto | undefined = undefined;
let { isViewing: showAssetViewer } = assetViewingStore;
@@ -109,7 +108,6 @@
{#if $showAssetViewer}
{
await refresh();
@@ -23,7 +22,7 @@
const refresh = async () => {
try {
const { data } = await api.serverInfoApi.getServerInfo();
- serverInfo = data;
+ $serverInfoStore = data;
} catch (e) {
console.log('Error [StatusBox] [onMount]');
}
@@ -44,7 +43,7 @@
Storage
- {#if serverInfo}
+ {#if $serverInfoStore}
- {asByteUnitString(serverInfo?.diskUseRaw, $locale)} of
- {asByteUnitString(serverInfo?.diskSizeRaw, $locale)} used
+ {asByteUnitString($serverInfoStore?.diskUseRaw, $locale)} of
+ {asByteUnitString($serverInfoStore?.diskSizeRaw, $locale)} used
{:else}
diff --git a/web/src/lib/stores/server-info.store.ts b/web/src/lib/stores/server-info.store.ts
new file mode 100644
index 000000000..24a6d3199
--- /dev/null
+++ b/web/src/lib/stores/server-info.store.ts
@@ -0,0 +1,4 @@
+import { writable } from 'svelte/store';
+import type { ServerInfoResponseDto } from '@api';
+
+export const serverInfoStore = writable
();
diff --git a/web/src/lib/stores/user.store.ts b/web/src/lib/stores/user.store.ts
new file mode 100644
index 000000000..e6dec6366
--- /dev/null
+++ b/web/src/lib/stores/user.store.ts
@@ -0,0 +1,4 @@
+import { writable } from 'svelte/store';
+import type { UserResponseDto } from '@api';
+
+export const user = writable(null);
diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts
index 94c12d140..b466e142c 100644
--- a/web/src/lib/utils/asset-utils.ts
+++ b/web/src/lib/utils/asset-utils.ts
@@ -1,6 +1,14 @@
import { notificationController, NotificationType } from '$lib/components/shared-components/notification/notification';
import { downloadManager } from '$lib/stores/download';
-import { api, BulkIdResponseDto, AssetResponseDto, DownloadResponseDto, DownloadInfoDto, AssetTypeEnum } from '@api';
+import {
+ api,
+ BulkIdResponseDto,
+ AssetResponseDto,
+ DownloadResponseDto,
+ DownloadInfoDto,
+ AssetTypeEnum,
+ UserResponseDto,
+} from '@api';
import { handleError } from './handle-error';
export const addAssetsToAlbum = async (albumId: string, assetIds: Array): Promise =>
@@ -203,3 +211,17 @@ export const getAssetType = (type: AssetTypeEnum) => {
return 'Asset';
}
};
+
+export const getSelectedAssets = (assets: Set, user: UserResponseDto | null): string[] => {
+ const ids = Array.from(assets)
+ .filter((a) => !a.isExternal && user && a.ownerId !== user.id)
+ .map((a) => a.id);
+ const numberOfIssues = Array.from(assets).filter((a) => a.isExternal || (user && a.ownerId === user.id)).length;
+ if (numberOfIssues > 0) {
+ notificationController.show({
+ message: `Can't change metadata of ${numberOfIssues} asset${numberOfIssues > 1 ? 's' : ''}`,
+ type: NotificationType.Warning,
+ });
+ }
+ return ids;
+};
diff --git a/web/src/routes/(user)/albums/[albumId]/+page.svelte b/web/src/routes/(user)/albums/[albumId]/+page.svelte
index a16216453..a88187713 100644
--- a/web/src/routes/(user)/albums/[albumId]/+page.svelte
+++ b/web/src/routes/(user)/albums/[albumId]/+page.svelte
@@ -59,6 +59,7 @@
import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store';
import AlbumOptions from '$lib/components/album-page/album-options.svelte';
import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
+ import { user } from '$lib/stores/user.store';
export let data: PageData;
@@ -66,6 +67,9 @@
let { slideshowState, slideshowShuffle } = slideshowStore;
let album = data.album;
+
+ $user = data.user;
+
$: album = data.album;
$: {
@@ -96,7 +100,6 @@
let isShowActivity = false;
let isLiked: ActivityResponseDto | null = null;
let reactions: ActivityResponseDto[] = [];
- let user = data.user;
let globalWidth: number;
let assetGridWidth: number;
@@ -179,10 +182,10 @@
};
const getFavorite = async () => {
- if (user) {
+ if ($user) {
try {
const { data } = await api.activityApi.getActivities({
- userId: user.id,
+ userId: $user.id,
albumId: album.id,
type: ReactionType.Like,
level: ReactionLevel.Album,
@@ -549,16 +552,10 @@
style={`width:${assetGridWidth}px`}
>
{#if viewMode === ViewMode.SELECT_ASSETS}
-
+
{:else}
0}
@@ -679,7 +676,7 @@
{/if}
- {#if album.sharedUsers.length > 0 && album && isShowActivity && user && !$showAssetViewer}
+ {#if album.sharedUsers.length > 0 && album && isShowActivity && $user && !$showAssetViewer}
{/if}
-{#if viewMode === ViewMode.OPTIONS}
+{#if viewMode === ViewMode.OPTIONS && $user}
(viewMode = ViewMode.VIEW)}
on:toggleEnableActivity={handleToggleEnableActivity}
on:showSelectSharedUser={() => (viewMode = ViewMode.SELECT_USERS)}
diff --git a/web/src/routes/(user)/photos/+page.svelte b/web/src/routes/(user)/photos/+page.svelte
index e74a109b9..6cf3bdd64 100644
--- a/web/src/routes/(user)/photos/+page.svelte
+++ b/web/src/routes/(user)/photos/+page.svelte
@@ -24,6 +24,7 @@
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
+ import { user } from '$lib/stores/user.store';
export let data: PageData;
@@ -33,6 +34,8 @@
const assetInteractionStore = createAssetInteractionStore();
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
+ $user = data.user;
+
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
const handleEscape = () => {