mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
Review comments
This commit is contained in:
parent
4f92be7f4f
commit
c2d37a912b
@ -207,7 +207,7 @@
|
|||||||
onSelect?.(asset);
|
onSelect?.(asset);
|
||||||
}
|
}
|
||||||
if (document.activeElement === element && evt.key === 'Escape') {
|
if (document.activeElement === element && evt.key === 'Escape') {
|
||||||
moveFocus((element) => element.dataset.thumbnailFocusContainer === undefined, true);
|
moveFocus((element) => element.dataset.thumbnailFocusContainer === undefined, 'next');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onclick={handleClick}
|
onclick={handleClick}
|
||||||
|
@ -12,9 +12,10 @@ const getFocusedThumb = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const focusNextAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, true);
|
export const focusNextAsset = () =>
|
||||||
|
moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, 'next');
|
||||||
export const focusPreviousAsset = () =>
|
export const focusPreviousAsset = () =>
|
||||||
moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, false);
|
moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, 'previous');
|
||||||
|
|
||||||
export const setFocusToAsset = async (scrollToAsset: (id: string) => Promise<boolean>, asset: { id: string }) => {
|
export const setFocusToAsset = async (scrollToAsset: (id: string) => Promise<boolean>, asset: { id: string }) => {
|
||||||
const scrolled = await scrollToAsset(asset.id);
|
const scrolled = await scrollToAsset(asset.id);
|
||||||
@ -27,8 +28,8 @@ export const setFocusToAsset = async (scrollToAsset: (id: string) => Promise<boo
|
|||||||
export const setFocusTo = async (
|
export const setFocusTo = async (
|
||||||
scrollToAsset: (id: string) => Promise<boolean>,
|
scrollToAsset: (id: string) => Promise<boolean>,
|
||||||
store: AssetStore,
|
store: AssetStore,
|
||||||
direction: 'next' | 'previous',
|
direction: 'earlier' | 'later',
|
||||||
skip: 'day' | 'month' | 'year',
|
magnitude: 'day' | 'month' | 'year',
|
||||||
) => {
|
) => {
|
||||||
const thumb = getFocusedThumb();
|
const thumb = getFocusedThumb();
|
||||||
if (!thumb) {
|
if (!thumb) {
|
||||||
@ -36,7 +37,7 @@ export const setFocusTo = async (
|
|||||||
// there are unfinished running invocations, so return early
|
// there are unfinished running invocations, so return early
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return direction === 'next' ? focusNextAsset() : focusPreviousAsset();
|
return direction === 'earlier' ? focusNextAsset() : focusPreviousAsset();
|
||||||
}
|
}
|
||||||
|
|
||||||
const invocation = tracker.startInvocation();
|
const invocation = tracker.startInvocation();
|
||||||
@ -47,7 +48,9 @@ export const setFocusTo = async (
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const asset =
|
const asset =
|
||||||
direction === 'next' ? await store.getNextAsset({ id }, skip) : await store.getPreviousAsset({ id }, skip);
|
direction === 'earlier'
|
||||||
|
? await store.getEarlierAsset({ id }, magnitude)
|
||||||
|
: await store.getLaterAsset({ id }, magnitude);
|
||||||
invocation.checkStillValid();
|
invocation.checkStillValid();
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
|
@ -382,26 +382,26 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePrevious = async () => {
|
const handlePrevious = async () => {
|
||||||
const previousAsset = await assetStore.getPreviousAsset($viewingAsset);
|
const laterAsset = await assetStore.getLaterAsset($viewingAsset);
|
||||||
|
|
||||||
if (previousAsset) {
|
if (laterAsset) {
|
||||||
const preloadAsset = await assetStore.getPreviousAsset(previousAsset);
|
const preloadAsset = await assetStore.getLaterAsset(laterAsset);
|
||||||
assetViewingStore.setAsset(previousAsset, preloadAsset ? [preloadAsset] : []);
|
assetViewingStore.setAsset(laterAsset, preloadAsset ? [preloadAsset] : []);
|
||||||
await navigate({ targetRoute: 'current', assetId: previousAsset.id });
|
await navigate({ targetRoute: 'current', assetId: laterAsset.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!previousAsset;
|
return !!laterAsset;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNext = async () => {
|
const handleNext = async () => {
|
||||||
const nextAsset = await assetStore.getNextAsset($viewingAsset);
|
const earlierAsset = await assetStore.getEarlierAsset($viewingAsset);
|
||||||
if (nextAsset) {
|
if (earlierAsset) {
|
||||||
const preloadAsset = await assetStore.getNextAsset(nextAsset);
|
const preloadAsset = await assetStore.getEarlierAsset(earlierAsset);
|
||||||
assetViewingStore.setAsset(nextAsset, preloadAsset ? [preloadAsset] : []);
|
assetViewingStore.setAsset(earlierAsset, preloadAsset ? [preloadAsset] : []);
|
||||||
await navigate({ targetRoute: 'current', assetId: nextAsset.id });
|
await navigate({ targetRoute: 'current', assetId: earlierAsset.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!nextAsset;
|
return !!earlierAsset;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRandom = async () => {
|
const handleRandom = async () => {
|
||||||
@ -629,8 +629,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const focusNextAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, true);
|
const focusNextAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, 'next');
|
||||||
const focusPreviousAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, false);
|
const focusPreviousAsset = () =>
|
||||||
|
moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, 'previous');
|
||||||
|
|
||||||
let isTrashEnabled = $derived($featureFlags.loaded && $featureFlags.trash);
|
let isTrashEnabled = $derived($featureFlags.loaded && $featureFlags.trash);
|
||||||
let isEmpty = $derived(assetStore.isInitialized && assetStore.buckets.length === 0);
|
let isEmpty = $derived(assetStore.isInitialized && assetStore.buckets.length === 0);
|
||||||
@ -669,12 +670,12 @@
|
|||||||
{ shortcut: { key: 'A', ctrl: true }, onShortcut: () => selectAllAssets(assetStore, assetInteraction) },
|
{ shortcut: { key: 'A', ctrl: true }, onShortcut: () => selectAllAssets(assetStore, assetInteraction) },
|
||||||
{ shortcut: { key: 'ArrowRight' }, onShortcut: focusNextAsset },
|
{ shortcut: { key: 'ArrowRight' }, onShortcut: focusNextAsset },
|
||||||
{ shortcut: { key: 'ArrowLeft' }, onShortcut: focusPreviousAsset },
|
{ shortcut: { key: 'ArrowLeft' }, onShortcut: focusPreviousAsset },
|
||||||
{ shortcut: { key: 'D' }, onShortcut: () => setFocusTo('next', 'day') },
|
{ shortcut: { key: 'D' }, onShortcut: () => setFocusTo('earlier', 'day') },
|
||||||
{ shortcut: { key: 'D', shift: true }, onShortcut: () => setFocusTo('previous', 'day') },
|
{ shortcut: { key: 'D', shift: true }, onShortcut: () => setFocusTo('later', 'day') },
|
||||||
{ shortcut: { key: 'M' }, onShortcut: () => setFocusTo('next', 'month') },
|
{ shortcut: { key: 'M' }, onShortcut: () => setFocusTo('earlier', 'month') },
|
||||||
{ shortcut: { key: 'M', shift: true }, onShortcut: () => setFocusTo('previous', 'month') },
|
{ shortcut: { key: 'M', shift: true }, onShortcut: () => setFocusTo('later', 'month') },
|
||||||
{ shortcut: { key: 'Y' }, onShortcut: () => setFocusTo('next', 'year') },
|
{ shortcut: { key: 'Y' }, onShortcut: () => setFocusTo('earlier', 'year') },
|
||||||
{ shortcut: { key: 'Y', shift: true }, onShortcut: () => setFocusTo('previous', 'year') },
|
{ shortcut: { key: 'Y', shift: true }, onShortcut: () => setFocusTo('later', 'year') },
|
||||||
{ shortcut: { key: 'G' }, onShortcut: () => (isShowSelectDate = true) },
|
{ shortcut: { key: 'G' }, onShortcut: () => (isShowSelectDate = true) },
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -728,7 +729,7 @@
|
|||||||
timezoneInput={false}
|
timezoneInput={false}
|
||||||
onConfirm={async (dateString: string) => {
|
onConfirm={async (dateString: string) => {
|
||||||
isShowSelectDate = false;
|
isShowSelectDate = false;
|
||||||
const date = DateTime.fromISO(dateString);
|
const date = DateTime.fromISO(dateString).toUTC();
|
||||||
const asset = await assetStore.getClosestAssetToDate(date);
|
const asset = await assetStore.getClosestAssetToDate(date);
|
||||||
if (asset) {
|
if (asset) {
|
||||||
await setFocusAsset(asset);
|
await setFocusAsset(asset);
|
||||||
|
@ -260,8 +260,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const focusNextAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, true);
|
const focusNextAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, 'next');
|
||||||
const focusPreviousAsset = () => moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, false);
|
const focusPreviousAsset = () =>
|
||||||
|
moveFocus((element) => element.dataset.thumbnailFocusContainer !== undefined, 'previous');
|
||||||
|
|
||||||
let isShortcutModalOpen = false;
|
let isShortcutModalOpen = false;
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
shortcuts = {
|
shortcuts = {
|
||||||
general: [
|
general: [
|
||||||
{ key: ['←', '→'], action: $t('previous_or_next_photo') },
|
{ key: ['←', '→'], action: $t('previous_or_next_photo') },
|
||||||
{ key: ['D', 'd'], action: 'Next or Previous Day' },
|
{ key: ['D', 'd'], action: 'Day forward/backward' },
|
||||||
{ key: ['M', 'm'], action: 'Next or Previous Month' },
|
{ key: ['M', 'm'], action: 'Month forward/backward' },
|
||||||
{ key: ['Y', 'y'], action: 'Next or Previous Year' },
|
{ key: ['Y', 'y'], action: 'Year forward/backward' },
|
||||||
{ key: ['x'], action: $t('select') },
|
{ key: ['x'], action: $t('select') },
|
||||||
{ key: ['Esc'], action: $t('back_close_deselect') },
|
{ key: ['Esc'], action: $t('back_close_deselect') },
|
||||||
{ key: ['Ctrl', 'k'], action: $t('search_your_photos') },
|
{ key: ['Ctrl', 'k'], action: $t('search_your_photos') },
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
shortcuts = {
|
shortcuts = {
|
||||||
general: [
|
general: [
|
||||||
{ key: ['←', '→'], action: $t('previous_or_next_photo') },
|
{ key: ['←', '→'], action: $t('previous_or_next_photo') },
|
||||||
|
{ key: ['D', 'd'], action: 'Day forward/backward' },
|
||||||
|
{ key: ['M', 'm'], action: 'Month forward/backward' },
|
||||||
|
{ key: ['Y', 'y'], action: 'Year forward/backward' },
|
||||||
{ key: ['x'], action: $t('select') },
|
{ key: ['x'], action: $t('select') },
|
||||||
{ key: ['Esc'], action: $t('back_close_deselect') },
|
{ key: ['Esc'], action: $t('back_close_deselect') },
|
||||||
{ key: ['Ctrl', 'k'], action: $t('search_your_photos') },
|
{ key: ['Ctrl', 'k'], action: $t('search_your_photos') },
|
||||||
|
@ -347,7 +347,7 @@ describe('AssetStore', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getPreviousAsset', () => {
|
describe('getLaterAsset', () => {
|
||||||
let assetStore: AssetStore;
|
let assetStore: AssetStore;
|
||||||
const bucketAssets: Record<string, AssetResponseDto[]> = {
|
const bucketAssets: Record<string, AssetResponseDto[]> = {
|
||||||
'2024-03-01T00:00:00.000Z': assetFactory
|
'2024-03-01T00:00:00.000Z': assetFactory
|
||||||
@ -374,8 +374,8 @@ describe('AssetStore', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns null for invalid assetId', async () => {
|
it('returns null for invalid assetId', async () => {
|
||||||
expect(() => assetStore.getPreviousAsset({ id: 'invalid' } as AssetResponseDto)).not.toThrow();
|
expect(() => assetStore.getLaterAsset({ id: 'invalid' } as AssetResponseDto)).not.toThrow();
|
||||||
expect(await assetStore.getPreviousAsset({ id: 'invalid' } as AssetResponseDto)).toBeUndefined();
|
expect(await assetStore.getLaterAsset({ id: 'invalid' } as AssetResponseDto)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns previous assetId', async () => {
|
it('returns previous assetId', async () => {
|
||||||
@ -384,7 +384,7 @@ describe('AssetStore', () => {
|
|||||||
|
|
||||||
const a = bucket!.getAssets()[0];
|
const a = bucket!.getAssets()[0];
|
||||||
const b = bucket!.getAssets()[1];
|
const b = bucket!.getAssets()[1];
|
||||||
const previous = await assetStore.getPreviousAsset(b);
|
const previous = await assetStore.getLaterAsset(b);
|
||||||
expect(previous).toEqual(a);
|
expect(previous).toEqual(a);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -396,7 +396,7 @@ describe('AssetStore', () => {
|
|||||||
const previousBucket = assetStore.getBucketByDate(2024, 3);
|
const previousBucket = assetStore.getBucketByDate(2024, 3);
|
||||||
const a = bucket!.getAssets()[0];
|
const a = bucket!.getAssets()[0];
|
||||||
const b = previousBucket!.getAssets()[0];
|
const b = previousBucket!.getAssets()[0];
|
||||||
const previous = await assetStore.getPreviousAsset(a);
|
const previous = await assetStore.getLaterAsset(a);
|
||||||
expect(previous).toEqual(b);
|
expect(previous).toEqual(b);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ describe('AssetStore', () => {
|
|||||||
const previousBucket = assetStore.getBucketByDate(2024, 3);
|
const previousBucket = assetStore.getBucketByDate(2024, 3);
|
||||||
const a = bucket!.getAssets()[0];
|
const a = bucket!.getAssets()[0];
|
||||||
const b = previousBucket!.getAssets()[0];
|
const b = previousBucket!.getAssets()[0];
|
||||||
const previous = await assetStore.getPreviousAsset(a);
|
const previous = await assetStore.getLaterAsset(a);
|
||||||
expect(previous).toEqual(b);
|
expect(previous).toEqual(b);
|
||||||
expect(loadBucketSpy).toBeCalledTimes(1);
|
expect(loadBucketSpy).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
@ -420,12 +420,12 @@ describe('AssetStore', () => {
|
|||||||
|
|
||||||
const [assetOne, assetTwo, assetThree] = assetStore.getAssets();
|
const [assetOne, assetTwo, assetThree] = assetStore.getAssets();
|
||||||
assetStore.removeAssets([assetTwo.id]);
|
assetStore.removeAssets([assetTwo.id]);
|
||||||
expect(await assetStore.getPreviousAsset(assetThree)).toEqual(assetOne);
|
expect(await assetStore.getLaterAsset(assetThree)).toEqual(assetOne);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns null when no more assets', async () => {
|
it('returns null when no more assets', async () => {
|
||||||
await assetStore.loadBucket('2024-03-01T00:00:00.000Z');
|
await assetStore.loadBucket('2024-03-01T00:00:00.000Z');
|
||||||
expect(await assetStore.getPreviousAsset(assetStore.getAssets()[0])).toBeUndefined();
|
expect(await assetStore.getLaterAsset(assetStore.getAssets()[0])).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ export type AssetStoreOptions = Omit<AssetApiGetTimeBucketsRequest, 'size'> & {
|
|||||||
timelineAlbumId?: string;
|
timelineAlbumId?: string;
|
||||||
deferInit?: boolean;
|
deferInit?: boolean;
|
||||||
};
|
};
|
||||||
|
type AssetDescriptor = { id: string };
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function updateObject(target: any, source: any): boolean {
|
function updateObject(target: any, source: any): boolean {
|
||||||
@ -60,6 +61,7 @@ function updateObject(target: any, source: any): boolean {
|
|||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
type Direction = 'forward' | 'backward';
|
||||||
|
|
||||||
export function assetSnapshot(asset: AssetResponseDto) {
|
export function assetSnapshot(asset: AssetResponseDto) {
|
||||||
return $state.snapshot(asset);
|
return $state.snapshot(asset);
|
||||||
@ -514,20 +516,16 @@ export class AssetBucket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findById(id: string) {
|
findAssetById(assetDescriptor: AssetDescriptor) {
|
||||||
return this.assets().find((asset) => asset.id === id);
|
return this.assets().find((asset) => asset.id === assetDescriptor.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
findClosest(target: DateTime) {
|
findClosest(target: DateTime) {
|
||||||
let closest = this.assets().next().value;
|
let closest = undefined;
|
||||||
if (!closest) {
|
let smallestDiff = Infinity;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let smallestDiff = Math.abs(target.toMillis() - DateTime.fromISO(closest.localDateTime).toUTC().toMillis());
|
|
||||||
|
|
||||||
for (const current of this.assets()) {
|
for (const current of this.assets()) {
|
||||||
const diff = Math.abs(target.toMillis() - DateTime.fromISO(current.localDateTime).toUTC().toMillis());
|
const currentDate = DateTime.fromISO(current.localDateTime).toUTC();
|
||||||
|
const diff = Math.abs(target.diff(currentDate).milliseconds);
|
||||||
if (diff < smallestDiff) {
|
if (diff < smallestDiff) {
|
||||||
smallestDiff = diff;
|
smallestDiff = diff;
|
||||||
closest = current;
|
closest = current;
|
||||||
@ -584,6 +582,11 @@ type AssetStoreLayoutOptions = {
|
|||||||
headerHeight?: number;
|
headerHeight?: number;
|
||||||
gap?: number;
|
gap?: number;
|
||||||
};
|
};
|
||||||
|
interface UpdateGeometryOptions {
|
||||||
|
invalidateHeight: boolean;
|
||||||
|
noDefer?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class AssetStore {
|
export class AssetStore {
|
||||||
// --- public ----
|
// --- public ----
|
||||||
isInitialized = $state(false);
|
isInitialized = $state(false);
|
||||||
@ -865,7 +868,7 @@ export class AssetStore {
|
|||||||
clearDeferredLayout(bucket: AssetBucket) {
|
clearDeferredLayout(bucket: AssetBucket) {
|
||||||
const hasDeferred = bucket.dateGroups.some((group) => group.deferredLayout);
|
const hasDeferred = bucket.dateGroups.some((group) => group.deferredLayout);
|
||||||
if (hasDeferred) {
|
if (hasDeferred) {
|
||||||
this.#updateGeometry(bucket, true, true);
|
this.#updateGeometry(bucket, { invalidateHeight: true, noDefer: true });
|
||||||
for (const group of bucket.dateGroups) {
|
for (const group of bucket.dateGroups) {
|
||||||
group.deferredLayout = false;
|
group.deferredLayout = false;
|
||||||
}
|
}
|
||||||
@ -987,7 +990,7 @@ export class AssetStore {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const bucket of this.buckets) {
|
for (const bucket of this.buckets) {
|
||||||
this.#updateGeometry(bucket, changedWidth);
|
this.#updateGeometry(bucket, { invalidateHeight: changedWidth });
|
||||||
}
|
}
|
||||||
this.updateIntersections();
|
this.updateIntersections();
|
||||||
this.#createScrubBuckets();
|
this.#createScrubBuckets();
|
||||||
@ -1013,7 +1016,9 @@ export class AssetStore {
|
|||||||
rowWidth: Math.floor(viewportWidth),
|
rowWidth: Math.floor(viewportWidth),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#updateGeometry(bucket: AssetBucket, invalidateHeight: boolean, noDefer: boolean = false) {
|
|
||||||
|
#updateGeometry(bucket: AssetBucket, options: UpdateGeometryOptions) {
|
||||||
|
const { invalidateHeight, noDefer = false } = options;
|
||||||
if (invalidateHeight) {
|
if (invalidateHeight) {
|
||||||
bucket.isBucketHeightActual = false;
|
bucket.isBucketHeightActual = false;
|
||||||
}
|
}
|
||||||
@ -1193,7 +1198,7 @@ export class AssetStore {
|
|||||||
}
|
}
|
||||||
for (const bucket of updatedBuckets) {
|
for (const bucket of updatedBuckets) {
|
||||||
bucket.sortDateGroups();
|
bucket.sortDateGroups();
|
||||||
this.#updateGeometry(bucket, true);
|
this.#updateGeometry(bucket, { invalidateHeight: true });
|
||||||
}
|
}
|
||||||
this.updateIntersections();
|
this.updateIntersections();
|
||||||
}
|
}
|
||||||
@ -1275,7 +1280,7 @@ export class AssetStore {
|
|||||||
}
|
}
|
||||||
const changedGeometry = changedBuckets.size > 0;
|
const changedGeometry = changedBuckets.size > 0;
|
||||||
for (const bucket of changedBuckets) {
|
for (const bucket of changedBuckets) {
|
||||||
this.#updateGeometry(bucket, true);
|
this.#updateGeometry(bucket, { invalidateHeight: true });
|
||||||
}
|
}
|
||||||
if (changedGeometry) {
|
if (changedGeometry) {
|
||||||
this.updateIntersections();
|
this.updateIntersections();
|
||||||
@ -1315,7 +1320,7 @@ export class AssetStore {
|
|||||||
|
|
||||||
refreshLayout() {
|
refreshLayout() {
|
||||||
for (const bucket of this.buckets) {
|
for (const bucket of this.buckets) {
|
||||||
this.#updateGeometry(bucket, true);
|
this.#updateGeometry(bucket, { invalidateHeight: true });
|
||||||
}
|
}
|
||||||
this.updateIntersections();
|
this.updateIntersections();
|
||||||
}
|
}
|
||||||
@ -1324,126 +1329,18 @@ export class AssetStore {
|
|||||||
return this.buckets[0]?.getFirstAsset();
|
return this.buckets[0]?.getFirstAsset();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPreviousAsset(
|
async getLaterAsset(
|
||||||
idable: { id: string },
|
assetDescriptor: AssetDescriptor,
|
||||||
skipTo: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
magnitude: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||||
): Promise<AssetResponseDto | undefined> {
|
): Promise<AssetResponseDto | undefined> {
|
||||||
const bucket = this.#findBucketForAsset(idable.id);
|
return this.#getAssetWithOffset(assetDescriptor, magnitude, 'forward');
|
||||||
if (!bucket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const asset = bucket.findById(idable.id);
|
|
||||||
if (!asset) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (skipTo) {
|
|
||||||
case 'day': {
|
|
||||||
return this.#getPreviousDay(asset, bucket);
|
|
||||||
}
|
|
||||||
case 'month': {
|
|
||||||
return this.#getPreviousMonth(asset, bucket);
|
|
||||||
}
|
|
||||||
case 'year': {
|
|
||||||
return this.#getPreviousYear(asset, bucket);
|
|
||||||
}
|
|
||||||
case 'asset': {
|
|
||||||
return this.#getPreviousAsset(asset, bucket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getPreviousDay(asset: AssetResponseDto, bucket: AssetBucket) {
|
async getEarlierAsset(
|
||||||
let nextDay = DateTime.fromISO(asset.localDateTime).toUTC().get('day') + 1;
|
assetDescriptor: AssetDescriptor,
|
||||||
const bucketIndex = this.buckets.indexOf(bucket);
|
magnitude: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||||
|
): Promise<AssetResponseDto | undefined> {
|
||||||
let nextDaygroup;
|
return this.#getAssetWithOffset(assetDescriptor, magnitude, 'backward');
|
||||||
while (nextDay <= 31) {
|
|
||||||
nextDaygroup = bucket.findDateGroupByDay(nextDay);
|
|
||||||
if (nextDaygroup) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
nextDay++;
|
|
||||||
}
|
|
||||||
if (nextDaygroup === undefined) {
|
|
||||||
let previousBucketIndex = bucketIndex - 1;
|
|
||||||
while (previousBucketIndex >= 0) {
|
|
||||||
bucket = this.buckets[previousBucketIndex];
|
|
||||||
if (!bucket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.loadBucket(bucket.bucketDate, { cancelable: false });
|
|
||||||
const previous = bucket.lastDateGroup?.intersetingAssets.at(0)?.asset;
|
|
||||||
if (previous) {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
previousBucketIndex--;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nextDaygroup.intersetingAssets.at(0)?.asset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async #getPreviousMonth(asset: AssetResponseDto, bucket: AssetBucket) {
|
|
||||||
const bucketIndex = this.buckets.indexOf(bucket);
|
|
||||||
const previousBucket = this.buckets[bucketIndex - 1];
|
|
||||||
if (previousBucket) {
|
|
||||||
await this.loadBucket(previousBucket.bucketDate, { cancelable: false });
|
|
||||||
return previousBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async #getPreviousYear(asset: AssetResponseDto, bucket: AssetBucket) {
|
|
||||||
const nextYear = DateTime.fromISO(asset.localDateTime).toUTC().get('year') + 1;
|
|
||||||
const bIdx = this.buckets.indexOf(bucket);
|
|
||||||
|
|
||||||
for (let idx = bIdx; idx >= 0; idx--) {
|
|
||||||
const otherBucket = this.buckets[idx];
|
|
||||||
const otherBucketYear = DateTime.fromISO(otherBucket.bucketDate).toUTC().get('year');
|
|
||||||
if (otherBucketYear >= nextYear) {
|
|
||||||
await this.loadBucket(otherBucket.bucketDate, { cancelable: false });
|
|
||||||
return otherBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async #getPreviousAsset(asset: AssetResponseDto, bucket: AssetBucket) {
|
|
||||||
// Find which date group contains this asset
|
|
||||||
for (let groupIndex = 0; groupIndex < bucket.dateGroups.length; groupIndex++) {
|
|
||||||
const group = bucket.dateGroups[groupIndex];
|
|
||||||
const assetIndex = group.intersetingAssets.findIndex((ia) => ia.id === asset.id);
|
|
||||||
|
|
||||||
if (assetIndex !== -1) {
|
|
||||||
// If not the first asset in this group, return the previous one
|
|
||||||
if (assetIndex > 0) {
|
|
||||||
return group.intersetingAssets[assetIndex - 1].asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are previous date groups in this bucket, check the previous one
|
|
||||||
if (groupIndex > 0) {
|
|
||||||
const prevGroup = bucket.dateGroups[groupIndex - 1];
|
|
||||||
return prevGroup.intersetingAssets.at(-1)?.asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we need to look in the previous bucket
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let bucketIndex = this.buckets.indexOf(bucket) - 1;
|
|
||||||
while (bucketIndex >= 0) {
|
|
||||||
bucket = this.buckets[bucketIndex];
|
|
||||||
if (!bucket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.loadBucket(bucket.bucketDate);
|
|
||||||
const previous = bucket.lastDateGroup?.intersetingAssets.at(-1)?.asset;
|
|
||||||
if (previous) {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
bucketIndex--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getClosestAssetToDate(date: DateTime) {
|
async getClosestAssetToDate(date: DateTime) {
|
||||||
@ -1457,92 +1354,110 @@ export class AssetStore {
|
|||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bucketIndex = this.buckets.indexOf(bucket) + 1;
|
const startIndex = this.buckets.indexOf(bucket);
|
||||||
while (bucketIndex < this.buckets.length) {
|
for (let currentIndex = startIndex + 1; currentIndex < this.buckets.length; currentIndex++) {
|
||||||
bucket = this.buckets[bucketIndex];
|
bucket = this.buckets[currentIndex];
|
||||||
await this.loadBucket(bucket.bucketDate);
|
await this.loadBucket(bucket.bucketDate);
|
||||||
const next = bucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
const next = bucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
||||||
if (next) {
|
if (next) {
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
bucketIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNextAsset(
|
async #getAssetWithOffset(
|
||||||
idable: { id: string },
|
assetDescriptor: AssetDescriptor,
|
||||||
skipTo: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
magnitude: 'asset' | 'day' | 'month' | 'year' = 'asset',
|
||||||
|
direction: Direction,
|
||||||
): Promise<AssetResponseDto | undefined> {
|
): Promise<AssetResponseDto | undefined> {
|
||||||
const bucket = this.#findBucketForAsset(idable.id);
|
const bucket = this.#findBucketForAsset(assetDescriptor.id);
|
||||||
if (!bucket) {
|
if (!bucket) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const asset = bucket.findById(idable.id);
|
const asset = bucket.findAssetById(assetDescriptor);
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
switch (magnitude) {
|
||||||
switch (skipTo) {
|
|
||||||
case 'day': {
|
case 'day': {
|
||||||
return this.#getNextDay(asset, bucket);
|
return this.#getAssetByDayOffset(asset, bucket, direction);
|
||||||
}
|
}
|
||||||
case 'month': {
|
case 'month': {
|
||||||
return this.#getNextMonth(asset, bucket);
|
return this.#getAssetByMonthOffset(asset, bucket, direction);
|
||||||
}
|
}
|
||||||
case 'year': {
|
case 'year': {
|
||||||
return this.#getNextYear(asset, bucket);
|
return this.#getAssetByYearOffset(asset, bucket, direction);
|
||||||
}
|
}
|
||||||
case 'asset': {
|
case 'asset': {
|
||||||
return this.#getNextAsset(asset, bucket);
|
return this.#getAssetByAssetOffset(asset, bucket, direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getNextDay(asset: AssetResponseDto, bucket: AssetBucket) {
|
async #getAssetByDayOffset(asset: AssetResponseDto, bucket: AssetBucket, direction: Direction) {
|
||||||
let prevDay = DateTime.fromISO(asset.localDateTime).toUTC().get('day') - 1;
|
const currentDate = DateTime.fromISO(asset.localDateTime).toUTC();
|
||||||
const bucketIndex = this.buckets.indexOf(bucket);
|
const targetDate =
|
||||||
|
direction === 'forward'
|
||||||
|
? currentDate.plus({ days: 1 }) // Moving forward in time (previous in UI)
|
||||||
|
: currentDate.minus({ days: 1 }); // Moving backward in time (next in UI)
|
||||||
|
|
||||||
let prevDayGroup;
|
// If the target day is in the same month/bucket
|
||||||
while (prevDay >= 0) {
|
if (targetDate.month === currentDate.month && targetDate.year === currentDate.year) {
|
||||||
prevDayGroup = bucket.findDateGroupByDay(prevDay);
|
const targetDayGroup = bucket.findDateGroupByDay(targetDate.day);
|
||||||
if (prevDayGroup) {
|
if (targetDayGroup) {
|
||||||
break;
|
return targetDayGroup.intersetingAssets.at(0)?.asset;
|
||||||
}
|
}
|
||||||
prevDay--;
|
|
||||||
}
|
}
|
||||||
if (prevDayGroup === undefined) {
|
|
||||||
let nextBucketIndex = bucketIndex + 1;
|
// Need to look through other buckets
|
||||||
while (nextBucketIndex < this.buckets.length) {
|
const startIndex = this.buckets.indexOf(bucket);
|
||||||
const otherBucket = this.buckets[nextBucketIndex];
|
const endCondition = (currentIndex: number) =>
|
||||||
await this.loadBucket(otherBucket.bucketDate, { cancelable: false });
|
direction === 'forward' ? currentIndex >= 0 : currentIndex < this.buckets.length;
|
||||||
const next = otherBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
const increment = direction === 'forward' ? -1 : 1; // -1 for newer buckets, +1 for older buckets
|
||||||
if (next) {
|
|
||||||
return next;
|
for (let currentIndex = startIndex + increment; endCondition(currentIndex); currentIndex += increment) {
|
||||||
}
|
const targetBucket = this.buckets[currentIndex];
|
||||||
nextBucketIndex++;
|
await this.loadBucket(targetBucket.bucketDate, { cancelable: false });
|
||||||
|
if (targetBucket.dateGroups.length > 0) {
|
||||||
|
return targetBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return prevDayGroup.intersetingAssets.at(0)?.asset;
|
|
||||||
}
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getNextMonth(asset: AssetResponseDto, bucket: AssetBucket) {
|
async #getAssetByMonthOffset(asset: AssetResponseDto, bucket: AssetBucket, direction: Direction) {
|
||||||
const bucketIndex = this.buckets.indexOf(bucket);
|
const bucketIndex = this.buckets.indexOf(bucket);
|
||||||
const nextMonthBucketIndex = this.buckets[bucketIndex + 1];
|
const targetBucketIndex = bucketIndex + (direction === 'forward' ? -1 : 1);
|
||||||
if (nextMonthBucketIndex) {
|
const targetBucket = this.buckets[targetBucketIndex];
|
||||||
await this.loadBucket(nextMonthBucketIndex.bucketDate, { cancelable: false });
|
|
||||||
return nextMonthBucketIndex.dateGroups[0]?.intersetingAssets[0]?.asset;
|
if (targetBucket) {
|
||||||
|
await this.loadBucket(targetBucket.bucketDate, { cancelable: false });
|
||||||
|
return targetBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getNextYear(asset: AssetResponseDto, bucket: AssetBucket) {
|
async #getAssetByYearOffset(asset: AssetResponseDto, bucket: AssetBucket, direction: Direction) {
|
||||||
const prevYear = DateTime.fromISO(asset.localDateTime).toUTC().get('year') - 1;
|
const currentDate = DateTime.fromISO(asset.localDateTime).toUTC();
|
||||||
|
const targetYear = currentDate.get('year') + (direction === 'forward' ? 1 : -1);
|
||||||
const bucketIndex = this.buckets.indexOf(bucket);
|
const bucketIndex = this.buckets.indexOf(bucket);
|
||||||
for (let idx = bucketIndex; idx < this.buckets.length - 1; idx++) {
|
|
||||||
const otherBucket = this.buckets[idx];
|
// Define search range based on direction
|
||||||
|
const startIndex = bucketIndex;
|
||||||
|
const endCondition = (currentIndex: number) =>
|
||||||
|
direction === 'forward' ? currentIndex >= 0 : currentIndex < this.buckets.length - 1;
|
||||||
|
const increment = direction === 'forward' ? -1 : 1;
|
||||||
|
|
||||||
|
for (let currentIndex = startIndex; endCondition(currentIndex); currentIndex += increment) {
|
||||||
|
const otherBucket = this.buckets[currentIndex];
|
||||||
const otherBucketYear = DateTime.fromISO(otherBucket.bucketDate).toUTC().get('year');
|
const otherBucketYear = DateTime.fromISO(otherBucket.bucketDate).toUTC().get('year');
|
||||||
if (otherBucketYear <= prevYear) {
|
|
||||||
|
const yearCondition =
|
||||||
|
direction === 'forward'
|
||||||
|
? otherBucketYear >= targetYear // Looking for newer years
|
||||||
|
: otherBucketYear <= targetYear; // Looking for older years
|
||||||
|
|
||||||
|
if (yearCondition) {
|
||||||
await this.loadBucket(otherBucket.bucketDate, { cancelable: false });
|
await this.loadBucket(otherBucket.bucketDate, { cancelable: false });
|
||||||
return otherBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
return otherBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
||||||
}
|
}
|
||||||
@ -1550,38 +1465,51 @@ export class AssetStore {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getNextAsset(asset: AssetResponseDto, bucket: AssetBucket) {
|
async #getAssetByAssetOffset(asset: AssetResponseDto, bucket: AssetBucket, direction: Direction) {
|
||||||
// Find which date group contains this asset
|
// Find which date group contains this asset
|
||||||
for (let groupIndex = 0; groupIndex < bucket.dateGroups.length; groupIndex++) {
|
for (let groupIndex = 0; groupIndex < bucket.dateGroups.length; groupIndex++) {
|
||||||
const group = bucket.dateGroups[groupIndex];
|
const group = bucket.dateGroups[groupIndex];
|
||||||
const assetIndex = group.intersetingAssets.findIndex((ia) => ia.id === asset.id);
|
const assetIndex = group.intersetingAssets.findIndex((intersectingAsset) => intersectingAsset.id === asset.id);
|
||||||
|
|
||||||
if (assetIndex !== -1) {
|
if (assetIndex !== -1) {
|
||||||
// If not the last asset in this group, return the next one
|
// If not at the boundary of the group, return the next/previous asset in this group
|
||||||
if (assetIndex < group.intersetingAssets.length - 1) {
|
const nextIndex = direction === 'forward' ? assetIndex - 1 : assetIndex + 1;
|
||||||
return group.intersetingAssets[assetIndex + 1].asset;
|
if (direction === 'forward' ? assetIndex > 0 : assetIndex < group.intersetingAssets.length - 1) {
|
||||||
|
return group.intersetingAssets[nextIndex].asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are more date groups in this bucket, check the next one
|
// If there are more date groups in this bucket, check the next/previous one
|
||||||
if (groupIndex < bucket.dateGroups.length - 1) {
|
const nextGroupIndex = direction === 'forward' ? groupIndex - 1 : groupIndex + 1;
|
||||||
return bucket.dateGroups[groupIndex + 1].intersetingAssets[0]?.asset;
|
if (direction === 'forward' ? groupIndex > 0 : groupIndex < bucket.dateGroups.length - 1) {
|
||||||
|
const adjacentGroup = bucket.dateGroups[nextGroupIndex];
|
||||||
|
return direction === 'forward'
|
||||||
|
? adjacentGroup.intersetingAssets.at(-1)?.asset
|
||||||
|
: adjacentGroup.intersetingAssets[0]?.asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we need to look in the next bucket
|
// Otherwise, we need to look in the adjacent bucket
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let bucketIndex = this.buckets.indexOf(bucket) + 1;
|
// Look through adjacent buckets until we find one with assets
|
||||||
while (bucketIndex < this.buckets.length) {
|
const startIndex = this.buckets.indexOf(bucket);
|
||||||
bucket = this.buckets[bucketIndex];
|
const endCondition = (currentIndex: number) =>
|
||||||
await this.loadBucket(bucket.bucketDate);
|
direction === 'forward' ? currentIndex >= 0 : currentIndex < this.buckets.length;
|
||||||
const next = bucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
const increment = direction === 'forward' ? -1 : 1;
|
||||||
if (next) {
|
|
||||||
return next;
|
for (let currentIndex = startIndex + increment; endCondition(currentIndex); currentIndex += increment) {
|
||||||
|
const adjacentBucket = this.buckets[currentIndex];
|
||||||
|
await this.loadBucket(adjacentBucket.bucketDate);
|
||||||
|
|
||||||
|
if (adjacentBucket.dateGroups.length > 0) {
|
||||||
|
return direction === 'forward'
|
||||||
|
? adjacentBucket.lastDateGroup?.intersetingAssets.at(-1)?.asset
|
||||||
|
: adjacentBucket.dateGroups[0]?.intersetingAssets[0]?.asset;
|
||||||
}
|
}
|
||||||
bucketIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
isExcluded(asset: AssetResponseDto) {
|
isExcluded(asset: AssetResponseDto) {
|
||||||
|
@ -12,7 +12,7 @@ export const setDefaultTabbleOptions = (options: TabbableOpts) => {
|
|||||||
export const getTabbable = (container: Element, includeContainer: boolean = false) =>
|
export const getTabbable = (container: Element, includeContainer: boolean = false) =>
|
||||||
tabbable(container, { ...defaultOpts, includeContainer });
|
tabbable(container, { ...defaultOpts, includeContainer });
|
||||||
|
|
||||||
export const moveFocus = (selector: (element: HTMLElement | SVGElement) => boolean, forwardDirection: boolean) => {
|
export const moveFocus = (selector: (element: HTMLElement | SVGElement) => boolean, direction: 'previous' | 'next') => {
|
||||||
const focusElements = focusable(document.body, { includeContainer: true });
|
const focusElements = focusable(document.body, { includeContainer: true });
|
||||||
const current = document.activeElement as HTMLElement;
|
const current = document.activeElement as HTMLElement;
|
||||||
const index = focusElements.indexOf(current);
|
const index = focusElements.indexOf(current);
|
||||||
@ -29,7 +29,7 @@ export const moveFocus = (selector: (element: HTMLElement | SVGElement) => boole
|
|||||||
const totalElements = focusElements.length;
|
const totalElements = focusElements.length;
|
||||||
let i = index;
|
let i = index;
|
||||||
do {
|
do {
|
||||||
i = (i + (forwardDirection ? 1 : -1) + totalElements) % totalElements;
|
i = (i + (direction === 'next' ? 1 : -1) + totalElements) % totalElements;
|
||||||
const next = focusElements[i];
|
const next = focusElements[i];
|
||||||
if (isTabbable(next) && selector(next)) {
|
if (isTabbable(next) && selector(next)) {
|
||||||
next.focus();
|
next.focus();
|
||||||
|
@ -1,25 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Tracks the state of asynchronous invocations to handle race conditions and stale operations.
|
||||||
|
* This class helps manage concurrent operations by tracking which invocations are active
|
||||||
|
* and allowing operations to check if they're still valid.
|
||||||
|
*/
|
||||||
export class InvocationTracker {
|
export class InvocationTracker {
|
||||||
|
/** Counter for the number of invocations that have been started */
|
||||||
invocationsStarted = 0;
|
invocationsStarted = 0;
|
||||||
|
/** Counter for the number of invocations that have been completed */
|
||||||
invocationsEnded = 0;
|
invocationsEnded = 0;
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new invocation and returns an object with utilities to manage the invocation lifecycle.
|
||||||
|
* @returns {Object} An object containing methods to manage the invocation:
|
||||||
|
* - isInvalidInvocationError: Checks if an error is an invalid invocation error
|
||||||
|
* - checkStillValid: Throws an error if the invocation is no longer valid
|
||||||
|
* - endInvocation: Marks the invocation as complete
|
||||||
|
*/
|
||||||
startInvocation() {
|
startInvocation() {
|
||||||
this.invocationsStarted++;
|
this.invocationsStarted++;
|
||||||
const invocation = this.invocationsStarted;
|
const invocation = this.invocationsStarted;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
/**
|
||||||
|
* Checks if an error is an invalid invocation error
|
||||||
|
* @param {unknown} error - The error to check
|
||||||
|
* @returns {boolean} True if the error is an invalid invocation error
|
||||||
|
*/
|
||||||
isInvalidInvocationError(error: unknown) {
|
isInvalidInvocationError(error: unknown) {
|
||||||
return error instanceof Error && error.message === 'Invocation not valid';
|
return error instanceof Error && error.message === 'Invocation not valid';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an error if this invocation is no longer valid
|
||||||
|
* @throws {Error} If the invocation is no longer valid
|
||||||
|
*/
|
||||||
checkStillValid: () => {
|
checkStillValid: () => {
|
||||||
if (invocation !== this.invocationsStarted) {
|
if (invocation !== this.invocationsStarted) {
|
||||||
throw new Error('Invocation not valid');
|
throw new Error('Invocation not valid');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks this invocation as complete
|
||||||
|
*/
|
||||||
endInvocation: () => {
|
endInvocation: () => {
|
||||||
this.invocationsEnded = invocation;
|
this.invocationsEnded = invocation;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there are any active invocations
|
||||||
|
* @returns {boolean} True if there are active invocations, false otherwise
|
||||||
|
*/
|
||||||
isActive() {
|
isActive() {
|
||||||
return this.invocationsStarted !== this.invocationsEnded;
|
return this.invocationsStarted !== this.invocationsEnded;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user