From 265996d230f4727d1f58c3e75cdc847ddac6497b Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:21:56 +1000 Subject: [PATCH 1/4] feat(ui): memoize ImageContextMenu selector Without the selector itself being memoized, the gallery was rerendering on every progress image. --- .../gallery/components/ImageContextMenu.tsx | 75 +++++++++---------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx index 1e5f95ab0d..64b1d349d8 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu.tsx @@ -1,49 +1,32 @@ -import { MenuItem, MenuList } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { memo, useCallback, useContext } from 'react'; -import { - FaExpand, - FaFolder, - FaFolderPlus, - FaShare, - FaTrash, -} from 'react-icons/fa'; -import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu'; -import { - resizeAndScaleCanvas, - setInitialCanvasImage, -} from 'features/canvas/store/canvasSlice'; -import { setActiveTab } from 'features/ui/store/uiSlice'; -import { useTranslation } from 'react-i18next'; import { ExternalLinkIcon } from '@chakra-ui/icons'; -import { IoArrowUndoCircleOutline } from 'react-icons/io5'; +import { MenuItem, MenuList } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; -import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters'; -import { initialImageSelected } from 'features/parameters/store/actions'; -import { sentImageToCanvas, sentImageToImg2Img } from '../store/actions'; import { useAppToaster } from 'app/components/Toaster'; -import { AddImageToBoardContext } from '../../../app/contexts/AddImageToBoardContext'; -import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages'; -import { ImageDTO } from 'services/api/types'; -import { RootState, stateSelector } from 'app/store/store'; +import { stateSelector } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu'; import { imagesAddedToBatch, selectionAddedToBatch, } from 'features/batch/store/batchSlice'; -import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { + resizeAndScaleCanvas, + setInitialCanvasImage, +} from 'features/canvas/store/canvasSlice'; import { imageToDeleteSelected } from 'features/imageDeletion/store/imageDeletionSlice'; - -const selector = createSelector( - [stateSelector, (state: RootState, imageDTO: ImageDTO) => imageDTO], - ({ gallery, batch }, imageDTO) => { - const selectionCount = gallery.selection.length; - const isInBatch = batch.imageNames.includes(imageDTO.image_name); - - return { selectionCount, isInBatch }; - }, - defaultSelectorOptions -); +import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters'; +import { initialImageSelected } from 'features/parameters/store/actions'; +import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; +import { setActiveTab } from 'features/ui/store/uiSlice'; +import { memo, useCallback, useContext, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { FaExpand, FaFolder, FaShare, FaTrash } from 'react-icons/fa'; +import { IoArrowUndoCircleOutline } from 'react-icons/io5'; +import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages'; +import { ImageDTO } from 'services/api/types'; +import { AddImageToBoardContext } from '../../../app/contexts/AddImageToBoardContext'; +import { sentImageToCanvas, sentImageToImg2Img } from '../store/actions'; type Props = { image: ImageDTO; @@ -51,9 +34,21 @@ type Props = { }; const ImageContextMenu = ({ image, children }: Props) => { - const { selectionCount, isInBatch } = useAppSelector((state) => - selector(state, image) + const selector = useMemo( + () => + createSelector( + [stateSelector], + ({ gallery, batch }) => { + const selectionCount = gallery.selection.length; + const isInBatch = batch.imageNames.includes(image.image_name); + + return { selectionCount, isInBatch }; + }, + defaultSelectorOptions + ), + [image.image_name] ); + const { selectionCount, isInBatch } = useAppSelector(selector); const dispatch = useAppDispatch(); const { t } = useTranslation(); From a7b8109ac28d13bfc62d0246b2c07f139dc95358 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:22:34 +1000 Subject: [PATCH 2/4] feat(ui): memoize NextPrevImageButtons component This was rerendering on every progress image, now it doesn't --- .../src/features/gallery/components/NextPrevImageButtons.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx index 4177db9a1b..3fcdd54cc9 100644 --- a/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx @@ -8,7 +8,7 @@ import { selectImagesById, } from 'features/gallery/store/gallerySlice'; import { clamp, isEqual } from 'lodash-es'; -import { useCallback, useState } from 'react'; +import { memo, useCallback, useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { FaAngleDoubleRight, FaAngleLeft, FaAngleRight } from 'react-icons/fa'; @@ -227,4 +227,4 @@ const NextPrevImageButtons = () => { ); }; -export default NextPrevImageButtons; +export default memo(NextPrevImageButtons); From 1c45d18e6d1065dc875e98a6e510ddc51d098a4c Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:23:13 +1000 Subject: [PATCH 3/4] fix(ui): correctly set disabled on invoke button during generation It wasn't disabled when it should have been, looked clickable during generation. --- .../parameters/components/ProcessButtons/InvokeButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx index e2338e2575..2e399647d8 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx @@ -78,7 +78,7 @@ export default function InvokeButton(props: InvokeButton) { aria-label={t('parameters.invoke')} type="submit" icon={} - isDisabled={!isReady} + isDisabled={!isReady || isProcessing} onClick={handleInvoke} tooltip={t('parameters.invoke')} tooltipProps={{ placement: 'top' }} @@ -95,7 +95,7 @@ export default function InvokeButton(props: InvokeButton) { Date: Mon, 10 Jul 2023 11:30:35 +1000 Subject: [PATCH 4/4] fix(nodes): remove `board_id` column from `images` table This is extraneous; the `board_images` table holds image-board relationships. --- invokeai/app/services/image_record_storage.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/invokeai/app/services/image_record_storage.py b/invokeai/app/services/image_record_storage.py index 5e5996ae76..014006eb7a 100644 --- a/invokeai/app/services/image_record_storage.py +++ b/invokeai/app/services/image_record_storage.py @@ -1,22 +1,16 @@ +import sqlite3 +import threading from abc import ABC, abstractmethod from datetime import datetime from typing import Generic, Optional, TypeVar, cast -import sqlite3 -import threading from pydantic import BaseModel, Field from pydantic.generics import GenericModel +from invokeai.app.models.image import ImageCategory, ResourceOrigin from invokeai.app.models.metadata import ImageMetadata -from invokeai.app.models.image import ( - ImageCategory, - ResourceOrigin, -) from invokeai.app.services.models.image_record import ( - ImageRecord, - ImageRecordChanges, - deserialize_image_record, -) + ImageRecord, ImageRecordChanges, deserialize_image_record) T = TypeVar("T", bound=BaseModel) @@ -162,7 +156,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase): node_id TEXT, metadata TEXT, is_intermediate BOOLEAN DEFAULT FALSE, - board_id TEXT, created_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), -- Updated via trigger updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),