fix(ui): fix all eslint & prettier issues

This commit is contained in:
psychedelicious 2023-07-22 23:26:14 +10:00
parent 6452d0fc28
commit c5147d0f57
95 changed files with 333 additions and 670 deletions

View File

@ -5,6 +5,10 @@ patches/
stats.html stats.html
index.html index.html
.yarn/ .yarn/
.yalc/
*.scss *.scss
src/services/api/ src/services/api/
src/services/fixtures/* src/services/fixtures/*
docs/
static/
src/theme/css/overlayscrollbars.css

View File

@ -48,6 +48,8 @@ export const useLogger = () => {
// Update the module-scoped logger context as needed // Update the module-scoped logger context as needed
useEffect(() => { useEffect(() => {
// TODO: type this properly
//eslint-disable-next-line @typescript-eslint/no-explicit-any
const newContext: Record<string, any> = { const newContext: Record<string, any> = {
...BASE_CONTEXT, ...BASE_CONTEXT,
}; };

View File

@ -12,7 +12,7 @@ import { defaultsDeep } from 'lodash-es';
import { UnserializeFunction } from 'redux-remember'; import { UnserializeFunction } from 'redux-remember';
const initialStates: { const initialStates: {
[key: string]: any; [key: string]: object; // TODO: type this properly
} = { } = {
canvas: initialCanvasState, canvas: initialCanvasState,
gallery: initialGalleryState, gallery: initialGalleryState,

View File

@ -15,7 +15,7 @@ export const addFirstListImagesListener = () => {
matcher: imagesApi.endpoints.listImages.matchFulfilled, matcher: imagesApi.endpoints.listImages.matchFulfilled,
effect: async ( effect: async (
action, action,
{ getState, dispatch, unsubscribe, cancelActiveListeners } { dispatch, unsubscribe, cancelActiveListeners }
) => { ) => {
// Only run this listener on the first listImages request for no-board images // Only run this listener on the first listImages request for no-board images
if ( if (

View File

@ -6,10 +6,7 @@ export const appStarted = createAction('app/appStarted');
export const addAppStartedListener = () => { export const addAppStartedListener = () => {
startAppListening({ startAppListening({
actionCreator: appStarted, actionCreator: appStarted,
effect: async ( effect: async (action, { unsubscribe, cancelActiveListeners }) => {
action,
{ getState, dispatch, unsubscribe, cancelActiveListeners }
) => {
// this should only run once // this should only run once
cancelActiveListeners(); cancelActiveListeners();
unsubscribe(); unsubscribe();

View File

@ -9,8 +9,8 @@ import { boardsApi } from '../../../../../services/api/endpoints/boards';
export const addDeleteBoardAndImagesFulfilledListener = () => { export const addDeleteBoardAndImagesFulfilledListener = () => {
startAppListening({ startAppListening({
matcher: boardsApi.endpoints.deleteBoardAndImages.matchFulfilled, matcher: boardsApi.endpoints.deleteBoardAndImages.matchFulfilled,
effect: async (action, { dispatch, getState, condition }) => { effect: async (action, { dispatch, getState }) => {
const { board_id, deleted_board_images, deleted_images } = action.payload; const { deleted_images } = action.payload;
// Remove all deleted images from the UI // Remove all deleted images from the UI

View File

@ -10,7 +10,7 @@ import { startAppListening } from '..';
export const addCanvasMergedListener = () => { export const addCanvasMergedListener = () => {
startAppListening({ startAppListening({
actionCreator: canvasMerged, actionCreator: canvasMerged,
effect: async (action, { dispatch, getState, take }) => { effect: async (action, { dispatch }) => {
const moduleLog = $logger const moduleLog = $logger
.get() .get()
.child({ namespace: 'canvasCopiedToClipboardListener' }); .child({ namespace: 'canvasCopiedToClipboardListener' });

View File

@ -8,7 +8,7 @@ import { startAppListening } from '..';
export const addCanvasSavedToGalleryListener = () => { export const addCanvasSavedToGalleryListener = () => {
startAppListening({ startAppListening({
actionCreator: canvasSavedToGallery, actionCreator: canvasSavedToGallery,
effect: async (action, { dispatch, getState, take }) => { effect: async (action, { dispatch, getState }) => {
const log = logger('canvas'); const log = logger('canvas');
const state = getState(); const state = getState();

View File

@ -62,10 +62,7 @@ const predicate: AnyListenerPredicate<RootState> = (
export const addControlNetAutoProcessListener = () => { export const addControlNetAutoProcessListener = () => {
startAppListening({ startAppListening({
predicate, predicate,
effect: async ( effect: async (action, { dispatch, cancelActiveListeners, delay }) => {
action,
{ dispatch, getState, cancelActiveListeners, delay }
) => {
const log = logger('session'); const log = logger('session');
const { controlNetId } = action.payload; const { controlNetId } = action.payload;

View File

@ -1,4 +1,4 @@
import { $logger, logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { controlNetImageProcessed } from 'features/controlNet/store/actions'; import { controlNetImageProcessed } from 'features/controlNet/store/actions';
import { controlNetProcessedImageChanged } from 'features/controlNet/store/controlNetSlice'; import { controlNetProcessedImageChanged } from 'features/controlNet/store/controlNetSlice';
import { sessionReadyToInvoke } from 'features/system/store/actions'; import { sessionReadyToInvoke } from 'features/system/store/actions';
@ -12,10 +12,7 @@ import { startAppListening } from '..';
export const addControlNetImageProcessedListener = () => { export const addControlNetImageProcessedListener = () => {
startAppListening({ startAppListening({
actionCreator: controlNetImageProcessed, actionCreator: controlNetImageProcessed,
effect: async ( effect: async (action, { dispatch, getState, take }) => {
action,
{ dispatch, getState, take, unsubscribe, subscribe }
) => {
const log = logger('session'); const log = logger('session');
const { controlNetId } = action.payload; const { controlNetId } = action.payload;
const controlNet = getState().controlNet.controlNets[controlNetId]; const controlNet = getState().controlNet.controlNets[controlNetId];

View File

@ -5,7 +5,7 @@ import { startAppListening } from '..';
export const addImageAddedToBoardFulfilledListener = () => { export const addImageAddedToBoardFulfilledListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.addImageToBoard.matchFulfilled, matcher: imagesApi.endpoints.addImageToBoard.matchFulfilled,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('images'); const log = logger('images');
const { board_id, imageDTO } = action.meta.arg.originalArgs; const { board_id, imageDTO } = action.meta.arg.originalArgs;
@ -19,7 +19,7 @@ export const addImageAddedToBoardFulfilledListener = () => {
export const addImageAddedToBoardRejectedListener = () => { export const addImageAddedToBoardRejectedListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.addImageToBoard.matchRejected, matcher: imagesApi.endpoints.addImageToBoard.matchRejected,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('images'); const log = logger('images');
const { board_id, imageDTO } = action.meta.arg.originalArgs; const { board_id, imageDTO } = action.meta.arg.originalArgs;

View File

@ -19,7 +19,6 @@ export const addRequestedImageDeletionListener = () => {
startAppListening({ startAppListening({
actionCreator: imageDeletionConfirmed, actionCreator: imageDeletionConfirmed,
effect: async (action, { dispatch, getState, condition }) => { effect: async (action, { dispatch, getState, condition }) => {
const log = logger('images');
const { imageDTO, imageUsage } = action.payload; const { imageDTO, imageUsage } = action.payload;
dispatch(isModalOpenChanged(false)); dispatch(isModalOpenChanged(false));
@ -104,8 +103,7 @@ export const addRequestedImageDeletionListener = () => {
export const addImageDeletedPendingListener = () => { export const addImageDeletedPendingListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.deleteImage.matchPending, matcher: imagesApi.endpoints.deleteImage.matchPending,
effect: (action, { dispatch, getState }) => { effect: () => {
const log = logger('images');
// //
}, },
}); });
@ -117,7 +115,7 @@ export const addImageDeletedPendingListener = () => {
export const addImageDeletedFulfilledListener = () => { export const addImageDeletedFulfilledListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.deleteImage.matchFulfilled, matcher: imagesApi.endpoints.deleteImage.matchFulfilled,
effect: (action, { dispatch, getState }) => { effect: (action) => {
const log = logger('images'); const log = logger('images');
log.debug({ imageDTO: action.meta.arg.originalArgs }, 'Image deleted'); log.debug({ imageDTO: action.meta.arg.originalArgs }, 'Image deleted');
}, },
@ -130,7 +128,7 @@ export const addImageDeletedFulfilledListener = () => {
export const addImageDeletedRejectedListener = () => { export const addImageDeletedRejectedListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.deleteImage.matchRejected, matcher: imagesApi.endpoints.deleteImage.matchRejected,
effect: (action, { dispatch, getState }) => { effect: (action) => {
const log = logger('images'); const log = logger('images');
log.debug( log.debug(
{ imageDTO: action.meta.arg.originalArgs }, { imageDTO: action.meta.arg.originalArgs },

View File

@ -23,7 +23,7 @@ export const dndDropped = createAction<{
export const addImageDroppedListener = () => { export const addImageDroppedListener = () => {
startAppListening({ startAppListening({
actionCreator: dndDropped, actionCreator: dndDropped,
effect: async (action, { dispatch, getState, take }) => { effect: async (action, { dispatch }) => {
const log = logger('images'); const log = logger('images');
const { activeData, overData } = action.payload; const { activeData, overData } = action.payload;

View File

@ -5,7 +5,7 @@ import { startAppListening } from '..';
export const addImageRemovedFromBoardFulfilledListener = () => { export const addImageRemovedFromBoardFulfilledListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.removeImageFromBoard.matchFulfilled, matcher: imagesApi.endpoints.removeImageFromBoard.matchFulfilled,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('images'); const log = logger('images');
const imageDTO = action.meta.arg.originalArgs; const imageDTO = action.meta.arg.originalArgs;
@ -17,7 +17,7 @@ export const addImageRemovedFromBoardFulfilledListener = () => {
export const addImageRemovedFromBoardRejectedListener = () => { export const addImageRemovedFromBoardRejectedListener = () => {
startAppListening({ startAppListening({
matcher: imagesApi.endpoints.removeImageFromBoard.matchRejected, matcher: imagesApi.endpoints.removeImageFromBoard.matchRejected,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('images'); const log = logger('images');
const imageDTO = action.meta.arg.originalArgs; const imageDTO = action.meta.arg.originalArgs;

View File

@ -9,7 +9,7 @@ import { startAppListening } from '..';
export const addImageToDeleteSelectedListener = () => { export const addImageToDeleteSelectedListener = () => {
startAppListening({ startAppListening({
actionCreator: imageToDeleteSelected, actionCreator: imageToDeleteSelected,
effect: async (action, { dispatch, getState, condition }) => { effect: async (action, { dispatch, getState }) => {
const imageDTO = action.payload; const imageDTO = action.payload;
const state = getState(); const state = getState();
const { shouldConfirmOnDelete } = state.system; const { shouldConfirmOnDelete } = state.system;

View File

@ -9,6 +9,7 @@ import { addToast } from 'features/system/store/systemSlice';
import { boardsApi } from 'services/api/endpoints/boards'; import { boardsApi } from 'services/api/endpoints/boards';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { imagesApi } from '../../../../../services/api/endpoints/images'; import { imagesApi } from '../../../../../services/api/endpoints/images';
import { omit } from 'lodash-es';
const DEFAULT_UPLOADED_TOAST: UseToastOptions = { const DEFAULT_UPLOADED_TOAST: UseToastOptions = {
title: 'Image Uploaded', title: 'Image Uploaded',
@ -22,7 +23,7 @@ export const addImageUploadedFulfilledListener = () => {
const log = logger('images'); const log = logger('images');
const imageDTO = action.payload; const imageDTO = action.payload;
const state = getState(); const state = getState();
const { selectedBoardId, autoAddBoardId } = state.gallery; const { autoAddBoardId } = state.gallery;
log.debug({ imageDTO }, 'Image uploaded'); log.debug({ imageDTO }, 'Image uploaded');
@ -140,8 +141,12 @@ export const addImageUploadedRejectedListener = () => {
matcher: imagesApi.endpoints.uploadImage.matchRejected, matcher: imagesApi.endpoints.uploadImage.matchRejected,
effect: (action, { dispatch }) => { effect: (action, { dispatch }) => {
const log = logger('images'); const log = logger('images');
const { file, postUploadAction, ...rest } = action.meta.arg.originalArgs; const sanitizedData = {
const sanitizedData = { arg: { ...rest, file: '<Blob>' } }; arg: {
...omit(action.meta.arg.originalArgs, ['file', 'postUploadAction']),
file: '<Blob>',
},
};
log.error({ ...sanitizedData }, 'Image upload failed'); log.error({ ...sanitizedData }, 'Image upload failed');
dispatch( dispatch(
addToast({ addToast({

View File

@ -8,7 +8,7 @@ import { startAppListening } from '..';
export const addInitialImageSelectedListener = () => { export const addInitialImageSelectedListener = () => {
startAppListening({ startAppListening({
actionCreator: initialImageSelected, actionCreator: initialImageSelected,
effect: (action, { getState, dispatch }) => { effect: (action, { dispatch }) => {
if (!action.payload) { if (!action.payload) {
dispatch( dispatch(
addToast( addToast(

View File

@ -1,4 +1,5 @@
import { $logger, logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { controlNetRemoved } from 'features/controlNet/store/controlNetSlice';
import { loraRemoved } from 'features/lora/store/loraSlice'; import { loraRemoved } from 'features/lora/store/loraSlice';
import { import {
modelChanged, modelChanged,
@ -11,7 +12,6 @@ import {
import { forEach, some } from 'lodash-es'; import { forEach, some } from 'lodash-es';
import { modelsApi } from 'services/api/endpoints/models'; import { modelsApi } from 'services/api/endpoints/models';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { controlNetRemoved } from 'features/controlNet/store/controlNetSlice';
export const addModelsLoadedListener = () => { export const addModelsLoadedListener = () => {
startAppListening({ startAppListening({
@ -167,7 +167,7 @@ export const addModelsLoadedListener = () => {
}); });
startAppListening({ startAppListening({
matcher: modelsApi.endpoints.getTextualInversionModels.matchFulfilled, matcher: modelsApi.endpoints.getTextualInversionModels.matchFulfilled,
effect: async (action, { getState, dispatch }) => { effect: async (action) => {
const log = logger('models'); const log = logger('models');
log.info( log.info(
{ models: action.payload.entities }, { models: action.payload.entities },

View File

@ -1,15 +1,15 @@
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { parseify } from 'common/util/serialize';
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice'; import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
import { parseSchema } from 'features/nodes/util/parseSchema'; import { parseSchema } from 'features/nodes/util/parseSchema';
import { size } from 'lodash-es'; import { size } from 'lodash-es';
import { receivedOpenAPISchema } from 'services/api/thunks/schema'; import { receivedOpenAPISchema } from 'services/api/thunks/schema';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { parseify } from 'common/util/serialize';
export const addReceivedOpenAPISchemaListener = () => { export const addReceivedOpenAPISchemaListener = () => {
startAppListening({ startAppListening({
actionCreator: receivedOpenAPISchema.fulfilled, actionCreator: receivedOpenAPISchema.fulfilled,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('system'); const log = logger('system');
const schemaJSON = action.payload; const schemaJSON = action.payload;
@ -28,7 +28,7 @@ export const addReceivedOpenAPISchemaListener = () => {
startAppListening({ startAppListening({
actionCreator: receivedOpenAPISchema.rejected, actionCreator: receivedOpenAPISchema.rejected,
effect: (action, { dispatch, getState }) => { effect: () => {
const log = logger('system'); const log = logger('system');
log.error('Problem dereferencing OpenAPI Schema'); log.error('Problem dereferencing OpenAPI Schema');
}, },

View File

@ -6,8 +6,7 @@ import { startAppListening } from '..';
export const addSessionCanceledPendingListener = () => { export const addSessionCanceledPendingListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionCanceled.pending, actionCreator: sessionCanceled.pending,
effect: (action, { getState, dispatch }) => { effect: () => {
const log = logger('session');
// //
}, },
}); });
@ -16,7 +15,7 @@ export const addSessionCanceledPendingListener = () => {
export const addSessionCanceledFulfilledListener = () => { export const addSessionCanceledFulfilledListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionCanceled.fulfilled, actionCreator: sessionCanceled.fulfilled,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('session'); const log = logger('session');
const { session_id } = action.meta.arg; const { session_id } = action.meta.arg;
log.debug({ session_id }, `Session canceled (${session_id})`); log.debug({ session_id }, `Session canceled (${session_id})`);
@ -27,7 +26,7 @@ export const addSessionCanceledFulfilledListener = () => {
export const addSessionCanceledRejectedListener = () => { export const addSessionCanceledRejectedListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionCanceled.rejected, actionCreator: sessionCanceled.rejected,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('session'); const log = logger('session');
const { session_id } = action.meta.arg; const { session_id } = action.meta.arg;
if (action.payload) { if (action.payload) {

View File

@ -7,8 +7,7 @@ import { startAppListening } from '..';
export const addSessionCreatedPendingListener = () => { export const addSessionCreatedPendingListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionCreated.pending, actionCreator: sessionCreated.pending,
effect: (action, { getState, dispatch }) => { effect: () => {
const log = logger('session');
// //
}, },
}); });
@ -17,7 +16,7 @@ export const addSessionCreatedPendingListener = () => {
export const addSessionCreatedFulfilledListener = () => { export const addSessionCreatedFulfilledListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionCreated.fulfilled, actionCreator: sessionCreated.fulfilled,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('session'); const log = logger('session');
const session = action.payload; const session = action.payload;
log.debug( log.debug(
@ -31,10 +30,10 @@ export const addSessionCreatedFulfilledListener = () => {
export const addSessionCreatedRejectedListener = () => { export const addSessionCreatedRejectedListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionCreated.rejected, actionCreator: sessionCreated.rejected,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('session'); const log = logger('session');
if (action.payload) { if (action.payload) {
const { arg, error } = action.payload; const { error } = action.payload;
const graph = parseify(action.meta.arg); const graph = parseify(action.meta.arg);
const stringifiedError = JSON.stringify(error); const stringifiedError = JSON.stringify(error);
log.error( log.error(

View File

@ -6,8 +6,7 @@ import { startAppListening } from '..';
export const addSessionInvokedPendingListener = () => { export const addSessionInvokedPendingListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionInvoked.pending, actionCreator: sessionInvoked.pending,
effect: (action, { getState, dispatch }) => { effect: () => {
const log = logger('session');
// //
}, },
}); });
@ -16,7 +15,7 @@ export const addSessionInvokedPendingListener = () => {
export const addSessionInvokedFulfilledListener = () => { export const addSessionInvokedFulfilledListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionInvoked.fulfilled, actionCreator: sessionInvoked.fulfilled,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('session'); const log = logger('session');
const { session_id } = action.meta.arg; const { session_id } = action.meta.arg;
log.debug({ session_id }, `Session invoked (${session_id})`); log.debug({ session_id }, `Session invoked (${session_id})`);
@ -27,11 +26,11 @@ export const addSessionInvokedFulfilledListener = () => {
export const addSessionInvokedRejectedListener = () => { export const addSessionInvokedRejectedListener = () => {
startAppListening({ startAppListening({
actionCreator: sessionInvoked.rejected, actionCreator: sessionInvoked.rejected,
effect: (action, { getState, dispatch }) => { effect: (action) => {
const log = logger('session'); const log = logger('session');
const { session_id } = action.meta.arg; const { session_id } = action.meta.arg;
if (action.payload) { if (action.payload) {
const { arg, error } = action.payload; const { error } = action.payload;
const stringifiedError = JSON.stringify(error); const stringifiedError = JSON.stringify(error);
log.error( log.error(
{ {

View File

@ -8,7 +8,7 @@ import { startAppListening } from '../..';
export const addSocketDisconnectedEventListener = () => { export const addSocketDisconnectedEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketDisconnected, actionCreator: socketDisconnected,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
log.debug('Disconnected'); log.debug('Disconnected');
// pass along the socket event as an application action // pass along the socket event as an application action

View File

@ -8,7 +8,7 @@ import { startAppListening } from '../..';
export const addGraphExecutionStateCompleteEventListener = () => { export const addGraphExecutionStateCompleteEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketGraphExecutionStateComplete, actionCreator: socketGraphExecutionStateComplete,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
log.debug(action.payload, 'Session complete'); log.debug(action.payload, 'Session complete');
// pass along the socket event as an application action // pass along the socket event as an application action

View File

@ -22,7 +22,7 @@ const nodeDenylist = ['dataURL_image'];
export const addInvocationCompleteEventListener = () => { export const addInvocationCompleteEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketInvocationComplete, actionCreator: socketInvocationComplete,
effect: async (action, { dispatch, getState, take }) => { effect: async (action, { dispatch, getState }) => {
const log = logger('socketio'); const log = logger('socketio');
const { data } = action.payload; const { data } = action.payload;
log.debug( log.debug(

View File

@ -8,7 +8,7 @@ import { startAppListening } from '../..';
export const addInvocationErrorEventListener = () => { export const addInvocationErrorEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketInvocationError, actionCreator: socketInvocationError,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
log.error( log.error(
action.payload, action.payload,

View File

@ -1,5 +1,4 @@
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { ModelType } from 'services/api/types';
import { import {
appSocketModelLoadCompleted, appSocketModelLoadCompleted,
appSocketModelLoadStarted, appSocketModelLoadStarted,
@ -8,18 +7,10 @@ import {
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
const MODEL_TYPES: Record<ModelType, string> = {
main: 'main',
vae: 'VAE',
lora: 'LoRA',
controlnet: 'ControlNet',
embedding: 'embedding',
};
export const addModelLoadEventListener = () => { export const addModelLoadEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketModelLoadStarted, actionCreator: socketModelLoadStarted,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
const { base_model, model_name, model_type, submodel } = const { base_model, model_name, model_type, submodel } =
action.payload.data; action.payload.data;
@ -39,7 +30,7 @@ export const addModelLoadEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketModelLoadCompleted, actionCreator: socketModelLoadCompleted,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
const { base_model, model_name, model_type, submodel } = const { base_model, model_name, model_type, submodel } =
action.payload.data; action.payload.data;

View File

@ -5,7 +5,7 @@ import { startAppListening } from '../..';
export const addSocketSubscribedEventListener = () => { export const addSocketSubscribedEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketSubscribed, actionCreator: socketSubscribed,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
log.debug(action.payload, 'Subscribed'); log.debug(action.payload, 'Subscribed');
dispatch(appSocketSubscribed(action.payload)); dispatch(appSocketSubscribed(action.payload));

View File

@ -8,7 +8,7 @@ import { startAppListening } from '../..';
export const addSocketUnsubscribedEventListener = () => { export const addSocketUnsubscribedEventListener = () => {
startAppListening({ startAppListening({
actionCreator: socketUnsubscribed, actionCreator: socketUnsubscribed,
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch }) => {
const log = logger('socketio'); const log = logger('socketio');
log.debug(action.payload, 'Unsubscribed'); log.debug(action.payload, 'Unsubscribed');
dispatch(appSocketUnsubscribed(action.payload)); dispatch(appSocketUnsubscribed(action.payload));

View File

@ -1,4 +1,3 @@
import { logger } from 'app/logging/logger';
import { stagingAreaImageSaved } from 'features/canvas/store/actions'; import { stagingAreaImageSaved } from 'features/canvas/store/actions';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
@ -7,8 +6,7 @@ import { startAppListening } from '..';
export const addStagingAreaImageSavedListener = () => { export const addStagingAreaImageSavedListener = () => {
startAppListening({ startAppListening({
actionCreator: stagingAreaImageSaved, actionCreator: stagingAreaImageSaved,
effect: async (action, { dispatch, getState, take }) => { effect: async (action, { dispatch, getState }) => {
const log = logger('canvas');
const { imageDTO } = action.payload; const { imageDTO } = action.payload;
try { try {

View File

@ -11,10 +11,7 @@ export const upscaleRequested = createAction<{ image_name: string }>(
export const addUpscaleRequestedListener = () => { export const addUpscaleRequestedListener = () => {
startAppListening({ startAppListening({
actionCreator: upscaleRequested, actionCreator: upscaleRequested,
effect: async ( effect: async (action, { dispatch, getState, take }) => {
action,
{ dispatch, getState, take, unsubscribe, subscribe }
) => {
const { image_name } = action.payload; const { image_name } = action.payload;
const { esrganModelName } = getState().postprocessing; const { esrganModelName } = getState().postprocessing;

View File

@ -4,7 +4,6 @@ import {
autoBatchEnhancer, autoBatchEnhancer,
combineReducers, combineReducers,
configureStore, configureStore,
createAsyncThunk,
} from '@reduxjs/toolkit'; } from '@reduxjs/toolkit';
import canvasReducer from 'features/canvas/store/canvasSlice'; import canvasReducer from 'features/canvas/store/canvasSlice';
import controlNetReducer from 'features/controlNet/store/controlNetSlice'; import controlNetReducer from 'features/controlNet/store/controlNetSlice';
@ -118,6 +117,7 @@ export const store = configureStore({
export type AppGetState = typeof store.getState; export type AppGetState = typeof store.getState;
export type RootState = ReturnType<typeof store.getState>; export type RootState = ReturnType<typeof store.getState>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AppThunkDispatch = ThunkDispatch<RootState, any, AnyAction>; export type AppThunkDispatch = ThunkDispatch<RootState, any, AnyAction>;
export type AppDispatch = typeof store.dispatch; export type AppDispatch = typeof store.dispatch;
export const stateSelector = (state: RootState) => state; export const stateSelector = (state: RootState) => state;

View File

@ -13,11 +13,10 @@ type IAIDroppableProps = {
dropLabel?: ReactNode; dropLabel?: ReactNode;
disabled?: boolean; disabled?: boolean;
data?: TypesafeDroppableData; data?: TypesafeDroppableData;
hoverRef?: React.Ref<HTMLDivElement>;
}; };
const IAIDroppable = (props: IAIDroppableProps) => { const IAIDroppable = (props: IAIDroppableProps) => {
const { dropLabel, data, disabled, hoverRef } = props; const { dropLabel, data, disabled } = props;
const dndId = useRef(uuidv4()); const dndId = useRef(uuidv4());
const { isOver, setNodeRef, active } = useDroppable({ const { isOver, setNodeRef, active } = useDroppable({

View File

@ -10,7 +10,10 @@ interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
} }
const IAIMantineSelectItemWithTooltip = forwardRef<HTMLDivElement, ItemProps>( const IAIMantineSelectItemWithTooltip = forwardRef<HTMLDivElement, ItemProps>(
({ label, tooltip, description, disabled, ...others }: ItemProps, ref) => ( (
{ label, tooltip, description, disabled: _disabled, ...others }: ItemProps,
ref
) => (
<Tooltip label={tooltip} placement="top" hasArrow openDelay={500}> <Tooltip label={tooltip} placement="top" hasArrow openDelay={500}>
<Box ref={ref} {...others}> <Box ref={ref} {...others}>
<Box> <Box>

View File

@ -1,5 +1,4 @@
import { import {
ChakraProps,
FormControl, FormControl,
FormControlProps, FormControlProps,
FormLabel, FormLabel,
@ -24,16 +23,15 @@ import {
Tooltip, Tooltip,
TooltipProps, TooltipProps,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { clamp } from 'lodash-es';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { roundDownToMultiple } from 'common/util/roundDownToMultiple'; import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
import { clamp } from 'lodash-es';
import { import {
FocusEvent, FocusEvent,
KeyboardEvent, KeyboardEvent,
memo,
MouseEvent, MouseEvent,
memo,
useCallback, useCallback,
useEffect, useEffect,
useMemo, useMemo,

View File

@ -1,6 +1,7 @@
import { Box, chakra, Flex } from '@chakra-ui/react'; import { Box, chakra, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { import {
canvasSelector, canvasSelector,
isStagingSelector, isStagingSelector,
@ -8,8 +9,6 @@ import {
import Konva from 'konva'; import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node'; import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types'; import { Vector2d } from 'konva/lib/types';
import { isEqual } from 'lodash-es';
import { useCallback, useRef } from 'react'; import { useCallback, useRef } from 'react';
import { Layer, Stage } from 'react-konva'; import { Layer, Stage } from 'react-konva';
import useCanvasDragMove from '../hooks/useCanvasDragMove'; import useCanvasDragMove from '../hooks/useCanvasDragMove';
@ -34,7 +33,6 @@ import IAICanvasStagingAreaToolbar from './IAICanvasStagingAreaToolbar';
import IAICanvasStatusText from './IAICanvasStatusText'; import IAICanvasStatusText from './IAICanvasStatusText';
import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox'; import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox';
import IAICanvasToolPreview from './IAICanvasToolPreview'; import IAICanvasToolPreview from './IAICanvasToolPreview';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
const selector = createSelector( const selector = createSelector(
[canvasSelector, isStagingSelector], [canvasSelector, isStagingSelector],

View File

@ -713,7 +713,7 @@ export const canvasSlice = createSlice({
}, },
commitStagingAreaImage: ( commitStagingAreaImage: (
state, state,
action: PayloadAction<string | undefined> _action: PayloadAction<string | undefined>
) => { ) => {
if (!state.layerState.stagingArea.images.length) { if (!state.layerState.stagingArea.images.length) {
return; return;
@ -866,11 +866,11 @@ export const canvasSlice = createSlice({
} }
}); });
builder.addCase(setShouldUseCanvasBetaLayout, (state, action) => { builder.addCase(setShouldUseCanvasBetaLayout, (state) => {
state.doesCanvasNeedScaling = true; state.doesCanvasNeedScaling = true;
}); });
builder.addCase(setActiveTab, (state, action) => { builder.addCase(setActiveTab, (state) => {
state.doesCanvasNeedScaling = true; state.doesCanvasNeedScaling = true;
}); });
builder.addCase(setAspectRatio, (state, action) => { builder.addCase(setAspectRatio, (state, action) => {
@ -882,26 +882,6 @@ export const canvasSlice = createSlice({
); );
} }
}); });
// builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
// const { image_name, image_url, thumbnail_url } = action.payload;
// state.layerState.objects.forEach((object) => {
// if (object.kind === 'image') {
// if (object.image.image_name === image_name) {
// object.image.image_url = image_url;
// object.image.thumbnail_url = thumbnail_url;
// }
// }
// });
// state.layerState.stagingArea.images.forEach((stagedImage) => {
// if (stagedImage.image.image_name === image_name) {
// stagedImage.image.image_url = image_url;
// stagedImage.image.thumbnail_url = thumbnail_url;
// }
// });
// });
}, },
}); });

View File

@ -11,8 +11,8 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { controlNetImageChanged } from '../store/controlNetSlice';
import { PostUploadAction } from 'services/api/types'; import { PostUploadAction } from 'services/api/types';
import { controlNetImageChanged } from '../store/controlNetSlice';
type Props = { type Props = {
controlNetId: string; controlNetId: string;
@ -59,19 +59,13 @@ const ControlNetImagePreview = (props: Props) => {
const [isMouseOverImage, setIsMouseOverImage] = useState(false); const [isMouseOverImage, setIsMouseOverImage] = useState(false);
const { const { currentData: controlImage } = useGetImageDTOQuery(
currentData: controlImage, controlImageName ?? skipToken
isLoading: isLoadingControlImage, );
isError: isErrorControlImage,
isSuccess: isSuccessControlImage,
} = useGetImageDTOQuery(controlImageName ?? skipToken);
const { const { currentData: processedControlImage } = useGetImageDTOQuery(
currentData: processedControlImage, processedControlImageName ?? skipToken
isLoading: isLoadingProcessedControlImage, );
isError: isErrorProcessedControlImage,
isSuccess: isSuccessProcessedControlImage,
} = useGetImageDTOQuery(processedControlImageName ?? skipToken);
const handleResetControlImage = useCallback(() => { const handleResetControlImage = useCallback(() => {
dispatch(controlNetImageChanged({ controlNetId, controlImage: null })); dispatch(controlNetImageChanged({ controlNetId, controlImage: null }));

View File

@ -55,11 +55,6 @@ const ParamControlNetBeginEnd = (props: Props) => {
[controlNetId, dispatch] [controlNetId, dispatch]
); );
const handleStepPctReset = useCallback(() => {
dispatch(controlNetBeginStepPctChanged({ controlNetId, beginStepPct: 0 }));
dispatch(controlNetEndStepPctChanged({ controlNetId, endStepPct: 1 }));
}, [controlNetId, dispatch]);
return ( return (
<FormControl isDisabled={!isEnabled}> <FormControl isDisabled={!isEnabled}>
<FormLabel>Begin / End Step Percentage</FormLabel> <FormLabel>Begin / End Step Percentage</FormLabel>

View File

@ -8,7 +8,6 @@ import {
controlNetControlModeChanged, controlNetControlModeChanged,
} from 'features/controlNet/store/controlNetSlice'; } from 'features/controlNet/store/controlNetSlice';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
type ParamControlNetControlModeProps = { type ParamControlNetControlModeProps = {
controlNetId: string; controlNetId: string;
@ -42,8 +41,6 @@ export default function ParamControlNetControlMode(
const { controlMode, isEnabled } = useAppSelector(selector); const { controlMode, isEnabled } = useAppSelector(selector);
const { t } = useTranslation();
const handleControlModeChange = useCallback( const handleControlModeChange = useCallback(
(controlMode: ControlModes) => { (controlMode: ControlModes) => {
dispatch(controlNetControlModeChanged({ controlNetId, controlMode })); dispatch(controlNetControlModeChanged({ controlNetId, controlMode }));

View File

@ -13,7 +13,6 @@ import { memo, useCallback, useMemo } from 'react';
import { CONTROLNET_PROCESSORS } from '../../store/constants'; import { CONTROLNET_PROCESSORS } from '../../store/constants';
import { controlNetProcessorTypeChanged } from '../../store/controlNetSlice'; import { controlNetProcessorTypeChanged } from '../../store/controlNetSlice';
import { ControlNetProcessorType } from '../../store/types'; import { ControlNetProcessorType } from '../../store/types';
import { FormControl, FormLabel } from '@chakra-ui/react';
type ParamControlNetProcessorSelectProps = { type ParamControlNetProcessorSelectProps = {
controlNetId: string; controlNetId: string;

View File

@ -8,7 +8,6 @@ import {
controlNetResizeModeChanged, controlNetResizeModeChanged,
} from 'features/controlNet/store/controlNetSlice'; } from 'features/controlNet/store/controlNetSlice';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
type ParamControlNetResizeModeProps = { type ParamControlNetResizeModeProps = {
controlNetId: string; controlNetId: string;
@ -41,8 +40,6 @@ export default function ParamControlNetResizeMode(
const { resizeMode, isEnabled } = useAppSelector(selector); const { resizeMode, isEnabled } = useAppSelector(selector);
const { t } = useTranslation();
const handleResizeModeChange = useCallback( const handleResizeModeChange = useCallback(
(resizeMode: ResizeModes) => { (resizeMode: ResizeModes) => {
dispatch(controlNetResizeModeChanged({ controlNetId, resizeMode })); dispatch(controlNetResizeModeChanged({ controlNetId, resizeMode }));

View File

@ -7,7 +7,7 @@ type Props = {
isEnabled: boolean; isEnabled: boolean;
}; };
const ZoeDepthProcessor = (props: Props) => { const ZoeDepthProcessor = (_props: Props) => {
// Has no parameters? // Has no parameters?
return null; return null;
}; };

View File

@ -314,11 +314,11 @@ export const controlNetSlice = createSlice({
} }
}); });
builder.addCase(appSocketInvocationError, (state, action) => { builder.addCase(appSocketInvocationError, (state) => {
state.pendingControlImages = []; state.pendingControlImages = [];
}); });
builder.addMatcher(isAnySessionRejected, (state, action) => { builder.addMatcher(isAnySessionRejected, (state) => {
state.pendingControlImages = []; state.pendingControlImages = [];
}); });

View File

@ -1,19 +1,16 @@
import { MenuGroup, MenuItem, MenuList } from '@chakra-ui/react'; import { MenuGroup, MenuItem, MenuList } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu'; import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu';
import { import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
autoAddBoardIdChanged,
boardIdSelected,
} from 'features/gallery/store/gallerySlice';
import { MouseEvent, memo, useCallback, useMemo } from 'react'; import { MouseEvent, memo, useCallback, useMemo } from 'react';
import { FaFolder, FaPlus } from 'react-icons/fa'; import { FaPlus } from 'react-icons/fa';
import { useBoardName } from 'services/api/hooks/useBoardName';
import { BoardDTO } from 'services/api/types'; import { BoardDTO } from 'services/api/types';
import { menuListMotionProps } from 'theme/components/menu'; import { menuListMotionProps } from 'theme/components/menu';
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems'; import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
import NoBoardContextMenuItems from './NoBoardContextMenuItems'; import NoBoardContextMenuItems from './NoBoardContextMenuItems';
import { useBoardName } from 'services/api/hooks/useBoardName';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
type Props = { type Props = {
board?: BoardDTO; board?: BoardDTO;
@ -29,20 +26,15 @@ const BoardContextMenu = memo(
const selector = useMemo( const selector = useMemo(
() => () =>
createSelector(stateSelector, ({ gallery }) => { createSelector(stateSelector, ({ gallery }) => {
const isSelected = gallery.selectedBoardId === board_id;
const isAutoAdd = gallery.autoAddBoardId === board_id; const isAutoAdd = gallery.autoAddBoardId === board_id;
return { isSelected, isAutoAdd }; return { isAutoAdd };
}), }),
[board_id] [board_id]
); );
const { isSelected, isAutoAdd } = useAppSelector(selector); const { isAutoAdd } = useAppSelector(selector);
const boardName = useBoardName(board_id); const boardName = useBoardName(board_id);
const handleSelectBoard = useCallback(() => {
dispatch(boardIdSelected(board_id));
}, [board_id, dispatch]);
const handleSetAutoAdd = useCallback(() => { const handleSetAutoAdd = useCallback(() => {
dispatch(autoAddBoardIdChanged(board_id)); dispatch(autoAddBoardIdChanged(board_id));
}, [board_id, dispatch]); }, [board_id, dispatch]);

View File

@ -1,21 +1,16 @@
import { ButtonGroup, Collapse, Flex, Grid, GridItem } from '@chakra-ui/react'; import { Collapse, Flex, Grid, GridItem } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIIconButton from 'common/components/IAIIconButton';
import { AnimatePresence, motion } from 'framer-motion';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import { memo, useCallback, useState } from 'react'; import { memo, useState } from 'react';
import { FaSearch } from 'react-icons/fa';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards'; import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
import { BoardDTO } from 'services/api/types'; import { BoardDTO } from 'services/api/types';
import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus';
import DeleteBoardModal from '../DeleteBoardModal'; import DeleteBoardModal from '../DeleteBoardModal';
import AddBoardButton from './AddBoardButton'; import AddBoardButton from './AddBoardButton';
import BoardsSearch from './BoardsSearch'; import BoardsSearch from './BoardsSearch';
import GalleryBoard from './GalleryBoard'; import GalleryBoard from './GalleryBoard';
import SystemBoardButton from './SystemBoardButton';
import NoBoardBoard from './NoBoardBoard'; import NoBoardBoard from './NoBoardBoard';
const selector = createSelector( const selector = createSelector(
@ -36,7 +31,6 @@ const BoardsList = (props: Props) => {
const { isOpen } = props; const { isOpen } = props;
const { selectedBoardId, searchText } = useAppSelector(selector); const { selectedBoardId, searchText } = useAppSelector(selector);
const { data: boards } = useListAllBoardsQuery(); const { data: boards } = useListAllBoardsQuery();
const isBatchEnabled = useFeatureStatus('batches').isFeatureEnabled;
const filteredBoards = searchText const filteredBoards = searchText
? boards?.filter((board) => ? boards?.filter((board) =>
board.board_name.toLowerCase().includes(searchText.toLowerCase()) board.board_name.toLowerCase().includes(searchText.toLowerCase())

View File

@ -1,7 +1,5 @@
import { import {
Badge,
Box, Box,
ChakraProps,
Editable, Editable,
EditableInput, EditableInput,
EditablePreview, EditablePreview,
@ -17,21 +15,16 @@ import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIDroppable from 'common/components/IAIDroppable'; import IAIDroppable from 'common/components/IAIDroppable';
import SelectionOverlay from 'common/components/SelectionOverlay';
import { boardIdSelected } from 'features/gallery/store/gallerySlice'; import { boardIdSelected } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { FaUser } from 'react-icons/fa'; import { FaUser } from 'react-icons/fa';
import { useUpdateBoardMutation } from 'services/api/endpoints/boards'; import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
import { BoardDTO } from 'services/api/types'; import { BoardDTO } from 'services/api/types';
import AutoAddIcon from '../AutoAddIcon'; import AutoAddIcon from '../AutoAddIcon';
import BoardContextMenu from '../BoardContextMenu'; import BoardContextMenu from '../BoardContextMenu';
import SelectionOverlay from 'common/components/SelectionOverlay';
const BASE_BADGE_STYLES: ChakraProps['sx'] = {
bg: 'base.500',
color: 'whiteAlpha.900',
};
interface GalleryBoardProps { interface GalleryBoardProps {
board: BoardDTO; board: BoardDTO;
isSelected: boolean; isSelected: boolean;
@ -68,8 +61,6 @@ const GalleryBoard = memo(
board.cover_image_name ?? skipToken board.cover_image_name ?? skipToken
); );
const { totalImages, totalAssets } = useBoardTotal(board.board_id);
const { board_name, board_id } = board; const { board_name, board_id } = board;
const [localBoardName, setLocalBoardName] = useState(board_name); const [localBoardName, setLocalBoardName] = useState(board_name);

View File

@ -1,4 +1,4 @@
import { Box, ChakraProps, Flex, Image, Text } from '@chakra-ui/react'; import { Box, Flex, Image, Text } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { MoveBoardDropData } from 'app/components/ImageDnd/typesafeDnd'; import { MoveBoardDropData } from 'app/components/ImageDnd/typesafeDnd';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
@ -10,14 +10,8 @@ import SelectionOverlay from 'common/components/SelectionOverlay';
import { boardIdSelected } from 'features/gallery/store/gallerySlice'; import { boardIdSelected } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useBoardName } from 'services/api/hooks/useBoardName'; import { useBoardName } from 'services/api/hooks/useBoardName';
import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
import AutoAddIcon from '../AutoAddIcon'; import AutoAddIcon from '../AutoAddIcon';
import BoardContextMenu from '../BoardContextMenu'; import BoardContextMenu from '../BoardContextMenu';
const BASE_BADGE_STYLES: ChakraProps['sx'] = {
bg: 'base.500',
color: 'whiteAlpha.900',
};
interface Props { interface Props {
isSelected: boolean; isSelected: boolean;
} }
@ -33,7 +27,6 @@ const selector = createSelector(
const NoBoardBoard = memo(({ isSelected }: Props) => { const NoBoardBoard = memo(({ isSelected }: Props) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { totalImages, totalAssets } = useBoardTotal(undefined);
const { autoAddBoardId } = useAppSelector(selector); const { autoAddBoardId } = useAppSelector(selector);
const boardName = useBoardName(undefined); const boardName = useBoardName(undefined);
const handleSelectBoard = useCallback(() => { const handleSelectBoard = useCallback(() => {

View File

@ -1,11 +1,6 @@
import { MenuItem } from '@chakra-ui/react'; import { MenuItem } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { memo, useCallback } from 'react';
import { stateSelector } from 'app/store/store'; import { FaTrash } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo } from 'react';
import { FaPlus, FaTrash } from 'react-icons/fa';
import { BoardDTO } from 'services/api/types'; import { BoardDTO } from 'services/api/types';
type Props = { type Props = {
@ -14,25 +9,6 @@ type Props = {
}; };
const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => { const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => {
const dispatch = useAppDispatch();
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ gallery }) => {
const isSelectedForAutoAdd =
board.board_id === gallery.autoAddBoardId;
return { isSelectedForAutoAdd };
},
defaultSelectorOptions
),
[board.board_id]
);
const { isSelectedForAutoAdd } = useAppSelector(selector);
const handleDelete = useCallback(() => { const handleDelete = useCallback(() => {
if (!setBoardToDelete) { if (!setBoardToDelete) {
return; return;
@ -40,12 +16,6 @@ const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => {
setBoardToDelete(board); setBoardToDelete(board);
}, [board, setBoardToDelete]); }, [board, setBoardToDelete]);
const handleToggleAutoAdd = useCallback(() => {
dispatch(
autoAddBoardIdChanged(isSelectedForAutoAdd ? undefined : board.board_id)
);
}, [board.board_id, dispatch, isSelectedForAutoAdd]);
return ( return (
<> <>
{board.image_count > 0 && ( {board.image_count > 0 && (
@ -59,11 +29,6 @@ const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => {
</MenuItem> */} </MenuItem> */}
</> </>
)} )}
{/* {!isSelectedForAutoAdd && (
<MenuItem icon={<FaPlus />} onClick={handleToggleAutoAdd}>
Auto-add to this Board
</MenuItem>
)} */}
<MenuItem <MenuItem
sx={{ color: 'error.600', _dark: { color: 'error.300' } }} sx={{ color: 'error.600', _dark: { color: 'error.300' } }}
icon={<FaTrash />} icon={<FaTrash />}

