mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-02 18:47:07 -05:00 
			
		
		
		
	fix(web): detail panel out of sync when reopening (#11713)
* fix(web): detail panel out of sync when reopening * extract event handler
This commit is contained in:
		
							parent
							
								
									b749a68349
								
							
						
					
					
						commit
						c2965c4408
					
				@ -1,16 +1,23 @@
 | 
				
			|||||||
import { AssetMediaResponseDto, LoginResponseDto, SharedLinkType } from '@immich/sdk';
 | 
					import { AssetMediaResponseDto, LoginResponseDto, SharedLinkType } from '@immich/sdk';
 | 
				
			||||||
import { expect, test } from '@playwright/test';
 | 
					import { expect, test } from '@playwright/test';
 | 
				
			||||||
 | 
					import type { Socket } from 'socket.io-client';
 | 
				
			||||||
import { utils } from 'src/utils';
 | 
					import { utils } from 'src/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test.describe('Detail Panel', () => {
 | 
					test.describe('Detail Panel', () => {
 | 
				
			||||||
  let admin: LoginResponseDto;
 | 
					  let admin: LoginResponseDto;
 | 
				
			||||||
  let asset: AssetMediaResponseDto;
 | 
					  let asset: AssetMediaResponseDto;
 | 
				
			||||||
 | 
					  let websocket: Socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test.beforeAll(async () => {
 | 
					  test.beforeAll(async () => {
 | 
				
			||||||
    utils.initSdk();
 | 
					    utils.initSdk();
 | 
				
			||||||
    await utils.resetDatabase();
 | 
					    await utils.resetDatabase();
 | 
				
			||||||
    admin = await utils.adminSetup();
 | 
					    admin = await utils.adminSetup();
 | 
				
			||||||
    asset = await utils.createAsset(admin.accessToken);
 | 
					    asset = await utils.createAsset(admin.accessToken);
 | 
				
			||||||
 | 
					    websocket = await utils.connectWebsocket(admin.accessToken);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test.afterAll(() => {
 | 
				
			||||||
 | 
					    utils.disconnectWebsocket(websocket);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('can be opened for shared links', async ({ page }) => {
 | 
					  test('can be opened for shared links', async ({ page }) => {
 | 
				
			||||||
@ -57,4 +64,23 @@ test.describe('Detail Panel', () => {
 | 
				
			|||||||
    await expect(textarea).toBeVisible();
 | 
					    await expect(textarea).toBeVisible();
 | 
				
			||||||
    await expect(textarea).not.toBeDisabled();
 | 
					    await expect(textarea).not.toBeDisabled();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('description changes are visible after reopening', async ({ context, page }) => {
 | 
				
			||||||
 | 
					    await utils.setAuthCookies(context, admin.accessToken);
 | 
				
			||||||
 | 
					    await page.goto(`/photos/${asset.id}`);
 | 
				
			||||||
 | 
					    await page.waitForSelector('#immich-asset-viewer');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await page.getByRole('button', { name: 'Info' }).click();
 | 
				
			||||||
 | 
					    const textarea = page.getByRole('textbox', { name: 'Add a description' });
 | 
				
			||||||
 | 
					    await textarea.fill('new description');
 | 
				
			||||||
 | 
					    await expect(textarea).toHaveValue('new description');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await page.getByRole('button', { name: 'Info' }).click();
 | 
				
			||||||
 | 
					    await expect(textarea).not.toBeVisible();
 | 
				
			||||||
 | 
					    await page.getByRole('button', { name: 'Info' }).click();
 | 
				
			||||||
 | 
					    await expect(textarea).toBeVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await utils.waitForWebsocketEvent({ event: 'assetUpdate', id: asset.id });
 | 
				
			||||||
 | 
					    await expect(textarea).toHaveValue('new description');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -83,7 +83,7 @@
 | 
				
			|||||||
  let isLiked: ActivityResponseDto | null = null;
 | 
					  let isLiked: ActivityResponseDto | null = null;
 | 
				
			||||||
  let numberOfComments: number;
 | 
					  let numberOfComments: number;
 | 
				
			||||||
  let fullscreenElement: Element;
 | 
					  let fullscreenElement: Element;
 | 
				
			||||||
  let unsubscribe: () => void;
 | 
					  let unsubscribes: (() => void)[] = [];
 | 
				
			||||||
  let zoomToggle = () => void 0;
 | 
					  let zoomToggle = () => void 0;
 | 
				
			||||||
  let copyImage: () => Promise<void>;
 | 
					  let copyImage: () => Promise<void>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -172,6 +172,12 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onAssetUpdate = (assetUpdate: AssetResponseDto) => {
 | 
				
			||||||
 | 
					    if (assetUpdate.id === asset.id) {
 | 
				
			||||||
 | 
					      asset = assetUpdate;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $: {
 | 
					  $: {
 | 
				
			||||||
    if (isShared && asset.id) {
 | 
					    if (isShared && asset.id) {
 | 
				
			||||||
      handlePromiseError(getFavorite());
 | 
					      handlePromiseError(getFavorite());
 | 
				
			||||||
@ -180,11 +186,11 @@
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onMount(async () => {
 | 
					  onMount(async () => {
 | 
				
			||||||
    unsubscribe = websocketEvents.on('on_upload_success', (assetUpdate) => {
 | 
					    unsubscribes.push(
 | 
				
			||||||
      if (assetUpdate.id === asset.id) {
 | 
					      websocketEvents.on('on_upload_success', onAssetUpdate),
 | 
				
			||||||
        asset = assetUpdate;
 | 
					      websocketEvents.on('on_asset_update', onAssetUpdate),
 | 
				
			||||||
      }
 | 
					    );
 | 
				
			||||||
    });
 | 
					
 | 
				
			||||||
    await navigate({ targetRoute: 'current', assetId: asset.id });
 | 
					    await navigate({ targetRoute: 'current', assetId: asset.id });
 | 
				
			||||||
    slideshowStateUnsubscribe = slideshowState.subscribe((value) => {
 | 
					    slideshowStateUnsubscribe = slideshowState.subscribe((value) => {
 | 
				
			||||||
      if (value === SlideshowState.PlaySlideshow) {
 | 
					      if (value === SlideshowState.PlaySlideshow) {
 | 
				
			||||||
@ -225,7 +231,10 @@
 | 
				
			|||||||
    if (shuffleSlideshowUnsubscribe) {
 | 
					    if (shuffleSlideshowUnsubscribe) {
 | 
				
			||||||
      shuffleSlideshowUnsubscribe();
 | 
					      shuffleSlideshowUnsubscribe();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    unsubscribe?.();
 | 
					
 | 
				
			||||||
 | 
					    for (const unsubscribe of unsubscribes) {
 | 
				
			||||||
 | 
					      unsubscribe();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $: {
 | 
					  $: {
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,6 @@
 | 
				
			|||||||
  import { locale } from '$lib/stores/preferences.store';
 | 
					  import { locale } from '$lib/stores/preferences.store';
 | 
				
			||||||
  import { featureFlags } from '$lib/stores/server-config.store';
 | 
					  import { featureFlags } from '$lib/stores/server-config.store';
 | 
				
			||||||
  import { user } from '$lib/stores/user.store';
 | 
					  import { user } from '$lib/stores/user.store';
 | 
				
			||||||
  import { websocketEvents } from '$lib/stores/websocket';
 | 
					 | 
				
			||||||
  import { getAssetThumbnailUrl, getPeopleThumbnailUrl, handlePromiseError, isSharedLink } from '$lib/utils';
 | 
					  import { getAssetThumbnailUrl, getPeopleThumbnailUrl, handlePromiseError, isSharedLink } from '$lib/utils';
 | 
				
			||||||
  import { delay, isFlipped } from '$lib/utils/asset-utils';
 | 
					  import { delay, isFlipped } from '$lib/utils/asset-utils';
 | 
				
			||||||
  import {
 | 
					  import {
 | 
				
			||||||
@ -30,7 +29,7 @@
 | 
				
			|||||||
    mdiAccountOff,
 | 
					    mdiAccountOff,
 | 
				
			||||||
  } from '@mdi/js';
 | 
					  } from '@mdi/js';
 | 
				
			||||||
  import { DateTime } from 'luxon';
 | 
					  import { DateTime } from 'luxon';
 | 
				
			||||||
  import { createEventDispatcher, onMount } from 'svelte';
 | 
					  import { createEventDispatcher } from 'svelte';
 | 
				
			||||||
  import { slide } from 'svelte/transition';
 | 
					  import { slide } from 'svelte/transition';
 | 
				
			||||||
  import { getByteUnitString } from '$lib/utils/byte-units';
 | 
					  import { getByteUnitString } from '$lib/utils/byte-units';
 | 
				
			||||||
  import { handleError } from '$lib/utils/handle-error';
 | 
					  import { handleError } from '$lib/utils/handle-error';
 | 
				
			||||||
@ -99,14 +98,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  $: unassignedFaces = asset.unassignedFaces || [];
 | 
					  $: unassignedFaces = asset.unassignedFaces || [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onMount(() => {
 | 
					 | 
				
			||||||
    return websocketEvents.on('on_asset_update', (assetUpdate) => {
 | 
					 | 
				
			||||||
      if (assetUpdate.id === asset.id) {
 | 
					 | 
				
			||||||
        asset = assetUpdate;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const dispatch = createEventDispatcher<{
 | 
					  const dispatch = createEventDispatcher<{
 | 
				
			||||||
    close: void;
 | 
					    close: void;
 | 
				
			||||||
  }>();
 | 
					  }>();
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user