mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:27:09 -05:00 
			
		
		
		
	fix(web): asset disappears from album after metadata edit (#7520)
This commit is contained in:
		
							parent
							
								
									100363c7be
								
							
						
					
					
						commit
						369acc7bea
					
				@ -20,7 +20,6 @@
 | 
				
			|||||||
  import ThemeButton from '../shared-components/theme-button.svelte';
 | 
					  import ThemeButton from '../shared-components/theme-button.svelte';
 | 
				
			||||||
  import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
 | 
					  import { shouldIgnoreShortcut } from '$lib/utils/shortcut';
 | 
				
			||||||
  import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js';
 | 
					  import { mdiFileImagePlusOutline, mdiFolderDownloadOutline } from '@mdi/js';
 | 
				
			||||||
  import UpdatePanel from '../shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
  import { handlePromiseError } from '$lib/utils';
 | 
					  import { handlePromiseError } from '$lib/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let sharedLink: SharedLinkResponseDto;
 | 
					  export let sharedLink: SharedLinkResponseDto;
 | 
				
			||||||
@ -168,5 +167,4 @@
 | 
				
			|||||||
      {/if}
 | 
					      {/if}
 | 
				
			||||||
    </section>
 | 
					    </section>
 | 
				
			||||||
  </AssetGrid>
 | 
					  </AssetGrid>
 | 
				
			||||||
  <UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
</main>
 | 
					</main>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +0,0 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					 | 
				
			||||||
  import { websocketEvents } from '$lib/stores/websocket';
 | 
					 | 
				
			||||||
  import type { AssetStore } from '$lib/stores/assets.store';
 | 
					 | 
				
			||||||
  import { onMount } from 'svelte';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  export let assetStore: AssetStore | null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  onMount(() => {
 | 
					 | 
				
			||||||
    return websocketEvents.on('on_asset_update', (asset) => {
 | 
					 | 
				
			||||||
      if (asset.originalFileName && assetStore) {
 | 
					 | 
				
			||||||
        assetStore.updateAsset(asset, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        assetStore.removeAsset(asset.id); // Update timeline
 | 
					 | 
				
			||||||
        assetStore.addAsset(asset);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
@ -49,6 +49,11 @@ interface AddAsset {
 | 
				
			|||||||
  value: AssetResponseDto;
 | 
					  value: AssetResponseDto;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface UpdateAsset {
 | 
				
			||||||
 | 
					  type: 'update';
 | 
				
			||||||
 | 
					  value: AssetResponseDto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface DeleteAsset {
 | 
					interface DeleteAsset {
 | 
				
			||||||
  type: 'delete';
 | 
					  type: 'delete';
 | 
				
			||||||
  value: string;
 | 
					  value: string;
 | 
				
			||||||
@ -61,7 +66,7 @@ interface TrashAsset {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const photoViewer = writable<HTMLImageElement | null>(null);
 | 
					export const photoViewer = writable<HTMLImageElement | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PendingChange = AddAsset | DeleteAsset | TrashAsset;
 | 
					type PendingChange = AddAsset | UpdateAsset | DeleteAsset | TrashAsset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class AssetStore {
 | 
					export class AssetStore {
 | 
				
			||||||
  private store$ = writable(this);
 | 
					  private store$ = writable(this);
 | 
				
			||||||
@ -102,6 +107,9 @@ export class AssetStore {
 | 
				
			|||||||
      websocketEvents.on('on_asset_trash', (ids) => {
 | 
					      websocketEvents.on('on_asset_trash', (ids) => {
 | 
				
			||||||
        this.addPendingChanges(...ids.map((id): TrashAsset => ({ type: 'trash', value: id })));
 | 
					        this.addPendingChanges(...ids.map((id): TrashAsset => ({ type: 'trash', value: id })));
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
 | 
					      websocketEvents.on('on_asset_update', (asset) => {
 | 
				
			||||||
 | 
					        this.addPendingChanges({ type: 'update', value: asset });
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
      websocketEvents.on('on_asset_delete', (id: string) => {
 | 
					      websocketEvents.on('on_asset_delete', (id: string) => {
 | 
				
			||||||
        this.addPendingChanges({ type: 'delete', value: id });
 | 
					        this.addPendingChanges({ type: 'delete', value: id });
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
@ -122,6 +130,11 @@ export class AssetStore {
 | 
				
			|||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case 'update': {
 | 
				
			||||||
 | 
					          this.updateAsset(value);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case 'trash': {
 | 
					        case 'trash': {
 | 
				
			||||||
          if (!this.options.isTrashed) {
 | 
					          if (!this.options.isTrashed) {
 | 
				
			||||||
            this.removeAsset(value);
 | 
					            this.removeAsset(value);
 | 
				
			||||||
@ -276,6 +289,10 @@ export class AssetStore {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.addAssetToBucket(asset);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private addAssetToBucket(asset: AssetResponseDto) {
 | 
				
			||||||
    const timeBucket = DateTime.fromISO(asset.fileCreatedAt).toUTC().startOf('month').toString();
 | 
					    const timeBucket = DateTime.fromISO(asset.fileCreatedAt).toUTC().startOf('month').toString();
 | 
				
			||||||
    let bucket = this.getBucketByDate(timeBucket);
 | 
					    let bucket = this.getBucketByDate(timeBucket);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -307,7 +324,7 @@ export class AssetStore {
 | 
				
			|||||||
    // If we added an asset to the store, we need to recalculate
 | 
					    // If we added an asset to the store, we need to recalculate
 | 
				
			||||||
    // asset store containers
 | 
					    // asset store containers
 | 
				
			||||||
    this.assets.push(asset);
 | 
					    this.assets.push(asset);
 | 
				
			||||||
    this.updateAsset(asset, true);
 | 
					    this.emit(true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getBucketByDate(bucketDate: string): AssetBucket | null {
 | 
					  getBucketByDate(bucketDate: string): AssetBucket | null {
 | 
				
			||||||
@ -338,14 +355,20 @@ export class AssetStore {
 | 
				
			|||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateAsset(_asset: AssetResponseDto, recalculate = false) {
 | 
					  updateAsset(_asset: AssetResponseDto) {
 | 
				
			||||||
    const asset = this.assets.find((asset) => asset.id === _asset.id);
 | 
					    const asset = this.assets.find((asset) => asset.id === _asset.id);
 | 
				
			||||||
    if (!asset) {
 | 
					    if (!asset) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Object.assign(asset, _asset);
 | 
					    const recalculate = asset.fileCreatedAt !== _asset.fileCreatedAt;
 | 
				
			||||||
 | 
					    if (recalculate) {
 | 
				
			||||||
 | 
					      this.removeAsset(asset.id);
 | 
				
			||||||
 | 
					      this.addAssetToBucket(_asset);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Object.assign(asset, _asset);
 | 
				
			||||||
    this.emit(recalculate);
 | 
					    this.emit(recalculate);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -357,6 +380,9 @@ export class AssetStore {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  removeAsset(id: string) {
 | 
					  removeAsset(id: string) {
 | 
				
			||||||
 | 
					    this.assets = this.assets.filter((asset) => asset.id !== id);
 | 
				
			||||||
 | 
					    delete this.assetToBucket[id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (let index = 0; index < this.buckets.length; index++) {
 | 
					    for (let index = 0; index < this.buckets.length; index++) {
 | 
				
			||||||
      const bucket = this.buckets[index];
 | 
					      const bucket = this.buckets[index];
 | 
				
			||||||
      for (let index_ = 0; index_ < bucket.assets.length; index_++) {
 | 
					      for (let index_ = 0; index_ < bucket.assets.length; index_++) {
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
    NotificationType,
 | 
					    NotificationType,
 | 
				
			||||||
    notificationController,
 | 
					    notificationController,
 | 
				
			||||||
  } from '$lib/components/shared-components/notification/notification';
 | 
					  } from '$lib/components/shared-components/notification/notification';
 | 
				
			||||||
  import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
  import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
 | 
					  import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
 | 
				
			||||||
  import { AppRoute, dateFormats } from '$lib/constants';
 | 
					  import { AppRoute, dateFormats } from '$lib/constants';
 | 
				
			||||||
  import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store';
 | 
					  import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store';
 | 
				
			||||||
@ -718,8 +717,6 @@
 | 
				
			|||||||
  />
 | 
					  />
 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
  ::placeholder {
 | 
					  ::placeholder {
 | 
				
			||||||
    color: rgb(60, 60, 60);
 | 
					    color: rgb(60, 60, 60);
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,6 @@
 | 
				
			|||||||
  import { AssetStore } from '$lib/stores/assets.store';
 | 
					  import { AssetStore } from '$lib/stores/assets.store';
 | 
				
			||||||
  import type { PageData } from './$types';
 | 
					  import type { PageData } from './$types';
 | 
				
			||||||
  import { mdiPlus, mdiDotsVertical } from '@mdi/js';
 | 
					  import { mdiPlus, mdiDotsVertical } from '@mdi/js';
 | 
				
			||||||
  import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let data: PageData;
 | 
					  export let data: PageData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,4 +52,3 @@
 | 
				
			|||||||
    />
 | 
					    />
 | 
				
			||||||
  </AssetGrid>
 | 
					  </AssetGrid>
 | 
				
			||||||
</UserPageLayout>
 | 
					</UserPageLayout>
 | 
				
			||||||
<UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,6 @@
 | 
				
			|||||||
  import { AssetStore } from '$lib/stores/assets.store';
 | 
					  import { AssetStore } from '$lib/stores/assets.store';
 | 
				
			||||||
  import type { PageData } from './$types';
 | 
					  import type { PageData } from './$types';
 | 
				
			||||||
  import { mdiDotsVertical, mdiPlus } from '@mdi/js';
 | 
					  import { mdiDotsVertical, mdiPlus } from '@mdi/js';
 | 
				
			||||||
  import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let data: PageData;
 | 
					  export let data: PageData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -58,4 +57,3 @@
 | 
				
			|||||||
    />
 | 
					    />
 | 
				
			||||||
  </AssetGrid>
 | 
					  </AssetGrid>
 | 
				
			||||||
</UserPageLayout>
 | 
					</UserPageLayout>
 | 
				
			||||||
<UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,6 @@
 | 
				
			|||||||
  import { onDestroy } from 'svelte';
 | 
					  import { onDestroy } from 'svelte';
 | 
				
			||||||
  import type { PageData } from './$types';
 | 
					  import type { PageData } from './$types';
 | 
				
			||||||
  import { mdiPlus, mdiArrowLeft } from '@mdi/js';
 | 
					  import { mdiPlus, mdiArrowLeft } from '@mdi/js';
 | 
				
			||||||
  import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let data: PageData;
 | 
					  export let data: PageData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,5 +45,4 @@
 | 
				
			|||||||
    </ControlAppBar>
 | 
					    </ControlAppBar>
 | 
				
			||||||
  {/if}
 | 
					  {/if}
 | 
				
			||||||
  <AssetGrid {assetStore} {assetInteractionStore} />
 | 
					  <AssetGrid {assetStore} {assetInteractionStore} />
 | 
				
			||||||
  <UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
</main>
 | 
					</main>
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,6 @@
 | 
				
			|||||||
  import { openFileUploadDialog } from '$lib/utils/file-uploader';
 | 
					  import { openFileUploadDialog } from '$lib/utils/file-uploader';
 | 
				
			||||||
  import { assetViewingStore } from '$lib/stores/asset-viewing.store';
 | 
					  import { assetViewingStore } from '$lib/stores/asset-viewing.store';
 | 
				
			||||||
  import { mdiDotsVertical, mdiPlus } from '@mdi/js';
 | 
					  import { mdiDotsVertical, mdiPlus } from '@mdi/js';
 | 
				
			||||||
  import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
  import { user } from '$lib/stores/user.store';
 | 
					  import { user } from '$lib/stores/user.store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let { isViewing: showAssetViewer } = assetViewingStore;
 | 
					  let { isViewing: showAssetViewer } = assetViewingStore;
 | 
				
			||||||
@ -96,4 +95,3 @@
 | 
				
			|||||||
    />
 | 
					    />
 | 
				
			||||||
  </AssetGrid>
 | 
					  </AssetGrid>
 | 
				
			||||||
</UserPageLayout>
 | 
					</UserPageLayout>
 | 
				
			||||||
<UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,6 @@
 | 
				
			|||||||
    NotificationType,
 | 
					    NotificationType,
 | 
				
			||||||
    notificationController,
 | 
					    notificationController,
 | 
				
			||||||
  } from '$lib/components/shared-components/notification/notification';
 | 
					  } from '$lib/components/shared-components/notification/notification';
 | 
				
			||||||
  import UpdatePanel from '$lib/components/shared-components/update-panel.svelte';
 | 
					 | 
				
			||||||
  import { AppRoute } from '$lib/constants';
 | 
					  import { AppRoute } from '$lib/constants';
 | 
				
			||||||
  import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
 | 
					  import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
 | 
				
			||||||
  import { AssetStore } from '$lib/stores/assets.store';
 | 
					  import { AssetStore } from '$lib/stores/assets.store';
 | 
				
			||||||
@ -115,4 +114,3 @@
 | 
				
			|||||||
    </svelte:fragment>
 | 
					    </svelte:fragment>
 | 
				
			||||||
  </ConfirmDialogue>
 | 
					  </ConfirmDialogue>
 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
<UpdatePanel {assetStore} />
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user