View File

@ -1,19 +1,6 @@
import { MenuItem } from '@chakra-ui/react'; import { memo } from 'react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
import { memo, useCallback } from 'react';
import { FaPlus } from 'react-icons/fa';
const NoBoardContextMenuItems = () => { const NoBoardContextMenuItems = () => {
const dispatch = useAppDispatch();
const autoAddBoardId = useAppSelector(
(state) => state.gallery.autoAddBoardId
);
const handleDisableAutoAdd = useCallback(() => {
dispatch(autoAddBoardIdChanged(undefined));
}, [dispatch]);
return ( return (
<> <>
{/* {autoAddBoardId && ( {/* {autoAddBoardId && (

View File

@ -108,7 +108,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
500 500
); );
const { currentData: imageDTO, isFetching } = useGetImageDTOQuery( const { currentData: imageDTO } = useGetImageDTOQuery(
lastSelectedImage ?? skipToken lastSelectedImage ?? skipToken
); );

View File

@ -8,17 +8,17 @@ import {
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { useNextPrevImage } from 'features/gallery/hooks/useNextPrevImage'; import { useNextPrevImage } from 'features/gallery/hooks/useNextPrevImage';
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors'; import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { memo, useCallback, useMemo, useRef, useState } from 'react'; import { memo, useCallback, useMemo, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { FaImage } from 'react-icons/fa';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import ImageMetadataViewer from '../ImageMetadataViewer/ImageMetadataViewer'; import ImageMetadataViewer from '../ImageMetadataViewer/ImageMetadataViewer';
import NextPrevImageButtons from '../NextPrevImageButtons'; import NextPrevImageButtons from '../NextPrevImageButtons';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { FaImage } from 'react-icons/fa';
export const imagesSelector = createSelector( export const imagesSelector = createSelector(
[stateSelector, selectLastSelectedImage], [stateSelector, selectLastSelectedImage],
@ -93,12 +93,7 @@ const CurrentImagePreview = () => {
] ]
); );
const { const { currentData: imageDTO } = useGetImageDTOQuery(imageName ?? skipToken);
currentData: imageDTO,
isLoading,
isError,
isSuccess,
} = useGetImageDTOQuery(imageName ?? skipToken);
const draggableData = useMemo<TypesafeDraggableData | undefined>(() => { const draggableData = useMemo<TypesafeDraggableData | undefined>(() => {
if (imageDTO) { if (imageDTO) {

View File

@ -1,9 +1,7 @@
import { import {
Box, Box,
Button,
ButtonGroup, ButtonGroup,
Flex, Flex,
Spacer,
Tab, Tab,
TabList, TabList,
Tabs, Tabs,
@ -14,16 +12,16 @@ import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIButton from 'common/components/IAIButton';
import { memo, useCallback, useRef } from 'react'; import { memo, useCallback, useRef } from 'react';
import { FaImages, FaServer } from 'react-icons/fa';
import { galleryViewChanged } from '../store/gallerySlice';
import BoardsList from './Boards/BoardsList/BoardsList'; import BoardsList from './Boards/BoardsList/BoardsList';
import GalleryBoardName from './GalleryBoardName'; import GalleryBoardName from './GalleryBoardName';
import GalleryPinButton from './GalleryPinButton'; import GalleryPinButton from './GalleryPinButton';
import GallerySettingsPopover from './GallerySettingsPopover'; import GallerySettingsPopover from './GallerySettingsPopover';
import BatchImageGrid from './ImageGrid/BatchImageGrid'; import BatchImageGrid from './ImageGrid/BatchImageGrid';
import GalleryImageGrid from './ImageGrid/GalleryImageGrid'; import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
import IAIButton from 'common/components/IAIButton';
import { FaImages, FaServer } from 'react-icons/fa';
import { galleryViewChanged } from '../store/gallerySlice';
const selector = createSelector( const selector = createSelector(
[stateSelector], [stateSelector],

View File

@ -8,13 +8,8 @@ import IAIDndImage from 'common/components/IAIDndImage';
import IAIErrorLoadingImageFallback from 'common/components/IAIErrorLoadingImageFallback'; import IAIErrorLoadingImageFallback from 'common/components/IAIErrorLoadingImageFallback';
import IAIFillSkeleton from 'common/components/IAIFillSkeleton'; import IAIFillSkeleton from 'common/components/IAIFillSkeleton';
import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu'; import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
import { import { imagesRemovedFromBatch } from 'features/gallery/store/gallerySlice';
imageRangeEndSelected, import { memo, useCallback, useMemo } from 'react';
imageSelected,
imageSelectionToggled,
imagesRemovedFromBatch,
} from 'features/gallery/store/gallerySlice';
import { MouseEvent, memo, useCallback, useMemo } from 'react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
const makeSelector = (image_name: string) => const makeSelector = (image_name: string) =>
@ -39,7 +34,6 @@ const BatchImage = (props: BatchImageProps) => {
currentData: imageDTO, currentData: imageDTO,
isLoading, isLoading,
isError, isError,
isSuccess,
} = useGetImageDTOQuery(imageName); } = useGetImageDTOQuery(imageName);
const selector = useMemo(() => makeSelector(imageName), [imageName]); const selector = useMemo(() => makeSelector(imageName), [imageName]);
@ -49,18 +43,18 @@ const BatchImage = (props: BatchImageProps) => {
dispatch(imagesRemovedFromBatch([imageName])); dispatch(imagesRemovedFromBatch([imageName]));
}, [dispatch, imageName]); }, [dispatch, imageName]);
const handleClick = useCallback( // const handleClick = useCallback(
(e: MouseEvent<HTMLDivElement>) => { // (e: MouseEvent<HTMLDivElement>) => {
if (e.shiftKey) { // if (e.shiftKey) {
dispatch(imageRangeEndSelected(imageName)); // dispatch(imageRangeEndSelected(imageName));
} else if (e.ctrlKey || e.metaKey) { // } else if (e.ctrlKey || e.metaKey) {
dispatch(imageSelectionToggled(imageName)); // dispatch(imageSelectionToggled(imageName));
} else { // } else {
dispatch(imageSelected(imageName)); // dispatch(imageSelected(imageName));
} // }
}, // },
[dispatch, imageName] // [dispatch, imageName]
); // );
const draggableData = useMemo<TypesafeDraggableData | undefined>(() => { const draggableData = useMemo<TypesafeDraggableData | undefined>(() => {
if (selectionCount > 1) { if (selectionCount > 1) {
@ -105,7 +99,7 @@ const BatchImage = (props: BatchImageProps) => {
}} }}
> >
<IAIDndImage <IAIDndImage
onClick={handleClick} // onClick={handleClick}
imageDTO={imageDTO} imageDTO={imageDTO}
draggableData={draggableData} draggableData={draggableData}
isSelected={isSelected} isSelected={isSelected}

View File

@ -6,7 +6,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import IAIFillSkeleton from 'common/components/IAIFillSkeleton'; import IAIFillSkeleton from 'common/components/IAIFillSkeleton';
import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
import { imageSelected } from 'features/gallery/store/gallerySlice'; import { imageSelected } from 'features/gallery/store/gallerySlice';
import { imageToDeleteSelected } from 'features/imageDeletion/store/imageDeletionSlice'; import { imageToDeleteSelected } from 'features/imageDeletion/store/imageDeletionSlice';
import { MouseEvent, memo, useCallback, useMemo } from 'react'; import { MouseEvent, memo, useCallback, useMemo } from 'react';
@ -36,8 +35,7 @@ const GalleryImage = (props: HoverableImageProps) => {
const { isSelected, selectionCount, selection } = const { isSelected, selectionCount, selection } =
useAppSelector(localSelector); useAppSelector(localSelector);
const handleClick = useCallback( const handleClick = useCallback(() => {
(e: MouseEvent<HTMLDivElement>) => {
// disable multiselect for now // disable multiselect for now
// if (e.shiftKey) { // if (e.shiftKey) {
// dispatch(imageRangeEndSelected(imageName)); // dispatch(imageRangeEndSelected(imageName));
@ -47,9 +45,7 @@ const GalleryImage = (props: HoverableImageProps) => {
// dispatch(imageSelected(imageName)); // dispatch(imageSelected(imageName));
// } // }
dispatch(imageSelected(imageName)); dispatch(imageSelected(imageName));
}, }, [dispatch, imageName]);
[dispatch, imageName]
);
const handleDelete = useCallback( const handleDelete = useCallback(
(e: MouseEvent<HTMLButtonElement>) => { (e: MouseEvent<HTMLButtonElement>) => {

View File

@ -19,8 +19,10 @@ export const gallerySlice = createSlice({
name: 'gallery', name: 'gallery',
initialState: initialGalleryState, initialState: initialGalleryState,
reducers: { reducers: {
imageRangeEndSelected: (state, action: PayloadAction<string>) => { imageRangeEndSelected: () => {
// TODO: multiselect // TODO
},
// imageRangeEndSelected: (state, action: PayloadAction<string>) => {
// const rangeEndImageName = action.payload; // const rangeEndImageName = action.payload;
// const lastSelectedImage = state.selection[state.selection.length - 1]; // const lastSelectedImage = state.selection[state.selection.length - 1];
// const filteredImages = selectFilteredImagesLocal(state); // const filteredImages = selectFilteredImagesLocal(state);
@ -39,8 +41,11 @@ export const gallerySlice = createSlice({
// .map((i) => i.image_name); // .map((i) => i.image_name);
// state.selection = uniq(state.selection.concat(imagesToSelect)); // state.selection = uniq(state.selection.concat(imagesToSelect));
// } // }
// },
imageSelectionToggled: () => {
// TODO
}, },
imageSelectionToggled: (state, action: PayloadAction<string>) => { // imageSelectionToggled: (state, action: PayloadAction<string>) => {
// TODO: multiselect // TODO: multiselect
// if ( // if (
// state.selection.includes(action.payload) && // state.selection.includes(action.payload) &&
@ -52,7 +57,6 @@ export const gallerySlice = createSlice({
// } else { // } else {
// state.selection = uniq(state.selection.concat(action.payload)); // state.selection = uniq(state.selection.concat(action.payload));
// } // }
},
imageSelected: (state, action: PayloadAction<string | null>) => { imageSelected: (state, action: PayloadAction<string | null>) => {
state.selection = action.payload ? [action.payload] : []; state.selection = action.payload ? [action.payload] : [];
}, },

View File

@ -7,10 +7,8 @@ import { FaList } from 'react-icons/fa';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const ArrayInputFieldComponent = ( const ArrayInputFieldComponent = (
props: FieldComponentProps<ArrayInputFieldValue, ArrayInputFieldTemplate> _props: FieldComponentProps<ArrayInputFieldValue, ArrayInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return <FaList />; return <FaList />;
}; };

View File

@ -6,10 +6,8 @@ import { memo } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const ClipInputFieldComponent = ( const ClipInputFieldComponent = (
props: FieldComponentProps<ClipInputFieldValue, ClipInputFieldTemplate> _props: FieldComponentProps<ClipInputFieldValue, ClipInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return null; return null;
}; };

View File

@ -6,13 +6,11 @@ import { memo } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const ConditioningInputFieldComponent = ( const ConditioningInputFieldComponent = (
props: FieldComponentProps< _props: FieldComponentProps<
ConditioningInputFieldValue, ConditioningInputFieldValue,
ConditioningInputFieldTemplate ConditioningInputFieldTemplate
> >
) => { ) => {
const { nodeId, field } = props;
return null; return null;
}; };

View File

@ -6,10 +6,8 @@ import { memo } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const ControlInputFieldComponent = ( const ControlInputFieldComponent = (
props: FieldComponentProps<ControlInputFieldValue, ControlInputFieldTemplate> _props: FieldComponentProps<ControlInputFieldValue, ControlInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return null; return null;
}; };

View File

@ -10,7 +10,6 @@ import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam'; import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam';
import { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models'; import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
@ -23,7 +22,6 @@ const ControlNetModelInputFieldComponent = (
const { nodeId, field } = props; const { nodeId, field } = props;
const controlNetModel = field.value; const controlNetModel = field.value;
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation();
const { data: controlNetModels } = useGetControlNetModelsQuery(); const { data: controlNetModels } = useGetControlNetModelsQuery();

View File

@ -1,25 +1,19 @@
import { useAppDispatch } from 'app/store/storeHooks';
import { fieldValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
ImageCollectionInputFieldTemplate, ImageCollectionInputFieldTemplate,
ImageCollectionInputFieldValue, ImageCollectionInputFieldValue,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo, useCallback } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
import IAIDndImage from 'common/components/IAIDndImage';
import { ImageDTO } from 'services/api/types';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { skipToken } from '@reduxjs/toolkit/dist/query';
import { uniq, uniqBy } from 'lodash-es';
import { import {
NodesMultiImageDropData, NodesMultiImageDropData,
isValidDrop, isValidDrop,
useDroppable, useDroppable,
} from 'app/components/ImageDnd/typesafeDnd'; } from 'app/components/ImageDnd/typesafeDnd';
import IAIDndImage from 'common/components/IAIDndImage';
import IAIDropOverlay from 'common/components/IAIDropOverlay'; import IAIDropOverlay from 'common/components/IAIDropOverlay';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { FieldComponentProps } from './types';
const ImageCollectionInputFieldComponent = ( const ImageCollectionInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<
@ -29,20 +23,20 @@ const ImageCollectionInputFieldComponent = (
) => { ) => {
const { nodeId, field } = props; const { nodeId, field } = props;
const dispatch = useAppDispatch(); // const dispatch = useAppDispatch();
const handleDrop = useCallback( // const handleDrop = useCallback(
({ image_name }: ImageDTO) => { // ({ image_name }: ImageDTO) => {
dispatch( // dispatch(
fieldValueChanged({ // fieldValueChanged({
nodeId, // nodeId,
fieldName: field.name, // fieldName: field.name,
value: uniqBy([...(field.value ?? []), { image_name }], 'image_name'), // value: uniqBy([...(field.value ?? []), { image_name }], 'image_name'),
}) // })
); // );
}, // },
[dispatch, field.name, field.value, nodeId] // [dispatch, field.name, field.value, nodeId]
); // );
const droppableData: NodesMultiImageDropData = { const droppableData: NodesMultiImageDropData = {
id: `node-${nodeId}-${field.name}`, id: `node-${nodeId}-${field.name}`,
@ -54,21 +48,20 @@ const ImageCollectionInputFieldComponent = (
isOver, isOver,
setNodeRef: setDroppableRef, setNodeRef: setDroppableRef,
active, active,
over,
} = useDroppable({ } = useDroppable({
id: `node_${nodeId}`, id: `node_${nodeId}`,
data: droppableData, data: droppableData,
}); });
const handleReset = useCallback(() => { // const handleReset = useCallback(() => {
dispatch( // dispatch(
fieldValueChanged({ // fieldValueChanged({
nodeId, // nodeId,
fieldName: field.name, // fieldName: field.name,
value: undefined, // value: undefined,
}) // })
); // );
}, [dispatch, field.name, nodeId]); // }, [dispatch, field.name, nodeId]);
return ( return (
<Flex <Flex

View File

@ -1,22 +1,20 @@
import { useAppDispatch } from 'app/store/storeHooks';
import { fieldValueChanged } from 'features/nodes/store/nodesSlice';
import {
ImageInputFieldTemplate,
ImageInputFieldValue,
} from 'features/nodes/types/types';
import { memo, useCallback, useMemo } from 'react';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/dist/query'; import { skipToken } from '@reduxjs/toolkit/dist/query';
import { import {
TypesafeDraggableData, TypesafeDraggableData,
TypesafeDroppableData, TypesafeDroppableData,
} from 'app/components/ImageDnd/typesafeDnd'; } from 'app/components/ImageDnd/typesafeDnd';
import { useAppDispatch } from 'app/store/storeHooks';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import { fieldValueChanged } from 'features/nodes/store/nodesSlice';
import {
ImageInputFieldTemplate,
ImageInputFieldValue,
} from 'features/nodes/types/types';
import { memo, useCallback, useMemo } from 'react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { FieldComponentProps } from './types';
import { PostUploadAction } from 'services/api/types'; import { PostUploadAction } from 'services/api/types';
import { FieldComponentProps } from './types';
const ImageInputFieldComponent = ( const ImageInputFieldComponent = (
props: FieldComponentProps<ImageInputFieldValue, ImageInputFieldTemplate> props: FieldComponentProps<ImageInputFieldValue, ImageInputFieldTemplate>
@ -25,12 +23,9 @@ const ImageInputFieldComponent = (
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { const { currentData: imageDTO } = useGetImageDTOQuery(
currentData: imageDTO, field.value?.image_name ?? skipToken
isLoading, );
isError,
isSuccess,
} = useGetImageDTOQuery(field.value?.image_name ?? skipToken);
const handleReset = useCallback(() => { const handleReset = useCallback(() => {
dispatch( dispatch(

View File

@ -7,10 +7,8 @@ import { FaAddressCard } from 'react-icons/fa';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const ItemInputFieldComponent = ( const ItemInputFieldComponent = (
props: FieldComponentProps<ItemInputFieldValue, ItemInputFieldTemplate> _props: FieldComponentProps<ItemInputFieldValue, ItemInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return <FaAddressCard />; return <FaAddressCard />;
}; };

View File

@ -6,10 +6,8 @@ import { memo } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const LatentsInputFieldComponent = ( const LatentsInputFieldComponent = (
props: FieldComponentProps<LatentsInputFieldValue, LatentsInputFieldTemplate> _props: FieldComponentProps<LatentsInputFieldValue, LatentsInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return null; return null;
}; };

View File

@ -6,9 +6,8 @@ import { memo } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const UNetInputFieldComponent = ( const UNetInputFieldComponent = (
props: FieldComponentProps<UNetInputFieldValue, UNetInputFieldTemplate> _props: FieldComponentProps<UNetInputFieldValue, UNetInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return null; return null;
}; };

View File

@ -6,9 +6,8 @@ import { memo } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const VaeInputFieldComponent = ( const VaeInputFieldComponent = (
props: FieldComponentProps<VaeInputFieldValue, VaeInputFieldTemplate> _props: FieldComponentProps<VaeInputFieldValue, VaeInputFieldTemplate>
) => { ) => {
const { nodeId, field } = props;
return null; return null;
}; };

View File

@ -11,7 +11,6 @@ import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToVAEModelParam } from 'features/parameters/util/modelIdToVAEModelParam'; import { modelIdToVAEModelParam } from 'features/parameters/util/modelIdToVAEModelParam';
import { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useGetVaeModelsQuery } from 'services/api/endpoints/models'; import { useGetVaeModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
@ -24,7 +23,6 @@ const VaeModelInputFieldComponent = (
const { nodeId, field } = props; const { nodeId, field } = props;
const vae = field.value; const vae = field.value;
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation();
const { data: vaeModels } = useGetVaeModelsQuery(); const { data: vaeModels } = useGetVaeModelsQuery();
const data = useMemo(() => { const data = useMemo(() => {

View File

@ -1,26 +1,25 @@
import { Box, Flex } from '@chakra-ui/layout'; import { Box, Flex } from '@chakra-ui/layout';
import { Tooltip } from '@chakra-ui/tooltip';
import { useAppToaster } from 'app/components/Toaster';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIInput from 'common/components/IAIInput'; import IAIInput from 'common/components/IAIInput';
import { useBuildInvocation } from 'features/nodes/hooks/useBuildInvocation';
import { InvocationTemplate } from 'features/nodes/types/types';
import Fuse from 'fuse.js';
import { map } from 'lodash-es'; import { map } from 'lodash-es';
import { import {
ChangeEvent, ChangeEvent,
FocusEvent, FocusEvent,
KeyboardEvent, KeyboardEvent,
memo,
ReactNode, ReactNode,
memo,
useCallback, useCallback,
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
import { Tooltip } from '@chakra-ui/tooltip';
import { AnyInvocationType } from 'services/events/types'; import { AnyInvocationType } from 'services/events/types';
import { useBuildInvocation } from 'features/nodes/hooks/useBuildInvocation';
import { addToast } from 'features/system/store/systemSlice';
import { nodeAdded } from '../../store/nodesSlice'; import { nodeAdded } from '../../store/nodesSlice';
import Fuse from 'fuse.js';
import { InvocationTemplate } from 'features/nodes/types/types';
import { useAppToaster } from 'app/components/Toaster';
interface NodeListItemProps { interface NodeListItemProps {
title: string; title: string;

View File

@ -1,93 +1,94 @@
import { useCallback } from 'react'; // TODO: enable this at some point
import { Connection, Node, useReactFlow } from 'reactflow'; // import graphlib from '@dagrejs/graphlib';
import graphlib from '@dagrejs/graphlib'; // import { useCallback } from 'react';
import { InvocationValue } from '../types/types'; // import { Connection, Node, useReactFlow } from 'reactflow';
// import { InvocationValue } from '../types/types';
export const useIsValidConnection = () => { // export const useIsValidConnection = () => {
const flow = useReactFlow(); // const flow = useReactFlow();
// Check if an in-progress connection is valid // // Check if an in-progress connection is valid
const isValidConnection = useCallback( // const isValidConnection = useCallback(
({ source, sourceHandle, target, targetHandle }: Connection): boolean => { // ({ source, sourceHandle, target, targetHandle }: Connection): boolean => {
const edges = flow.getEdges(); // const edges = flow.getEdges();
const nodes = flow.getNodes(); // const nodes = flow.getNodes();
return true; // // Connection must have valid targets
// if (!(source && sourceHandle && target && targetHandle)) {
// return false;
// }
// // Connection must have valid targets // // Connection is invalid if target already has a connection
// if (!(source && sourceHandle && target && targetHandle)) { // if (
// return false; // edges.find((edge) => {
// } // return edge.target === target && edge.targetHandle === targetHandle;
// })
// ) {
// return false;
// }
// // Connection is invalid if target already has a connection // // Find the source and target nodes
// if ( // const sourceNode = flow.getNode(source) as Node<InvocationValue>;
// edges.find((edge) => {
// return edge.target === target && edge.targetHandle === targetHandle;
// })
// ) {
// return false;
// }
// // Find the source and target nodes // const targetNode = flow.getNode(target) as Node<InvocationValue>;
// const sourceNode = flow.getNode(source) as Node<InvocationValue>;
// const targetNode = flow.getNode(target) as Node<InvocationValue>; // // Conditional guards against undefined nodes/handles
// if (!(sourceNode && targetNode && sourceNode.data && targetNode.data)) {
// return false;
// }
// // Conditional guards against undefined nodes/handles // // Connection types must be the same for a connection
// if (!(sourceNode && targetNode && sourceNode.data && targetNode.data)) { // if (
// return false; // sourceNode.data.outputs[sourceHandle].type !==
// } // targetNode.data.inputs[targetHandle].type
// ) {
// return false;
// }
// // Connection types must be the same for a connection // // Graphs much be acyclic (no loops!)
// if (
// sourceNode.data.outputs[sourceHandle].type !==
// targetNode.data.inputs[targetHandle].type
// ) {
// return false;
// }
// // Graphs much be acyclic (no loops!) // /**
// * TODO: use `graphlib.alg.findCycles()` to identify strong connections
// *
// * this validation func only runs when the cursor hits the second handle of the connection,
// * and only on that second handle - so it cannot tell us exhaustively which connections
// * are valid.
// *
// * ideally, we check when the connection starts to calculate all invalid handles at once.
// *
// * requires making a new graphlib graph - and calling `findCycles()` - for each potential
// * handle. instead of using the `isValidConnection` prop, it would use the `onConnectStart`
// * prop.
// *
// * the strong connections should be stored in global state.
// *
// * then, `isValidConnection` would simple loop through the strong connections and if the
// * source and target are in a single strong connection, return false.
// *
// * and also, we can use this knowledge to style every handle when a connection starts,
// * which is otherwise not possible.
// */
// /** // // build a graphlib graph
// * TODO: use `graphlib.alg.findCycles()` to identify strong connections // const g = new graphlib.Graph();
// *
// * this validation func only runs when the cursor hits the second handle of the connection,
// * and only on that second handle - so it cannot tell us exhaustively which connections
// * are valid.
// *
// * ideally, we check when the connection starts to calculate all invalid handles at once.
// *
// * requires making a new graphlib graph - and calling `findCycles()` - for each potential
// * handle. instead of using the `isValidConnection` prop, it would use the `onConnectStart`
// * prop.
// *
// * the strong connections should be stored in global state.
// *
// * then, `isValidConnection` would simple loop through the strong connections and if the
// * source and target are in a single strong connection, return false.
// *
// * and also, we can use this knowledge to style every handle when a connection starts,
// * which is otherwise not possible.
// */
// // build a graphlib graph // nodes.forEach((n) => {
// const g = new graphlib.Graph(); // g.setNode(n.id);
// });
// nodes.forEach((n) => { // edges.forEach((e) => {
// g.setNode(n.id); // g.setEdge(e.source, e.target);
// }); // });
// edges.forEach((e) => { // // Add the candidate edge to the graph
// g.setEdge(e.source, e.target); // g.setEdge(source, target);
// });
// // Add the candidate edge to the graph // return graphlib.alg.isAcyclic(g);
// g.setEdge(source, target); // },
// [flow]
// );
// return graphlib.alg.isAcyclic(g); // return isValidConnection;
}, // };
[flow]
);
return isValidConnection; export const useIsValidConnection = () => () => true;
};

View File

@ -417,14 +417,17 @@ export const getFieldType = (
// if schemaObject has no type, then it should have one of allOf, anyOf, oneOf // if schemaObject has no type, then it should have one of allOf, anyOf, oneOf
if (schemaObject.allOf) { if (schemaObject.allOf) {
rawFieldType = refObjectToFieldType( rawFieldType = refObjectToFieldType(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
schemaObject.allOf![0] as OpenAPIV3.ReferenceObject schemaObject.allOf![0] as OpenAPIV3.ReferenceObject
); );
} else if (schemaObject.anyOf) { } else if (schemaObject.anyOf) {
rawFieldType = refObjectToFieldType( rawFieldType = refObjectToFieldType(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
schemaObject.anyOf![0] as OpenAPIV3.ReferenceObject schemaObject.anyOf![0] as OpenAPIV3.ReferenceObject
); );
} else if (schemaObject.oneOf) { } else if (schemaObject.oneOf) {
rawFieldType = refObjectToFieldType( rawFieldType = refObjectToFieldType(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
schemaObject.oneOf![0] as OpenAPIV3.ReferenceObject schemaObject.oneOf![0] as OpenAPIV3.ReferenceObject
); );
} }
@ -547,6 +550,7 @@ export const buildOutputFieldTemplates = (
const outputSchemaName = refObject.$ref.split('/').slice(-1)[0]; const outputSchemaName = refObject.$ref.split('/').slice(-1)[0];
// get the output schema itself // get the output schema itself
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const outputSchema = openAPI.components!.schemas![outputSchemaName]; const outputSchema = openAPI.components!.schemas![outputSchemaName];
if (isSchemaObject(outputSchema)) { if (isSchemaObject(outputSchema)) {

View File

@ -37,7 +37,7 @@ export const buildNodesGraph = (state: RootState): Graph => {
// Reduce the node editor nodes into invocation graph nodes // Reduce the node editor nodes into invocation graph nodes
const parsedNodes = filteredNodes.reduce<NonNullable<Graph['nodes']>>( const parsedNodes = filteredNodes.reduce<NonNullable<Graph['nodes']>>(
(nodesAccumulator, node, nodeIndex) => { (nodesAccumulator, node) => {
const { id, data } = node; const { id, data } = node;
const { type, inputs } = data; const { type, inputs } = data;
@ -50,7 +50,7 @@ export const buildNodesGraph = (state: RootState): Graph => {
return inputsAccumulator; return inputsAccumulator;
}, },
{} as Record<Exclude<string, 'id' | 'type'>, any> {} as Record<Exclude<string, 'id' | 'type'>, unknown>
); );
// Build this specific node // Build this specific node
@ -72,7 +72,7 @@ export const buildNodesGraph = (state: RootState): Graph => {
// Reduce the node editor edges into invocation graph edges // Reduce the node editor edges into invocation graph edges
const parsedEdges = edges.reduce<NonNullable<Graph['edges']>>( const parsedEdges = edges.reduce<NonNullable<Graph['edges']>>(
(edgesAccumulator, edge, edgeIndex) => { (edgesAccumulator, edge) => {
const { source, target, sourceHandle, targetHandle } = edge; const { source, target, sourceHandle, targetHandle } = edge;
// Format the edges and add to the edges array // Format the edges and add to the edges array

View File

@ -24,6 +24,7 @@ const invocationDenylist = [
export const parseSchema = (openAPI: OpenAPIV3.Document) => { export const parseSchema = (openAPI: OpenAPIV3.Document) => {
// filter out non-invocation schemas, plus some tricky invocations for now // filter out non-invocation schemas, plus some tricky invocations for now
const filteredSchemas = filter( const filteredSchemas = filter(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
openAPI.components!.schemas, openAPI.components!.schemas,
(schema, key) => (schema, key) =>
key.includes('Invocation') && key.includes('Invocation') &&
@ -102,6 +103,7 @@ export const parseSchema = (openAPI: OpenAPIV3.Document) => {
// some special handling is needed for collect, iterate and range nodes // some special handling is needed for collect, iterate and range nodes
if (type === 'iterate') { if (type === 'iterate') {
// this is guaranteed to be a SchemaObject // this is guaranteed to be a SchemaObject
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const iterationOutput = openAPI.components!.schemas![ const iterationOutput = openAPI.components!.schemas![
'IterateInvocationOutput' 'IterateInvocationOutput'
] as OpenAPIV3.SchemaObject; ] as OpenAPIV3.SchemaObject;

View File

@ -15,7 +15,6 @@ import { getValidControlNets } from 'features/controlNet/util/getValidControlNet
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { map } from 'lodash-es'; import { map } from 'lodash-es';
import { Fragment, memo, useCallback } from 'react'; import { Fragment, memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaPlus } from 'react-icons/fa'; import { FaPlus } from 'react-icons/fa';
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models'; import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@ -38,7 +37,6 @@ const selector = createSelector(
); );
const ParamControlNetCollapse = () => { const ParamControlNetCollapse = () => {
const { t } = useTranslation();
const { controlNetsArray, activeLabel } = useAppSelector(selector); const { controlNetsArray, activeLabel } = useAppSelector(selector);
const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled; const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();

View File

@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next';
const selector = createSelector( const selector = createSelector(
[stateSelector], [stateSelector],
({ generation, hotkeys, config, ui }) => { ({ generation, hotkeys, config }) => {
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } = const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
config.sd.width; config.sd.width;
const { width, aspectRatio } = generation; const { width, aspectRatio } = generation;

View File

@ -27,12 +27,9 @@ const selector = createSelector(
const InitialImage = () => { const InitialImage = () => {
const { initialImage } = useAppSelector(selector); const { initialImage } = useAppSelector(selector);
const { const { currentData: imageDTO } = useGetImageDTOQuery(
currentData: imageDTO, initialImage?.imageName ?? skipToken
isLoading, );
isError,
isSuccess,
} = useGetImageDTOQuery(initialImage?.imageName ?? skipToken);
const draggableData = useMemo<TypesafeDraggableData | undefined>(() => { const draggableData = useMemo<TypesafeDraggableData | undefined>(() => {
if (imageDTO) { if (imageDTO) {

View File

@ -5,7 +5,6 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice'; import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice';
import { ChangeEvent } from 'react'; import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next';
const selector = createSelector( const selector = createSelector(
stateSelector, stateSelector,
@ -23,8 +22,6 @@ export const ParamCpuNoiseToggle = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { isDisabled, shouldUseCpuNoise } = useAppSelector(selector); const { isDisabled, shouldUseCpuNoise } = useAppSelector(selector);
const { t } = useTranslation();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(shouldUseCpuNoiseChanged(e.target.checked)); dispatch(shouldUseCpuNoiseChanged(e.target.checked));

View File

@ -3,7 +3,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { setShouldUseNoiseSettings } from 'features/parameters/store/generationSlice'; import { setShouldUseNoiseSettings } from 'features/parameters/store/generationSlice';
import { ChangeEvent } from 'react'; import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next';
export const ParamNoiseToggle = () => { export const ParamNoiseToggle = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -12,8 +11,6 @@ export const ParamNoiseToggle = () => {
(state: RootState) => state.generation.shouldUseNoiseSettings (state: RootState) => state.generation.shouldUseNoiseSettings
); );
const { t } = useTranslation();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(setShouldUseNoiseSettings(e.target.checked)); dispatch(setShouldUseNoiseSettings(e.target.checked));

View File

@ -7,7 +7,6 @@ import {
ESRGANModelName, ESRGANModelName,
esrganModelNameChanged, esrganModelNameChanged,
} from 'features/parameters/store/postprocessingSlice'; } from 'features/parameters/store/postprocessingSlice';
import { useTranslation } from 'react-i18next';
export const ESRGAN_MODEL_NAMES: SelectItem[] = [ export const ESRGAN_MODEL_NAMES: SelectItem[] = [
{ {

View File

@ -3,7 +3,6 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISwitch from 'common/components/IAISwitch'; import IAISwitch from 'common/components/IAISwitch';
import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice'; import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice';
import { ChangeEvent } from 'react'; import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next';
export const ParamVariationToggle = () => { export const ParamVariationToggle = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -12,8 +11,6 @@ export const ParamVariationToggle = () => {
(state: RootState) => state.generation.shouldGenerateVariations (state: RootState) => state.generation.shouldGenerateVariations
); );
const { t } = useTranslation();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(setShouldGenerateVariations(e.target.checked)); dispatch(setShouldGenerateVariations(e.target.checked));

View File

@ -1,75 +0,0 @@
import { Flex, Text } from '@chakra-ui/react';
import { memo, useMemo } from 'react';
export const ratioToCSSString = (
ratio: AspectRatio,
orientation: Orientation
) => {
if (orientation === 'portrait') {
return `${ratio[0]}/${ratio[1]}`;
}
return `${ratio[1]}/${ratio[0]}`;
};
export const ratioToDisplayString = (
ratio: AspectRatio,
orientation: Orientation
) => {
if (orientation === 'portrait') {
return `${ratio[0]}:${ratio[1]}`;
}
return `${ratio[1]}:${ratio[0]}`;
};
type AspectRatioPreviewProps = {
ratio: AspectRatio;
orientation: Orientation;
size: string;
};
export type AspectRatio = [number, number];
export type Orientation = 'portrait' | 'landscape';
const AspectRatioPreview = (props: AspectRatioPreviewProps) => {
const { ratio, size, orientation } = props;
const ratioCSSString = useMemo(() => {
if (orientation === 'portrait') {
return `${ratio[0]}/${ratio[1]}`;
}
return `${ratio[1]}/${ratio[0]}`;
}, [ratio, orientation]);
const ratioDisplayString = useMemo(() => `${ratio[0]}:${ratio[1]}`, [ratio]);
return (
<Flex
sx={{
alignItems: 'center',
justifyContent: 'center',
w: size,
h: size,
}}
>
<Flex
sx={{
alignItems: 'center',
justifyContent: 'center',
bg: 'base.700',
color: 'base.400',
borderRadius: 'base',
aspectRatio: ratioCSSString,
objectFit: 'contain',
...(orientation === 'landscape' ? { h: 'full' } : { w: 'full' }),
}}
>
<Text sx={{ size: 'xs', userSelect: 'none' }}>
{ratioDisplayString}
</Text>
</Flex>
</Flex>
);
};
export default memo(AspectRatioPreview);

View File

@ -1,76 +0,0 @@
import { Box, Flex, FormControl, FormLabel, Select } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setWidth } from 'features/parameters/store/generationSlice';
import { memo, useState } from 'react';
import AspectRatioPreview, {
AspectRatio,
Orientation,
} from './AspectRatioPreview';
const RATIOS: AspectRatio[] = [
[1, 1],
[5, 4],
[3, 2],
[16, 10],
[16, 9],
];
RATIOS.forEach((r) => {
const float = r[0] / r[1];
console.log((512 * float) / 8);
});
const dimensionsSettingsSelector = createSelector(
(state: RootState) => state.generation,
(generation) => {
const { width, height } = generation;
return { width, height };
}
);
const DimensionsSettings = () => {
const { width, height } = useAppSelector(dimensionsSettingsSelector);
const dispatch = useAppDispatch();
const [ratioIndex, setRatioIndex] = useState(4);
const [orientation, setOrientation] = useState<Orientation>('portrait');
return (
<Flex gap={3}>
<Box flexShrink={0}>
<AspectRatioPreview
ratio={RATIOS[ratioIndex]}
orientation={orientation}
size="4rem"
/>
</Box>
<FormControl>
<FormLabel>Aspect Ratio</FormLabel>
<Select
onChange={(e) => {
setRatioIndex(Number(e.target.value));
}}
>
{RATIOS.map((r, i) => (
<option key={r.join()} value={i}>{`${r[0]}:${r[1]}`}</option>
))}
</Select>
</FormControl>
<IAISlider
label="Size"
value={width}
min={64}
max={2048}
step={8}
onChange={(v) => {
dispatch(setWidth(v));
}}
/>
</Flex>
);
};
export default memo(DimensionsSettings);

View File

@ -3,7 +3,6 @@ import { useAppDispatch } from 'app/store/storeHooks';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { UnsafeImageMetadata } from 'services/api/endpoints/images'; import { UnsafeImageMetadata } from 'services/api/endpoints/images';
import { isImageField } from 'services/api/guards';
import { ImageDTO } from 'services/api/types'; import { ImageDTO } from 'services/api/types';
import { initialImageSelected, modelSelected } from '../store/actions'; import { initialImageSelected, modelSelected } from '../store/actions';
import { import {

View File

@ -266,7 +266,7 @@ export const generationSlice = createSlice({
const defaultModel = action.payload.sd?.defaultModel; const defaultModel = action.payload.sd?.defaultModel;
if (defaultModel && !state.model) { if (defaultModel && !state.model) {
const [base_model, model_type, model_name] = defaultModel.split('/'); const [base_model, _model_type, model_name] = defaultModel.split('/');
const result = zMainModel.safeParse({ const result = zMainModel.safeParse({
model_name, model_name,

View File

@ -6,7 +6,7 @@ export const modelIdToControlNetModelParam = (
controlNetModelId: string controlNetModelId: string
): ControlNetModelField | undefined => { ): ControlNetModelField | undefined => {
const log = logger('models'); const log = logger('models');
const [base_model, model_type, model_name] = controlNetModelId.split('/'); const [base_model, _model_type, model_name] = controlNetModelId.split('/');
const result = zControlNetModel.safeParse({ const result = zControlNetModel.safeParse({
base_model, base_model,

View File

@ -6,7 +6,7 @@ export const modelIdToLoRAModelParam = (
): LoRAModelParam | undefined => { ): LoRAModelParam | undefined => {
const log = logger('models'); const log = logger('models');
const [base_model, model_type, model_name] = loraModelId.split('/'); const [base_model, _model_type, model_name] = loraModelId.split('/');
const result = zLoRAModel.safeParse({ const result = zLoRAModel.safeParse({
base_model, base_model,

View File

@ -8,7 +8,7 @@ export const modelIdToMainModelParam = (
mainModelId: string mainModelId: string
): MainModelParam | undefined => { ): MainModelParam | undefined => {
const log = logger('models'); const log = logger('models');
const [base_model, model_type, model_name] = mainModelId.split('/'); const [base_model, _model_type, model_name] = mainModelId.split('/');
const result = zMainModel.safeParse({ const result = zMainModel.safeParse({
base_model, base_model,

View File

@ -5,7 +5,7 @@ export const modelIdToVAEModelParam = (
vaeModelId: string vaeModelId: string
): VaeModelParam | undefined => { ): VaeModelParam | undefined => {
const log = logger('models'); const log = logger('models');
const [base_model, model_type, model_name] = vaeModelId.split('/'); const [base_model, _model_type, model_name] = vaeModelId.split('/');
const result = zVaeModel.safeParse({ const result = zVaeModel.safeParse({
base_model, base_model,

View File

@ -1,15 +1,14 @@
import { Flex, Icon, Text } from '@chakra-ui/react'; import { Flex, Icon, Text } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { isEqual } from 'lodash-es'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { useTranslation } from 'react-i18next';
import { systemSelector } from '../store/systemSelectors';
import { ResourceKey } from 'i18next';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { ResourceKey } from 'i18next';
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { FaCircle } from 'react-icons/fa'; import { FaCircle } from 'react-icons/fa';
import { useHoverDirty } from 'react-use'; import { useHoverDirty } from 'react-use';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { systemSelector } from '../store/systemSelectors';
const statusIndicatorSelector = createSelector( const statusIndicatorSelector = createSelector(
systemSelector, systemSelector,

View File

@ -5,7 +5,6 @@ import { PropsWithChildren, memo } from 'react';
import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants'; import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
import { uiSelector } from '../store/uiSelectors'; import { uiSelector } from '../store/uiSelectors';
import PinParametersPanelButton from './PinParametersPanelButton'; import PinParametersPanelButton from './PinParametersPanelButton';
import OverlayScrollable from './common/OverlayScrollable';
const selector = createSelector(uiSelector, (ui) => { const selector = createSelector(uiSelector, (ui) => {
const { shouldPinParametersPanel, shouldShowParametersPanel } = ui; const { shouldPinParametersPanel, shouldShowParametersPanel } = ui;

View File

@ -19,18 +19,17 @@ const selector = createSelector(
[uiSelector, generationSelector], [uiSelector, generationSelector],
(ui, generation) => { (ui, generation) => {
const { shouldUseSliders } = ui; const { shouldUseSliders } = ui;
const { shouldFitToWidthHeight, shouldRandomizeSeed } = generation; const { shouldRandomizeSeed } = generation;
const activeLabel = !shouldRandomizeSeed ? 'Manual Seed' : undefined; const activeLabel = !shouldRandomizeSeed ? 'Manual Seed' : undefined;
return { shouldUseSliders, shouldFitToWidthHeight, activeLabel }; return { shouldUseSliders, activeLabel };
}, },
defaultSelectorOptions defaultSelectorOptions
); );
const ImageToImageTabCoreParameters = () => { const ImageToImageTabCoreParameters = () => {
const { shouldUseSliders, shouldFitToWidthHeight, activeLabel } = const { shouldUseSliders, activeLabel } = useAppSelector(selector);
useAppSelector(selector);
return ( return (
<IAICollapse <IAICollapse

View File

@ -1,12 +1,11 @@
import i18n from 'i18next'; import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend'; import Backend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
// TODO: Disabled for IDE performance issues with our translation JSON // TODO: Disabled for IDE performance issues with our translation JSON
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
import translationEN from '../public/locales/en.json'; import translationEN from '../public/locales/en.json';
import { LOCALSTORAGE_PREFIX } from 'app/store/constants';
if (import.meta.env.MODE === 'package') { if (import.meta.env.MODE === 'package') {
i18n.use(initReactI18next).init({ i18n.use(initReactI18next).init({

View File

@ -50,7 +50,9 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
socket.on('connect_error', (error) => { socket.on('connect_error', (error) => {
if (error && error.message) { if (error && error.message) {
const data: string | undefined = (error as any).data; const data: string | undefined = (
error as unknown as { data: string | undefined }
).data;
if (data === 'ERR_UNAUTHENTICATED') { if (data === 'ERR_UNAUTHENTICATED') {
dispatch( dispatch(
addToast( addToast(

View File

@ -71,9 +71,13 @@ const invokeAIOutline = defineStyle((props) => {
border: '1px solid', border: '1px solid',
borderColor: c === 'gray' ? borderColor : 'currentColor', borderColor: c === 'gray' ? borderColor : 'currentColor',
'.chakra-button__group[data-attached][data-orientation=horizontal] > &:not(:last-of-type)': '.chakra-button__group[data-attached][data-orientation=horizontal] > &:not(:last-of-type)':
{ marginEnd: '-1px' }, {
marginEnd: '-1px',
},
'.chakra-button__group[data-attached][data-orientation=vertical] > &:not(:last-of-type)': '.chakra-button__group[data-attached][data-orientation=vertical] > &:not(:last-of-type)':
{ marginBottom: '-1px' }, {
marginBottom: '-1px',
},
}; };
}); });

View File

@ -14,14 +14,14 @@ const invokeAIOverlay = defineStyle((props) => ({
const invokeAIDialogContainer = defineStyle({}); const invokeAIDialogContainer = defineStyle({});
const invokeAIDialog = defineStyle((props) => { const invokeAIDialog = defineStyle(() => {
return { return {
layerStyle: 'first', layerStyle: 'first',
maxH: '80vh', maxH: '80vh',
}; };
}); });
const invokeAIHeader = defineStyle((props) => { const invokeAIHeader = defineStyle(() => {
return { return {
fontWeight: '600', fontWeight: '600',
fontSize: 'lg', fontSize: 'lg',
@ -42,8 +42,8 @@ const invokeAIFooter = defineStyle({});
export const invokeAI = definePartsStyle((props) => ({ export const invokeAI = definePartsStyle((props) => ({
overlay: invokeAIOverlay(props), overlay: invokeAIOverlay(props),
dialogContainer: invokeAIDialogContainer, dialogContainer: invokeAIDialogContainer,
dialog: invokeAIDialog(props), dialog: invokeAIDialog(),
header: invokeAIHeader(props), header: invokeAIHeader(),
closeButton: invokeAICloseButton, closeButton: invokeAICloseButton,
body: invokeAIBody, body: invokeAIBody,
footer: invokeAIFooter, footer: invokeAIFooter,