|
|
|
@ -2,7 +2,7 @@ import { sdkMock } from '$lib/__mocks__/sdk.mock';
|
|
|
|
import { getMonthGroupByDate } from '$lib/managers/timeline-manager/internal/search-support.svelte';
|
|
|
|
import { getMonthGroupByDate } from '$lib/managers/timeline-manager/internal/search-support.svelte';
|
|
|
|
import { AbortError } from '$lib/utils';
|
|
|
|
import { AbortError } from '$lib/utils';
|
|
|
|
import { fromISODateTimeUTCToObject } from '$lib/utils/timeline-util';
|
|
|
|
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 { timelineAssetFactory, toResponseDto } from '@test-data/factories/asset-factory';
|
|
|
|
import { tick } from 'svelte';
|
|
|
|
import { tick } from 'svelte';
|
|
|
|
import { TimelineManager } from './timeline-manager.svelte';
|
|
|
|
import { TimelineManager } from './timeline-manager.svelte';
|
|
|
|
@ -175,7 +175,7 @@ describe('TimelineManager', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('addAssets', () => {
|
|
|
|
describe('upsertAssets', () => {
|
|
|
|
let timelineManager: TimelineManager;
|
|
|
|
let timelineManager: TimelineManager;
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
@ -196,7 +196,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
timelineManager.addAssets([asset]);
|
|
|
|
timelineManager.upsertAssets([asset]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.months.length).toEqual(1);
|
|
|
|
expect(timelineManager.months.length).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
@ -212,8 +212,8 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.map((asset) => deriveLocalDateTimeFromFileCreatedAt(asset));
|
|
|
|
.map((asset) => deriveLocalDateTimeFromFileCreatedAt(asset));
|
|
|
|
timelineManager.addAssets([assetOne]);
|
|
|
|
timelineManager.upsertAssets([assetOne]);
|
|
|
|
timelineManager.addAssets([assetTwo]);
|
|
|
|
timelineManager.upsertAssets([assetTwo]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.months.length).toEqual(1);
|
|
|
|
expect(timelineManager.months.length).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(2);
|
|
|
|
expect(timelineManager.assetCount).toEqual(2);
|
|
|
|
@ -238,7 +238,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-16T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-16T12:00:00.000Z'),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
timelineManager.addAssets([assetOne, assetTwo, assetThree]);
|
|
|
|
timelineManager.upsertAssets([assetOne, assetTwo, assetThree]);
|
|
|
|
|
|
|
|
|
|
|
|
const month = getMonthGroupByDate(timelineManager, { year: 2024, month: 1 });
|
|
|
|
const month = getMonthGroupByDate(timelineManager, { year: 2024, month: 1 });
|
|
|
|
expect(month).not.toBeNull();
|
|
|
|
expect(month).not.toBeNull();
|
|
|
|
@ -264,7 +264,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2023-01-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2023-01-20T12:00:00.000Z'),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
timelineManager.addAssets([assetOne, assetTwo, assetThree]);
|
|
|
|
timelineManager.upsertAssets([assetOne, assetTwo, assetThree]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.months.length).toEqual(3);
|
|
|
|
expect(timelineManager.months.length).toEqual(3);
|
|
|
|
expect(timelineManager.months[0].yearMonth.year).toEqual(2024);
|
|
|
|
expect(timelineManager.months[0].yearMonth.year).toEqual(2024);
|
|
|
|
@ -278,12 +278,10 @@ describe('TimelineManager', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('updates existing asset', () => {
|
|
|
|
it('updates existing asset', () => {
|
|
|
|
const updateAssetsSpy = vi.spyOn(timelineManager, 'updateAssets');
|
|
|
|
|
|
|
|
const asset = deriveLocalDateTimeFromFileCreatedAt(timelineAssetFactory.build());
|
|
|
|
const asset = deriveLocalDateTimeFromFileCreatedAt(timelineAssetFactory.build());
|
|
|
|
timelineManager.addAssets([asset]);
|
|
|
|
timelineManager.upsertAssets([asset]);
|
|
|
|
|
|
|
|
|
|
|
|
timelineManager.addAssets([asset]);
|
|
|
|
timelineManager.upsertAssets([asset]);
|
|
|
|
expect(updateAssetsSpy).toBeCalledWith([asset]);
|
|
|
|
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
@ -294,12 +292,12 @@ describe('TimelineManager', () => {
|
|
|
|
|
|
|
|
|
|
|
|
const timelineManager = new TimelineManager();
|
|
|
|
const timelineManager = new TimelineManager();
|
|
|
|
await timelineManager.updateOptions({ isTrashed: true });
|
|
|
|
await timelineManager.updateOptions({ isTrashed: true });
|
|
|
|
timelineManager.addAssets([asset, trashedAsset]);
|
|
|
|
timelineManager.upsertAssets([asset, trashedAsset]);
|
|
|
|
expect(await getAssets(timelineManager)).toEqual([trashedAsset]);
|
|
|
|
expect(await getAssets(timelineManager)).toEqual([trashedAsset]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('updateAssets', () => {
|
|
|
|
describe('upsertAssets - updating existing', () => {
|
|
|
|
let timelineManager: TimelineManager;
|
|
|
|
let timelineManager: TimelineManager;
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
@ -309,22 +307,15 @@ describe('TimelineManager', () => {
|
|
|
|
await timelineManager.updateViewport({ width: 1588, height: 1000 });
|
|
|
|
await timelineManager.updateViewport({ width: 1588, height: 1000 });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('ignores non-existing assets', () => {
|
|
|
|
|
|
|
|
timelineManager.updateAssets([deriveLocalDateTimeFromFileCreatedAt(timelineAssetFactory.build())]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.months.length).toEqual(0);
|
|
|
|
|
|
|
|
expect(timelineManager.assetCount).toEqual(0);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('updates an asset', () => {
|
|
|
|
it('updates an asset', () => {
|
|
|
|
const asset = deriveLocalDateTimeFromFileCreatedAt(timelineAssetFactory.build({ isFavorite: false }));
|
|
|
|
const asset = deriveLocalDateTimeFromFileCreatedAt(timelineAssetFactory.build({ isFavorite: false }));
|
|
|
|
const updatedAsset = { ...asset, isFavorite: true };
|
|
|
|
const updatedAsset = { ...asset, isFavorite: true };
|
|
|
|
|
|
|
|
|
|
|
|
timelineManager.addAssets([asset]);
|
|
|
|
timelineManager.upsertAssets([asset]);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.months[0].getFirstAsset().isFavorite).toEqual(false);
|
|
|
|
expect(timelineManager.months[0].getFirstAsset().isFavorite).toEqual(false);
|
|
|
|
|
|
|
|
|
|
|
|
timelineManager.updateAssets([updatedAsset]);
|
|
|
|
timelineManager.upsertAssets([updatedAsset]);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.months[0].getFirstAsset().isFavorite).toEqual(true);
|
|
|
|
expect(timelineManager.months[0].getFirstAsset().isFavorite).toEqual(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@ -340,18 +331,80 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-03-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-03-20T12:00:00.000Z'),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
timelineManager.addAssets([asset]);
|
|
|
|
timelineManager.upsertAssets([asset]);
|
|
|
|
expect(timelineManager.months.length).toEqual(1);
|
|
|
|
expect(timelineManager.months.length).toEqual(1);
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })).not.toBeUndefined();
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })).not.toBeUndefined();
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })?.getAssets().length).toEqual(1);
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })?.getAssets().length).toEqual(1);
|
|
|
|
|
|
|
|
|
|
|
|
timelineManager.updateAssets([updatedAsset]);
|
|
|
|
timelineManager.upsertAssets([updatedAsset]);
|
|
|
|
expect(timelineManager.months.length).toEqual(2);
|
|
|
|
expect(timelineManager.months.length).toEqual(2);
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })).not.toBeUndefined();
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })).not.toBeUndefined();
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })?.getAssets().length).toEqual(0);
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 1 })?.getAssets().length).toEqual(0);
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 3 })).not.toBeUndefined();
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 3 })).not.toBeUndefined();
|
|
|
|
expect(getMonthGroupByDate(timelineManager, { year: 2024, month: 3 })?.getAssets().length).toEqual(1);
|
|
|
|
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', () => {
|
|
|
|
describe('removeAssets', () => {
|
|
|
|
@ -365,7 +418,7 @@ describe('TimelineManager', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('ignores invalid IDs', () => {
|
|
|
|
it('ignores invalid IDs', () => {
|
|
|
|
timelineManager.addAssets(
|
|
|
|
timelineManager.upsertAssets(
|
|
|
|
timelineAssetFactory
|
|
|
|
timelineAssetFactory
|
|
|
|
.buildList(2, {
|
|
|
|
.buildList(2, {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
@ -385,7 +438,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.map((asset) => deriveLocalDateTimeFromFileCreatedAt(asset));
|
|
|
|
.map((asset) => deriveLocalDateTimeFromFileCreatedAt(asset));
|
|
|
|
timelineManager.addAssets([assetOne, assetTwo]);
|
|
|
|
timelineManager.upsertAssets([assetOne, assetTwo]);
|
|
|
|
timelineManager.removeAssets([assetOne.id]);
|
|
|
|
timelineManager.removeAssets([assetOne.id]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
expect(timelineManager.assetCount).toEqual(1);
|
|
|
|
@ -399,7 +452,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-20T12:00:00.000Z'),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.map((asset) => deriveLocalDateTimeFromFileCreatedAt(asset));
|
|
|
|
.map((asset) => deriveLocalDateTimeFromFileCreatedAt(asset));
|
|
|
|
timelineManager.addAssets(assets);
|
|
|
|
timelineManager.upsertAssets(assets);
|
|
|
|
timelineManager.removeAssets(assets.map((asset) => asset.id));
|
|
|
|
timelineManager.removeAssets(assets.map((asset) => asset.id));
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.assetCount).toEqual(0);
|
|
|
|
expect(timelineManager.assetCount).toEqual(0);
|
|
|
|
@ -431,7 +484,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-15T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-15T12:00:00.000Z'),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
timelineManager.addAssets([assetOne, assetTwo]);
|
|
|
|
timelineManager.upsertAssets([assetOne, assetTwo]);
|
|
|
|
expect(timelineManager.getFirstAsset()).toEqual(assetOne);
|
|
|
|
expect(timelineManager.getFirstAsset()).toEqual(assetOne);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@ -556,7 +609,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-02-15T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-02-15T12:00:00.000Z'),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
timelineManager.addAssets([assetOne, assetTwo]);
|
|
|
|
timelineManager.upsertAssets([assetOne, assetTwo]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(timelineManager.getMonthGroupByAssetId(assetTwo.id)?.yearMonth.year).toEqual(2024);
|
|
|
|
expect(timelineManager.getMonthGroupByAssetId(assetTwo.id)?.yearMonth.year).toEqual(2024);
|
|
|
|
expect(timelineManager.getMonthGroupByAssetId(assetTwo.id)?.yearMonth.month).toEqual(2);
|
|
|
|
expect(timelineManager.getMonthGroupByAssetId(assetTwo.id)?.yearMonth.month).toEqual(2);
|
|
|
|
@ -575,7 +628,7 @@ describe('TimelineManager', () => {
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-02-15T12:00:00.000Z'),
|
|
|
|
fileCreatedAt: fromISODateTimeUTCToObject('2024-02-15T12:00:00.000Z'),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
timelineManager.addAssets([assetOne, assetTwo]);
|
|
|
|
timelineManager.upsertAssets([assetOne, assetTwo]);
|
|
|
|
|
|
|
|
|
|
|
|
timelineManager.removeAssets([assetTwo.id]);
|
|
|
|
timelineManager.removeAssets([assetTwo.id]);
|
|
|
|
expect(timelineManager.getMonthGroupByAssetId(assetOne.id)?.yearMonth.year).toEqual(2024);
|
|
|
|
expect(timelineManager.getMonthGroupByAssetId(assetOne.id)?.yearMonth.year).toEqual(2024);
|
|
|
|
|