Files
InvokeAI/invokeai/frontend/web/src/services/api/util/optimisticUpdates.ts
2025-06-26 20:00:39 +10:00

91 lines
2.7 KiB
TypeScript

import type { ImageDTO, ImageNamesResult } from 'services/api/types';
/**
* Calculates the optimal insertion position for a new image in the names list.
* For starred_first=true: starred images go to position 0, unstarred go after all starred images
* For starred_first=false: all new images go to position 0 (newest first)
*/
export function calculateImageInsertionPosition(
imageDTO: ImageDTO,
starredFirst: boolean,
starredCount: number
): number {
if (!starredFirst) {
// When starred_first is false, always insert at the beginning (newest first)
return 0;
}
// When starred_first is true
if (imageDTO.starred) {
// Starred images go at the very beginning
return 0;
}
// Unstarred images go after all starred images
return starredCount;
}
/**
* Optimistically inserts a new image into the ImageNamesResult at the correct position
*/
export function insertImageIntoNamesResult(
currentResult: ImageNamesResult,
imageDTO: ImageDTO,
starredFirst: boolean
): ImageNamesResult {
// Don't insert if the image is already in the list
if (currentResult.image_names.includes(imageDTO.image_name)) {
return currentResult;
}
const insertPosition = calculateImageInsertionPosition(imageDTO, starredFirst, currentResult.starred_count);
const newImageNames = [...currentResult.image_names];
newImageNames.splice(insertPosition, 0, imageDTO.image_name);
return {
image_names: newImageNames,
starred_count: starredFirst && imageDTO.starred ? currentResult.starred_count + 1 : currentResult.starred_count,
total_count: currentResult.total_count + 1,
};
}
/**
* Optimistically removes an image from the ImageNamesResult
*/
export function removeImageFromNamesResult(
currentResult: ImageNamesResult,
imageNameToRemove: string,
wasStarred: boolean,
starredFirst: boolean
): ImageNamesResult {
const newImageNames = currentResult.image_names.filter((name) => name !== imageNameToRemove);
return {
image_names: newImageNames,
starred_count: starredFirst && wasStarred ? currentResult.starred_count - 1 : currentResult.starred_count,
total_count: currentResult.total_count - 1,
};
}
/**
* Optimistically updates an image's position in the result when its starred status changes
*/
export function updateImagePositionInNamesResult(
currentResult: ImageNamesResult,
updatedImageDTO: ImageDTO,
previouslyStarred: boolean,
starredFirst: boolean
): ImageNamesResult {
// First remove the image from its current position
const withoutImage = removeImageFromNamesResult(
currentResult,
updatedImageDTO.image_name,
previouslyStarred,
starredFirst
);
// Then insert it at the new correct position
return insertImageIntoNamesResult(withoutImage, updatedImageDTO, starredFirst);
}