feat(ui): wip update UI for migration

This commit is contained in:
psychedelicious 2023-05-22 22:21:57 +10:00 committed by Kent Keirsey
parent 4a7a5234df
commit 7a1de3887e
16 changed files with 89 additions and 81 deletions

View File

@ -1,12 +1,15 @@
import { initialImageChanged } from 'features/parameters/store/generationSlice'; import { initialImageChanged } from 'features/parameters/store/generationSlice';
import { Image, isInvokeAIImage } from 'app/types/invokeai';
import { selectResultsById } from 'features/gallery/store/resultsSlice'; import { selectResultsById } from 'features/gallery/store/resultsSlice';
import { selectUploadsById } from 'features/gallery/store/uploadsSlice'; import { selectUploadsById } from 'features/gallery/store/uploadsSlice';
import { t } from 'i18next'; import { t } from 'i18next';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { initialImageSelected } from 'features/parameters/store/actions'; import {
initialImageSelected,
isImageDTO,
} from 'features/parameters/store/actions';
import { makeToast } from 'app/components/Toaster'; import { makeToast } from 'app/components/Toaster';
import { ImageDTO } from 'services/api';
export const addInitialImageSelectedListener = () => { export const addInitialImageSelectedListener = () => {
startAppListening({ startAppListening({
@ -21,21 +24,21 @@ export const addInitialImageSelectedListener = () => {
return; return;
} }
if (isInvokeAIImage(action.payload)) { if (isImageDTO(action.payload)) {
dispatch(initialImageChanged(action.payload)); dispatch(initialImageChanged(action.payload));
dispatch(addToast(makeToast(t('toast.sentToImageToImage')))); dispatch(addToast(makeToast(t('toast.sentToImageToImage'))));
return; return;
} }
const { name, type } = action.payload; const { image_name, image_type } = action.payload;
let image: Image | undefined; let image: ImageDTO | undefined;
const state = getState(); const state = getState();
if (type === 'results') { if (image_type === 'results') {
image = selectResultsById(state, name); image = selectResultsById(state, image_name);
} else if (type === 'uploads') { } else if (image_type === 'uploads') {
image = selectUploadsById(state, name); image = selectUploadsById(state, image_name);
} }
if (!image) { if (!image) {

View File

@ -1,15 +1,10 @@
import { invocationComplete } from 'services/events/actions'; import { invocationComplete } from 'services/events/actions';
import { isImageOutput } from 'services/types/guards'; import { isImageOutput } from 'services/types/guards';
import { import {
buildImageUrls, imageMetadataReceived,
extractTimestampFromImageName, imageUrlsReceived,
} from 'services/util/deserializeImageField'; } from 'services/thunks/image';
import { Image } from 'app/types/invokeai';
import { resultAdded } from 'features/gallery/store/resultsSlice';
import { imageMetadataReceived } from 'services/thunks/image';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { imageSelected } from 'features/gallery/store/gallerySlice';
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
const nodeDenylist = ['dataURL_image']; const nodeDenylist = ['dataURL_image'];
@ -33,20 +28,18 @@ export const addImageResultReceivedListener = () => {
const { result, node, graph_execution_state_id } = data; const { result, node, graph_execution_state_id } = data;
if (isImageOutput(result) && !nodeDenylist.includes(node.type)) { if (isImageOutput(result) && !nodeDenylist.includes(node.type)) {
const name = result.image.image_name; const { image_name, image_type } = result.image;
const type = result.image.image_type;
// dispatch(imageUrlsReceived({ imageName: name, imageType: type })); dispatch(
imageUrlsReceived({ imageName: image_name, imageType: image_type })
);
// const [{ payload }] = await take( dispatch(
// (action): action is ReturnType<typeof imageUrlsReceived.fulfilled> => imageMetadataReceived({
// imageUrlsReceived.fulfilled.match(action) && imageName: image_name,
// action.payload.image_name === name imageType: image_type,
// ); })
);
// console.log(payload);
dispatch(imageMetadataReceived({ imageName: name, imageType: type }));
// const [x] = await take( // const [x] = await take(
// ( // (

View File

@ -122,21 +122,21 @@ export type PostProcessedImageMetadata = ESRGANMetadata | FacetoolMetadata;
/** /**
* ResultImage * ResultImage
*/ */
export type Image = { // export ty`pe Image = {
name: string; // name: string;
type: ImageType; // type: ImageType;
url: string; // url: string;
thumbnail: string; // thumbnail: string;
metadata: ImageResponseMetadata; // metadata: ImageResponseMetadata;
}; // };
export const isInvokeAIImage = (obj: Image | SelectedImage): obj is Image => { // export const isInvokeAIImage = (obj: Image | SelectedImage): obj is Image => {
if ('url' in obj && 'thumbnail' in obj) { // if ('url' in obj && 'thumbnail' in obj) {
return true; // return true;
} // }
return false; // return false;
}; // };
/** /**
* Types related to the system status. * Types related to the system status.

View File

@ -1,5 +1,4 @@
import { Badge, Flex } from '@chakra-ui/react'; import { Badge, Flex } from '@chakra-ui/react';
import { Image } from 'app/types/invokeai';
import { isNumber, isString } from 'lodash-es'; import { isNumber, isString } from 'lodash-es';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ImageDTO } from 'services/api'; import { ImageDTO } from 'services/api';

View File

@ -1,6 +1,5 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import * as InvokeAI from 'app/types/invokeai';
import { import {
roundDownToMultiple, roundDownToMultiple,
roundToMultiple, roundToMultiple,
@ -29,6 +28,7 @@ import {
isCanvasBaseImage, isCanvasBaseImage,
isCanvasMaskLine, isCanvasMaskLine,
} from './canvasTypes'; } from './canvasTypes';
import { ImageDTO } from 'services/api';
export const initialLayerState: CanvasLayerState = { export const initialLayerState: CanvasLayerState = {
objects: [], objects: [],
@ -157,7 +157,7 @@ export const canvasSlice = createSlice({
setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => { setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => {
state.cursorPosition = action.payload; state.cursorPosition = action.payload;
}, },
setInitialCanvasImage: (state, action: PayloadAction<InvokeAI.Image>) => { setInitialCanvasImage: (state, action: PayloadAction<ImageDTO>) => {
const image = action.payload; const image = action.payload;
const { width, height } = image.metadata; const { width, height } = image.metadata;
const { stageDimensions } = state; const { stageDimensions } = state;
@ -302,7 +302,7 @@ export const canvasSlice = createSlice({
selectedImageIndex: -1, selectedImageIndex: -1,
}; };
}, },
addImageToStagingArea: (state, action: PayloadAction<InvokeAI.Image>) => { addImageToStagingArea: (state, action: PayloadAction<ImageDTO>) => {
const image = action.payload; const image = action.payload;
if (!image || !state.layerState.stagingArea.boundingBox) { if (!image || !state.layerState.stagingArea.boundingBox) {

View File

@ -1,6 +1,7 @@
import * as InvokeAI from 'app/types/invokeai'; import * as InvokeAI from 'app/types/invokeai';
import { IRect, Vector2d } from 'konva/lib/types'; import { IRect, Vector2d } from 'konva/lib/types';
import { RgbaColor } from 'react-colorful'; import { RgbaColor } from 'react-colorful';
import { ImageDTO } from 'services/api';
export const LAYER_NAMES_DICT = [ export const LAYER_NAMES_DICT = [
{ key: 'Base', value: 'base' }, { key: 'Base', value: 'base' },
@ -37,7 +38,7 @@ export type CanvasImage = {
y: number; y: number;
width: number; width: number;
height: number; height: number;
image: InvokeAI.Image; image: ImageDTO;
}; };
export type CanvasMaskLine = { export type CanvasMaskLine = {

View File

@ -12,7 +12,7 @@ import { memo, useCallback } from 'react';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import DeleteImageModal from '../DeleteImageModal'; import DeleteImageModal from '../DeleteImageModal';
import { requestedImageDeletion } from 'features/gallery/store/actions'; import { requestedImageDeletion } from 'features/gallery/store/actions';
import { Image } from 'app/types/invokeai'; import { ImageDTO } from 'services/api';
const selector = createSelector( const selector = createSelector(
[systemSelector], [systemSelector],
@ -30,7 +30,7 @@ const selector = createSelector(
); );
type DeleteImageButtonProps = { type DeleteImageButtonProps = {
image: Image | undefined; image: ImageDTO | undefined;
}; };
const DeleteImageButton = (props: DeleteImageButtonProps) => { const DeleteImageButton = (props: DeleteImageButtonProps) => {

View File

@ -5,7 +5,6 @@ import {
FlexProps, FlexProps,
Grid, Grid,
Icon, Icon,
Image,
Text, Text,
forwardRef, forwardRef,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@ -51,7 +50,6 @@ import { uploadsAdapter } from '../store/uploadsSlice';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { Virtuoso, VirtuosoGrid } from 'react-virtuoso'; import { Virtuoso, VirtuosoGrid } from 'react-virtuoso';
import { Image as ImageType } from 'app/types/invokeai';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import GalleryProgressImage from './GalleryProgressImage'; import GalleryProgressImage from './GalleryProgressImage';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';

View File

@ -1,9 +1,9 @@
import { createAction } from '@reduxjs/toolkit'; import { createAction } from '@reduxjs/toolkit';
import { Image } from 'app/types/invokeai'; import { ImageNameAndType } from 'features/parameters/store/actions';
import { SelectedImage } from 'features/parameters/store/actions'; import { ImageDTO } from 'services/api';
export const requestedImageDeletion = createAction< export const requestedImageDeletion = createAction<
Image | SelectedImage | undefined ImageDTO | ImageNameAndType | undefined
>('gallery/requestedImageDeletion'); >('gallery/requestedImageDeletion');
export const sentImageToCanvas = createAction('gallery/sentImageToCanvas'); export const sentImageToCanvas = createAction('gallery/sentImageToCanvas');

View File

@ -1,5 +1,4 @@
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'; import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
import { Image } from 'app/types/invokeai';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { import {
@ -7,7 +6,6 @@ import {
IMAGES_PER_PAGE, IMAGES_PER_PAGE,
} from 'services/thunks/gallery'; } from 'services/thunks/gallery';
import { imageDeleted, imageUrlsReceived } from 'services/thunks/image'; import { imageDeleted, imageUrlsReceived } from 'services/thunks/image';
import { deserializeImageResponse } from 'services/util/deserializeImageResponse';
import { ImageDTO } from 'services/api'; import { ImageDTO } from 'services/api';
import { dateComparator } from 'common/util/dateComparator'; import { dateComparator } from 'common/util/dateComparator';

View File

@ -1,10 +1,10 @@
import * as React from 'react'; import * as React from 'react';
import { TransformComponent, useTransformContext } from 'react-zoom-pan-pinch'; import { TransformComponent, useTransformContext } from 'react-zoom-pan-pinch';
import * as InvokeAI from 'app/types/invokeai';
import { useGetUrl } from 'common/util/getUrl'; import { useGetUrl } from 'common/util/getUrl';
import { ImageDTO } from 'services/api';
type ReactPanZoomProps = { type ReactPanZoomProps = {
image: InvokeAI.Image; image: ImageDTO;
styleClass?: string; styleClass?: string;
alt?: string; alt?: string;
ref?: React.Ref<HTMLImageElement>; ref?: React.Ref<HTMLImageElement>;
@ -37,7 +37,7 @@ export default function ReactPanZoomImage({
transform: `rotate(${rotation}deg) scaleX(${scaleX}) scaleY(${scaleY})`, transform: `rotate(${rotation}deg) scaleX(${scaleX}) scaleY(${scaleY})`,
width: '100%', width: '100%',
}} }}
src={getUrl(image.url)} src={getUrl(image.image_url)}
alt={alt} alt={alt}
ref={ref} ref={ref}
className={styleClass ? styleClass : ''} className={styleClass ? styleClass : ''}

View File

@ -7,9 +7,9 @@ import { allParametersSet, setSeed } from '../store/generationSlice';
import { isImageField } from 'services/types/guards'; import { isImageField } from 'services/types/guards';
import { NUMPY_RAND_MAX } from 'app/constants'; import { NUMPY_RAND_MAX } from 'app/constants';
import { initialImageSelected } from '../store/actions'; import { initialImageSelected } from '../store/actions';
import { Image } from 'app/types/invokeai';
import { setActiveTab } from 'features/ui/store/uiSlice'; import { setActiveTab } from 'features/ui/store/uiSlice';
import { useAppToaster } from 'app/components/Toaster'; import { useAppToaster } from 'app/components/Toaster';
import { ImageDTO } from 'services/api';
export const useParameters = () => { export const useParameters = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -88,9 +88,7 @@ export const useParameters = () => {
return; return;
} }
dispatch( dispatch(initialImageSelected(image));
initialImageSelected({ name: image.image_name, type: image.image_type })
);
toaster({ toaster({
title: t('toast.initialImageSet'), title: t('toast.initialImageSet'),
status: 'info', status: 'info',
@ -105,21 +103,21 @@ export const useParameters = () => {
* Sets image as initial image with toast * Sets image as initial image with toast
*/ */
const sendToImageToImage = useCallback( const sendToImageToImage = useCallback(
(image: Image) => { (image: ImageDTO) => {
dispatch(initialImageSelected({ name: image.name, type: image.type })); dispatch(initialImageSelected(image));
}, },
[dispatch] [dispatch]
); );
const recallAllParameters = useCallback( const recallAllParameters = useCallback(
(image: Image | undefined) => { (image: ImageDTO | undefined) => {
const type = image?.metadata?.invokeai?.node?.type; const type = image?.metadata?.type;
if (['txt2img', 'img2img', 'inpaint'].includes(String(type))) { if (['txt2img', 'img2img', 'inpaint'].includes(String(type))) {
dispatch(allParametersSet(image)); dispatch(allParametersSet(image));
if (image?.metadata?.invokeai?.node?.type === 'img2img') { if (image?.metadata?.type === 'img2img') {
dispatch(setActiveTab('img2img')); dispatch(setActiveTab('img2img'));
} else if (image?.metadata?.invokeai?.node?.type === 'txt2img') { } else if (image?.metadata?.type === 'txt2img') {
dispatch(setActiveTab('txt2img')); dispatch(setActiveTab('txt2img'));
} }

View File

@ -1,12 +1,31 @@
import { createAction } from '@reduxjs/toolkit'; import { createAction } from '@reduxjs/toolkit';
import { Image } from 'app/types/invokeai'; import { isObject } from 'lodash-es';
import { ImageType } from 'services/api'; import { ImageDTO, ImageType } from 'services/api';
export type SelectedImage = { export type ImageNameAndType = {
name: string; image_name: string;
type: ImageType; image_type: ImageType;
};
export const isImageDTO = (image: any): image is ImageDTO => {
return (
image &&
isObject(image) &&
'image_name' in image &&
image?.image_name !== undefined &&
'image_type' in image &&
image?.image_type !== undefined &&
'image_url' in image &&
image?.image_url !== undefined &&
'thumbnail_url' in image &&
image?.thumbnail_url !== undefined &&
'image_category' in image &&
image?.image_category !== undefined &&
'created_at' in image &&
image?.created_at !== undefined
);
}; };
export const initialImageSelected = createAction< export const initialImageSelected = createAction<
Image | SelectedImage | undefined ImageDTO | ImageNameAndType | undefined
>('generation/initialImageSelected'); >('generation/initialImageSelected');

View File

@ -6,13 +6,14 @@ import { clamp, sample } from 'lodash-es';
import { setAllParametersReducer } from './setAllParametersReducer'; import { setAllParametersReducer } from './setAllParametersReducer';
import { receivedModels } from 'services/thunks/model'; import { receivedModels } from 'services/thunks/model';
import { Scheduler } from 'app/constants'; import { Scheduler } from 'app/constants';
import { ImageDTO } from 'services/api';
export interface GenerationState { export interface GenerationState {
cfgScale: number; cfgScale: number;
height: number; height: number;
img2imgStrength: number; img2imgStrength: number;
infillMethod: string; infillMethod: string;
initialImage?: InvokeAI.Image; initialImage?: ImageDTO;
iterations: number; iterations: number;
perlin: number; perlin: number;
prompt: string; prompt: string;
@ -213,7 +214,7 @@ export const generationSlice = createSlice({
setShouldUseNoiseSettings: (state, action: PayloadAction<boolean>) => { setShouldUseNoiseSettings: (state, action: PayloadAction<boolean>) => {
state.shouldUseNoiseSettings = action.payload; state.shouldUseNoiseSettings = action.payload;
}, },
initialImageChanged: (state, action: PayloadAction<InvokeAI.Image>) => { initialImageChanged: (state, action: PayloadAction<ImageDTO>) => {
state.initialImage = action.payload; state.initialImage = action.payload;
}, },
modelSelected: (state, action: PayloadAction<string>) => { modelSelected: (state, action: PayloadAction<string>) => {

View File

@ -1,12 +1,11 @@
import { Draft, PayloadAction } from '@reduxjs/toolkit'; import { Draft, PayloadAction } from '@reduxjs/toolkit';
import { Image } from 'app/types/invokeai';
import { GenerationState } from './generationSlice'; import { GenerationState } from './generationSlice';
import { ImageToImageInvocation } from 'services/api'; import { ImageDTO, ImageToImageInvocation } from 'services/api';
import { isScheduler } from 'app/constants'; import { isScheduler } from 'app/constants';
export const setAllParametersReducer = ( export const setAllParametersReducer = (
state: Draft<GenerationState>, state: Draft<GenerationState>,
action: PayloadAction<Image | undefined> action: PayloadAction<ImageDTO | undefined>
) => { ) => {
const node = action.payload?.metadata.invokeai?.node; const node = action.payload?.metadata.invokeai?.node;

View File

@ -1,4 +1,3 @@
import { Image } from 'app/types/invokeai';
import { get, isObject, isString } from 'lodash-es'; import { get, isObject, isString } from 'lodash-es';
import { import {
GraphExecutionState, GraphExecutionState,