diff --git a/web/src/lib/components/timeline/TimelineDateGroup.svelte b/web/src/lib/components/timeline/TimelineDateGroup.svelte index cd0dc9a212..c662c16e72 100644 --- a/web/src/lib/components/timeline/TimelineDateGroup.svelte +++ b/web/src/lib/components/timeline/TimelineDateGroup.svelte @@ -2,7 +2,7 @@ import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte'; import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte'; - import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; + import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import { assetSnapshot, assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; diff --git a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts index bdf2b17cbe..3c6f2d8256 100644 --- a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts @@ -1,6 +1,6 @@ import { TUNABLES } from '$lib/utils/tunables'; import type { MonthGroup } from '../month-group.svelte'; -import type { TimelineManager } from '../timeline-manager.svelte'; +import { TimelineManager } from '../timeline-manager.svelte'; const { TIMELINE: { INTERSECTION_EXPAND_TOP, INTERSECTION_EXPAND_BOTTOM }, diff --git a/web/src/lib/managers/timeline-manager/internal/layout-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/layout-support.svelte.ts index 434b2d1847..b5dd5d5f70 100644 --- a/web/src/lib/managers/timeline-manager/internal/layout-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/layout-support.svelte.ts @@ -1,5 +1,5 @@ import type { MonthGroup } from '../month-group.svelte'; -import type { TimelineManager } from '../timeline-manager.svelte'; +import { TimelineManager } from '../timeline-manager.svelte'; import type { UpdateGeometryOptions } from '../types'; export function updateGeometry(timelineManager: TimelineManager, month: MonthGroup, options: UpdateGeometryOptions) { diff --git a/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts index 70b41462b9..28e98f9deb 100644 --- a/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/load-support.svelte.ts @@ -2,7 +2,7 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import { toISOYearMonthUTC } from '$lib/utils/timeline-util'; import { getTimeBucket } from '@immich/sdk'; import type { MonthGroup } from '../month-group.svelte'; -import type { TimelineManager } from '../timeline-manager.svelte'; +import { TimelineManager } from '../timeline-manager.svelte'; import type { TimelineManagerOptions } from '../types'; export async function loadFromTimeBuckets( diff --git a/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts index 52a37b52d0..f889456c20 100644 --- a/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/search-support.svelte.ts @@ -2,7 +2,7 @@ import { plainDateTimeCompare, type TimelineYearMonth } from '$lib/utils/timelin import { AssetOrder } from '@immich/sdk'; import { DateTime } from 'luxon'; import type { MonthGroup } from '../month-group.svelte'; -import type { TimelineManager } from '../timeline-manager.svelte'; +import { TimelineManager } from '../timeline-manager.svelte'; import type { AssetDescriptor, Direction, TimelineAsset } from '../types'; export async function getAssetWithOffset( diff --git a/web/src/lib/managers/timeline-manager/internal/websocket-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/websocket-support.svelte.ts index bff2f15cb9..9488811fe8 100644 --- a/web/src/lib/managers/timeline-manager/internal/websocket-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/websocket-support.svelte.ts @@ -1,4 +1,4 @@ -import type { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; +import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import type { PendingChange, TimelineAsset } from '$lib/managers/timeline-manager/types'; import { websocketEvents } from '$lib/stores/websocket'; import { toTimelineAsset } from '$lib/utils/timeline-util'; diff --git a/web/src/lib/managers/timeline-manager/month-group.svelte.ts b/web/src/lib/managers/timeline-manager/month-group.svelte.ts index 6ad74d4577..f4edf6111b 100644 --- a/web/src/lib/managers/timeline-manager/month-group.svelte.ts +++ b/web/src/lib/managers/timeline-manager/month-group.svelte.ts @@ -20,7 +20,7 @@ import { get } from 'svelte/store'; import { onCreateMonthGroup } from '$lib/managers/timeline-manager/internal/TestHooks.svelte'; import { DayGroup } from './day-group.svelte'; import { GroupInsertionCache } from './group-insertion-cache.svelte'; -import type { TimelineManager } from './timeline-manager.svelte'; +import { TimelineManager } from './timeline-manager.svelte'; import type { AssetDescriptor, AssetOperation, Direction, TimelineAsset } from './types'; import { ViewerAsset } from './viewer-asset.svelte'; diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.spec.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.spec.ts index 1539dd56e7..cbfce5c829 100644 --- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.spec.ts +++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.spec.ts @@ -5,7 +5,7 @@ import { setTestHooks } from '$lib/managers/timeline-manager/internal/TestHooks. import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte'; import { AbortError } from '$lib/utils'; import { fromISODateTimeUTCToObject } from '$lib/utils/timeline-util'; -import { type AssetResponseDto, type TimeBucketAssetResponseDto } from '@immich/sdk'; +import { AssetVisibility, type AssetResponseDto, type TimeBucketAssetResponseDto } from '@immich/sdk'; import { timelineAssetFactory, toResponseDto } from '@test-data/factories/asset-factory'; import { tick } from 'svelte'; import type { MockInstance } from 'vitest'; @@ -465,6 +465,69 @@ describe('TimelineManager', () => { expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 3 })).not.toBeUndefined(); expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 3 })?.getAssets().length).toEqual(1); }); + + it('asset is removed during upsert when TimelineManager if visibility changes', async () => { + await timelineManager.updateOptions({ + visibility: AssetVisibility.Archive, + }); + const fixture = deriveLocalDateTimeFromFileCreatedAt( + timelineAssetFactory.build({ + visibility: AssetVisibility.Archive, + }), + ); + + timelineManager.upsertAssets([fixture]); + expect(timelineManager.assetCount).toEqual(1); + + const updated = Object.freeze({ ...fixture, visibility: AssetVisibility.Timeline }); + timelineManager.upsertAssets([updated]); + expect(timelineManager.assetCount).toEqual(0); + + timelineManager.upsertAssets([{ ...fixture, visibility: AssetVisibility.Archive }]); + expect(timelineManager.assetCount).toEqual(1); + }); + + it('asset is removed during upsert when TimelineManager if isFavorite changes', async () => { + await timelineManager.updateOptions({ + isFavorite: true, + }); + const fixture = deriveLocalDateTimeFromFileCreatedAt( + timelineAssetFactory.build({ + isFavorite: true, + }), + ); + + timelineManager.upsertAssets([fixture]); + expect(timelineManager.assetCount).toEqual(1); + + const updated = Object.freeze({ ...fixture, isFavorite: false }); + timelineManager.upsertAssets([updated]); + expect(timelineManager.assetCount).toEqual(0); + + timelineManager.upsertAssets([{ ...fixture, isFavorite: true }]); + expect(timelineManager.assetCount).toEqual(1); + }); + + it('asset is removed during upsert when TimelineManager if isTrashed changes', async () => { + await timelineManager.updateOptions({ + isTrashed: true, + }); + const fixture = deriveLocalDateTimeFromFileCreatedAt( + timelineAssetFactory.build({ + isTrashed: true, + }), + ); + + timelineManager.upsertAssets([fixture]); + expect(timelineManager.assetCount).toEqual(1); + + const updated = Object.freeze({ ...fixture, isTrashed: false }); + timelineManager.upsertAssets([updated]); + expect(timelineManager.assetCount).toEqual(0); + + timelineManager.upsertAssets([{ ...fixture, isTrashed: true }]); + expect(timelineManager.assetCount).toEqual(1); + }); }); describe('removeAssets', () => { diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts index f1c0da1160..70e89d29cd 100644 --- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts +++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts @@ -323,9 +323,9 @@ export class TimelineManager extends VirtualScrollManager { } upsertAssets(assets: TimelineAsset[]) { - const notExcluded = assets.filter((asset) => !this.isExcluded(asset)); - const notUpdated = this.#updateAssets(notExcluded); - this.addAssetsToSegments(notUpdated); + const notUpdated = this.#updateAssets(assets); + const notExcluded = notUpdated.filter((asset) => !this.isExcluded(asset)); + this.addAssetsToSegments(notExcluded); } async findMonthGroupForAsset(id: string) { diff --git a/web/src/lib/modals/NavigateToDateModal.svelte b/web/src/lib/modals/NavigateToDateModal.svelte index 4b83c66bc6..365cbdb21c 100644 --- a/web/src/lib/modals/NavigateToDateModal.svelte +++ b/web/src/lib/modals/NavigateToDateModal.svelte @@ -1,6 +1,6 @@