refactor: remove unused methods/routes, fix some gallery invalidation issues

This commit is contained in:
psychedelicious
2025-06-25 13:44:57 +10:00
parent 98368b0665
commit b2b42be51c
22 changed files with 139 additions and 657 deletions

View File

@@ -10,7 +10,6 @@ import {
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import type { CanvasState, RefImagesState } from 'features/controlLayers/store/types';
import type { ImageUsage } from 'features/deleteImageModal/store/types';
import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
import { imageSelected } from 'features/gallery/store/gallerySlice';
import { fieldImageCollectionValueChanged, fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
import { selectNodesSlice } from 'features/nodes/store/selectors';
@@ -81,14 +80,8 @@ const handleDeletions = async (image_names: string[], dispatch: AppDispatch, get
await dispatch(imagesApi.endpoints.deleteImages.initiate({ image_names }, { track: false })).unwrap();
if (intersection(state.gallery.selection, image_names).length > 0) {
// Some selected images were deleted, need to select the next image
const queryArgs = selectListImagesQueryArgs(state);
const { data } = imagesApi.endpoints.listImages.select(queryArgs)(state);
if (data) {
// When we delete multiple images, we clear the selection. Then, the the next time we load images, we will
// select the first one. This is handled below in the listener for `imagesApi.endpoints.listImages.matchFulfilled`.
dispatch(imageSelected(null));
}
// Some selected images were deleted, clear selection
dispatch(imageSelected(null));
}
// We need to reset the features where the image is in use - none of these work if their image(s) don't exist

View File

@@ -5,6 +5,7 @@ import { CanvasAlertsInvocationProgress } from 'features/controlLayers/component
import { DndImage } from 'features/dnd/DndImage';
import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer/ImageMetadataViewer';
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
import { selectAutoSwitch } from 'features/gallery/store/gallerySelectors';
import type { ProgressImage as ProgressImageType } from 'features/nodes/types/common';
import { selectShouldShowImageDetails, selectShouldShowProgressInViewer } from 'features/ui/store/uiSelectors';
import type { AnimationProps } from 'framer-motion';
@@ -21,6 +22,7 @@ import { ProgressIndicator } from './ProgressIndicator2';
export const CurrentImagePreview = memo(({ imageDTO }: { imageDTO: ImageDTO | null }) => {
const shouldShowImageDetails = useAppSelector(selectShouldShowImageDetails);
const shouldShowProgressInViewer = useAppSelector(selectShouldShowProgressInViewer);
const autoSwitch = useAppSelector(selectAutoSwitch);
const socket = useStore($socket);
const [progressEvent, setProgressEvent] = useState<S['InvocationProgressEvent'] | null>(null);
@@ -58,6 +60,29 @@ export const CurrentImagePreview = memo(({ imageDTO }: { imageDTO: ImageDTO | nu
};
}, [socket]);
useEffect(() => {
if (!socket) {
return;
}
if (autoSwitch) {
return;
}
// When auto-switch is enabled, we will get a load event as we switch to the new image. This in turn clears the progress image,
// creating the illusion of the progress image turning into the new image.
// But when auto-switch is disabled, we won't get that load event, so we need to clear the progress image manually.
const onQueueItemStatusChanged = () => {
setProgressEvent(null);
setProgressImage(null);
};
socket.on('queue_item_status_changed', onQueueItemStatusChanged);
return () => {
socket.off('queue_item_status_changed', onQueueItemStatusChanged);
};
}, [autoSwitch, socket]);
const onLoadImage = useCallback(() => {
if (!progressEvent || !imageDTO) {
return;

View File

@@ -4,10 +4,11 @@ import { logger } from 'app/logging/logger';
import { EMPTY_ARRAY } from 'app/store/constants';
import { useAppSelector, useAppStore } from 'app/store/storeHooks';
import {
LIMIT,
selectGalleryImageMinimumWidth,
selectImageToCompare,
selectLastSelectedImage,
selectListImagesQueryArgs,
selectListImageNamesQueryArgs,
} from 'features/gallery/store/gallerySelectors';
import { imageToCompareChanged, selectionChanged } from 'features/gallery/store/gallerySlice';
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
@@ -37,31 +38,26 @@ const SCROLL_SEEK_VELOCITY_THRESHOLD = 4096;
const DEBOUNCE_DELAY = 500;
const SPINNER_OPACITY = 0.3;
type ListImagesQueryArgs = ReturnType<typeof selectListImagesQueryArgs>;
type ListImageNamesQueryArgs = ReturnType<typeof selectListImageNamesQueryArgs>;
type GridContext = {
queryArgs: ListImagesQueryArgs;
queryArgs: ListImageNamesQueryArgs;
imageNames: string[];
};
export const useDebouncedListImagesQueryArgs = () => {
const _galleryQueryArgs = useAppSelector(selectListImagesQueryArgs);
const [queryArgs] = useDebounce(_galleryQueryArgs, DEBOUNCE_DELAY);
return queryArgs;
};
// Hook to get an image DTO from cache or trigger loading
const useImageDTOFromListQuery = (
index: number,
imageName: string,
queryArgs: ListImagesQueryArgs
queryArgs: ListImageNamesQueryArgs
): ImageDTO | null => {
const { arg, options } = useMemo(() => {
const pageOffset = Math.floor(index / queryArgs.limit) * queryArgs.limit;
const pageOffset = Math.floor(index / LIMIT) * LIMIT;
return {
arg: {
...queryArgs,
offset: pageOffset,
limit: LIMIT,
} satisfies Parameters<typeof useListImagesQuery>[0],
options: {
selectFromResult: ({ data }) => {
@@ -82,7 +78,7 @@ const useImageDTOFromListQuery = (
// Individual image component that gets its data from RTK Query cache
const ImageAtPosition = memo(
({ index, queryArgs, imageName }: { index: number; imageName: string; queryArgs: ListImagesQueryArgs }) => {
({ index, queryArgs, imageName }: { index: number; imageName: string; queryArgs: ListImageNamesQueryArgs }) => {
const imageDTO = useImageDTOFromListQuery(index, imageName, queryArgs);
if (!imageDTO) {
@@ -408,7 +404,8 @@ const getImageNamesQueryOptions = {
} satisfies Parameters<typeof useGetImageNamesQuery>[1];
export const useGalleryImageNames = () => {
const queryArgs = useDebouncedListImagesQueryArgs();
const _queryArgs = useAppSelector(selectListImageNamesQueryArgs);
const [queryArgs] = useDebounce(_queryArgs, DEBOUNCE_DELAY);
const { imageNames, isLoading, isFetching } = useGetImageNamesQuery(queryArgs, getImageNamesQueryOptions);
return { imageNames, isLoading, isFetching, queryArgs };
};

View File

@@ -2,8 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types';
import type { ListBoardsArgs, ListImagesArgs } from 'services/api/types';
import type { SetNonNullable } from 'type-fest';
import type { ListBoardsArgs } from 'services/api/types';
export const selectFirstSelectedImage = createSelector(selectGallerySlice, (gallery) => gallery.selection.at(0));
export const selectLastSelectedImage = createSelector(selectGallerySlice, (gallery) => gallery.selection.at(-1));
@@ -28,7 +27,7 @@ export const selectGallerySearchTerm = createSelector(selectGallerySlice, (galle
export const selectGalleryOrderDir = createSelector(selectGallerySlice, (gallery) => gallery.orderDir);
export const selectGalleryStarredFirst = createSelector(selectGallerySlice, (gallery) => gallery.starredFirst);
export const selectListImagesQueryArgs = createMemoizedSelector(
export const selectListImageNamesQueryArgs = createMemoizedSelector(
[
selectSelectedBoardId,
selectGalleryQueryCategories,
@@ -36,17 +35,20 @@ export const selectListImagesQueryArgs = createMemoizedSelector(
selectGalleryOrderDir,
selectGalleryStarredFirst,
],
(board_id, categories, search_term, order_dir, starred_first) =>
({
board_id,
categories,
search_term,
order_dir,
starred_first,
is_intermediate: false, // We don't show intermediate images in the gallery
limit: 100, // Page size is _always_ 100
}) satisfies SetNonNullable<ListImagesArgs, 'limit'>
(board_id, categories, search_term, order_dir, starred_first) => ({
board_id,
categories,
search_term,
order_dir,
starred_first,
is_intermediate: false,
})
);
export const LIMIT = 100;
export const selectListImagesBaseQueryArgs = createMemoizedSelector(selectListImageNamesQueryArgs, (baseQueryArgs) => ({
...baseQueryArgs,
limit: LIMIT,
}));
export const selectAutoAssignBoardOnClick = createSelector(
selectGallerySlice,
(gallery) => gallery.autoAssignBoardOnClick