Skip to content

Commit 5226898

Browse files
authored
fix: update timeline-manager after archive actions (#24010)
* fix: update timeline-manager after archive actions * Add locators to thumb icons
1 parent dd41698 commit 5226898

File tree

7 files changed

+145
-29
lines changed

7 files changed

+145
-29
lines changed

e2e/src/web/specs/timeline/timeline.parallel-e2e-spec.ts

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,53 @@ test.describe('Timeline', () => {
611611
await page.getByText('Photos', { exact: true }).click();
612612
await thumbnailUtils.expectInViewport(page, assetToArchive.id);
613613
});
614+
test('open /archive, favorite photo, unfavorite', async ({ page }) => {
615+
const assetToFavorite = assets[0];
616+
changes.assetArchivals.push(assetToFavorite.id);
617+
await pageUtils.openArchivePage(page);
618+
const favorite = pageRoutePromise(page, '**/api/assets', async (route, request) => {
619+
const requestJson = request.postDataJSON();
620+
if (requestJson.isFavorite === undefined) {
621+
return await route.continue();
622+
}
623+
const isFavorite = requestJson.isFavorite;
624+
if (isFavorite) {
625+
changes.assetFavorites.push(...requestJson.ids);
626+
}
627+
await route.fulfill({
628+
status: 204,
629+
});
630+
});
631+
await thumbnailUtils.withAssetId(page, assetToFavorite.id).hover();
632+
await thumbnailUtils.selectButton(page, assetToFavorite.id).click();
633+
await page.getByLabel('Favorite').click();
634+
await expect(favorite).resolves.toEqual({
635+
isFavorite: true,
636+
ids: [assetToFavorite.id],
637+
});
638+
await expect(thumbnailUtils.withAssetId(page, assetToFavorite.id)).toHaveCount(1);
639+
await thumbnailUtils.expectInViewport(page, assetToFavorite.id);
640+
await thumbnailUtils.expectThumbnailIsFavorite(page, assetToFavorite.id);
641+
await thumbnailUtils.withAssetId(page, assetToFavorite.id).hover();
642+
await thumbnailUtils.selectButton(page, assetToFavorite.id).click();
643+
const unFavoriteRequest = pageRoutePromise(page, '**/api/assets', async (route, request) => {
644+
const requestJson = request.postDataJSON();
645+
if (requestJson.isFavorite === undefined) {
646+
return await route.continue();
647+
}
648+
changes.assetFavorites = changes.assetFavorites.filter((id) => !requestJson.ids.includes(id));
649+
await route.fulfill({
650+
status: 204,
651+
});
652+
});
653+
await page.getByLabel('Remove from favorites').click();
654+
await expect(unFavoriteRequest).resolves.toEqual({
655+
isFavorite: false,
656+
ids: [assetToFavorite.id],
657+
});
658+
await expect(thumbnailUtils.withAssetId(page, assetToFavorite.id)).toHaveCount(1);
659+
await thumbnailUtils.expectThumbnailIsNotFavorite(page, assetToFavorite.id);
660+
});
614661
test('open album, archive photo, open album, unarchive', async ({ page }) => {
615662
const album = timelineRestData.album;
616663
await pageUtils.openAlbumPage(page, album.id);
@@ -633,8 +680,7 @@ test.describe('Timeline', () => {
633680
visibility: 'archive',
634681
ids: [assetToArchive.id],
635682
});
636-
console.log('Skipping assertion - TODO - fix that archiving in album doesnt add icon');
637-
// await thumbnail.expectThumbnailIsArchive(page, assetToArchive.id);
683+
await thumbnailUtils.expectThumbnailIsArchive(page, assetToArchive.id);
638684
await page.locator('#asset-selection-app-bar').getByLabel('Close').click();
639685
await page.getByRole('link').getByText('Archive').click();
640686
await timelineUtils.waitForTimelineLoad(page);
@@ -656,8 +702,7 @@ test.describe('Timeline', () => {
656702
visibility: 'timeline',
657703
ids: [assetToArchive.id],
658704
});
659-
console.log('Skipping assertion - TODO - fix bug with not removing asset from timeline-manager after unarchive');
660-
// await expect(thumbnail.withAssetId(page, assetToArchive.id)).toHaveCount(0);
705+
await expect(thumbnailUtils.withAssetId(page, assetToArchive.id)).toHaveCount(0);
661706
await pageUtils.openAlbumPage(page, album.id);
662707
await thumbnailUtils.expectInViewport(page, assetToArchive.id);
663708
});
@@ -712,6 +757,50 @@ test.describe('Timeline', () => {
712757
await page.getByText('Photos', { exact: true }).click();
713758
await thumbnailUtils.expectInViewport(page, assetToFavorite.id);
714759
});
760+
test('open /favorites, archive photo, unarchive photo', async ({ page }) => {
761+
await pageUtils.openFavorites(page);
762+
const assetToArchive = getAsset(timelineRestData, 'ad31e29f-2069-4574-b9a9-ad86523c92cb')!;
763+
await thumbnailUtils.withAssetId(page, assetToArchive.id).hover();
764+
await thumbnailUtils.selectButton(page, assetToArchive.id).click();
765+
await page.getByLabel('Menu').click();
766+
const archive = pageRoutePromise(page, '**/api/assets', async (route, request) => {
767+
const requestJson = request.postDataJSON();
768+
if (requestJson.visibility !== 'archive') {
769+
return await route.continue();
770+
}
771+
await route.fulfill({
772+
status: 204,
773+
});
774+
changes.assetArchivals.push(...requestJson.ids);
775+
});
776+
await page.getByRole('menuitem').getByText('Archive').click();
777+
await expect(archive).resolves.toEqual({
778+
visibility: 'archive',
779+
ids: [assetToArchive.id],
780+
});
781+
await page.getByRole('link').getByText('Archive').click();
782+
await thumbnailUtils.expectInViewport(page, assetToArchive.id);
783+
await thumbnailUtils.expectThumbnailIsNotArchive(page, assetToArchive.id);
784+
await thumbnailUtils.withAssetId(page, assetToArchive.id).hover();
785+
await thumbnailUtils.selectButton(page, assetToArchive.id).click();
786+
const unarchiveRequest = pageRoutePromise(page, '**/api/assets', async (route, request) => {
787+
const requestJson = request.postDataJSON();
788+
if (requestJson.visibility !== 'timeline') {
789+
return await route.continue();
790+
}
791+
changes.assetArchivals = changes.assetArchivals.filter((id) => !requestJson.ids.includes(id));
792+
await route.fulfill({
793+
status: 204,
794+
});
795+
});
796+
await page.getByLabel('Unarchive').click();
797+
await expect(unarchiveRequest).resolves.toEqual({
798+
visibility: 'timeline',
799+
ids: [assetToArchive.id],
800+
});
801+
await expect(thumbnailUtils.withAssetId(page, assetToArchive.id)).toHaveCount(0);
802+
await thumbnailUtils.expectThumbnailIsNotArchive(page, assetToArchive.id);
803+
});
715804
test('Open album, favorite photo, open /favorites, remove favorite, Open album', async ({ page }) => {
716805
const album = timelineRestData.album;
717806
await pageUtils.openAlbumPage(page, album.id);

e2e/src/web/specs/timeline/utils.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,16 @@ export const thumbnailUtils = {
105105
return await poll(page, () => thumbnailUtils.queryThumbnailInViewport(page, collector));
106106
},
107107
async expectThumbnailIsFavorite(page: Page, assetId: string) {
108-
await expect(
109-
thumbnailUtils
110-
.withAssetId(page, assetId)
111-
.locator(
112-
'path[d="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"]',
113-
),
114-
).toHaveCount(1);
108+
await expect(thumbnailUtils.withAssetId(page, assetId).locator('[data-icon-favorite]')).toHaveCount(1);
109+
},
110+
async expectThumbnailIsNotFavorite(page: Page, assetId: string) {
111+
await expect(thumbnailUtils.withAssetId(page, assetId).locator('[data-icon-favorite]')).toHaveCount(0);
115112
},
116113
async expectThumbnailIsArchive(page: Page, assetId: string) {
117-
await expect(
118-
thumbnailUtils
119-
.withAssetId(page, assetId)
120-
.locator('path[d="M20 21H4V10H6V19H18V10H20V21M3 3H21V9H3V3M5 5V7H19V5M10.5 11V14H8L12 18L16 14H13.5V11"]'),
121-
).toHaveCount(1);
114+
await expect(thumbnailUtils.withAssetId(page, assetId).locator('[data-icon-archive]')).toHaveCount(1);
115+
},
116+
async expectThumbnailIsNotArchive(page: Page, assetId: string) {
117+
await expect(thumbnailUtils.withAssetId(page, assetId).locator('[data-icon-archive]')).toHaveCount(0);
122118
},
123119
async expectSelectedReadonly(page: Page, assetId: string) {
124120
// todo - need a data attribute for selected
@@ -208,10 +204,18 @@ export const pageUtils = {
208204
await page.goto(`/photos`);
209205
await timelineUtils.waitForTimelineLoad(page);
210206
},
207+
async openFavorites(page: Page) {
208+
await page.goto(`/favorites`);
209+
await timelineUtils.waitForTimelineLoad(page);
210+
},
211211
async openAlbumPage(page: Page, albumId: string) {
212212
await page.goto(`/albums/${albumId}`);
213213
await timelineUtils.waitForTimelineLoad(page);
214214
},
215+
async openArchivePage(page: Page) {
216+
await page.goto(`/archive`);
217+
await timelineUtils.waitForTimelineLoad(page);
218+
},
215219
async deepLinkAlbumPage(page: Page, albumId: string, assetId: string) {
216220
await page.goto(`/albums/${albumId}?at=${assetId}`);
217221
await timelineUtils.waitForTimelineLoad(page);

web/src/lib/components/assets/thumbnail/thumbnail.svelte

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,28 +264,28 @@
264264
<!-- Favorite asset star -->
265265
{#if !authManager.isSharedLink && asset.isFavorite}
266266
<div class="absolute bottom-2 start-2">
267-
<Icon icon={mdiHeart} size="24" class="text-white" />
267+
<Icon data-icon-favorite icon={mdiHeart} size="24" class="text-white" />
268268
</div>
269269
{/if}
270270

271271
{#if !authManager.isSharedLink && showArchiveIcon && asset.visibility === AssetVisibility.Archive}
272272
<div class={['absolute start-2', asset.isFavorite ? 'bottom-10' : 'bottom-2']}>
273-
<Icon icon={mdiArchiveArrowDownOutline} size="24" class="text-white" />
273+
<Icon data-icon-archive icon={mdiArchiveArrowDownOutline} size="24" class="text-white" />
274274
</div>
275275
{/if}
276276

277277
{#if asset.isImage && asset.projectionType === ProjectionType.EQUIRECTANGULAR}
278278
<div class="absolute end-0 top-0 flex place-items-center gap-1 text-xs font-medium text-white">
279279
<span class="pe-2 pt-2">
280-
<Icon icon={mdiRotate360} size="24" />
280+
<Icon data-icon-equirectangular icon={mdiRotate360} size="24" />
281281
</span>
282282
</div>
283283
{/if}
284284

285285
{#if asset.isImage && asset.duration && !asset.duration.includes('0:00:00.000')}
286286
<div class="absolute end-0 top-0 flex place-items-center gap-1 text-xs font-medium text-white">
287287
<span class="pe-2 pt-2">
288-
<Icon icon={mdiFileGifBox} size="24" />
288+
<Icon data-icon-playable icon={mdiFileGifBox} size="24" />
289289
</span>
290290
</div>
291291
{/if}
@@ -300,7 +300,7 @@
300300
>
301301
<span class="pe-2 pt-2 flex place-items-center gap-1">
302302
<p>{asset.stack.assetCount.toLocaleString($locale)}</p>
303-
<Icon icon={mdiCameraBurst} size="24" />
303+
<Icon data-icon-stack icon={mdiCameraBurst} size="24" />
304304
</span>
305305
</div>
306306
{/if}
@@ -366,7 +366,7 @@
366366
/>
367367
<div class="absolute end-0 top-0 flex place-items-center gap-1 text-xs font-medium text-white">
368368
<span class="pe-2 pt-2">
369-
<Icon icon={mdiMotionPauseOutline} size="24" />
369+
<Icon data-icon-playable-pause icon={mdiMotionPauseOutline} size="24" />
370370
</span>
371371
</div>
372372
</div>
@@ -406,13 +406,13 @@
406406
{disabled}
407407
>
408408
{#if disabled}
409-
<Icon icon={mdiCheckCircle} size="24" class="text-zinc-800" />
409+
<Icon data-icon-select icon={mdiCheckCircle} size="24" class="text-zinc-800" />
410410
{:else if selected}
411411
<div class="rounded-full bg-[#D9DCEF] dark:bg-[#232932]">
412-
<Icon icon={mdiCheckCircle} size="24" class="text-primary" />
412+
<Icon data-icon-select icon={mdiCheckCircle} size="24" class="text-primary" />
413413
</div>
414414
{:else}
415-
<Icon icon={mdiCheckCircle} size="24" class="text-white/80 hover:text-white" />
415+
<Icon data-icon-select icon={mdiCheckCircle} size="24" class="text-white/80 hover:text-white" />
416416
{/if}
417417
</button>
418418
{/if}

web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,15 @@
567567
onClick={() => updateThumbnailUsingCurrentSelection()}
568568
/>
569569
{/if}
570-
<ArchiveAction menuItem unarchive={assetInteraction.isAllArchived} />
570+
<ArchiveAction
571+
menuItem
572+
unarchive={assetInteraction.isAllArchived}
573+
onArchive={(ids, visibility) =>
574+
timelineManager.updateAssetOperation(ids, (asset) => {
575+
asset.visibility = visibility;
576+
return { remove: false };
577+
})}
578+
/>
571579
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
572580
{/if}
573581

web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@
8585
<ArchiveAction
8686
menuItem
8787
unarchive={assetInteraction.isAllArchived}
88-
onArchive={(assetIds) => timelineManager.removeAssets(assetIds)}
88+
onArchive={(ids, visibility) =>
89+
timelineManager.updateAssetOperation(ids, (asset) => {
90+
asset.visibility = visibility;
91+
return { remove: false };
92+
})}
8993
/>
9094
{#if $preferences.tags.enabled}
9195
<TagAction menuItem />

web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,11 @@
511511
<ArchiveAction
512512
menuItem
513513
unarchive={assetInteraction.isAllArchived}
514-
onArchive={(assetIds) => timelineManager.removeAssets(assetIds)}
514+
onArchive={(ids, visibility) =>
515+
timelineManager.updateAssetOperation(ids, (asset) => {
516+
asset.visibility = visibility;
517+
return { remove: false };
518+
})}
515519
/>
516520
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
517521
<TagAction menuItem />

web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,14 @@
146146
<ChangeDate menuItem />
147147
<ChangeDescription menuItem />
148148
<ChangeLocation menuItem />
149-
<ArchiveAction menuItem onArchive={(assetIds) => timelineManager.removeAssets(assetIds)} />
149+
<ArchiveAction
150+
menuItem
151+
onArchive={(ids, visibility) =>
152+
timelineManager.updateAssetOperation(ids, (asset) => {
153+
asset.visibility = visibility;
154+
return { remove: false };
155+
})}
156+
/>
150157
{#if $preferences.tags.enabled}
151158
<TagAction menuItem />
152159
{/if}

0 commit comments

Comments
 (0)