From 02e4a3aa82e8862d5be277cf53a50dd3b548801a Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Thu, 22 May 2025 13:54:57 +1000
Subject: [PATCH] refactor(ui): params state zodification
---
.../components/CanvasMainPanelContent.tsx | 30 ++++++++--
.../src/features/controlLayers/store/types.ts | 58 ++++++++-----------
.../util/getScaledBoundingBoxDimensions.ts | 18 +++---
.../nodes/util/graph/graphBuilderUtils.ts | 4 +-
.../parameters/util/optimalDimension.ts | 5 +-
.../web/src/features/queue/store/readiness.ts | 3 +-
6 files changed, 65 insertions(+), 53 deletions(-)
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx
index 9ea0026b59..4bc6262c41 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx
@@ -26,6 +26,7 @@ import { CanvasToolbar } from 'features/controlLayers/components/Toolbar/CanvasT
import { Transform } from 'features/controlLayers/components/Transform/Transform';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { selectDynamicGrid, selectShowHUD } from 'features/controlLayers/store/canvasSettingsSlice';
+import { selectIsSessionStarted } from 'features/controlLayers/store/selectors';
import { memo, useCallback } from 'react';
import { PiDotsThreeOutlineVerticalFill } from 'react-icons/pi';
@@ -36,7 +37,7 @@ const FOCUS_REGION_STYLES: SystemStyleObject = {
height: 'full',
};
-const MenuContent = () => {
+const MenuContent = memo(() => {
return (
@@ -45,9 +46,31 @@ const MenuContent = () => {
);
-};
+});
+MenuContent.displayName = 'MenuContent';
export const CanvasMainPanelContent = memo(() => {
+ const isSessionStarted = useAppSelector(selectIsSessionStarted);
+
+ if (!isSessionStarted) {
+ return ;
+ }
+
+ return ;
+});
+
+CanvasMainPanelContent.displayName = 'CanvasMainPanelContent';
+
+const CanvasNoSession = memo(() => {
+ return (
+
+ FRESH CANVAS is fresh when: - No control layers - No inpaint masks - No regions - No Raster Layers
+
+ );
+});
+CanvasNoSession.displayName = 'CanvasNoSession';
+
+const CanvasActiveSession = memo(() => {
const dynamicGrid = useAppSelector(selectDynamicGrid);
const showHUD = useAppSelector(selectShowHUD);
@@ -134,5 +157,4 @@ export const CanvasMainPanelContent = memo(() => {
);
});
-
-CanvasMainPanelContent.displayName = 'CanvasMainPanelContent';
+CanvasActiveSession.displayName = 'ActiveCanvasContent';
diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts
index fca9e1a6ce..09b540f951 100644
--- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts
+++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts
@@ -540,48 +540,40 @@ export type ParamsState = z.infer;
const INITIAL_PARAMS_STATE = zParamsState.parse({});
export const getInitialParamsState = () => deepClone(INITIAL_PARAMS_STATE);
+const zInpaintMasks = z.object({
+ isHidden: z.boolean(),
+ entities: z.array(zCanvasInpaintMaskState),
+});
+const zRasterLayers = z.object({
+ isHidden: z.boolean(),
+ entities: z.array(zCanvasRasterLayerState),
+});
+const zControlLayers = z.object({
+ isHidden: z.boolean(),
+ entities: z.array(zCanvasControlLayerState),
+});
+const zRegionalGuidance = z.object({
+ isHidden: z.boolean(),
+ entities: z.array(zCanvasRegionalGuidanceState),
+});
+const zReferenceImages = z.object({
+ entities: z.array(zCanvasReferenceImageState),
+});
const zCanvasState = z.object({
_version: z.literal(3).default(3),
isSessionStarted: z.boolean().default(false),
selectedEntityIdentifier: zCanvasEntityIdentifer.nullable().default(null),
bookmarkedEntityIdentifier: zCanvasEntityIdentifer.nullable().default(null),
- inpaintMasks: z
- .object({
- isHidden: z.boolean(),
- entities: z.array(zCanvasInpaintMaskState),
- })
- .default({ isHidden: false, entities: [] }),
- rasterLayers: z
- .object({
- isHidden: z.boolean(),
- entities: z.array(zCanvasRasterLayerState),
- })
- .default({ isHidden: false, entities: [] }),
- controlLayers: z
- .object({
- isHidden: z.boolean(),
- entities: z.array(zCanvasControlLayerState),
- })
- .default({ isHidden: false, entities: [] }),
- regionalGuidance: z
- .object({
- isHidden: z.boolean(),
- entities: z.array(zCanvasRegionalGuidanceState),
- })
- .default({ isHidden: false, entities: [] }),
- referenceImages: z
- .object({
- entities: z.array(zCanvasReferenceImageState),
- })
- .default({ entities: [] }),
+ inpaintMasks: zInpaintMasks.default({ isHidden: false, entities: [] }),
+ rasterLayers: zRasterLayers.default({ isHidden: false, entities: [] }),
+ controlLayers: zControlLayers.default({ isHidden: false, entities: [] }),
+ regionalGuidance: zRegionalGuidance.default({ isHidden: false, entities: [] }),
+ referenceImages: zReferenceImages.default({ entities: [] }),
bbox: zBboxState.default({
rect: { x: 0, y: 0, width: 512, height: 512 },
aspectRatio: DEFAULT_ASPECT_RATIO_CONFIG,
scaleMethod: 'auto',
- scaledSize: {
- width: 512,
- height: 512,
- },
+ scaledSize: { width: 512, height: 512 },
modelBase: 'sd-1',
}),
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/util/getScaledBoundingBoxDimensions.ts b/invokeai/frontend/web/src/features/controlLayers/util/getScaledBoundingBoxDimensions.ts
index 3b12790f2f..5f58e77545 100644
--- a/invokeai/frontend/web/src/features/controlLayers/util/getScaledBoundingBoxDimensions.ts
+++ b/invokeai/frontend/web/src/features/controlLayers/util/getScaledBoundingBoxDimensions.ts
@@ -1,6 +1,6 @@
import { roundToMultiple } from 'common/util/roundDownToMultiple';
import type { Dimensions } from 'features/controlLayers/store/types';
-import type { MainModelBase } from 'features/nodes/types/common';
+import type { BaseModelType } from 'features/nodes/types/common';
import {
getGridSize,
getOptimalDimension,
@@ -11,16 +11,16 @@ import {
* Scales the bounding box dimensions to the optimal dimension. The optimal dimensions should be the trained dimension
* for the model. For example, 1024 for SDXL or 512 for SD1.5.
* @param dimensions The un-scaled bbox dimensions
- * @param modelBase The base model
+ * @param base The base model
*/
-export const getScaledBoundingBoxDimensions = (dimensions: Dimensions, modelBase: MainModelBase): Dimensions => {
+export const getScaledBoundingBoxDimensions = (dimensions: Dimensions, base?: BaseModelType): Dimensions => {
// Special cases: Return original if SDXL and in training dimensions
- if (modelBase === 'sdxl' && isInSDXLTrainingDimensions(dimensions.width, dimensions.height)) {
+ if (base === 'sdxl' && isInSDXLTrainingDimensions(dimensions.width, dimensions.height)) {
return { ...dimensions };
}
- const optimalDimension = getOptimalDimension(modelBase);
- const gridSize = getGridSize(modelBase);
+ const optimalDimension = getOptimalDimension(base);
+ const gridSize = getGridSize(base);
const width = roundToMultiple(dimensions.width, gridSize);
const height = roundToMultiple(dimensions.height, gridSize);
@@ -56,13 +56,13 @@ export const getScaledBoundingBoxDimensions = (dimensions: Dimensions, modelBase
* Calculate the new width and height that will fit the given aspect ratio, retaining the input area
* @param ratio The aspect ratio to calculate the new size for
* @param area The input area
- * @param modelBase The base model
+ * @param base The base model
* @returns The width and height that will fit the given aspect ratio, retaining the input area
*/
-export const calculateNewSize = (ratio: number, area: number, modelBase: MainModelBase): Dimensions => {
+export const calculateNewSize = (ratio: number, area: number, base?: BaseModelType): Dimensions => {
const exactWidth = Math.sqrt(area * ratio);
const exactHeight = exactWidth / ratio;
- const gridSize = getGridSize(modelBase);
+ const gridSize = getGridSize(base);
return {
width: roundToMultiple(exactWidth, gridSize),
diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts
index c288f80bb7..3ebe337ed0 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts
@@ -1,7 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
-import { type ParamsState, selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
-import type { CanvasState } from 'features/controlLayers/store/types';
+import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
+import type { CanvasState, ParamsState } from 'features/controlLayers/store/types';
import type { BoardField } from 'features/nodes/types/common';
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
import { buildPresetModifiedPrompt } from 'features/stylePresets/hooks/usePresetModifiedPrompts';
diff --git a/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts b/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts
index 90a5b41348..9041a87213 100644
--- a/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts
+++ b/invokeai/frontend/web/src/features/parameters/util/optimalDimension.ts
@@ -1,4 +1,3 @@
-import type { MainModelBase } from 'features/nodes/types/common';
import type { BaseModelType } from 'services/api/types';
/**
@@ -117,7 +116,7 @@ export const getIsSizeTooLarge = (width: number, height: number, optimalDimensio
* @param optimalDimension The optimal dimension
* @returns Whether the current width and height needs to be resized to the optimal dimension
*/
-export const getIsSizeOptimal = (width: number, height: number, modelBase: MainModelBase): boolean => {
- const optimalDimension = getOptimalDimension(modelBase);
+export const getIsSizeOptimal = (width: number, height: number, base?: BaseModelType): boolean => {
+ const optimalDimension = getOptimalDimension(base);
return !getIsSizeTooSmall(width, height, optimalDimension) && !getIsSizeTooLarge(width, height, optimalDimension);
};
diff --git a/invokeai/frontend/web/src/features/queue/store/readiness.ts b/invokeai/frontend/web/src/features/queue/store/readiness.ts
index a91ccbfb19..849ed380e7 100644
--- a/invokeai/frontend/web/src/features/queue/store/readiness.ts
+++ b/invokeai/frontend/web/src/features/queue/store/readiness.ts
@@ -8,10 +8,9 @@ import { useAppSelector } from 'app/store/storeHooks';
import type { AppConfig } from 'app/types/invokeai';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { useCanvasManagerSafe } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
-import type { ParamsState } from 'features/controlLayers/store/paramsSlice';
import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
-import type { CanvasState } from 'features/controlLayers/store/types';
+import type { CanvasState, ParamsState } from 'features/controlLayers/store/types';
import {
getControlLayerWarnings,
getGlobalReferenceImageWarnings,