ext and revious fields.
Use cursor arrows to make a checkbox selection, and space to toggle.
"""
+ self.nextrely -= 1
for i in textwrap.wrap(label, width=window_width - 6):
self.add_widget_intelligent(
npyscreen.FixedText,
@@ -337,76 +348,127 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
use_two_lines=False,
scroll_exit=True,
)
- self.nextrely += 1
- self.add_widget_intelligent(
- npyscreen.TitleFixedText,
- name="GPU Management",
- begin_entry_at=0,
- editable=False,
- color="CONTROL",
- scroll_exit=True,
- )
- self.nextrely -= 1
- self.free_gpu_mem = self.add_widget_intelligent(
- npyscreen.Checkbox,
- name="Free GPU memory after each generation",
- value=old_opts.free_gpu_mem,
- max_width=45,
- relx=5,
- scroll_exit=True,
- )
- self.nextrely -= 1
- self.xformers_enabled = self.add_widget_intelligent(
- npyscreen.Checkbox,
- name="Enable xformers support",
- value=old_opts.xformers_enabled,
- max_width=30,
- relx=50,
- scroll_exit=True,
- )
- self.nextrely -= 1
- self.always_use_cpu = self.add_widget_intelligent(
- npyscreen.Checkbox,
- name="Force CPU to be used on GPU systems",
- value=old_opts.always_use_cpu,
- relx=80,
- scroll_exit=True,
- )
+
+ # old settings for defaults
precision = old_opts.precision or ("float32" if program_opts.full_precision else "auto")
+ device = old_opts.device
+ attention_type = old_opts.attention_type
+ attention_slice_size = old_opts.attention_slice_size
self.nextrely += 1
self.add_widget_intelligent(
npyscreen.TitleFixedText,
- name="Floating Point Precision",
+ name="Image Generation Options:",
+ editable=False,
+ color="CONTROL",
+ scroll_exit=True,
+ )
+ self.nextrely -= 2
+ self.generation_options = self.add_widget_intelligent(
+ MultiSelectColumns,
+ columns=3,
+ values=GENERATION_OPT_CHOICES,
+ value=[GENERATION_OPT_CHOICES.index(x) for x in GENERATION_OPT_CHOICES if getattr(old_opts, x)],
+ relx=30,
+ max_height=2,
+ max_width=80,
+ scroll_exit=True,
+ )
+
+ self.add_widget_intelligent(
+ npyscreen.TitleFixedText,
+ name="Floating Point Precision:",
begin_entry_at=0,
editable=False,
color="CONTROL",
scroll_exit=True,
)
- self.nextrely -= 1
+ self.nextrely -= 2
self.precision = self.add_widget_intelligent(
- SingleSelectColumns,
- columns=3,
+ SingleSelectColumnsSimple,
+ columns=len(PRECISION_CHOICES),
name="Precision",
values=PRECISION_CHOICES,
value=PRECISION_CHOICES.index(precision),
begin_entry_at=3,
max_height=2,
+ relx=30,
+ max_width=56,
+ scroll_exit=True,
+ )
+ self.add_widget_intelligent(
+ npyscreen.TitleFixedText,
+ name="Generation Device:",
+ begin_entry_at=0,
+ editable=False,
+ color="CONTROL",
+ scroll_exit=True,
+ )
+ self.nextrely -= 2
+ self.device = self.add_widget_intelligent(
+ SingleSelectColumnsSimple,
+ columns=len(DEVICE_CHOICES),
+ values=DEVICE_CHOICES,
+ value=[DEVICE_CHOICES.index(device)],
+ begin_entry_at=3,
+ relx=30,
+ max_height=2,
+ max_width=60,
+ scroll_exit=True,
+ )
+ self.add_widget_intelligent(
+ npyscreen.TitleFixedText,
+ name="Attention Type:",
+ begin_entry_at=0,
+ editable=False,
+ color="CONTROL",
+ scroll_exit=True,
+ )
+ self.nextrely -= 2
+ self.attention_type = self.add_widget_intelligent(
+ SingleSelectColumnsSimple,
+ columns=len(ATTENTION_CHOICES),
+ values=ATTENTION_CHOICES,
+ value=[ATTENTION_CHOICES.index(attention_type)],
+ begin_entry_at=3,
+ max_height=2,
+ relx=30,
max_width=80,
scroll_exit=True,
)
- self.nextrely += 1
+ self.attention_type.on_changed = self.show_hide_slice_sizes
+ self.attention_slice_label = self.add_widget_intelligent(
+ npyscreen.TitleFixedText,
+ name="Attention Slice Size:",
+ relx=5,
+ editable=False,
+ hidden=attention_type != "sliced",
+ color="CONTROL",
+ scroll_exit=True,
+ )
+ self.nextrely -= 2
+ self.attention_slice_size = self.add_widget_intelligent(
+ SingleSelectColumnsSimple,
+ columns=len(ATTENTION_SLICE_CHOICES),
+ values=ATTENTION_SLICE_CHOICES,
+ value=[ATTENTION_SLICE_CHOICES.index(attention_slice_size)],
+ relx=30,
+ hidden=attention_type != "sliced",
+ max_height=2,
+ max_width=110,
+ scroll_exit=True,
+ )
self.add_widget_intelligent(
npyscreen.TitleFixedText,
- name="RAM cache size (GB). Make this at least large enough to hold a single full model.",
+ name="Model RAM cache size (GB). Make this at least large enough to hold a single full model.",
begin_entry_at=0,
editable=False,
color="CONTROL",
scroll_exit=True,
)
self.nextrely -= 1
- self.max_cache_size = self.add_widget_intelligent(
+ self.ram = self.add_widget_intelligent(
npyscreen.Slider,
- value=clip(old_opts.max_cache_size, range=(3.0, MAX_RAM), step=0.5),
+ value=clip(old_opts.ram_cache_size, range=(3.0, MAX_RAM), step=0.5),
out_of=round(MAX_RAM),
lowest=0.0,
step=0.5,
@@ -417,16 +479,16 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
self.nextrely += 1
self.add_widget_intelligent(
npyscreen.TitleFixedText,
- name="VRAM cache size (GB). Reserving a small amount of VRAM will modestly speed up the start of image generation.",
+ name="Model VRAM cache size (GB). Reserving a small amount of VRAM will modestly speed up the start of image generation.",
begin_entry_at=0,
editable=False,
color="CONTROL",
scroll_exit=True,
)
self.nextrely -= 1
- self.max_vram_cache_size = self.add_widget_intelligent(
+ self.vram = self.add_widget_intelligent(
npyscreen.Slider,
- value=clip(old_opts.max_vram_cache_size, range=(0, MAX_VRAM), step=0.25),
+ value=clip(old_opts.vram_cache_size, range=(0, MAX_VRAM), step=0.25),
out_of=round(MAX_VRAM * 2) / 2,
lowest=0.0,
relx=8,
@@ -434,7 +496,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
scroll_exit=True,
)
else:
- self.max_vram_cache_size = DummyWidgetValue.zero
+ self.vram_cache_size = DummyWidgetValue.zero
self.nextrely += 1
self.outdir = self.add_widget_intelligent(
FileBox,
@@ -490,6 +552,11 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS
when_pressed_function=self.on_ok,
)
+ def show_hide_slice_sizes(self, value):
+ show = ATTENTION_CHOICES[value[0]] == "sliced"
+ self.attention_slice_label.hidden = not show
+ self.attention_slice_size.hidden = not show
+
def on_ok(self):
options = self.marshall_arguments()
if self.validate_field_values(options):
@@ -523,12 +590,9 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS
new_opts = Namespace()
for attr in [
+ "ram",
+ "vram",
"outdir",
- "free_gpu_mem",
- "max_cache_size",
- "max_vram_cache_size",
- "xformers_enabled",
- "always_use_cpu",
]:
setattr(new_opts, attr, getattr(self, attr).value)
@@ -541,6 +605,12 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS
new_opts.hf_token = self.hf_token.value
new_opts.license_acceptance = self.license_acceptance.value
new_opts.precision = PRECISION_CHOICES[self.precision.value[0]]
+ new_opts.device = DEVICE_CHOICES[self.device.value[0]]
+ new_opts.attention_type = ATTENTION_CHOICES[self.attention_type.value[0]]
+ new_opts.attention_slice_size = ATTENTION_SLICE_CHOICES[self.attention_slice_size.value[0]]
+ generation_options = [GENERATION_OPT_CHOICES[x] for x in self.generation_options.value]
+ for v in GENERATION_OPT_CHOICES:
+ setattr(new_opts, v, v in generation_options)
return new_opts
@@ -635,8 +705,6 @@ def initialize_rootdir(root: Path, yes_to_all: bool = False):
path = dest / "core"
path.mkdir(parents=True, exist_ok=True)
- maybe_create_models_yaml(root)
-
def maybe_create_models_yaml(root: Path):
models_yaml = root / "configs" / "models.yaml"
diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py
index 1b10554e69..d87bc03fb7 100644
--- a/invokeai/backend/model_management/model_manager.py
+++ b/invokeai/backend/model_management/model_manager.py
@@ -341,7 +341,8 @@ class ModelManager(object):
self.logger = logger
self.cache = ModelCache(
max_cache_size=max_cache_size,
- max_vram_cache_size=self.app_config.max_vram_cache_size,
+ max_vram_cache_size=self.app_config.vram_cache_size,
+ lazy_offloading=self.app_config.lazy_offload,
execution_device=device_type,
precision=precision,
sequential_offload=sequential_offload,
diff --git a/invokeai/backend/stable_diffusion/diffusers_pipeline.py b/invokeai/backend/stable_diffusion/diffusers_pipeline.py
index 0180830b76..63b0c78b51 100644
--- a/invokeai/backend/stable_diffusion/diffusers_pipeline.py
+++ b/invokeai/backend/stable_diffusion/diffusers_pipeline.py
@@ -33,7 +33,7 @@ from .diffusion import (
PostprocessingSettings,
BasicConditioningInfo,
)
-from ..util import normalize_device
+from ..util import normalize_device, auto_detect_slice_size
@dataclass
@@ -291,6 +291,24 @@ class StableDiffusionGeneratorPipeline(StableDiffusionPipeline):
if xformers is available, use it, otherwise use sliced attention.
"""
config = InvokeAIAppConfig.get_config()
+ if config.attention_type == "xformers":
+ self.enable_xformers_memory_efficient_attention()
+ return
+ elif config.attention_type == "sliced":
+ slice_size = config.attention_slice_size
+ if slice_size == "auto":
+ slice_size = auto_detect_slice_size(latents)
+ elif slice_size == "balanced":
+ slice_size = "auto"
+ self.enable_attention_slicing(slice_size=slice_size)
+ return
+ elif config.attention_type == "normal":
+ self.disable_attention_slicing()
+ return
+ elif config.attention_type == "torch-sdp":
+ raise Exception("torch-sdp attention slicing not yet implemented")
+
+ # the remainder if this code is called when attention_type=='auto'
if self.unet.device.type == "cuda":
if is_xformers_available() and not config.disable_xformers:
self.enable_xformers_memory_efficient_attention()
diff --git a/invokeai/backend/util/__init__.py b/invokeai/backend/util/__init__.py
index 30bb0efc15..b4e1c6e3a3 100644
--- a/invokeai/backend/util/__init__.py
+++ b/invokeai/backend/util/__init__.py
@@ -11,4 +11,11 @@ from .devices import ( # noqa: F401
torch_dtype,
)
from .log import write_log # noqa: F401
-from .util import ask_user, download_with_resume, instantiate_from_config, url_attachment_name, Chdir # noqa: F401
+from .util import ( # noqa: F401
+ ask_user,
+ download_with_resume,
+ instantiate_from_config,
+ url_attachment_name,
+ Chdir,
+)
+from .attention import auto_detect_slice_size # noqa: F401
diff --git a/invokeai/backend/util/attention.py b/invokeai/backend/util/attention.py
new file mode 100644
index 0000000000..a821464394
--- /dev/null
+++ b/invokeai/backend/util/attention.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2023 Lincoln Stein and the InvokeAI Team
+"""
+Utility routine used for autodetection of optimal slice size
+for attention mechanism.
+"""
+import torch
+import psutil
+
+
+def auto_detect_slice_size(latents: torch.Tensor) -> str:
+ bytes_per_element_needed_for_baddbmm_duplication = latents.element_size() + 4
+ max_size_required_for_baddbmm = (
+ 16
+ * latents.size(dim=2)
+ * latents.size(dim=3)
+ * latents.size(dim=2)
+ * latents.size(dim=3)
+ * bytes_per_element_needed_for_baddbmm_duplication
+ )
+ if latents.device.type in {"cpu", "mps"}:
+ mem_free = psutil.virtual_memory().free
+ elif latents.device.type == "cuda":
+ mem_free, _ = torch.cuda.mem_get_info(latents.device)
+ else:
+ raise ValueError(f"unrecognized device {latents.device}")
+
+ if max_size_required_for_baddbmm > (mem_free * 3.0 / 4.0):
+ return "max"
+ elif torch.backends.mps.is_available():
+ return "max"
+ else:
+ return "balanced"
diff --git a/invokeai/backend/util/devices.py b/invokeai/backend/util/devices.py
index 1827f295e4..bdaf3244f3 100644
--- a/invokeai/backend/util/devices.py
+++ b/invokeai/backend/util/devices.py
@@ -17,13 +17,17 @@ config = InvokeAIAppConfig.get_config()
def choose_torch_device() -> torch.device:
"""Convenience routine for guessing which GPU device to run model on"""
- if config.always_use_cpu:
+ if config.use_cpu: # legacy setting - force CPU
return CPU_DEVICE
- if torch.cuda.is_available():
- return torch.device("cuda")
- if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
- return torch.device("mps")
- return CPU_DEVICE
+ elif config.device == "auto":
+ if torch.cuda.is_available():
+ return torch.device("cuda")
+ if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
+ return torch.device("mps")
+ else:
+ return CPU_DEVICE
+ else:
+ return torch.device(config.device)
def choose_precision(device: torch.device) -> str:
diff --git a/invokeai/frontend/install/widgets.py b/invokeai/frontend/install/widgets.py
index 79b6280990..9eefd93e09 100644
--- a/invokeai/frontend/install/widgets.py
+++ b/invokeai/frontend/install/widgets.py
@@ -17,8 +17,8 @@ from shutil import get_terminal_size
from curses import BUTTON2_CLICKED, BUTTON3_CLICKED
# minimum size for UIs
-MIN_COLS = 130
-MIN_LINES = 38
+MIN_COLS = 150
+MIN_LINES = 40
class WindowTooSmallException(Exception):
@@ -177,6 +177,8 @@ class FloatTitleSlider(npyscreen.TitleText):
class SelectColumnBase:
+ """Base class for selection widget arranged in columns."""
+
def make_contained_widgets(self):
self._my_widgets = []
column_width = self.width // self.columns
@@ -253,6 +255,7 @@ class MultiSelectColumns(SelectColumnBase, npyscreen.MultiSelect):
class SingleSelectWithChanged(npyscreen.SelectOne):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+ self.on_changed = None
def h_select(self, ch):
super().h_select(ch)
@@ -260,7 +263,9 @@ class SingleSelectWithChanged(npyscreen.SelectOne):
self.on_changed(self.value)
-class SingleSelectColumns(SelectColumnBase, SingleSelectWithChanged):
+class SingleSelectColumnsSimple(SelectColumnBase, SingleSelectWithChanged):
+ """Row of radio buttons. Spacebar to select."""
+
def __init__(self, screen, columns: int = 1, values: list = [], **keywords):
self.columns = columns
self.value_cnt = len(values)
@@ -268,15 +273,19 @@ class SingleSelectColumns(SelectColumnBase, SingleSelectWithChanged):
self.on_changed = None
super().__init__(screen, values=values, **keywords)
- def when_value_edited(self):
- self.h_select(self.cursor_line)
+ def h_cursor_line_right(self, ch):
+ self.h_exit_down("bye bye")
+
+ def h_cursor_line_left(self, ch):
+ self.h_exit_up("bye bye")
+
+
+class SingleSelectColumns(SingleSelectColumnsSimple):
+ """Row of radio buttons. When tabbing over a selection, it is auto selected."""
def when_cursor_moved(self):
self.h_select(self.cursor_line)
- def h_cursor_line_right(self, ch):
- self.h_exit_down("bye bye")
-
class TextBoxInner(npyscreen.MultiLineEdit):
def __init__(self, *args, **kwargs):
@@ -324,55 +333,6 @@ class TextBoxInner(npyscreen.MultiLineEdit):
if bstate & (BUTTON2_CLICKED | BUTTON3_CLICKED):
self.h_paste()
- # def update(self, clear=True):
- # if clear:
- # self.clear()
-
- # HEIGHT = self.height
- # WIDTH = self.width
- # # draw box.
- # self.parent.curses_pad.hline(self.rely, self.relx, curses.ACS_HLINE, WIDTH)
- # self.parent.curses_pad.hline(
- # self.rely + HEIGHT, self.relx, curses.ACS_HLINE, WIDTH
- # )
- # self.parent.curses_pad.vline(
- # self.rely, self.relx, curses.ACS_VLINE, self.height
- # )
- # self.parent.curses_pad.vline(
- # self.rely, self.relx + WIDTH, curses.ACS_VLINE, HEIGHT
- # )
-
- # # draw corners
- # self.parent.curses_pad.addch(
- # self.rely,
- # self.relx,
- # curses.ACS_ULCORNER,
- # )
- # self.parent.curses_pad.addch(
- # self.rely,
- # self.relx + WIDTH,
- # curses.ACS_URCORNER,
- # )
- # self.parent.curses_pad.addch(
- # self.rely + HEIGHT,
- # self.relx,
- # curses.ACS_LLCORNER,
- # )
- # self.parent.curses_pad.addch(
- # self.rely + HEIGHT,
- # self.relx + WIDTH,
- # curses.ACS_LRCORNER,
- # )
-
- # # fool our superclass into thinking drawing area is smaller - this is really hacky but it seems to work
- # (relx, rely, height, width) = (self.relx, self.rely, self.height, self.width)
- # self.relx += 1
- # self.rely += 1
- # self.height -= 1
- # self.width -= 1
- # super().update(clear=False)
- # (self.relx, self.rely, self.height, self.width) = (relx, rely, height, width)
-
class TextBox(npyscreen.BoxTitle):
_contained_widget = TextBoxInner
diff --git a/invokeai/frontend/web/.eslintrc.js b/invokeai/frontend/web/.eslintrc.js
index c48e08d45e..c2b1433a9a 100644
--- a/invokeai/frontend/web/.eslintrc.js
+++ b/invokeai/frontend/web/.eslintrc.js
@@ -9,8 +9,8 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
- 'plugin:prettier/recommended',
'plugin:react/jsx-runtime',
+ 'prettier',
],
parser: '@typescript-eslint/parser',
parserOptions: {
@@ -23,6 +23,11 @@ module.exports = {
plugins: ['react', '@typescript-eslint', 'eslint-plugin-react-hooks'],
root: true,
rules: {
+ curly: 'error',
+ 'react/jsx-curly-brace-presence': [
+ 'error',
+ { props: 'never', children: 'never' },
+ ],
'react-hooks/exhaustive-deps': 'error',
'no-var': 'error',
'brace-style': 'error',
@@ -34,7 +39,6 @@ module.exports = {
'warn',
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
],
- 'prettier/prettier': ['error', { endOfLine: 'auto' }],
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-empty-interface': [
diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json
index 6c9db74bbc..e3f6dc48d7 100644
--- a/invokeai/frontend/web/package.json
+++ b/invokeai/frontend/web/package.json
@@ -29,12 +29,13 @@
"lint:eslint": "eslint --max-warnings=0 .",
"lint:prettier": "prettier --check .",
"lint:tsc": "tsc --noEmit",
- "lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:tsc && yarn run lint:madge",
+ "lint": "concurrently -g -n eslint,prettier,tsc,madge -c cyan,green,magenta,yellow \"yarn run lint:eslint\" \"yarn run lint:prettier\" \"yarn run lint:tsc\" \"yarn run lint:madge\"",
"fix": "eslint --fix . && prettier --loglevel warn --write . && tsc --noEmit",
"lint-staged": "lint-staged",
"postinstall": "patch-package && yarn run theme",
"theme": "chakra-cli tokens src/theme/theme.ts",
- "theme:watch": "chakra-cli tokens src/theme/theme.ts --watch"
+ "theme:watch": "chakra-cli tokens src/theme/theme.ts --watch",
+ "up": "yarn upgrade-interactive --latest"
},
"madge": {
"detectiveOptions": {
@@ -54,7 +55,7 @@
},
"dependencies": {
"@chakra-ui/anatomy": "^2.2.0",
- "@chakra-ui/icons": "^2.0.19",
+ "@chakra-ui/icons": "^2.1.0",
"@chakra-ui/react": "^2.8.0",
"@chakra-ui/styled-system": "^2.9.1",
"@chakra-ui/theme-tools": "^2.1.0",
@@ -65,55 +66,55 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@floating-ui/react-dom": "^2.0.1",
- "@fontsource-variable/inter": "^5.0.3",
- "@fontsource/inter": "^5.0.3",
- "@mantine/core": "^6.0.14",
- "@mantine/form": "^6.0.15",
- "@mantine/hooks": "^6.0.14",
+ "@fontsource-variable/inter": "^5.0.8",
+ "@fontsource/inter": "^5.0.8",
+ "@mantine/core": "^6.0.19",
+ "@mantine/form": "^6.0.19",
+ "@mantine/hooks": "^6.0.19",
"@nanostores/react": "^0.7.1",
"@reduxjs/toolkit": "^1.9.5",
"@roarr/browser-log-writer": "^1.1.5",
- "chakra-ui-contextmenu": "^1.0.5",
"dateformat": "^5.0.3",
- "downshift": "^7.6.0",
- "formik": "^2.4.2",
- "framer-motion": "^10.12.17",
+ "formik": "^2.4.3",
+ "framer-motion": "^10.16.1",
"fuse.js": "^6.6.2",
- "i18next": "^23.2.3",
+ "i18next": "^23.4.4",
"i18next-browser-languagedetector": "^7.0.2",
"i18next-http-backend": "^2.2.1",
"konva": "^9.2.0",
"lodash-es": "^4.17.21",
"nanostores": "^0.9.2",
- "openapi-fetch": "^0.6.1",
+ "new-github-issue-url": "^1.0.0",
+ "openapi-fetch": "^0.7.4",
"overlayscrollbars": "^2.2.0",
"overlayscrollbars-react": "^0.5.0",
- "patch-package": "^7.0.0",
+ "patch-package": "^8.0.0",
"query-string": "^8.1.0",
- "re-resizable": "^6.9.9",
"react": "^18.2.0",
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
- "react-hotkeys-hook": "4.4.0",
- "react-i18next": "^13.0.1",
+ "react-error-boundary": "^4.0.11",
+ "react-hotkeys-hook": "4.4.1",
+ "react-i18next": "^13.1.2",
"react-icons": "^4.10.1",
"react-konva": "^18.2.10",
- "react-redux": "^8.1.1",
- "react-resizable-panels": "^0.0.52",
+ "react-redux": "^8.1.2",
+ "react-resizable-panels": "^0.0.55",
"react-use": "^17.4.0",
- "react-virtuoso": "^4.3.11",
+ "react-virtuoso": "^4.5.0",
"react-zoom-pan-pinch": "^3.0.8",
- "reactflow": "^11.7.4",
+ "reactflow": "^11.8.3",
"redux-dynamic-middlewares": "^2.2.0",
- "redux-remember": "^3.3.1",
- "roarr": "^7.15.0",
- "serialize-error": "^11.0.0",
- "socket.io-client": "^4.7.0",
+ "redux-remember": "^4.0.1",
+ "roarr": "^7.15.1",
+ "serialize-error": "^11.0.1",
+ "socket.io-client": "^4.7.2",
"use-debounce": "^9.0.4",
"use-image": "^1.1.1",
"uuid": "^9.0.0",
- "zod": "^3.21.4"
+ "zod": "^3.22.2",
+ "zod-validation-error": "^1.5.0"
},
"peerDependencies": {
"@chakra-ui/cli": "^2.4.0",
@@ -126,38 +127,36 @@
"@chakra-ui/cli": "^2.4.1",
"@types/dateformat": "^5.0.0",
"@types/lodash-es": "^4.14.194",
- "@types/node": "^20.3.1",
- "@types/react": "^18.2.14",
+ "@types/node": "^20.5.1",
+ "@types/react": "^18.2.20",
"@types/react-dom": "^18.2.6",
"@types/react-redux": "^7.1.25",
"@types/react-transition-group": "^4.4.6",
"@types/uuid": "^9.0.2",
- "@typescript-eslint/eslint-plugin": "^5.60.0",
- "@typescript-eslint/parser": "^5.60.0",
+ "@typescript-eslint/eslint-plugin": "^6.4.1",
+ "@typescript-eslint/parser": "^6.4.1",
"@vitejs/plugin-react-swc": "^3.3.2",
"axios": "^1.4.0",
"babel-plugin-transform-imports": "^2.0.0",
"concurrently": "^8.2.0",
- "eslint": "^8.43.0",
- "eslint-config-prettier": "^8.8.0",
- "eslint-plugin-prettier": "^4.2.1",
- "eslint-plugin-react": "^7.32.2",
+ "eslint": "^8.47.0",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-prettier": "^5.0.0",
+ "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"form-data": "^4.0.0",
"husky": "^8.0.3",
- "lint-staged": "^13.2.2",
+ "lint-staged": "^14.0.1",
"madge": "^6.1.0",
"openapi-types": "^12.1.3",
- "openapi-typescript": "^6.2.8",
- "openapi-typescript-codegen": "^0.24.0",
+ "openapi-typescript": "^6.5.2",
"postinstall-postinstall": "^2.1.0",
- "prettier": "^2.8.8",
+ "prettier": "^3.0.2",
"rollup-plugin-visualizer": "^5.9.2",
- "terser": "^5.18.1",
"ts-toolbelt": "^9.6.0",
- "vite": "^4.3.9",
- "vite-plugin-css-injected-by-js": "^3.1.1",
- "vite-plugin-dts": "^2.3.0",
+ "vite": "^4.4.9",
+ "vite-plugin-css-injected-by-js": "^3.3.0",
+ "vite-plugin-dts": "^3.5.2",
"vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.0",
"yarn": "^1.22.19"
diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json
index f41da82e07..e39f438146 100644
--- a/invokeai/frontend/web/public/locales/en.json
+++ b/invokeai/frontend/web/public/locales/en.json
@@ -19,7 +19,7 @@
"toggleAutoscroll": "Toggle autoscroll",
"toggleLogViewer": "Toggle Log Viewer",
"showGallery": "Show Gallery",
- "showOptionsPanel": "Show Options Panel",
+ "showOptionsPanel": "Show Side Panel",
"menu": "Menu"
},
"common": {
@@ -52,7 +52,7 @@
"img2img": "Image To Image",
"unifiedCanvas": "Unified Canvas",
"linear": "Linear",
- "nodes": "Node Editor",
+ "nodes": "Workflow Editor",
"batch": "Batch Manager",
"modelManager": "Model Manager",
"postprocessing": "Post Processing",
@@ -95,7 +95,6 @@
"statusModelConverted": "Model Converted",
"statusMergingModels": "Merging Models",
"statusMergedModels": "Models Merged",
- "pinOptionsPanel": "Pin Options Panel",
"loading": "Loading",
"loadingInvokeAI": "Loading Invoke AI",
"random": "Random",
@@ -116,7 +115,6 @@
"maintainAspectRatio": "Maintain Aspect Ratio",
"autoSwitchNewImages": "Auto-Switch to New Images",
"singleColumnLayout": "Single Column Layout",
- "pinGallery": "Pin Gallery",
"allImagesLoaded": "All Images Loaded",
"loadMore": "Load More",
"noImagesInGallery": "No Images to Display",
@@ -133,6 +131,7 @@
"generalHotkeys": "General Hotkeys",
"galleryHotkeys": "Gallery Hotkeys",
"unifiedCanvasHotkeys": "Unified Canvas Hotkeys",
+ "nodesHotkeys": "Nodes Hotkeys",
"invoke": {
"title": "Invoke",
"desc": "Generate an image"
@@ -332,6 +331,10 @@
"acceptStagingImage": {
"title": "Accept Staging Image",
"desc": "Accept Current Staging Area Image"
+ },
+ "addNodes": {
+ "title": "Add Nodes",
+ "desc": "Opens the add node menu"
}
},
"modelManager": {
@@ -506,12 +509,9 @@
"maskAdjustmentsHeader": "Mask Adjustments",
"maskBlur": "Mask Blur",
"maskBlurMethod": "Mask Blur Method",
- "seamPaintingHeader": "Seam Painting",
- "seamSize": "Seam Size",
- "seamBlur": "Seam Blur",
- "seamSteps": "Seam Steps",
- "seamStrength": "Seam Strength",
- "seamThreshold": "Seam Threshold",
+ "coherencePassHeader": "Coherence Pass",
+ "coherenceSteps": "Coherence Pass Steps",
+ "coherenceStrength": "Coherence Pass Strength",
"seamLowThreshold": "Low",
"seamHighThreshold": "High",
"scaleBeforeProcessing": "Scale Before Processing",
@@ -572,7 +572,7 @@
"resetWebUI": "Reset Web UI",
"resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.",
"resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.",
- "resetComplete": "Web UI has been reset. Refresh the page to reload.",
+ "resetComplete": "Web UI has been reset.",
"consoleLogLevel": "Log Level",
"shouldLogToConsole": "Console Logging",
"developer": "Developer",
@@ -715,11 +715,12 @@
"swapSizes": "Swap Sizes"
},
"nodes": {
- "reloadSchema": "Reload Schema",
- "saveGraph": "Save Graph",
- "loadGraph": "Load Graph (saved from Node Editor) (Do not copy-paste metadata)",
- "clearGraph": "Clear Graph",
- "clearGraphDesc": "Are you sure you want to clear all nodes?",
+ "reloadNodeTemplates": "Reload Node Templates",
+ "saveWorkflow": "Save Workflow",
+ "loadWorkflow": "Load Workflow",
+ "resetWorkflow": "Reset Workflow",
+ "resetWorkflowDesc": "Are you sure you want to reset this workflow?",
+ "resetWorkflowDesc2": "Resetting the workflow will clear all nodes, edges and workflow details.",
"zoomInNodes": "Zoom In",
"zoomOutNodes": "Zoom Out",
"fitViewportNodes": "Fit View",
diff --git a/invokeai/frontend/web/scripts/typegen.js b/invokeai/frontend/web/scripts/typegen.js
index d105917e66..485cf6cbc3 100644
--- a/invokeai/frontend/web/scripts/typegen.js
+++ b/invokeai/frontend/web/scripts/typegen.js
@@ -27,22 +27,10 @@ async function main() {
* field accepts connection input. If it does, we can make the field optional.
*/
- // Check if we are generating types for an invocation
- const isInvocationPath = metadata.path.match(
- /^#\/components\/schemas\/\w*Invocation$/
- );
-
- const hasInvocationProperties =
- schemaObject.properties &&
- ['id', 'is_intermediate', 'type'].every(
- (prop) => prop in schemaObject.properties
- );
-
- if (isInvocationPath && hasInvocationProperties) {
+ if ('class' in schemaObject && schemaObject.class === 'invocation') {
// We only want to make fields optional if they are required
if (!Array.isArray(schemaObject?.required)) {
- schemaObject.required = ['id', 'type'];
- return;
+ schemaObject.required = [];
}
schemaObject.required.forEach((prop) => {
@@ -61,19 +49,13 @@ async function main() {
);
}
});
-
- schemaObject.required = [
- ...new Set(schemaObject.required.concat(['id', 'type'])),
- ];
-
return;
}
- // if (
- // 'input' in schemaObject &&
- // (schemaObject.input === 'any' || schemaObject.input === 'connection')
- // ) {
- // schemaObject.required = false;
- // }
+
+ // Check if we are generating types for an invocation output
+ if ('class' in schemaObject && schemaObject.class === 'output') {
+ // modify output types
+ }
},
});
fs.writeFileSync(OUTPUT_FILE, types);
diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx
index fa45ae93cd..c2cc4645b8 100644
--- a/invokeai/frontend/web/src/app/components/App.tsx
+++ b/invokeai/frontend/web/src/app/components/App.tsx
@@ -1,4 +1,4 @@
-import { Flex, Grid, Portal } from '@chakra-ui/react';
+import { Flex, Grid } from '@chakra-ui/react';
import { useLogger } from 'app/logging/useLogger';
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@@ -6,17 +6,15 @@ import { PartialAppConfig } from 'app/types/invokeai';
import ImageUploader from 'common/components/ImageUploader';
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
-import GalleryDrawer from 'features/gallery/components/GalleryPanel';
import SiteHeader from 'features/system/components/SiteHeader';
import { configChanged } from 'features/system/store/configSlice';
import { languageSelector } from 'features/system/store/systemSelectors';
-import FloatingGalleryButton from 'features/ui/components/FloatingGalleryButton';
-import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons';
import InvokeTabs from 'features/ui/components/InvokeTabs';
-import ParametersDrawer from 'features/ui/components/ParametersDrawer';
import i18n from 'i18n';
import { size } from 'lodash-es';
-import { ReactNode, memo, useEffect } from 'react';
+import { ReactNode, memo, useCallback, useEffect } from 'react';
+import { ErrorBoundary } from 'react-error-boundary';
+import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
import GlobalHotkeys from './GlobalHotkeys';
import Toaster from './Toaster';
@@ -30,8 +28,13 @@ interface Props {
const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
const language = useAppSelector(languageSelector);
- const logger = useLogger();
+ const logger = useLogger('system');
const dispatch = useAppDispatch();
+ const handleReset = useCallback(() => {
+ localStorage.clear();
+ location.reload();
+ return false;
+ }, []);
useEffect(() => {
i18n.changeLanguage(language);
@@ -39,7 +42,7 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
useEffect(() => {
if (size(config)) {
- logger.info({ namespace: 'App', config }, 'Received config');
+ logger.info({ config }, 'Received config');
dispatch(configChanged(config));
}
}, [dispatch, config, logger]);
@@ -49,7 +52,10 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
}, [dispatch]);
return (
- <>
+
{
-
-
-
-
-
-
-
-
-
- >
+
);
};
diff --git a/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx b/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx
new file mode 100644
index 0000000000..76a34388eb
--- /dev/null
+++ b/invokeai/frontend/web/src/app/components/AppErrorBoundaryFallback.tsx
@@ -0,0 +1,97 @@
+import { Flex, Heading, Link, Text, useToast } from '@chakra-ui/react';
+import IAIButton from 'common/components/IAIButton';
+import newGithubIssueUrl from 'new-github-issue-url';
+import { memo, useCallback, useMemo } from 'react';
+import { FaCopy, FaExternalLinkAlt } from 'react-icons/fa';
+import { FaArrowRotateLeft } from 'react-icons/fa6';
+import { serializeError } from 'serialize-error';
+
+type Props = {
+ error: Error;
+ resetErrorBoundary: () => void;
+};
+
+const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => {
+ const toast = useToast();
+
+ const handleCopy = useCallback(() => {
+ const text = JSON.stringify(serializeError(error), null, 2);
+ navigator.clipboard.writeText(`\`\`\`\n${text}\n\`\`\``);
+ toast({
+ title: 'Error Copied',
+ });
+ }, [error, toast]);
+
+ const url = useMemo(
+ () =>
+ newGithubIssueUrl({
+ user: 'invoke-ai',
+ repo: 'InvokeAI',
+ template: 'BUG_REPORT.yml',
+ title: `[bug]: ${error.name}: ${error.message}`,
+ }),
+ [error.message, error.name]
+ );
+ return (
+
+
+ Something went wrong
+
+
+ {error.name}: {error.message}
+
+
+
+ }
+ onClick={resetErrorBoundary}
+ >
+ Reset UI
+
+ } onClick={handleCopy}>
+ Copy Error
+
+
+ }>Create Issue
+
+
+
+
+ );
+};
+
+export default memo(AppErrorBoundaryFallback);
diff --git a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts
index bbe77dc698..ac48fcc7b1 100644
--- a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts
+++ b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts
@@ -1,30 +1,21 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import {
ctrlKeyPressed,
metaKeyPressed,
shiftKeyPressed,
} from 'features/ui/store/hotkeysSlice';
-import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import {
- setActiveTab,
- toggleGalleryPanel,
- toggleParametersPanel,
- togglePinGalleryPanel,
- togglePinParametersPanel,
-} from 'features/ui/store/uiSlice';
+import { setActiveTab } from 'features/ui/store/uiSlice';
import { isEqual } from 'lodash-es';
import React, { memo } from 'react';
import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook';
const globalHotkeysSelector = createSelector(
[stateSelector],
- ({ hotkeys, ui }) => {
+ ({ hotkeys }) => {
const { shift, ctrl, meta } = hotkeys;
- const { shouldPinParametersPanel, shouldPinGallery } = ui;
- return { shift, ctrl, meta, shouldPinGallery, shouldPinParametersPanel };
+ return { shift, ctrl, meta };
},
{
memoizeOptions: {
@@ -41,9 +32,7 @@ const globalHotkeysSelector = createSelector(
*/
const GlobalHotkeys: React.FC = () => {
const dispatch = useAppDispatch();
- const { shift, ctrl, meta, shouldPinParametersPanel, shouldPinGallery } =
- useAppSelector(globalHotkeysSelector);
- const activeTabName = useAppSelector(activeTabNameSelector);
+ const { shift, ctrl, meta } = useAppSelector(globalHotkeysSelector);
useHotkeys(
'*',
@@ -68,34 +57,6 @@ const GlobalHotkeys: React.FC = () => {
[shift, ctrl, meta]
);
- useHotkeys('o', () => {
- dispatch(toggleParametersPanel());
- if (activeTabName === 'unifiedCanvas' && shouldPinParametersPanel) {
- dispatch(requestCanvasRescale());
- }
- });
-
- useHotkeys(['shift+o'], () => {
- dispatch(togglePinParametersPanel());
- if (activeTabName === 'unifiedCanvas') {
- dispatch(requestCanvasRescale());
- }
- });
-
- useHotkeys('g', () => {
- dispatch(toggleGalleryPanel());
- if (activeTabName === 'unifiedCanvas' && shouldPinGallery) {
- dispatch(requestCanvasRescale());
- }
- });
-
- useHotkeys(['shift+g'], () => {
- dispatch(togglePinGalleryPanel());
- if (activeTabName === 'unifiedCanvas') {
- dispatch(requestCanvasRescale());
- }
- });
-
useHotkeys('1', () => {
dispatch(setActiveTab('txt2img'));
});
@@ -112,6 +73,10 @@ const GlobalHotkeys: React.FC = () => {
dispatch(setActiveTab('nodes'));
});
+ useHotkeys('5', () => {
+ dispatch(setActiveTab('modelManager'));
+ });
+
return null;
};
diff --git a/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx b/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx
index 621b196ae0..9bcc7c831b 100644
--- a/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx
+++ b/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx
@@ -3,7 +3,7 @@ import {
createLocalStorageManager,
extendTheme,
} from '@chakra-ui/react';
-import { ReactNode, useEffect, useMemo } from 'react';
+import { ReactNode, memo, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { theme as invokeAITheme } from 'theme/theme';
@@ -46,4 +46,4 @@ function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
);
}
-export default ThemeLocaleProvider;
+export default memo(ThemeLocaleProvider);
diff --git a/invokeai/frontend/web/src/app/components/Toaster.ts b/invokeai/frontend/web/src/app/components/Toaster.ts
index dff2a7c7f5..9d7149023b 100644
--- a/invokeai/frontend/web/src/app/components/Toaster.ts
+++ b/invokeai/frontend/web/src/app/components/Toaster.ts
@@ -3,7 +3,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { toastQueueSelector } from 'features/system/store/systemSelectors';
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
import { MakeToastArg, makeToast } from 'features/system/util/makeToast';
-import { useCallback, useEffect } from 'react';
+import { memo, useCallback, useEffect } from 'react';
/**
* Logical component. Watches the toast queue and makes toasts when the queue is not empty.
@@ -44,4 +44,4 @@ export const useAppToaster = () => {
return toaster;
};
-export default Toaster;
+export default memo(Toaster);
diff --git a/invokeai/frontend/web/src/app/logging/logger.ts b/invokeai/frontend/web/src/app/logging/logger.ts
index 7797b8dc92..2d7b8a7744 100644
--- a/invokeai/frontend/web/src/app/logging/logger.ts
+++ b/invokeai/frontend/web/src/app/logging/logger.ts
@@ -9,7 +9,7 @@ export const log = Roarr.child(BASE_CONTEXT);
export const $logger = atom(Roarr.child(BASE_CONTEXT));
-type LoggerNamespace =
+export type LoggerNamespace =
| 'images'
| 'models'
| 'config'
diff --git a/invokeai/frontend/web/src/app/logging/useLogger.ts b/invokeai/frontend/web/src/app/logging/useLogger.ts
index 6c60bd4fd0..d31bcc2660 100644
--- a/invokeai/frontend/web/src/app/logging/useLogger.ts
+++ b/invokeai/frontend/web/src/app/logging/useLogger.ts
@@ -1,12 +1,17 @@
-import { useStore } from '@nanostores/react';
import { createSelector } from '@reduxjs/toolkit';
import { createLogWriter } from '@roarr/browser-log-writer';
import { useAppSelector } from 'app/store/storeHooks';
import { systemSelector } from 'features/system/store/systemSelectors';
import { isEqual } from 'lodash-es';
-import { useEffect } from 'react';
+import { useEffect, useMemo } from 'react';
import { ROARR, Roarr } from 'roarr';
-import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP } from './logger';
+import {
+ $logger,
+ BASE_CONTEXT,
+ LOG_LEVEL_MAP,
+ LoggerNamespace,
+ logger,
+} from './logger';
const selector = createSelector(
systemSelector,
@@ -25,7 +30,7 @@ const selector = createSelector(
}
);
-export const useLogger = () => {
+export const useLogger = (namespace: LoggerNamespace) => {
const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector);
// The provided Roarr browser log writer uses localStorage to config logging to console
@@ -57,7 +62,7 @@ export const useLogger = () => {
$logger.set(Roarr.child(newContext));
}, []);
- const logger = useStore($logger);
+ const log = useMemo(() => logger(namespace), [namespace]);
- return logger;
+ return log;
};
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts
index b419e98782..770c9fc11b 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeleted.ts
@@ -1,13 +1,17 @@
import { logger } from 'app/logging/logger';
import { resetCanvas } from 'features/canvas/store/canvasSlice';
-import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
+import {
+ controlNetImageChanged,
+ controlNetProcessedImageChanged,
+} from 'features/controlNet/store/controlNetSlice';
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
import { imageSelected } from 'features/gallery/store/gallerySlice';
-import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
+import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
+import { isInvocationNode } from 'features/nodes/types/types';
import { clearInitialImage } from 'features/parameters/store/generationSlice';
-import { clamp } from 'lodash-es';
+import { clamp, forEach } from 'lodash-es';
import { api } from 'services/api';
import { imagesApi } from 'services/api/endpoints/images';
import { imagesAdapter } from 'services/api/util';
@@ -73,22 +77,61 @@ export const addRequestedSingleImageDeletionListener = () => {
}
// We need to reset the features where the image is in use - none of these work if their image(s) don't exist
-
if (imageUsage.isCanvasImage) {
dispatch(resetCanvas());
}
- if (imageUsage.isControlNetImage) {
- dispatch(controlNetReset());
- }
+ imageDTOs.forEach((imageDTO) => {
+ // reset init image if we deleted it
+ if (
+ getState().generation.initialImage?.imageName === imageDTO.image_name
+ ) {
+ dispatch(clearInitialImage());
+ }
- if (imageUsage.isInitialImage) {
- dispatch(clearInitialImage());
- }
+ // reset controlNets that use the deleted images
+ forEach(getState().controlNet.controlNets, (controlNet) => {
+ if (
+ controlNet.controlImage === imageDTO.image_name ||
+ controlNet.processedControlImage === imageDTO.image_name
+ ) {
+ dispatch(
+ controlNetImageChanged({
+ controlNetId: controlNet.controlNetId,
+ controlImage: null,
+ })
+ );
+ dispatch(
+ controlNetProcessedImageChanged({
+ controlNetId: controlNet.controlNetId,
+ processedControlImage: null,
+ })
+ );
+ }
+ });
- if (imageUsage.isNodesImage) {
- dispatch(nodeEditorReset());
- }
+ // reset nodes that use the deleted images
+ getState().nodes.nodes.forEach((node) => {
+ if (!isInvocationNode(node)) {
+ return;
+ }
+
+ forEach(node.data.inputs, (input) => {
+ if (
+ input.type === 'ImageField' &&
+ input.value?.image_name === imageDTO.image_name
+ ) {
+ dispatch(
+ fieldImageValueChanged({
+ nodeId: node.data.id,
+ fieldName: input.name,
+ value: undefined,
+ })
+ );
+ }
+ });
+ });
+ });
// Delete from server
const { requestId } = dispatch(
@@ -154,17 +197,58 @@ export const addRequestedMultipleImageDeletionListener = () => {
dispatch(resetCanvas());
}
- if (imagesUsage.some((i) => i.isControlNetImage)) {
- dispatch(controlNetReset());
- }
+ imageDTOs.forEach((imageDTO) => {
+ // reset init image if we deleted it
+ if (
+ getState().generation.initialImage?.imageName ===
+ imageDTO.image_name
+ ) {
+ dispatch(clearInitialImage());
+ }
- if (imagesUsage.some((i) => i.isInitialImage)) {
- dispatch(clearInitialImage());
- }
+ // reset controlNets that use the deleted images
+ forEach(getState().controlNet.controlNets, (controlNet) => {
+ if (
+ controlNet.controlImage === imageDTO.image_name ||
+ controlNet.processedControlImage === imageDTO.image_name
+ ) {
+ dispatch(
+ controlNetImageChanged({
+ controlNetId: controlNet.controlNetId,
+ controlImage: null,
+ })
+ );
+ dispatch(
+ controlNetProcessedImageChanged({
+ controlNetId: controlNet.controlNetId,
+ processedControlImage: null,
+ })
+ );
+ }
+ });
- if (imagesUsage.some((i) => i.isNodesImage)) {
- dispatch(nodeEditorReset());
- }
+ // reset nodes that use the deleted images
+ getState().nodes.nodes.forEach((node) => {
+ if (!isInvocationNode(node)) {
+ return;
+ }
+
+ forEach(node.data.inputs, (input) => {
+ if (
+ input.type === 'ImageField' &&
+ input.value?.image_name === imageDTO.image_name
+ ) {
+ dispatch(
+ fieldImageValueChanged({
+ nodeId: node.data.id,
+ fieldName: input.name,
+ value: undefined,
+ })
+ );
+ }
+ });
+ });
+ });
} catch {
// no-op
}
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts
index 32a6cce203..739bbd7110 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts
@@ -5,6 +5,7 @@ import { modelsApi } from 'services/api/endpoints/models';
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
import { appSocketConnected, socketConnected } from 'services/events/actions';
import { startAppListening } from '../..';
+import { size } from 'lodash-es';
export const addSocketConnectedEventListener = () => {
startAppListening({
@@ -18,7 +19,7 @@ export const addSocketConnectedEventListener = () => {
const { disabledTabs } = config;
- if (!nodes.schema && !disabledTabs.includes('nodes')) {
+ if (!size(nodes.nodeTemplates) && !disabledTabs.includes('nodes')) {
dispatch(receivedOpenAPISchema());
}
diff --git a/invokeai/frontend/web/src/common/components/IAIButton.tsx b/invokeai/frontend/web/src/common/components/IAIButton.tsx
index d1e77537cc..4058296aaf 100644
--- a/invokeai/frontend/web/src/common/components/IAIButton.tsx
+++ b/invokeai/frontend/web/src/common/components/IAIButton.tsx
@@ -8,8 +8,8 @@ import {
import { memo, ReactNode } from 'react';
export interface IAIButtonProps extends ButtonProps {
- tooltip?: string;
- tooltipProps?: Omit;
+ tooltip?: TooltipProps['label'];
+ tooltipProps?: Omit;
isChecked?: boolean;
children: ReactNode;
}
diff --git a/invokeai/frontend/web/src/common/components/IAICollapse.tsx b/invokeai/frontend/web/src/common/components/IAICollapse.tsx
index 0ce767ed9d..a5e08e6ddc 100644
--- a/invokeai/frontend/web/src/common/components/IAICollapse.tsx
+++ b/invokeai/frontend/web/src/common/components/IAICollapse.tsx
@@ -34,14 +34,10 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
gap: 2,
borderTopRadius: 'base',
borderBottomRadius: isOpen ? 0 : 'base',
- bg: isOpen
- ? mode('base.200', 'base.750')(colorMode)
- : mode('base.150', 'base.800')(colorMode),
+ bg: mode('base.250', 'base.750')(colorMode),
color: mode('base.900', 'base.100')(colorMode),
_hover: {
- bg: isOpen
- ? mode('base.250', 'base.700')(colorMode)
- : mode('base.200', 'base.750')(colorMode),
+ bg: mode('base.300', 'base.700')(colorMode),
},
fontSize: 'sm',
fontWeight: 600,
@@ -90,9 +86,10 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
{
const [isHovered, setIsHovered] = useState(false);
const handleMouseOver = useCallback(
(e: MouseEvent) => {
- if (onMouseOver) onMouseOver(e);
+ if (onMouseOver) {
+ onMouseOver(e);
+ }
setIsHovered(true);
},
[onMouseOver]
);
const handleMouseOut = useCallback(
(e: MouseEvent) => {
- if (onMouseOut) onMouseOut(e);
+ if (onMouseOut) {
+ onMouseOut(e);
+ }
setIsHovered(false);
},
[onMouseOut]
@@ -122,7 +126,7 @@ const IAIDndImage = (props: IAIDndImageProps) => {
? {}
: {
cursor: 'pointer',
- bg: mode('base.200', 'base.800')(colorMode),
+ bg: mode('base.200', 'base.700')(colorMode),
_hover: {
bg: mode('base.300', 'base.650')(colorMode),
color: mode('base.500', 'base.300')(colorMode),
diff --git a/invokeai/frontend/web/src/common/components/IAIErrorLoadingImageFallback.tsx b/invokeai/frontend/web/src/common/components/IAIErrorLoadingImageFallback.tsx
index 2136acc3c3..0a5d4fb12f 100644
--- a/invokeai/frontend/web/src/common/components/IAIErrorLoadingImageFallback.tsx
+++ b/invokeai/frontend/web/src/common/components/IAIErrorLoadingImageFallback.tsx
@@ -1,4 +1,5 @@
import { Box, Flex, Icon } from '@chakra-ui/react';
+import { memo } from 'react';
import { FaExclamation } from 'react-icons/fa';
const IAIErrorLoadingImageFallback = () => {
@@ -39,4 +40,4 @@ const IAIErrorLoadingImageFallback = () => {
);
};
-export default IAIErrorLoadingImageFallback;
+export default memo(IAIErrorLoadingImageFallback);
diff --git a/invokeai/frontend/web/src/common/components/IAIFillSkeleton.tsx b/invokeai/frontend/web/src/common/components/IAIFillSkeleton.tsx
index a3c83cb734..8081714432 100644
--- a/invokeai/frontend/web/src/common/components/IAIFillSkeleton.tsx
+++ b/invokeai/frontend/web/src/common/components/IAIFillSkeleton.tsx
@@ -1,4 +1,5 @@
import { Box, Skeleton } from '@chakra-ui/react';
+import { memo } from 'react';
const IAIFillSkeleton = () => {
return (
@@ -27,4 +28,4 @@ const IAIFillSkeleton = () => {
);
};
-export default IAIFillSkeleton;
+export default memo(IAIFillSkeleton);
diff --git a/invokeai/frontend/web/src/common/components/IAIIconButton.tsx b/invokeai/frontend/web/src/common/components/IAIIconButton.tsx
index ed1514055e..0a42430689 100644
--- a/invokeai/frontend/web/src/common/components/IAIIconButton.tsx
+++ b/invokeai/frontend/web/src/common/components/IAIIconButton.tsx
@@ -9,8 +9,8 @@ import { memo } from 'react';
export type IAIIconButtonProps = IconButtonProps & {
role?: string;
- tooltip?: string;
- tooltipProps?: Omit;
+ tooltip?: TooltipProps['label'];
+ tooltipProps?: Omit;
isChecked?: boolean;
};
diff --git a/invokeai/frontend/web/src/common/components/ImageMetadataOverlay.tsx b/invokeai/frontend/web/src/common/components/ImageMetadataOverlay.tsx
index 3ef7d8f83e..765dd3c000 100644
--- a/invokeai/frontend/web/src/common/components/ImageMetadataOverlay.tsx
+++ b/invokeai/frontend/web/src/common/components/ImageMetadataOverlay.tsx
@@ -1,4 +1,5 @@
import { Badge, Flex } from '@chakra-ui/react';
+import { memo } from 'react';
import { ImageDTO } from 'services/api/types';
type ImageMetadataOverlayProps = {
@@ -26,4 +27,4 @@ const ImageMetadataOverlay = ({ imageDTO }: ImageMetadataOverlayProps) => {
);
};
-export default ImageMetadataOverlay;
+export default memo(ImageMetadataOverlay);
diff --git a/invokeai/frontend/web/src/common/components/ImageUploadOverlay.tsx b/invokeai/frontend/web/src/common/components/ImageUploadOverlay.tsx
index b2d5ddb2da..5c91a7ceda 100644
--- a/invokeai/frontend/web/src/common/components/ImageUploadOverlay.tsx
+++ b/invokeai/frontend/web/src/common/components/ImageUploadOverlay.tsx
@@ -1,4 +1,5 @@
import { Box, Flex, Heading } from '@chakra-ui/react';
+import { memo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
type ImageUploadOverlayProps = {
@@ -87,4 +88,4 @@ const ImageUploadOverlay = (props: ImageUploadOverlayProps) => {
);
};
-export default ImageUploadOverlay;
+export default memo(ImageUploadOverlay);
diff --git a/invokeai/frontend/web/src/common/components/ImageUploader.tsx b/invokeai/frontend/web/src/common/components/ImageUploader.tsx
index c990a9a24e..5f95056a51 100644
--- a/invokeai/frontend/web/src/common/components/ImageUploader.tsx
+++ b/invokeai/frontend/web/src/common/components/ImageUploader.tsx
@@ -150,7 +150,9 @@ const ImageUploader = (props: ImageUploaderProps) => {
{...getRootProps({ style: {} })}
onKeyDown={(e: KeyboardEvent) => {
// Bail out if user hits spacebar - do not open the uploader
- if (e.key === ' ') return;
+ if (e.key === ' ') {
+ return;
+ }
}}
>
diff --git a/invokeai/frontend/web/src/common/components/SelectImagePlaceholder.tsx b/invokeai/frontend/web/src/common/components/SelectImagePlaceholder.tsx
index a19d447755..2db202ddc0 100644
--- a/invokeai/frontend/web/src/common/components/SelectImagePlaceholder.tsx
+++ b/invokeai/frontend/web/src/common/components/SelectImagePlaceholder.tsx
@@ -1,4 +1,5 @@
import { Flex, Icon } from '@chakra-ui/react';
+import { memo } from 'react';
import { FaImage } from 'react-icons/fa';
const SelectImagePlaceholder = () => {
@@ -19,4 +20,4 @@ const SelectImagePlaceholder = () => {
);
};
-export default SelectImagePlaceholder;
+export default memo(SelectImagePlaceholder);
diff --git a/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx b/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx
index 9ff6cd341b..aed5e1f083 100644
--- a/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx
+++ b/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx
@@ -1,4 +1,5 @@
import { Box } from '@chakra-ui/react';
+import { memo } from 'react';
type Props = {
isSelected: boolean;
@@ -18,6 +19,7 @@ const SelectionOverlay = ({ isSelected, isHovered }: Props) => {
opacity: isSelected ? 1 : 0.7,
transitionProperty: 'common',
transitionDuration: '0.1s',
+ pointerEvents: 'none',
shadow: isSelected
? isHovered
? 'hoverSelected.light'
@@ -39,4 +41,4 @@ const SelectionOverlay = ({ isSelected, isHovered }: Props) => {
);
};
-export default SelectionOverlay;
+export default memo(SelectionOverlay);
diff --git a/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts b/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
index f43ec1851f..e06a1106c1 100644
--- a/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
+++ b/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
@@ -2,71 +2,108 @@ import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-// import { validateSeedWeights } from 'common/util/seedWeightPairs';
+import { isInvocationNode } from 'features/nodes/types/types';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import { forEach } from 'lodash-es';
-import { NON_REFINER_BASE_MODELS } from 'services/api/constants';
-import { modelsApi } from '../../services/api/endpoints/models';
+import { forEach, map } from 'lodash-es';
+import { getConnectedEdges } from 'reactflow';
-const readinessSelector = createSelector(
+const selector = createSelector(
[stateSelector, activeTabNameSelector],
(state, activeTabName) => {
- const { generation, system } = state;
- const { initialImage } = generation;
+ const { generation, system, nodes } = state;
+ const { initialImage, model } = generation;
const { isProcessing, isConnected } = system;
- let isReady = true;
- const reasonsWhyNotReady: string[] = [];
+ const reasons: string[] = [];
- if (activeTabName === 'img2img' && !initialImage) {
- isReady = false;
- reasonsWhyNotReady.push('No initial image selected');
- }
-
- const { isSuccess: mainModelsSuccessfullyLoaded } =
- modelsApi.endpoints.getMainModels.select(NON_REFINER_BASE_MODELS)(state);
- if (!mainModelsSuccessfullyLoaded) {
- isReady = false;
- reasonsWhyNotReady.push('Models are not loaded');
- }
-
- // TODO: job queue
// Cannot generate if already processing an image
if (isProcessing) {
- isReady = false;
- reasonsWhyNotReady.push('System Busy');
+ reasons.push('System busy');
}
// Cannot generate if not connected
if (!isConnected) {
- isReady = false;
- reasonsWhyNotReady.push('System Disconnected');
+ reasons.push('System disconnected');
}
- // // Cannot generate variations without valid seed weights
- // if (
- // shouldGenerateVariations &&
- // (!(validateSeedWeights(seedWeights) || seedWeights === '') || seed === -1)
- // ) {
- // isReady = false;
- // reasonsWhyNotReady.push('Seed-Weights badly formatted.');
- // }
+ if (activeTabName === 'img2img' && !initialImage) {
+ reasons.push('No initial image selected');
+ }
- forEach(state.controlNet.controlNets, (controlNet, id) => {
- if (!controlNet.model) {
- isReady = false;
- reasonsWhyNotReady.push(`ControlNet ${id} has no model selected.`);
+ if (activeTabName === 'nodes' && nodes.shouldValidateGraph) {
+ if (!nodes.nodes.length) {
+ reasons.push('No nodes in graph');
}
- });
- // All good
- return { isReady, reasonsWhyNotReady };
+ nodes.nodes.forEach((node) => {
+ if (!isInvocationNode(node)) {
+ return;
+ }
+
+ const nodeTemplate = nodes.nodeTemplates[node.data.type];
+
+ if (!nodeTemplate) {
+ // Node type not found
+ reasons.push('Missing node template');
+ return;
+ }
+
+ const connectedEdges = getConnectedEdges([node], nodes.edges);
+
+ forEach(node.data.inputs, (field) => {
+ const fieldTemplate = nodeTemplate.inputs[field.name];
+ const hasConnection = connectedEdges.some(
+ (edge) =>
+ edge.target === node.id && edge.targetHandle === field.name
+ );
+
+ if (!fieldTemplate) {
+ reasons.push('Missing field template');
+ return;
+ }
+
+ if (fieldTemplate.required && !field.value && !hasConnection) {
+ reasons.push(
+ `${node.data.label || nodeTemplate.title} -> ${
+ field.label || fieldTemplate.title
+ } missing input`
+ );
+ return;
+ }
+ });
+ });
+ } else {
+ if (!model) {
+ reasons.push('No model selected');
+ }
+
+ if (state.controlNet.isEnabled) {
+ map(state.controlNet.controlNets).forEach((controlNet, i) => {
+ if (!controlNet.isEnabled) {
+ return;
+ }
+ if (!controlNet.model) {
+ reasons.push(`ControlNet ${i + 1} has no model selected.`);
+ }
+
+ if (
+ !controlNet.controlImage ||
+ (!controlNet.processedControlImage &&
+ controlNet.processorType !== 'none')
+ ) {
+ reasons.push(`ControlNet ${i + 1} has no control image`);
+ }
+ });
+ }
+ }
+
+ return { isReady: !reasons.length, isProcessing, reasons };
},
defaultSelectorOptions
);
export const useIsReadyToInvoke = () => {
- const { isReady } = useAppSelector(readinessSelector);
- return isReady;
+ const { isReady, isProcessing, reasons } = useAppSelector(selector);
+ return { isReady, isProcessing, reasons };
};
diff --git a/invokeai/frontend/web/src/common/hooks/useResolution.ts b/invokeai/frontend/web/src/common/hooks/useResolution.ts
index 96b95ee074..fb52555be8 100644
--- a/invokeai/frontend/web/src/common/hooks/useResolution.ts
+++ b/invokeai/frontend/web/src/common/hooks/useResolution.ts
@@ -11,8 +11,14 @@ export default function useResolution():
const tabletResolutions = ['md', 'lg'];
const desktopResolutions = ['xl', '2xl'];
- if (mobileResolutions.includes(breakpointValue)) return 'mobile';
- if (tabletResolutions.includes(breakpointValue)) return 'tablet';
- if (desktopResolutions.includes(breakpointValue)) return 'desktop';
+ if (mobileResolutions.includes(breakpointValue)) {
+ return 'mobile';
+ }
+ if (tabletResolutions.includes(breakpointValue)) {
+ return 'tablet';
+ }
+ if (desktopResolutions.includes(breakpointValue)) {
+ return 'desktop';
+ }
return 'unknown';
}
diff --git a/invokeai/frontend/web/src/common/util/colorTokenToCssVar.ts b/invokeai/frontend/web/src/common/util/colorTokenToCssVar.ts
new file mode 100644
index 0000000000..e29005186f
--- /dev/null
+++ b/invokeai/frontend/web/src/common/util/colorTokenToCssVar.ts
@@ -0,0 +1,2 @@
+export const colorTokenToCssVar = (colorToken: string) =>
+ `var(--invokeai-colors-${colorToken.split('.').join('-')}`;
diff --git a/invokeai/frontend/web/src/common/util/dateComparator.ts b/invokeai/frontend/web/src/common/util/dateComparator.ts
index ea0dc28b6d..27af542261 100644
--- a/invokeai/frontend/web/src/common/util/dateComparator.ts
+++ b/invokeai/frontend/web/src/common/util/dateComparator.ts
@@ -6,7 +6,11 @@ export const dateComparator = (a: string, b: string) => {
const dateB = new Date(b);
// sort in ascending order
- if (dateA > dateB) return 1;
- if (dateA < dateB) return -1;
+ if (dateA > dateB) {
+ return 1;
+ }
+ if (dateA < dateB) {
+ return -1;
+ }
return 0;
};
diff --git a/invokeai/frontend/web/src/common/util/openBase64ImageInTab.ts b/invokeai/frontend/web/src/common/util/openBase64ImageInTab.ts
index 0e18ccb45f..71d3bcd661 100644
--- a/invokeai/frontend/web/src/common/util/openBase64ImageInTab.ts
+++ b/invokeai/frontend/web/src/common/util/openBase64ImageInTab.ts
@@ -5,7 +5,9 @@ type Base64AndCaption = {
const openBase64ImageInTab = (images: Base64AndCaption[]) => {
const w = window.open('');
- if (!w) return;
+ if (!w) {
+ return;
+ }
images.forEach((i) => {
const image = new Image();
diff --git a/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx b/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx
index 49a13c401c..a86497aade 100644
--- a/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx
@@ -5,6 +5,7 @@ import { clearCanvasHistory } from 'features/canvas/store/canvasSlice';
import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa';
import { isStagingSelector } from '../store/canvasSelectors';
+import { memo } from 'react';
const ClearCanvasHistoryButtonModal = () => {
const isStaging = useAppSelector(isStagingSelector);
@@ -28,4 +29,4 @@ const ClearCanvasHistoryButtonModal = () => {
);
};
-export default ClearCanvasHistoryButtonModal;
+export default memo(ClearCanvasHistoryButtonModal);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
index 7a82e64270..4f9e47282d 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx
@@ -1,6 +1,6 @@
import { Box, chakra, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
-import { useAppSelector } from 'app/store/storeHooks';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import {
canvasSelector,
@@ -9,7 +9,7 @@ import {
import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types';
-import { useCallback, useRef } from 'react';
+import { memo, useCallback, useEffect, useRef } from 'react';
import { Layer, Stage } from 'react-konva';
import useCanvasDragMove from '../hooks/useCanvasDragMove';
import useCanvasHotkeys from '../hooks/useCanvasHotkeys';
@@ -18,6 +18,7 @@ import useCanvasMouseMove from '../hooks/useCanvasMouseMove';
import useCanvasMouseOut from '../hooks/useCanvasMouseOut';
import useCanvasMouseUp from '../hooks/useCanvasMouseUp';
import useCanvasWheel from '../hooks/useCanvasZoom';
+import { canvasResized } from '../store/canvasSlice';
import {
setCanvasBaseLayer,
setCanvasStage,
@@ -106,7 +107,8 @@ const IAICanvas = () => {
shouldAntialias,
} = useAppSelector(selector);
useCanvasHotkeys();
-
+ const dispatch = useAppDispatch();
+ const containerRef = useRef(null);
const stageRef = useRef(null);
const canvasBaseLayerRef = useRef(null);
@@ -137,8 +139,30 @@ const IAICanvas = () => {
const { handleDragStart, handleDragMove, handleDragEnd } =
useCanvasDragMove();
+ useEffect(() => {
+ if (!containerRef.current) {
+ return;
+ }
+ const resizeObserver = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ if (entry.contentBoxSize) {
+ const { width, height } = entry.contentRect;
+ dispatch(canvasResized({ width, height }));
+ }
+ }
+ });
+
+ resizeObserver.observe(containerRef.current);
+
+ return () => {
+ resizeObserver.disconnect();
+ };
+ }, [dispatch]);
+
return (
{
borderRadius: 'base',
}}
>
-
+
{
/>
-
-
+
+
);
};
-export default IAICanvas;
+export default memo(IAICanvas);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx
index e90d2c4d25..22a8848cad 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx
@@ -4,6 +4,7 @@ import { isEqual } from 'lodash-es';
import { Group, Rect } from 'react-konva';
import { canvasSelector } from '../store/canvasSelectors';
+import { memo } from 'react';
const selector = createSelector(
canvasSelector,
@@ -67,4 +68,4 @@ const IAICanvasBoundingBoxOverlay = () => {
);
};
-export default IAICanvasBoundingBoxOverlay;
+export default memo(IAICanvasBoundingBoxOverlay);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx
index 1b97acba71..50a68357fb 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx
@@ -6,7 +6,7 @@ import { useAppSelector } from 'app/store/storeHooks';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { isEqual, range } from 'lodash-es';
-import { ReactNode, useCallback, useLayoutEffect, useState } from 'react';
+import { ReactNode, memo, useCallback, useLayoutEffect, useState } from 'react';
import { Group, Line as KonvaLine } from 'react-konva';
const selector = createSelector(
@@ -117,4 +117,4 @@ const IAICanvasGrid = () => {
return {gridLines};
};
-export default IAICanvasGrid;
+export default memo(IAICanvasGrid);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx
index eb41857e46..9f8829c280 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasImage.tsx
@@ -4,6 +4,7 @@ import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import useImage from 'use-image';
import { CanvasImage } from '../store/canvasTypes';
import { $authToken } from 'services/api/client';
+import { memo } from 'react';
type IAICanvasImageProps = {
canvasImage: CanvasImage;
@@ -25,4 +26,4 @@ const IAICanvasImage = (props: IAICanvasImageProps) => {
return ;
};
-export default IAICanvasImage;
+export default memo(IAICanvasImage);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx
index ea5e9a6486..b636ef9528 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx
@@ -4,7 +4,7 @@ import { systemSelector } from 'features/system/store/systemSelectors';
import { ImageConfig } from 'konva/lib/shapes/Image';
import { isEqual } from 'lodash-es';
-import { useEffect, useState } from 'react';
+import { memo, useEffect, useState } from 'react';
import { Image as KonvaImage } from 'react-konva';
import { canvasSelector } from '../store/canvasSelectors';
@@ -66,4 +66,4 @@ const IAICanvasIntermediateImage = (props: Props) => {
) : null;
};
-export default IAICanvasIntermediateImage;
+export default memo(IAICanvasIntermediateImage);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
index e374d2aa7b..e65f51cade 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx
@@ -7,7 +7,7 @@ import { Rect } from 'react-konva';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import Konva from 'konva';
import { isNumber } from 'lodash-es';
-import { useCallback, useEffect, useRef, useState } from 'react';
+import { memo, useCallback, useEffect, useRef, useState } from 'react';
export const canvasMaskCompositerSelector = createSelector(
canvasSelector,
@@ -125,7 +125,9 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
}, [offset]);
useEffect(() => {
- if (fillPatternImage) return;
+ if (fillPatternImage) {
+ return;
+ }
const image = new Image();
image.onload = () => {
@@ -135,7 +137,9 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
}, [fillPatternImage, maskColorString]);
useEffect(() => {
- if (!fillPatternImage) return;
+ if (!fillPatternImage) {
+ return;
+ }
fillPatternImage.src = getColoredSVG(maskColorString);
}, [fillPatternImage, maskColorString]);
@@ -151,8 +155,9 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
!isNumber(stageScale) ||
!isNumber(stageDimensions.width) ||
!isNumber(stageDimensions.height)
- )
+ ) {
return null;
+ }
return (
{
);
};
-export default IAICanvasMaskCompositer;
+export default memo(IAICanvasMaskCompositer);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx
index a553653901..ca91e11350 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx
@@ -6,6 +6,7 @@ import { isEqual } from 'lodash-es';
import { Group, Line } from 'react-konva';
import { isCanvasMaskLine } from '../store/canvasTypes';
+import { memo } from 'react';
export const canvasLinesSelector = createSelector(
[canvasSelector],
@@ -52,4 +53,4 @@ const IAICanvasLines = (props: InpaintingCanvasLinesProps) => {
);
};
-export default IAICanvasLines;
+export default memo(IAICanvasLines);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx
index ec1e87cca7..c56dba2b8c 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx
@@ -12,6 +12,7 @@ import {
isCanvasFillRect,
} from '../store/canvasTypes';
import IAICanvasImage from './IAICanvasImage';
+import { memo } from 'react';
const selector = createSelector(
[canvasSelector],
@@ -33,7 +34,9 @@ const selector = createSelector(
const IAICanvasObjectRenderer = () => {
const { objects } = useAppSelector(selector);
- if (!objects) return null;
+ if (!objects) {
+ return null;
+ }
return (
@@ -101,4 +104,4 @@ const IAICanvasObjectRenderer = () => {
);
};
-export default IAICanvasObjectRenderer;
+export default memo(IAICanvasObjectRenderer);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx
deleted file mode 100644
index d16a5dab87..0000000000
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { Flex, Spinner } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import {
- canvasSelector,
- initialCanvasImageSelector,
-} from 'features/canvas/store/canvasSelectors';
-import {
- resizeAndScaleCanvas,
- resizeCanvas,
- setCanvasContainerDimensions,
- setDoesCanvasNeedScaling,
-} from 'features/canvas/store/canvasSlice';
-import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import { useLayoutEffect, useRef } from 'react';
-
-const canvasResizerSelector = createSelector(
- canvasSelector,
- initialCanvasImageSelector,
- activeTabNameSelector,
- (canvas, initialCanvasImage, activeTabName) => {
- const { doesCanvasNeedScaling, isCanvasInitialized } = canvas;
- return {
- doesCanvasNeedScaling,
- activeTabName,
- initialCanvasImage,
- isCanvasInitialized,
- };
- }
-);
-
-const IAICanvasResizer = () => {
- const dispatch = useAppDispatch();
- const {
- doesCanvasNeedScaling,
- activeTabName,
- initialCanvasImage,
- isCanvasInitialized,
- } = useAppSelector(canvasResizerSelector);
-
- const ref = useRef(null);
-
- useLayoutEffect(() => {
- window.setTimeout(() => {
- if (!ref.current) return;
-
- const { clientWidth, clientHeight } = ref.current;
-
- dispatch(
- setCanvasContainerDimensions({
- width: clientWidth,
- height: clientHeight,
- })
- );
-
- if (!isCanvasInitialized) {
- dispatch(resizeAndScaleCanvas());
- } else {
- dispatch(resizeCanvas());
- }
-
- dispatch(setDoesCanvasNeedScaling(false));
- }, 0);
- }, [
- dispatch,
- initialCanvasImage,
- doesCanvasNeedScaling,
- activeTabName,
- isCanvasInitialized,
- ]);
-
- return (
-
-
-
- );
-};
-
-export default IAICanvasResizer;
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
index 5355e28762..fa73f020da 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx
@@ -6,6 +6,7 @@ import { isEqual } from 'lodash-es';
import { Group, Rect } from 'react-konva';
import IAICanvasImage from './IAICanvasImage';
+import { memo } from 'react';
const selector = createSelector(
[canvasSelector],
@@ -88,4 +89,4 @@ const IAICanvasStagingArea = (props: Props) => {
);
};
-export default IAICanvasStagingArea;
+export default memo(IAICanvasStagingArea);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx
index 1929bff8f9..cc15141d38 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx
@@ -13,7 +13,7 @@ import {
} from 'features/canvas/store/canvasSlice';
import { isEqual } from 'lodash-es';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import {
@@ -129,7 +129,9 @@ const IAICanvasStagingAreaToolbar = () => {
currentStagingAreaImage?.imageName ?? skipToken
);
- if (!currentStagingAreaImage) return null;
+ if (!currentStagingAreaImage) {
+ return null;
+ }
return (
{
w="100%"
align="center"
justify="center"
- filter="drop-shadow(0 0.5rem 1rem rgba(0,0,0))"
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
>
-
+
{
);
};
-export default IAICanvasStagingAreaToolbar;
+export default memo(IAICanvasStagingAreaToolbar);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx
index 8c1dfbb86f..7aa9cad003 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx
@@ -7,6 +7,7 @@ import { isEqual } from 'lodash-es';
import { useTranslation } from 'react-i18next';
import roundToHundreth from '../util/roundToHundreth';
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
+import { memo } from 'react';
const warningColor = 'var(--invokeai-colors-warning-500)';
@@ -162,4 +163,4 @@ const IAICanvasStatusText = () => {
);
};
-export default IAICanvasStatusText;
+export default memo(IAICanvasStatusText);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx
index 8ad58e020c..7529ec42a0 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx
@@ -10,6 +10,7 @@ import {
COLOR_PICKER_SIZE,
COLOR_PICKER_STROKE_RADIUS,
} from '../util/constants';
+import { memo } from 'react';
const canvasBrushPreviewSelector = createSelector(
canvasSelector,
@@ -134,7 +135,9 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
clip,
} = useAppSelector(canvasBrushPreviewSelector);
- if (!shouldDrawBrushPreview) return null;
+ if (!shouldDrawBrushPreview) {
+ return null;
+ }
return (
@@ -206,4 +209,4 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
);
};
-export default IAICanvasToolPreview;
+export default memo(IAICanvasToolPreview);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
index 41c281d259..0f94b1c57a 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx
@@ -19,7 +19,7 @@ import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types';
import { isEqual } from 'lodash-es';
-import { useCallback, useEffect, useRef, useState } from 'react';
+import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { Group, Rect, Transformer } from 'react-konva';
@@ -85,7 +85,9 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
useState(false);
useEffect(() => {
- if (!transformerRef.current || !shapeRef.current) return;
+ if (!transformerRef.current || !shapeRef.current) {
+ return;
+ }
transformerRef.current.nodes([shapeRef.current]);
transformerRef.current.getLayer()?.batchDraw();
}, []);
@@ -133,7 +135,9 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
* not its width and height. We need to un-scale the width and height before
* setting the values.
*/
- if (!shapeRef.current) return;
+ if (!shapeRef.current) {
+ return;
+ }
const rect = shapeRef.current;
@@ -313,4 +317,4 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
);
};
-export default IAICanvasBoundingBox;
+export default memo(IAICanvasBoundingBox);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx
index 25ef295631..76211a2e95 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx
@@ -20,6 +20,7 @@ import {
} from 'features/canvas/store/canvasSlice';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { isEqual } from 'lodash-es';
+import { memo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
@@ -150,4 +151,4 @@ const IAICanvasMaskOptions = () => {
);
};
-export default IAICanvasMaskOptions;
+export default memo(IAICanvasMaskOptions);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx
index ae03df8409..aae2da5632 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx
@@ -18,7 +18,7 @@ import {
} from 'features/canvas/store/canvasSlice';
import { isEqual } from 'lodash-es';
-import { ChangeEvent } from 'react';
+import { ChangeEvent, memo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { FaWrench } from 'react-icons/fa';
@@ -163,4 +163,4 @@ const IAICanvasSettingsButtonPopover = () => {
);
};
-export default IAICanvasSettingsButtonPopover;
+export default memo(IAICanvasSettingsButtonPopover);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
index 158e2954af..a3e8f6af8b 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx
@@ -18,6 +18,7 @@ import {
} from 'features/canvas/store/canvasSlice';
import { systemSelector } from 'features/system/store/systemSelectors';
import { clamp, isEqual } from 'lodash-es';
+import { memo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
@@ -252,4 +253,4 @@ const IAICanvasToolChooserOptions = () => {
);
};
-export default IAICanvasToolChooserOptions;
+export default memo(IAICanvasToolChooserOptions);
diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx
index 26ccfe31b6..49ce63d25f 100644
--- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx
+++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx
@@ -18,7 +18,6 @@ import {
import {
resetCanvas,
resetCanvasView,
- resizeAndScaleCanvas,
setIsMaskEnabled,
setLayer,
setTool,
@@ -48,6 +47,7 @@ import IAICanvasRedoButton from './IAICanvasRedoButton';
import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover';
import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
import IAICanvasUndoButton from './IAICanvasUndoButton';
+import { memo } from 'react';
export const selector = createSelector(
[systemSelector, canvasSelector, isStagingSelector],
@@ -166,7 +166,9 @@ const IAICanvasToolbar = () => {
const handleResetCanvasView = (shouldScaleTo1 = false) => {
const canvasBaseLayer = getCanvasBaseLayer();
- if (!canvasBaseLayer) return;
+ if (!canvasBaseLayer) {
+ return;
+ }
const clientRect = canvasBaseLayer.getClientRect({
skipTransform: true,
});
@@ -180,7 +182,6 @@ const IAICanvasToolbar = () => {
const handleResetCanvas = () => {
dispatch(resetCanvas());
- dispatch(resizeAndScaleCanvas());
};
const handleMergeVisible = () => {
@@ -309,4 +310,4 @@ const IAICanvasToolbar = () => {
);
};
-export default IAICanvasToolbar;
+export default memo(IAICanvasToolbar);
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts
index 6861c25842..81e9c0b855 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts
@@ -32,13 +32,17 @@ const useCanvasDrag = () => {
return {
handleDragStart: useCallback(() => {
- if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) return;
+ if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
+ return;
+ }
dispatch(setIsMovingStage(true));
}, [dispatch, isMovingBoundingBox, isStaging, tool]),
handleDragMove: useCallback(
(e: KonvaEventObject) => {
- if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) return;
+ if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
+ return;
+ }
const newCoordinates = { x: e.target.x(), y: e.target.y() };
@@ -48,7 +52,9 @@ const useCanvasDrag = () => {
),
handleDragEnd: useCallback(() => {
- if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) return;
+ if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {
+ return;
+ }
dispatch(setIsMovingStage(false));
}, [dispatch, isMovingBoundingBox, isStaging, tool]),
};
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts
index 6f4669a42a..1641360e5e 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts
@@ -134,7 +134,9 @@ const useInpaintingCanvasHotkeys = () => {
useHotkeys(
['space'],
(e: KeyboardEvent) => {
- if (e.repeat) return;
+ if (e.repeat) {
+ return;
+ }
canvasStage?.container().focus();
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts
index 67bf7a8539..d98a44edd9 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts
@@ -38,7 +38,9 @@ const useCanvasMouseDown = (stageRef: MutableRefObject) => {
return useCallback(
(e: KonvaEventObject) => {
- if (!stageRef.current) return;
+ if (!stageRef.current) {
+ return;
+ }
stageRef.current.container().focus();
@@ -54,7 +56,9 @@ const useCanvasMouseDown = (stageRef: MutableRefObject) => {
const scaledCursorPosition = getScaledCursorPosition(stageRef.current);
- if (!scaledCursorPosition) return;
+ if (!scaledCursorPosition) {
+ return;
+ }
e.evt.preventDefault();
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts
index abeab825e4..088356006e 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts
@@ -41,11 +41,15 @@ const useCanvasMouseMove = (
const { updateColorUnderCursor } = useColorPicker();
return useCallback(() => {
- if (!stageRef.current) return;
+ if (!stageRef.current) {
+ return;
+ }
const scaledCursorPosition = getScaledCursorPosition(stageRef.current);
- if (!scaledCursorPosition) return;
+ if (!scaledCursorPosition) {
+ return;
+ }
dispatch(setCursorPosition(scaledCursorPosition));
@@ -56,7 +60,9 @@ const useCanvasMouseMove = (
return;
}
- if (!isDrawing || tool === 'move' || isStaging) return;
+ if (!isDrawing || tool === 'move' || isStaging) {
+ return;
+ }
didMouseMoveRef.current = true;
dispatch(
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts
index 8e70543c6f..d99d63c223 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts
@@ -47,7 +47,9 @@ const useCanvasMouseUp = (
if (!didMouseMoveRef.current && isDrawing && stageRef.current) {
const scaledCursorPosition = getScaledCursorPosition(stageRef.current);
- if (!scaledCursorPosition) return;
+ if (!scaledCursorPosition) {
+ return;
+ }
/**
* Extend the current line.
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts
index 3d6a1d7804..f58211ca2c 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts
@@ -35,13 +35,17 @@ const useCanvasWheel = (stageRef: MutableRefObject) => {
return useCallback(
(e: KonvaEventObject) => {
// stop default scrolling
- if (!stageRef.current || isMoveStageKeyHeld) return;
+ if (!stageRef.current || isMoveStageKeyHeld) {
+ return;
+ }
e.evt.preventDefault();
const cursorPos = stageRef.current.getPointerPosition();
- if (!cursorPos) return;
+ if (!cursorPos) {
+ return;
+ }
const mousePointTo = {
x: (cursorPos.x - stageRef.current.x()) / stageScale,
diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
index 64289a1fd3..0ade036987 100644
--- a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
+++ b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts
@@ -16,11 +16,15 @@ const useColorPicker = () => {
return {
updateColorUnderCursor: () => {
- if (!stage || !canvasBaseLayer) return;
+ if (!stage || !canvasBaseLayer) {
+ return;
+ }
const position = stage.getPointerPosition();
- if (!position) return;
+ if (!position) {
+ return;
+ }
const pixelRatio = Konva.pixelRatio;
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts
index dc0df55ad0..1990f28516 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts
@@ -3,8 +3,4 @@ import { CanvasState } from './canvasTypes';
/**
* Canvas slice persist denylist
*/
-export const canvasPersistDenylist: (keyof CanvasState)[] = [
- 'cursorPosition',
- 'isCanvasInitialized',
- 'doesCanvasNeedScaling',
-];
+export const canvasPersistDenylist: (keyof CanvasState)[] = ['cursorPosition'];
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts
index 11f829221a..ca26a0567f 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts
@@ -5,10 +5,6 @@ import {
roundToMultiple,
} from 'common/util/roundDownToMultiple';
import { setAspectRatio } from 'features/parameters/store/generationSlice';
-import {
- setActiveTab,
- setShouldUseCanvasBetaLayout,
-} from 'features/ui/store/uiSlice';
import { IRect, Vector2d } from 'konva/lib/types';
import { clamp, cloneDeep } from 'lodash-es';
import { RgbaColor } from 'react-colorful';
@@ -50,12 +46,9 @@ export const initialCanvasState: CanvasState = {
boundingBoxScaleMethod: 'none',
brushColor: { r: 90, g: 90, b: 255, a: 1 },
brushSize: 50,
- canvasContainerDimensions: { width: 0, height: 0 },
colorPickerColor: { r: 90, g: 90, b: 255, a: 1 },
cursorPosition: null,
- doesCanvasNeedScaling: false,
futureLayerStates: [],
- isCanvasInitialized: false,
isDrawing: false,
isMaskEnabled: true,
isMouseOverBoundingBox: false,
@@ -208,7 +201,6 @@ export const canvasSlice = createSlice({
};
state.futureLayerStates = [];
- state.isCanvasInitialized = false;
const newScale = calculateScale(
stageDimensions.width,
stageDimensions.height,
@@ -228,7 +220,6 @@ export const canvasSlice = createSlice({
);
state.stageScale = newScale;
state.stageCoordinates = newCoordinates;
- state.doesCanvasNeedScaling = true;
},
setBoundingBoxDimensions: (state, action: PayloadAction) => {
const newDimensions = roundDimensionsTo64(action.payload);
@@ -258,9 +249,6 @@ export const canvasSlice = createSlice({
setBoundingBoxPreviewFill: (state, action: PayloadAction) => {
state.boundingBoxPreviewFill = action.payload;
},
- setDoesCanvasNeedScaling: (state, action: PayloadAction) => {
- state.doesCanvasNeedScaling = action.payload;
- },
setStageScale: (state, action: PayloadAction) => {
state.stageScale = action.payload;
},
@@ -397,7 +385,9 @@ export const canvasSlice = createSlice({
const { tool, layer, brushColor, brushSize, shouldRestrictStrokesToBox } =
state;
- if (tool === 'move' || tool === 'colorPicker') return;
+ if (tool === 'move' || tool === 'colorPicker') {
+ return;
+ }
const newStrokeWidth = brushSize / 2;
@@ -434,14 +424,18 @@ export const canvasSlice = createSlice({
addPointToCurrentLine: (state, action: PayloadAction) => {
const lastLine = state.layerState.objects.findLast(isCanvasAnyLine);
- if (!lastLine) return;
+ if (!lastLine) {
+ return;
+ }
lastLine.points.push(...action.payload);
},
undo: (state) => {
const targetState = state.pastLayerStates.pop();
- if (!targetState) return;
+ if (!targetState) {
+ return;
+ }
state.futureLayerStates.unshift(cloneDeep(state.layerState));
@@ -454,7 +448,9 @@ export const canvasSlice = createSlice({
redo: (state) => {
const targetState = state.futureLayerStates.shift();
- if (!targetState) return;
+ if (!targetState) {
+ return;
+ }
state.pastLayerStates.push(cloneDeep(state.layerState));
@@ -485,97 +481,14 @@ export const canvasSlice = createSlice({
state.layerState = initialLayerState;
state.futureLayerStates = [];
},
- setCanvasContainerDimensions: (
+ canvasResized: (
state,
- action: PayloadAction
+ action: PayloadAction<{ width: number; height: number }>
) => {
- state.canvasContainerDimensions = action.payload;
- },
- resizeAndScaleCanvas: (state) => {
- const { width: containerWidth, height: containerHeight } =
- state.canvasContainerDimensions;
-
- const initialCanvasImage =
- state.layerState.objects.find(isCanvasBaseImage);
-
+ const { width, height } = action.payload;
const newStageDimensions = {
- width: Math.floor(containerWidth),
- height: Math.floor(containerHeight),
- };
-
- if (!initialCanvasImage) {
- const newScale = calculateScale(
- newStageDimensions.width,
- newStageDimensions.height,
- 512,
- 512,
- STAGE_PADDING_PERCENTAGE
- );
-
- const newCoordinates = calculateCoordinates(
- newStageDimensions.width,
- newStageDimensions.height,
- 0,
- 0,
- 512,
- 512,
- newScale
- );
-
- const newBoundingBoxDimensions = { width: 512, height: 512 };
-
- state.stageScale = newScale;
- state.stageCoordinates = newCoordinates;
- state.stageDimensions = newStageDimensions;
- state.boundingBoxCoordinates = { x: 0, y: 0 };
- state.boundingBoxDimensions = newBoundingBoxDimensions;
-
- if (state.boundingBoxScaleMethod === 'auto') {
- const scaledDimensions = getScaledBoundingBoxDimensions(
- newBoundingBoxDimensions
- );
- state.scaledBoundingBoxDimensions = scaledDimensions;
- }
-
- return;
- }
-
- const { width: imageWidth, height: imageHeight } = initialCanvasImage;
-
- const padding = 0.95;
-
- const newScale = calculateScale(
- containerWidth,
- containerHeight,
- imageWidth,
- imageHeight,
- padding
- );
-
- const newCoordinates = calculateCoordinates(
- newStageDimensions.width,
- newStageDimensions.height,
- 0,
- 0,
- imageWidth,
- imageHeight,
- newScale
- );
-
- state.minimumStageScale = newScale;
- state.stageScale = newScale;
- state.stageCoordinates = floorCoordinates(newCoordinates);
- state.stageDimensions = newStageDimensions;
-
- state.isCanvasInitialized = true;
- },
- resizeCanvas: (state) => {
- const { width: containerWidth, height: containerHeight } =
- state.canvasContainerDimensions;
-
- const newStageDimensions = {
- width: Math.floor(containerWidth),
- height: Math.floor(containerHeight),
+ width: Math.floor(width),
+ height: Math.floor(height),
};
state.stageDimensions = newStageDimensions;
@@ -868,14 +781,6 @@ export const canvasSlice = createSlice({
state.layerState.stagingArea = initialLayerState.stagingArea;
}
});
-
- builder.addCase(setShouldUseCanvasBetaLayout, (state) => {
- state.doesCanvasNeedScaling = true;
- });
-
- builder.addCase(setActiveTab, (state) => {
- state.doesCanvasNeedScaling = true;
- });
builder.addCase(setAspectRatio, (state, action) => {
const ratio = action.payload;
if (ratio) {
@@ -907,8 +812,6 @@ export const {
resetCanvas,
resetCanvasInteractionState,
resetCanvasView,
- resizeAndScaleCanvas,
- resizeCanvas,
setBoundingBoxCoordinates,
setBoundingBoxDimensions,
setBoundingBoxPreviewFill,
@@ -916,10 +819,8 @@ export const {
flipBoundingBoxAxes,
setBrushColor,
setBrushSize,
- setCanvasContainerDimensions,
setColorPickerColor,
setCursorPosition,
- setDoesCanvasNeedScaling,
setInitialCanvasImage,
setIsDrawing,
setIsMaskEnabled,
@@ -958,6 +859,7 @@ export const {
stagingAreaInitialized,
canvasSessionIdChanged,
setShouldAntialias,
+ canvasResized,
} = canvasSlice.actions;
export default canvasSlice.reducer;
diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts
index f2ba90b050..1b4eca329d 100644
--- a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts
+++ b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts
@@ -126,12 +126,9 @@ export interface CanvasState {
boundingBoxScaleMethod: BoundingBoxScale;
brushColor: RgbaColor;
brushSize: number;
- canvasContainerDimensions: Dimensions;
colorPickerColor: RgbaColor;
cursorPosition: Vector2d | null;
- doesCanvasNeedScaling: boolean;
futureLayerStates: CanvasLayerState[];
- isCanvasInitialized: boolean;
isDrawing: boolean;
isMaskEnabled: boolean;
isMouseOverBoundingBox: boolean;
diff --git a/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts b/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts
deleted file mode 100644
index f16c92651a..0000000000
--- a/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { AppDispatch, AppGetState } from 'app/store/store';
-import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import { debounce } from 'lodash-es';
-import { setDoesCanvasNeedScaling } from '../canvasSlice';
-
-const debouncedCanvasScale = debounce((dispatch: AppDispatch) => {
- dispatch(setDoesCanvasNeedScaling(true));
-}, 300);
-
-export const requestCanvasRescale =
- () => (dispatch: AppDispatch, getState: AppGetState) => {
- const activeTabName = activeTabNameSelector(getState());
- if (activeTabName === 'unifiedCanvas') {
- debouncedCanvasScale(dispatch);
- }
- };
diff --git a/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts b/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts
index 03a4d749bf..4cfd7dc8f1 100644
--- a/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts
+++ b/invokeai/frontend/web/src/features/canvas/util/getScaledCursorPosition.ts
@@ -5,7 +5,9 @@ const getScaledCursorPosition = (stage: Stage) => {
const stageTransform = stage.getAbsoluteTransform().copy();
- if (!pointerPosition || !stageTransform) return;
+ if (!pointerPosition || !stageTransform) {
+ return;
+ }
const scaledCursorPosition = stageTransform.invert().point(pointerPosition);
diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx
index 3252207edc..de9995c577 100644
--- a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx
+++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx
@@ -80,19 +80,19 @@ const ControlNet = (props: ControlNetProps) => {
sx={{
flexDir: 'column',
gap: 3,
- p: 3,
+ p: 2,
borderRadius: 'base',
position: 'relative',
- bg: 'base.200',
+ bg: 'base.250',
_dark: {
- bg: 'base.850',
+ bg: 'base.750',
},
}}
>
@@ -194,7 +194,7 @@ const ControlNet = (props: ControlNetProps) => {
aspectRatio: '1/1',
}}
>
-
+
)}
@@ -207,7 +207,7 @@ const ControlNet = (props: ControlNetProps) => {
{isExpanded && (
<>
-
+
>
diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx
index 0683282811..3b92d9d0c6 100644
--- a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx
+++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx
@@ -1,14 +1,14 @@
-import { Box, Flex, Spinner, SystemStyleObject } from '@chakra-ui/react';
+import { Box, Flex, Spinner } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { skipToken } from '@reduxjs/toolkit/dist/query';
-import {
- TypesafeDraggableData,
- TypesafeDroppableData,
-} from 'features/dnd/types';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIDndImage from 'common/components/IAIDndImage';
+import {
+ TypesafeDraggableData,
+ TypesafeDroppableData,
+} from 'features/dnd/types';
import { memo, useCallback, useMemo, useState } from 'react';
import { FaUndo } from 'react-icons/fa';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
@@ -21,7 +21,7 @@ import {
type Props = {
controlNet: ControlNetConfig;
- height: SystemStyleObject['h'];
+ isSmall?: boolean;
};
const selector = createSelector(
@@ -36,15 +36,14 @@ const selector = createSelector(
defaultSelectorOptions
);
-const ControlNetImagePreview = (props: Props) => {
- const { height } = props;
+const ControlNetImagePreview = ({ isSmall, controlNet }: Props) => {
const {
controlImage: controlImageName,
processedControlImage: processedControlImageName,
processorType,
isEnabled,
controlNetId,
- } = props.controlNet;
+ } = controlNet;
const dispatch = useAppDispatch();
@@ -109,7 +108,7 @@ const ControlNetImagePreview = (props: Props) => {
sx={{
position: 'relative',
w: 'full',
- h: height,
+ h: isSmall ? 28 : 366, // magic no touch
alignItems: 'center',
justifyContent: 'center',
pointerEvents: isEnabled ? 'auto' : 'none',
diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx
index 8eed90ce16..97a54dc7d1 100644
--- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx
+++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetFeatureToggle.tsx
@@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch';
import { isControlNetEnabledToggled } from 'features/controlNet/store/controlNetSlice';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
const selector = createSelector(
stateSelector,
@@ -36,4 +36,4 @@ const ParamControlNetFeatureToggle = () => {
);
};
-export default ParamControlNetFeatureToggle;
+export default memo(ParamControlNetFeatureToggle);
diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx
index c08283e1f9..6725c47bb8 100644
--- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx
+++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetWeight.tsx
@@ -23,7 +23,7 @@ const ParamControlNetWeight = (props: ParamControlNetWeightProps) => {
return (
{
);
};
-export default ParamDynamicPromptsCollapse;
+export default memo(ParamDynamicPromptsCollapse);
diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx
index 809ec0df10..c028a5d55c 100644
--- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx
+++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsCombinatorial.tsx
@@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { combinatorialToggled } from '../store/dynamicPromptsSlice';
const selector = createSelector(
@@ -34,4 +34,4 @@ const ParamDynamicPromptsCombinatorial = () => {
);
};
-export default ParamDynamicPromptsCombinatorial;
+export default memo(ParamDynamicPromptsCombinatorial);
diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsEnabled.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsEnabled.tsx
index f92fa410f2..1b31147937 100644
--- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsEnabled.tsx
+++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsEnabled.tsx
@@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { isEnabledToggled } from '../store/dynamicPromptsSlice';
const selector = createSelector(
@@ -33,4 +33,4 @@ const ParamDynamicPromptsToggle = () => {
);
};
-export default ParamDynamicPromptsToggle;
+export default memo(ParamDynamicPromptsToggle);
diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsMaxPrompts.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsMaxPrompts.tsx
index 5bee317d22..f374f1cb15 100644
--- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsMaxPrompts.tsx
+++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsMaxPrompts.tsx
@@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISlider from 'common/components/IAISlider';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import {
maxPromptsChanged,
maxPromptsReset,
@@ -60,4 +60,4 @@ const ParamDynamicPromptsMaxPrompts = () => {
);
};
-export default ParamDynamicPromptsMaxPrompts;
+export default memo(ParamDynamicPromptsMaxPrompts);
diff --git a/invokeai/frontend/web/src/features/embedding/components/ParamEmbeddingPopover.tsx b/invokeai/frontend/web/src/features/embedding/components/ParamEmbeddingPopover.tsx
index 4eb9a67de2..93daaf946f 100644
--- a/invokeai/frontend/web/src/features/embedding/components/ParamEmbeddingPopover.tsx
+++ b/invokeai/frontend/web/src/features/embedding/components/ParamEmbeddingPopover.tsx
@@ -13,7 +13,7 @@ import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSe
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { forEach } from 'lodash-es';
-import { PropsWithChildren, useCallback, useMemo, useRef } from 'react';
+import { PropsWithChildren, memo, useCallback, useMemo, useRef } from 'react';
import { useGetTextualInversionModelsQuery } from 'services/api/endpoints/models';
import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
@@ -118,7 +118,7 @@ const ParamEmbeddingPopover = (props: Props) => {
{
);
};
-export default ParamEmbeddingPopover;
+export default memo(ParamEmbeddingPopover);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx
index ffdde04ef5..4e748d61e8 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx
@@ -1,4 +1,5 @@
import { Badge, Flex } from '@chakra-ui/react';
+import { memo } from 'react';
const AutoAddIcon = () => {
return (
@@ -20,4 +21,4 @@ const AutoAddIcon = () => {
);
};
-export default AutoAddIcon;
+export default memo(AutoAddIcon);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardAutoAddSelect.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardAutoAddSelect.tsx
index 96d17b548e..be19589f9b 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardAutoAddSelect.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardAutoAddSelect.tsx
@@ -6,7 +6,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
-import { useCallback, useRef } from 'react';
+import { memo, useCallback, useRef } from 'react';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
const selector = createSelector(
@@ -66,7 +66,7 @@ const BoardAutoAddSelect = () => {
label="Auto-Add Board"
inputRef={inputRef}
autoFocus
- placeholder={'Select a Board'}
+ placeholder="Select a Board"
value={autoAddBoardId}
data={boards}
nothingFound="No matching Boards"
@@ -81,4 +81,4 @@ const BoardAutoAddSelect = () => {
);
};
-export default BoardAutoAddSelect;
+export default memo(BoardAutoAddSelect);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx
index 0667c05435..6a012030e8 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx
@@ -2,8 +2,12 @@ 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 { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu';
+import {
+ IAIContextMenu,
+ IAIContextMenuProps,
+} from 'common/components/IAIContextMenu';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
+import { BoardId } from 'features/gallery/store/types';
import { MouseEvent, memo, useCallback, useMemo } from 'react';
import { FaPlus } from 'react-icons/fa';
import { useBoardName } from 'services/api/hooks/useBoardName';
@@ -11,80 +15,80 @@ import { BoardDTO } from 'services/api/types';
import { menuListMotionProps } from 'theme/components/menu';
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
import NoBoardContextMenuItems from './NoBoardContextMenuItems';
-import { BoardId } from 'features/gallery/store/types';
type Props = {
board?: BoardDTO;
board_id: BoardId;
- children: ContextMenuProps['children'];
+ children: IAIContextMenuProps['children'];
setBoardToDelete?: (board?: BoardDTO) => void;
};
-const BoardContextMenu = memo(
- ({ board, board_id, setBoardToDelete, children }: Props) => {
- const dispatch = useAppDispatch();
+const BoardContextMenu = ({
+ board,
+ board_id,
+ setBoardToDelete,
+ children,
+}: Props) => {
+ const dispatch = useAppDispatch();
- const selector = useMemo(
- () =>
- createSelector(stateSelector, ({ gallery, system }) => {
- const isAutoAdd = gallery.autoAddBoardId === board_id;
- const isProcessing = system.isProcessing;
- const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
- return { isAutoAdd, isProcessing, autoAssignBoardOnClick };
- }),
- [board_id]
- );
+ const selector = useMemo(
+ () =>
+ createSelector(stateSelector, ({ gallery, system }) => {
+ const isAutoAdd = gallery.autoAddBoardId === board_id;
+ const isProcessing = system.isProcessing;
+ const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
+ return { isAutoAdd, isProcessing, autoAssignBoardOnClick };
+ }),
+ [board_id]
+ );
- const { isAutoAdd, isProcessing, autoAssignBoardOnClick } =
- useAppSelector(selector);
- const boardName = useBoardName(board_id);
+ const { isAutoAdd, isProcessing, autoAssignBoardOnClick } =
+ useAppSelector(selector);
+ const boardName = useBoardName(board_id);
- const handleSetAutoAdd = useCallback(() => {
- dispatch(autoAddBoardIdChanged(board_id));
- }, [board_id, dispatch]);
+ const handleSetAutoAdd = useCallback(() => {
+ dispatch(autoAddBoardIdChanged(board_id));
+ }, [board_id, dispatch]);
- const skipEvent = useCallback((e: MouseEvent) => {
- e.preventDefault();
- }, []);
+ const skipEvent = useCallback((e: MouseEvent) => {
+ e.preventDefault();
+ }, []);
- return (
-
- menuProps={{ size: 'sm', isLazy: true }}
- menuButtonProps={{
- bg: 'transparent',
- _hover: { bg: 'transparent' },
- }}
- renderMenu={() => (
-
-
- }
- isDisabled={isAutoAdd || isProcessing || autoAssignBoardOnClick}
- onClick={handleSetAutoAdd}
- >
- Auto-add to this Board
-
- {!board && }
- {board && (
-
- )}
-
-
- )}
- >
- {children}
-
- );
- }
-);
+ return (
+
+ menuProps={{ size: 'sm', isLazy: true }}
+ menuButtonProps={{
+ bg: 'transparent',
+ _hover: { bg: 'transparent' },
+ }}
+ renderMenu={() => (
+
+
+ }
+ isDisabled={isAutoAdd || isProcessing || autoAssignBoardOnClick}
+ onClick={handleSetAutoAdd}
+ >
+ Auto-add to this Board
+
+ {!board && }
+ {board && (
+
+ )}
+
+
+ )}
+ >
+ {children}
+
+ );
+};
-BoardContextMenu.displayName = 'HoverableBoard';
-
-export default BoardContextMenu;
+export default memo(BoardContextMenu);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/AddBoardButton.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/AddBoardButton.tsx
index 7a07680878..ebd08e94d5 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/AddBoardButton.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/AddBoardButton.tsx
@@ -1,5 +1,5 @@
import IAIIconButton from 'common/components/IAIIconButton';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { FaPlus } from 'react-icons/fa';
import { useCreateBoardMutation } from 'services/api/endpoints/boards';
@@ -24,4 +24,4 @@ const AddBoardButton = () => {
);
};
-export default AddBoardButton;
+export default memo(AddBoardButton);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
index cb3474f6bd..4bbd9533fa 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
@@ -41,7 +41,7 @@ const BoardsList = (props: Props) => {
<>
void;
}
-const GalleryBoard = memo(
- ({ board, isSelected, setBoardToDelete }: GalleryBoardProps) => {
- const dispatch = useAppDispatch();
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ gallery, system }) => {
- const isSelectedForAutoAdd =
- board.board_id === gallery.autoAddBoardId;
- const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
- const isProcessing = system.isProcessing;
+const GalleryBoard = ({
+ board,
+ isSelected,
+ setBoardToDelete,
+}: GalleryBoardProps) => {
+ const dispatch = useAppDispatch();
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ gallery, system }) => {
+ const isSelectedForAutoAdd =
+ board.board_id === gallery.autoAddBoardId;
+ const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
+ const isProcessing = system.isProcessing;
- return {
- isSelectedForAutoAdd,
- autoAssignBoardOnClick,
- isProcessing,
- };
- },
- defaultSelectorOptions
- ),
- [board.board_id]
- );
+ return {
+ isSelectedForAutoAdd,
+ autoAssignBoardOnClick,
+ isProcessing,
+ };
+ },
+ defaultSelectorOptions
+ ),
+ [board.board_id]
+ );
- const { isSelectedForAutoAdd, autoAssignBoardOnClick, isProcessing } =
- useAppSelector(selector);
- const [isHovered, setIsHovered] = useState(false);
- const handleMouseOver = useCallback(() => {
- setIsHovered(true);
- }, []);
- const handleMouseOut = useCallback(() => {
- setIsHovered(false);
- }, []);
+ const { isSelectedForAutoAdd, autoAssignBoardOnClick, isProcessing } =
+ useAppSelector(selector);
+ const [isHovered, setIsHovered] = useState(false);
+ const handleMouseOver = useCallback(() => {
+ setIsHovered(true);
+ }, []);
+ const handleMouseOut = useCallback(() => {
+ setIsHovered(false);
+ }, []);
- const { data: imagesTotal } = useGetBoardImagesTotalQuery(board.board_id);
- const { data: assetsTotal } = useGetBoardAssetsTotalQuery(board.board_id);
- const tooltip = useMemo(() => {
- if (!imagesTotal || !assetsTotal) {
- return undefined;
+ const { data: imagesTotal } = useGetBoardImagesTotalQuery(board.board_id);
+ const { data: assetsTotal } = useGetBoardAssetsTotalQuery(board.board_id);
+ const tooltip = useMemo(() => {
+ if (!imagesTotal || !assetsTotal) {
+ return undefined;
+ }
+ return `${imagesTotal} image${
+ imagesTotal > 1 ? 's' : ''
+ }, ${assetsTotal} asset${assetsTotal > 1 ? 's' : ''}`;
+ }, [assetsTotal, imagesTotal]);
+
+ const { currentData: coverImage } = useGetImageDTOQuery(
+ board.cover_image_name ?? skipToken
+ );
+
+ const { board_name, board_id } = board;
+ const [localBoardName, setLocalBoardName] = useState(board_name);
+
+ const handleSelectBoard = useCallback(() => {
+ dispatch(boardIdSelected(board_id));
+ if (autoAssignBoardOnClick && !isProcessing) {
+ dispatch(autoAddBoardIdChanged(board_id));
+ }
+ }, [board_id, autoAssignBoardOnClick, isProcessing, dispatch]);
+
+ const [updateBoard, { isLoading: isUpdateBoardLoading }] =
+ useUpdateBoardMutation();
+
+ const droppableData: AddToBoardDropData = useMemo(
+ () => ({
+ id: board_id,
+ actionType: 'ADD_TO_BOARD',
+ context: { boardId: board_id },
+ }),
+ [board_id]
+ );
+
+ const handleSubmit = useCallback(
+ async (newBoardName: string) => {
+ // empty strings are not allowed
+ if (!newBoardName.trim()) {
+ setLocalBoardName(board_name);
+ return;
}
- return `${imagesTotal} image${
- imagesTotal > 1 ? 's' : ''
- }, ${assetsTotal} asset${assetsTotal > 1 ? 's' : ''}`;
- }, [assetsTotal, imagesTotal]);
- const { currentData: coverImage } = useGetImageDTOQuery(
- board.cover_image_name ?? skipToken
- );
-
- const { board_name, board_id } = board;
- const [localBoardName, setLocalBoardName] = useState(board_name);
-
- const handleSelectBoard = useCallback(() => {
- dispatch(boardIdSelected(board_id));
- if (autoAssignBoardOnClick && !isProcessing) {
- dispatch(autoAddBoardIdChanged(board_id));
+ // don't updated the board name if it hasn't changed
+ if (newBoardName === board_name) {
+ return;
}
- }, [board_id, autoAssignBoardOnClick, isProcessing, dispatch]);
- const [updateBoard, { isLoading: isUpdateBoardLoading }] =
- useUpdateBoardMutation();
+ try {
+ const { board_name } = await updateBoard({
+ board_id,
+ changes: { board_name: newBoardName },
+ }).unwrap();
- const droppableData: AddToBoardDropData = useMemo(
- () => ({
- id: board_id,
- actionType: 'ADD_TO_BOARD',
- context: { boardId: board_id },
- }),
- [board_id]
- );
+ // update local state
+ setLocalBoardName(board_name);
+ } catch {
+ // revert on error
+ setLocalBoardName(board_name);
+ }
+ },
+ [board_id, board_name, updateBoard]
+ );
- const handleSubmit = useCallback(
- async (newBoardName: string) => {
- // empty strings are not allowed
- if (!newBoardName.trim()) {
- setLocalBoardName(board_name);
- return;
- }
+ const handleChange = useCallback((newBoardName: string) => {
+ setLocalBoardName(newBoardName);
+ }, []);
- // don't updated the board name if it hasn't changed
- if (newBoardName === board_name) {
- return;
- }
-
- try {
- const { board_name } = await updateBoard({
- board_id,
- changes: { board_name: newBoardName },
- }).unwrap();
-
- // update local state
- setLocalBoardName(board_name);
- } catch {
- // revert on error
- setLocalBoardName(board_name);
- }
- },
- [board_id, board_name, updateBoard]
- );
-
- const handleChange = useCallback((newBoardName: string) => {
- setLocalBoardName(newBoardName);
- }, []);
-
- return (
-
+
-
-
- {(ref) => (
-
-
- {coverImage?.thumbnail_url ? (
- (
+
+
+ {coverImage?.thumbnail_url ? (
+
+ ) : (
+
+
- ) : (
-
-
-
- )}
- {/*
+ )}
+ {/*
*/}
- {isSelectedForAutoAdd && }
-
- }
+
+
+
-
-
+
-
-
-
-
- Move}
- />
+ // get rid of the edit border
+ boxShadow: 'none',
+ },
+ }}
+ />
+
-
- )}
-
-
-
- );
- }
-);
-GalleryBoard.displayName = 'HoverableBoard';
+ Move}
+ />
+
+
+ )}
+
+
+
+ );
+};
-export default GalleryBoard;
+export default memo(GalleryBoard);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GenericBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GenericBoard.tsx
index 1698a81ac0..7a95e7fcd9 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GenericBoard.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GenericBoard.tsx
@@ -3,7 +3,7 @@ import IAIDroppable from 'common/components/IAIDroppable';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { TypesafeDroppableData } from 'features/dnd/types';
import { BoardId } from 'features/gallery/store/types';
-import { ReactNode } from 'react';
+import { ReactNode, memo } from 'react';
import BoardContextMenu from '../BoardContextMenu';
type GenericBoardProps = {
@@ -105,4 +105,4 @@ const GenericBoard = (props: GenericBoardProps) => {
);
};
-export default GenericBoard;
+export default memo(GenericBoard);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx
index fec280db0f..da51a5fe39 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx
@@ -156,4 +156,4 @@ const NoBoardBoard = memo(({ isSelected }: Props) => {
NoBoardBoard.displayName = 'HoverableBoard';
-export default NoBoardBoard;
+export default memo(NoBoardBoard);
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx
index d62027769b..0212376507 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx
@@ -26,7 +26,7 @@ import {
setShouldShowImageDetails,
setShouldShowProgressInViewer,
} from 'features/ui/store/uiSlice';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import {
@@ -323,4 +323,4 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
);
};
-export default CurrentImageButtons;
+export default memo(CurrentImageButtons);
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx
index 1d8863f4d8..1c342d093e 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageDisplay.tsx
@@ -2,6 +2,7 @@ import { Flex } from '@chakra-ui/react';
import CurrentImageButtons from './CurrentImageButtons';
import CurrentImagePreview from './CurrentImagePreview';
+import { memo } from 'react';
const CurrentImageDisplay = () => {
return (
@@ -22,4 +23,4 @@ const CurrentImageDisplay = () => {
);
};
-export default CurrentImageDisplay;
+export default memo(CurrentImageDisplay);
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageHidden.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageHidden.tsx
index 062cdd7c00..af2a7c5f98 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageHidden.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageHidden.tsx
@@ -1,4 +1,5 @@
import { Flex } from '@chakra-ui/react';
+import { memo } from 'react';
import { FaEyeSlash } from 'react-icons/fa';
const CurrentImageHidden = () => {
@@ -18,4 +19,4 @@ const CurrentImageHidden = () => {
);
};
-export default CurrentImageHidden;
+export default memo(CurrentImageHidden);
diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryPanel.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryPanel.tsx
deleted file mode 100644
index 1bbec03f3e..0000000000
--- a/invokeai/frontend/web/src/features/gallery/components/GalleryPanel.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { gallerySelector } from 'features/gallery/store/gallerySelectors';
-import { setGalleryImageMinimumWidth } from 'features/gallery/store/gallerySlice';
-
-import { clamp, isEqual } from 'lodash-es';
-import { useHotkeys } from 'react-hotkeys-hook';
-
-import { createSelector } from '@reduxjs/toolkit';
-import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
-import ResizableDrawer from 'features/ui/components/common/ResizableDrawer/ResizableDrawer';
-import {
- activeTabNameSelector,
- uiSelector,
-} from 'features/ui/store/uiSelectors';
-import { setShouldShowGallery } from 'features/ui/store/uiSlice';
-import { memo } from 'react';
-import ImageGalleryContent from './ImageGalleryContent';
-
-const selector = createSelector(
- [activeTabNameSelector, uiSelector, gallerySelector, isStagingSelector],
- (activeTabName, ui, gallery, isStaging) => {
- const { shouldPinGallery, shouldShowGallery } = ui;
- const { galleryImageMinimumWidth } = gallery;
-
- return {
- activeTabName,
- isStaging,
- shouldPinGallery,
- shouldShowGallery,
- galleryImageMinimumWidth,
- isResizable: activeTabName !== 'unifiedCanvas',
- };
- },
- {
- memoizeOptions: {
- resultEqualityCheck: isEqual,
- },
- }
-);
-
-const GalleryDrawer = () => {
- const dispatch = useAppDispatch();
- const {
- shouldPinGallery,
- shouldShowGallery,
- galleryImageMinimumWidth,
- // activeTabName,
- // isStaging,
- // isResizable,
- } = useAppSelector(selector);
-
- const handleCloseGallery = () => {
- dispatch(setShouldShowGallery(false));
- shouldPinGallery && dispatch(requestCanvasRescale());
- };
-
- useHotkeys(
- 'esc',
- () => {
- dispatch(setShouldShowGallery(false));
- },
- {
- enabled: () => !shouldPinGallery,
- preventDefault: true,
- },
- [shouldPinGallery]
- );
-
- const IMAGE_SIZE_STEP = 32;
-
- useHotkeys(
- 'shift+up',
- () => {
- if (galleryImageMinimumWidth < 256) {
- const newMinWidth = clamp(
- galleryImageMinimumWidth + IMAGE_SIZE_STEP,
- 32,
- 256
- );
- dispatch(setGalleryImageMinimumWidth(newMinWidth));
- }
- },
- [galleryImageMinimumWidth]
- );
-
- useHotkeys(
- 'shift+down',
- () => {
- if (galleryImageMinimumWidth > 32) {
- const newMinWidth = clamp(
- galleryImageMinimumWidth - IMAGE_SIZE_STEP,
- 32,
- 256
- );
- dispatch(setGalleryImageMinimumWidth(newMinWidth));
- }
- },
- [galleryImageMinimumWidth]
- );
-
- if (shouldPinGallery) {
- return null;
- }
-
- return (
-
-
-
- );
-};
-
-export default memo(GalleryDrawer);
diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryPinButton.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryPinButton.tsx
deleted file mode 100644
index 916dec69a2..0000000000
--- a/invokeai/frontend/web/src/features/gallery/components/GalleryPinButton.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { createSelector } from '@reduxjs/toolkit';
-import { stateSelector } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-import IAIIconButton from 'common/components/IAIIconButton';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
-import { togglePinGalleryPanel } from 'features/ui/store/uiSlice';
-import { useTranslation } from 'react-i18next';
-import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
-
-const selector = createSelector(
- [stateSelector],
- (state) => {
- const { shouldPinGallery } = state.ui;
-
- return {
- shouldPinGallery,
- };
- },
- defaultSelectorOptions
-);
-
-const GalleryPinButton = () => {
- const dispatch = useAppDispatch();
- const { t } = useTranslation();
-
- const { shouldPinGallery } = useAppSelector(selector);
-
- const handleSetShouldPinGallery = () => {
- dispatch(togglePinGalleryPanel());
- dispatch(requestCanvasRescale());
- };
- return (
- : }
- />
- );
-};
-
-export default GalleryPinButton;
diff --git a/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx b/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx
index 23cfdcc5fd..2eab78d118 100644
--- a/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx
@@ -12,7 +12,7 @@ import {
setGalleryImageMinimumWidth,
shouldAutoSwitchChanged,
} from 'features/gallery/store/gallerySlice';
-import { ChangeEvent, useCallback } from 'react';
+import { ChangeEvent, memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaWrench } from 'react-icons/fa';
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
@@ -101,4 +101,4 @@ const GallerySettingsPopover = () => {
);
};
-export default GallerySettingsPopover;
+export default memo(GallerySettingsPopover);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx
index 0f36273122..bf2b344b4c 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx
@@ -5,7 +5,7 @@ import {
isModalOpenChanged,
} from 'features/changeBoardModal/store/slice';
import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { FaFolder, FaTrash } from 'react-icons/fa';
import { MdStar, MdStarBorder } from 'react-icons/md';
import {
@@ -74,4 +74,4 @@ const MultipleSelectionMenuItems = () => {
);
};
-export default MultipleSelectionMenuItems;
+export default memo(MultipleSelectionMenuItems);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx
index ef6e2ccd5c..76eee18d72 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx
@@ -1,11 +1,8 @@
-import { MenuItem } from '@chakra-ui/react';
+import { Flex, MenuItem, Text } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/dist/query';
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch } from 'app/store/storeHooks';
-import {
- resizeAndScaleCanvas,
- setInitialCanvasImage,
-} from 'features/canvas/store/canvasSlice';
+import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
import {
imagesToChangeSelected,
isModalOpenChanged,
@@ -29,6 +26,7 @@ import {
FaShare,
FaTrash,
} from 'react-icons/fa';
+import { MdStar, MdStarBorder } from 'react-icons/md';
import {
useGetImageMetadataQuery,
useStarImagesMutation,
@@ -37,7 +35,6 @@ import {
import { ImageDTO } from 'services/api/types';
import { useDebounce } from 'use-debounce';
import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions';
-import { MdStar, MdStarBorder } from 'react-icons/md';
type SingleSelectionMenuItemsProps = {
imageDTO: ImageDTO;
@@ -110,7 +107,6 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
const handleSendToCanvas = useCallback(() => {
dispatch(sentImageToCanvas());
dispatch(setInitialCanvasImage(imageDTO));
- dispatch(resizeAndScaleCanvas());
dispatch(setActiveTab('unifiedCanvas'));
toaster({
@@ -136,11 +132,15 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
}, [copyImageToClipboard, imageDTO.image_url]);
const handleStarImage = useCallback(() => {
- if (imageDTO) starImages({ imageDTOs: [imageDTO] });
+ if (imageDTO) {
+ starImages({ imageDTOs: [imageDTO] });
+ }
}, [starImages, imageDTO]);
const handleUnstarImage = useCallback(() => {
- if (imageDTO) unstarImages({ imageDTOs: [imageDTO] });
+ if (imageDTO) {
+ unstarImages({ imageDTOs: [imageDTO] });
+ }
}, [unstarImages, imageDTO]);
return (
@@ -228,6 +228,18 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
>
{t('gallery.deleteImage')}
+ {metadata?.created_by && (
+
+
+ Created by {metadata?.created_by}
+
+
+ )}
>
);
};
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageFallbackSpinner.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageFallbackSpinner.tsx
index fd603d3756..95577efc13 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageFallbackSpinner.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageFallbackSpinner.tsx
@@ -1,4 +1,5 @@
import { Flex, Spinner, SpinnerProps } from '@chakra-ui/react';
+import { memo } from 'react';
type ImageFallbackSpinnerProps = SpinnerProps;
@@ -23,4 +24,4 @@ const ImageFallbackSpinner = (props: ImageFallbackSpinnerProps) => {
);
};
-export default ImageFallbackSpinner;
+export default memo(ImageFallbackSpinner);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx
index 804df49b8e..6c34029490 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx
@@ -18,7 +18,6 @@ import { FaImages, FaServer } from 'react-icons/fa';
import { galleryViewChanged } from '../store/gallerySlice';
import BoardsList from './Boards/BoardsList/BoardsList';
import GalleryBoardName from './GalleryBoardName';
-import GalleryPinButton from './GalleryPinButton';
import GallerySettingsPopover from './GallerySettingsPopover';
import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
@@ -75,7 +74,6 @@ const ImageGalleryContent = () => {
onToggle={onToggleBoardList}
/>
-
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx
index 5dbbf011e8..40af91d53a 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx
@@ -88,8 +88,12 @@ const GalleryImage = (props: HoverableImageProps) => {
}, []);
const starIcon = useMemo(() => {
- if (imageDTO?.starred) return ;
- if (!imageDTO?.starred && isHovered) return ;
+ if (imageDTO?.starred) {
+ return ;
+ }
+ if (!imageDTO?.starred && isHovered) {
+ return ;
+ }
}, [imageDTO?.starred, isHovered]);
if (!imageDTO) {
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridItemContainer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridItemContainer.tsx
index a09455ef2c..f55ca1dedf 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridItemContainer.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridItemContainer.tsx
@@ -1,5 +1,5 @@
import { Box, FlexProps, forwardRef } from '@chakra-ui/react';
-import { PropsWithChildren } from 'react';
+import { PropsWithChildren, memo } from 'react';
type ItemContainerProps = PropsWithChildren & FlexProps;
const ItemContainer = forwardRef((props: ItemContainerProps, ref) => (
@@ -8,4 +8,4 @@ const ItemContainer = forwardRef((props: ItemContainerProps, ref) => (
));
-export default ItemContainer;
+export default memo(ItemContainer);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridListContainer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridListContainer.tsx
index fbbca2b2cf..a93222b58e 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridListContainer.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/ImageGridListContainer.tsx
@@ -1,7 +1,7 @@
import { FlexProps, Grid, forwardRef } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
-import { PropsWithChildren } from 'react';
+import { PropsWithChildren, memo } from 'react';
type ListContainerProps = PropsWithChildren & FlexProps;
const ListContainer = forwardRef((props: ListContainerProps, ref) => {
@@ -23,4 +23,4 @@ const ListContainer = forwardRef((props: ListContainerProps, ref) => {
);
});
-export default ListContainer;
+export default memo(ListContainer);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataJSON.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx
similarity index 53%
rename from invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataJSON.tsx
rename to invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx
index 69385607de..87c0957354 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataJSON.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx
@@ -1,34 +1,37 @@
import { Box, Flex, IconButton, Tooltip } from '@chakra-ui/react';
+import { isString } from 'lodash-es';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { FaCopy, FaSave } from 'react-icons/fa';
type Props = {
label: string;
- jsonObject: object;
+ data: object | string;
fileName?: string;
+ withDownload?: boolean;
+ withCopy?: boolean;
};
-const ImageMetadataJSON = (props: Props) => {
- const { label, jsonObject, fileName } = props;
- const jsonString = useMemo(
- () => JSON.stringify(jsonObject, null, 2),
- [jsonObject]
+const DataViewer = (props: Props) => {
+ const { label, data, fileName, withDownload = true, withCopy = true } = props;
+ const dataString = useMemo(
+ () => (isString(data) ? data : JSON.stringify(data, null, 2)),
+ [data]
);
const handleCopy = useCallback(() => {
- navigator.clipboard.writeText(jsonString);
- }, [jsonString]);
+ navigator.clipboard.writeText(dataString);
+ }, [dataString]);
const handleSave = useCallback(() => {
- const blob = new Blob([jsonString]);
+ const blob = new Blob([dataString]);
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `${fileName || label}.json`;
document.body.appendChild(a);
a.click();
a.remove();
- }, [jsonString, label, fileName]);
+ }, [dataString, label, fileName]);
return (
{
},
}}
>
- {jsonString}
+ {dataString}
-
- }
- variant="ghost"
- opacity={0.7}
- onClick={handleSave}
- />
-
-
- }
- variant="ghost"
- opacity={0.7}
- onClick={handleCopy}
- />
-
+ {withDownload && (
+
+ }
+ variant="ghost"
+ opacity={0.7}
+ onClick={handleSave}
+ />
+
+ )}
+ {withCopy && (
+
+ }
+ variant="ghost"
+ opacity={0.7}
+ onClick={handleCopy}
+ />
+
+ )}
);
};
-export default ImageMetadataJSON;
+export default memo(DataViewer);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx
index c0821c2226..c3e5d763a4 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx
@@ -1,5 +1,5 @@
import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { UnsafeImageMetadata } from 'services/api/types';
import ImageMetadataItem from './ImageMetadataItem';
@@ -69,6 +69,9 @@ const ImageMetadataActions = (props: Props) => {
return (
<>
+ {metadata.created_by && (
+
+ )}
{metadata.generation_mode && (
{
);
};
-export default ImageMetadataActions;
+export default memo(ImageMetadataActions);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataItem.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataItem.tsx
index d72561351f..c03fd26ba1 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataItem.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataItem.tsx
@@ -1,5 +1,6 @@
import { ExternalLinkIcon } from '@chakra-ui/icons';
import { Flex, IconButton, Link, Text, Tooltip } from '@chakra-ui/react';
+import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { FaCopy } from 'react-icons/fa';
import { IoArrowUndoCircleOutline } from 'react-icons/io5';
@@ -74,4 +75,4 @@ const ImageMetadataItem = ({
);
};
-export default ImageMetadataItem;
+export default memo(ImageMetadataItem);
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx
index d70aea8a8d..9262d081b5 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx
@@ -16,7 +16,7 @@ import { useGetImageMetadataQuery } from 'services/api/endpoints/images';
import { ImageDTO } from 'services/api/types';
import { useDebounce } from 'use-debounce';
import ImageMetadataActions from './ImageMetadataActions';
-import ImageMetadataJSON from './ImageMetadataJSON';
+import DataViewer from './DataViewer';
type ImageMetadataViewerProps = {
image: ImageDTO;
@@ -79,21 +79,21 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => {
{metadata ? (
-
+
) : (
)}
{image ? (
-
+
) : (
)}
{graph ? (
-
+
) : (
)}
diff --git a/invokeai/frontend/web/src/features/lora/components/ParamLoraList.tsx b/invokeai/frontend/web/src/features/lora/components/ParamLoraList.tsx
index 5ba4e711ef..83fddef578 100644
--- a/invokeai/frontend/web/src/features/lora/components/ParamLoraList.tsx
+++ b/invokeai/frontend/web/src/features/lora/components/ParamLoraList.tsx
@@ -5,6 +5,7 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { map } from 'lodash-es';
import ParamLora from './ParamLora';
+import { memo } from 'react';
const selector = createSelector(
stateSelector,
@@ -29,4 +30,4 @@ const ParamLoraList = () => {
);
};
-export default ParamLoraList;
+export default memo(ParamLoraList);
diff --git a/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx b/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx
index 2046d36ab2..bb485d44b6 100644
--- a/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx
+++ b/invokeai/frontend/web/src/features/lora/components/ParamLoraSelect.tsx
@@ -9,7 +9,7 @@ import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectI
import { loraAdded } from 'features/lora/store/loraSlice';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { forEach } from 'lodash-es';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useGetLoRAModelsQuery } from 'services/api/endpoints/models';
const selector = createSelector(
@@ -102,4 +102,4 @@ const ParamLoRASelect = () => {
);
};
-export default ParamLoRASelect;
+export default memo(ParamLoRASelect);
diff --git a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx
deleted file mode 100644
index a816762d0f..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-import { Flex, Text } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppToaster } from 'app/components/Toaster';
-import { stateSelector } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
-import { map } from 'lodash-es';
-import { forwardRef, useCallback } from 'react';
-import 'reactflow/dist/style.css';
-import { AnyInvocationType } from 'services/events/types';
-import { useBuildNodeData } from '../hooks/useBuildNodeData';
-import { nodeAdded } from '../store/nodesSlice';
-
-type NodeTemplate = {
- label: string;
- value: string;
- description: string;
- tags: string[];
-};
-
-const selector = createSelector(
- [stateSelector],
- ({ nodes }) => {
- const data: NodeTemplate[] = map(nodes.nodeTemplates, (template) => {
- return {
- label: template.title,
- value: template.type,
- description: template.description,
- tags: template.tags,
- };
- });
-
- data.push({
- label: 'Progress Image',
- value: 'current_image',
- description: 'Displays the current image in the Node Editor',
- tags: ['progress'],
- });
-
- data.push({
- label: 'Notes',
- value: 'notes',
- description: 'Add notes about your workflow',
- tags: ['notes'],
- });
-
- return { data };
- },
- defaultSelectorOptions
-);
-
-const AddNodeMenu = () => {
- const dispatch = useAppDispatch();
- const { data } = useAppSelector(selector);
-
- const buildInvocation = useBuildNodeData();
-
- const toaster = useAppToaster();
-
- const addNode = useCallback(
- (nodeType: AnyInvocationType) => {
- const invocation = buildInvocation(nodeType);
-
- if (!invocation) {
- toaster({
- status: 'error',
- title: `Unknown Invocation type ${nodeType}`,
- });
- return;
- }
-
- dispatch(nodeAdded(invocation));
- },
- [dispatch, buildInvocation, toaster]
- );
-
- const handleChange = useCallback(
- (v: string | null) => {
- if (!v) {
- return;
- }
-
- addNode(v as AnyInvocationType);
- },
- [addNode]
- );
-
- return (
-
-
- item.label.toLowerCase().includes(value.toLowerCase().trim()) ||
- item.value.toLowerCase().includes(value.toLowerCase().trim()) ||
- item.description.toLowerCase().includes(value.toLowerCase().trim()) ||
- item.tags.includes(value.toLowerCase().trim())
- }
- onChange={handleChange}
- sx={{
- width: '24rem',
- }}
- />
-
- );
-};
-
-interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
- value: string;
- label: string;
- description: string;
-}
-
-const SelectItem = forwardRef(
- ({ label, description, ...others }: ItemProps, ref) => {
- return (
-
-
- {label}
-
- {description}
-
-
-
- );
- }
-);
-
-SelectItem.displayName = 'SelectItem';
-
-export default AddNodeMenu;
diff --git a/invokeai/frontend/web/src/features/nodes/components/CustomEdges.tsx b/invokeai/frontend/web/src/features/nodes/components/CustomEdges.tsx
deleted file mode 100644
index f80f0451e4..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/CustomEdges.tsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import { Badge, Flex } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { stateSelector } from 'app/store/store';
-import { useAppSelector } from 'app/store/storeHooks';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
-import { memo, useMemo } from 'react';
-import {
- BaseEdge,
- EdgeLabelRenderer,
- EdgeProps,
- getBezierPath,
-} from 'reactflow';
-import { FIELDS, colorTokenToCssVar } from '../types/constants';
-import { isInvocationNode } from '../types/types';
-
-const makeEdgeSelector = (
- source: string,
- sourceHandleId: string | null | undefined,
- target: string,
- targetHandleId: string | null | undefined,
- selected?: boolean
-) =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const sourceNode = nodes.nodes.find((node) => node.id === source);
- const targetNode = nodes.nodes.find((node) => node.id === target);
-
- const isInvocationToInvocationEdge =
- isInvocationNode(sourceNode) && isInvocationNode(targetNode);
-
- const isSelected =
- sourceNode?.selected || targetNode?.selected || selected;
- const sourceType = isInvocationToInvocationEdge
- ? sourceNode?.data?.outputs[sourceHandleId || '']?.type
- : undefined;
-
- const stroke =
- sourceType && nodes.shouldColorEdges
- ? colorTokenToCssVar(FIELDS[sourceType].color)
- : colorTokenToCssVar('base.500');
-
- return {
- isSelected,
- shouldAnimate: nodes.shouldAnimateEdges && isSelected,
- stroke,
- };
- },
- defaultSelectorOptions
- );
-
-const CollapsedEdge = memo(
- ({
- sourceX,
- sourceY,
- targetX,
- targetY,
- sourcePosition,
- targetPosition,
- markerEnd,
- data,
- selected,
- source,
- target,
- sourceHandleId,
- targetHandleId,
- }: EdgeProps<{ count: number }>) => {
- const selector = useMemo(
- () =>
- makeEdgeSelector(
- source,
- sourceHandleId,
- target,
- targetHandleId,
- selected
- ),
- [selected, source, sourceHandleId, target, targetHandleId]
- );
-
- const { isSelected, shouldAnimate } = useAppSelector(selector);
-
- const [edgePath, labelX, labelY] = getBezierPath({
- sourceX,
- sourceY,
- sourcePosition,
- targetX,
- targetY,
- targetPosition,
- });
-
- const { base500 } = useChakraThemeTokens();
-
- return (
- <>
-
- {data?.count && data.count > 1 && (
-
-
-
- {data.count}
-
-
-
- )}
- >
- );
- }
-);
-
-CollapsedEdge.displayName = 'CollapsedEdge';
-
-const DefaultEdge = memo(
- ({
- sourceX,
- sourceY,
- targetX,
- targetY,
- sourcePosition,
- targetPosition,
- markerEnd,
- selected,
- source,
- target,
- sourceHandleId,
- targetHandleId,
- }: EdgeProps) => {
- const selector = useMemo(
- () =>
- makeEdgeSelector(
- source,
- sourceHandleId,
- target,
- targetHandleId,
- selected
- ),
- [source, sourceHandleId, target, targetHandleId, selected]
- );
-
- const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
-
- const [edgePath] = getBezierPath({
- sourceX,
- sourceY,
- sourcePosition,
- targetX,
- targetY,
- targetPosition,
- });
-
- return (
-
- );
- }
-);
-
-DefaultEdge.displayName = 'DefaultEdge';
-
-export const edgeTypes = {
- collapsed: CollapsedEdge,
- default: DefaultEdge,
-};
diff --git a/invokeai/frontend/web/src/features/nodes/components/CustomNodes.tsx b/invokeai/frontend/web/src/features/nodes/components/CustomNodes.tsx
deleted file mode 100644
index be845df435..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/CustomNodes.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import CurrentImageNode from './nodes/CurrentImageNode';
-import InvocationNodeWrapper from './nodes/InvocationNodeWrapper';
-import NotesNode from './nodes/NotesNode';
-
-export const nodeTypes = {
- invocation: InvocationNodeWrapper,
- current_image: CurrentImageNode,
- notes: NotesNode,
-};
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/InvocationNode.tsx b/invokeai/frontend/web/src/features/nodes/components/Invocation/InvocationNode.tsx
deleted file mode 100644
index 6c610d7f34..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/InvocationNode.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import { useFieldNames, useWithFooter } from 'features/nodes/hooks/useNodeData';
-import { memo } from 'react';
-import InputField from '../fields/InputField';
-import OutputField from '../fields/OutputField';
-import NodeFooter from './NodeFooter';
-import NodeHeader from './NodeHeader';
-import NodeWrapper from './NodeWrapper';
-
-type Props = {
- nodeId: string;
- isOpen: boolean;
- label: string;
- type: string;
- selected: boolean;
-};
-
-const InvocationNode = ({ nodeId, isOpen, label, type, selected }: Props) => {
- const inputFieldNames = useFieldNames(nodeId, 'input');
- const outputFieldNames = useFieldNames(nodeId, 'output');
- const withFooter = useWithFooter(nodeId);
-
- return (
-
-
- {isOpen && (
- <>
-
-
- {outputFieldNames.map((fieldName) => (
-
- ))}
- {inputFieldNames.map((fieldName) => (
-
- ))}
-
-
- {withFooter && }
- >
- )}
-
- );
-};
-
-export default memo(InvocationNode);
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeSettings.tsx b/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeSettings.tsx
deleted file mode 100644
index bf12358871..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeSettings.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import { useAppDispatch } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
-import IAIPopover from 'common/components/IAIPopover';
-import IAISwitch from 'common/components/IAISwitch';
-import { fieldBooleanValueChanged } from 'features/nodes/store/nodesSlice';
-import { InvocationNodeData } from 'features/nodes/types/types';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { FaBars } from 'react-icons/fa';
-
-interface Props {
- data: InvocationNodeData;
-}
-
-const NodeSettings = (props: Props) => {
- const { data } = props;
- const dispatch = useAppDispatch();
-
- const handleChangeIsIntermediate = useCallback(
- (e: ChangeEvent) => {
- dispatch(
- fieldBooleanValueChanged({
- nodeId: data.id,
- fieldName: 'is_intermediate',
- value: e.target.checked,
- })
- );
- },
- [data.id, dispatch]
- );
-
- return (
- }
- />
- }
- >
-
-
-
-
- );
-};
-
-export default memo(NodeSettings);
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeWrapper.tsx b/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeWrapper.tsx
deleted file mode 100644
index 68ed0684ed..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeWrapper.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import {
- Box,
- ChakraProps,
- useColorModeValue,
- useToken,
-} from '@chakra-ui/react';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { nodeClicked } from 'features/nodes/store/nodesSlice';
-import {
- MouseEvent,
- PropsWithChildren,
- memo,
- useCallback,
- useMemo,
-} from 'react';
-import { DRAG_HANDLE_CLASSNAME, NODE_WIDTH } from '../../types/constants';
-
-const useNodeSelect = (nodeId: string) => {
- const dispatch = useAppDispatch();
-
- const selectNode = useCallback(
- (e: MouseEvent) => {
- dispatch(nodeClicked({ nodeId, ctrlOrMeta: e.ctrlKey || e.metaKey }));
- },
- [dispatch, nodeId]
- );
-
- return selectNode;
-};
-
-type NodeWrapperProps = PropsWithChildren & {
- nodeId: string;
- selected: boolean;
- width?: NonNullable['w'];
-};
-
-const NodeWrapper = (props: NodeWrapperProps) => {
- const { width, children, nodeId, selected } = props;
-
- const [
- nodeSelectedOutlineLight,
- nodeSelectedOutlineDark,
- shadowsXl,
- shadowsBase,
- ] = useToken('shadows', [
- 'nodeSelectedOutline.light',
- 'nodeSelectedOutline.dark',
- 'shadows.xl',
- 'shadows.base',
- ]);
-
- const selectNode = useNodeSelect(nodeId);
-
- const shadow = useColorModeValue(
- nodeSelectedOutlineLight,
- nodeSelectedOutlineDark
- );
-
- const shift = useAppSelector((state) => state.hotkeys.shift);
- const opacity = useAppSelector((state) => state.nodes.nodeOpacity);
- const className = useMemo(
- () => (shift ? DRAG_HANDLE_CLASSNAME : 'nopan'),
- [shift]
- );
-
- return (
-
-
- {children}
-
- );
-};
-
-export default memo(NodeWrapper);
diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx b/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx
index 5e610cfc39..4cefdbb20b 100644
--- a/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx
@@ -1,107 +1,95 @@
import { Flex } from '@chakra-ui/react';
import { useAppSelector } from 'app/store/storeHooks';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
-import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
-import { memo, useState } from 'react';
-import { MdDeviceHub } from 'react-icons/md';
-import { Panel, PanelGroup } from 'react-resizable-panels';
-import 'reactflow/dist/style.css';
-import NodeEditorPanelGroup from './panel/NodeEditorPanelGroup';
-import { Flow } from './Flow';
import { AnimatePresence, motion } from 'framer-motion';
+import { memo } from 'react';
+import { MdDeviceHub } from 'react-icons/md';
+import 'reactflow/dist/style.css';
+import AddNodePopover from './flow/AddNodePopover/AddNodePopover';
+import { Flow } from './flow/Flow';
+import TopLeftPanel from './flow/panels/TopLeftPanel/TopLeftPanel';
+import TopCenterPanel from './flow/panels/TopCenterPanel/TopCenterPanel';
+import TopRightPanel from './flow/panels/TopRightPanel/TopRightPanel';
+import BottomLeftPanel from './flow/panels/BottomLeftPanel/BottomLeftPanel';
+import MinimapPanel from './flow/panels/MinimapPanel/MinimapPanel';
const NodeEditor = () => {
- const [isPanelCollapsed, setIsPanelCollapsed] = useState(false);
const isReady = useAppSelector((state) => state.nodes.isReady);
return (
-
-
-
-
-
-
-
-
- {isReady && (
-
-
-
- )}
-
-
- {!isReady && (
-
-
-
-
-
- )}
-
-
-
-
+
+ {isReady && (
+
+
+
+
+
+
+
+
+
+ )}
+
+
+ {!isReady && (
+
+
+
+
+
+ )}
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx b/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx
deleted file mode 100644
index 4525dc5f6b..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { RootState } from 'app/store/store';
-import { useAppSelector } from 'app/store/storeHooks';
-import ImageMetadataJSON from 'features/gallery/components/ImageMetadataViewer/ImageMetadataJSON';
-import { omit } from 'lodash-es';
-import { useMemo } from 'react';
-import { useDebounce } from 'use-debounce';
-import { buildNodesGraph } from '../util/graphBuilders/buildNodesGraph';
-
-const useNodesGraph = () => {
- const nodes = useAppSelector((state: RootState) => state.nodes);
- const [debouncedNodes] = useDebounce(nodes, 300);
- const graph = useMemo(
- () => omit(buildNodesGraph(debouncedNodes), 'id'),
- [debouncedNodes]
- );
-
- return graph;
-};
-
-const NodeGraph = () => {
- const graph = useNodesGraph();
-
- return ;
-};
-
-export default NodeGraph;
diff --git a/invokeai/frontend/web/src/features/nodes/components/editorPanels/BottomLeftPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/editorPanels/BottomLeftPanel.tsx
deleted file mode 100644
index 39aa2444c4..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/editorPanels/BottomLeftPanel.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { memo } from 'react';
-import { Panel } from 'reactflow';
-import ViewportControls from '../ViewportControls';
-import NodeOpacitySlider from '../NodeOpacitySlider';
-import { Flex } from '@chakra-ui/react';
-
-const BottomLeftPanel = () => (
-
-
-
-
-
-
-);
-
-export default memo(BottomLeftPanel);
diff --git a/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopCenterPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopCenterPanel.tsx
deleted file mode 100644
index 240c2057be..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopCenterPanel.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { HStack } from '@chakra-ui/react';
-import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton';
-import { memo } from 'react';
-import { Panel } from 'reactflow';
-import NodeEditorSettings from '../NodeEditorSettings';
-import ClearGraphButton from '../ui/ClearGraphButton';
-import NodeInvokeButton from '../ui/NodeInvokeButton';
-import ReloadSchemaButton from '../ui/ReloadSchemaButton';
-
-const TopCenterPanel = () => {
- return (
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default memo(TopCenterPanel);
diff --git a/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopLeftPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopLeftPanel.tsx
deleted file mode 100644
index 2b89db000a..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopLeftPanel.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { memo } from 'react';
-import { Panel } from 'reactflow';
-import AddNodeMenu from '../AddNodeMenu';
-
-const TopLeftPanel = () => (
-
-
-
-);
-
-export default memo(TopLeftPanel);
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/FieldContextMenu.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/FieldContextMenu.tsx
deleted file mode 100644
index d9f8f951bc..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/fields/FieldContextMenu.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { MenuItem, MenuList } from '@chakra-ui/react';
-import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu';
-import {
- InputFieldTemplate,
- InputFieldValue,
-} from 'features/nodes/types/types';
-import { MouseEvent, useCallback } from 'react';
-import { menuListMotionProps } from 'theme/components/menu';
-
-type Props = {
- nodeId: string;
- field: InputFieldValue;
- fieldTemplate: InputFieldTemplate;
- children: ContextMenuProps['children'];
-};
-
-const FieldContextMenu = (props: Props) => {
- const skipEvent = useCallback((e: MouseEvent) => {
- e.preventDefault();
- }, []);
-
- return (
-
- menuProps={{
- size: 'sm',
- isLazy: true,
- }}
- menuButtonProps={{
- bg: 'transparent',
- _hover: { bg: 'transparent' },
- }}
- renderMenu={() => (
-
-
-
- )}
- >
- {props.children}
-
- );
-};
-
-export default FieldContextMenu;
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/InputField.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/InputField.tsx
deleted file mode 100644
index 47033baa7b..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/fields/InputField.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import { Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react';
-import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
-import {
- useDoesInputHaveValue,
- useFieldTemplate,
-} from 'features/nodes/hooks/useNodeData';
-import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
-import { PropsWithChildren, memo, useMemo } from 'react';
-import FieldHandle from './FieldHandle';
-import FieldTitle from './FieldTitle';
-import FieldTooltipContent from './FieldTooltipContent';
-import InputFieldRenderer from './InputFieldRenderer';
-
-interface Props {
- nodeId: string;
- fieldName: string;
-}
-
-const InputField = ({ nodeId, fieldName }: Props) => {
- const fieldTemplate = useFieldTemplate(nodeId, fieldName, 'input');
- const doesFieldHaveValue = useDoesInputHaveValue(nodeId, fieldName);
-
- const {
- isConnected,
- isConnectionInProgress,
- isConnectionStartField,
- connectionError,
- shouldDim,
- } = useConnectionState({ nodeId, fieldName, kind: 'input' });
-
- const isMissingInput = useMemo(() => {
- if (fieldTemplate?.fieldKind !== 'input') {
- return false;
- }
-
- if (!fieldTemplate.required) {
- return false;
- }
-
- if (!isConnected && fieldTemplate.input === 'connection') {
- return true;
- }
-
- if (!doesFieldHaveValue && !isConnected && fieldTemplate.input === 'any') {
- return true;
- }
- }, [fieldTemplate, isConnected, doesFieldHaveValue]);
-
- if (fieldTemplate?.fieldKind !== 'input') {
- return (
-
-
- Unknown input: {fieldName}
-
-
- );
- }
-
- return (
-
-
-
- }
- openDelay={HANDLE_TOOLTIP_OPEN_DELAY}
- placement="top"
- shouldWrapChildren
- hasArrow
- >
-
-
-
-
-
-
-
- {fieldTemplate.input !== 'direct' && (
-
- )}
-
- );
-};
-
-export default InputField;
-
-type InputFieldWrapperProps = PropsWithChildren<{
- shouldDim: boolean;
-}>;
-
-const InputFieldWrapper = memo(
- ({ shouldDim, children }: InputFieldWrapperProps) => (
-
- {children}
-
- )
-);
-
-InputFieldWrapper.displayName = 'InputFieldWrapper';
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/LinearViewField.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/LinearViewField.tsx
deleted file mode 100644
index ea4bb76d62..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/fields/LinearViewField.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react';
-import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
-import { memo } from 'react';
-import FieldTitle from './FieldTitle';
-import FieldTooltipContent from './FieldTooltipContent';
-import InputFieldRenderer from './InputFieldRenderer';
-
-type Props = {
- nodeId: string;
- fieldName: string;
-};
-
-const LinearViewField = ({ nodeId, fieldName }: Props) => {
- return (
-
-
-
- }
- openDelay={HANDLE_TOOLTIP_OPEN_DELAY}
- placement="top"
- shouldWrapChildren
- hasArrow
- >
-
-
-
-
-
-
-
- );
-};
-
-export default memo(LinearViewField);
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/types.ts b/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/types.ts
deleted file mode 100644
index 5a5e3a9dcf..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import {
- InputFieldTemplate,
- InputFieldValue,
-} from 'features/nodes/types/types';
-
-export type FieldComponentProps<
- V extends InputFieldValue,
- T extends InputFieldTemplate
-> = {
- nodeId: string;
- field: V;
- fieldTemplate: T;
-};
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx
new file mode 100644
index 0000000000..83f7482177
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopover.tsx
@@ -0,0 +1,205 @@
+import {
+ Flex,
+ Popover,
+ PopoverAnchor,
+ PopoverBody,
+ PopoverContent,
+} from '@chakra-ui/react';
+import { createSelector } from '@reduxjs/toolkit';
+import { useAppToaster } from 'app/components/Toaster';
+import { stateSelector } from 'app/store/store';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
+import { useBuildNodeData } from 'features/nodes/hooks/useBuildNodeData';
+import {
+ addNodePopoverClosed,
+ addNodePopoverOpened,
+ nodeAdded,
+} from 'features/nodes/store/nodesSlice';
+import { map } from 'lodash-es';
+import { memo, useCallback, useRef } from 'react';
+import { useHotkeys } from 'react-hotkeys-hook';
+import { HotkeyCallback } from 'react-hotkeys-hook/dist/types';
+import 'reactflow/dist/style.css';
+import { AnyInvocationType } from 'services/events/types';
+import { AddNodePopoverSelectItem } from './AddNodePopoverSelectItem';
+
+type NodeTemplate = {
+ label: string;
+ value: string;
+ description: string;
+ tags: string[];
+};
+
+const filter = (value: string, item: NodeTemplate) => {
+ const regex = new RegExp(
+ value
+ .trim()
+ .replace(/[-[\]{}()*+!<=:?./\\^$|#,]/g, '')
+ .split(' ')
+ .join('.*'),
+ 'gi'
+ );
+ return (
+ regex.test(item.label) ||
+ regex.test(item.description) ||
+ item.tags.some((tag) => regex.test(tag))
+ );
+};
+
+const selector = createSelector(
+ [stateSelector],
+ ({ nodes }) => {
+ const data: NodeTemplate[] = map(nodes.nodeTemplates, (template) => {
+ return {
+ label: template.title,
+ value: template.type,
+ description: template.description,
+ tags: template.tags,
+ };
+ });
+
+ data.push({
+ label: 'Progress Image',
+ value: 'current_image',
+ description: 'Displays the current image in the Node Editor',
+ tags: ['progress'],
+ });
+
+ data.push({
+ label: 'Notes',
+ value: 'notes',
+ description: 'Add notes about your workflow',
+ tags: ['notes'],
+ });
+
+ data.sort((a, b) => a.label.localeCompare(b.label));
+
+ return { data };
+ },
+ defaultSelectorOptions
+);
+
+const AddNodePopover = () => {
+ const dispatch = useAppDispatch();
+ const buildInvocation = useBuildNodeData();
+ const toaster = useAppToaster();
+ const { data } = useAppSelector(selector);
+ const isOpen = useAppSelector((state) => state.nodes.isAddNodePopoverOpen);
+ const inputRef = useRef(null);
+
+ const addNode = useCallback(
+ (nodeType: AnyInvocationType) => {
+ const invocation = buildInvocation(nodeType);
+
+ if (!invocation) {
+ toaster({
+ status: 'error',
+ title: `Unknown Invocation type ${nodeType}`,
+ });
+ return;
+ }
+
+ dispatch(nodeAdded(invocation));
+ },
+ [dispatch, buildInvocation, toaster]
+ );
+
+ const handleChange = useCallback(
+ (v: string | null) => {
+ if (!v) {
+ return;
+ }
+
+ addNode(v as AnyInvocationType);
+ },
+ [addNode]
+ );
+
+ const onClose = useCallback(() => {
+ dispatch(addNodePopoverClosed());
+ }, [dispatch]);
+
+ const onOpen = useCallback(() => {
+ dispatch(addNodePopoverOpened());
+ }, [dispatch]);
+
+ const handleHotkeyOpen: HotkeyCallback = useCallback(
+ (e) => {
+ e.preventDefault();
+ onOpen();
+ setTimeout(() => {
+ inputRef.current?.focus();
+ }, 0);
+ },
+ [onOpen]
+ );
+
+ const handleHotkeyClose: HotkeyCallback = useCallback(() => {
+ onClose();
+ }, [onClose]);
+
+ useHotkeys(['shift+a', 'space'], handleHotkeyOpen);
+ useHotkeys(['escape'], handleHotkeyClose);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default memo(AddNodePopover);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopoverSelectItem.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopoverSelectItem.tsx
new file mode 100644
index 0000000000..95b033f95c
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/AddNodePopover/AddNodePopoverSelectItem.tsx
@@ -0,0 +1,29 @@
+import { Text } from '@chakra-ui/react';
+import { forwardRef } from 'react';
+import 'reactflow/dist/style.css';
+
+interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
+ value: string;
+ label: string;
+ description: string;
+}
+
+export const AddNodePopoverSelectItem = forwardRef(
+ ({ label, description, ...others }: ItemProps, ref) => {
+ return (
+
+
+ {label}
+
+ {description}
+
+
+
+ );
+ }
+);
+
+AddNodePopoverSelectItem.displayName = 'AddNodePopoverSelectItem';
diff --git a/invokeai/frontend/web/src/features/nodes/components/Flow.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx
similarity index 66%
rename from invokeai/frontend/web/src/features/nodes/components/Flow.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx
index 3290a65054..e8fb66d074 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Flow.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx
@@ -1,7 +1,11 @@
import { useToken } from '@chakra-ui/react';
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { contextMenusClosed } from 'features/ui/store/uiSlice';
import { useCallback } from 'react';
+import { useHotkeys } from 'react-hotkeys-hook';
import {
Background,
OnConnect,
@@ -16,7 +20,7 @@ import {
ProOptions,
ReactFlow,
} from 'reactflow';
-import { useIsValidConnection } from '../hooks/useIsValidConnection';
+import { useIsValidConnection } from '../../hooks/useIsValidConnection';
import {
connectionEnded,
connectionMade,
@@ -25,30 +29,54 @@ import {
edgesDeleted,
nodesChanged,
nodesDeleted,
+ selectedAll,
selectedEdgesChanged,
selectedNodesChanged,
+ selectionCopied,
+ selectionPasted,
viewportChanged,
-} from '../store/nodesSlice';
-import { CustomConnectionLine } from './CustomConnectionLine';
-import { edgeTypes } from './CustomEdges';
-import { nodeTypes } from './CustomNodes';
-import BottomLeftPanel from './editorPanels/BottomLeftPanel';
-import MinimapPanel from './editorPanels/MinimapPanel';
-import TopCenterPanel from './editorPanels/TopCenterPanel';
-import TopLeftPanel from './editorPanels/TopLeftPanel';
-import TopRightPanel from './editorPanels/TopRightPanel';
+} from '../../store/nodesSlice';
+import CustomConnectionLine from './connectionLines/CustomConnectionLine';
+import InvocationCollapsedEdge from './edges/InvocationCollapsedEdge';
+import InvocationDefaultEdge from './edges/InvocationDefaultEdge';
+import CurrentImageNode from './nodes/CurrentImage/CurrentImageNode';
+import InvocationNodeWrapper from './nodes/Invocation/InvocationNodeWrapper';
+import NotesNode from './nodes/Notes/NotesNode';
+
+const DELETE_KEYS = ['Delete', 'Backspace'];
+
+const edgeTypes = {
+ collapsed: InvocationCollapsedEdge,
+ default: InvocationDefaultEdge,
+};
+
+const nodeTypes = {
+ invocation: InvocationNodeWrapper,
+ current_image: CurrentImageNode,
+ notes: NotesNode,
+};
// TODO: can we support reactflow? if not, we could style the attribution so it matches the app
const proOptions: ProOptions = { hideAttribution: true };
+const selector = createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const { shouldSnapToGrid, selectionMode } = nodes;
+ return {
+ shouldSnapToGrid,
+ selectionMode,
+ };
+ },
+ defaultSelectorOptions
+);
+
export const Flow = () => {
const dispatch = useAppDispatch();
const nodes = useAppSelector((state) => state.nodes.nodes);
const edges = useAppSelector((state) => state.nodes.edges);
const viewport = useAppSelector((state) => state.nodes.viewport);
- const shouldSnapToGrid = useAppSelector(
- (state) => state.nodes.shouldSnapToGrid
- );
+ const { shouldSnapToGrid, selectionMode } = useAppSelector(selector);
const isValidConnection = useIsValidConnection();
@@ -119,8 +147,24 @@ export const Flow = () => {
dispatch(contextMenusClosed());
}, [dispatch]);
+ useHotkeys(['Ctrl+c', 'Meta+c'], (e) => {
+ e.preventDefault();
+ dispatch(selectionCopied());
+ });
+
+ useHotkeys(['Ctrl+a', 'Meta+a'], (e) => {
+ e.preventDefault();
+ dispatch(selectedAll());
+ });
+
+ useHotkeys(['Ctrl+v', 'Meta+v'], (e) => {
+ e.preventDefault();
+ dispatch(selectionPasted());
+ });
+
return (
{
proOptions={proOptions}
style={{ borderRadius }}
onPaneClick={handlePaneClick}
+ deleteKeyCode={DELETE_KEYS}
+ selectionMode={selectionMode}
>
-
-
-
-
-
);
diff --git a/invokeai/frontend/web/src/features/nodes/components/CustomConnectionLine.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx
similarity index 85%
rename from invokeai/frontend/web/src/features/nodes/components/CustomConnectionLine.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx
index 678d8e3d1d..a379be7ee2 100644
--- a/invokeai/frontend/web/src/features/nodes/components/CustomConnectionLine.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/connectionLines/CustomConnectionLine.tsx
@@ -1,8 +1,10 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
+import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
+import { FIELDS } from 'features/nodes/types/constants';
+import { memo } from 'react';
import { ConnectionLineComponentProps, getBezierPath } from 'reactflow';
-import { FIELDS, colorTokenToCssVar } from '../types/constants';
const selector = createSelector(stateSelector, ({ nodes }) => {
const { shouldAnimateEdges, currentConnectionFieldType, shouldColorEdges } =
@@ -25,7 +27,7 @@ const selector = createSelector(stateSelector, ({ nodes }) => {
};
});
-export const CustomConnectionLine = ({
+const CustomConnectionLine = ({
fromX,
fromY,
fromPosition,
@@ -59,3 +61,5 @@ export const CustomConnectionLine = ({
);
};
+
+export default memo(CustomConnectionLine);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationCollapsedEdge.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationCollapsedEdge.tsx
new file mode 100644
index 0000000000..fca38def34
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationCollapsedEdge.tsx
@@ -0,0 +1,94 @@
+import { Badge, Flex } from '@chakra-ui/react';
+import { useAppSelector } from 'app/store/storeHooks';
+import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
+import { memo, useMemo } from 'react';
+import {
+ BaseEdge,
+ EdgeLabelRenderer,
+ EdgeProps,
+ getBezierPath,
+} from 'reactflow';
+import { makeEdgeSelector } from './util/makeEdgeSelector';
+
+const InvocationCollapsedEdge = ({
+ sourceX,
+ sourceY,
+ targetX,
+ targetY,
+ sourcePosition,
+ targetPosition,
+ markerEnd,
+ data,
+ selected,
+ source,
+ target,
+ sourceHandleId,
+ targetHandleId,
+}: EdgeProps<{ count: number }>) => {
+ const selector = useMemo(
+ () =>
+ makeEdgeSelector(
+ source,
+ sourceHandleId,
+ target,
+ targetHandleId,
+ selected
+ ),
+ [selected, source, sourceHandleId, target, targetHandleId]
+ );
+
+ const { isSelected, shouldAnimate } = useAppSelector(selector);
+
+ const [edgePath, labelX, labelY] = getBezierPath({
+ sourceX,
+ sourceY,
+ sourcePosition,
+ targetX,
+ targetY,
+ targetPosition,
+ });
+
+ const { base500 } = useChakraThemeTokens();
+
+ return (
+ <>
+
+ {data?.count && data.count > 1 && (
+
+
+
+ {data.count}
+
+
+
+ )}
+ >
+ );
+};
+
+export default memo(InvocationCollapsedEdge);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx
new file mode 100644
index 0000000000..effefb12ab
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx
@@ -0,0 +1,58 @@
+import { useAppSelector } from 'app/store/storeHooks';
+import { memo, useMemo } from 'react';
+import { BaseEdge, EdgeProps, getBezierPath } from 'reactflow';
+import { makeEdgeSelector } from './util/makeEdgeSelector';
+
+const InvocationDefaultEdge = ({
+ sourceX,
+ sourceY,
+ targetX,
+ targetY,
+ sourcePosition,
+ targetPosition,
+ markerEnd,
+ selected,
+ source,
+ target,
+ sourceHandleId,
+ targetHandleId,
+}: EdgeProps) => {
+ const selector = useMemo(
+ () =>
+ makeEdgeSelector(
+ source,
+ sourceHandleId,
+ target,
+ targetHandleId,
+ selected
+ ),
+ [source, sourceHandleId, target, targetHandleId, selected]
+ );
+
+ const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
+
+ const [edgePath] = getBezierPath({
+ sourceX,
+ sourceY,
+ sourcePosition,
+ targetX,
+ targetY,
+ targetPosition,
+ });
+
+ return (
+
+ );
+};
+
+export default memo(InvocationDefaultEdge);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts b/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts
new file mode 100644
index 0000000000..b5dc484eae
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts
@@ -0,0 +1,42 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
+import { FIELDS } from 'features/nodes/types/constants';
+import { isInvocationNode } from 'features/nodes/types/types';
+
+export const makeEdgeSelector = (
+ source: string,
+ sourceHandleId: string | null | undefined,
+ target: string,
+ targetHandleId: string | null | undefined,
+ selected?: boolean
+) =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const sourceNode = nodes.nodes.find((node) => node.id === source);
+ const targetNode = nodes.nodes.find((node) => node.id === target);
+
+ const isInvocationToInvocationEdge =
+ isInvocationNode(sourceNode) && isInvocationNode(targetNode);
+
+ const isSelected =
+ sourceNode?.selected || targetNode?.selected || selected;
+ const sourceType = isInvocationToInvocationEdge
+ ? sourceNode?.data?.outputs[sourceHandleId || '']?.type
+ : undefined;
+
+ const stroke =
+ sourceType && nodes.shouldColorEdges
+ ? colorTokenToCssVar(FIELDS[sourceType].color)
+ : colorTokenToCssVar('base.500');
+
+ return {
+ isSelected,
+ shouldAnimate: nodes.shouldAnimateEdges && isSelected,
+ stroke,
+ };
+ },
+ defaultSelectorOptions
+ );
diff --git a/invokeai/frontend/web/src/features/nodes/components/nodes/CurrentImageNode.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/CurrentImage/CurrentImageNode.tsx
similarity index 97%
rename from invokeai/frontend/web/src/features/nodes/components/nodes/CurrentImageNode.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/CurrentImage/CurrentImageNode.tsx
index 985978f72d..6a8a2a3552 100644
--- a/invokeai/frontend/web/src/features/nodes/components/nodes/CurrentImageNode.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/CurrentImage/CurrentImageNode.tsx
@@ -7,7 +7,7 @@ import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { PropsWithChildren, memo } from 'react';
import { useSelector } from 'react-redux';
import { NodeProps } from 'reactflow';
-import NodeWrapper from '../Invocation/NodeWrapper';
+import NodeWrapper from '../common/NodeWrapper';
const selector = createSelector(stateSelector, ({ system, gallery }) => {
const imageDTO = gallery.selection[gallery.selection.length - 1];
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx
new file mode 100644
index 0000000000..8f6a2531a0
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNode.tsx
@@ -0,0 +1,86 @@
+import { Flex, Grid, GridItem } from '@chakra-ui/react';
+import { memo } from 'react';
+import InvocationNodeFooter from './InvocationNodeFooter';
+import InvocationNodeHeader from './InvocationNodeHeader';
+import NodeWrapper from '../common/NodeWrapper';
+import OutputField from './fields/OutputField';
+import InputField from './fields/InputField';
+import { useOutputFieldNames } from 'features/nodes/hooks/useOutputFieldNames';
+import { useWithFooter } from 'features/nodes/hooks/useWithFooter';
+import { useConnectionInputFieldNames } from 'features/nodes/hooks/useConnectionInputFieldNames';
+import { useAnyOrDirectInputFieldNames } from 'features/nodes/hooks/useAnyOrDirectInputFieldNames';
+
+type Props = {
+ nodeId: string;
+ isOpen: boolean;
+ label: string;
+ type: string;
+ selected: boolean;
+};
+
+const InvocationNode = ({ nodeId, isOpen, label, type, selected }: Props) => {
+ const inputConnectionFieldNames = useConnectionInputFieldNames(nodeId);
+ const inputAnyOrDirectFieldNames = useAnyOrDirectInputFieldNames(nodeId);
+ const outputFieldNames = useOutputFieldNames(nodeId);
+ const withFooter = useWithFooter(nodeId);
+
+ return (
+
+
+ {isOpen && (
+ <>
+
+
+
+ {inputConnectionFieldNames.map((fieldName, i) => (
+
+
+
+ ))}
+ {outputFieldNames.map((fieldName, i) => (
+
+
+
+ ))}
+
+ {inputAnyOrDirectFieldNames.map((fieldName) => (
+
+ ))}
+
+
+ {withFooter && }
+ >
+ )}
+
+ );
+};
+
+export default memo(InvocationNode);
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeCollapsedHandles.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeCollapsedHandles.tsx
similarity index 94%
rename from invokeai/frontend/web/src/features/nodes/components/Invocation/NodeCollapsedHandles.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeCollapsedHandles.tsx
index 32dd554ef4..30e02bfd84 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeCollapsedHandles.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeCollapsedHandles.tsx
@@ -10,7 +10,7 @@ interface Props {
nodeId: string;
}
-const NodeCollapsedHandles = ({ nodeId }: Props) => {
+const InvocationNodeCollapsedHandles = ({ nodeId }: Props) => {
const data = useNodeData(nodeId);
const { base400, base600 } = useChakraThemeTokens();
const backgroundColor = useColorModeValue(base400, base600);
@@ -71,4 +71,4 @@ const NodeCollapsedHandles = ({ nodeId }: Props) => {
);
};
-export default memo(NodeCollapsedHandles);
+export default memo(InvocationNodeCollapsedHandles);
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeFooter.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx
similarity index 86%
rename from invokeai/frontend/web/src/features/nodes/components/Invocation/NodeFooter.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx
index c858872b57..ffcdd13fef 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeFooter.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx
@@ -6,10 +6,8 @@ import {
Spacer,
} from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
-import {
- useHasImageOutput,
- useIsIntermediate,
-} from 'features/nodes/hooks/useNodeData';
+import { useHasImageOutput } from 'features/nodes/hooks/useHasImageOutput';
+import { useIsIntermediate } from 'features/nodes/hooks/useIsIntermediate';
import { fieldBooleanValueChanged } from 'features/nodes/store/nodesSlice';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { ChangeEvent, memo, useCallback } from 'react';
@@ -18,7 +16,7 @@ type Props = {
nodeId: string;
};
-const NodeFooter = ({ nodeId }: Props) => {
+const InvocationNodeFooter = ({ nodeId }: Props) => {
return (
{
);
};
-export default memo(NodeFooter);
+export default memo(InvocationNodeFooter);
const SaveImageCheckbox = memo(({ nodeId }: { nodeId: string }) => {
const dispatch = useAppDispatch();
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeHeader.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeHeader.tsx
similarity index 52%
rename from invokeai/frontend/web/src/features/nodes/components/Invocation/NodeHeader.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeHeader.tsx
index ea503a8f27..cd6c5215d1 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeHeader.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeHeader.tsx
@@ -1,10 +1,10 @@
import { Flex } from '@chakra-ui/react';
import { memo } from 'react';
-import NodeCollapseButton from '../Invocation/NodeCollapseButton';
-import NodeCollapsedHandles from '../Invocation/NodeCollapsedHandles';
-import NodeNotesEdit from '../Invocation/NodeNotesEdit';
-import NodeStatusIndicator from '../Invocation/NodeStatusIndicator';
-import NodeTitle from '../Invocation/NodeTitle';
+import NodeCollapseButton from '../common/NodeCollapseButton';
+import NodeTitle from '../common/NodeTitle';
+import InvocationNodeCollapsedHandles from './InvocationNodeCollapsedHandles';
+import InvocationNodeNotes from './InvocationNodeNotes';
+import InvocationNodeStatusIndicator from './InvocationNodeStatusIndicator';
type Props = {
nodeId: string;
@@ -14,7 +14,7 @@ type Props = {
selected: boolean;
};
-const NodeHeader = ({ nodeId, isOpen }: Props) => {
+const InvocationNodeHeader = ({ nodeId, isOpen }: Props) => {
return (
{
justifyContent: 'space-between',
h: 8,
textAlign: 'center',
- fontWeight: 600,
+ fontWeight: 500,
color: 'base.700',
_dark: { color: 'base.200' },
}}
@@ -33,12 +33,12 @@ const NodeHeader = ({ nodeId, isOpen }: Props) => {
-
-
+
+
- {!isOpen && }
+ {!isOpen && }
);
};
-export default memo(NodeHeader);
+export default memo(InvocationNodeHeader);
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeNotesEdit.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeNotes.tsx
similarity index 87%
rename from invokeai/frontend/web/src/features/nodes/components/Invocation/NodeNotesEdit.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeNotes.tsx
index fa5a9d76fb..aca5f75224 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeNotesEdit.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeNotes.tsx
@@ -16,14 +16,11 @@ import {
} from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
import IAITextarea from 'common/components/IAITextarea';
-import {
- useNodeData,
- useNodeLabel,
- useNodeTemplate,
- useNodeTemplateTitle,
-} from 'features/nodes/hooks/useNodeData';
+import { useNodeData } from 'features/nodes/hooks/useNodeData';
+import { useNodeLabel } from 'features/nodes/hooks/useNodeLabel';
+import { useNodeTemplate } from 'features/nodes/hooks/useNodeTemplate';
+import { useNodeTemplateTitle } from 'features/nodes/hooks/useNodeTemplateTitle';
import { nodeNotesChanged } from 'features/nodes/store/nodesSlice';
-import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { isInvocationNodeData } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react';
import { FaInfoCircle } from 'react-icons/fa';
@@ -32,7 +29,7 @@ interface Props {
nodeId: string;
}
-const NodeNotesEdit = ({ nodeId }: Props) => {
+const InvocationNodeNotes = ({ nodeId }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const label = useNodeLabel(nodeId);
const title = useNodeTemplateTitle(nodeId);
@@ -45,7 +42,7 @@ const NodeNotesEdit = ({ nodeId }: Props) => {
shouldWrapChildren
>
{
);
};
-export default memo(NodeNotesEdit);
+export default memo(InvocationNodeNotes);
const TooltipContent = memo(({ nodeId }: { nodeId: string }) => {
const data = useNodeData(nodeId);
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeStatusIndicator.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeStatusIndicator.tsx
similarity index 97%
rename from invokeai/frontend/web/src/features/nodes/components/Invocation/NodeStatusIndicator.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeStatusIndicator.tsx
index d53fec4b42..6e1da90ad8 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/NodeStatusIndicator.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeStatusIndicator.tsx
@@ -28,7 +28,7 @@ const circleStyles = {
'.chakra-progress__track': { stroke: 'transparent' },
};
-const NodeStatusIndicator = ({ nodeId }: Props) => {
+const InvocationNodeStatusIndicator = ({ nodeId }: Props) => {
const selectNodeExecutionState = useMemo(
() =>
createSelector(
@@ -64,7 +64,7 @@ const NodeStatusIndicator = ({ nodeId }: Props) => {
);
};
-export default memo(NodeStatusIndicator);
+export default memo(InvocationNodeStatusIndicator);
type TooltipLabelProps = {
nodeExecutionState: NodeExecutionState;
diff --git a/invokeai/frontend/web/src/features/nodes/components/Invocation/UnknownNodeFallback.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx
similarity index 88%
rename from invokeai/frontend/web/src/features/nodes/components/Invocation/UnknownNodeFallback.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx
index 664a788b5a..7ec59f00f0 100644
--- a/invokeai/frontend/web/src/features/nodes/components/Invocation/UnknownNodeFallback.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx
@@ -1,8 +1,8 @@
import { Box, Flex, Text } from '@chakra-ui/react';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { memo } from 'react';
-import NodeCollapseButton from '../Invocation/NodeCollapseButton';
-import NodeWrapper from '../Invocation/NodeWrapper';
+import NodeCollapseButton from '../common/NodeCollapseButton';
+import NodeWrapper from '../common/NodeWrapper';
type Props = {
nodeId: string;
@@ -12,7 +12,7 @@ type Props = {
selected: boolean;
};
-const UnknownNodeFallback = ({
+const InvocationNodeUnknownFallback = ({
nodeId,
isOpen,
label,
@@ -72,4 +72,4 @@ const UnknownNodeFallback = ({
);
};
-export default memo(UnknownNodeFallback);
+export default memo(InvocationNodeUnknownFallback);
diff --git a/invokeai/frontend/web/src/features/nodes/components/nodes/InvocationNodeWrapper.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeWrapper.tsx
similarity index 90%
rename from invokeai/frontend/web/src/features/nodes/components/nodes/InvocationNodeWrapper.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeWrapper.tsx
index 26bda27d8b..3c79eac1d3 100644
--- a/invokeai/frontend/web/src/features/nodes/components/nodes/InvocationNodeWrapper.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeWrapper.tsx
@@ -5,7 +5,7 @@ import { InvocationNodeData } from 'features/nodes/types/types';
import { memo, useMemo } from 'react';
import { NodeProps } from 'reactflow';
import InvocationNode from '../Invocation/InvocationNode';
-import UnknownNodeFallback from '../Invocation/UnknownNodeFallback';
+import InvocationNodeUnknownFallback from './InvocationNodeUnknownFallback';
const InvocationNodeWrapper = (props: NodeProps) => {
const { data, selected } = props;
@@ -23,7 +23,7 @@ const InvocationNodeWrapper = (props: NodeProps) => {
if (!nodeTemplate) {
return (
- ['children'];
+};
+
+const FieldContextMenu = ({ nodeId, fieldName, kind, children }: Props) => {
+ const dispatch = useAppDispatch();
+ const label = useFieldLabel(nodeId, fieldName);
+ const fieldTemplateTitle = useFieldTemplateTitle(nodeId, fieldName, kind);
+ const input = useFieldInputKind(nodeId, fieldName);
+
+ const skipEvent = useCallback((e: MouseEvent) => {
+ e.preventDefault();
+ }, []);
+
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const isExposed = Boolean(
+ nodes.workflow.exposedFields.find(
+ (f) => f.nodeId === nodeId && f.fieldName === fieldName
+ )
+ );
+
+ return { isExposed };
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, nodeId]
+ );
+
+ const mayExpose = useMemo(
+ () => ['any', 'direct'].includes(input ?? '__UNKNOWN_INPUT__'),
+ [input]
+ );
+
+ const { isExposed } = useAppSelector(selector);
+
+ const handleExposeField = useCallback(() => {
+ dispatch(workflowExposedFieldAdded({ nodeId, fieldName }));
+ }, [dispatch, fieldName, nodeId]);
+
+ const handleUnexposeField = useCallback(() => {
+ dispatch(workflowExposedFieldRemoved({ nodeId, fieldName }));
+ }, [dispatch, fieldName, nodeId]);
+
+ const menuItems = useMemo(() => {
+ const menuItems: ReactNode[] = [];
+ if (mayExpose && !isExposed) {
+ menuItems.push(
+ }
+ onClick={handleExposeField}
+ >
+ Add to Linear View
+
+ );
+ }
+ if (mayExpose && isExposed) {
+ menuItems.push(
+ }
+ onClick={handleUnexposeField}
+ >
+ Remove from Linear View
+
+ );
+ }
+ return menuItems;
+ }, [
+ fieldName,
+ handleExposeField,
+ handleUnexposeField,
+ isExposed,
+ mayExpose,
+ nodeId,
+ ]);
+
+ return (
+
+ menuProps={{
+ size: 'sm',
+ isLazy: true,
+ }}
+ menuButtonProps={{
+ bg: 'transparent',
+ _hover: { bg: 'transparent' },
+ }}
+ renderMenu={() =>
+ !menuItems.length ? null : (
+
+
+ {menuItems}
+
+
+ )
+ }
+ >
+ {children}
+
+ );
+};
+
+export default memo(FieldContextMenu);
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/FieldHandle.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/FieldHandle.tsx
similarity index 92%
rename from invokeai/frontend/web/src/features/nodes/components/fields/FieldHandle.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/FieldHandle.tsx
index f79a57a4eb..14924a16fe 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/FieldHandle.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/FieldHandle.tsx
@@ -1,12 +1,15 @@
import { Tooltip } from '@chakra-ui/react';
-import { CSSProperties, memo, useMemo } from 'react';
-import { Handle, HandleType, Position } from 'reactflow';
+import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
import {
FIELDS,
HANDLE_TOOLTIP_OPEN_DELAY,
- colorTokenToCssVar,
-} from '../../types/constants';
-import { InputFieldTemplate, OutputFieldTemplate } from '../../types/types';
+} from 'features/nodes/types/constants';
+import {
+ InputFieldTemplate,
+ OutputFieldTemplate,
+} from 'features/nodes/types/types';
+import { CSSProperties, memo, useMemo } from 'react';
+import { Handle, HandleType, Position } from 'reactflow';
export const handleBaseStyles: CSSProperties = {
position: 'absolute',
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/FieldTitle.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/FieldTitle.tsx
similarity index 52%
rename from invokeai/frontend/web/src/features/nodes/components/fields/FieldTitle.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/FieldTitle.tsx
index e9a49989f6..7a0ee62a88 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/FieldTitle.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/FieldTitle.tsx
@@ -3,63 +3,41 @@ import {
EditableInput,
EditablePreview,
Flex,
+ forwardRef,
useEditableControls,
} from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIDraggable from 'common/components/IAIDraggable';
-import { NodeFieldDraggableData } from 'features/dnd/types';
-import {
- useFieldData,
- useFieldTemplate,
-} from 'features/nodes/hooks/useNodeData';
+import { useFieldLabel } from 'features/nodes/hooks/useFieldLabel';
+import { useFieldTemplateTitle } from 'features/nodes/hooks/useFieldTemplateTitle';
import { fieldLabelChanged } from 'features/nodes/store/nodesSlice';
-import {
- MouseEvent,
- memo,
- useCallback,
- useEffect,
- useMemo,
- useState,
-} from 'react';
+import { MouseEvent, memo, useCallback, useEffect, useState } from 'react';
interface Props {
nodeId: string;
fieldName: string;
- isDraggable?: boolean;
kind: 'input' | 'output';
+ isMissingInput?: boolean;
}
-const FieldTitle = (props: Props) => {
- const { nodeId, fieldName, isDraggable = false, kind } = props;
- const fieldTemplate = useFieldTemplate(nodeId, fieldName, kind);
- const field = useFieldData(nodeId, fieldName);
+const FieldTitle = forwardRef((props: Props, ref) => {
+ const { nodeId, fieldName, kind, isMissingInput = false } = props;
+ const label = useFieldLabel(nodeId, fieldName);
+ const fieldTemplateTitle = useFieldTemplateTitle(nodeId, fieldName, kind);
const dispatch = useAppDispatch();
const [localTitle, setLocalTitle] = useState(
- field?.label || fieldTemplate?.title || 'Unknown Field'
- );
-
- const draggableData: NodeFieldDraggableData | undefined = useMemo(
- () =>
- field &&
- fieldTemplate?.fieldKind === 'input' &&
- fieldTemplate?.input !== 'connection' &&
- isDraggable
- ? {
- id: `${nodeId}-${fieldName}`,
- payloadType: 'NODE_FIELD',
- payload: { nodeId, field, fieldTemplate },
- }
- : undefined,
- [field, fieldName, fieldTemplate, isDraggable, nodeId]
+ label || fieldTemplateTitle || 'Unknown Field'
);
const handleSubmit = useCallback(
async (newTitle: string) => {
+ if (newTitle && (newTitle === label || newTitle === fieldTemplateTitle)) {
+ return;
+ }
+ setLocalTitle(newTitle || fieldTemplateTitle || 'Unknown Field');
dispatch(fieldLabelChanged({ nodeId, fieldName, label: newTitle }));
- setLocalTitle(newTitle || fieldTemplate?.title || 'Unknown Field');
},
- [dispatch, nodeId, fieldName, fieldTemplate?.title]
+ [label, fieldTemplateTitle, dispatch, nodeId, fieldName]
);
const handleChange = useCallback((newTitle: string) => {
@@ -68,39 +46,54 @@ const FieldTitle = (props: Props) => {
useEffect(() => {
// Another component may change the title; sync local title with global state
- setLocalTitle(field?.label || fieldTemplate?.title || 'Unknown Field');
- }, [field?.label, fieldTemplate?.title]);
+ setLocalTitle(label || fieldTemplateTitle || 'Unknown Field');
+ }, [label, fieldTemplateTitle]);
return (
{
},
}}
/>
-
+
);
-};
+});
export default memo(FieldTitle);
-type EditableControlsProps = {
- draggableData?: NodeFieldDraggableData;
-};
-
-const EditableControls = memo((props: EditableControlsProps) => {
+const EditableControls = memo(() => {
const { isEditing, getEditButtonProps } = useEditableControls();
- const handleDoubleClick = useCallback(
+ const handleClick = useCallback(
(e: MouseEvent) => {
const { onClick } = getEditButtonProps();
if (!onClick) {
return;
}
onClick(e);
+ e.preventDefault();
},
[getEditButtonProps]
);
@@ -137,19 +127,9 @@ const EditableControls = memo((props: EditableControlsProps) => {
return null;
}
- if (props.draggableData) {
- return (
-
- );
- }
-
return (
{
const isInputTemplate = isInputFieldTemplate(fieldTemplate);
const fieldTitle = useMemo(() => {
if (isInputFieldValue(field)) {
- if (field.label && fieldTemplate) {
+ if (field.label && fieldTemplate?.title) {
return `${field.label} (${fieldTemplate.title})`;
}
@@ -53,4 +51,4 @@ const FieldTooltipContent = ({ nodeId, fieldName, kind }: Props) => {
);
};
-export default FieldTooltipContent;
+export default memo(FieldTooltipContent);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx
new file mode 100644
index 0000000000..3758ae4114
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx
@@ -0,0 +1,178 @@
+import { Box, Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react';
+import SelectionOverlay from 'common/components/SelectionOverlay';
+import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
+import { useDoesInputHaveValue } from 'features/nodes/hooks/useDoesInputHaveValue';
+import { useFieldInputKind } from 'features/nodes/hooks/useFieldInputKind';
+import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
+import { useIsMouseOverField } from 'features/nodes/hooks/useIsMouseOverField';
+import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
+import { PropsWithChildren, memo, useMemo } from 'react';
+import FieldContextMenu from './FieldContextMenu';
+import FieldHandle from './FieldHandle';
+import FieldTitle from './FieldTitle';
+import FieldTooltipContent from './FieldTooltipContent';
+import InputFieldRenderer from './InputFieldRenderer';
+
+interface Props {
+ nodeId: string;
+ fieldName: string;
+}
+
+const InputField = ({ nodeId, fieldName }: Props) => {
+ const fieldTemplate = useFieldTemplate(nodeId, fieldName, 'input');
+ const doesFieldHaveValue = useDoesInputHaveValue(nodeId, fieldName);
+ const input = useFieldInputKind(nodeId, fieldName);
+
+ const {
+ isConnected,
+ isConnectionInProgress,
+ isConnectionStartField,
+ connectionError,
+ shouldDim,
+ } = useConnectionState({ nodeId, fieldName, kind: 'input' });
+
+ const isMissingInput = useMemo(() => {
+ if (fieldTemplate?.fieldKind !== 'input') {
+ return false;
+ }
+
+ if (!fieldTemplate.required) {
+ return false;
+ }
+
+ if (!isConnected && fieldTemplate.input === 'connection') {
+ return true;
+ }
+
+ if (!doesFieldHaveValue && !isConnected && fieldTemplate.input === 'any') {
+ return true;
+ }
+ }, [fieldTemplate, isConnected, doesFieldHaveValue]);
+
+ if (fieldTemplate?.fieldKind !== 'input') {
+ return (
+
+
+ Unknown input: {fieldName}
+
+
+ );
+ }
+
+ return (
+
+
+
+ {(ref) => (
+
+ }
+ openDelay={HANDLE_TOOLTIP_OPEN_DELAY}
+ placement="top"
+ hasArrow
+ >
+
+
+
+
+ )}
+
+
+
+
+
+
+ {fieldTemplate.input !== 'direct' && (
+
+ )}
+
+ );
+};
+
+export default memo(InputField);
+
+type InputFieldWrapperProps = PropsWithChildren<{
+ shouldDim: boolean;
+ nodeId: string;
+ fieldName: string;
+}>;
+
+const InputFieldWrapper = memo(
+ ({ shouldDim, nodeId, fieldName, children }: InputFieldWrapperProps) => {
+ const { isMouseOverField, handleMouseOver, handleMouseOut } =
+ useIsMouseOverField(nodeId, fieldName);
+
+ return (
+
+ {children}
+
+
+ );
+ }
+);
+
+InputFieldWrapper.displayName = 'InputFieldWrapper';
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/InputFieldRenderer.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx
similarity index 73%
rename from invokeai/frontend/web/src/features/nodes/components/fields/InputFieldRenderer.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx
index acec921d8e..9b3ce100c8 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/InputFieldRenderer.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx
@@ -1,30 +1,29 @@
-import { Box } from '@chakra-ui/react';
-import {
- useFieldData,
- useFieldTemplate,
-} from 'features/nodes/hooks/useNodeData';
+import { Box, Text } from '@chakra-ui/react';
+import { useFieldData } from 'features/nodes/hooks/useFieldData';
+import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
import { memo } from 'react';
-import BooleanInputField from './fieldTypes/BooleanInputField';
-import ClipInputField from './fieldTypes/ClipInputField';
-import CollectionInputField from './fieldTypes/CollectionInputField';
-import CollectionItemInputField from './fieldTypes/CollectionItemInputField';
-import ColorInputField from './fieldTypes/ColorInputField';
-import ConditioningInputField from './fieldTypes/ConditioningInputField';
-import ControlInputField from './fieldTypes/ControlInputField';
-import ControlNetModelInputField from './fieldTypes/ControlNetModelInputField';
-import EnumInputField from './fieldTypes/EnumInputField';
-import ImageCollectionInputField from './fieldTypes/ImageCollectionInputField';
-import ImageInputField from './fieldTypes/ImageInputField';
-import LatentsInputField from './fieldTypes/LatentsInputField';
-import LoRAModelInputField from './fieldTypes/LoRAModelInputField';
-import MainModelInputField from './fieldTypes/MainModelInputField';
-import NumberInputField from './fieldTypes/NumberInputField';
-import RefinerModelInputField from './fieldTypes/RefinerModelInputField';
-import SDXLMainModelInputField from './fieldTypes/SDXLMainModelInputField';
-import StringInputField from './fieldTypes/StringInputField';
-import UnetInputField from './fieldTypes/UnetInputField';
-import VaeInputField from './fieldTypes/VaeInputField';
-import VaeModelInputField from './fieldTypes/VaeModelInputField';
+import BooleanInputField from './inputs/BooleanInputField';
+import ClipInputField from './inputs/ClipInputField';
+import CollectionInputField from './inputs/CollectionInputField';
+import CollectionItemInputField from './inputs/CollectionItemInputField';
+import ColorInputField from './inputs/ColorInputField';
+import ConditioningInputField from './inputs/ConditioningInputField';
+import ControlInputField from './inputs/ControlInputField';
+import ControlNetModelInputField from './inputs/ControlNetModelInputField';
+import EnumInputField from './inputs/EnumInputField';
+import ImageCollectionInputField from './inputs/ImageCollectionInputField';
+import ImageInputField from './inputs/ImageInputField';
+import LatentsInputField from './inputs/LatentsInputField';
+import LoRAModelInputField from './inputs/LoRAModelInputField';
+import MainModelInputField from './inputs/MainModelInputField';
+import NumberInputField from './inputs/NumberInputField';
+import RefinerModelInputField from './inputs/RefinerModelInputField';
+import SDXLMainModelInputField from './inputs/SDXLMainModelInputField';
+import SchedulerInputField from './inputs/SchedulerInputField';
+import StringInputField from './inputs/StringInputField';
+import UnetInputField from './inputs/UnetInputField';
+import VaeInputField from './inputs/VaeInputField';
+import VaeModelInputField from './inputs/VaeModelInputField';
type InputFieldProps = {
nodeId: string;
@@ -286,7 +285,30 @@ const InputFieldRenderer = ({ nodeId, fieldName }: InputFieldProps) => {
);
}
- return Unknown field type: {field?.type};
+ if (field?.type === 'Scheduler' && fieldTemplate?.type === 'Scheduler') {
+ return (
+
+ );
+ }
+
+ return (
+
+
+ Unknown field type: {field?.type}
+
+
+ );
};
export default memo(InputFieldRenderer);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/LinearViewField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/LinearViewField.tsx
new file mode 100644
index 0000000000..cbf4a19137
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/LinearViewField.tsx
@@ -0,0 +1,82 @@
+import { Flex, FormControl, FormLabel, Icon, Tooltip } from '@chakra-ui/react';
+import { useAppDispatch } from 'app/store/storeHooks';
+import IAIIconButton from 'common/components/IAIIconButton';
+import SelectionOverlay from 'common/components/SelectionOverlay';
+import { useIsMouseOverField } from 'features/nodes/hooks/useIsMouseOverField';
+import { workflowExposedFieldRemoved } from 'features/nodes/store/nodesSlice';
+import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
+import { memo, useCallback } from 'react';
+import { FaInfoCircle, FaTrash } from 'react-icons/fa';
+import FieldTitle from './FieldTitle';
+import FieldTooltipContent from './FieldTooltipContent';
+import InputFieldRenderer from './InputFieldRenderer';
+
+type Props = {
+ nodeId: string;
+ fieldName: string;
+};
+
+const LinearViewField = ({ nodeId, fieldName }: Props) => {
+ const dispatch = useAppDispatch();
+ const { isMouseOverField, handleMouseOut, handleMouseOver } =
+ useIsMouseOverField(nodeId, fieldName);
+
+ const handleRemoveField = useCallback(() => {
+ dispatch(workflowExposedFieldRemoved({ nodeId, fieldName }));
+ }, [dispatch, fieldName, nodeId]);
+
+ return (
+
+
+
+
+
+ }
+ openDelay={HANDLE_TOOLTIP_OPEN_DELAY}
+ placement="top"
+ hasArrow
+ >
+
+
+
+
+ }
+ />
+
+
+
+
+
+ );
+};
+
+export default memo(LinearViewField);
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/OutputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx
similarity index 92%
rename from invokeai/frontend/web/src/features/nodes/components/fields/OutputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx
index 2a257d741e..e717423f65 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/OutputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/OutputField.tsx
@@ -1,12 +1,6 @@
-import {
- Flex,
- FormControl,
- FormLabel,
- Spacer,
- Tooltip,
-} from '@chakra-ui/react';
+import { Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react';
import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
-import { useFieldTemplate } from 'features/nodes/hooks/useNodeData';
+import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
import { PropsWithChildren, memo } from 'react';
import FieldHandle from './FieldHandle';
@@ -42,7 +36,6 @@ const OutputField = ({ nodeId, fieldName }: Props) => {
return (
-
{children}
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/BooleanInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/BooleanInputField.tsx
similarity index 86%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/BooleanInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/BooleanInputField.tsx
index daf2f598ba..c9f83403f6 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/BooleanInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/BooleanInputField.tsx
@@ -4,9 +4,9 @@ import { fieldBooleanValueChanged } from 'features/nodes/store/nodesSlice';
import {
BooleanInputFieldTemplate,
BooleanInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react';
-import { FieldComponentProps } from './types';
const BooleanInputFieldComponent = (
props: FieldComponentProps
@@ -29,7 +29,11 @@ const BooleanInputFieldComponent = (
);
return (
-
+
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ClipInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ClipInputField.tsx
similarity index 86%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ClipInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ClipInputField.tsx
index 37c3db3d11..cf5d7fae95 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ClipInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ClipInputField.tsx
@@ -1,9 +1,9 @@
import {
ClipInputFieldTemplate,
ClipInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
-import { FieldComponentProps } from './types';
const ClipInputFieldComponent = (
_props: FieldComponentProps
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/CollectionInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/CollectionInputField.tsx
similarity index 88%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/CollectionInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/CollectionInputField.tsx
index 99c88af2cb..7cbc46f28c 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/CollectionInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/CollectionInputField.tsx
@@ -1,9 +1,9 @@
import {
CollectionInputFieldTemplate,
CollectionInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
-import { FieldComponentProps } from './types';
const CollectionInputFieldComponent = (
_props: FieldComponentProps<
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/CollectionItemInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/CollectionItemInputField.tsx
similarity index 88%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/CollectionItemInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/CollectionItemInputField.tsx
index 00f753d8d3..e67a20bdfb 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/CollectionItemInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/CollectionItemInputField.tsx
@@ -1,9 +1,9 @@
import {
CollectionItemInputFieldTemplate,
CollectionItemInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
-import { FieldComponentProps } from './types';
const CollectionItemInputFieldComponent = (
_props: FieldComponentProps<
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ColorInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorInputField.tsx
similarity index 95%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ColorInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorInputField.tsx
index 422c3ba48f..c2af279cb5 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ColorInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorInputField.tsx
@@ -3,10 +3,10 @@ import { fieldColorValueChanged } from 'features/nodes/store/nodesSlice';
import {
ColorInputFieldTemplate,
ColorInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo, useCallback } from 'react';
import { RgbaColor, RgbaColorPicker } from 'react-colorful';
-import { FieldComponentProps } from './types';
const ColorInputFieldComponent = (
props: FieldComponentProps
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ConditioningInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ConditioningInputField.tsx
similarity index 88%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ConditioningInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ConditioningInputField.tsx
index e280251cd3..9d174f40c5 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ConditioningInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ConditioningInputField.tsx
@@ -1,9 +1,9 @@
import {
ConditioningInputFieldTemplate,
ConditioningInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
-import { FieldComponentProps } from './types';
const ConditioningInputFieldComponent = (
_props: FieldComponentProps<
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ControlInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ControlInputField.tsx
similarity index 87%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ControlInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ControlInputField.tsx
index 6b2b3deafb..346dd49b21 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ControlInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ControlInputField.tsx
@@ -1,9 +1,9 @@
import {
ControlInputFieldTemplate,
ControlInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
-import { FieldComponentProps } from './types';
const ControlInputFieldComponent = (
_props: FieldComponentProps
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ControlNetModelInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ControlNetModelInputField.tsx
similarity index 97%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ControlNetModelInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ControlNetModelInputField.tsx
index 492ec51d20..f66c8b0cfd 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/ControlNetModelInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ControlNetModelInputField.tsx
@@ -5,13 +5,13 @@ import { fieldControlNetModelValueChanged } from 'features/nodes/store/nodesSlic
import {
ControlNetModelInputFieldTemplate,
ControlNetModelInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam';
import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react';
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
-import { FieldComponentProps } from './types';
const ControlNetModelInputFieldComponent = (
props: FieldComponentProps<
@@ -85,7 +85,7 @@ const ControlNetModelInputFieldComponent = (
return (
@@ -30,7 +30,7 @@ const EnumInputFieldComponent = (
return (
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/NumberInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberInputField.tsx
similarity index 96%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/NumberInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberInputField.tsx
index df5c3f763e..1e569d5005 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/NumberInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberInputField.tsx
@@ -13,9 +13,9 @@ import {
FloatInputFieldValue,
IntegerInputFieldTemplate,
IntegerInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo, useEffect, useMemo, useState } from 'react';
-import { FieldComponentProps } from './types';
const NumberInputFieldComponent = (
props: FieldComponentProps<
@@ -64,7 +64,7 @@ const NumberInputFieldComponent = (
step={isIntegerField ? 1 : 0.1}
precision={isIntegerField ? 0 : 3}
>
-
+
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/RefinerModelInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/RefinerModelInputField.tsx
similarity index 93%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/RefinerModelInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/RefinerModelInputField.tsx
index 0eec884de0..4298670934 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/RefinerModelInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/RefinerModelInputField.tsx
@@ -6,6 +6,7 @@ import { fieldRefinerModelValueChanged } from 'features/nodes/store/nodesSlice';
import {
SDXLRefinerModelInputFieldTemplate,
SDXLRefinerModelInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam';
@@ -16,7 +17,6 @@ import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { REFINER_BASE_MODELS } from 'services/api/constants';
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
-import { FieldComponentProps } from './types';
const RefinerModelInputFieldComponent = (
props: FieldComponentProps<
@@ -96,7 +96,7 @@ const RefinerModelInputFieldComponent = (
) : (
0 ? 'Select a model' : 'No models available'}
@@ -104,10 +104,15 @@ const RefinerModelInputFieldComponent = (
error={data.length === 0}
disabled={data.length === 0}
onChange={handleChangeModel}
+ sx={{
+ '.mantine-Select-dropdown': {
+ width: '16rem !important',
+ },
+ }}
/>
{isSyncModelEnabled && (
-
+
)}
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/SDXLMainModelInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SDXLMainModelInputField.tsx
similarity index 93%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/SDXLMainModelInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SDXLMainModelInputField.tsx
index e904aad246..f1721ecd58 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/SDXLMainModelInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SDXLMainModelInputField.tsx
@@ -6,6 +6,7 @@ import { fieldMainModelValueChanged } from 'features/nodes/store/nodesSlice';
import {
SDXLMainModelInputFieldTemplate,
SDXLMainModelInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam';
@@ -19,7 +20,6 @@ import {
useGetMainModelsQuery,
useGetOnnxModelsQuery,
} from 'services/api/endpoints/models';
-import { FieldComponentProps } from './types';
const ModelInputFieldComponent = (
props: FieldComponentProps<
@@ -123,7 +123,7 @@ const ModelInputFieldComponent = (
) : (
0 ? 'Select a model' : 'No models available'}
@@ -131,8 +131,13 @@ const ModelInputFieldComponent = (
error={data.length === 0}
disabled={data.length === 0}
onChange={handleChangeModel}
+ sx={{
+ '.mantine-Select-dropdown': {
+ width: '16rem !important',
+ },
+ }}
/>
- {isSyncModelEnabled && }
+ {isSyncModelEnabled && }
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SchedulerInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SchedulerInputField.tsx
new file mode 100644
index 0000000000..557c128942
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/SchedulerInputField.tsx
@@ -0,0 +1,80 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
+import { fieldSchedulerValueChanged } from 'features/nodes/store/nodesSlice';
+import {
+ SchedulerInputFieldTemplate,
+ SchedulerInputFieldValue,
+ FieldComponentProps,
+} from 'features/nodes/types/types';
+import {
+ SCHEDULER_LABEL_MAP,
+ SchedulerParam,
+} from 'features/parameters/types/parameterSchemas';
+import { map } from 'lodash-es';
+import { memo, useCallback } from 'react';
+
+const selector = createSelector(
+ [stateSelector],
+ ({ ui }) => {
+ const { favoriteSchedulers: enabledSchedulers } = ui;
+
+ const data = map(SCHEDULER_LABEL_MAP, (label, name) => ({
+ value: name,
+ label: label,
+ group: enabledSchedulers.includes(name as SchedulerParam)
+ ? 'Favorites'
+ : undefined,
+ })).sort((a, b) => a.label.localeCompare(b.label));
+
+ return {
+ data,
+ };
+ },
+ defaultSelectorOptions
+);
+
+const SchedulerInputField = (
+ props: FieldComponentProps<
+ SchedulerInputFieldValue,
+ SchedulerInputFieldTemplate
+ >
+) => {
+ const { nodeId, field } = props;
+ const dispatch = useAppDispatch();
+ const { data } = useAppSelector(selector);
+
+ const handleChange = useCallback(
+ (value: string | null) => {
+ if (!value) {
+ return;
+ }
+ dispatch(
+ fieldSchedulerValueChanged({
+ nodeId,
+ fieldName: field.name,
+ value: value as SchedulerParam,
+ })
+ );
+ },
+ [dispatch, field.name, nodeId]
+ );
+
+ return (
+
+ );
+};
+
+export default memo(SchedulerInputField);
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/StringInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/StringInputField.tsx
similarity index 96%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/StringInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/StringInputField.tsx
index c172e928d0..c82b8f612c 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/StringInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/StringInputField.tsx
@@ -5,9 +5,9 @@ import { fieldStringValueChanged } from 'features/nodes/store/nodesSlice';
import {
StringInputFieldTemplate,
StringInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react';
-import { FieldComponentProps } from './types';
const StringInputFieldComponent = (
props: FieldComponentProps
@@ -31,6 +31,7 @@ const StringInputFieldComponent = (
if (fieldTemplate.ui_component === 'textarea') {
return (
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/VaeInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/VaeInputField.tsx
similarity index 86%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/VaeInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/VaeInputField.tsx
index 16c59368f9..738267faab 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/VaeInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/VaeInputField.tsx
@@ -1,9 +1,9 @@
import {
VaeInputFieldTemplate,
VaeInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
-import { FieldComponentProps } from './types';
const VaeInputFieldComponent = (
_props: FieldComponentProps
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/VaeModelInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/VaeModelInputField.tsx
similarity index 94%
rename from invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/VaeModelInputField.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/VaeModelInputField.tsx
index 5dd639cf5c..529febb6c1 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/fieldTypes/VaeModelInputField.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/VaeModelInputField.tsx
@@ -6,13 +6,13 @@ import { fieldVaeModelValueChanged } from 'features/nodes/store/nodesSlice';
import {
VaeModelInputFieldTemplate,
VaeModelInputFieldValue,
+ FieldComponentProps,
} from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToVAEModelParam } from 'features/parameters/util/modelIdToVAEModelParam';
import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react';
import { useGetVaeModelsQuery } from 'services/api/endpoints/models';
-import { FieldComponentProps } from './types';
const VaeModelInputFieldComponent = (
props: FieldComponentProps<
@@ -85,6 +85,7 @@ const VaeModelInputFieldComponent = (
return (
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/nodes/NotesNode.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Notes/NotesNode.tsx
similarity index 90%
rename from invokeai/frontend/web/src/features/nodes/components/nodes/NotesNode.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/nodes/Notes/NotesNode.tsx
index 7a46c11901..ec869f3dad 100644
--- a/invokeai/frontend/web/src/features/nodes/components/nodes/NotesNode.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Notes/NotesNode.tsx
@@ -5,9 +5,9 @@ import { notesNodeValueChanged } from 'features/nodes/store/nodesSlice';
import { NotesNodeData } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react';
import { NodeProps } from 'reactflow';
-import NodeCollapseButton from '../Invocation/NodeCollapseButton';
-import NodeTitle from '../Invocation/NodeTitle';
-import NodeWrapper from '../Invocation/NodeWrapper';
+import NodeWrapper from '../common/NodeWrapper';
+import NodeCollapseButton from '../common/NodeCollapseButton';
+import NodeTitle from '../common/NodeTitle';
const NotesNode = (props: NodeProps) => {
const { id: nodeId, data, selected } = props;
@@ -40,7 +40,7 @@ const NotesNode = (props: NodeProps) => {
<>
{
return (
{
return (
{
noOfLines={1}
/>
['w'];
+};
+
+const NodeWrapper = (props: NodeWrapperProps) => {
+ const { nodeId, width, children, selected } = props;
+
+ const selectIsInProgress = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) =>
+ nodes.nodeExecutionStates[nodeId]?.status === NodeStatus.IN_PROGRESS
+ ),
+ [nodeId]
+ );
+
+ const isInProgress = useAppSelector(selectIsInProgress);
+
+ const [
+ nodeSelectedLight,
+ nodeSelectedDark,
+ nodeInProgressLight,
+ nodeInProgressDark,
+ shadowsXl,
+ shadowsBase,
+ ] = useToken('shadows', [
+ 'nodeSelected.light',
+ 'nodeSelected.dark',
+ 'nodeInProgress.light',
+ 'nodeInProgress.dark',
+ 'shadows.xl',
+ 'shadows.base',
+ ]);
+
+ const dispatch = useAppDispatch();
+
+ const selectedShadow = useColorModeValue(nodeSelectedLight, nodeSelectedDark);
+ const inProgressShadow = useColorModeValue(
+ nodeInProgressLight,
+ nodeInProgressDark
+ );
+
+ const opacity = useAppSelector((state) => state.nodes.nodeOpacity);
+
+ const handleClick = useCallback(() => {
+ dispatch(contextMenusClosed());
+ }, [dispatch]);
+
+ return (
+
+
+
+ {children}
+
+ );
+};
+
+export default memo(NodeWrapper);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx
new file mode 100644
index 0000000000..c59557f1a0
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/BottomLeftPanel.tsx
@@ -0,0 +1,13 @@
+import { Flex } from '@chakra-ui/react';
+import { memo } from 'react';
+import NodeOpacitySlider from './NodeOpacitySlider';
+import ViewportControls from './ViewportControls';
+
+const BottomLeftPanel = () => (
+
+
+
+
+);
+
+export default memo(BottomLeftPanel);
diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeOpacitySlider.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/NodeOpacitySlider.tsx
similarity index 84%
rename from invokeai/frontend/web/src/features/nodes/components/NodeOpacitySlider.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/NodeOpacitySlider.tsx
index 693940859f..7818dece72 100644
--- a/invokeai/frontend/web/src/features/nodes/components/NodeOpacitySlider.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/NodeOpacitySlider.tsx
@@ -1,13 +1,13 @@
import {
- Box,
+ Flex,
Slider,
SliderFilledTrack,
SliderThumb,
SliderTrack,
} from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { nodeOpacityChanged } from 'features/nodes/store/nodesSlice';
import { useCallback } from 'react';
-import { nodeOpacityChanged } from '../store/nodesSlice';
export default function NodeOpacitySlider() {
const dispatch = useAppDispatch();
@@ -21,7 +21,7 @@ export default function NodeOpacitySlider() {
);
return (
-
+
-
+
);
}
diff --git a/invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx
similarity index 53%
rename from invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx
index 7416c6c555..15d8d58d7b 100644
--- a/invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/ViewportControls.tsx
@@ -1,28 +1,27 @@
-import { ButtonGroup, Tooltip } from '@chakra-ui/react';
+import { ButtonGroup } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
+import {
+ // shouldShowFieldTypeLegendChanged,
+ shouldShowMinimapPanelChanged,
+} from 'features/nodes/store/nodesSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import {
FaExpand,
- FaInfo,
+ // FaInfo,
FaMapMarkerAlt,
- FaMinus,
- FaPlus,
} from 'react-icons/fa';
+import { FaMagnifyingGlassMinus, FaMagnifyingGlassPlus } from 'react-icons/fa6';
import { useReactFlow } from 'reactflow';
-import {
- shouldShowFieldTypeLegendChanged,
- shouldShowMinimapPanelChanged,
-} from '../store/nodesSlice';
const ViewportControls = () => {
const { t } = useTranslation();
const { zoomIn, zoomOut, fitView } = useReactFlow();
const dispatch = useAppDispatch();
- const shouldShowFieldTypeLegend = useAppSelector(
- (state) => state.nodes.shouldShowFieldTypeLegend
- );
+ // const shouldShowFieldTypeLegend = useAppSelector(
+ // (state) => state.nodes.shouldShowFieldTypeLegend
+ // );
const shouldShowMinimapPanel = useAppSelector(
(state) => state.nodes.shouldShowMinimapPanel
);
@@ -39,9 +38,9 @@ const ViewportControls = () => {
fitView();
}, [fitView]);
- const handleClickedToggleFieldTypeLegend = useCallback(() => {
- dispatch(shouldShowFieldTypeLegendChanged(!shouldShowFieldTypeLegend));
- }, [shouldShowFieldTypeLegend, dispatch]);
+ // const handleClickedToggleFieldTypeLegend = useCallback(() => {
+ // dispatch(shouldShowFieldTypeLegendChanged(!shouldShowFieldTypeLegend));
+ // }, [shouldShowFieldTypeLegend, dispatch]);
const handleClickedToggleMiniMapPanel = useCallback(() => {
dispatch(shouldShowMinimapPanelChanged(!shouldShowMinimapPanel));
@@ -49,28 +48,25 @@ const ViewportControls = () => {
return (
-
- }
- />
-
-
- }
- />
-
-
- }
- />
-
- }
+ />
+ }
+ />
+ }
+ />
+ {/* {
onClick={handleClickedToggleFieldTypeLegend}
icon={}
/>
-
- */}
+
- }
- />
-
+ aria-label={
+ shouldShowMinimapPanel
+ ? t('nodes.hideMinimapnodes')
+ : t('nodes.showMinimapnodes')
+ }
+ isChecked={shouldShowMinimapPanel}
+ onClick={handleClickedToggleMiniMapPanel}
+ icon={}
+ />
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/editorPanels/MinimapPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx
similarity index 60%
rename from invokeai/frontend/web/src/features/nodes/components/editorPanels/MinimapPanel.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx
index 8b7fb942a6..9d7289c273 100644
--- a/invokeai/frontend/web/src/features/nodes/components/editorPanels/MinimapPanel.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/MinimapPanel/MinimapPanel.tsx
@@ -1,19 +1,12 @@
+import { Flex, chakra, useColorModeValue } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
-import { useColorModeValue } from '@chakra-ui/react';
import { memo } from 'react';
import { MiniMap } from 'reactflow';
-const MinimapPanel = () => {
- const miniMapStyle = useColorModeValue(
- {
- background: 'var(--invokeai-colors-base-200)',
- },
- {
- background: 'var(--invokeai-colors-base-500)',
- }
- );
+const ChakraMiniMap = chakra(MiniMap);
+const MinimapPanel = () => {
const shouldShowMinimapPanel = useAppSelector(
(state: RootState) => state.nodes.shouldShowMinimapPanel
);
@@ -29,18 +22,28 @@ const MinimapPanel = () => {
);
return (
- <>
+
{shouldShowMinimapPanel && (
-
)}
- >
+
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/LoadWorkflowButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/LoadWorkflowButton.tsx
new file mode 100644
index 0000000000..8454f5539f
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/LoadWorkflowButton.tsx
@@ -0,0 +1,30 @@
+import { FileButton } from '@mantine/core';
+import IAIIconButton from 'common/components/IAIIconButton';
+import { useLoadWorkflowFromFile } from 'features/nodes/hooks/useLoadWorkflowFromFile';
+import { memo, useRef } from 'react';
+import { useTranslation } from 'react-i18next';
+import { FaUpload } from 'react-icons/fa';
+
+const LoadWorkflowButton = () => {
+ const { t } = useTranslation();
+ const resetRef = useRef<() => void>(null);
+ const loadWorkflowFromFile = useLoadWorkflowFromFile();
+ return (
+
+ {(props) => (
+ }
+ tooltip={t('nodes.loadWorkflow')}
+ aria-label={t('nodes.loadWorkflow')}
+ {...props}
+ />
+ )}
+
+ );
+};
+
+export default memo(LoadWorkflowButton);
diff --git a/invokeai/frontend/web/src/features/nodes/components/ui/ReloadSchemaButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx
similarity index 58%
rename from invokeai/frontend/web/src/features/nodes/components/ui/ReloadSchemaButton.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx
index cbb0ea58ee..905b0b74a2 100644
--- a/invokeai/frontend/web/src/features/nodes/components/ui/ReloadSchemaButton.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton.tsx
@@ -1,11 +1,11 @@
import { useAppDispatch } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
+import IAIButton from 'common/components/IAIButton';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaSyncAlt } from 'react-icons/fa';
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
-const ReloadSchemaButton = () => {
+const ReloadNodeTemplatesButton = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
@@ -14,13 +14,15 @@ const ReloadSchemaButton = () => {
}, [dispatch]);
return (
- }
- tooltip={t('nodes.reloadSchema')}
- aria-label={t('nodes.reloadSchema')}
+ }
+ tooltip={t('nodes.reloadNodeTemplates')}
+ aria-label={t('nodes.reloadNodeTemplates')}
onClick={handleReloadSchema}
- />
+ >
+ {t('nodes.reloadNodeTemplates')}
+
);
};
-export default memo(ReloadSchemaButton);
+export default memo(ReloadNodeTemplatesButton);
diff --git a/invokeai/frontend/web/src/features/nodes/components/ui/ClearGraphButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ResetWorkflowButton.tsx
similarity index 78%
rename from invokeai/frontend/web/src/features/nodes/components/ui/ClearGraphButton.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ResetWorkflowButton.tsx
index 1501d0270b..129b7f72c9 100644
--- a/invokeai/frontend/web/src/features/nodes/components/ui/ClearGraphButton.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/ResetWorkflowButton.tsx
@@ -6,6 +6,7 @@ import {
AlertDialogHeader,
AlertDialogOverlay,
Button,
+ Flex,
Text,
useDisclosure,
} from '@chakra-ui/react';
@@ -19,7 +20,7 @@ import { memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa';
-const ClearGraphButton = () => {
+const ResetWorkflowButton = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const { isOpen, onOpen, onClose } = useDisclosure();
@@ -48,10 +49,11 @@ const ClearGraphButton = () => {
<>
}
- tooltip={t('nodes.clearGraph')}
- aria-label={t('nodes.clearGraph')}
+ tooltip={t('nodes.resetWorkflow')}
+ aria-label={t('nodes.resetWorkflow')}
onClick={onOpen}
isDisabled={!nodesCount}
+ colorScheme="error"
/>
{
- {t('nodes.clearGraph')}
+ {t('nodes.resetWorkflow')}
-
- {t('nodes.clearGraphDesc')}
+
+
+ {t('nodes.resetWorkflowDesc')}
+ {t('nodes.resetWorkflowDesc2')}
+
-
@@ -85,4 +90,4 @@ const ClearGraphButton = () => {
);
};
-export default memo(ClearGraphButton);
+export default memo(ResetWorkflowButton);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/SaveWorkflowButton.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/SaveWorkflowButton.tsx
new file mode 100644
index 0000000000..45764307a3
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/SaveWorkflowButton.tsx
@@ -0,0 +1,29 @@
+import IAIIconButton from 'common/components/IAIIconButton';
+import { useWorkflow } from 'features/nodes/hooks/useWorkflow';
+import { memo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+import { FaSave } from 'react-icons/fa';
+
+const SaveWorkflowButton = () => {
+ const { t } = useTranslation();
+ const workflow = useWorkflow();
+ const handleSave = useCallback(() => {
+ const blob = new Blob([JSON.stringify(workflow, null, 2)]);
+ const a = document.createElement('a');
+ a.href = URL.createObjectURL(blob);
+ a.download = `${workflow.name || 'My Workflow'}.json`;
+ document.body.appendChild(a);
+ a.click();
+ a.remove();
+ }, [workflow]);
+ return (
+ }
+ tooltip={t('nodes.saveWorkflow')}
+ aria-label={t('nodes.saveWorkflow')}
+ onClick={handleSave}
+ />
+ );
+};
+
+export default memo(SaveWorkflowButton);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx
new file mode 100644
index 0000000000..3a2ac7ad89
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/TopCenterPanel.tsx
@@ -0,0 +1,25 @@
+import { Flex } from '@chakra-ui/layout';
+import { memo } from 'react';
+import LoadWorkflowButton from './LoadWorkflowButton';
+import ResetWorkflowButton from './ResetWorkflowButton';
+import SaveWorkflowButton from './SaveWorkflowButton';
+
+const TopCenterPanel = () => {
+ return (
+
+
+
+
+
+ );
+};
+
+export default memo(TopCenterPanel);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/WorkflowEditorControls.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/WorkflowEditorControls.tsx
new file mode 100644
index 0000000000..3a72f52b0c
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopCenterPanel/WorkflowEditorControls.tsx
@@ -0,0 +1,15 @@
+import { Flex } from '@chakra-ui/react';
+import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton';
+import InvokeButton from 'features/parameters/components/ProcessButtons/InvokeButton';
+import { memo } from 'react';
+
+const WorkflowEditorControls = () => {
+ return (
+
+
+
+
+ );
+};
+
+export default memo(WorkflowEditorControls);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx
new file mode 100644
index 0000000000..73296ef52d
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopLeftPanel/TopLeftPanel.tsx
@@ -0,0 +1,27 @@
+import { Flex } from '@chakra-ui/layout';
+import { useAppDispatch } from 'app/store/storeHooks';
+import IAIIconButton from 'common/components/IAIIconButton';
+import { addNodePopoverOpened } from 'features/nodes/store/nodesSlice';
+import { memo, useCallback } from 'react';
+import { FaPlus } from 'react-icons/fa';
+
+const TopLeftPanel = () => {
+ const dispatch = useAppDispatch();
+
+ const handleOpenAddNodePopover = useCallback(() => {
+ dispatch(addNodePopoverOpened());
+ }, [dispatch]);
+
+ return (
+
+ }
+ onClick={handleOpenAddNodePopover}
+ />
+
+ );
+};
+
+export default memo(TopLeftPanel);
diff --git a/invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/FieldTypeLegend.tsx
similarity index 93%
rename from invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/FieldTypeLegend.tsx
index a523cc29fe..0afd6a80f7 100644
--- a/invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/FieldTypeLegend.tsx
@@ -1,8 +1,8 @@
import { Badge, Flex, Tooltip } from '@chakra-ui/react';
+import { FIELDS } from 'features/nodes/types/constants';
import { map } from 'lodash-es';
import { memo } from 'react';
import 'reactflow/dist/style.css';
-import { FIELDS } from '../types/constants';
const FieldTypeLegend = () => {
return (
diff --git a/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopRightPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx
similarity index 55%
rename from invokeai/frontend/web/src/features/nodes/components/editorPanels/TopRightPanel.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx
index 7facf3973f..db8f544c2e 100644
--- a/invokeai/frontend/web/src/features/nodes/components/editorPanels/TopRightPanel.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/TopRightPanel.tsx
@@ -1,7 +1,8 @@
+import { Flex } from '@chakra-ui/layout';
import { useAppSelector } from 'app/store/storeHooks';
import { memo } from 'react';
-import { Panel } from 'reactflow';
-import FieldTypeLegend from '../FieldTypeLegend';
+import FieldTypeLegend from './FieldTypeLegend';
+import WorkflowEditorSettings from './WorkflowEditorSettings';
const TopRightPanel = () => {
const shouldShowFieldTypeLegend = useAppSelector(
@@ -9,9 +10,10 @@ const TopRightPanel = () => {
);
return (
-
+
+
{shouldShowFieldTypeLegend && }
-
+
);
};
diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeEditorSettings.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx
similarity index 73%
rename from invokeai/frontend/web/src/features/nodes/components/NodeEditorSettings.tsx
rename to invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx
index b942b2b3c0..c423750cd8 100644
--- a/invokeai/frontend/web/src/features/nodes/components/NodeEditorSettings.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx
@@ -1,6 +1,7 @@
import {
Divider,
Flex,
+ FormLabelProps,
Heading,
Modal,
ModalBody,
@@ -8,22 +9,30 @@ import {
ModalContent,
ModalHeader,
ModalOverlay,
+ forwardRef,
useDisclosure,
} from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIIconButton from 'common/components/IAIIconButton';
import IAISwitch from 'common/components/IAISwitch';
-import { ChangeEvent, memo, useCallback } from 'react';
-import { FaCog } from 'react-icons/fa';
import {
+ selectionModeChanged,
shouldAnimateEdgesChanged,
shouldColorEdgesChanged,
shouldSnapToGridChanged,
shouldValidateGraphChanged,
-} from '../store/nodesSlice';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+} from 'features/nodes/store/nodesSlice';
+import { ChangeEvent, memo, useCallback } from 'react';
+import { FaCog } from 'react-icons/fa';
+import { SelectionMode } from 'reactflow';
+import ReloadNodeTemplatesButton from '../TopCenterPanel/ReloadSchemaButton';
+
+const formLabelProps: FormLabelProps = {
+ fontWeight: 600,
+};
const selector = createSelector(
stateSelector,
@@ -33,18 +42,20 @@ const selector = createSelector(
shouldValidateGraph,
shouldSnapToGrid,
shouldColorEdges,
+ selectionMode,
} = nodes;
return {
shouldAnimateEdges,
shouldValidateGraph,
shouldSnapToGrid,
shouldColorEdges,
+ selectionModeIsChecked: selectionMode === SelectionMode.Full,
};
},
defaultSelectorOptions
);
-const NodeEditorSettings = () => {
+const WorkflowEditorSettings = forwardRef((_, ref) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const dispatch = useAppDispatch();
const {
@@ -52,6 +63,7 @@ const NodeEditorSettings = () => {
shouldValidateGraph,
shouldSnapToGrid,
shouldColorEdges,
+ selectionModeIsChecked,
} = useAppSelector(selector);
const handleChangeShouldValidate = useCallback(
@@ -82,10 +94,19 @@ const NodeEditorSettings = () => {
[dispatch]
);
+ const handleChangeSelectionMode = useCallback(
+ (e: ChangeEvent) => {
+ dispatch(selectionModeChanged(e.target.checked));
+ },
+ [dispatch]
+ );
+
return (
<>
}
onClick={onOpen}
/>
@@ -93,7 +114,7 @@ const NodeEditorSettings = () => {
- Node Editor Settings
+ Workflow Editor Settings
{
>
General
{
/>
{
/>
+
Advanced
+
>
);
-};
+});
-export default memo(NodeEditorSettings);
+export default memo(WorkflowEditorSettings);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/NodeEditorPanelGroup.tsx b/invokeai/frontend/web/src/features/nodes/components/panel/NodeEditorPanelGroup.tsx
deleted file mode 100644
index 269108e87a..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/panel/NodeEditorPanelGroup.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import InspectorPanel from 'features/nodes/components/panel/InspectorPanel';
-import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
-import { memo, useState } from 'react';
-import { Panel, PanelGroup } from 'react-resizable-panels';
-import 'reactflow/dist/style.css';
-import WorkflowPanel from './WorkflowPanel';
-
-const NodeEditorPanelGroup = () => {
- const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false);
- const [isBottomPanelCollapsed, setIsBottomPanelCollapsed] = useState(false);
-
- return (
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default memo(NodeEditorPanelGroup);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/WorkflowTab.tsx b/invokeai/frontend/web/src/features/nodes/components/panel/workflow/WorkflowTab.tsx
deleted file mode 100644
index c9400ab5f6..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/WorkflowTab.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import { RootState } from 'app/store/store';
-import { useAppSelector } from 'app/store/storeHooks';
-import ImageMetadataJSON from 'features/gallery/components/ImageMetadataViewer/ImageMetadataJSON';
-import { buildWorkflow } from 'features/nodes/util/buildWorkflow';
-import { memo, useMemo } from 'react';
-import { useDebounce } from 'use-debounce';
-
-const useWatchWorkflow = () => {
- const nodes = useAppSelector((state: RootState) => state.nodes);
- const [debouncedNodes] = useDebounce(nodes, 300);
- const workflow = useMemo(
- () => buildWorkflow(debouncedNodes),
- [debouncedNodes]
- );
-
- return {
- workflow,
- };
-};
-
-const WorkflowWorkflowTab = () => {
- const { workflow } = useWatchWorkflow();
-
- return (
-
-
-
- );
-};
-
-export default memo(WorkflowWorkflowTab);
diff --git a/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx b/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx
deleted file mode 100644
index 1b9dc38cb6..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx
+++ /dev/null
@@ -1,208 +0,0 @@
-import { Box, Flex } from '@chakra-ui/layout';
-import { Tooltip } from '@chakra-ui/tooltip';
-import { useAppToaster } from 'app/components/Toaster';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIInput from 'common/components/IAIInput';
-import { useBuildNodeData } from 'features/nodes/hooks/useBuildNodeData';
-import { InvocationTemplate } from 'features/nodes/types/types';
-import Fuse from 'fuse.js';
-import { map } from 'lodash-es';
-import {
- ChangeEvent,
- FocusEvent,
- KeyboardEvent,
- ReactNode,
- memo,
- useCallback,
- useRef,
- useState,
-} from 'react';
-import { AnyInvocationType } from 'services/events/types';
-import { nodeAdded } from '../../store/nodesSlice';
-
-interface NodeListItemProps {
- title: string;
- description: string;
- type: AnyInvocationType;
- isSelected: boolean;
- addNode: (nodeType: AnyInvocationType) => void;
-}
-
-const NodeListItem = (props: NodeListItemProps) => {
- const { title, description, type, isSelected, addNode } = props;
- return (
-
- addNode(type)}
- background={isSelected ? 'base.600' : 'none'}
- _hover={{
- background: 'base.600',
- cursor: 'pointer',
- }}
- >
- {title}
-
-
- );
-};
-
-NodeListItem.displayName = 'NodeListItem';
-
-const NodeSearch = () => {
- const nodeTemplates = useAppSelector((state) =>
- map(state.nodes.nodeTemplates)
- );
-
- const [filteredNodes, setFilteredNodes] = useState<
- Fuse.FuseResult[]
- >([]);
-
- const buildInvocation = useBuildNodeData();
- const dispatch = useAppDispatch();
- const toaster = useAppToaster();
-
- const [searchText, setSearchText] = useState('');
- const [showNodeList, setShowNodeList] = useState(false);
- const [focusedIndex, setFocusedIndex] = useState(-1);
- const nodeSearchRef = useRef(null);
-
- const fuseOptions = {
- findAllMatches: true,
- threshold: 0,
- ignoreLocation: true,
- keys: ['title', 'type', 'tags'],
- };
-
- const fuse = new Fuse(nodeTemplates, fuseOptions);
-
- const findNode = (e: ChangeEvent) => {
- setSearchText(e.target.value);
- setFilteredNodes(fuse.search(e.target.value));
- setShowNodeList(true);
- };
-
- const addNode = useCallback(
- (nodeType: AnyInvocationType) => {
- const invocation = buildInvocation(nodeType);
-
- if (!invocation) {
- toaster({
- status: 'error',
- title: `Unknown Invocation type ${nodeType}`,
- });
- return;
- }
-
- dispatch(nodeAdded(invocation));
- },
- [dispatch, buildInvocation, toaster]
- );
-
- const renderNodeList = () => {
- const nodeListToRender: ReactNode[] = [];
-
- if (searchText.length > 0) {
- filteredNodes.forEach(({ item }, index) => {
- const { title, description, type } = item;
- if (title.toLowerCase().includes(searchText)) {
- nodeListToRender.push(
-
- );
- }
- });
- } else {
- nodeTemplates.forEach(({ title, description, type }, index) => {
- nodeListToRender.push(
-
- );
- });
- }
-
- return (
-
- {nodeListToRender}
-
- );
- };
-
- const searchKeyHandler = (e: KeyboardEvent) => {
- const { key } = e;
- let nextIndex = 0;
-
- if (key === 'ArrowDown') {
- setShowNodeList(true);
- if (searchText.length > 0) {
- nextIndex = (focusedIndex + 1) % filteredNodes.length;
- } else {
- nextIndex = (focusedIndex + 1) % nodeTemplates.length;
- }
- }
-
- if (key === 'ArrowUp') {
- setShowNodeList(true);
- if (searchText.length > 0) {
- nextIndex =
- (focusedIndex + filteredNodes.length - 1) % filteredNodes.length;
- } else {
- nextIndex =
- (focusedIndex + nodeTemplates.length - 1) % nodeTemplates.length;
- }
- }
-
- // # TODO Handle Blur
- // if (key === 'Escape') {
- // }
-
- if (key === 'Enter') {
- let selectedNodeType: AnyInvocationType | undefined;
-
- if (searchText.length > 0) {
- selectedNodeType = filteredNodes[focusedIndex]?.item.type;
- } else {
- selectedNodeType = nodeTemplates[focusedIndex]?.type;
- }
-
- if (selectedNodeType) {
- addNode(selectedNodeType);
- }
- setShowNodeList(false);
- }
-
- setFocusedIndex(nextIndex);
- };
-
- const searchInputBlurHandler = (e: FocusEvent) => {
- if (!e.currentTarget.contains(e.relatedTarget)) setShowNodeList(false);
- };
-
- return (
- setShowNodeList(true)}
- onBlur={searchInputBlurHandler}
- ref={nodeSearchRef}
- >
-
- {showNodeList && renderNodeList()}
-
- );
-};
-
-export default memo(NodeSearch);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx
new file mode 100644
index 0000000000..f40d5ddd80
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/NodeEditorPanelGroup.tsx
@@ -0,0 +1,69 @@
+import { Flex } from '@chakra-ui/react';
+import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
+import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
+import { usePanelStorage } from 'features/ui/hooks/usePanelStorage';
+import { memo, useCallback, useRef, useState } from 'react';
+import {
+ ImperativePanelGroupHandle,
+ Panel,
+ PanelGroup,
+} from 'react-resizable-panels';
+import 'reactflow/dist/style.css';
+import InspectorPanel from './inspector/InspectorPanel';
+import WorkflowPanel from './workflow/WorkflowPanel';
+
+const NodeEditorPanelGroup = () => {
+ const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false);
+ const [isBottomPanelCollapsed, setIsBottomPanelCollapsed] = useState(false);
+ const panelGroupRef = useRef(null);
+ const panelStorage = usePanelStorage();
+ const handleDoubleClickHandle = useCallback(() => {
+ if (!panelGroupRef.current) {
+ return;
+ }
+ panelGroupRef.current.setLayout([50, 50]);
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default memo(NodeEditorPanelGroup);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/ScrollableContent.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/ScrollableContent.tsx
similarity index 91%
rename from invokeai/frontend/web/src/features/nodes/components/panel/ScrollableContent.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/ScrollableContent.tsx
index 3b8cf5d520..7e3f4aa249 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/ScrollableContent.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/ScrollableContent.tsx
@@ -1,6 +1,6 @@
import { Box, Flex } from '@chakra-ui/react';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
-import { PropsWithChildren } from 'react';
+import { PropsWithChildren, memo } from 'react';
const ScrollableContent = (props: PropsWithChildren) => {
return (
@@ -42,4 +42,4 @@ const ScrollableContent = (props: PropsWithChildren) => {
);
};
-export default ScrollableContent;
+export default memo(ScrollableContent);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/NodeDataInspector.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorDataTab.tsx
similarity index 77%
rename from invokeai/frontend/web/src/features/nodes/components/panel/NodeDataInspector.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorDataTab.tsx
index 084f743d19..a97834f138 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/NodeDataInspector.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorDataTab.tsx
@@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
-import ImageMetadataJSON from 'features/gallery/components/ImageMetadataViewer/ImageMetadataJSON';
+import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
import { memo } from 'react';
const selector = createSelector(
@@ -23,14 +23,14 @@ const selector = createSelector(
defaultSelectorOptions
);
-const NodeDataInspector = () => {
+const InspectorDataTab = () => {
const { data } = useAppSelector(selector);
if (!data) {
return ;
}
- return ;
+ return ;
};
-export default memo(NodeDataInspector);
+export default memo(InspectorDataTab);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorOutputsTab.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorOutputsTab.tsx
new file mode 100644
index 0000000000..43148a653d
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorOutputsTab.tsx
@@ -0,0 +1,101 @@
+import { Box, Flex } from '@chakra-ui/react';
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { IAINoContentFallback } from 'common/components/IAIImageFallback';
+import { memo } from 'react';
+import ImageOutputPreview from './outputs/ImageOutputPreview';
+import ScrollableContent from '../ScrollableContent';
+import { AnyResult } from 'services/events/types';
+import StringOutputPreview from './outputs/StringOutputPreview';
+import NumberOutputPreview from './outputs/NumberOutputPreview';
+
+const selector = createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const lastSelectedNodeId =
+ nodes.selectedNodes[nodes.selectedNodes.length - 1];
+
+ const lastSelectedNode = nodes.nodes.find(
+ (node) => node.id === lastSelectedNodeId
+ );
+
+ const nes =
+ nodes.nodeExecutionStates[lastSelectedNodeId ?? '__UNKNOWN_NODE__'];
+
+ return {
+ node: lastSelectedNode,
+ nes,
+ };
+ },
+ defaultSelectorOptions
+);
+
+const InspectorOutputsTab = () => {
+ const { node, nes } = useAppSelector(selector);
+
+ if (!node || !nes) {
+ return ;
+ }
+
+ if (nes.outputs.length === 0) {
+ return ;
+ }
+
+ return (
+
+
+
+ {nes.outputs.map((result, i) => {
+ if (result.type === 'string_output') {
+ return (
+
+ );
+ }
+ if (result.type === 'float_output') {
+ return (
+
+ );
+ }
+ if (result.type === 'integer_output') {
+ return (
+
+ );
+ }
+ if (result.type === 'image_output') {
+ return (
+
+ );
+ }
+ return (
+
+ {JSON.stringify(result, null, 2)}
+
+ );
+ })}
+
+
+
+ );
+};
+
+export default memo(InspectorOutputsTab);
+
+const getKey = (result: AnyResult, i: number) => `${result.type}-${i}`;
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/InspectorPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx
similarity index 58%
rename from invokeai/frontend/web/src/features/nodes/components/panel/InspectorPanel.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx
index 587bea19ec..22f3ad6bb5 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/InspectorPanel.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorPanel.tsx
@@ -7,18 +7,21 @@ import {
Tabs,
} from '@chakra-ui/react';
import { memo } from 'react';
-import NodeDataInspector from './NodeDataInspector';
-import NodeTemplateInspector from './NodeTemplateInspector';
+import InspectorDataTab from './InspectorDataTab';
+import InspectorOutputsTab from './InspectorOutputsTab';
+import InspectorTemplateTab from './InspectorTemplateTab';
const InspectorPanel = () => {
return (
{
sx={{ display: 'flex', flexDir: 'column', w: 'full', h: 'full' }}
>
- Node Template
- Node Data
+ Outputs
+ Data
+ Template
-
+
-
+
+
+
+
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/NodeTemplateInspector.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorTemplateTab.tsx
similarity index 85%
rename from invokeai/frontend/web/src/features/nodes/components/panel/NodeTemplateInspector.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorTemplateTab.tsx
index b483158b36..525b58b1cb 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/NodeTemplateInspector.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/InspectorTemplateTab.tsx
@@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
-import ImageMetadataJSON from 'features/gallery/components/ImageMetadataViewer/ImageMetadataJSON';
+import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
import { memo } from 'react';
const selector = createSelector(
@@ -34,7 +34,7 @@ const NodeTemplateInspector = () => {
return ;
}
- return ;
+ return ;
};
export default memo(NodeTemplateInspector);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/ImageOutputPreview.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/ImageOutputPreview.tsx
new file mode 100644
index 0000000000..4d89fcbc69
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/ImageOutputPreview.tsx
@@ -0,0 +1,17 @@
+import IAIDndImage from 'common/components/IAIDndImage';
+import { memo } from 'react';
+import { useGetImageDTOQuery } from 'services/api/endpoints/images';
+import { ImageOutput } from 'services/api/types';
+
+type Props = {
+ output: ImageOutput;
+};
+
+const ImageOutputPreview = ({ output }: Props) => {
+ const { image } = output;
+ const { data: imageDTO } = useGetImageDTOQuery(image.image_name);
+
+ return ;
+};
+
+export default memo(ImageOutputPreview);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/NumberOutputPreview.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/NumberOutputPreview.tsx
new file mode 100644
index 0000000000..ebe03740b3
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/NumberOutputPreview.tsx
@@ -0,0 +1,13 @@
+import { Text } from '@chakra-ui/react';
+import { memo } from 'react';
+import { FloatOutput, IntegerOutput } from 'services/api/types';
+
+type Props = {
+ output: IntegerOutput | FloatOutput;
+};
+
+const NumberOutputPreview = ({ output }: Props) => {
+ return {output.value};
+};
+
+export default memo(NumberOutputPreview);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/StringOutputPreview.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/StringOutputPreview.tsx
new file mode 100644
index 0000000000..1dce0530dd
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/inspector/outputs/StringOutputPreview.tsx
@@ -0,0 +1,13 @@
+import { Text } from '@chakra-ui/react';
+import { memo } from 'react';
+import { StringOutput } from 'services/api/types';
+
+type Props = {
+ output: StringOutput;
+};
+
+const StringOutputPreview = ({ output }: Props) => {
+ return {output.value};
+};
+
+export default memo(StringOutputPreview);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/GeneralTab.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowGeneralTab.tsx
similarity index 98%
rename from invokeai/frontend/web/src/features/nodes/components/panel/workflow/GeneralTab.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowGeneralTab.tsx
index 8dab91c0d5..e36675b71f 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/GeneralTab.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowGeneralTab.tsx
@@ -36,7 +36,7 @@ const selector = createSelector(
defaultSelectorOptions
);
-const WorkflowPanel = () => {
+const WorkflowGeneralTab = () => {
const { author, name, description, tags, version, contact, notes } =
useAppSelector(selector);
const dispatch = useAppDispatch();
@@ -139,4 +139,4 @@ const WorkflowPanel = () => {
);
};
-export default memo(WorkflowPanel);
+export default memo(WorkflowGeneralTab);
diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx
new file mode 100644
index 0000000000..aa3b1ad1be
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowJSONTab.tsx
@@ -0,0 +1,23 @@
+import { Flex } from '@chakra-ui/react';
+import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
+import { useWorkflow } from 'features/nodes/hooks/useWorkflow';
+import { memo } from 'react';
+
+const WorkflowJSONTab = () => {
+ const workflow = useWorkflow();
+
+ return (
+
+
+
+ );
+};
+
+export default memo(WorkflowJSONTab);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/LinearTab.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowLinearTab.tsx
similarity index 73%
rename from invokeai/frontend/web/src/features/nodes/components/panel/workflow/LinearTab.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowLinearTab.tsx
index cc7428a8ec..d1cecefbff 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/LinearTab.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowLinearTab.tsx
@@ -3,11 +3,9 @@ import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-import IAIDroppable from 'common/components/IAIDroppable';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
-import { AddFieldToLinearViewDropData } from 'features/dnd/types';
import { memo } from 'react';
-import LinearViewField from '../../fields/LinearViewField';
+import LinearViewField from '../../flow/nodes/Invocation/fields/LinearViewField';
import ScrollableContent from '../ScrollableContent';
const selector = createSelector(
@@ -20,12 +18,7 @@ const selector = createSelector(
defaultSelectorOptions
);
-const droppableData: AddFieldToLinearViewDropData = {
- id: 'add-field-to-linear-view',
- actionType: 'ADD_FIELD_TO_LINEAR',
-};
-
-const LinearTabContent = () => {
+const WorkflowLinearTab = () => {
const { fields } = useAppSelector(selector);
return (
@@ -42,6 +35,7 @@ const LinearTabContent = () => {
position: 'relative',
flexDir: 'column',
alignItems: 'flex-start',
+ p: 1,
gap: 2,
h: 'full',
w: 'full',
@@ -50,7 +44,7 @@ const LinearTabContent = () => {
{fields.length ? (
fields.map(({ nodeId, fieldName }) => (
@@ -63,9 +57,8 @@ const LinearTabContent = () => {
)}
-
);
};
-export default memo(LinearTabContent);
+export default memo(WorkflowLinearTab);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/NotesTab.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowNotesTab.tsx
similarity index 94%
rename from invokeai/frontend/web/src/features/nodes/components/panel/workflow/NotesTab.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowNotesTab.tsx
index d8b19c1645..d1ea0bcea1 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/workflow/NotesTab.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowNotesTab.tsx
@@ -14,7 +14,7 @@ const selector = createSelector(stateSelector, ({ nodes }) => {
};
});
-const WorkflowPanel = () => {
+const WorkflowNotesTab = () => {
const { notes } = useAppSelector(selector);
const dispatch = useAppDispatch();
@@ -48,4 +48,4 @@ const WorkflowPanel = () => {
);
};
-export default memo(WorkflowPanel);
+export default memo(WorkflowNotesTab);
diff --git a/invokeai/frontend/web/src/features/nodes/components/panel/WorkflowPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx
similarity index 73%
rename from invokeai/frontend/web/src/features/nodes/components/panel/WorkflowPanel.tsx
rename to invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx
index 052cf15ad7..4cf7b2e431 100644
--- a/invokeai/frontend/web/src/features/nodes/components/panel/WorkflowPanel.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowPanel.tsx
@@ -7,9 +7,9 @@ import {
Tabs,
} from '@chakra-ui/react';
import { memo } from 'react';
-import GeneralTab from './workflow/GeneralTab';
-import LinearTab from './workflow/LinearTab';
-import WorkflowTab from './workflow/WorkflowTab';
+import WorkflowGeneralTab from './WorkflowGeneralTab';
+import WorkflowJSONTab from './WorkflowJSONTab';
+import WorkflowLinearTab from './WorkflowLinearTab';
const WorkflowPanel = () => {
return (
@@ -20,7 +20,8 @@ const WorkflowPanel = () => {
w: 'full',
h: 'full',
borderRadius: 'base',
- p: 4,
+ p: 2,
+ gap: 2,
}}
>
{
-
+
-
+
-
+
diff --git a/invokeai/frontend/web/src/features/nodes/components/ui/NodeInvokeButton.tsx b/invokeai/frontend/web/src/features/nodes/components/ui/NodeInvokeButton.tsx
deleted file mode 100644
index f207e910b1..0000000000
--- a/invokeai/frontend/web/src/features/nodes/components/ui/NodeInvokeButton.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { Box } from '@chakra-ui/react';
-import { userInvoked } from 'app/store/actions';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIButton, { IAIButtonProps } from 'common/components/IAIButton';
-import IAIIconButton, {
- IAIIconButtonProps,
-} from 'common/components/IAIIconButton';
-import { selectIsReadyNodes } from 'features/nodes/store/selectors';
-import ProgressBar from 'features/system/components/ProgressBar';
-import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
-import { memo, useCallback } from 'react';
-import { useHotkeys } from 'react-hotkeys-hook';
-import { useTranslation } from 'react-i18next';
-import { FaPlay } from 'react-icons/fa';
-
-interface InvokeButton
- extends Omit {
- iconButton?: boolean;
-}
-
-const NodeInvokeButton = (props: InvokeButton) => {
- const { iconButton = false, ...rest } = props;
- const dispatch = useAppDispatch();
- const activeTabName = useAppSelector(activeTabNameSelector);
- const isReady = useAppSelector(selectIsReadyNodes);
- const handleInvoke = useCallback(() => {
- dispatch(userInvoked('nodes'));
- }, [dispatch]);
-
- const { t } = useTranslation();
-
- useHotkeys(
- ['ctrl+enter', 'meta+enter'],
- handleInvoke,
- {
- enabled: () => isReady,
- preventDefault: true,
- enableOnFormTags: ['input', 'textarea', 'select'],
- },
- [isReady, activeTabName]
- );
-
- return (
-
-
- {!isReady && (
-
-
-
- )}
- {iconButton ? (
- }
- isDisabled={!isReady}
- onClick={handleInvoke}
- flexGrow={1}
- w="100%"
- tooltip={t('parameters.invoke')}
- tooltipProps={{ placement: 'bottom' }}
- colorScheme="accent"
- id="invoke-button"
- {...rest}
- />
- ) : (
-
- Invoke
-
- )}
-
-
- );
-};
-
-export default memo(NodeInvokeButton);
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts
new file mode 100644
index 0000000000..21f19295d0
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts
@@ -0,0 +1,36 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { map } from 'lodash-es';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useAnyOrDirectInputFieldNames = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return [];
+ }
+ const nodeTemplate = nodes.nodeTemplates[node.data.type];
+ if (!nodeTemplate) {
+ return [];
+ }
+ return map(nodeTemplate.inputs)
+ .filter((field) => ['any', 'direct'].includes(field.input))
+ .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0))
+ .map((field) => field.name)
+ .filter((fieldName) => fieldName !== 'is_intermediate');
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const fieldNames = useAppSelector(selector);
+ return fieldNames;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useBuildNodeData.ts b/invokeai/frontend/web/src/features/nodes/hooks/useBuildNodeData.ts
index e38c20c05a..43025720bd 100644
--- a/invokeai/frontend/web/src/features/nodes/hooks/useBuildNodeData.ts
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useBuildNodeData.ts
@@ -14,7 +14,7 @@ import {
OutputFieldValue,
} from '../types/types';
import { buildInputFieldValue } from '../util/fieldValueBuilders';
-import { DRAG_HANDLE_CLASSNAME } from '../types/constants';
+import { DRAG_HANDLE_CLASSNAME, NODE_WIDTH } from '../types/constants';
const templatesSelector = createSelector(
[(state: RootState) => state.nodes],
@@ -34,10 +34,24 @@ export const useBuildNodeData = () => {
(type: AnyInvocationType | 'current_image' | 'notes') => {
const nodeId = uuidv4();
+ let _x = window.innerWidth / 2;
+ let _y = window.innerHeight / 2;
+
+ // attempt to center the node in the middle of the flow
+ const rect = document
+ .querySelector('#workflow-editor')
+ ?.getBoundingClientRect();
+
+ if (rect) {
+ _x = rect.width / 2 - NODE_WIDTH / 2;
+ _y = rect.height / 2 - NODE_WIDTH / 2;
+ }
+
const { x, y } = flow.project({
- x: window.innerWidth / 2.5,
- y: window.innerHeight / 8,
+ x: _x,
+ y: _y,
});
+
if (type === 'current_image') {
const node: Node = {
...SHARED_NODE_PROPERTIES,
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts
new file mode 100644
index 0000000000..b7eef02e9d
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts
@@ -0,0 +1,36 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { map } from 'lodash-es';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useConnectionInputFieldNames = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return [];
+ }
+ const nodeTemplate = nodes.nodeTemplates[node.data.type];
+ if (!nodeTemplate) {
+ return [];
+ }
+ return map(nodeTemplate.inputs)
+ .filter((field) => field.input === 'connection')
+ .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0))
+ .map((field) => field.name)
+ .filter((fieldName) => fieldName !== 'is_intermediate');
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const fieldNames = useAppSelector(selector);
+ return fieldNames;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionState.ts b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionState.ts
index e2154f7391..96b2d652e9 100644
--- a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionState.ts
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionState.ts
@@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeIsConnectionValidSelector';
import { useMemo } from 'react';
-import { useFieldType } from './useNodeData';
+import { useFieldType } from './useFieldType.ts';
const selectIsConnectionInProgress = createSelector(
stateSelector,
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useDoesInputHaveValue.ts b/invokeai/frontend/web/src/features/nodes/hooks/useDoesInputHaveValue.ts
new file mode 100644
index 0000000000..f56099ed2b
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useDoesInputHaveValue.ts
@@ -0,0 +1,28 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useDoesInputHaveValue = (nodeId: string, fieldName: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ return Boolean(node?.data.inputs[fieldName]?.value);
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, nodeId]
+ );
+
+ const doesFieldHaveValue = useAppSelector(selector);
+
+ return doesFieldHaveValue;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldData.ts b/invokeai/frontend/web/src/features/nodes/hooks/useFieldData.ts
new file mode 100644
index 0000000000..ba2c4e2d5c
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useFieldData.ts
@@ -0,0 +1,28 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useFieldData = (nodeId: string, fieldName: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ return node?.data.inputs[fieldName];
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, nodeId]
+ );
+
+ const fieldData = useAppSelector(selector);
+
+ return fieldData;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldInputKind.ts b/invokeai/frontend/web/src/features/nodes/hooks/useFieldInputKind.ts
new file mode 100644
index 0000000000..159815a6a6
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useFieldInputKind.ts
@@ -0,0 +1,30 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useFieldInputKind = (nodeId: string, fieldName: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
+ const fieldTemplate = nodeTemplate?.inputs[fieldName];
+ return fieldTemplate?.input;
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, nodeId]
+ );
+
+ const inputKind = useAppSelector(selector);
+
+ return inputKind;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldLabel.ts b/invokeai/frontend/web/src/features/nodes/hooks/useFieldLabel.ts
new file mode 100644
index 0000000000..fcf33c3427
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useFieldLabel.ts
@@ -0,0 +1,28 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useFieldLabel = (nodeId: string, fieldName: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ return node?.data.inputs[fieldName]?.label;
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, nodeId]
+ );
+
+ const label = useAppSelector(selector);
+
+ return label;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldTemplate.ts b/invokeai/frontend/web/src/features/nodes/hooks/useFieldTemplate.ts
new file mode 100644
index 0000000000..93d545aaea
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useFieldTemplate.ts
@@ -0,0 +1,34 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { KIND_MAP } from '../types/constants';
+import { isInvocationNode } from '../types/types';
+
+export const useFieldTemplate = (
+ nodeId: string,
+ fieldName: string,
+ kind: 'input' | 'output'
+) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
+ return nodeTemplate?.[KIND_MAP[kind]][fieldName];
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, kind, nodeId]
+ );
+
+ const fieldTemplate = useAppSelector(selector);
+
+ return fieldTemplate;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldTemplateTitle.ts b/invokeai/frontend/web/src/features/nodes/hooks/useFieldTemplateTitle.ts
new file mode 100644
index 0000000000..923c25cc18
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useFieldTemplateTitle.ts
@@ -0,0 +1,34 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+import { KIND_MAP } from '../types/constants';
+
+export const useFieldTemplateTitle = (
+ nodeId: string,
+ fieldName: string,
+ kind: 'input' | 'output'
+) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
+ return nodeTemplate?.[KIND_MAP[kind]][fieldName]?.title;
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, kind, nodeId]
+ );
+
+ const fieldTemplate = useAppSelector(selector);
+
+ return fieldTemplate;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useFieldType.ts.ts b/invokeai/frontend/web/src/features/nodes/hooks/useFieldType.ts.ts
new file mode 100644
index 0000000000..f4d78f8954
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useFieldType.ts.ts
@@ -0,0 +1,33 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { KIND_MAP } from '../types/constants';
+import { isInvocationNode } from '../types/types';
+
+export const useFieldType = (
+ nodeId: string,
+ fieldName: string,
+ kind: 'input' | 'output'
+) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return;
+ }
+ return node?.data[KIND_MAP[kind]][fieldName]?.type;
+ },
+ defaultSelectorOptions
+ ),
+ [fieldName, kind, nodeId]
+ );
+
+ const fieldType = useAppSelector(selector);
+
+ return fieldType;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useHasImageOutput.ts b/invokeai/frontend/web/src/features/nodes/hooks/useHasImageOutput.ts
new file mode 100644
index 0000000000..0976ededd1
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useHasImageOutput.ts
@@ -0,0 +1,31 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { some } from 'lodash-es';
+import { useMemo } from 'react';
+import { IMAGE_FIELDS } from '../types/constants';
+import { isInvocationNode } from '../types/types';
+
+export const useHasImageOutput = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return false;
+ }
+ return some(node.data.outputs, (output) =>
+ IMAGE_FIELDS.includes(output.type)
+ );
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const hasImageOutput = useAppSelector(selector);
+ return hasImageOutput;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useIsIntermediate.ts b/invokeai/frontend/web/src/features/nodes/hooks/useIsIntermediate.ts
new file mode 100644
index 0000000000..13b94f207c
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useIsIntermediate.ts
@@ -0,0 +1,27 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useIsIntermediate = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return false;
+ }
+ return Boolean(node.data.inputs.is_intermediate?.value);
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const is_intermediate = useAppSelector(selector);
+ return is_intermediate;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useIsMouseOverField.ts b/invokeai/frontend/web/src/features/nodes/hooks/useIsMouseOverField.ts
new file mode 100644
index 0000000000..9108cd12b6
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useIsMouseOverField.ts
@@ -0,0 +1,33 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useCallback, useMemo } from 'react';
+import { mouseOverFieldChanged } from '../store/nodesSlice';
+
+export const useIsMouseOverField = (nodeId: string, fieldName: string) => {
+ const dispatch = useAppDispatch();
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) =>
+ nodes.mouseOverField?.nodeId === nodeId &&
+ nodes.mouseOverField?.fieldName === fieldName,
+ defaultSelectorOptions
+ ),
+ [fieldName, nodeId]
+ );
+
+ const isMouseOverField = useAppSelector(selector);
+
+ const handleMouseOver = useCallback(() => {
+ dispatch(mouseOverFieldChanged({ nodeId, fieldName }));
+ }, [dispatch, fieldName, nodeId]);
+
+ const handleMouseOut = useCallback(() => {
+ dispatch(mouseOverFieldChanged(null));
+ }, [dispatch]);
+
+ return { isMouseOverField, handleMouseOver, handleMouseOut };
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useLoadWorkflowFromFile.tsx b/invokeai/frontend/web/src/features/nodes/hooks/useLoadWorkflowFromFile.tsx
new file mode 100644
index 0000000000..7e42bcea5f
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useLoadWorkflowFromFile.tsx
@@ -0,0 +1,103 @@
+import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
+import { useLogger } from 'app/logging/useLogger';
+import { useAppDispatch } from 'app/store/storeHooks';
+import { parseify } from 'common/util/serialize';
+import { workflowLoaded } from 'features/nodes/store/nodesSlice';
+import { zWorkflow } from 'features/nodes/types/types';
+import { addToast } from 'features/system/store/systemSlice';
+import { makeToast } from 'features/system/util/makeToast';
+import { memo, useCallback } from 'react';
+import { ZodError } from 'zod';
+import { fromZodError, fromZodIssue } from 'zod-validation-error';
+
+export const useLoadWorkflowFromFile = () => {
+ const dispatch = useAppDispatch();
+ const logger = useLogger('nodes');
+ const loadWorkflowFromFile = useCallback(
+ (file: File | null) => {
+ if (!file) {
+ return;
+ }
+ const reader = new FileReader();
+ reader.onload = async () => {
+ const rawJSON = reader.result;
+
+ try {
+ const parsedJSON = JSON.parse(String(rawJSON));
+ const result = zWorkflow.safeParse(parsedJSON);
+
+ if (!result.success) {
+ const message = fromZodError(result.error, {
+ prefix: 'Workflow Validation Error',
+ }).toString();
+ logger.error({ error: parseify(result.error) }, message);
+
+ dispatch(
+ addToast(
+ makeToast({
+ title: 'Unable to Validate Workflow',
+ description: (
+
+ ),
+ status: 'error',
+ duration: 5000,
+ })
+ )
+ );
+ return;
+ }
+
+ dispatch(workflowLoaded(result.data));
+
+ dispatch(
+ addToast(
+ makeToast({
+ title: 'Workflow Loaded',
+ status: 'success',
+ })
+ )
+ );
+ reader.abort();
+ } catch (error) {
+ // file reader error
+ if (error) {
+ dispatch(
+ addToast(
+ makeToast({
+ title: 'Unable to Load Workflow',
+ status: 'error',
+ })
+ )
+ );
+ }
+ }
+ };
+
+ reader.readAsText(file);
+ },
+ [dispatch, logger]
+ );
+
+ return loadWorkflowFromFile;
+};
+
+const WorkflowValidationErrorContent = memo((props: { error: ZodError }) => {
+ if (props.error.issues[0]) {
+ return (
+
+ {fromZodIssue(props.error.issues[0], { prefix: null }).toString()}
+
+ );
+ }
+ return (
+
+ {props.error.issues.map((issue, i) => (
+
+ {fromZodIssue(issue, { prefix: null }).toString()}
+
+ ))}
+
+ );
+});
+
+WorkflowValidationErrorContent.displayName = 'WorkflowValidationErrorContent';
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useNodeData.ts b/invokeai/frontend/web/src/features/nodes/hooks/useNodeData.ts
index 231c7678ef..cda8f91dfd 100644
--- a/invokeai/frontend/web/src/features/nodes/hooks/useNodeData.ts
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useNodeData.ts
@@ -2,35 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-import { map, some } from 'lodash-es';
import { useMemo } from 'react';
-import { FOOTER_FIELDS, IMAGE_FIELDS } from '../types/constants';
-import { isInvocationNode } from '../types/types';
-
-const KIND_MAP = {
- input: 'inputs' as const,
- output: 'outputs' as const,
-};
-
-export const useNodeTemplate = (nodeId: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
- return nodeTemplate;
- },
- defaultSelectorOptions
- ),
- [nodeId]
- );
-
- const nodeTemplate = useAppSelector(selector);
-
- return nodeTemplate;
-};
export const useNodeData = (nodeId: string) => {
const selector = useMemo(
@@ -50,237 +22,3 @@ export const useNodeData = (nodeId: string) => {
return nodeData;
};
-
-export const useFieldData = (nodeId: string, fieldName: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return;
- }
- return node?.data.inputs[fieldName];
- },
- defaultSelectorOptions
- ),
- [fieldName, nodeId]
- );
-
- const fieldData = useAppSelector(selector);
-
- return fieldData;
-};
-
-export const useFieldType = (
- nodeId: string,
- fieldName: string,
- kind: 'input' | 'output'
-) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return;
- }
- return node?.data[KIND_MAP[kind]][fieldName]?.type;
- },
- defaultSelectorOptions
- ),
- [fieldName, kind, nodeId]
- );
-
- const fieldType = useAppSelector(selector);
-
- return fieldType;
-};
-
-export const useFieldNames = (nodeId: string, kind: 'input' | 'output') => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return [];
- }
- return map(node.data[KIND_MAP[kind]], (field) => field.name).filter(
- (fieldName) => fieldName !== 'is_intermediate'
- );
- },
- defaultSelectorOptions
- ),
- [kind, nodeId]
- );
-
- const fieldNames = useAppSelector(selector);
- return fieldNames;
-};
-
-export const useWithFooter = (nodeId: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return false;
- }
- return some(node.data.outputs, (output) =>
- FOOTER_FIELDS.includes(output.type)
- );
- },
- defaultSelectorOptions
- ),
- [nodeId]
- );
-
- const withFooter = useAppSelector(selector);
- return withFooter;
-};
-
-export const useHasImageOutput = (nodeId: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return false;
- }
- return some(node.data.outputs, (output) =>
- IMAGE_FIELDS.includes(output.type)
- );
- },
- defaultSelectorOptions
- ),
- [nodeId]
- );
-
- const hasImageOutput = useAppSelector(selector);
- return hasImageOutput;
-};
-
-export const useIsIntermediate = (nodeId: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return false;
- }
- return Boolean(node.data.inputs.is_intermediate?.value);
- },
- defaultSelectorOptions
- ),
- [nodeId]
- );
-
- const is_intermediate = useAppSelector(selector);
- return is_intermediate;
-};
-
-export const useNodeLabel = (nodeId: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return false;
- }
-
- return node.data.label;
- },
- defaultSelectorOptions
- ),
- [nodeId]
- );
-
- const label = useAppSelector(selector);
- return label;
-};
-
-export const useNodeTemplateTitle = (nodeId: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return false;
- }
- const nodeTemplate = node
- ? nodes.nodeTemplates[node.data.type]
- : undefined;
-
- return nodeTemplate?.title;
- },
- defaultSelectorOptions
- ),
- [nodeId]
- );
-
- const title = useAppSelector(selector);
- return title;
-};
-
-export const useFieldTemplate = (
- nodeId: string,
- fieldName: string,
- kind: 'input' | 'output'
-) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return;
- }
- const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
- return nodeTemplate?.[KIND_MAP[kind]][fieldName];
- },
- defaultSelectorOptions
- ),
- [fieldName, kind, nodeId]
- );
-
- const fieldTemplate = useAppSelector(selector);
-
- return fieldTemplate;
-};
-
-export const useDoesInputHaveValue = (nodeId: string, fieldName: string) => {
- const selector = useMemo(
- () =>
- createSelector(
- stateSelector,
- ({ nodes }) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- if (!isInvocationNode(node)) {
- return;
- }
- return Boolean(node?.data.inputs[fieldName]?.value);
- },
- defaultSelectorOptions
- ),
- [fieldName, nodeId]
- );
-
- const doesFieldHaveValue = useAppSelector(selector);
-
- return doesFieldHaveValue;
-};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useNodeLabel.ts b/invokeai/frontend/web/src/features/nodes/hooks/useNodeLabel.ts
new file mode 100644
index 0000000000..f9bbe4cc1d
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useNodeLabel.ts
@@ -0,0 +1,28 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useNodeLabel = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return false;
+ }
+
+ return node.data.label;
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const label = useAppSelector(selector);
+ return label;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useNodeTemplate.ts b/invokeai/frontend/web/src/features/nodes/hooks/useNodeTemplate.ts
new file mode 100644
index 0000000000..733c03e6cf
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useNodeTemplate.ts
@@ -0,0 +1,25 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+
+export const useNodeTemplate = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
+ return nodeTemplate;
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const nodeTemplate = useAppSelector(selector);
+
+ return nodeTemplate;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useNodeTemplateTitle.ts b/invokeai/frontend/web/src/features/nodes/hooks/useNodeTemplateTitle.ts
new file mode 100644
index 0000000000..4ef3eed5d9
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useNodeTemplateTitle.ts
@@ -0,0 +1,31 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useNodeTemplateTitle = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return false;
+ }
+ const nodeTemplate = node
+ ? nodes.nodeTemplates[node.data.type]
+ : undefined;
+
+ return nodeTemplate?.title;
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const title = useAppSelector(selector);
+ return title;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts
new file mode 100644
index 0000000000..41d3a1ac91
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts
@@ -0,0 +1,35 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { map } from 'lodash-es';
+import { useMemo } from 'react';
+import { isInvocationNode } from '../types/types';
+
+export const useOutputFieldNames = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return [];
+ }
+ const nodeTemplate = nodes.nodeTemplates[node.data.type];
+ if (!nodeTemplate) {
+ return [];
+ }
+ return map(nodeTemplate.outputs)
+ .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0))
+ .map((field) => field.name)
+ .filter((fieldName) => fieldName !== 'is_intermediate');
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const fieldNames = useAppSelector(selector);
+ return fieldNames;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useWithFooter.ts b/invokeai/frontend/web/src/features/nodes/hooks/useWithFooter.ts
new file mode 100644
index 0000000000..8bde120005
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useWithFooter.ts
@@ -0,0 +1,31 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { some } from 'lodash-es';
+import { useMemo } from 'react';
+import { FOOTER_FIELDS } from '../types/constants';
+import { isInvocationNode } from '../types/types';
+
+export const useWithFooter = (nodeId: string) => {
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ nodes }) => {
+ const node = nodes.nodes.find((node) => node.id === nodeId);
+ if (!isInvocationNode(node)) {
+ return false;
+ }
+ return some(node.data.outputs, (output) =>
+ FOOTER_FIELDS.includes(output.type)
+ );
+ },
+ defaultSelectorOptions
+ ),
+ [nodeId]
+ );
+
+ const withFooter = useAppSelector(selector);
+ return withFooter;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useWorkflow.ts b/invokeai/frontend/web/src/features/nodes/hooks/useWorkflow.ts
new file mode 100644
index 0000000000..f729aa1004
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useWorkflow.ts
@@ -0,0 +1,16 @@
+import { RootState } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import { buildWorkflow } from 'features/nodes/util/buildWorkflow';
+import { useMemo } from 'react';
+import { useDebounce } from 'use-debounce';
+
+export const useWorkflow = () => {
+ const nodes = useAppSelector((state: RootState) => state.nodes);
+ const [debouncedNodes] = useDebounce(nodes, 300);
+ const workflow = useMemo(
+ () => buildWorkflow(debouncedNodes),
+ [debouncedNodes]
+ );
+
+ return workflow;
+};
diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts b/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts
index cf3ee3918c..acf9918a89 100644
--- a/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts
@@ -4,11 +4,12 @@ import { NodesState } from './types';
* Nodes slice persist denylist
*/
export const nodesPersistDenylist: (keyof NodesState)[] = [
- 'schema',
'nodeTemplates',
'connectionStartParams',
'currentConnectionFieldType',
'selectedNodes',
'selectedEdges',
'isReady',
+ 'nodesToCopy',
+ 'edgesToCopy',
];
diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
index 437980d436..dec0daabe9 100644
--- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
@@ -14,6 +14,7 @@ import {
Node,
NodeChange,
OnConnectStartParams,
+ SelectionMode,
Viewport,
} from 'reactflow';
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
@@ -25,6 +26,7 @@ import {
appSocketInvocationError,
appSocketInvocationStarted,
} from 'services/events/actions';
+import { v4 as uuidv4 } from 'uuid';
import { DRAG_HANDLE_CLASSNAME } from '../types/constants';
import {
BooleanInputFieldValue,
@@ -43,19 +45,45 @@ import {
isNotesNode,
LoRAModelInputFieldValue,
MainModelInputFieldValue,
+ NodeExecutionState,
NodeStatus,
NotesNodeData,
+ SchedulerInputFieldValue,
SDXLRefinerModelInputFieldValue,
StringInputFieldValue,
VaeModelInputFieldValue,
Workflow,
} from '../types/types';
import { NodesState } from './types';
+import { findUnoccupiedPosition } from './util/findUnoccupiedPosition';
+
+export const WORKFLOW_FORMAT_VERSION = '1.0.0';
+
+const initialNodeExecutionState: Omit = {
+ status: NodeStatus.PENDING,
+ error: null,
+ progress: null,
+ progressImage: null,
+ outputs: [],
+};
+
+export const initialWorkflow = {
+ meta: {
+ version: WORKFLOW_FORMAT_VERSION,
+ },
+ name: '',
+ author: '',
+ description: '',
+ notes: '',
+ tags: '',
+ contact: '',
+ version: '',
+ exposedFields: [],
+};
export const initialNodesState: NodesState = {
nodes: [],
edges: [],
- schema: null,
nodeTemplates: {},
isReady: false,
connectionStartParams: null,
@@ -64,23 +92,19 @@ export const initialNodesState: NodesState = {
shouldShowMinimapPanel: true,
shouldValidateGraph: true,
shouldAnimateEdges: true,
- shouldSnapToGrid: true,
+ shouldSnapToGrid: false,
shouldColorEdges: true,
+ isAddNodePopoverOpen: false,
nodeOpacity: 1,
selectedNodes: [],
selectedEdges: [],
- workflow: {
- name: '',
- author: '',
- description: '',
- notes: '',
- tags: '',
- contact: '',
- version: '',
- exposedFields: [],
- },
+ workflow: initialWorkflow,
nodeExecutionStates: {},
viewport: { x: 0, y: 0, zoom: 1 },
+ mouseOverField: null,
+ nodesToCopy: [],
+ edgesToCopy: [],
+ selectionMode: SelectionMode.Partial,
};
type FieldValueAction = PayloadAction<{
@@ -122,6 +146,24 @@ const nodesSlice = createSlice({
>
) => {
const node = action.payload;
+ const position = findUnoccupiedPosition(
+ state.nodes,
+ node.position.x,
+ node.position.y
+ );
+ node.position = position;
+ node.selected = true;
+
+ state.nodes = applyNodeChanges(
+ state.nodes.map((n) => ({ id: n.id, type: 'select', selected: false })),
+ state.nodes
+ );
+
+ state.edges = applyEdgeChanges(
+ state.edges.map((e) => ({ id: e.id, type: 'select', selected: false })),
+ state.edges
+ );
+
state.nodes.push(node);
if (!isInvocationNode(node)) {
@@ -129,10 +171,8 @@ const nodesSlice = createSlice({
}
state.nodeExecutionStates[node.id] = {
- status: NodeStatus.PENDING,
- error: null,
- progress: null,
- progressImage: null,
+ nodeId: node.id,
+ ...initialNodeExecutionState,
};
},
edgesChanged: (state, action: PayloadAction) => {
@@ -446,6 +486,12 @@ const nodesSlice = createSlice({
) => {
fieldValueReducer(state, action);
},
+ fieldSchedulerValueChanged: (
+ state,
+ action: FieldValueAction
+ ) => {
+ fieldValueReducer(state, action);
+ },
imageCollectionFieldValueChanged: (
state,
action: PayloadAction<{
@@ -484,19 +530,6 @@ const nodesSlice = createSlice({
'image_name'
);
},
- nodeClicked: (
- state,
- action: PayloadAction<{ nodeId: string; ctrlOrMeta?: boolean }>
- ) => {
- const { nodeId, ctrlOrMeta } = action.payload;
- state.nodes.forEach((node) => {
- if (node.id === nodeId) {
- node.selected = true;
- } else if (!ctrlOrMeta) {
- node.selected = false;
- }
- });
- },
notesNodeValueChanged: (
state,
action: PayloadAction<{ nodeId: string; value: string }>
@@ -528,6 +561,7 @@ const nodesSlice = createSlice({
nodeEditorReset: (state) => {
state.nodes = [];
state.edges = [];
+ state.workflow.exposedFields = [];
},
shouldValidateGraphChanged: (state, action: PayloadAction) => {
state.shouldValidateGraph = action.payload;
@@ -544,15 +578,6 @@ const nodesSlice = createSlice({
nodeOpacityChanged: (state, action: PayloadAction) => {
state.nodeOpacity = action.payload;
},
- loadFileNodes: (
- state,
- action: PayloadAction[]>
- ) => {
- state.nodes = action.payload;
- },
- loadFileEdges: (state, action: PayloadAction) => {
- state.edges = action.payload;
- },
workflowNameChanged: (state, action: PayloadAction) => {
state.workflow.name = action.payload;
},
@@ -575,9 +600,9 @@ const nodesSlice = createSlice({
state.workflow.contact = action.payload;
},
workflowLoaded: (state, action: PayloadAction) => {
- // TODO: validation
const { nodes, edges, ...workflow } = action.payload;
state.workflow = workflow;
+
state.nodes = applyNodeChanges(
nodes.map((node) => ({
item: { ...node, dragHandle: `.${DRAG_HANDLE_CLASSNAME}` },
@@ -589,18 +614,135 @@ const nodesSlice = createSlice({
edges.map((edge) => ({ item: edge, type: 'add' })),
[]
);
+
+ state.nodeExecutionStates = nodes.reduce<
+ Record
+ >((acc, node) => {
+ acc[node.id] = {
+ nodeId: node.id,
+ ...initialNodeExecutionState,
+ };
+ return acc;
+ }, {});
+ },
+ workflowReset: (state) => {
+ state.workflow = cloneDeep(initialWorkflow);
},
viewportChanged: (state, action: PayloadAction) => {
state.viewport = action.payload;
},
+ mouseOverFieldChanged: (
+ state,
+ action: PayloadAction
+ ) => {
+ state.mouseOverField = action.payload;
+ },
+ selectedAll: (state) => {
+ state.nodes = applyNodeChanges(
+ state.nodes.map((n) => ({ id: n.id, type: 'select', selected: true })),
+ state.nodes
+ );
+ state.edges = applyEdgeChanges(
+ state.edges.map((e) => ({ id: e.id, type: 'select', selected: true })),
+ state.edges
+ );
+ },
+ selectionCopied: (state) => {
+ state.nodesToCopy = state.nodes.filter((n) => n.selected).map(cloneDeep);
+ state.edgesToCopy = state.edges.filter((e) => e.selected).map(cloneDeep);
+ },
+ selectionPasted: (state) => {
+ const newNodes = state.nodesToCopy.map(cloneDeep);
+ const oldNodeIds = newNodes.map((n) => n.data.id);
+ const newEdges = state.edgesToCopy
+ .filter(
+ (e) => oldNodeIds.includes(e.source) && oldNodeIds.includes(e.target)
+ )
+ .map(cloneDeep);
+
+ newEdges.forEach((e) => (e.selected = true));
+
+ newNodes.forEach((node) => {
+ const newNodeId = uuidv4();
+ newEdges.forEach((edge) => {
+ if (edge.source === node.data.id) {
+ edge.source = newNodeId;
+ edge.id = edge.id.replace(node.data.id, newNodeId);
+ }
+ if (edge.target === node.data.id) {
+ edge.target = newNodeId;
+ edge.id = edge.id.replace(node.data.id, newNodeId);
+ }
+ });
+ node.selected = true;
+ node.id = newNodeId;
+ node.data.id = newNodeId;
+
+ const position = findUnoccupiedPosition(
+ state.nodes,
+ node.position.x,
+ node.position.y
+ );
+
+ node.position = position;
+ });
+
+ const nodeAdditions: NodeChange[] = newNodes.map((n) => ({
+ item: n,
+ type: 'add',
+ }));
+ const nodeSelectionChanges: NodeChange[] = state.nodes.map((n) => ({
+ id: n.data.id,
+ type: 'select',
+ selected: false,
+ }));
+
+ const edgeAdditions: EdgeChange[] = newEdges.map((e) => ({
+ item: e,
+ type: 'add',
+ }));
+ const edgeSelectionChanges: EdgeChange[] = state.edges.map((e) => ({
+ id: e.id,
+ type: 'select',
+ selected: false,
+ }));
+
+ state.nodes = applyNodeChanges(
+ nodeAdditions.concat(nodeSelectionChanges),
+ state.nodes
+ );
+
+ state.edges = applyEdgeChanges(
+ edgeAdditions.concat(edgeSelectionChanges),
+ state.edges
+ );
+
+ newNodes.forEach((node) => {
+ state.nodeExecutionStates[node.id] = {
+ nodeId: node.id,
+ ...initialNodeExecutionState,
+ };
+ });
+ },
+ addNodePopoverOpened: (state) => {
+ state.isAddNodePopoverOpen = true;
+ },
+ addNodePopoverClosed: (state) => {
+ state.isAddNodePopoverOpen = false;
+ },
+ addNodePopoverToggled: (state) => {
+ state.isAddNodePopoverOpen = !state.isAddNodePopoverOpen;
+ },
+ selectionModeChanged: (state, action: PayloadAction) => {
+ state.selectionMode = action.payload
+ ? SelectionMode.Full
+ : SelectionMode.Partial;
+ },
},
extraReducers: (builder) => {
builder.addCase(receivedOpenAPISchema.pending, (state) => {
state.isReady = false;
});
- builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => {
- state.schema = action.payload;
- });
builder.addCase(appSocketInvocationStarted, (state, action) => {
const { source_node_id } = action.payload.data;
const node = state.nodeExecutionStates[source_node_id];
@@ -609,13 +751,14 @@ const nodesSlice = createSlice({
}
});
builder.addCase(appSocketInvocationComplete, (state, action) => {
- const { source_node_id } = action.payload.data;
- const node = state.nodeExecutionStates[source_node_id];
- if (node) {
- node.status = NodeStatus.COMPLETED;
- if (node.progress !== null) {
- node.progress = 1;
+ const { source_node_id, result } = action.payload.data;
+ const nes = state.nodeExecutionStates[source_node_id];
+ if (nes) {
+ nes.status = NodeStatus.COMPLETED;
+ if (nes.progress !== null) {
+ nes.progress = 1;
}
+ nes.outputs.push(result);
}
});
builder.addCase(appSocketInvocationError, (state, action) => {
@@ -644,6 +787,7 @@ const nodesSlice = createSlice({
nes.error = null;
nes.progress = null;
nes.progressImage = null;
+ nes.outputs = [];
});
});
},
@@ -657,14 +801,11 @@ export const {
connectionMade,
connectionStarted,
connectionEnded,
- nodeClicked,
shouldShowFieldTypeLegendChanged,
shouldShowMinimapPanelChanged,
nodeTemplatesBuilt,
nodeEditorReset,
imageCollectionFieldValueChanged,
- loadFileNodes,
- loadFileEdges,
fieldStringValueChanged,
fieldNumberValueChanged,
fieldBooleanValueChanged,
@@ -676,6 +817,7 @@ export const {
fieldEnumModelValueChanged,
fieldControlNetModelValueChanged,
fieldRefinerModelValueChanged,
+ fieldSchedulerValueChanged,
nodeIsOpenChanged,
nodeLabelChanged,
nodeNotesChanged,
@@ -700,6 +842,14 @@ export const {
workflowExposedFieldRemoved,
fieldLabelChanged,
viewportChanged,
+ mouseOverFieldChanged,
+ selectionCopied,
+ selectionPasted,
+ selectedAll,
+ addNodePopoverOpened,
+ addNodePopoverClosed,
+ addNodePopoverToggled,
+ selectionModeChanged,
} = nodesSlice.actions;
export default nodesSlice.reducer;
diff --git a/invokeai/frontend/web/src/features/nodes/store/selectors.ts b/invokeai/frontend/web/src/features/nodes/store/selectors.ts
deleted file mode 100644
index 41a608baa3..0000000000
--- a/invokeai/frontend/web/src/features/nodes/store/selectors.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { createSelector } from '@reduxjs/toolkit';
-import { stateSelector } from 'app/store/store';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-// import { validateSeedWeights } from 'common/util/seedWeightPairs';
-import { every } from 'lodash-es';
-import { getConnectedEdges } from 'reactflow';
-import { isInvocationNode } from '../types/types';
-import { NodesState } from './types';
-
-export const selectIsReadyNodes = createSelector(
- [stateSelector],
- (state) => {
- const { nodes, system } = state;
- const { isProcessing, isConnected } = system;
-
- if (isProcessing || !isConnected) {
- // Cannot generate if already processing an image
- return false;
- }
-
- if (!nodes.shouldValidateGraph) {
- return true;
- }
-
- const isGraphReady = every(nodes.nodes, (node) => {
- if (!isInvocationNode(node)) {
- return true;
- }
-
- const nodeTemplate = nodes.nodeTemplates[node.data.type];
-
- if (!nodeTemplate) {
- // Node type not found
- return false;
- }
-
- const connectedEdges = getConnectedEdges([node], nodes.edges);
-
- const isNodeValid = every(node.data.inputs, (field) => {
- const fieldTemplate = nodeTemplate.inputs[field.name];
- const hasConnection = connectedEdges.some(
- (edge) => edge.target === node.id && edge.targetHandle === field.name
- );
-
- if (!fieldTemplate) {
- // Field type not found
- return false;
- }
-
- if (fieldTemplate.required && !field.value && !hasConnection) {
- // Required field is empty or does not have a connection
- return false;
- }
-
- // ok
- return true;
- });
-
- return isNodeValid;
- });
-
- return isGraphReady;
- },
- defaultSelectorOptions
-);
-
-export const getNodeAndTemplate = (nodeId: string, nodes: NodesState) => {
- const node = nodes.nodes.find((node) => node.id === nodeId);
- const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
-
- return { node, nodeTemplate };
-};
-
-export const getInputFieldAndTemplate = (
- nodeId: string,
- fieldName: string,
- nodes: NodesState
-) => {
- const node = nodes.nodes
- .filter(isInvocationNode)
- .find((node) => node.id === nodeId);
- const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
-
- if (!node || !nodeTemplate) {
- return;
- }
-
- const field = node.data.inputs[fieldName];
- const fieldTemplate = nodeTemplate.inputs[fieldName];
-
- return { field, fieldTemplate };
-};
diff --git a/invokeai/frontend/web/src/features/nodes/store/types.ts b/invokeai/frontend/web/src/features/nodes/store/types.ts
index 27e25b8731..26eec9b2d5 100644
--- a/invokeai/frontend/web/src/features/nodes/store/types.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/types.ts
@@ -1,6 +1,12 @@
-import { OpenAPIV3 } from 'openapi-types';
-import { Edge, Node, OnConnectStartParams, Viewport } from 'reactflow';
import {
+ Edge,
+ Node,
+ OnConnectStartParams,
+ SelectionMode,
+ Viewport,
+} from 'reactflow';
+import {
+ FieldIdentifier,
FieldType,
InvocationEdgeExtra,
InvocationTemplate,
@@ -12,7 +18,6 @@ import {
export type NodesState = {
nodes: Node[];
edges: Edge[];
- schema: OpenAPIV3.Document | null;
nodeTemplates: Record;
connectionStartParams: OnConnectStartParams | null;
currentConnectionFieldType: FieldType | null;
@@ -29,4 +34,9 @@ export type NodesState = {
nodeExecutionStates: Record;
viewport: Viewport;
isReady: boolean;
+ mouseOverField: FieldIdentifier | null;
+ nodesToCopy: Node[];
+ edgesToCopy: Edge[];
+ isAddNodePopoverOpen: boolean;
+ selectionMode: SelectionMode;
};
diff --git a/invokeai/frontend/web/src/features/nodes/store/util/findUnoccupiedPosition.ts b/invokeai/frontend/web/src/features/nodes/store/util/findUnoccupiedPosition.ts
new file mode 100644
index 0000000000..57f36f4d5e
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/store/util/findUnoccupiedPosition.ts
@@ -0,0 +1,11 @@
+import { Node } from 'reactflow';
+
+export const findUnoccupiedPosition = (nodes: Node[], x: number, y: number) => {
+ let newX = x;
+ let newY = y;
+ while (nodes.find((n) => n.position.x === newX && n.position.y === newY)) {
+ newX = newX + 50;
+ newY = newY + 50;
+ }
+ return { x: newX, y: newY };
+};
diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts
index 1c5c89ff2d..4e61e46d8a 100644
--- a/invokeai/frontend/web/src/features/nodes/types/constants.ts
+++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts
@@ -9,6 +9,11 @@ export const DRAG_HANDLE_CLASSNAME = 'node-drag-handle';
export const IMAGE_FIELDS = ['ImageField', 'ImageCollection'];
export const FOOTER_FIELDS = IMAGE_FIELDS;
+export const KIND_MAP = {
+ input: 'inputs' as const,
+ output: 'outputs' as const,
+};
+
export const COLLECTION_TYPES: FieldType[] = [
'Collection',
'IntegerCollection',
@@ -18,9 +23,6 @@ export const COLLECTION_TYPES: FieldType[] = [
'ImageCollection',
];
-export const colorTokenToCssVar = (colorToken: string) =>
- `var(--invokeai-colors-${colorToken.split('.').join('-')}`;
-
export const FIELDS: Record = {
integer: {
title: 'Integer',
@@ -127,6 +129,11 @@ export const FIELDS: Record = {
title: 'ControlNet',
description: 'TODO',
},
+ Scheduler: {
+ color: 'base.500',
+ title: 'Scheduler',
+ description: 'TODO',
+ },
Collection: {
color: 'base.500',
title: 'Collection',
diff --git a/invokeai/frontend/web/src/features/nodes/types/typeGuards.ts b/invokeai/frontend/web/src/features/nodes/types/typeGuards.ts
deleted file mode 100644
index 99c9a28150..0000000000
--- a/invokeai/frontend/web/src/features/nodes/types/typeGuards.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { OpenAPIV3 } from 'openapi-types';
-
-export const isReferenceObject = (
- obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject
-): obj is OpenAPIV3.ReferenceObject => '$ref' in obj;
-
-export const isSchemaObject = (
- obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject
-): obj is OpenAPIV3.SchemaObject => !('$ref' in obj);
diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts
index 60e4877fd8..26aa19bd9d 100644
--- a/invokeai/frontend/web/src/features/nodes/types/types.ts
+++ b/invokeai/frontend/web/src/features/nodes/types/types.ts
@@ -1,21 +1,18 @@
import {
- ControlNetModelParam,
- LoRAModelParam,
- MainModelParam,
- OnnxModelParam,
- VaeModelParam,
+ SchedulerParam,
+ zBaseModel,
+ zMainOrOnnxModel,
+ zScheduler,
} from 'features/parameters/types/parameterSchemas';
import { OpenAPIV3 } from 'openapi-types';
import { RgbaColor } from 'react-colorful';
-import { Edge, Node } from 'reactflow';
+import { Node } from 'reactflow';
+import { Graph, ImageDTO, _InputField, _OutputField } from 'services/api/types';
import {
- Graph,
- ImageDTO,
- ImageField,
- _InputField,
- _OutputField,
-} from 'services/api/types';
-import { AnyInvocationType, ProgressImage } from 'services/events/types';
+ AnyInvocationType,
+ AnyResult,
+ ProgressImage,
+} from 'services/events/types';
import { O } from 'ts-toolbelt';
import { z } from 'zod';
@@ -46,6 +43,10 @@ export type InvocationTemplate = {
* Array of the invocation outputs
*/
outputs: Record;
+ /**
+ * The type of this node's output
+ */
+ outputType: string; // TODO: generate a union of output types
};
export type FieldUIConfig = {
@@ -98,6 +99,7 @@ export const zFieldType = z.enum([
// region Misc
'FilePath',
'enum',
+ 'Scheduler',
// endregion
]);
@@ -106,39 +108,6 @@ export type FieldType = z.infer;
export const isFieldType = (value: unknown): value is FieldType =>
zFieldType.safeParse(value).success;
-/**
- * An input field is persisted across reloads as part of the user's local state.
- *
- * An input field has three properties:
- * - `id` a unique identifier
- * - `name` the name of the field, which comes from the python dataclass
- * - `value` the field's value
- */
-export type InputFieldValue =
- | IntegerInputFieldValue
- | SeedInputFieldValue
- | FloatInputFieldValue
- | StringInputFieldValue
- | BooleanInputFieldValue
- | ImageInputFieldValue
- | LatentsInputFieldValue
- | ConditioningInputFieldValue
- | UNetInputFieldValue
- | ClipInputFieldValue
- | VaeInputFieldValue
- | ControlInputFieldValue
- | EnumInputFieldValue
- | MainModelInputFieldValue
- | SDXLMainModelInputFieldValue
- | SDXLRefinerModelInputFieldValue
- | VaeModelInputFieldValue
- | LoRAModelInputFieldValue
- | ControlNetModelInputFieldValue
- | CollectionInputFieldValue
- | CollectionItemInputFieldValue
- | ColorInputFieldValue
- | ImageCollectionInputFieldValue;
-
/**
* An input field template is generated on each page load from the OpenAPI schema.
*
@@ -167,7 +136,21 @@ export type InputFieldTemplate =
| CollectionInputFieldTemplate
| CollectionItemInputFieldTemplate
| ColorInputFieldTemplate
- | ImageCollectionInputFieldTemplate;
+ | ImageCollectionInputFieldTemplate
+ | SchedulerInputFieldTemplate;
+
+/**
+ * Indicates the kind of input(s) this field may have.
+ */
+export const zInputKind = z.enum(['connection', 'direct', 'any']);
+export type InputKind = z.infer;
+
+export const zFieldValueBase = z.object({
+ id: z.string().trim().min(1),
+ name: z.string().trim().min(1),
+ type: zFieldType,
+});
+export type FieldValueBase = z.infer;
/**
* An output field is persisted across as part of the user's local state.
@@ -176,7 +159,11 @@ export type InputFieldTemplate =
* - `id` a unique identifier
* - `name` the name of the field, which comes from the python dataclass
*/
-export type OutputFieldValue = FieldValueBase & { fieldKind: 'output' };
+
+export const zOutputFieldValue = zFieldValueBase.extend({
+ fieldKind: z.literal('output'),
+});
+export type OutputFieldValue = z.infer;
/**
* An output field template is generated on each page load from the OpenAPI schema.
@@ -189,138 +176,309 @@ export type OutputFieldTemplate = {
type: FieldType;
title: string;
description: string;
-};
+} & _OutputField;
-/**
- * Indicates the kind of input(s) this field may have.
- */
-export type InputKind = 'connection' | 'direct' | 'any';
+export const zInputFieldValueBase = zFieldValueBase.extend({
+ fieldKind: z.literal('input'),
+ label: z.string(),
+});
+export type InputFieldValueBase = z.infer;
-export type FieldValueBase = {
- id: string;
- name: string;
- type: FieldType;
-};
+export const zModelIdentifier = z.object({
+ model_name: z.string().trim().min(1),
+ base_model: zBaseModel,
+});
-export type InputFieldValueBase = FieldValueBase & {
- fieldKind: 'input';
- label: string;
-};
+export const zImageField = z.object({
+ image_name: z.string().trim().min(1),
+});
+export type ImageField = z.infer;
-export type IntegerInputFieldValue = InputFieldValueBase & {
- type: 'integer';
- value?: number;
-};
+export const zLatentsField = z.object({
+ latents_name: z.string().trim().min(1),
+ seed: z.number().int().optional(),
+});
+export type LatentsField = z.infer;
-export type FloatInputFieldValue = InputFieldValueBase & {
- type: 'float';
- value?: number;
-};
+export const zConditioningField = z.object({
+ conditioning_name: z.string().trim().min(1),
+});
+export type ConditioningField = z.infer;
-export type SeedInputFieldValue = InputFieldValueBase & {
- type: 'Seed';
- value?: number;
-};
+export const zIntegerInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('integer'),
+ value: z.number().optional(),
+});
+export type IntegerInputFieldValue = z.infer;
-export type StringInputFieldValue = InputFieldValueBase & {
- type: 'string';
- value?: string;
-};
+export const zFloatInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('float'),
+ value: z.number().optional(),
+});
+export type FloatInputFieldValue = z.infer;
-export type BooleanInputFieldValue = InputFieldValueBase & {
- type: 'boolean';
- value?: boolean;
-};
+export const zStringInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('string'),
+ value: z.string().optional(),
+});
+export type StringInputFieldValue = z.infer;
-export type EnumInputFieldValue = InputFieldValueBase & {
- type: 'enum';
- value?: number | string;
-};
+export const zBooleanInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('boolean'),
+ value: z.boolean().optional(),
+});
+export type BooleanInputFieldValue = z.infer;
-export type LatentsInputFieldValue = InputFieldValueBase & {
- type: 'LatentsField';
- value?: undefined;
-};
+export const zEnumInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('enum'),
+ value: z.union([z.string(), z.number()]).optional(),
+});
+export type EnumInputFieldValue = z.infer;
-export type ConditioningInputFieldValue = InputFieldValueBase & {
- type: 'ConditioningField';
- value?: string;
-};
+export const zLatentsInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('LatentsField'),
+ value: zLatentsField.optional(),
+});
+export type LatentsInputFieldValue = z.infer;
-export type ControlInputFieldValue = InputFieldValueBase & {
- type: 'ControlField';
- value?: undefined;
-};
+export const zConditioningInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('ConditioningField'),
+ value: zConditioningField.optional(),
+});
+export type ConditioningInputFieldValue = z.infer<
+ typeof zConditioningInputFieldValue
+>;
-export type UNetInputFieldValue = InputFieldValueBase & {
- type: 'UNetField';
- value?: undefined;
-};
+export const zControlNetModel = zModelIdentifier;
+export type ControlNetModel = z.infer;
-export type ClipInputFieldValue = InputFieldValueBase & {
- type: 'ClipField';
- value?: undefined;
-};
+export const zControlField = zInputFieldValueBase.extend({
+ image: zImageField,
+ control_model: zControlNetModel,
+ control_weight: z.union([z.number(), z.array(z.number())]).optional(),
+ begin_step_percent: z.number().optional(),
+ end_step_percent: z.number().optional(),
+ control_mode: z
+ .enum(['balanced', 'more_prompt', 'more_control', 'unbalanced'])
+ .optional(),
+ resize_mode: z
+ .enum(['just_resize', 'crop_resize', 'fill_resize', 'just_resize_simple'])
+ .optional(),
+});
+export type ControlField = z.infer;
-export type VaeInputFieldValue = InputFieldValueBase & {
- type: 'VaeField';
- value?: undefined;
-};
+export const zControlInputFieldTemplate = zInputFieldValueBase.extend({
+ type: z.literal('ControlField'),
+ value: zControlField.optional(),
+});
+export type ControlInputFieldValue = z.infer;
-export type ImageInputFieldValue = InputFieldValueBase & {
- type: 'ImageField';
- value?: ImageField;
-};
+export const zModelType = z.enum([
+ 'onnx',
+ 'main',
+ 'vae',
+ 'lora',
+ 'controlnet',
+ 'embedding',
+]);
+export type ModelType = z.infer;
-export type ImageCollectionInputFieldValue = InputFieldValueBase & {
- type: 'ImageCollection';
- value?: ImageField[];
-};
+export const zSubModelType = z.enum([
+ 'unet',
+ 'text_encoder',
+ 'text_encoder_2',
+ 'tokenizer',
+ 'tokenizer_2',
+ 'vae',
+ 'vae_decoder',
+ 'vae_encoder',
+ 'scheduler',
+ 'safety_checker',
+]);
+export type SubModelType = z.infer;
-export type MainModelInputFieldValue = InputFieldValueBase & {
- type: 'MainModelField';
- value?: MainModelParam | OnnxModelParam;
-};
+export const zModelInfo = zModelIdentifier.extend({
+ model_type: zModelType,
+ submodel: zSubModelType.optional(),
+});
+export type ModelInfo = z.infer;
-export type SDXLMainModelInputFieldValue = InputFieldValueBase & {
- type: 'SDXLMainModelField';
- value?: MainModelParam | OnnxModelParam;
-};
+export const zLoraInfo = zModelInfo.extend({
+ weight: z.number().optional(),
+});
+export type LoraInfo = z.infer;
-export type SDXLRefinerModelInputFieldValue = InputFieldValueBase & {
- type: 'SDXLRefinerModelField';
- value?: MainModelParam | OnnxModelParam;
-};
+export const zUNetField = z.object({
+ unet: zModelInfo,
+ scheduler: zModelInfo,
+ loras: z.array(zLoraInfo),
+});
+export type UNetField = z.infer;
-export type VaeModelInputFieldValue = InputFieldValueBase & {
- type: 'VaeModelField';
- value?: VaeModelParam;
-};
+export const zUNetInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('UNetField'),
+ value: zUNetField.optional(),
+});
+export type UNetInputFieldValue = z.infer;
-export type LoRAModelInputFieldValue = InputFieldValueBase & {
- type: 'LoRAModelField';
- value?: LoRAModelParam;
-};
+export const zClipField = z.object({
+ tokenizer: zModelInfo,
+ text_encoder: zModelInfo,
+ skipped_layers: z.number(),
+ loras: z.array(zLoraInfo),
+});
+export type ClipField = z.infer;
-export type ControlNetModelInputFieldValue = InputFieldValueBase & {
- type: 'ControlNetModelField';
- value?: ControlNetModelParam;
-};
+export const zClipInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('ClipField'),
+ value: zClipField.optional(),
+});
+export type ClipInputFieldValue = z.infer;
-export type CollectionInputFieldValue = InputFieldValueBase & {
- type: 'Collection';
- value?: (string | number)[];
-};
+export const zVaeField = z.object({
+ vae: zModelInfo,
+});
+export type VaeField = z.infer;
-export type CollectionItemInputFieldValue = InputFieldValueBase & {
- type: 'CollectionItem';
- value?: undefined;
-};
+export const zVaeInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('VaeField'),
+ value: zVaeField.optional(),
+});
+export type VaeInputFieldValue = z.infer;
-export type ColorInputFieldValue = InputFieldValueBase & {
- type: 'ColorField';
- value?: RgbaColor;
-};
+export const zImageInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('ImageField'),
+ value: zImageField.optional(),
+});
+export type ImageInputFieldValue = z.infer;
+
+export const zImageCollectionInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('ImageCollection'),
+ value: z.array(zImageField).optional(),
+});
+export type ImageCollectionInputFieldValue = z.infer<
+ typeof zImageCollectionInputFieldValue
+>;
+
+export const zMainModelInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('MainModelField'),
+ value: zMainOrOnnxModel.optional(),
+});
+export type MainModelInputFieldValue = z.infer<
+ typeof zMainModelInputFieldValue
+>;
+
+export const zSDXLMainModelInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('SDXLMainModelField'),
+ value: zMainOrOnnxModel.optional(),
+});
+export type SDXLMainModelInputFieldValue = z.infer<
+ typeof zSDXLMainModelInputFieldValue
+>;
+
+export const zSDXLRefinerModelInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('SDXLRefinerModelField'),
+ value: zMainOrOnnxModel.optional(), // TODO: should narrow this down to a refiner model
+});
+export type SDXLRefinerModelInputFieldValue = z.infer<
+ typeof zSDXLRefinerModelInputFieldValue
+>;
+
+export const zVaeModelField = zModelIdentifier;
+
+export const zVaeModelInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('VaeModelField'),
+ value: zVaeModelField.optional(),
+});
+export type VaeModelInputFieldValue = z.infer;
+
+export const zLoRAModelField = zModelIdentifier;
+export type LoRAModelField = z.infer;
+
+export const zLoRAModelInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('LoRAModelField'),
+ value: zLoRAModelField.optional(),
+});
+export type LoRAModelInputFieldValue = z.infer<
+ typeof zLoRAModelInputFieldValue
+>;
+
+export const zControlNetModelField = zModelIdentifier;
+export type ControlNetModelField = z.infer;
+
+export const zControlNetModelInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('ControlNetModelField'),
+ value: zControlNetModelField.optional(),
+});
+export type ControlNetModelInputFieldValue = z.infer<
+ typeof zControlNetModelInputFieldValue
+>;
+
+export const zCollectionInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('Collection'),
+ value: z.array(z.any()).optional(), // TODO: should this field ever have a value?
+});
+export type CollectionInputFieldValue = z.infer<
+ typeof zCollectionInputFieldValue
+>;
+
+export const zCollectionItemInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('CollectionItem'),
+ value: z.any().optional(), // TODO: should this field ever have a value?
+});
+export type CollectionItemInputFieldValue = z.infer<
+ typeof zCollectionItemInputFieldValue
+>;
+
+export const zColorField = z.object({
+ r: z.number().int().min(0).max(255),
+ g: z.number().int().min(0).max(255),
+ b: z.number().int().min(0).max(255),
+ a: z.number().int().min(0).max(255),
+});
+export type ColorField = z.infer;
+
+export const zColorInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('ColorField'),
+ value: zColorField.optional(),
+});
+export type ColorInputFieldValue = z.infer;
+
+export const zSchedulerInputFieldValue = zInputFieldValueBase.extend({
+ type: z.literal('Scheduler'),
+ value: zScheduler.optional(),
+});
+export type SchedulerInputFieldValue = z.infer<
+ typeof zSchedulerInputFieldValue
+>;
+
+export const zInputFieldValue = z.discriminatedUnion('type', [
+ zIntegerInputFieldValue,
+ zFloatInputFieldValue,
+ zStringInputFieldValue,
+ zBooleanInputFieldValue,
+ zImageInputFieldValue,
+ zLatentsInputFieldValue,
+ zConditioningInputFieldValue,
+ zUNetInputFieldValue,
+ zClipInputFieldValue,
+ zVaeInputFieldValue,
+ zControlInputFieldTemplate,
+ zEnumInputFieldValue,
+ zMainModelInputFieldValue,
+ zSDXLMainModelInputFieldValue,
+ zSDXLRefinerModelInputFieldValue,
+ zVaeModelInputFieldValue,
+ zLoRAModelInputFieldValue,
+ zControlNetModelInputFieldValue,
+ zCollectionInputFieldValue,
+ zCollectionItemInputFieldValue,
+ zColorInputFieldValue,
+ zImageCollectionInputFieldValue,
+ zSchedulerInputFieldValue,
+]);
+
+export type InputFieldValue = z.infer;
export type InputFieldTemplateBase = {
name: string;
@@ -456,6 +614,11 @@ export type ColorInputFieldTemplate = InputFieldTemplateBase & {
type: 'ColorField';
};
+export type SchedulerInputFieldTemplate = InputFieldTemplateBase & {
+ default: SchedulerParam;
+ type: 'Scheduler';
+};
+
export const isInputFieldValue = (
field?: InputFieldValue | OutputFieldValue
): field is InputFieldValue => Boolean(field && field.fieldKind === 'input');
@@ -475,11 +638,8 @@ export type TypeHints = {
export type InvocationSchemaExtra = {
output: OpenAPIV3.ReferenceObject; // the output of the invocation
- ui?: {
- tags?: string[];
- title?: string;
- };
title: string;
+ tags?: string[];
properties: Omit<
NonNullable &
(_InputField | _OutputField),
@@ -501,6 +661,19 @@ export type InvocationBaseSchemaObject = Omit<
> &
InvocationSchemaExtra;
+export type InvocationOutputSchemaObject = Omit<
+ OpenAPIV3.SchemaObject,
+ 'properties'
+> & {
+ properties: OpenAPIV3.SchemaObject['properties'] & {
+ type: Omit & {
+ default: string;
+ };
+ } & {
+ class: 'output';
+ };
+};
+
export type InvocationFieldSchema = OpenAPIV3.SchemaObject & _InputField;
export interface ArraySchemaObject extends InvocationBaseSchemaObject {
@@ -511,11 +684,30 @@ export interface NonArraySchemaObject extends InvocationBaseSchemaObject {
type?: OpenAPIV3.NonArraySchemaObjectType;
}
-export type InvocationSchemaObject = ArraySchemaObject | NonArraySchemaObject;
+export type InvocationSchemaObject = (
+ | ArraySchemaObject
+ | NonArraySchemaObject
+) & { class: 'invocation' };
+
+export const isSchemaObject = (
+ obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject
+): obj is OpenAPIV3.SchemaObject => !('$ref' in obj);
export const isInvocationSchemaObject = (
- obj: OpenAPIV3.ReferenceObject | InvocationSchemaObject
-): obj is InvocationSchemaObject => !('$ref' in obj);
+ obj:
+ | OpenAPIV3.ReferenceObject
+ | OpenAPIV3.SchemaObject
+ | InvocationSchemaObject
+): obj is InvocationSchemaObject =>
+ 'class' in obj && obj.class === 'invocation';
+
+export const isInvocationOutputSchemaObject = (
+ obj:
+ | OpenAPIV3.ReferenceObject
+ | OpenAPIV3.SchemaObject
+ | InvocationOutputSchemaObject
+): obj is InvocationOutputSchemaObject =>
+ 'class' in obj && obj.class === 'output';
export const isInvocationFieldSchema = (
obj: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject
@@ -523,24 +715,26 @@ export const isInvocationFieldSchema = (
export type InvocationEdgeExtra = { type: 'default' | 'collapsed' };
-export const zInputFieldValue = z.object({
- id: z.string().trim().min(1),
- name: z.string().trim().min(1),
- type: zFieldType,
- label: z.string(),
- isExposed: z.boolean(),
-});
-
export const zInvocationNodeData = z.object({
id: z.string().trim().min(1),
+ // no easy way to build this dynamically, and we don't want to anyways, because this will be used
+ // to validate incoming workflows, and we want to allow community nodes.
type: z.string().trim().min(1),
- inputs: z.record(z.any()),
- outputs: z.record(z.any()),
+ inputs: z.record(zInputFieldValue),
+ outputs: z.record(zOutputFieldValue),
label: z.string(),
isOpen: z.boolean(),
notes: z.string(),
});
+// Massage this to get better type safety while developing
+export type InvocationNodeData = Omit<
+ z.infer,
+ 'type'
+> & {
+ type: AnyInvocationType;
+};
+
export const zNotesNodeData = z.object({
id: z.string().trim().min(1),
type: z.literal('notes'),
@@ -549,75 +743,83 @@ export const zNotesNodeData = z.object({
notes: z.string(),
});
+export type NotesNodeData = z.infer;
+
+export const zWorkflowInvocationNode = z.object({
+ id: z.string().trim().min(1),
+ type: z.literal('invocation'),
+ data: zInvocationNodeData,
+ width: z.number().gt(0),
+ height: z.number().gt(0),
+ position: z.object({
+ x: z.number(),
+ y: z.number(),
+ }),
+});
+
+export const zWorkflowNotesNode = z.object({
+ id: z.string().trim().min(1),
+ type: z.literal('notes'),
+ data: zNotesNodeData,
+ width: z.number().gt(0),
+ height: z.number().gt(0),
+ position: z.object({
+ x: z.number(),
+ y: z.number(),
+ }),
+});
+
+export const zWorkflowNode = z.discriminatedUnion('type', [
+ zWorkflowInvocationNode,
+ zWorkflowNotesNode,
+]);
+
+export type WorkflowNode = z.infer;
+
+export const zWorkflowEdge = z.object({
+ source: z.string().trim().min(1),
+ sourceHandle: z.string().trim().min(1),
+ target: z.string().trim().min(1),
+ targetHandle: z.string().trim().min(1),
+ id: z.string().trim().min(1),
+ type: z.enum(['default', 'collapsed']),
+});
+
+export const zFieldIdentifier = z.object({
+ nodeId: z.string().trim().min(1),
+ fieldName: z.string().trim().min(1),
+});
+
+export type FieldIdentifier = z.infer;
+
+export const zSemVer = z.string().refine((val) => {
+ const [major, minor, patch] = val.split('.');
+ return (
+ major !== undefined &&
+ minor !== undefined &&
+ patch !== undefined &&
+ Number.isInteger(Number(major)) &&
+ Number.isInteger(Number(minor)) &&
+ Number.isInteger(Number(patch))
+ );
+});
+
+export type SemVer = z.infer;
+
export const zWorkflow = z.object({
- name: z.string().trim().min(1),
+ name: z.string(),
author: z.string(),
description: z.string(),
version: z.string(),
contact: z.string(),
tags: z.string(),
notes: z.string(),
- nodes: z.array(
- z.object({
- id: z.string().trim().min(1),
- type: z.string().trim().min(1),
- data: z.union([zInvocationNodeData, zNotesNodeData]),
- width: z.number().gt(0),
- height: z.number().gt(0),
- position: z.object({
- x: z.number(),
- y: z.number(),
- }),
- })
- ),
- edges: z.array(
- z.object({
- source: z.string().trim().min(1),
- sourceHandle: z.string().trim().min(1),
- target: z.string().trim().min(1),
- targetHandle: z.string().trim().min(1),
- id: z.string().trim().min(1),
- type: z.string().trim().min(1),
- })
- ),
+ nodes: z.array(zWorkflowNode),
+ edges: z.array(zWorkflowEdge),
+ exposedFields: z.array(zFieldIdentifier),
});
-export type Workflow = {
- name: string;
- author: string;
- description: string;
- version: string;
- contact: string;
- tags: string;
- notes: string;
- nodes: Pick<
- Node,
- 'id' | 'type' | 'data' | 'width' | 'height' | 'position'
- >[];
- edges: Pick<
- Edge,
- 'source' | 'sourceHandle' | 'target' | 'targetHandle' | 'id' | 'type'
- >[];
- exposedFields: FieldIdentifier[];
-};
-
-export type InvocationNodeData = {
- id: string;
- type: AnyInvocationType;
- inputs: Record;
- outputs: Record;
- label: string;
- isOpen: boolean;
- notes: string;
-};
-
-export type NotesNodeData = {
- id: string;
- type: 'notes';
- label: string;
- notes: string;
- isOpen: boolean;
-};
+export type Workflow = z.infer;
export type CurrentImageNodeData = {
id: string;
@@ -658,13 +860,19 @@ export enum NodeStatus {
}
export type NodeExecutionState = {
+ nodeId: string;
status: NodeStatus;
progress: number | null;
progressImage: ProgressImage | null;
error: string | null;
+ outputs: AnyResult[];
};
-export type FieldIdentifier = {
+export type FieldComponentProps<
+ V extends InputFieldValue,
+ T extends InputFieldTemplate,
+> = {
nodeId: string;
- fieldName: string;
+ field: V;
+ fieldTemplate: T;
};
diff --git a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts
index da3aff7e1c..cb0d0b942b 100644
--- a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts
@@ -1,8 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
-import { pick } from 'lodash-es';
import { NodesState } from '../store/types';
-import { Workflow, isInvocationNode, isNotesNode } from '../types/types';
+import { Workflow, zWorkflowEdge, zWorkflowNode } from '../types/types';
export const buildWorkflow = (nodesState: NodesState): Workflow => {
const { workflow: workflowMeta, nodes, edges } = nodesState;
@@ -13,25 +12,19 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => {
};
nodes.forEach((node) => {
- if (!isInvocationNode(node) && !isNotesNode(node)) {
+ const result = zWorkflowNode.safeParse(node);
+ if (!result.success) {
return;
}
- workflow.nodes.push(
- pick(node, ['id', 'type', 'position', 'width', 'height', 'data'])
- );
+ workflow.nodes.push(result.data);
});
edges.forEach((edge) => {
- workflow.edges.push(
- pick(edge, [
- 'source',
- 'sourceHandle',
- 'target',
- 'targetHandle',
- 'id',
- 'type',
- ])
- );
+ const result = zWorkflowEdge.safeParse(edge);
+ if (!result.success) {
+ return;
+ }
+ workflow.edges.push(result.data);
});
return workflow;
diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts
index 37aaab59b6..ca7674a021 100644
--- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts
@@ -1,8 +1,4 @@
-import { logger } from 'app/logging/logger';
-import { parseify } from 'common/util/serialize';
-import { reduce } from 'lodash-es';
import { OpenAPIV3 } from 'openapi-types';
-import { isSchemaObject } from '../types/typeGuards';
import {
BooleanInputFieldTemplate,
ClipInputFieldTemplate,
@@ -24,15 +20,14 @@ import {
LatentsInputFieldTemplate,
LoRAModelInputFieldTemplate,
MainModelInputFieldTemplate,
- OutputFieldTemplate,
SDXLMainModelInputFieldTemplate,
SDXLRefinerModelInputFieldTemplate,
+ SchedulerInputFieldTemplate,
StringInputFieldTemplate,
UNetInputFieldTemplate,
VaeInputFieldTemplate,
VaeModelInputFieldTemplate,
isFieldType,
- isInvocationFieldSchema,
} from '../types/types';
export type BaseFieldProperties = 'name' | 'title' | 'description';
@@ -400,6 +395,19 @@ const buildColorInputFieldTemplate = ({
return template;
};
+const buildSchedulerInputFieldTemplate = ({
+ schemaObject,
+ baseField,
+}: BuildInputFieldArg): SchedulerInputFieldTemplate => {
+ const template: SchedulerInputFieldTemplate = {
+ ...baseField,
+ type: 'Scheduler',
+ default: schemaObject.default ?? 'euler',
+ };
+
+ return template;
+};
+
export const getFieldType = (
schemaObject: InvocationFieldSchema
): FieldType => {
@@ -459,7 +467,7 @@ export const buildInputFieldTemplate = (
const fieldType = getFieldType(fieldSchema);
// console.log('input fieldType', fieldType);
- const { input, ui_hidden, ui_component, ui_type } = fieldSchema;
+ const { input, ui_hidden, ui_component, ui_type, ui_order } = fieldSchema;
const extra = {
input,
@@ -467,6 +475,7 @@ export const buildInputFieldTemplate = (
ui_component,
ui_type,
required: nodeSchema.required?.includes(name) ?? false,
+ ui_order,
};
const baseField = {
@@ -606,68 +615,11 @@ export const buildInputFieldTemplate = (
baseField,
});
}
+ if (fieldType === 'Scheduler') {
+ return buildSchedulerInputFieldTemplate({
+ schemaObject: fieldSchema,
+ baseField,
+ });
+ }
return;
};
-
-/**
- * Builds invocation output fields from an invocation's output reference object.
- * @param openAPI The OpenAPI schema
- * @param refObject The output reference object
- * @returns A record of outputs
- */
-export const buildOutputFieldTemplates = (
- refObject: OpenAPIV3.ReferenceObject,
- openAPI: OpenAPIV3.Document
-): Record => {
- // extract output schema name from ref
- const outputSchemaName = refObject.$ref.split('/').slice(-1)[0];
-
- if (!outputSchemaName) {
- logger('nodes').error(
- { refObject: parseify(refObject) },
- 'No output schema name found in ref object'
- );
- throw 'No output schema name found in ref object';
- }
-
- // get the output schema itself
- const outputSchema = openAPI.components?.schemas?.[outputSchemaName];
- if (!outputSchema) {
- logger('nodes').error({ outputSchemaName }, 'Output schema not found');
- throw 'Output schema not found';
- }
-
- // console.log('output', outputSchema);
- if (isSchemaObject(outputSchema)) {
- // console.log('isSchemaObject');
- const outputFields = reduce(
- outputSchema.properties as OpenAPIV3.SchemaObject,
- (outputsAccumulator, property, propertyName) => {
- if (
- !['type', 'id'].includes(propertyName) &&
- !['object'].includes(property.type) && // TODO: handle objects?
- isInvocationFieldSchema(property)
- ) {
- const fieldType = getFieldType(property);
- // console.log('output fieldType', fieldType);
- outputsAccumulator[propertyName] = {
- fieldKind: 'output',
- name: propertyName,
- title: property.title ?? '',
- description: property.description ?? '',
- type: fieldType,
- };
- } else {
- // console.warn('Unhandled OUTPUT property', property);
- }
-
- return outputsAccumulator;
- },
- {} as Record
- );
-
- return outputFields;
- }
-
- return {};
-};
diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts
index 473dc83bb6..07f8074eb9 100644
--- a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts
@@ -93,5 +93,9 @@ export const buildInputFieldValue = (
fieldValue.value = undefined;
}
+ if (template.type === 'Scheduler') {
+ fieldValue.value = 'euler';
+ }
+
return fieldValue;
};
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts
index ae3b31c2ad..9c71de5516 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addDynamicPromptsToGraph.ts
@@ -108,13 +108,13 @@ export const addDynamicPromptsToGraph = (
// Connect random int to the start of the range of size so the range starts on the random first seed
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: NOISE, field: 'seed' },
});
if (metadataAccumulator) {
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: METADATA_ACCUMULATOR, field: 'seed' },
});
}
@@ -198,7 +198,7 @@ export const addDynamicPromptsToGraph = (
// Connect random int to the start of the range of size so the range starts on the random first seed
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: RANGE_OF_SIZE, field: 'start' },
});
} else {
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts
index 01158d1cf0..e199a78a20 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addLoRAsToGraph.ts
@@ -6,6 +6,9 @@ import {
MetadataAccumulatorInvocation,
} from 'services/api/types';
import {
+ CANVAS_INPAINT_GRAPH,
+ CANVAS_OUTPAINT_GRAPH,
+ CANVAS_COHERENCE_DENOISE_LATENTS,
CLIP_SKIP,
LORA_LOADER,
MAIN_MODEL_LOADER,
@@ -136,6 +139,22 @@ export const addLoRAsToGraph = (
},
});
+ if (
+ graph.id &&
+ [CANVAS_INPAINT_GRAPH, CANVAS_OUTPAINT_GRAPH].includes(graph.id)
+ ) {
+ graph.edges.push({
+ source: {
+ node_id: currentLoraNodeId,
+ field: 'unet',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'unet',
+ },
+ });
+ }
+
graph.edges.push({
source: {
node_id: currentLoraNodeId,
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts
index 190816f21f..a52264ca8e 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLLoRAstoGraph.ts
@@ -6,10 +6,13 @@ import {
SDXLLoraLoaderInvocation,
} from 'services/api/types';
import {
+ CANVAS_COHERENCE_DENOISE_LATENTS,
LORA_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
POSITIVE_CONDITIONING,
+ SDXL_CANVAS_INPAINT_GRAPH,
+ SDXL_CANVAS_OUTPAINT_GRAPH,
SDXL_MODEL_LOADER,
} from './constants';
@@ -163,6 +166,24 @@ export const addSDXLLoRAsToGraph = (
},
});
+ if (
+ graph.id &&
+ [SDXL_CANVAS_INPAINT_GRAPH, SDXL_CANVAS_OUTPAINT_GRAPH].includes(
+ graph.id
+ )
+ ) {
+ graph.edges.push({
+ source: {
+ node_id: currentLoraNodeId,
+ field: 'unet',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'unet',
+ },
+ });
+ }
+
graph.edges.push({
source: {
node_id: currentLoraNodeId,
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts
index 2a6ef8e80c..3edea0b3c0 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts
@@ -33,7 +33,9 @@ export const addSDXLRefinerToGraph = (
refinerStart,
} = state.sdxl;
- if (!refinerModel) return;
+ if (!refinerModel) {
+ return;
+ }
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts
index 6b0da8e197..4b017340cb 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts
@@ -17,8 +17,10 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_INPAINT_GRAPH,
CANVAS_OUTPUT,
+ CANVAS_COHERENCE_DENOISE_LATENTS,
+ CANVAS_COHERENCE_NOISE,
+ CANVAS_COHERENCE_NOISE_INCREMENT,
CLIP_SKIP,
- COLOR_CORRECT,
DENOISE_LATENTS,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
@@ -61,6 +63,8 @@ export const buildCanvasInpaintGraph = (
shouldUseCpuNoise,
maskBlur,
maskBlurMethod,
+ canvasCoherenceSteps,
+ canvasCoherenceStrength,
clipSkip,
} = state.generation;
@@ -139,23 +143,39 @@ export const buildCanvasInpaintGraph = (
denoising_start: 1 - strength,
denoising_end: 1,
},
+ [CANVAS_COHERENCE_NOISE]: {
+ type: 'noise',
+ id: NOISE,
+ use_cpu,
+ is_intermediate: true,
+ },
+ [CANVAS_COHERENCE_NOISE_INCREMENT]: {
+ type: 'add',
+ id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ b: 1,
+ is_intermediate: true,
+ },
+ [CANVAS_COHERENCE_DENOISE_LATENTS]: {
+ type: 'denoise_latents',
+ id: DENOISE_LATENTS,
+ is_intermediate: true,
+ steps: canvasCoherenceSteps,
+ cfg_scale: cfg_scale,
+ scheduler: scheduler,
+ denoising_start: 1 - canvasCoherenceStrength,
+ denoising_end: 1,
+ },
[LATENTS_TO_IMAGE]: {
type: 'l2i',
id: LATENTS_TO_IMAGE,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
- [COLOR_CORRECT]: {
- type: 'color_correct',
- id: COLOR_CORRECT,
- is_intermediate: true,
- reference: canvasInitImage,
- },
[CANVAS_OUTPUT]: {
- type: 'img_paste',
+ type: 'color_correct',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
- base_image: canvasInitImage,
+ reference: canvasInitImage,
},
[RANGE_OF_SIZE]: {
type: 'range_of_size',
@@ -287,12 +307,83 @@ export const buildCanvasInpaintGraph = (
field: 'seed',
},
},
- // Decode Inpainted Latents To Image
+ // Canvas Refine
+ {
+ source: {
+ node_id: ITERATE,
+ field: 'item',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'a',
+ },
+ },
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'value',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE,
+ field: 'seed',
+ },
+ },
+ {
+ source: {
+ node_id: MAIN_MODEL_LOADER,
+ field: 'unet',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'unet',
+ },
+ },
+ {
+ source: {
+ node_id: POSITIVE_CONDITIONING,
+ field: 'conditioning',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'positive_conditioning',
+ },
+ },
+ {
+ source: {
+ node_id: NEGATIVE_CONDITIONING,
+ field: 'conditioning',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'negative_conditioning',
+ },
+ },
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_NOISE,
+ field: 'noise',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'noise',
+ },
+ },
{
source: {
node_id: DENOISE_LATENTS,
field: 'latents',
},
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'latents',
+ },
+ },
+ // Decode Inpainted Latents To Image
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'latents',
+ },
destination: {
node_id: LATENTS_TO_IMAGE,
field: 'latents',
@@ -338,11 +429,12 @@ export const buildCanvasInpaintGraph = (
height: height,
};
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: scaledWidth,
- height: scaledHeight,
- };
+ (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth;
+ (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width =
+ scaledWidth;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height =
+ scaledHeight;
// Connect Nodes
graph.edges.push(
@@ -384,7 +476,7 @@ export const buildCanvasInpaintGraph = (
field: 'image',
},
destination: {
- node_id: COLOR_CORRECT,
+ node_id: CANVAS_OUTPUT,
field: 'image',
},
},
@@ -398,27 +490,6 @@ export const buildCanvasInpaintGraph = (
field: 'image',
},
},
- {
- source: {
- node_id: MASK_RESIZE_DOWN,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Back Onto Original Image
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- destination: {
- node_id: CANVAS_OUTPUT,
- field: 'image',
- },
- },
{
source: {
node_id: MASK_RESIZE_DOWN,
@@ -432,11 +503,11 @@ export const buildCanvasInpaintGraph = (
);
} else {
// Add Images To Nodes
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: width,
- height: height,
- };
+ (graph.nodes[NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[NOISE] as NoiseInvocation).height = height;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height;
+
graph.nodes[INPAINT_IMAGE] = {
...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation),
image: canvasInitImage,
@@ -453,27 +524,6 @@ export const buildCanvasInpaintGraph = (
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
- destination: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- },
- {
- source: {
- node_id: MASK_BLUR,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Back Onto Original Image
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
@@ -504,7 +554,7 @@ export const buildCanvasInpaintGraph = (
// Connect random int to the start of the range of size so the range starts on the random first seed
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: RANGE_OF_SIZE, field: 'start' },
});
} else {
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts
index a949c88e5f..9f424d3dcf 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts
@@ -19,8 +19,10 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPAINT_GRAPH,
CANVAS_OUTPUT,
+ CANVAS_COHERENCE_DENOISE_LATENTS,
+ CANVAS_COHERENCE_NOISE,
+ CANVAS_COHERENCE_NOISE_INCREMENT,
CLIP_SKIP,
- COLOR_CORRECT,
DENOISE_LATENTS,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
@@ -32,7 +34,6 @@ import {
MAIN_MODEL_LOADER,
MASK_BLUR,
MASK_COMBINE,
- MASK_EDGE,
MASK_FROM_ALPHA,
MASK_RESIZE_DOWN,
MASK_RESIZE_UP,
@@ -41,10 +42,6 @@ import {
POSITIVE_CONDITIONING,
RANDOM_INT,
RANGE_OF_SIZE,
- SEAM_FIX_DENOISE_LATENTS,
- SEAM_MASK_COMBINE,
- SEAM_MASK_RESIZE_DOWN,
- SEAM_MASK_RESIZE_UP,
} from './constants';
/**
@@ -72,12 +69,8 @@ export const buildCanvasOutpaintGraph = (
shouldUseCpuNoise,
maskBlur,
maskBlurMethod,
- seamSize,
- seamBlur,
- seamSteps,
- seamStrength,
- seamLowThreshold,
- seamHighThreshold,
+ canvasCoherenceSteps,
+ canvasCoherenceStrength,
tileSize,
infillMethod,
clipSkip,
@@ -141,11 +134,6 @@ export const buildCanvasOutpaintGraph = (
is_intermediate: true,
mask2: canvasMaskImage,
},
- [SEAM_MASK_COMBINE]: {
- type: 'mask_combine',
- id: MASK_COMBINE,
- is_intermediate: true,
- },
[MASK_BLUR]: {
type: 'img_blur',
id: MASK_BLUR,
@@ -153,12 +141,6 @@ export const buildCanvasOutpaintGraph = (
radius: maskBlur,
blur_type: maskBlurMethod,
},
- [INPAINT_INFILL]: {
- type: 'infill_tile',
- id: INPAINT_INFILL,
- is_intermediate: true,
- tile_size: tileSize,
- },
[INPAINT_IMAGE]: {
type: 'i2l',
id: INPAINT_IMAGE,
@@ -181,23 +163,26 @@ export const buildCanvasOutpaintGraph = (
denoising_start: 1 - strength,
denoising_end: 1,
},
- [MASK_EDGE]: {
- type: 'mask_edge',
- id: MASK_EDGE,
+ [CANVAS_COHERENCE_NOISE]: {
+ type: 'noise',
+ id: NOISE,
+ use_cpu,
is_intermediate: true,
- edge_size: seamSize,
- edge_blur: seamBlur,
- low_threshold: seamLowThreshold,
- high_threshold: seamHighThreshold,
},
- [SEAM_FIX_DENOISE_LATENTS]: {
- type: 'denoise_latents',
- id: SEAM_FIX_DENOISE_LATENTS,
+ [CANVAS_COHERENCE_NOISE_INCREMENT]: {
+ type: 'add',
+ id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ b: 1,
is_intermediate: true,
- steps: seamSteps,
+ },
+ [CANVAS_COHERENCE_DENOISE_LATENTS]: {
+ type: 'denoise_latents',
+ id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ is_intermediate: true,
+ steps: canvasCoherenceSteps,
cfg_scale: cfg_scale,
scheduler: scheduler,
- denoising_start: 1 - seamStrength,
+ denoising_start: 1 - canvasCoherenceStrength,
denoising_end: 1,
},
[LATENTS_TO_IMAGE]: {
@@ -206,13 +191,8 @@ export const buildCanvasOutpaintGraph = (
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
- [COLOR_CORRECT]: {
- type: 'color_correct',
- id: COLOR_CORRECT,
- is_intermediate: true,
- },
[CANVAS_OUTPUT]: {
- type: 'img_paste',
+ type: 'color_correct',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
},
@@ -368,14 +348,34 @@ export const buildCanvasOutpaintGraph = (
field: 'seed',
},
},
- // Seam Paint
+ // Canvas Refine
+ {
+ source: {
+ node_id: ITERATE,
+ field: 'item',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'a',
+ },
+ },
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'value',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE,
+ field: 'seed',
+ },
+ },
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'unet',
},
},
@@ -385,7 +385,7 @@ export const buildCanvasOutpaintGraph = (
field: 'conditioning',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'positive_conditioning',
},
},
@@ -395,17 +395,17 @@ export const buildCanvasOutpaintGraph = (
field: 'conditioning',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'negative_conditioning',
},
},
{
source: {
- node_id: NOISE,
+ node_id: CANVAS_COHERENCE_NOISE,
field: 'noise',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'noise',
},
},
@@ -415,14 +415,14 @@ export const buildCanvasOutpaintGraph = (
field: 'latents',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'latents',
},
},
// Decode the result from Inpaint
{
source: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'latents',
},
destination: {
@@ -442,6 +442,23 @@ export const buildCanvasOutpaintGraph = (
};
}
+ if (infillMethod === 'lama') {
+ graph.nodes[INPAINT_INFILL] = {
+ type: 'infill_lama',
+ id: INPAINT_INFILL,
+ is_intermediate: true,
+ };
+ }
+
+ if (infillMethod === 'tile') {
+ graph.nodes[INPAINT_INFILL] = {
+ type: 'infill_tile',
+ id: INPAINT_INFILL,
+ is_intermediate: true,
+ tile_size: tileSize,
+ };
+ }
+
// Handle Scale Before Processing
if (['auto', 'manual'].includes(boundingBoxScaleMethod)) {
const scaledWidth: number = scaledBoundingBoxDimensions.width;
@@ -463,13 +480,6 @@ export const buildCanvasOutpaintGraph = (
width: scaledWidth,
height: scaledHeight,
};
- graph.nodes[SEAM_MASK_RESIZE_UP] = {
- type: 'img_resize',
- id: SEAM_MASK_RESIZE_UP,
- is_intermediate: true,
- width: scaledWidth,
- height: scaledHeight,
- };
graph.nodes[INPAINT_IMAGE_RESIZE_DOWN] = {
type: 'img_resize',
id: INPAINT_IMAGE_RESIZE_DOWN,
@@ -491,19 +501,13 @@ export const buildCanvasOutpaintGraph = (
width: width,
height: height,
};
- graph.nodes[SEAM_MASK_RESIZE_DOWN] = {
- type: 'img_resize',
- id: SEAM_MASK_RESIZE_DOWN,
- is_intermediate: true,
- width: width,
- height: height,
- };
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: scaledWidth,
- height: scaledHeight,
- };
+ (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth;
+ (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width =
+ scaledWidth;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height =
+ scaledHeight;
// Connect Nodes
graph.edges.push(
@@ -539,57 +543,6 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
},
- // Seam Paint Mask
- {
- source: {
- node_id: MASK_FROM_ALPHA,
- field: 'image',
- },
- destination: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- },
- {
- source: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_RESIZE_UP,
- field: 'image',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_RESIZE_UP,
- field: 'image',
- },
- destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
- field: 'mask',
- },
- },
- {
- source: {
- node_id: MASK_BLUR,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask1',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_RESIZE_UP,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask2',
- },
- },
// Resize Results Down
{
source: {
@@ -611,16 +564,6 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
},
- {
- source: {
- node_id: SEAM_MASK_COMBINE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_RESIZE_DOWN,
- field: 'image',
- },
- },
{
source: {
node_id: INPAINT_INFILL,
@@ -638,7 +581,7 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
destination: {
- node_id: COLOR_CORRECT,
+ node_id: CANVAS_OUTPUT,
field: 'reference',
},
},
@@ -647,37 +590,6 @@ export const buildCanvasOutpaintGraph = (
node_id: INPAINT_IMAGE_RESIZE_DOWN,
field: 'image',
},
- destination: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_RESIZE_DOWN,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Everything Back
- {
- source: {
- node_id: INPAINT_INFILL_RESIZE_DOWN,
- field: 'image',
- },
- destination: {
- node_id: CANVAS_OUTPUT,
- field: 'base_image',
- },
- },
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
@@ -685,7 +597,7 @@ export const buildCanvasOutpaintGraph = (
},
{
source: {
- node_id: SEAM_MASK_RESIZE_DOWN,
+ node_id: MASK_RESIZE_DOWN,
field: 'image',
},
destination: {
@@ -702,11 +614,12 @@ export const buildCanvasOutpaintGraph = (
| InfillPatchMatchInvocation),
image: canvasInitImage,
};
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: width,
- height: height,
- };
+
+ (graph.nodes[NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[NOISE] as NoiseInvocation).height = height;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height;
+
graph.nodes[INPAINT_IMAGE] = {
...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation),
image: canvasInitImage,
@@ -727,47 +640,6 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
},
- // Seam Paint Mask
- {
- source: {
- node_id: MASK_FROM_ALPHA,
- field: 'image',
- },
- destination: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- },
- {
- source: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
- field: 'mask',
- },
- },
- {
- source: {
- node_id: MASK_FROM_ALPHA,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask1',
- },
- },
- {
- source: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask2',
- },
- },
// Color Correct The Inpainted Result
{
source: {
@@ -775,7 +647,7 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
destination: {
- node_id: COLOR_CORRECT,
+ node_id: CANVAS_OUTPUT,
field: 'reference',
},
},
@@ -784,37 +656,6 @@ export const buildCanvasOutpaintGraph = (
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
- destination: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_COMBINE,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Everything Back
- {
- source: {
- node_id: INPAINT_INFILL,
- field: 'image',
- },
- destination: {
- node_id: CANVAS_OUTPUT,
- field: 'base_image',
- },
- },
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
@@ -822,7 +663,7 @@ export const buildCanvasOutpaintGraph = (
},
{
source: {
- node_id: SEAM_MASK_COMBINE,
+ node_id: MASK_BLUR,
field: 'image',
},
destination: {
@@ -845,7 +686,7 @@ export const buildCanvasOutpaintGraph = (
// Connect random int to the start of the range of size so the range starts on the random first seed
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: RANGE_OF_SIZE, field: 'start' },
});
} else {
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts
index ba40a70c83..f60c710c64 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts
@@ -17,7 +17,9 @@ import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
- COLOR_CORRECT,
+ CANVAS_COHERENCE_DENOISE_LATENTS,
+ CANVAS_COHERENCE_NOISE,
+ CANVAS_COHERENCE_NOISE_INCREMENT,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
INPAINT_IMAGE_RESIZE_UP,
@@ -61,6 +63,8 @@ export const buildCanvasSDXLInpaintGraph = (
shouldUseCpuNoise,
maskBlur,
maskBlurMethod,
+ canvasCoherenceSteps,
+ canvasCoherenceStrength,
} = state.generation;
const {
@@ -144,23 +148,39 @@ export const buildCanvasSDXLInpaintGraph = (
: 1 - strength,
denoising_end: shouldUseSDXLRefiner ? refinerStart : 1,
},
+ [CANVAS_COHERENCE_NOISE]: {
+ type: 'noise',
+ id: NOISE,
+ use_cpu,
+ is_intermediate: true,
+ },
+ [CANVAS_COHERENCE_NOISE_INCREMENT]: {
+ type: 'add',
+ id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ b: 1,
+ is_intermediate: true,
+ },
+ [CANVAS_COHERENCE_DENOISE_LATENTS]: {
+ type: 'denoise_latents',
+ id: SDXL_DENOISE_LATENTS,
+ is_intermediate: true,
+ steps: canvasCoherenceSteps,
+ cfg_scale: cfg_scale,
+ scheduler: scheduler,
+ denoising_start: 1 - canvasCoherenceStrength,
+ denoising_end: 1,
+ },
[LATENTS_TO_IMAGE]: {
type: 'l2i',
id: LATENTS_TO_IMAGE,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
- [COLOR_CORRECT]: {
- type: 'color_correct',
- id: COLOR_CORRECT,
- is_intermediate: true,
- reference: canvasInitImage,
- },
[CANVAS_OUTPUT]: {
- type: 'img_paste',
+ type: 'color_correct',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
- base_image: canvasInitImage,
+ reference: canvasInitImage,
},
[RANGE_OF_SIZE]: {
type: 'range_of_size',
@@ -301,12 +321,83 @@ export const buildCanvasSDXLInpaintGraph = (
field: 'seed',
},
},
- // Decode inpainted latents to image
+ // Canvas Refine
+ {
+ source: {
+ node_id: ITERATE,
+ field: 'item',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'a',
+ },
+ },
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'value',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE,
+ field: 'seed',
+ },
+ },
+ {
+ source: {
+ node_id: SDXL_MODEL_LOADER,
+ field: 'unet',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'unet',
+ },
+ },
+ {
+ source: {
+ node_id: POSITIVE_CONDITIONING,
+ field: 'conditioning',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'positive_conditioning',
+ },
+ },
+ {
+ source: {
+ node_id: NEGATIVE_CONDITIONING,
+ field: 'conditioning',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'negative_conditioning',
+ },
+ },
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_NOISE,
+ field: 'noise',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'noise',
+ },
+ },
{
source: {
node_id: SDXL_DENOISE_LATENTS,
field: 'latents',
},
+ destination: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'latents',
+ },
+ },
+ // Decode Inpainted Latents To Image
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ field: 'latents',
+ },
destination: {
node_id: LATENTS_TO_IMAGE,
field: 'latents',
@@ -352,11 +443,12 @@ export const buildCanvasSDXLInpaintGraph = (
height: height,
};
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: scaledWidth,
- height: scaledHeight,
- };
+ (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth;
+ (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width =
+ scaledWidth;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height =
+ scaledHeight;
// Connect Nodes
graph.edges.push(
@@ -398,7 +490,7 @@ export const buildCanvasSDXLInpaintGraph = (
field: 'image',
},
destination: {
- node_id: COLOR_CORRECT,
+ node_id: CANVAS_OUTPUT,
field: 'image',
},
},
@@ -412,27 +504,6 @@ export const buildCanvasSDXLInpaintGraph = (
field: 'image',
},
},
- {
- source: {
- node_id: MASK_RESIZE_DOWN,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Back Onto Original Image
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- destination: {
- node_id: CANVAS_OUTPUT,
- field: 'image',
- },
- },
{
source: {
node_id: MASK_RESIZE_DOWN,
@@ -446,11 +517,11 @@ export const buildCanvasSDXLInpaintGraph = (
);
} else {
// Add Images To Nodes
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: width,
- height: height,
- };
+ (graph.nodes[NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[NOISE] as NoiseInvocation).height = height;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height;
+
graph.nodes[INPAINT_IMAGE] = {
...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation),
image: canvasInitImage,
@@ -467,27 +538,6 @@ export const buildCanvasSDXLInpaintGraph = (
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
- destination: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- },
- {
- source: {
- node_id: MASK_BLUR,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Back Onto Original Image
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
@@ -518,7 +568,7 @@ export const buildCanvasSDXLInpaintGraph = (
// Connect random int to the start of the range of size so the range starts on the random first seed
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: RANGE_OF_SIZE, field: 'start' },
});
} else {
@@ -528,7 +578,7 @@ export const buildCanvasSDXLInpaintGraph = (
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
- addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS);
+ addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS);
}
// optionally add custom VAE
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts
index 1cc268c03d..7e98c37233 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts
@@ -19,7 +19,9 @@ import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
- COLOR_CORRECT,
+ CANVAS_COHERENCE_DENOISE_LATENTS,
+ CANVAS_COHERENCE_NOISE,
+ CANVAS_COHERENCE_NOISE_INCREMENT,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
INPAINT_IMAGE_RESIZE_UP,
@@ -29,7 +31,6 @@ import {
LATENTS_TO_IMAGE,
MASK_BLUR,
MASK_COMBINE,
- MASK_EDGE,
MASK_FROM_ALPHA,
MASK_RESIZE_DOWN,
MASK_RESIZE_UP,
@@ -41,10 +42,6 @@ import {
SDXL_CANVAS_OUTPAINT_GRAPH,
SDXL_DENOISE_LATENTS,
SDXL_MODEL_LOADER,
- SEAM_FIX_DENOISE_LATENTS,
- SEAM_MASK_COMBINE,
- SEAM_MASK_RESIZE_DOWN,
- SEAM_MASK_RESIZE_UP,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -72,12 +69,8 @@ export const buildCanvasSDXLOutpaintGraph = (
shouldUseCpuNoise,
maskBlur,
maskBlurMethod,
- seamSize,
- seamBlur,
- seamSteps,
- seamStrength,
- seamLowThreshold,
- seamHighThreshold,
+ canvasCoherenceSteps,
+ canvasCoherenceStrength,
tileSize,
infillMethod,
} = state.generation;
@@ -144,11 +137,6 @@ export const buildCanvasSDXLOutpaintGraph = (
is_intermediate: true,
mask2: canvasMaskImage,
},
- [SEAM_MASK_COMBINE]: {
- type: 'mask_combine',
- id: MASK_COMBINE,
- is_intermediate: true,
- },
[MASK_BLUR]: {
type: 'img_blur',
id: MASK_BLUR,
@@ -156,12 +144,6 @@ export const buildCanvasSDXLOutpaintGraph = (
radius: maskBlur,
blur_type: maskBlurMethod,
},
- [INPAINT_INFILL]: {
- type: 'infill_tile',
- id: INPAINT_INFILL,
- is_intermediate: true,
- tile_size: tileSize,
- },
[INPAINT_IMAGE]: {
type: 'i2l',
id: INPAINT_IMAGE,
@@ -186,23 +168,26 @@ export const buildCanvasSDXLOutpaintGraph = (
: 1 - strength,
denoising_end: shouldUseSDXLRefiner ? refinerStart : 1,
},
- [MASK_EDGE]: {
- type: 'mask_edge',
- id: MASK_EDGE,
+ [CANVAS_COHERENCE_NOISE]: {
+ type: 'noise',
+ id: NOISE,
+ use_cpu,
is_intermediate: true,
- edge_size: seamSize,
- edge_blur: seamBlur,
- low_threshold: seamLowThreshold,
- high_threshold: seamHighThreshold,
},
- [SEAM_FIX_DENOISE_LATENTS]: {
- type: 'denoise_latents',
- id: SEAM_FIX_DENOISE_LATENTS,
+ [CANVAS_COHERENCE_NOISE_INCREMENT]: {
+ type: 'add',
+ id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ b: 1,
is_intermediate: true,
- steps: seamSteps,
+ },
+ [CANVAS_COHERENCE_DENOISE_LATENTS]: {
+ type: 'denoise_latents',
+ id: CANVAS_COHERENCE_DENOISE_LATENTS,
+ is_intermediate: true,
+ steps: canvasCoherenceSteps,
cfg_scale: cfg_scale,
scheduler: scheduler,
- denoising_start: 1 - seamStrength,
+ denoising_start: 1 - canvasCoherenceStrength,
denoising_end: 1,
},
[LATENTS_TO_IMAGE]: {
@@ -211,13 +196,8 @@ export const buildCanvasSDXLOutpaintGraph = (
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
- [COLOR_CORRECT]: {
- type: 'color_correct',
- id: COLOR_CORRECT,
- is_intermediate: true,
- },
[CANVAS_OUTPUT]: {
- type: 'img_paste',
+ type: 'color_correct',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
},
@@ -382,14 +362,34 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'seed',
},
},
- // Seam Paint
+ // Canvas Refine
+ {
+ source: {
+ node_id: ITERATE,
+ field: 'item',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'a',
+ },
+ },
+ {
+ source: {
+ node_id: CANVAS_COHERENCE_NOISE_INCREMENT,
+ field: 'value',
+ },
+ destination: {
+ node_id: CANVAS_COHERENCE_NOISE,
+ field: 'seed',
+ },
+ },
{
source: {
node_id: SDXL_MODEL_LOADER,
field: 'unet',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'unet',
},
},
@@ -399,7 +399,7 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'conditioning',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'positive_conditioning',
},
},
@@ -409,17 +409,17 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'conditioning',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'negative_conditioning',
},
},
{
source: {
- node_id: NOISE,
+ node_id: CANVAS_COHERENCE_NOISE,
field: 'noise',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'noise',
},
},
@@ -429,14 +429,14 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'latents',
},
destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'latents',
},
},
// Decode inpainted latents to image
{
source: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
+ node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'latents',
},
destination: {
@@ -457,6 +457,23 @@ export const buildCanvasSDXLOutpaintGraph = (
};
}
+ if (infillMethod === 'lama') {
+ graph.nodes[INPAINT_INFILL] = {
+ type: 'infill_lama',
+ id: INPAINT_INFILL,
+ is_intermediate: true,
+ };
+ }
+
+ if (infillMethod === 'tile') {
+ graph.nodes[INPAINT_INFILL] = {
+ type: 'infill_tile',
+ id: INPAINT_INFILL,
+ is_intermediate: true,
+ tile_size: tileSize,
+ };
+ }
+
// Handle Scale Before Processing
if (['auto', 'manual'].includes(boundingBoxScaleMethod)) {
const scaledWidth: number = scaledBoundingBoxDimensions.width;
@@ -478,13 +495,6 @@ export const buildCanvasSDXLOutpaintGraph = (
width: scaledWidth,
height: scaledHeight,
};
- graph.nodes[SEAM_MASK_RESIZE_UP] = {
- type: 'img_resize',
- id: SEAM_MASK_RESIZE_UP,
- is_intermediate: true,
- width: scaledWidth,
- height: scaledHeight,
- };
graph.nodes[INPAINT_IMAGE_RESIZE_DOWN] = {
type: 'img_resize',
id: INPAINT_IMAGE_RESIZE_DOWN,
@@ -506,19 +516,13 @@ export const buildCanvasSDXLOutpaintGraph = (
width: width,
height: height,
};
- graph.nodes[SEAM_MASK_RESIZE_DOWN] = {
- type: 'img_resize',
- id: SEAM_MASK_RESIZE_DOWN,
- is_intermediate: true,
- width: width,
- height: height,
- };
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: scaledWidth,
- height: scaledHeight,
- };
+ (graph.nodes[NOISE] as NoiseInvocation).width = scaledWidth;
+ (graph.nodes[NOISE] as NoiseInvocation).height = scaledHeight;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width =
+ scaledWidth;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height =
+ scaledHeight;
// Connect Nodes
graph.edges.push(
@@ -554,57 +558,6 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
},
- // Seam Paint Mask
- {
- source: {
- node_id: MASK_FROM_ALPHA,
- field: 'image',
- },
- destination: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- },
- {
- source: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_RESIZE_UP,
- field: 'image',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_RESIZE_UP,
- field: 'image',
- },
- destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
- field: 'mask',
- },
- },
- {
- source: {
- node_id: MASK_BLUR,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask1',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_RESIZE_UP,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask2',
- },
- },
// Resize Results Down
{
source: {
@@ -626,16 +579,6 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
},
- {
- source: {
- node_id: SEAM_MASK_COMBINE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_RESIZE_DOWN,
- field: 'image',
- },
- },
{
source: {
node_id: INPAINT_INFILL,
@@ -653,7 +596,7 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
destination: {
- node_id: COLOR_CORRECT,
+ node_id: CANVAS_OUTPUT,
field: 'reference',
},
},
@@ -662,37 +605,6 @@ export const buildCanvasSDXLOutpaintGraph = (
node_id: INPAINT_IMAGE_RESIZE_DOWN,
field: 'image',
},
- destination: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_RESIZE_DOWN,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Everything Back
- {
- source: {
- node_id: INPAINT_INFILL_RESIZE_DOWN,
- field: 'image',
- },
- destination: {
- node_id: CANVAS_OUTPUT,
- field: 'base_image',
- },
- },
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
@@ -700,7 +612,7 @@ export const buildCanvasSDXLOutpaintGraph = (
},
{
source: {
- node_id: SEAM_MASK_RESIZE_DOWN,
+ node_id: MASK_RESIZE_DOWN,
field: 'image',
},
destination: {
@@ -717,11 +629,12 @@ export const buildCanvasSDXLOutpaintGraph = (
| InfillPatchMatchInvocation),
image: canvasInitImage,
};
- graph.nodes[NOISE] = {
- ...(graph.nodes[NOISE] as NoiseInvocation),
- width: width,
- height: height,
- };
+
+ (graph.nodes[NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[NOISE] as NoiseInvocation).height = height;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).width = width;
+ (graph.nodes[CANVAS_COHERENCE_NOISE] as NoiseInvocation).height = height;
+
graph.nodes[INPAINT_IMAGE] = {
...(graph.nodes[INPAINT_IMAGE] as ImageToLatentsInvocation),
image: canvasInitImage,
@@ -742,47 +655,6 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
},
- // Seam Paint Mask
- {
- source: {
- node_id: MASK_FROM_ALPHA,
- field: 'image',
- },
- destination: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- },
- {
- source: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_FIX_DENOISE_LATENTS,
- field: 'mask',
- },
- },
- {
- source: {
- node_id: MASK_FROM_ALPHA,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask1',
- },
- },
- {
- source: {
- node_id: MASK_EDGE,
- field: 'image',
- },
- destination: {
- node_id: SEAM_MASK_COMBINE,
- field: 'mask2',
- },
- },
// Color Correct The Inpainted Result
{
source: {
@@ -790,7 +662,7 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
destination: {
- node_id: COLOR_CORRECT,
+ node_id: CANVAS_OUTPUT,
field: 'reference',
},
},
@@ -799,37 +671,6 @@ export const buildCanvasSDXLOutpaintGraph = (
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
- destination: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
- },
- {
- source: {
- node_id: SEAM_MASK_COMBINE,
- field: 'image',
- },
- destination: {
- node_id: COLOR_CORRECT,
- field: 'mask',
- },
- },
- // Paste Everything Back
- {
- source: {
- node_id: INPAINT_INFILL,
- field: 'image',
- },
- destination: {
- node_id: CANVAS_OUTPUT,
- field: 'base_image',
- },
- },
- {
- source: {
- node_id: COLOR_CORRECT,
- field: 'image',
- },
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
@@ -837,7 +678,7 @@ export const buildCanvasSDXLOutpaintGraph = (
},
{
source: {
- node_id: SEAM_MASK_COMBINE,
+ node_id: MASK_BLUR,
field: 'image',
},
destination: {
@@ -860,7 +701,7 @@ export const buildCanvasSDXLOutpaintGraph = (
// Connect random int to the start of the range of size so the range starts on the random first seed
graph.edges.push({
- source: { node_id: RANDOM_INT, field: 'a' },
+ source: { node_id: RANDOM_INT, field: 'value' },
destination: { node_id: RANGE_OF_SIZE, field: 'start' },
});
} else {
@@ -870,7 +711,7 @@ export const buildCanvasSDXLOutpaintGraph = (
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
- addSDXLRefinerToGraph(state, graph, SEAM_FIX_DENOISE_LATENTS);
+ addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS);
}
// optionally add custom VAE
diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts
index 1f6acd4e26..6547d4a092 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/constants.ts
@@ -25,14 +25,15 @@ export const INPAINT_IMAGE_RESIZE_DOWN = 'inpaint_image_resize_down';
export const INPAINT_INFILL = 'inpaint_infill';
export const INPAINT_INFILL_RESIZE_DOWN = 'inpaint_infill_resize_down';
export const INPAINT_FINAL_IMAGE = 'inpaint_final_image';
-export const SEAM_FIX_DENOISE_LATENTS = 'seam_fix_denoise_latents';
+export const CANVAS_COHERENCE_DENOISE_LATENTS =
+ 'canvas_coherence_denoise_latents';
+export const CANVAS_COHERENCE_NOISE = 'canvas_coherence_noise';
+export const CANVAS_COHERENCE_NOISE_INCREMENT =
+ 'canvas_coherence_noise_increment';
export const MASK_FROM_ALPHA = 'tomask';
export const MASK_EDGE = 'mask_edge';
export const MASK_BLUR = 'mask_blur';
export const MASK_COMBINE = 'mask_combine';
-export const SEAM_MASK_COMBINE = 'seam_mask_combine';
-export const SEAM_MASK_RESIZE_UP = 'seam_mask_resize_up';
-export const SEAM_MASK_RESIZE_DOWN = 'seam_mask_resize_down';
export const MASK_RESIZE_UP = 'mask_resize_up';
export const MASK_RESIZE_DOWN = 'mask_resize_down';
export const COLOR_CORRECT = 'color_correct';
diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts
index 19201b23bb..4bbb754d58 100644
--- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts
@@ -1,83 +1,169 @@
-import { filter, reduce } from 'lodash-es';
+import { logger } from 'app/logging/logger';
+import { parseify } from 'common/util/serialize';
+import { reduce } from 'lodash-es';
import { OpenAPIV3 } from 'openapi-types';
+import { AnyInvocationType } from 'services/events/types';
import {
InputFieldTemplate,
InvocationSchemaObject,
InvocationTemplate,
+ OutputFieldTemplate,
isInvocationFieldSchema,
+ isInvocationOutputSchemaObject,
isInvocationSchemaObject,
} from '../types/types';
-import {
- buildInputFieldTemplate,
- buildOutputFieldTemplates,
-} from './fieldTemplateBuilders';
+import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders';
-const RESERVED_FIELD_NAMES = ['id', 'type', 'metadata'];
+const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata'];
+const RESERVED_OUTPUT_FIELD_NAMES = ['type'];
-const invocationDenylist = [
- 'Graph',
- 'InvocationMeta',
- 'MetadataAccumulatorInvocation',
+const invocationDenylist: AnyInvocationType[] = [
+ 'graph',
+ 'metadata_accumulator',
];
+const isAllowedInputField = (nodeType: string, fieldName: string) => {
+ if (RESERVED_INPUT_FIELD_NAMES.includes(fieldName)) {
+ return false;
+ }
+ if (nodeType === 'collect' && fieldName === 'collection') {
+ return false;
+ }
+ if (nodeType === 'iterate' && fieldName === 'index') {
+ return false;
+ }
+ return true;
+};
+
+const isAllowedOutputField = (nodeType: string, fieldName: string) => {
+ if (RESERVED_OUTPUT_FIELD_NAMES.includes(fieldName)) {
+ return false;
+ }
+ return true;
+};
+
+const isNotInDenylist = (schema: InvocationSchemaObject) =>
+ !invocationDenylist.includes(schema.properties.type.default);
+
export const parseSchema = (
openAPI: OpenAPIV3.Document
): Record => {
- const filteredSchemas = filter(
- openAPI.components?.schemas,
- (schema, key) =>
- key.includes('Invocation') &&
- !key.includes('InvocationOutput') &&
- !invocationDenylist.some((denylistItem) => key.includes(denylistItem))
- ) as (OpenAPIV3.ReferenceObject | InvocationSchemaObject)[];
+ const filteredSchemas = Object.values(openAPI.components?.schemas ?? {})
+ .filter(isInvocationSchemaObject)
+ .filter(isNotInDenylist);
const invocations = filteredSchemas.reduce<
Record
>((acc, schema) => {
- if (isInvocationSchemaObject(schema)) {
- const type = schema.properties.type.default;
- const title = schema.ui?.title ?? schema.title.replace('Invocation', '');
- const tags = schema.ui?.tags ?? [];
- const description = schema.description ?? '';
+ const type = schema.properties.type.default;
+ const title = schema.title.replace('Invocation', '');
+ const tags = schema.tags ?? [];
+ const description = schema.description ?? '';
- const inputs = reduce(
- schema.properties,
- (inputsAccumulator, property, propertyName) => {
- if (
- !RESERVED_FIELD_NAMES.includes(propertyName) &&
- isInvocationFieldSchema(property) &&
- !property.ui_hidden
- ) {
- const field = buildInputFieldTemplate(
- schema,
- property,
- propertyName
- );
-
- if (field) {
- inputsAccumulator[propertyName] = field;
- }
- }
+ const inputs = reduce(
+ schema.properties,
+ (inputsAccumulator, property, propertyName) => {
+ if (!isAllowedInputField(type, propertyName)) {
+ logger('nodes').trace(
+ { type, propertyName, property: parseify(property) },
+ 'Skipped reserved input field'
+ );
return inputsAccumulator;
- },
- {} as Record
+ }
+
+ if (!isInvocationFieldSchema(property)) {
+ logger('nodes').warn(
+ { type, propertyName, property: parseify(property) },
+ 'Unhandled input property'
+ );
+ return inputsAccumulator;
+ }
+
+ const field = buildInputFieldTemplate(schema, property, propertyName);
+
+ if (field) {
+ inputsAccumulator[propertyName] = field;
+ }
+
+ return inputsAccumulator;
+ },
+ {} as Record
+ );
+
+ const outputSchemaName = schema.output.$ref.split('/').pop();
+
+ if (!outputSchemaName) {
+ logger('nodes').error(
+ { outputRefObject: parseify(schema.output) },
+ 'No output schema name found in ref object'
);
-
- const rawOutput = (schema as InvocationSchemaObject).output;
- const outputs = buildOutputFieldTemplates(rawOutput, openAPI);
-
- const invocation: InvocationTemplate = {
- title,
- type,
- tags,
- description,
- inputs,
- outputs,
- };
-
- Object.assign(acc, { [type]: invocation });
+ throw 'No output schema name found in ref object';
}
+ const outputSchema = openAPI.components?.schemas?.[outputSchemaName];
+ if (!outputSchema) {
+ logger('nodes').error({ outputSchemaName }, 'Output schema not found');
+ throw 'Output schema not found';
+ }
+
+ if (!isInvocationOutputSchemaObject(outputSchema)) {
+ logger('nodes').error(
+ { outputSchema: parseify(outputSchema) },
+ 'Invalid output schema'
+ );
+ throw 'Invalid output schema';
+ }
+
+ const outputType = outputSchema.properties.type.default;
+
+ const outputs = reduce(
+ outputSchema.properties,
+ (outputsAccumulator, property, propertyName) => {
+ if (!isAllowedOutputField(type, propertyName)) {
+ logger('nodes').trace(
+ { type, propertyName, property: parseify(property) },
+ 'Skipped reserved output field'
+ );
+ return outputsAccumulator;
+ }
+
+ if (!isInvocationFieldSchema(property)) {
+ logger('nodes').warn(
+ { type, propertyName, property: parseify(property) },
+ 'Unhandled output property'
+ );
+ return outputsAccumulator;
+ }
+
+ const fieldType = getFieldType(property);
+ outputsAccumulator[propertyName] = {
+ fieldKind: 'output',
+ name: propertyName,
+ title: property.title ?? '',
+ description: property.description ?? '',
+ type: fieldType,
+ ui_hidden: property.ui_hidden ?? false,
+ ui_type: property.ui_type,
+ ui_order: property.ui_order,
+ };
+
+ return outputsAccumulator;
+ },
+ {} as Record
+ );
+
+ const invocation: InvocationTemplate = {
+ title,
+ type,
+ tags,
+ description,
+ inputs,
+ outputs,
+ outputType,
+ };
+
+ Object.assign(acc, { [type]: invocation });
+
return acc;
}, {});
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx
index 66c76ae7cb..bca1402571 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx
@@ -28,7 +28,7 @@ export default function ParamAdvancedCollapse() {
}
return (
-
+
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx
index 511e90f0f3..eeef340324 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx
@@ -1,5 +1,6 @@
import { Box } from '@chakra-ui/react';
import { useCanvasGenerationMode } from 'features/canvas/hooks/useCanvasGenerationMode';
+import { memo } from 'react';
const GENERATION_MODE_NAME_MAP = {
txt2img: 'Text to Image',
@@ -18,4 +19,4 @@ const GenerationModeStatusText = () => {
);
};
-export default GenerationModeStatusText;
+export default memo(GenerationModeStatusText);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx
index 9ac0e3588f..2a8f1ece69 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx
@@ -27,7 +27,9 @@ const ParamInfillMethod = () => {
const { data: appConfigData, isLoading } = useGetAppConfigQuery();
- const infill_methods = appConfigData?.infill_methods;
+ const infill_methods = appConfigData?.infill_methods.filter(
+ (method) => method !== 'lama'
+ );
const { t } = useTranslation();
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskBlurMethod.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskBlurMethod.tsx
index fa20dcdbcc..62d0605640 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskBlurMethod.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/MaskAdjustment/ParamMaskBlurMethod.tsx
@@ -21,7 +21,9 @@ export default function ParamMaskBlurMethod() {
const { t } = useTranslation();
const handleMaskBlurMethodChange = (v: string | null) => {
- if (!v) return;
+ if (!v) {
+ return;
+ }
dispatch(setMaskBlurMethod(v as MaskBlurMethods));
};
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse.tsx
new file mode 100644
index 0000000000..b454c4ccec
--- /dev/null
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse.tsx
@@ -0,0 +1,21 @@
+import { Flex } from '@chakra-ui/react';
+import IAICollapse from 'common/components/IAICollapse';
+import { memo } from 'react';
+import { useTranslation } from 'react-i18next';
+import ParamCanvasCoherenceSteps from './ParamCanvasCoherenceSteps';
+import ParamCanvasCoherenceStrength from './ParamCanvasCoherenceStrength';
+
+const ParamCanvasCoherencePassCollapse = () => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default memo(ParamCanvasCoherencePassCollapse);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSteps.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceSteps.tsx
similarity index 54%
rename from invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSteps.tsx
rename to invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceSteps.tsx
index e69339dbfe..5482a7e1d9 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSteps.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceSteps.tsx
@@ -1,36 +1,36 @@
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
-import { setSeamSteps } from 'features/parameters/store/generationSlice';
+import { setCanvasCoherenceSteps } from 'features/parameters/store/generationSlice';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
-const ParamSeamSteps = () => {
+const ParamCanvasCoherenceSteps = () => {
const dispatch = useAppDispatch();
- const seamSteps = useAppSelector(
- (state: RootState) => state.generation.seamSteps
+ const canvasCoherenceSteps = useAppSelector(
+ (state: RootState) => state.generation.canvasCoherenceSteps
);
const { t } = useTranslation();
return (
{
- dispatch(setSeamSteps(v));
+ dispatch(setCanvasCoherenceSteps(v));
}}
withInput
withSliderMarks
withReset
handleReset={() => {
- dispatch(setSeamSteps(20));
+ dispatch(setCanvasCoherenceSteps(20));
}}
/>
);
};
-export default memo(ParamSeamSteps);
+export default memo(ParamCanvasCoherenceSteps);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceStrength.tsx
similarity index 54%
rename from invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamStrength.tsx
rename to invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceStrength.tsx
index 3f0fa01fcb..f478bd70fe 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamStrength.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherenceStrength.tsx
@@ -1,36 +1,36 @@
import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
-import { setSeamStrength } from 'features/parameters/store/generationSlice';
+import { setCanvasCoherenceStrength } from 'features/parameters/store/generationSlice';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
-const ParamSeamStrength = () => {
+const ParamCanvasCoherenceStrength = () => {
const dispatch = useAppDispatch();
- const seamStrength = useAppSelector(
- (state: RootState) => state.generation.seamStrength
+ const canvasCoherenceStrength = useAppSelector(
+ (state: RootState) => state.generation.canvasCoherenceStrength
);
const { t } = useTranslation();
return (
{
- dispatch(setSeamStrength(v));
+ dispatch(setCanvasCoherenceStrength(v));
}}
withInput
withSliderMarks
withReset
handleReset={() => {
- dispatch(setSeamStrength(0.7));
+ dispatch(setCanvasCoherenceStrength(0.3));
}}
/>
);
};
-export default memo(ParamSeamStrength);
+export default memo(ParamCanvasCoherenceStrength);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamBlur.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamBlur.tsx
deleted file mode 100644
index 2ab048ce72..0000000000
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamBlur.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import type { RootState } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAISlider from 'common/components/IAISlider';
-import { setSeamBlur } from 'features/parameters/store/generationSlice';
-import { memo } from 'react';
-import { useTranslation } from 'react-i18next';
-
-const ParamSeamBlur = () => {
- const dispatch = useAppDispatch();
- const seamBlur = useAppSelector(
- (state: RootState) => state.generation.seamBlur
- );
- const { t } = useTranslation();
-
- return (
- {
- dispatch(setSeamBlur(v));
- }}
- withInput
- withSliderMarks
- withReset
- handleReset={() => {
- dispatch(setSeamBlur(8));
- }}
- />
- );
-};
-
-export default memo(ParamSeamBlur);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse.tsx
deleted file mode 100644
index 23e06797e5..0000000000
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamPaintingCollapse.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import IAICollapse from 'common/components/IAICollapse';
-import { memo } from 'react';
-import { useTranslation } from 'react-i18next';
-import ParamSeamBlur from './ParamSeamBlur';
-import ParamSeamSize from './ParamSeamSize';
-import ParamSeamSteps from './ParamSeamSteps';
-import ParamSeamStrength from './ParamSeamStrength';
-import ParamSeamThreshold from './ParamSeamThreshold';
-
-const ParamSeamPaintingCollapse = () => {
- const { t } = useTranslation();
-
- return (
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default memo(ParamSeamPaintingCollapse);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSize.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSize.tsx
deleted file mode 100644
index 841e9555fd..0000000000
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamSize.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import type { RootState } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAISlider from 'common/components/IAISlider';
-import { setSeamSize } from 'features/parameters/store/generationSlice';
-import { memo } from 'react';
-import { useTranslation } from 'react-i18next';
-
-const ParamSeamSize = () => {
- const dispatch = useAppDispatch();
- const seamSize = useAppSelector(
- (state: RootState) => state.generation.seamSize
- );
- const { t } = useTranslation();
-
- return (
- {
- dispatch(setSeamSize(v));
- }}
- withInput
- withSliderMarks
- withReset
- handleReset={() => {
- dispatch(setSeamSize(16));
- }}
- />
- );
-};
-
-export default memo(ParamSeamSize);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamThreshold.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamThreshold.tsx
deleted file mode 100644
index f40491db98..0000000000
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/SeamPainting/ParamSeamThreshold.tsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import {
- FormControl,
- FormLabel,
- HStack,
- RangeSlider,
- RangeSliderFilledTrack,
- RangeSliderMark,
- RangeSliderThumb,
- RangeSliderTrack,
- Tooltip,
-} from '@chakra-ui/react';
-import type { RootState } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
-import {
- setSeamHighThreshold,
- setSeamLowThreshold,
-} from 'features/parameters/store/generationSlice';
-import { memo, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
-import { BiReset } from 'react-icons/bi';
-
-const ParamSeamThreshold = () => {
- const dispatch = useAppDispatch();
- const seamLowThreshold = useAppSelector(
- (state: RootState) => state.generation.seamLowThreshold
- );
-
- const seamHighThreshold = useAppSelector(
- (state: RootState) => state.generation.seamHighThreshold
- );
- const { t } = useTranslation();
-
- const handleSeamThresholdChange = useCallback(
- (v: number[]) => {
- dispatch(setSeamLowThreshold(v[0] as number));
- dispatch(setSeamHighThreshold(v[1] as number));
- },
- [dispatch]
- );
-
- const handleSeamThresholdReset = () => {
- dispatch(setSeamLowThreshold(100));
- dispatch(setSeamHighThreshold(200));
- };
-
- return (
-
- {t('parameters.seamThreshold')}
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- 100
-
-
- 200
-
-
- 255
-
-
- }
- onClick={handleSeamThresholdReset}
- />
-
-
- );
-};
-
-export default memo(ParamSeamThreshold);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx
index c4d2d35f8f..9732e34c84 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx
@@ -69,31 +69,29 @@ const ParamControlNetCollapse = () => {
return (
-
-
-
-
-
+
+
+
}
isDisabled={!firstModel}
flexGrow={1}
- size="md"
+ size="sm"
onClick={handleClickedAddControlNet}
/>
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx
index 513ab64930..2aab013f4f 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamNegativeConditioning.tsx
@@ -5,7 +5,7 @@ import IAITextarea from 'common/components/IAITextarea';
import AddEmbeddingButton from 'features/embedding/components/AddEmbeddingButton';
import ParamEmbeddingPopover from 'features/embedding/components/ParamEmbeddingPopover';
import { setNegativePrompt } from 'features/parameters/store/generationSlice';
-import { ChangeEvent, KeyboardEvent, useCallback, useRef } from 'react';
+import { ChangeEvent, KeyboardEvent, memo, useCallback, useRef } from 'react';
import { flushSync } from 'react-dom';
import { useTranslation } from 'react-i18next';
import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus';
@@ -109,4 +109,4 @@ const ParamNegativeConditioning = () => {
);
};
-export default ParamNegativeConditioning;
+export default memo(ParamNegativeConditioning);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx
index 59b5138e3e..ca45da121f 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Core/ParamPositiveConditioning.tsx
@@ -1,7 +1,7 @@
import { Box, FormControl, useDisclosure } from '@chakra-ui/react';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { ChangeEvent, KeyboardEvent, useCallback, useRef } from 'react';
+import { ChangeEvent, KeyboardEvent, memo, useCallback, useRef } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import {
@@ -23,9 +23,8 @@ import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus';
const promptInputSelector = createSelector(
[stateSelector, activeTabNameSelector],
- ({ generation, ui }, activeTabName) => {
+ ({ generation }, activeTabName) => {
return {
- shouldPinParametersPanel: ui.shouldPinParametersPanel,
prompt: generation.positivePrompt,
activeTabName,
};
@@ -42,8 +41,7 @@ const promptInputSelector = createSelector(
*/
const ParamPositiveConditioning = () => {
const dispatch = useAppDispatch();
- const { prompt, shouldPinParametersPanel, activeTabName } =
- useAppSelector(promptInputSelector);
+ const { prompt, activeTabName } = useAppSelector(promptInputSelector);
const isReady = useIsReadyToInvoke();
const promptRef = useRef(null);
const { isOpen, onClose, onOpen } = useDisclosure();
@@ -148,7 +146,7 @@ const ParamPositiveConditioning = () => {
@@ -159,4 +157,4 @@ const ParamPositiveConditioning = () => {
);
};
-export default ParamPositiveConditioning;
+export default memo(ParamPositiveConditioning);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImage.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImage.tsx
index e8a629e2ac..17786dac43 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImage.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImage.tsx
@@ -9,7 +9,7 @@ import {
TypesafeDraggableData,
TypesafeDroppableData,
} from 'features/dnd/types';
-import { useMemo } from 'react';
+import { memo, useMemo } from 'react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
const selector = createSelector(
@@ -64,4 +64,4 @@ const InitialImage = () => {
);
};
-export default InitialImage;
+export default memo(InitialImage);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx
index 9e23a1a243..ee08d4ca99 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ImageToImage/InitialImageDisplay.tsx
@@ -6,7 +6,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIIconButton from 'common/components/IAIIconButton';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import { clearInitialImage } from 'features/parameters/store/generationSlice';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { FaUndo, FaUpload } from 'react-icons/fa';
import InitialImage from './InitialImage';
import { PostUploadAction } from 'services/api/types';
@@ -40,7 +40,7 @@ const InitialImageDisplay = () => {
return (
{
alignItems: 'center',
justifyContent: 'center',
borderRadius: 'base',
- p: 4,
+ p: 2,
gap: 4,
}}
>
@@ -64,6 +64,7 @@ const InitialImageDisplay = () => {
>
{
}
{...getUploadButtonProps()}
/>
}
onClick={handleReset}
isDisabled={isResetButtonDisabled}
@@ -95,4 +96,4 @@ const InitialImageDisplay = () => {
);
};
-export default InitialImageDisplay;
+export default memo(InitialImageDisplay);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Upscale/ParamUpscaleSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Upscale/ParamUpscaleSettings.tsx
index 5824c38123..c858ae66a7 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Upscale/ParamUpscaleSettings.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Upscale/ParamUpscaleSettings.tsx
@@ -5,7 +5,7 @@ import IAIButton from 'common/components/IAIButton';
import IAIIconButton from 'common/components/IAIIconButton';
import IAIPopover from 'common/components/IAIPopover';
import { selectIsBusy } from 'features/system/store/systemSelectors';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FaExpandArrowsAlt } from 'react-icons/fa';
import { ImageDTO } from 'services/api/types';
@@ -59,4 +59,4 @@ const ParamUpscalePopover = (props: Props) => {
);
};
-export default ParamUpscalePopover;
+export default memo(ParamUpscalePopover);
diff --git a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/CancelButton.tsx b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/CancelButton.tsx
index bb6e7e862d..e7bd36b931 100644
--- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/CancelButton.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/CancelButton.tsx
@@ -27,6 +27,7 @@ import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
import { ChevronDownIcon } from '@chakra-ui/icons';
import { sessionCanceled } from 'services/api/thunks/session';
+import IAIButton from 'common/components/IAIButton';
const cancelButtonSelector = createSelector(
systemSelector,
@@ -49,15 +50,14 @@ const cancelButtonSelector = createSelector(
}
);
-interface CancelButtonProps {
+type Props = Omit & {
btnGroupWidth?: string | number;
-}
+ asIconButton?: boolean;
+};
-const CancelButton = (
- props: CancelButtonProps & Omit
-) => {
+const CancelButton = (props: Props) => {
const dispatch = useAppDispatch();
- const { btnGroupWidth = 'auto', ...rest } = props;
+ const { btnGroupWidth = 'auto', asIconButton = false, ...rest } = props;
const {
isProcessing,
isConnected,
@@ -124,16 +124,31 @@ const CancelButton = (
return (
-
+ {asIconButton ? (
+
+ ) : (
+
+ Cancel
+
+ )}
);
}
+
+const tooltipSelector = createSelector(
+ [stateSelector],
+ ({ gallery }) => {
+ const { autoAddBoardId } = gallery;
+
+ return {
+ autoAddBoardId,
+ };
+ },
+ defaultSelectorOptions
+);
+
+export const InvokeButtonTooltipContent = memo(() => {
+ const { isReady, reasons } = useIsReadyToInvoke();
+ const { autoAddBoardId } = useAppSelector(tooltipSelector);
+ const autoAddBoardName = useBoardName(autoAddBoardId);
+
+ return (
+
+
+ {isReady ? 'Ready to Invoke' : 'Unable to Invoke'}
+
+ {reasons.length > 0 && (
+
+ {reasons.map((reason, i) => (
+
+ {reason}
+
+ ))}
+
+ )}
+
+
+ Adding images to{' '}
+
+ {autoAddBoardName || 'Uncategorized'}
+
+
+
+ );
+});
+
+InvokeButtonTooltipContent.displayName = 'InvokeButtonTooltipContent';
diff --git a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx
index f132092012..41f1f3c918 100644
--- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx
@@ -1,4 +1,5 @@
import { Flex } from '@chakra-ui/react';
+import { memo } from 'react';
import CancelButton from './CancelButton';
import InvokeButton from './InvokeButton';
@@ -7,11 +8,11 @@ import InvokeButton from './InvokeButton';
*/
const ProcessButtons = () => {
return (
-
+
);
};
-export default ProcessButtons;
+export default memo(ProcessButtons);
diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts
index d8495c5751..8a4b9a7963 100644
--- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts
+++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts
@@ -37,12 +37,8 @@ export interface GenerationState {
scheduler: SchedulerParam;
maskBlur: number;
maskBlurMethod: MaskBlurMethodParam;
- seamSize: number;
- seamBlur: number;
- seamSteps: number;
- seamStrength: StrengthParam;
- seamLowThreshold: number;
- seamHighThreshold: number;
+ canvasCoherenceSteps: number;
+ canvasCoherenceStrength: StrengthParam;
seed: SeedParam;
seedWeights: string;
shouldFitToWidthHeight: boolean;
@@ -80,12 +76,8 @@ export const initialGenerationState: GenerationState = {
scheduler: 'euler',
maskBlur: 16,
maskBlurMethod: 'box',
- seamSize: 16,
- seamBlur: 8,
- seamSteps: 20,
- seamStrength: 0.7,
- seamLowThreshold: 100,
- seamHighThreshold: 200,
+ canvasCoherenceSteps: 20,
+ canvasCoherenceStrength: 0.3,
seed: 0,
seedWeights: '',
shouldFitToWidthHeight: true,
@@ -212,23 +204,11 @@ export const generationSlice = createSlice({
setMaskBlurMethod: (state, action: PayloadAction) => {
state.maskBlurMethod = action.payload;
},
- setSeamSize: (state, action: PayloadAction) => {
- state.seamSize = action.payload;
+ setCanvasCoherenceSteps: (state, action: PayloadAction) => {
+ state.canvasCoherenceSteps = action.payload;
},
- setSeamBlur: (state, action: PayloadAction) => {
- state.seamBlur = action.payload;
- },
- setSeamSteps: (state, action: PayloadAction) => {
- state.seamSteps = action.payload;
- },
- setSeamStrength: (state, action: PayloadAction) => {
- state.seamStrength = action.payload;
- },
- setSeamLowThreshold: (state, action: PayloadAction) => {
- state.seamLowThreshold = action.payload;
- },
- setSeamHighThreshold: (state, action: PayloadAction) => {
- state.seamHighThreshold = action.payload;
+ setCanvasCoherenceStrength: (state, action: PayloadAction) => {
+ state.canvasCoherenceStrength = action.payload;
},
setTileSize: (state, action: PayloadAction) => {
state.tileSize = action.payload;
@@ -313,7 +293,9 @@ export const generationSlice = createSlice({
});
builder.addCase(setShouldShowAdvancedOptions, (state, action) => {
const advancedOptionsStatus = action.payload;
- if (!advancedOptionsStatus) state.clipSkip = 0;
+ if (!advancedOptionsStatus) {
+ state.clipSkip = 0;
+ }
});
},
});
@@ -336,12 +318,8 @@ export const {
setScheduler,
setMaskBlur,
setMaskBlurMethod,
- setSeamSize,
- setSeamBlur,
- setSeamSteps,
- setSeamStrength,
- setSeamLowThreshold,
- setSeamHighThreshold,
+ setCanvasCoherenceSteps,
+ setCanvasCoherenceStrength,
setSeed,
setSeedWeights,
setShouldFitToWidthHeight,
diff --git a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts
index 25905e1e14..e210efc414 100644
--- a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts
+++ b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts
@@ -210,7 +210,7 @@ export type HeightParam = z.infer;
export const isValidHeight = (val: unknown): val is HeightParam =>
zHeight.safeParse(val).success;
-const zBaseModel = z.enum(['sd-1', 'sd-2', 'sdxl', 'sdxl-refiner']);
+export const zBaseModel = z.enum(['sd-1', 'sd-2', 'sdxl', 'sdxl-refiner']);
export type BaseModelParam = z.infer;
diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx
index 7d51c6dea7..057ee6fe78 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLConcatButton.tsx
@@ -9,10 +9,6 @@ export default function ParamSDXLConcatButton() {
(state: RootState) => state.sdxl.shouldConcatSDXLStylePrompt
);
- const shouldPinParametersPanel = useAppSelector(
- (state: RootState) => state.ui.shouldPinParametersPanel
- );
-
const dispatch = useAppDispatch();
const handleShouldConcatPromptChange = () => {
@@ -31,7 +27,7 @@ export default function ParamSDXLConcatButton() {
sx={{
position: 'absolute',
insetInlineEnd: 1,
- top: shouldPinParametersPanel ? 12 : 20,
+ top: 6,
border: 'none',
color: shouldConcatSDXLStylePrompt ? 'accent.500' : 'base.500',
_hover: {
diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLNegativeStyleConditioning.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLNegativeStyleConditioning.tsx
index e1533bc886..ff877f5e9a 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLNegativeStyleConditioning.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLNegativeStyleConditioning.tsx
@@ -1,7 +1,7 @@
import { Box, FormControl, useDisclosure } from '@chakra-ui/react';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { ChangeEvent, KeyboardEvent, useCallback, useRef } from 'react';
+import { ChangeEvent, KeyboardEvent, memo, useCallback, useRef } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
@@ -167,4 +167,4 @@ const ParamSDXLNegativeStyleConditioning = () => {
);
};
-export default ParamSDXLNegativeStyleConditioning;
+export default memo(ParamSDXLNegativeStyleConditioning);
diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLPositiveStyleConditioning.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLPositiveStyleConditioning.tsx
index fdd29eaeb7..8ff2f9f19e 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLPositiveStyleConditioning.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLPositiveStyleConditioning.tsx
@@ -1,7 +1,7 @@
import { Box, FormControl, useDisclosure } from '@chakra-ui/react';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { ChangeEvent, KeyboardEvent, useCallback, useRef } from 'react';
+import { ChangeEvent, KeyboardEvent, memo, useCallback, useRef } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
@@ -166,4 +166,4 @@ const ParamSDXLPositiveStyleConditioning = () => {
);
};
-export default ParamSDXLPositiveStyleConditioning;
+export default memo(ParamSDXLPositiveStyleConditioning);
diff --git a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx
index 3b186006f1..5a3a8dc379 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/ParamSDXLRefinerCollapse.tsx
@@ -12,6 +12,7 @@ import ParamSDXLRefinerScheduler from './SDXLRefiner/ParamSDXLRefinerScheduler';
import ParamSDXLRefinerStart from './SDXLRefiner/ParamSDXLRefinerStart';
import ParamSDXLRefinerSteps from './SDXLRefiner/ParamSDXLRefinerSteps';
import ParamUseSDXLRefiner from './SDXLRefiner/ParamUseSDXLRefiner';
+import { memo } from 'react';
const selector = createSelector(
stateSelector,
@@ -47,4 +48,4 @@ const ParamSDXLRefinerCollapse = () => {
);
};
-export default ParamSDXLRefinerCollapse;
+export default memo(ParamSDXLRefinerCollapse);
diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabCoreParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabCoreParameters.tsx
index 4d7c919655..dae462ad47 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabCoreParameters.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLImageToImageTabCoreParameters.tsx
@@ -32,11 +32,7 @@ const SDXLImageToImageTabCoreParameters = () => {
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
return (
-
+
{
return (
<>
-
@@ -22,4 +21,4 @@ const SDXLImageToImageTabParameters = () => {
);
};
-export default SDXLImageToImageTabParameters;
+export default memo(SDXLImageToImageTabParameters);
diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx
index c562951c4d..084c12af61 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLTextToImageTabParameters.tsx
@@ -2,8 +2,8 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
-import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
import TextToImageTabCoreParameters from 'features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters';
+import { memo } from 'react';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
@@ -11,7 +11,6 @@ const SDXLTextToImageTabParameters = () => {
return (
<>
-
@@ -22,4 +21,4 @@ const SDXLTextToImageTabParameters = () => {
);
};
-export default SDXLTextToImageTabParameters;
+export default memo(SDXLTextToImageTabParameters);
diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabCoreParameters.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabCoreParameters.tsx
index 7db6ccc219..4cfbdeb895 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabCoreParameters.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLUnifiedCanvasTabCoreParameters.tsx
@@ -30,11 +30,7 @@ const SDXLUnifiedCanvasTabCoreParameters = () => {
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
return (
-
+
-
@@ -23,7 +21,7 @@ export default function SDXLUnifiedCanvasTabParameters() {
-
+
>
);
}
diff --git a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx
index 4da46fdac9..029444b776 100644
--- a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx
+++ b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx
@@ -60,11 +60,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: t('hotkeys.toggleOptions.desc'),
hotkey: 'O',
},
- {
- title: t('hotkeys.pinOptions.title'),
- desc: t('hotkeys.pinOptions.desc'),
- hotkey: 'Shift+O',
- },
{
title: t('hotkeys.toggleGallery.title'),
desc: t('hotkeys.toggleGallery.desc'),
@@ -136,11 +131,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: t('hotkeys.nextImage.desc'),
hotkey: 'Arrow Right',
},
- {
- title: t('hotkeys.toggleGalleryPin.title'),
- desc: t('hotkeys.toggleGalleryPin.desc'),
- hotkey: 'Shift+G',
- },
{
title: t('hotkeys.increaseGalleryThumbSize.title'),
desc: t('hotkeys.increaseGalleryThumbSize.desc'),
@@ -286,6 +276,14 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
},
];
+ const nodesHotkeys = [
+ {
+ title: t('hotkeys.addNodes.title'),
+ desc: t('hotkeys.addNodes.desc'),
+ hotkey: 'Shift + A / Space',
+ },
+ ];
+
const renderHotkeyModalItems = (hotkeys: HotkeyList[]) => (
{hotkeys.map((hotkey, i) => (
@@ -377,6 +375,22 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
{renderHotkeyModalItems(unifiedCanvasHotkeys)}
+
+
+
+
+ {t('hotkeys.nodesHotkeys')}
+
+
+
+
+ {renderHotkeyModalItems(nodesHotkeys)}
+
+
diff --git a/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx b/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx
index aa4a3dfdfc..10349afd52 100644
--- a/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx
+++ b/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx
@@ -1,7 +1,7 @@
import { Flex, Image, Text } from '@chakra-ui/react';
import InvokeAILogoImage from 'assets/images/logo.png';
import { AnimatePresence, motion } from 'framer-motion';
-import { useRef } from 'react';
+import { memo, useRef } from 'react';
import { useHoverDirty } from 'react-use';
import { useGetAppVersionQuery } from 'services/api/endpoints/appInfo';
@@ -15,7 +15,7 @@ const InvokeAILogoComponent = ({ showVersion = true }: Props) => {
const isHovered = useHoverDirty(ref);
return (
-
+
{
);
};
-export default InvokeAILogoComponent;
+export default memo(InvokeAILogoComponent);
diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/ResetWebUIButton.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/ResetWebUIButton.tsx
new file mode 100644
index 0000000000..9617d0cd34
--- /dev/null
+++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/ResetWebUIButton.tsx
@@ -0,0 +1,82 @@
+import {
+ Flex,
+ Modal,
+ ModalBody,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Text,
+ useDisclosure,
+} from '@chakra-ui/react';
+import { LOCALSTORAGE_KEYS, LOCALSTORAGE_PREFIX } from 'app/store/constants';
+import IAIButton from 'common/components/IAIButton';
+import { memo, useCallback, useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+
+type Props = {
+ onSettingsModalClose: () => void;
+};
+
+const ResetWebUIButton = ({ onSettingsModalClose }: Props) => {
+ const { t } = useTranslation();
+ const [countdown, setCountdown] = useState(5);
+
+ const {
+ isOpen: isRefreshModalOpen,
+ onOpen: onRefreshModalOpen,
+ onClose: onRefreshModalClose,
+ } = useDisclosure();
+
+ const handleClickResetWebUI = useCallback(() => {
+ // Only remove our keys
+ Object.keys(window.localStorage).forEach((key) => {
+ if (
+ LOCALSTORAGE_KEYS.includes(key) ||
+ key.startsWith(LOCALSTORAGE_PREFIX)
+ ) {
+ localStorage.removeItem(key);
+ }
+ });
+ onSettingsModalClose();
+ onRefreshModalOpen();
+ setInterval(() => setCountdown((prev) => prev - 1), 1000);
+ }, [onSettingsModalClose, onRefreshModalOpen]);
+
+ useEffect(() => {
+ if (countdown <= 0) {
+ window.location.reload();
+ }
+ }, [countdown]);
+
+ return (
+ <>
+
+ {t('settings.resetWebUI')}
+
+
+
+
+
+
+
+
+ {t('settings.resetComplete')}
+ Reloading in {countdown}...
+
+
+
+
+
+
+ >
+ );
+};
+
+export default memo(ResetWebUIButton);
diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx
index 04c71be20f..9f9f9fc58a 100644
--- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx
+++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx
@@ -31,7 +31,6 @@ import {
} from 'features/system/store/systemSlice';
import {
setShouldShowProgressInViewer,
- setShouldUseCanvasBetaLayout,
setShouldUseSliders,
} from 'features/ui/store/uiSlice';
import { isEqual } from 'lodash-es';
@@ -39,8 +38,10 @@ import {
ChangeEvent,
ReactElement,
cloneElement,
+ memo,
useCallback,
useEffect,
+ useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import { LogLevelName } from 'roarr';
@@ -67,18 +68,13 @@ const selector = createSelector(
shouldUseWatermarker,
} = system;
- const {
- shouldUseCanvasBetaLayout,
- shouldUseSliders,
- shouldShowProgressInViewer,
- } = ui;
+ const { shouldUseSliders, shouldShowProgressInViewer } = ui;
const { shouldShowAdvancedOptions } = generation;
return {
shouldConfirmOnDelete,
enableImageDebugging,
- shouldUseCanvasBetaLayout,
shouldUseSliders,
shouldShowProgressInViewer,
consoleLogLevel,
@@ -97,7 +93,6 @@ const selector = createSelector(
type ConfigOptions = {
shouldShowDeveloperSettings: boolean;
shouldShowResetWebUiText: boolean;
- shouldShowBetaLayout: boolean;
shouldShowAdvancedOptionsSettings: boolean;
shouldShowClearIntermediates: boolean;
shouldShowLocalizationToggle: boolean;
@@ -112,8 +107,8 @@ type SettingsModalProps = {
const SettingsModal = ({ children, config }: SettingsModalProps) => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
+ const [countdown, setCountdown] = useState(3);
- const shouldShowBetaLayout = config?.shouldShowBetaLayout ?? true;
const shouldShowDeveloperSettings =
config?.shouldShowDeveloperSettings ?? true;
const shouldShowResetWebUiText = config?.shouldShowResetWebUiText ?? true;
@@ -155,7 +150,6 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
const {
shouldConfirmOnDelete,
enableImageDebugging,
- shouldUseCanvasBetaLayout,
shouldUseSliders,
shouldShowProgressInViewer,
consoleLogLevel,
@@ -178,8 +172,15 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
});
onSettingsModalClose();
onRefreshModalOpen();
+ setInterval(() => setCountdown((prev) => prev - 1), 1000);
}, [onSettingsModalClose, onRefreshModalOpen]);
+ useEffect(() => {
+ if (countdown <= 0) {
+ window.location.reload();
+ }
+ }, [countdown]);
+
const handleLogLevelChanged = useCallback(
(v: string) => {
dispatch(consoleLogLevelChanged(v as LogLevelName));
@@ -296,17 +297,6 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
)
}
/>
- {shouldShowBetaLayout && (
- ) =>
- dispatch(setShouldUseCanvasBetaLayout(e.target.checked))
- }
- />
- )}
{shouldShowLocalizationToggle && (
{
isOpen={isRefreshModalOpen}
onClose={onRefreshModalClose}
isCentered
+ closeOnEsc={false}
>
@@ -387,7 +378,9 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
- {t('settings.resetComplete')}
+
+ {t('settings.resetComplete')} Reloading in {countdown}...
+
@@ -398,4 +391,4 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
);
};
-export default SettingsModal;
+export default memo(SettingsModal);
diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/StyledFlex.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/StyledFlex.tsx
index fd0580f4e2..ec61993c33 100644
--- a/invokeai/frontend/web/src/features/system/components/SettingsModal/StyledFlex.tsx
+++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/StyledFlex.tsx
@@ -1,5 +1,5 @@
import { Flex } from '@chakra-ui/react';
-import { PropsWithChildren } from 'react';
+import { PropsWithChildren, memo } from 'react';
const StyledFlex = (props: PropsWithChildren) => {
return (
@@ -20,4 +20,4 @@ const StyledFlex = (props: PropsWithChildren) => {
);
};
-export default StyledFlex;
+export default memo(StyledFlex);
diff --git a/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx b/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx
index 767b394ac1..4a19ee7fa3 100644
--- a/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx
+++ b/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx
@@ -4,7 +4,7 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { AnimatePresence, motion } from 'framer-motion';
import { ResourceKey } from 'i18next';
-import { useMemo, useRef } from 'react';
+import { memo, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { FaCircle } from 'react-icons/fa';
import { useHoverDirty } from 'react-use';
@@ -125,4 +125,4 @@ const StatusIndicator = () => {
);
};
-export default StatusIndicator;
+export default memo(StatusIndicator);
diff --git a/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts b/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts
deleted file mode 100644
index 8ba5731a5b..0000000000
--- a/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppSelector } from 'app/store/storeHooks';
-import { useMemo } from 'react';
-import { configSelector } from '../store/configSelectors';
-import { systemSelector } from '../store/systemSelectors';
-
-const isApplicationReadySelector = createSelector(
- [systemSelector, configSelector],
- (system, config) => {
- const { wasSchemaParsed } = system;
-
- const { disabledTabs } = config;
-
- return {
- disabledTabs,
- wasSchemaParsed,
- };
- }
-);
-
-/**
- * Checks if the application is ready to be used, i.e. if the initial startup process is finished.
- */
-export const useIsApplicationReady = () => {
- const { disabledTabs, wasSchemaParsed } = useAppSelector(
- isApplicationReadySelector
- );
-
- const isApplicationReady = useMemo(() => {
- if (!disabledTabs.includes('nodes') && !wasSchemaParsed) {
- return false;
- }
-
- return true;
- }, [disabledTabs, wasSchemaParsed]);
-
- return isApplicationReady;
-};
diff --git a/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts
index bba279c4bc..b5376afc4f 100644
--- a/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts
+++ b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts
@@ -16,7 +16,6 @@ export const systemPersistDenylist: (keyof SystemState)[] = [
'isCancelScheduled',
'progressImage',
'wereModelsReceived',
- 'wasSchemaParsed',
'isPersisted',
'isUploading',
];
diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts
index d789df49a4..bf8036ba98 100644
--- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts
+++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts
@@ -2,9 +2,8 @@ import { UseToastOptions } from '@chakra-ui/react';
import { PayloadAction, createSlice, isAnyOf } from '@reduxjs/toolkit';
import { InvokeLogLevel } from 'app/logging/logger';
import { userInvoked } from 'app/store/actions';
-import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
import { t } from 'i18next';
-import { startCase, upperFirst } from 'lodash-es';
+import { get, startCase, upperFirst } from 'lodash-es';
import { LogLevelName } from 'roarr';
import {
isAnySessionRejected,
@@ -68,10 +67,6 @@ export interface SystemState {
* Whether or not the available models were received
*/
wereModelsReceived: boolean;
- /**
- * Whether or not the OpenAPI schema was received and parsed
- */
- wasSchemaParsed: boolean;
/**
* The console output logging level
*/
@@ -112,7 +107,6 @@ export const initialSystemState: SystemState = {
isCancelScheduled: false,
subscribedNodeIds: [],
wereModelsReceived: false,
- wasSchemaParsed: false,
consoleLogLevel: 'debug',
shouldLogToConsole: true,
statusTranslationKey: 'common.statusDisconnected',
@@ -339,13 +333,6 @@ export const systemSlice = createSlice({
);
});
- /**
- * OpenAPI schema was parsed
- */
- builder.addCase(nodeTemplatesBuilt, (state) => {
- state.wasSchemaParsed = true;
- });
-
// *** Matchers - must be after all cases ***
/**
@@ -381,14 +368,14 @@ export const systemSlice = createSlice({
return;
}
} else if (action.payload?.error) {
- errorDescription = action.payload?.error as string;
+ errorDescription = action.payload?.error;
}
state.toastQueue.push(
makeToast({
title: t('toast.serverError'),
status: 'error',
- description: errorDescription,
+ description: get(errorDescription, 'detail', 'Unknown Error'),
duration,
})
);
diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx
index af3eb72d8d..7af1a4d674 100644
--- a/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx
@@ -1,65 +1,57 @@
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { Flex } from '@chakra-ui/layout';
+import { Portal } from '@chakra-ui/portal';
import IAIIconButton from 'common/components/IAIIconButton';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
-import { setShouldShowGallery } from 'features/ui/store/uiSlice';
-import { isEqual } from 'lodash-es';
-import { memo } from 'react';
+import { RefObject, memo } from 'react';
import { useTranslation } from 'react-i18next';
import { MdPhotoLibrary } from 'react-icons/md';
-import { activeTabNameSelector, uiSelector } from '../store/uiSelectors';
-import { NO_GALLERY_TABS } from './InvokeTabs';
+import { ImperativePanelHandle } from 'react-resizable-panels';
-const floatingGalleryButtonSelector = createSelector(
- [activeTabNameSelector, uiSelector],
- (activeTabName, ui) => {
- const { shouldPinGallery, shouldShowGallery } = ui;
+type Props = {
+ isGalleryCollapsed: boolean;
+ galleryPanelRef: RefObject;
+};
- return {
- shouldPinGallery,
- shouldShowGalleryButton: NO_GALLERY_TABS.includes(activeTabName)
- ? false
- : !shouldShowGallery,
- };
- },
- { memoizeOptions: { resultEqualityCheck: isEqual } }
-);
-
-const FloatingGalleryButton = () => {
+const FloatingGalleryButton = ({
+ isGalleryCollapsed,
+ galleryPanelRef,
+}: Props) => {
const { t } = useTranslation();
- const { shouldPinGallery, shouldShowGalleryButton } = useAppSelector(
- floatingGalleryButtonSelector
- );
- const dispatch = useAppDispatch();
const handleShowGallery = () => {
- dispatch(setShouldShowGallery(true));
- shouldPinGallery && dispatch(requestCanvasRescale());
+ galleryPanelRef.current?.expand();
};
- return shouldShowGalleryButton ? (
-
-
-
- ) : null;
+ if (!isGalleryCollapsed) {
+ return null;
+ }
+
+ return (
+
+
+ }
+ sx={{
+ p: 0,
+ px: 3,
+ h: 48,
+ borderStartEndRadius: 0,
+ borderEndEndRadius: 0,
+ shadow: '2xl',
+ }}
+ />
+
+
+ );
};
export default memo(FloatingGalleryButton);
diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx
index 0969426339..aa24896591 100644
--- a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx
@@ -1,20 +1,12 @@
-import { ChakraProps, Flex } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { ChakraProps, Flex, Portal } from '@chakra-ui/react';
import IAIIconButton from 'common/components/IAIIconButton';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton';
import InvokeButton from 'features/parameters/components/ProcessButtons/InvokeButton';
-import {
- activeTabNameSelector,
- uiSelector,
-} from 'features/ui/store/uiSelectors';
-import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice';
-import { isEqual } from 'lodash-es';
-import { memo } from 'react';
+import { RefObject, memo } from 'react';
import { useTranslation } from 'react-i18next';
import { FaSlidersH } from 'react-icons/fa';
+import { ImperativePanelHandle } from 'react-resizable-panels';
const floatingButtonStyles: ChakraProps['sx'] = {
borderStartStartRadius: 0,
@@ -22,81 +14,48 @@ const floatingButtonStyles: ChakraProps['sx'] = {
shadow: '2xl',
};
-export const floatingParametersPanelButtonSelector = createSelector(
- [uiSelector, activeTabNameSelector],
- (ui, activeTabName) => {
- const {
- shouldPinParametersPanel,
- shouldUseCanvasBetaLayout,
- shouldShowParametersPanel,
- } = ui;
+type Props = {
+ isSidePanelCollapsed: boolean;
+ sidePanelRef: RefObject;
+};
- const canvasBetaLayoutCheck =
- shouldUseCanvasBetaLayout && activeTabName === 'unifiedCanvas';
-
- const shouldShowProcessButtons =
- !canvasBetaLayoutCheck &&
- (!shouldPinParametersPanel || !shouldShowParametersPanel);
-
- const shouldShowParametersPanelButton =
- !canvasBetaLayoutCheck &&
- !shouldShowParametersPanel &&
- ['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName);
-
- return {
- shouldPinParametersPanel,
- shouldShowParametersPanelButton,
- shouldShowProcessButtons,
- };
- },
- { memoizeOptions: { resultEqualityCheck: isEqual } }
-);
-
-const FloatingParametersPanelButtons = () => {
- const dispatch = useAppDispatch();
+const FloatingSidePanelButtons = ({
+ isSidePanelCollapsed,
+ sidePanelRef,
+}: Props) => {
const { t } = useTranslation();
- const {
- shouldShowProcessButtons,
- shouldShowParametersPanelButton,
- shouldPinParametersPanel,
- } = useAppSelector(floatingParametersPanelButtonSelector);
- const handleShowOptionsPanel = () => {
- dispatch(setShouldShowParametersPanel(true));
- shouldPinParametersPanel && dispatch(requestCanvasRescale());
+ const handleShowSidePanel = () => {
+ sidePanelRef.current?.expand();
};
- if (!shouldShowParametersPanelButton) {
+ if (!isSidePanelCollapsed) {
return null;
}
return (
-
-
+
-
-
- {shouldShowProcessButtons && (
- <>
-
-
- >
- )}
-
+ }
+ />
+
+
+
+
);
};
-export default memo(FloatingParametersPanelButtons);
+export default memo(FloatingSidePanelButtons);
diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx
index 2dd9220288..0f5a8d92ff 100644
--- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx
@@ -11,12 +11,12 @@ import {
} from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import AuxiliaryProgressIndicator from 'app/components/AuxiliaryProgressIndicator';
-import { RootState, stateSelector } from 'app/store/store';
+import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
+import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup';
import { InvokeTabName, tabMap } from 'features/ui/store/tabMap';
-import { setActiveTab, togglePanels } from 'features/ui/store/uiSlice';
+import { setActiveTab } from 'features/ui/store/uiSlice';
import { ResourceKey } from 'i18next';
import { isEqual } from 'lodash-es';
import { MouseEvent, ReactNode, memo, useCallback, useMemo } from 'react';
@@ -25,11 +25,15 @@ import { useTranslation } from 'react-i18next';
import { FaCube, FaFont, FaImage } from 'react-icons/fa';
import { MdDeviceHub, MdGridOn } from 'react-icons/md';
import { Panel, PanelGroup } from 'react-resizable-panels';
-import { useMinimumPanelSize } from '../hooks/useMinimumPanelSize';
+import { usePanel } from '../hooks/usePanel';
+import { usePanelStorage } from '../hooks/usePanelStorage';
import {
activeTabIndexSelector,
activeTabNameSelector,
} from '../store/uiSelectors';
+import FloatingGalleryButton from './FloatingGalleryButton';
+import FloatingSidePanelButtons from './FloatingParametersPanelButtons';
+import ParametersPanel from './ParametersPanel';
import ImageTab from './tabs/ImageToImage/ImageToImageTab';
import ModelManagerTab from './tabs/ModelManager/ModelManagerTab';
import NodesTab from './tabs/Nodes/NodesTab';
@@ -89,38 +93,20 @@ const enabledTabsSelector = createSelector(
}
);
-const MIN_GALLERY_WIDTH = 350;
-const DEFAULT_GALLERY_PCT = 20;
+const SIDE_PANEL_MIN_SIZE_PX = 448;
+const MAIN_PANEL_MIN_SIZE_PX = 448;
+const GALLERY_PANEL_MIN_SIZE_PX = 360;
+
export const NO_GALLERY_TABS: InvokeTabName[] = ['modelManager'];
+export const NO_SIDE_PANEL_TABS: InvokeTabName[] = ['modelManager'];
const InvokeTabs = () => {
const activeTab = useAppSelector(activeTabIndexSelector);
const activeTabName = useAppSelector(activeTabNameSelector);
const enabledTabs = useAppSelector(enabledTabsSelector);
-
- const { shouldPinGallery, shouldPinParametersPanel, shouldShowGallery } =
- useAppSelector((state: RootState) => state.ui);
-
const { t } = useTranslation();
-
const dispatch = useAppDispatch();
- useHotkeys(
- 'f',
- () => {
- dispatch(togglePanels());
- (shouldPinGallery || shouldPinParametersPanel) &&
- dispatch(requestCanvasRescale());
- },
- [shouldPinGallery, shouldPinParametersPanel]
- );
-
- const handleResizeGallery = useCallback(() => {
- if (activeTabName === 'unifiedCanvas') {
- dispatch(requestCanvasRescale());
- }
- }, [dispatch, activeTabName]);
-
const handleClickTab = useCallback((e: MouseEvent) => {
if (e.target instanceof HTMLElement) {
e.target.blur();
@@ -153,9 +139,6 @@ const InvokeTabs = () => {
[enabledTabs]
);
- const { ref: galleryPanelRef, minSizePct: galleryMinSizePct } =
- useMinimumPanelSize(MIN_GALLERY_WIDTH, DEFAULT_GALLERY_PCT, 'app');
-
const handleTabChange = useCallback(
(index: number) => {
const activeTabName = tabMap[index];
@@ -167,6 +150,60 @@ const InvokeTabs = () => {
[dispatch]
);
+ const {
+ minSize: sidePanelMinSize,
+ isCollapsed: isSidePanelCollapsed,
+ setIsCollapsed: setIsSidePanelCollapsed,
+ ref: sidePanelRef,
+ reset: resetSidePanel,
+ expand: expandSidePanel,
+ collapse: collapseSidePanel,
+ toggle: toggleSidePanel,
+ } = usePanel(SIDE_PANEL_MIN_SIZE_PX, 'pixels');
+
+ const {
+ ref: galleryPanelRef,
+ minSize: galleryPanelMinSize,
+ isCollapsed: isGalleryPanelCollapsed,
+ setIsCollapsed: setIsGalleryPanelCollapsed,
+ reset: resetGalleryPanel,
+ expand: expandGalleryPanel,
+ collapse: collapseGalleryPanel,
+ toggle: toggleGalleryPanel,
+ } = usePanel(GALLERY_PANEL_MIN_SIZE_PX, 'pixels');
+
+ useHotkeys(
+ 'f',
+ () => {
+ if (isGalleryPanelCollapsed || isSidePanelCollapsed) {
+ expandGalleryPanel();
+ expandSidePanel();
+ } else {
+ collapseSidePanel();
+ collapseGalleryPanel();
+ }
+ },
+ [dispatch, isGalleryPanelCollapsed, isSidePanelCollapsed]
+ );
+
+ useHotkeys(
+ ['t', 'o'],
+ () => {
+ toggleSidePanel();
+ },
+ [dispatch]
+ );
+
+ useHotkeys(
+ 'g',
+ () => {
+ toggleGalleryPanel();
+ },
+ [dispatch]
+ );
+
+ const panelStorage = usePanelStorage();
+
return (
{
autoSaveId="app"
direction="horizontal"
style={{ height: '100%', width: '100%' }}
+ storage={panelStorage}
+ units="pixels"
>
-
+ {!NO_SIDE_PANEL_TABS.includes(activeTabName) && (
+ <>
+
+ {activeTabName === 'nodes' ? (
+
+ ) : (
+
+ )}
+
+
+
+ >
+ )}
+
{tabPanels}
- {shouldPinGallery &&
- shouldShowGallery &&
- !NO_GALLERY_TABS.includes(activeTabName) && (
- <>
-
- DEFAULT_GALLERY_PCT &&
- galleryMinSizePct < 100 // prevent this error https://github.com/bvaughn/react-resizable-panels/blob/main/packages/react-resizable-panels/src/Panel.ts#L96
- ? galleryMinSizePct
- : DEFAULT_GALLERY_PCT
- }
- minSize={galleryMinSizePct}
- maxSize={50}
- >
-
-
- >
- )}
+ {!NO_GALLERY_TABS.includes(activeTabName) && (
+ <>
+
+
+
+
+
+ >
+ )}
);
diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx
deleted file mode 100644
index 393cb5bb34..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { RootState } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
-import SDXLImageToImageTabParameters from 'features/sdxl/components/SDXLImageToImageTabParameters';
-import SDXLTextToImageTabParameters from 'features/sdxl/components/SDXLTextToImageTabParameters';
-import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
-import {
- activeTabNameSelector,
- uiSelector,
-} from 'features/ui/store/uiSelectors';
-import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice';
-import { memo, useMemo } from 'react';
-import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
-import PinParametersPanelButton from './PinParametersPanelButton';
-import ResizableDrawer from './common/ResizableDrawer/ResizableDrawer';
-import ImageToImageTabParameters from './tabs/ImageToImage/ImageToImageTabParameters';
-import TextToImageTabParameters from './tabs/TextToImage/TextToImageTabParameters';
-import UnifiedCanvasParameters from './tabs/UnifiedCanvas/UnifiedCanvasParameters';
-
-const selector = createSelector(
- [uiSelector, activeTabNameSelector],
- (ui, activeTabName) => {
- const { shouldPinParametersPanel, shouldShowParametersPanel } = ui;
-
- return {
- activeTabName,
- shouldPinParametersPanel,
- shouldShowParametersPanel,
- };
- },
- defaultSelectorOptions
-);
-
-const ParametersDrawer = () => {
- const dispatch = useAppDispatch();
- const { shouldPinParametersPanel, shouldShowParametersPanel, activeTabName } =
- useAppSelector(selector);
-
- const handleClosePanel = () => {
- dispatch(setShouldShowParametersPanel(false));
- };
-
- const model = useAppSelector((state: RootState) => state.generation.model);
-
- const drawerContent = useMemo(() => {
- if (activeTabName === 'txt2img') {
- return model && model.base_model === 'sdxl' ? (
-
- ) : (
-
- );
- }
-
- if (activeTabName === 'img2img') {
- return model && model.base_model === 'sdxl' ? (
-
- ) : (
-
- );
- }
-
- if (activeTabName === 'unifiedCanvas') {
- return ;
- }
-
- return null;
- }, [activeTabName, model]);
-
- if (shouldPinParametersPanel) {
- return null;
- }
-
- return (
-
-
-
-
-
-
-
- {drawerContent}
-
-
-
- );
-};
-
-export default memo(ParametersDrawer);
diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx
new file mode 100644
index 0000000000..d3543db7bf
--- /dev/null
+++ b/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx
@@ -0,0 +1,130 @@
+import { Box, Flex } from '@chakra-ui/react';
+import { RootState } from 'app/store/store';
+import { useAppSelector } from 'app/store/storeHooks';
+import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
+import SDXLImageToImageTabParameters from 'features/sdxl/components/SDXLImageToImageTabParameters';
+import SDXLTextToImageTabParameters from 'features/sdxl/components/SDXLTextToImageTabParameters';
+import SDXLUnifiedCanvasTabParameters from 'features/sdxl/components/SDXLUnifiedCanvasTabParameters';
+import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
+import { PropsWithChildren, memo } from 'react';
+import { activeTabNameSelector } from '../store/uiSelectors';
+import ImageToImageTabParameters from './tabs/ImageToImage/ImageToImageTabParameters';
+import TextToImageTabParameters from './tabs/TextToImage/TextToImageTabParameters';
+import UnifiedCanvasParameters from './tabs/UnifiedCanvas/UnifiedCanvasParameters';
+
+const ParametersPanel = () => {
+ const activeTabName = useAppSelector(activeTabNameSelector);
+ const model = useAppSelector((state: RootState) => state.generation.model);
+
+ if (activeTabName === 'txt2img') {
+ return (
+
+ {model && model.base_model === 'sdxl' ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ if (activeTabName === 'img2img') {
+ return (
+
+ {model && model.base_model === 'sdxl' ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ if (activeTabName === 'unifiedCanvas') {
+ return (
+
+ {model && model.base_model === 'sdxl' ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ return null;
+};
+
+export default memo(ParametersPanel);
+
+const ParametersPanelWrapper = memo((props: PropsWithChildren) => {
+ return (
+
+
+
+
+
+
+
+ {props.children}
+
+
+
+
+
+
+ );
+});
+
+ParametersPanelWrapper.displayName = 'ParametersPanelWrapper';
diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPinnedWrapper.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPinnedWrapper.tsx
deleted file mode 100644
index c7c1182d21..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/ParametersPinnedWrapper.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { Box, Flex } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppSelector } from 'app/store/storeHooks';
-import { PropsWithChildren, memo } from 'react';
-import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
-import { uiSelector } from '../store/uiSelectors';
-import PinParametersPanelButton from './PinParametersPanelButton';
-
-const selector = createSelector(uiSelector, (ui) => {
- const { shouldPinParametersPanel, shouldShowParametersPanel } = ui;
-
- return {
- shouldPinParametersPanel,
- shouldShowParametersPanel,
- };
-});
-
-type ParametersPinnedWrapperProps = PropsWithChildren;
-
-const ParametersPinnedWrapper = (props: ParametersPinnedWrapperProps) => {
- const { shouldPinParametersPanel, shouldShowParametersPanel } =
- useAppSelector(selector);
-
- if (!(shouldPinParametersPanel && shouldShowParametersPanel)) {
- return null;
- }
-
- return (
-
-
- {props.children}
-
-
-
-
- );
-};
-
-export default memo(ParametersPinnedWrapper);
diff --git a/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx b/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx
deleted file mode 100644
index 5d4cc4b9d7..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton, {
- IAIIconButtonProps,
-} from 'common/components/IAIIconButton';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
-import { useTranslation } from 'react-i18next';
-import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs';
-import { setShouldPinParametersPanel } from '../store/uiSlice';
-
-type PinParametersPanelButtonProps = Omit;
-
-const PinParametersPanelButton = (props: PinParametersPanelButtonProps) => {
- const { sx } = props;
- const dispatch = useAppDispatch();
- const shouldPinParametersPanel = useAppSelector(
- (state) => state.ui.shouldPinParametersPanel
- );
-
- const { t } = useTranslation();
-
- const handleClickPinOptionsPanel = () => {
- dispatch(setShouldPinParametersPanel(!shouldPinParametersPanel));
- dispatch(requestCanvasRescale());
- };
-
- return (
- : }
- variant="ghost"
- size="sm"
- sx={{
- color: 'base.500',
- _hover: {
- color: 'base.600',
- },
- _active: {
- color: 'base.700',
- },
- _dark: {
- color: 'base.500',
- _hover: {
- color: 'base.400',
- },
- _active: {
- color: 'base.300',
- },
- },
- ...sx,
- }}
- />
- );
-};
-
-export default PinParametersPanelButton;
diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx
deleted file mode 100644
index dbe975b17f..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/ResizableDrawer.tsx
+++ /dev/null
@@ -1,196 +0,0 @@
-import {
- Box,
- chakra,
- ChakraProps,
- Slide,
- useOutsideClick,
- useTheme,
- SlideDirection,
- useColorMode,
-} from '@chakra-ui/react';
-import {
- Resizable,
- ResizableProps,
- ResizeCallback,
- ResizeStartCallback,
-} from 're-resizable';
-import { ReactNode, useEffect, useMemo, useRef, useState } from 'react';
-import { LangDirection } from './types';
-import {
- getHandleEnables,
- getMinMaxDimensions,
- getSlideDirection,
- getStyles,
-} from './util';
-import { mode } from 'theme/util/mode';
-
-type ResizableDrawerProps = ResizableProps & {
- children: ReactNode;
- isResizable: boolean;
- isOpen: boolean;
- onClose: () => void;
- direction?: SlideDirection;
- initialWidth?: number;
- minWidth?: number;
- maxWidth?: number;
- initialHeight?: number;
- minHeight?: number;
- maxHeight?: number;
- onResizeStart?: ResizeStartCallback;
- onResizeStop?: ResizeCallback;
- onResize?: ResizeCallback;
- handleWidth?: string | number;
- handleInteractWidth?: string | number;
- sx?: ChakraProps['sx'];
-};
-
-const ChakraResizeable = chakra(Resizable, {
- shouldForwardProp: (prop) => !['sx'].includes(prop),
-});
-
-const ResizableDrawer = ({
- direction = 'left',
- isResizable,
- isOpen,
- onClose,
- children,
- initialWidth,
- minWidth,
- maxWidth,
- initialHeight,
- minHeight,
- maxHeight,
- onResizeStart,
- onResizeStop,
- onResize,
- sx = {},
-}: ResizableDrawerProps) => {
- const langDirection = useTheme().direction as LangDirection;
- const { colorMode } = useColorMode();
- const outsideClickRef = useRef(null);
-
- const defaultWidth = useMemo(
- () =>
- initialWidth ??
- minWidth ??
- (['left', 'right'].includes(direction) ? 'auto' : '100%'),
- [initialWidth, minWidth, direction]
- );
-
- const defaultHeight = useMemo(
- () =>
- initialHeight ??
- minHeight ??
- (['top', 'bottom'].includes(direction) ? 'auto' : '100%'),
- [initialHeight, minHeight, direction]
- );
-
- const [width, setWidth] = useState(defaultWidth);
-
- const [height, setHeight] = useState(defaultHeight);
-
- useOutsideClick({
- ref: outsideClickRef,
- handler: () => {
- onClose();
- },
- enabled: isOpen,
- });
-
- const handleEnables = useMemo(
- () => (isResizable ? getHandleEnables({ direction, langDirection }) : {}),
- [isResizable, langDirection, direction]
- );
-
- const minMaxDimensions = useMemo(
- () =>
- getMinMaxDimensions({
- direction,
- minWidth,
- maxWidth,
- minHeight,
- maxHeight,
- }),
- [minWidth, maxWidth, minHeight, maxHeight, direction]
- );
-
- const { containerStyles, handleStyles } = useMemo(
- () =>
- getStyles({
- isResizable,
- direction,
- }),
- [isResizable, direction]
- );
-
- const slideDirection = useMemo(
- () => getSlideDirection(direction, langDirection),
- [direction, langDirection]
- );
-
- useEffect(() => {
- if (['left', 'right'].includes(direction)) {
- setHeight('100vh');
- // setHeight(isPinned ? '100%' : '100vh');
- }
- if (['top', 'bottom'].includes(direction)) {
- setWidth('100vw');
- // setWidth(isPinned ? '100%' : '100vw');
- }
- }, [direction]);
-
- return (
-
-
- {
- onResizeStart && onResizeStart(event, direction, elementRef);
- }}
- onResize={(event, direction, elementRef, delta) => {
- onResize && onResize(event, direction, elementRef, delta);
- }}
- onResizeStop={(event, direction, elementRef, delta) => {
- if (['left', 'right'].includes(direction)) {
- setWidth(Number(width) + delta.width);
- }
- if (['top', 'bottom'].includes(direction)) {
- setHeight(Number(height) + delta.height);
- }
- onResizeStop && onResizeStop(event, direction, elementRef, delta);
- }}
- >
- {children}
-
-
-
- );
-};
-
-export default ResizableDrawer;
diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts
deleted file mode 100644
index 5aa42ab7e5..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/types.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export type Placement = 'top' | 'right' | 'bottom' | 'left';
-export type LangDirection = 'ltr' | 'rtl' | undefined;
diff --git a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts b/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts
deleted file mode 100644
index c9a660c297..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/common/ResizableDrawer/util.ts
+++ /dev/null
@@ -1,283 +0,0 @@
-import { SlideDirection } from '@chakra-ui/react';
-import { AnimationProps } from 'framer-motion';
-import { HandleStyles } from 're-resizable';
-import { CSSProperties } from 'react';
-import { LangDirection } from './types';
-
-export type GetHandleEnablesOptions = {
- direction: SlideDirection;
- langDirection: LangDirection;
-};
-
-/**
- * Determine handles to enable. `re-resizable` doesn't handle RTL, so we have to do that here.
- */
-export const getHandleEnables = ({
- direction,
- langDirection,
-}: GetHandleEnablesOptions) => {
- const top = direction === 'bottom';
-
- const right =
- (langDirection !== 'rtl' && direction === 'left') ||
- (langDirection === 'rtl' && direction === 'right');
-
- const bottom = direction === 'top';
-
- const left =
- (langDirection !== 'rtl' && direction === 'right') ||
- (langDirection === 'rtl' && direction === 'left');
-
- return {
- top,
- right,
- bottom,
- left,
- };
-};
-
-export type GetDefaultSizeOptions = {
- initialWidth?: string | number;
- initialHeight?: string | number;
- direction: SlideDirection;
-};
-
-// Get default sizes based on direction and initial values
-export const getDefaultSize = ({
- initialWidth,
- initialHeight,
- direction,
-}: GetDefaultSizeOptions) => {
- const width =
- initialWidth ?? (['left', 'right'].includes(direction) ? 500 : '100vw');
-
- const height =
- initialHeight ?? (['top', 'bottom'].includes(direction) ? 500 : '100vh');
-
- return { width, height };
-};
-
-export type GetMinMaxDimensionsOptions = {
- direction: SlideDirection;
- minWidth?: number;
- maxWidth?: number;
- minHeight?: number;
- maxHeight?: number;
-};
-
-// Get the min/max width/height based on direction and provided values
-export const getMinMaxDimensions = ({
- direction,
- minWidth,
- maxWidth,
- minHeight,
- maxHeight,
-}: GetMinMaxDimensionsOptions) => {
- const minW =
- minWidth ?? (['left', 'right'].includes(direction) ? 10 : undefined);
-
- const maxW =
- maxWidth ?? (['left', 'right'].includes(direction) ? '95vw' : undefined);
-
- const minH =
- minHeight ?? (['top', 'bottom'].includes(direction) ? 10 : undefined);
-
- const maxH =
- maxHeight ?? (['top', 'bottom'].includes(direction) ? '95vh' : undefined);
-
- return {
- ...(minW ? { minWidth: minW } : {}),
- ...(maxW ? { maxWidth: maxW } : {}),
- ...(minH ? { minHeight: minH } : {}),
- ...(maxH ? { maxHeight: maxH } : {}),
- };
-};
-
-export type GetAnimationsOptions = {
- direction: SlideDirection;
- langDirection: LangDirection;
-};
-
-// Get the framer-motion animation props, taking into account language direction
-export const getAnimations = ({
- direction,
- langDirection,
-}: GetAnimationsOptions): AnimationProps => {
- const baseAnimation = {
- initial: { opacity: 0 },
- animate: { opacity: 1 },
- exit: { opacity: 0 },
- // chakra consumes the transition prop, which, for it, is a string.
- // however we know the transition prop will make it to framer motion,
- // which wants it as an object. cast as string to satisfy TS.
- transition: { duration: 0.2, ease: 'easeInOut' },
- };
-
- const langDirectionFactor = langDirection === 'rtl' ? -1 : 1;
-
- if (direction === 'top') {
- return {
- ...baseAnimation,
- initial: { y: -999 },
- animate: { y: 0 },
- exit: { y: -999 },
- };
- }
-
- if (direction === 'right') {
- return {
- ...baseAnimation,
- initial: { x: 999 * langDirectionFactor },
- animate: { x: 0 },
- exit: { x: 999 * langDirectionFactor },
- };
- }
-
- if (direction === 'bottom') {
- return {
- ...baseAnimation,
- initial: { y: 999 },
- animate: { y: 0 },
- exit: { y: 999 },
- };
- }
-
- if (direction === 'left') {
- return {
- ...baseAnimation,
- initial: { x: -999 * langDirectionFactor },
- animate: { x: 0 },
- exit: { x: -999 * langDirectionFactor },
- };
- }
-
- return {};
-};
-
-export type GetResizableStylesProps = {
- isResizable: boolean;
- direction: SlideDirection;
-};
-
-// Expand the handle hitbox
-const HANDLE_INTERACT_PADDING = '0.75rem';
-
-// Visible padding around handle
-const HANDLE_PADDING = '1rem';
-const HANDLE_WIDTH = '5px';
-
-// Get the styles for the container and handle. Do not need to handle langDirection here bc we use direction-agnostic CSS
-export const getStyles = ({
- isResizable,
- direction,
-}: GetResizableStylesProps): {
- containerStyles: CSSProperties; // technically this could be ChakraProps['sx'], but we cannot use this for HandleStyles so leave it as CSSProperties to be consistent
- handleStyles: HandleStyles;
-} => {
- // if (!isResizable) {
- // return { containerStyles: {}, handleStyles: {} };
- // }
-
- // Calculate the positioning offset of the handle hitbox so it is centered over the handle
- const handleOffset = `calc((2 * ${HANDLE_INTERACT_PADDING} + ${HANDLE_WIDTH}) / -2)`;
-
- if (direction === 'top') {
- return {
- containerStyles: {
- borderBottomWidth: HANDLE_WIDTH,
- paddingBottom: HANDLE_PADDING,
- },
- handleStyles: isResizable
- ? {
- top: {
- paddingTop: HANDLE_INTERACT_PADDING,
- paddingBottom: HANDLE_INTERACT_PADDING,
- bottom: handleOffset,
- },
- }
- : {},
- };
- }
-
- if (direction === 'left') {
- return {
- containerStyles: {
- borderInlineEndWidth: HANDLE_WIDTH,
- paddingInlineEnd: HANDLE_PADDING,
- },
- handleStyles: isResizable
- ? {
- right: {
- paddingInlineStart: HANDLE_INTERACT_PADDING,
- paddingInlineEnd: HANDLE_INTERACT_PADDING,
- insetInlineEnd: handleOffset,
- },
- }
- : {},
- };
- }
-
- if (direction === 'bottom') {
- return {
- containerStyles: {
- borderTopWidth: HANDLE_WIDTH,
- paddingTop: HANDLE_PADDING,
- },
- handleStyles: isResizable
- ? {
- bottom: {
- paddingTop: HANDLE_INTERACT_PADDING,
- paddingBottom: HANDLE_INTERACT_PADDING,
- top: handleOffset,
- },
- }
- : {},
- };
- }
-
- if (direction === 'right') {
- return {
- containerStyles: {
- borderInlineStartWidth: HANDLE_WIDTH,
- paddingInlineStart: HANDLE_PADDING,
- },
- handleStyles: isResizable
- ? {
- left: {
- paddingInlineStart: HANDLE_INTERACT_PADDING,
- paddingInlineEnd: HANDLE_INTERACT_PADDING,
- insetInlineStart: handleOffset,
- },
- }
- : {},
- };
- }
-
- return { containerStyles: {}, handleStyles: {} };
-};
-
-// Chakra's Slide does not handle langDirection, so we need to do it here
-export const getSlideDirection = (
- direction: SlideDirection,
- langDirection: LangDirection
-) => {
- if (['top', 'bottom'].includes(direction)) {
- return direction;
- }
-
- if (direction === 'left') {
- if (langDirection === 'rtl') {
- return 'right';
- }
- return 'left';
- }
-
- if (direction === 'right') {
- if (langDirection === 'rtl') {
- return 'left';
- }
- return 'right';
- }
-
- return 'left';
-};
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx
index d58630d1b9..8744fc2e0c 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTab.tsx
@@ -1,73 +1,57 @@
-import { Box, Flex } from '@chakra-ui/react';
-import { RootState } from 'app/store/store';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
+import { Box } from '@chakra-ui/react';
import InitialImageDisplay from 'features/parameters/components/Parameters/ImageToImage/InitialImageDisplay';
-import SDXLImageToImageTabParameters from 'features/sdxl/components/SDXLImageToImageTabParameters';
+import { usePanelStorage } from 'features/ui/hooks/usePanelStorage';
import { memo, useCallback, useRef } from 'react';
import {
ImperativePanelGroupHandle,
Panel,
PanelGroup,
} from 'react-resizable-panels';
-import ParametersPinnedWrapper from '../../ParametersPinnedWrapper';
import ResizeHandle from '../ResizeHandle';
import TextToImageTabMain from '../TextToImage/TextToImageTabMain';
-import ImageToImageTabParameters from './ImageToImageTabParameters';
const ImageToImageTab = () => {
- const dispatch = useAppDispatch();
const panelGroupRef = useRef(null);
- const model = useAppSelector((state: RootState) => state.generation.model);
const handleDoubleClickHandle = useCallback(() => {
if (!panelGroupRef.current) {
return;
}
-
panelGroupRef.current.setLayout([50, 50]);
}, []);
+ const panelStorage = usePanelStorage();
+
return (
-
-
- {model && model.base_model === 'sdxl' ? (
-
- ) : (
-
- )}
-
-
-
+
+
-
-
-
-
- {
- dispatch(requestCanvasRescale());
- }}
- >
-
-
-
-
-
+
+
+
+
+
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabCoreParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabCoreParameters.tsx
index d343d17a47..5c6f68e6ed 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabCoreParameters.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/ImageToImageTabCoreParameters.tsx
@@ -32,11 +32,7 @@ const ImageToImageTabCoreParameters = () => {
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
return (
-
+
{
return (
<>
-
- {/* */}
@@ -28,4 +25,4 @@ const ImageToImageTabParameters = () => {
);
};
-export default ImageToImageTabParameters;
+export default memo(ImageToImageTabParameters);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/AdvancedAddModels.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/AdvancedAddModels.tsx
index 88e83fadc8..a2a12b7f00 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/AdvancedAddModels.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/AdvancedAddModels.tsx
@@ -23,7 +23,9 @@ export default function AdvancedAddModels() {
value={advancedAddMode}
data={advancedAddModeData}
onChange={(v) => {
- if (!v) return;
+ if (!v) {
+ return;
+ }
setAdvancedAddMode(v as ManualAddMode);
}}
/>
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/ScanAdvancedAddModels.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/ScanAdvancedAddModels.tsx
index 32906c3396..997341279d 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/ScanAdvancedAddModels.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/ScanAdvancedAddModels.tsx
@@ -74,7 +74,9 @@ export default function ScanAdvancedAddModels() {
value={advancedAddMode}
data={advancedAddModeData}
onChange={(v) => {
- if (!v) return;
+ if (!v) {
+ return;
+ }
setAdvancedAddMode(v as ManualAddMode);
if (v === 'checkpoint') {
setIsCheckpoint(true);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelConvert.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelConvert.tsx
index 045745e206..56dcdfd52f 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelConvert.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelConvert.tsx
@@ -111,7 +111,7 @@ export default function ModelConvert(props: ModelConvertProps) {
acceptButtonText={`${t('modelManager.convert')}`}
triggerComponent={
{
);
};
-export default ModelList;
+export default memo(ModelList);
const modelsFilter = <
T extends
| MainModelConfigEntity
| LoRAModelConfigEntity
- | OnnxModelConfigEntity
+ | OnnxModelConfigEntity,
>(
data: EntityState | undefined,
model_type: ModelType,
@@ -266,7 +266,7 @@ const modelsFilter = <
return filteredModels;
};
-const StyledModelContainer = (props: PropsWithChildren) => {
+const StyledModelContainer = memo((props: PropsWithChildren) => {
return (
{
{props.children}
);
-};
+});
+
+StyledModelContainer.displayName = 'StyledModelContainer';
type ModelListWrapperProps = {
title: string;
@@ -294,7 +296,7 @@ type ModelListWrapperProps = {
selected: ModelListProps;
};
-function ModelListWrapper(props: ModelListWrapperProps) {
+const ModelListWrapper = memo((props: ModelListWrapperProps) => {
const { title, modelList, selected } = props;
return (
@@ -313,23 +315,29 @@ function ModelListWrapper(props: ModelListWrapperProps) {
);
-}
+});
-function FetchingModelsLoader({ loadingMessage }: { loadingMessage?: string }) {
- return (
-
-
-
-
- {loadingMessage ? loadingMessage : 'Fetching...'}
-
-
-
- );
-}
+ModelListWrapper.displayName = 'ModelListWrapper';
+
+const FetchingModelsLoader = memo(
+ ({ loadingMessage }: { loadingMessage?: string }) => {
+ return (
+
+
+
+
+ {loadingMessage ? loadingMessage : 'Fetching...'}
+
+
+
+ );
+ }
+);
+
+FetchingModelsLoader.displayName = 'FetchingModelsLoader';
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerSettingsPanel/SyncModelsButton.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerSettingsPanel/SyncModelsButton.tsx
index 6405fba1a7..33ee345ef7 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerSettingsPanel/SyncModelsButton.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerSettingsPanel/SyncModelsButton.tsx
@@ -1,18 +1,19 @@
-import { makeToast } from 'features/system/util/makeToast';
+import { ButtonProps } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
import IAIButton from 'common/components/IAIButton';
import IAIIconButton from 'common/components/IAIIconButton';
import { addToast } from 'features/system/store/systemSlice';
+import { makeToast } from 'features/system/util/makeToast';
import { useTranslation } from 'react-i18next';
import { FaSync } from 'react-icons/fa';
import { useSyncModelsMutation } from 'services/api/endpoints/models';
-type SyncModelsButtonProps = {
+type SyncModelsButtonProps = ButtonProps & {
iconMode?: boolean;
};
export default function SyncModelsButton(props: SyncModelsButtonProps) {
- const { iconMode = false } = props;
+ const { iconMode = false, ...rest } = props;
const dispatch = useAppDispatch();
const { t } = useTranslation();
@@ -50,6 +51,7 @@ export default function SyncModelsButton(props: SyncModelsButtonProps) {
isLoading={isLoading}
onClick={syncModelsHandler}
minW="max-content"
+ {...rest}
>
Sync Models
@@ -61,6 +63,7 @@ export default function SyncModelsButton(props: SyncModelsButtonProps) {
isLoading={isLoading}
onClick={syncModelsHandler}
size="sm"
+ {...rest}
/>
);
}
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx
index b8f99bfa29..b2defec39d 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ResizeHandle.tsx
@@ -5,16 +5,27 @@ import { PanelResizeHandle } from 'react-resizable-panels';
type ResizeHandleProps = Omit & {
direction?: 'horizontal' | 'vertical';
collapsedDirection?: 'top' | 'bottom' | 'left' | 'right';
+ isCollapsed?: boolean;
};
const ResizeHandle = (props: ResizeHandleProps) => {
- const { direction = 'horizontal', collapsedDirection, ...rest } = props;
+ const {
+ direction = 'horizontal',
+ collapsedDirection,
+ isCollapsed = false,
+ ...rest
+ } = props;
const bg = useColorModeValue('base.100', 'base.850');
const hoverBg = useColorModeValue('base.300', 'base.700');
if (direction === 'horizontal') {
return (
-
+
{
}
return (
-
+
{
- const model = useAppSelector((state: RootState) => state.generation.model);
- return (
-
-
- {model && model.base_model === 'sdxl' ? (
-
- ) : (
-
- )}
-
-
-
- );
+ return ;
};
export default memo(TextToImageTab);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters.tsx
index de8f64e661..152efd3e17 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters.tsx
@@ -29,11 +29,7 @@ const TextToImageTabCoreParameters = () => {
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
return (
-
+
{
return (
@@ -25,4 +26,4 @@ const TextToImageTabMain = () => {
);
};
-export default TextToImageTabMain;
+export default memo(TextToImageTabMain);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx
index 75fa063e17..559ef0849a 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/TextToImage/TextToImageTabParameters.tsx
@@ -5,8 +5,7 @@ import ParamControlNetCollapse from 'features/parameters/components/Parameters/C
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
-// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
-import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
+import { memo } from 'react';
import ParamPromptArea from '../../../../parameters/components/Parameters/Prompt/ParamPromptArea';
import TextToImageTabCoreParameters from './TextToImageTabCoreParameters';
@@ -14,12 +13,10 @@ const TextToImageTabParameters = () => {
return (
<>
-
- {/* */}
@@ -28,4 +25,4 @@ const TextToImageTabParameters = () => {
);
};
-export default TextToImageTabParameters;
+export default memo(TextToImageTabParameters);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx
index c83bb6934e..0b8366b06d 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasColorPicker.tsx
@@ -35,10 +35,12 @@ export default function UnifiedCanvasColorPicker() {
const { brushColor, maskColor, layer, isStaging } = useAppSelector(selector);
const currentColorDisplay = () => {
- if (layer === 'base')
+ if (layer === 'base') {
return `rgba(${brushColor.r},${brushColor.g},${brushColor.b},${brushColor.a})`;
- if (layer === 'mask')
+ }
+ if (layer === 'mask') {
return `rgba(${maskColor.r},${maskColor.g},${maskColor.b},${maskColor.a})`;
+ }
};
useHotkeys(
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx
index a179a95c3f..22737ce0bb 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolSettings/UnifiedCanvasSettings.tsx
@@ -18,6 +18,7 @@ import { FaWrench } from 'react-icons/fa';
import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal';
import { isEqual } from 'lodash-es';
import { useTranslation } from 'react-i18next';
+import { memo } from 'react';
export const canvasControlsSelector = createSelector(
[canvasSelector],
@@ -109,4 +110,4 @@ const UnifiedCanvasSettings = () => {
);
};
-export default UnifiedCanvasSettings;
+export default memo(UnifiedCanvasSettings);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx
deleted file mode 100644
index ca2d2a1d0a..0000000000
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { Flex } from '@chakra-ui/layout';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import IAIIconButton from 'common/components/IAIIconButton';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
-import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton';
-import InvokeButton from 'features/parameters/components/ProcessButtons/InvokeButton';
-import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice';
-import { useTranslation } from 'react-i18next';
-import { FaSlidersH } from 'react-icons/fa';
-
-export default function UnifiedCanvasProcessingButtons() {
- const shouldPinParametersPanel = useAppSelector(
- (state) => state.ui.shouldPinParametersPanel
- );
- const shouldShowParametersPanel = useAppSelector(
- (state) => state.ui.shouldShowParametersPanel
- );
-
- const dispatch = useAppDispatch();
- const { t } = useTranslation();
-
- const handleShowOptionsPanel = () => {
- dispatch(setShouldShowParametersPanel(true));
- shouldPinParametersPanel && dispatch(requestCanvasRescale());
- };
-
- return !shouldPinParametersPanel || !shouldShowParametersPanel ? (
-
-
-
-
-
-
-
-
-
-
-
- ) : null;
-}
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx
index e8eeed7acc..85396c87be 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasResetCanvas.tsx
@@ -1,10 +1,7 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
-import {
- resetCanvas,
- resizeAndScaleCanvas,
-} from 'features/canvas/store/canvasSlice';
+import { resetCanvas } from 'features/canvas/store/canvasSlice';
import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa';
@@ -15,7 +12,6 @@ export default function UnifiedCanvasResetCanvas() {
const handleResetCanvas = () => {
dispatch(resetCanvas());
- dispatch(resizeAndScaleCanvas());
};
return (
{
const canvasBaseLayer = getCanvasBaseLayer();
- if (!canvasBaseLayer) return;
+ if (!canvasBaseLayer) {
+ return;
+ }
const clientRect = canvasBaseLayer.getClientRect({
skipTransform: true,
});
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx
index a6c4ec7c40..a11f40a257 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbar/UnifiedCanvasToolSelect.tsx
@@ -13,6 +13,7 @@ import {
} from 'features/canvas/store/canvasSlice';
import { systemSelector } from 'features/system/store/systemSelectors';
import { isEqual } from 'lodash-es';
+import { memo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
@@ -161,4 +162,4 @@ const UnifiedCanvasToolSelect = () => {
);
};
-export default UnifiedCanvasToolSelect;
+export default memo(UnifiedCanvasToolSelect);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx
index b5eec3bec3..7ef5af6949 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasBeta/UnifiedCanvasToolbarBeta.tsx
@@ -2,6 +2,7 @@ import { Flex } from '@chakra-ui/react';
import IAICanvasRedoButton from 'features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton';
import IAICanvasUndoButton from 'features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton';
+import { memo } from 'react';
import UnifiedCanvasSettings from './UnifiedCanvasToolSettings/UnifiedCanvasSettings';
import UnifiedCanvasCopyToClipboard from './UnifiedCanvasToolbar/UnifiedCanvasCopyToClipboard';
import UnifiedCanvasDownloadImage from './UnifiedCanvasToolbar/UnifiedCanvasDownloadImage';
@@ -9,7 +10,6 @@ import UnifiedCanvasFileUploader from './UnifiedCanvasToolbar/UnifiedCanvasFileU
import UnifiedCanvasLayerSelect from './UnifiedCanvasToolbar/UnifiedCanvasLayerSelect';
import UnifiedCanvasMergeVisible from './UnifiedCanvasToolbar/UnifiedCanvasMergeVisible';
import UnifiedCanvasMoveTool from './UnifiedCanvasToolbar/UnifiedCanvasMoveTool';
-import UnifiedCanvasProcessingButtons from './UnifiedCanvasToolbar/UnifiedCanvasProcessingButtons';
import UnifiedCanvasResetCanvas from './UnifiedCanvasToolbar/UnifiedCanvasResetCanvas';
import UnifiedCanvasResetView from './UnifiedCanvasToolbar/UnifiedCanvasResetView';
import UnifiedCanvasSaveToGallery from './UnifiedCanvasToolbar/UnifiedCanvasSaveToGallery';
@@ -46,9 +46,8 @@ const UnifiedCanvasToolbarBeta = () => {
-
);
};
-export default UnifiedCanvasToolbarBeta;
+export default memo(UnifiedCanvasToolbarBeta);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx
index 91bf4732c3..601493afe9 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasContent.tsx
@@ -1,33 +1,11 @@
-import { Box, Flex } from '@chakra-ui/react';
-import { createSelector } from '@reduxjs/toolkit';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
+import { Flex } from '@chakra-ui/react';
import IAIDropOverlay from 'common/components/IAIDropOverlay';
import IAICanvas from 'features/canvas/components/IAICanvas';
-import IAICanvasResizer from 'features/canvas/components/IAICanvasResizer';
import IAICanvasToolbar from 'features/canvas/components/IAICanvasToolbar/IAICanvasToolbar';
-import { canvasSelector } from 'features/canvas/store/canvasSelectors';
-import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks';
import { CanvasInitialImageDropData } from 'features/dnd/types';
import { isValidDrop } from 'features/dnd/util/isValidDrop';
-import { uiSelector } from 'features/ui/store/uiSelectors';
-import { memo, useLayoutEffect } from 'react';
-import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta';
-import UnifiedCanvasToolbarBeta from './UnifiedCanvasBeta/UnifiedCanvasToolbarBeta';
-
-const selector = createSelector(
- [canvasSelector, uiSelector],
- (canvas, ui) => {
- const { doesCanvasNeedScaling } = canvas;
- const { shouldUseCanvasBetaLayout } = ui;
- return {
- doesCanvasNeedScaling,
- shouldUseCanvasBetaLayout,
- };
- },
- defaultSelectorOptions
-);
+import { memo } from 'react';
const droppableData: CanvasInitialImageDropData = {
id: 'canvas-intial-image',
@@ -35,11 +13,6 @@ const droppableData: CanvasInitialImageDropData = {
};
const UnifiedCanvasContent = () => {
- const dispatch = useAppDispatch();
-
- const { doesCanvasNeedScaling, shouldUseCanvasBetaLayout } =
- useAppSelector(selector);
-
const {
isOver,
setNodeRef: setDroppableRef,
@@ -49,106 +22,27 @@ const UnifiedCanvasContent = () => {
data: droppableData,
});
- useLayoutEffect(() => {
- const resizeCallback = () => {
- dispatch(requestCanvasRescale());
- };
-
- window.addEventListener('resize', resizeCallback);
-
- return () => window.removeEventListener('resize', resizeCallback);
- }, [dispatch]);
-
- if (shouldUseCanvasBetaLayout) {
- return (
-
-
-
-
-
-
- {doesCanvasNeedScaling ? : }
- {isValidDrop(droppableData, active) && (
-
- )}
-
-
-
-
- );
- }
-
return (
-
-
-
-
-
- {doesCanvasNeedScaling ? : }
- {isValidDrop(droppableData, active) && (
-
- )}
-
-
-
-
+
+
+ {isValidDrop(droppableData, active) && (
+
+ )}
+
);
};
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasCoreParameters.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasCoreParameters.tsx
index 6e4ce7d5d0..36f7ff7320 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasCoreParameters.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasCoreParameters.tsx
@@ -30,11 +30,7 @@ const UnifiedCanvasCoreParameters = () => {
const { shouldUseSliders, activeLabel } = useAppSelector(selector);
return (
-
+
{
return (
<>
-
- {/* */}
-
+
>
);
};
-export default UnifiedCanvasParameters;
+export default memo(UnifiedCanvasParameters);
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx
index 0a5b872e4b..33af70e2bc 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/UnifiedCanvas/UnifiedCanvasTab.tsx
@@ -1,26 +1,8 @@
-import { Flex } from '@chakra-ui/react';
-import { RootState } from 'app/store/store';
-import { useAppSelector } from 'app/store/storeHooks';
-import SDXLUnifiedCanvasTabParameters from 'features/sdxl/components/SDXLUnifiedCanvasTabParameters';
import { memo } from 'react';
-import ParametersPinnedWrapper from '../../ParametersPinnedWrapper';
import UnifiedCanvasContent from './UnifiedCanvasContent';
-import UnifiedCanvasParameters from './UnifiedCanvasParameters';
const UnifiedCanvasTab = () => {
- const model = useAppSelector((state: RootState) => state.generation.model);
- return (
-
-
- {model && model.base_model === 'sdxl' ? (
-
- ) : (
-
- )}
-
-
-
- );
+ return ;
};
export default memo(UnifiedCanvasTab);
diff --git a/invokeai/frontend/web/src/features/ui/hooks/useMinimumPanelSize.ts b/invokeai/frontend/web/src/features/ui/hooks/useMinimumPanelSize.ts
deleted file mode 100644
index 3b2d9a068a..0000000000
--- a/invokeai/frontend/web/src/features/ui/hooks/useMinimumPanelSize.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-// adapted from https://github.com/bvaughn/react-resizable-panels/issues/141#issuecomment-1540048714
-
-import {
- RefObject,
- useCallback,
- useLayoutEffect,
- useRef,
- useState,
-} from 'react';
-import { ImperativePanelHandle } from 'react-resizable-panels';
-
-export const useMinimumPanelSize = (
- minSizePx: number,
- defaultSizePct: number,
- groupId: string,
- orientation: 'horizontal' | 'vertical' = 'horizontal'
-): {
- ref: RefObject;
- minSizePct: number;
-} => {
- const ref = useRef(null);
- const [minSizePct, setMinSizePct] = useState(defaultSizePct);
-
- const handleWindowResize = useCallback(() => {
- const size = ref.current?.getSize();
-
- if (size !== undefined && size < minSizePct) {
- ref.current?.resize(minSizePct);
- }
- }, [minSizePct]);
-
- useLayoutEffect(() => {
- const panelGroup = document.querySelector(
- `[data-panel-group-id="${groupId}"]`
- );
- const resizeHandles = document.querySelectorAll(
- orientation === 'horizontal'
- ? '.resize-handle-horizontal'
- : '.resize-handle-vertical'
- );
-
- if (!panelGroup) {
- return;
- }
- const observer = new ResizeObserver(() => {
- let dim =
- orientation === 'horizontal'
- ? panelGroup.getBoundingClientRect().width
- : panelGroup.getBoundingClientRect().height;
-
- resizeHandles.forEach((resizeHandle) => {
- dim -=
- orientation === 'horizontal'
- ? resizeHandle.getBoundingClientRect().width
- : resizeHandle.getBoundingClientRect().height;
- });
-
- // Minimum size in pixels is a percentage of the PanelGroup's width/height
- setMinSizePct((minSizePx / dim) * 100);
- });
- observer.observe(panelGroup);
- resizeHandles.forEach((resizeHandle) => {
- observer.observe(resizeHandle);
- });
-
- window.addEventListener('resize', handleWindowResize);
-
- return () => {
- observer.disconnect();
- window.removeEventListener('resize', handleWindowResize);
- };
- }, [groupId, handleWindowResize, minSizePct, minSizePx, orientation]);
-
- return { ref, minSizePct };
-};
diff --git a/invokeai/frontend/web/src/features/ui/hooks/usePanel.ts b/invokeai/frontend/web/src/features/ui/hooks/usePanel.ts
new file mode 100644
index 0000000000..f1deaa1c35
--- /dev/null
+++ b/invokeai/frontend/web/src/features/ui/hooks/usePanel.ts
@@ -0,0 +1,52 @@
+import { useCallback, useRef, useState } from 'react';
+import { flushSync } from 'react-dom';
+import { ImperativePanelHandle, Units } from 'react-resizable-panels';
+
+export const usePanel = (minSize: number, units: Units) => {
+ const ref = useRef(null);
+
+ const [isCollapsed, setIsCollapsed] = useState(() =>
+ Boolean(ref.current?.getCollapsed())
+ );
+
+ const toggle = useCallback(() => {
+ if (ref.current?.getCollapsed()) {
+ flushSync(() => {
+ ref.current?.expand();
+ });
+ } else {
+ flushSync(() => {
+ ref.current?.collapse();
+ });
+ }
+ }, []);
+
+ const expand = useCallback(() => {
+ flushSync(() => {
+ ref.current?.expand();
+ });
+ }, []);
+
+ const collapse = useCallback(() => {
+ flushSync(() => {
+ ref.current?.collapse();
+ });
+ }, []);
+
+ const reset = useCallback(() => {
+ flushSync(() => {
+ ref.current?.resize(minSize, units);
+ });
+ }, [minSize, units]);
+
+ return {
+ ref,
+ minSize,
+ isCollapsed,
+ setIsCollapsed,
+ reset,
+ toggle,
+ expand,
+ collapse,
+ };
+};
diff --git a/invokeai/frontend/web/src/features/ui/hooks/usePanelStorage.ts b/invokeai/frontend/web/src/features/ui/hooks/usePanelStorage.ts
new file mode 100644
index 0000000000..a19125b92b
--- /dev/null
+++ b/invokeai/frontend/web/src/features/ui/hooks/usePanelStorage.ts
@@ -0,0 +1,17 @@
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { useCallback } from 'react';
+import { panelsChanged } from '../store/uiSlice';
+
+export const usePanelStorage = () => {
+ const dispatch = useAppDispatch();
+ const panels = useAppSelector((state) => state.ui.panels);
+ const getItem = useCallback((name: string) => panels[name] ?? '', [panels]);
+ const setItem = useCallback(
+ (name: string, value: string) => {
+ dispatch(panelsChanged({ name, value }));
+ },
+ [dispatch]
+ );
+
+ return { getItem, setItem };
+};
diff --git a/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts b/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts
index 07fefd95e8..ec26c26d0c 100644
--- a/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts
+++ b/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts
@@ -6,4 +6,5 @@ import { UIState } from './uiTypes';
export const uiPersistDenylist: (keyof UIState)[] = [
'shouldShowImageDetails',
'globalContextMenuCloseTrigger',
+ 'panels',
];
diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts
index ca35eab300..2e4227e8e6 100644
--- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts
+++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts
@@ -8,19 +8,16 @@ import { UIState } from './uiTypes';
export const initialUIState: UIState = {
activeTab: 0,
- shouldPinParametersPanel: true,
- shouldShowParametersPanel: true,
shouldShowImageDetails: false,
shouldUseCanvasBetaLayout: false,
shouldShowExistingModelsInSearch: false,
shouldUseSliders: false,
- shouldPinGallery: true,
- shouldShowGallery: true,
shouldHidePreview: false,
shouldShowProgressInViewer: true,
shouldShowEmbeddingPicker: false,
favoriteSchedulers: [],
globalContextMenuCloseTrigger: 0,
+ panels: {},
};
export const uiSlice = createSlice({
@@ -30,13 +27,6 @@ export const uiSlice = createSlice({
setActiveTab: (state, action: PayloadAction) => {
setActiveTabReducer(state, action.payload);
},
- setShouldPinParametersPanel: (state, action: PayloadAction) => {
- state.shouldPinParametersPanel = action.payload;
- state.shouldShowParametersPanel = true;
- },
- setShouldShowParametersPanel: (state, action: PayloadAction) => {
- state.shouldShowParametersPanel = action.payload;
- },
setShouldShowImageDetails: (state, action: PayloadAction) => {
state.shouldShowImageDetails = action.payload;
},
@@ -55,36 +45,6 @@ export const uiSlice = createSlice({
setShouldUseSliders: (state, action: PayloadAction) => {
state.shouldUseSliders = action.payload;
},
- setShouldShowGallery: (state, action: PayloadAction) => {
- state.shouldShowGallery = action.payload;
- },
- togglePinGalleryPanel: (state) => {
- state.shouldPinGallery = !state.shouldPinGallery;
- if (!state.shouldPinGallery) {
- state.shouldShowGallery = true;
- }
- },
- togglePinParametersPanel: (state) => {
- state.shouldPinParametersPanel = !state.shouldPinParametersPanel;
- if (!state.shouldPinParametersPanel) {
- state.shouldShowParametersPanel = true;
- }
- },
- toggleParametersPanel: (state) => {
- state.shouldShowParametersPanel = !state.shouldShowParametersPanel;
- },
- toggleGalleryPanel: (state) => {
- state.shouldShowGallery = !state.shouldShowGallery;
- },
- togglePanels: (state) => {
- if (state.shouldShowGallery || state.shouldShowParametersPanel) {
- state.shouldShowGallery = false;
- state.shouldShowParametersPanel = false;
- } else {
- state.shouldShowGallery = true;
- state.shouldShowParametersPanel = true;
- }
- },
setShouldShowProgressInViewer: (state, action: PayloadAction) => {
state.shouldShowProgressInViewer = action.payload;
},
@@ -100,6 +60,12 @@ export const uiSlice = createSlice({
contextMenusClosed: (state) => {
state.globalContextMenuCloseTrigger += 1;
},
+ panelsChanged: (
+ state,
+ action: PayloadAction<{ name: string; value: string }>
+ ) => {
+ state.panels[action.payload.name] = action.payload.value;
+ },
},
extraReducers(builder) {
builder.addCase(initialImageChanged, (state) => {
@@ -110,23 +76,16 @@ export const uiSlice = createSlice({
export const {
setActiveTab,
- setShouldPinParametersPanel,
- setShouldShowParametersPanel,
setShouldShowImageDetails,
setShouldUseCanvasBetaLayout,
setShouldShowExistingModelsInSearch,
setShouldUseSliders,
setShouldHidePreview,
- setShouldShowGallery,
- togglePanels,
- togglePinGalleryPanel,
- togglePinParametersPanel,
- toggleParametersPanel,
- toggleGalleryPanel,
setShouldShowProgressInViewer,
favoriteSchedulersChanged,
toggleEmbeddingPicker,
contextMenusClosed,
+ panelsChanged,
} = uiSlice.actions;
export default uiSlice.reducer;
diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts
index 08c75a12f5..0f0ed64f97 100644
--- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts
+++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts
@@ -14,17 +14,14 @@ export type Rect = Coordinates & Dimensions;
export interface UIState {
activeTab: number;
- shouldPinParametersPanel: boolean;
- shouldShowParametersPanel: boolean;
shouldShowImageDetails: boolean;
shouldUseCanvasBetaLayout: boolean;
shouldShowExistingModelsInSearch: boolean;
shouldUseSliders: boolean;
shouldHidePreview: boolean;
- shouldPinGallery: boolean;
- shouldShowGallery: boolean;
shouldShowProgressInViewer: boolean;
shouldShowEmbeddingPicker: boolean;
favoriteSchedulers: SchedulerParam[];
globalContextMenuCloseTrigger: number;
+ panels: Record;
}
diff --git a/invokeai/frontend/web/src/mantine-theme/hooks/useMantineSelectStyles.ts b/invokeai/frontend/web/src/mantine-theme/hooks/useMantineSelectStyles.ts
index f8aa16558f..d56b6cc70d 100644
--- a/invokeai/frontend/web/src/mantine-theme/hooks/useMantineSelectStyles.ts
+++ b/invokeai/frontend/web/src/mantine-theme/hooks/useMantineSelectStyles.ts
@@ -24,6 +24,9 @@ export const useMantineSelectStyles = () => {
const { colorMode } = useColorMode();
const [boxShadow] = useToken('shadows', ['dark-lg']);
+ const [space1, space2, space6] = useToken('space', [1, 2, 6]);
+ const [radiiBase] = useToken('radii', ['base']);
+ const [lineHeightsBase] = useToken('lineHeights', ['base']);
const styles = useCallback(
() => ({
@@ -35,11 +38,22 @@ export const useMantineSelectStyles = () => {
'::after': { borderTopColor: mode(base300, base700)(colorMode) },
},
input: {
+ border: 'unset',
backgroundColor: mode(base50, base900)(colorMode),
+ borderRadius: radiiBase,
+ borderStyle: 'solid',
borderWidth: '2px',
borderColor: mode(base200, base800)(colorMode),
color: mode(base900, base100)(colorMode),
- paddingRight: 24,
+ minHeight: 'unset',
+ lineHeight: lineHeightsBase,
+ height: 'auto',
+ paddingRight: 0,
+ paddingLeft: 0,
+ paddingInlineStart: space2,
+ paddingInlineEnd: space6,
+ paddingTop: space1,
+ paddingBottom: space1,
fontWeight: 600,
'&:hover': { borderColor: mode(base300, base600)(colorMode) },
'&:focus': {
@@ -127,6 +141,11 @@ export const useMantineSelectStyles = () => {
base900,
boxShadow,
colorMode,
+ lineHeightsBase,
+ radiiBase,
+ space1,
+ space2,
+ space6,
]
);
diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts
index 316ee0c085..516ee49d48 100644
--- a/invokeai/frontend/web/src/services/api/schema.d.ts
+++ b/invokeai/frontend/web/src/services/api/schema.d.ts
@@ -7,104 +7,104 @@
export type paths = {
"/api/v1/sessions/": {
/**
- * List Sessions
+ * List Sessions
* @description Gets a list of sessions, optionally searching
*/
get: operations["list_sessions"];
/**
- * Create Session
+ * Create Session
* @description Creates a new session, optionally initializing it with an invocation graph
*/
post: operations["create_session"];
};
"/api/v1/sessions/{session_id}": {
/**
- * Get Session
+ * Get Session
* @description Gets a session
*/
get: operations["get_session"];
};
"/api/v1/sessions/{session_id}/nodes": {
/**
- * Add Node
+ * Add Node
* @description Adds a node to the graph
*/
post: operations["add_node"];
};
"/api/v1/sessions/{session_id}/nodes/{node_path}": {
/**
- * Update Node
+ * Update Node
* @description Updates a node in the graph and removes all linked edges
*/
put: operations["update_node"];
/**
- * Delete Node
+ * Delete Node
* @description Deletes a node in the graph and removes all linked edges
*/
delete: operations["delete_node"];
};
"/api/v1/sessions/{session_id}/edges": {
/**
- * Add Edge
+ * Add Edge
* @description Adds an edge to the graph
*/
post: operations["add_edge"];
};
"/api/v1/sessions/{session_id}/edges/{from_node_id}/{from_field}/{to_node_id}/{to_field}": {
/**
- * Delete Edge
+ * Delete Edge
* @description Deletes an edge from the graph
*/
delete: operations["delete_edge"];
};
"/api/v1/sessions/{session_id}/invoke": {
/**
- * Invoke Session
+ * Invoke Session
* @description Invokes a session
*/
put: operations["invoke_session"];
/**
- * Cancel Session Invoke
+ * Cancel Session Invoke
* @description Invokes a session
*/
delete: operations["cancel_session_invoke"];
};
"/api/v1/models/": {
/**
- * List Models
+ * List Models
* @description Gets a list of models
*/
get: operations["list_models"];
};
"/api/v1/models/{base_model}/{model_type}/{model_name}": {
/**
- * Delete Model
+ * Delete Model
* @description Delete Model
*/
delete: operations["del_model"];
/**
- * Update Model
+ * Update Model
* @description Update model contents with a new config. If the model name or base fields are changed, then the model is renamed.
*/
patch: operations["update_model"];
};
"/api/v1/models/import": {
/**
- * Import Model
+ * Import Model
* @description Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically
*/
post: operations["import_model"];
};
"/api/v1/models/add": {
/**
- * Add Model
+ * Add Model
* @description Add a model using the configuration information appropriate for its type. Only local models can be added by path
*/
post: operations["add_model"];
};
"/api/v1/models/convert/{base_model}/{model_type}/{model_name}": {
/**
- * Convert Model
+ * Convert Model
* @description Convert a checkpoint model into a diffusers model, optionally saving to the indicated destination directory, or `models` if none.
*/
put: operations["convert_model"];
@@ -115,14 +115,14 @@ export type paths = {
};
"/api/v1/models/ckpt_confs": {
/**
- * List Ckpt Configs
+ * List Ckpt Configs
* @description Return a list of the legacy checkpoint configuration files stored in `ROOT/configs/stable-diffusion`, relative to ROOT.
*/
get: operations["list_ckpt_configs"];
};
"/api/v1/models/sync": {
/**
- * Sync To Config
+ * Sync To Config
* @description Call after making changes to models.yaml, autoimport directories or models directory to synchronize
* in-memory data structures with disk data structures.
*/
@@ -130,78 +130,78 @@ export type paths = {
};
"/api/v1/models/merge/{base_model}": {
/**
- * Merge Models
+ * Merge Models
* @description Convert a checkpoint model into a diffusers model
*/
put: operations["merge_models"];
};
"/api/v1/images/upload": {
/**
- * Upload Image
+ * Upload Image
* @description Uploads an image
*/
post: operations["upload_image"];
};
"/api/v1/images/i/{image_name}": {
/**
- * Get Image Dto
+ * Get Image Dto
* @description Gets an image's DTO
*/
get: operations["get_image_dto"];
/**
- * Delete Image
+ * Delete Image
* @description Deletes an image
*/
delete: operations["delete_image"];
/**
- * Update Image
+ * Update Image
* @description Updates an image
*/
patch: operations["update_image"];
};
"/api/v1/images/clear-intermediates": {
/**
- * Clear Intermediates
+ * Clear Intermediates
* @description Clears all intermediates
*/
post: operations["clear_intermediates"];
};
"/api/v1/images/i/{image_name}/metadata": {
/**
- * Get Image Metadata
+ * Get Image Metadata
* @description Gets an image's metadata
*/
get: operations["get_image_metadata"];
};
"/api/v1/images/i/{image_name}/full": {
/**
- * Get Image Full
+ * Get Image Full
* @description Gets a full-resolution image file
*/
get: operations["get_image_full"];
/**
- * Get Image Full
+ * Get Image Full
* @description Gets a full-resolution image file
*/
head: operations["get_image_full"];
};
"/api/v1/images/i/{image_name}/thumbnail": {
/**
- * Get Image Thumbnail
+ * Get Image Thumbnail
* @description Gets a thumbnail image file
*/
get: operations["get_image_thumbnail"];
};
"/api/v1/images/i/{image_name}/urls": {
/**
- * Get Image Urls
+ * Get Image Urls
* @description Gets an image and thumbnail URL
*/
get: operations["get_image_urls"];
};
"/api/v1/images/": {
/**
- * List Image Dtos
+ * List Image Dtos
* @description Gets a list of image DTOs
*/
get: operations["list_image_dtos"];
@@ -220,62 +220,62 @@ export type paths = {
};
"/api/v1/boards/": {
/**
- * List Boards
+ * List Boards
* @description Gets a list of boards
*/
get: operations["list_boards"];
/**
- * Create Board
+ * Create Board
* @description Creates a board
*/
post: operations["create_board"];
};
"/api/v1/boards/{board_id}": {
/**
- * Get Board
+ * Get Board
* @description Gets a board
*/
get: operations["get_board"];
/**
- * Delete Board
+ * Delete Board
* @description Deletes a board
*/
delete: operations["delete_board"];
/**
- * Update Board
+ * Update Board
* @description Updates a board
*/
patch: operations["update_board"];
};
"/api/v1/boards/{board_id}/image_names": {
/**
- * List All Board Image Names
+ * List All Board Image Names
* @description Gets a list of images for a board
*/
get: operations["list_all_board_image_names"];
};
"/api/v1/board_images/": {
/**
- * Add Image To Board
+ * Add Image To Board
* @description Creates a board_image
*/
post: operations["add_image_to_board"];
/**
- * Remove Image From Board
+ * Remove Image From Board
* @description Removes an image from its board, if it had one
*/
delete: operations["remove_image_from_board"];
};
"/api/v1/board_images/batch": {
/**
- * Add Images To Board
+ * Add Images To Board
* @description Adds a list of images to a board
*/
post: operations["add_images_to_board"];
};
"/api/v1/board_images/batch/delete": {
/**
- * Remove Images From Board
+ * Remove Images From Board
* @description Removes a list of images from their board, if they had one
*/
post: operations["remove_images_from_board"];
@@ -290,12 +290,12 @@ export type paths = {
};
"/api/v1/app/logging": {
/**
- * Get Log Level
+ * Get Log Level
* @description Returns the log level
*/
get: operations["get_log_level"];
/**
- * Set Log Level
+ * Set Log Level
* @description Sets the log verbosity level
*/
post: operations["set_log_level"];
@@ -309,638 +309,138 @@ export type components = {
/** AddImagesToBoardResult */
AddImagesToBoardResult: {
/**
- * Board Id
+ * Board Id
* @description The id of the board the images were added to
*/
board_id: string;
/**
- * Added Image Names
+ * Added Image Names
* @description The image names that were added to the board
*/
- added_image_names: (string)[];
+ added_image_names: string[];
};
/**
- * Add Integers
+ * Add Integers
* @description Adds two numbers
*/
AddInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default add
+ * Type
+ * @default add
* @enum {string}
*/
type: "add";
/**
- * A
- * @description The first number
+ * A
+ * @description The first number
* @default 0
*/
a?: number;
/**
- * B
- * @description The second number
+ * B
+ * @description The second number
* @default 0
*/
b?: number;
};
/**
- * AppConfig
+ * AppConfig
* @description App Config Response
*/
AppConfig: {
/**
- * Infill Methods
+ * Infill Methods
* @description List of available infill methods
*/
- infill_methods: (string)[];
+ infill_methods: string[];
/**
- * Upscaling Methods
+ * Upscaling Methods
* @description List of upscaling methods
*/
- upscaling_methods: (components["schemas"]["Upscaler"])[];
+ upscaling_methods: components["schemas"]["Upscaler"][];
/**
- * Nsfw Methods
+ * Nsfw Methods
* @description List of NSFW checking methods
*/
- nsfw_methods: (string)[];
+ nsfw_methods: string[];
/**
- * Watermarking Methods
+ * Watermarking Methods
* @description List of invisible watermark methods
*/
- watermarking_methods: (string)[];
+ watermarking_methods: string[];
};
/**
- * AppVersion
+ * AppVersion
* @description App Version Response
*/
AppVersion: {
/**
- * Version
+ * Version
* @description App version
*/
version: string;
};
/**
- * BaseModelType
- * @description An enumeration.
+ * BaseModelType
+ * @description An enumeration.
* @enum {string}
*/
BaseModelType: "sd-1" | "sd-2" | "sdxl" | "sdxl-refiner";
- /** BoardChanges */
- BoardChanges: {
- /**
- * Board Name
- * @description The board's new name.
- */
- board_name?: string;
- /**
- * Cover Image Name
- * @description The name of the board's new cover image.
- */
- cover_image_name?: string;
- };
/**
- * BoardDTO
- * @description Deserialized board record with cover image URL and image count.
+ * Blank Image
+ * @description Creates a blank image and forwards it to the pipeline
*/
- BoardDTO: {
+ BlankImageInvocation: {
/**
- * Board Id
- * @description The unique ID of the board.
- */
- board_id: string;
- /**
- * Board Name
- * @description The name of the board.
- */
- board_name: string;
- /**
- * Created At
- * @description The created timestamp of the board.
- */
- created_at: string;
- /**
- * Updated At
- * @description The updated timestamp of the board.
- */
- updated_at: string;
- /**
- * Deleted At
- * @description The deleted timestamp of the board.
- */
- deleted_at?: string;
- /**
- * Cover Image Name
- * @description The name of the board's cover image.
- */
- cover_image_name?: string;
- /**
- * Image Count
- * @description The number of images in the board.
- */
- image_count: number;
- };
- /** Body_add_image_to_board */
- Body_add_image_to_board: {
- /**
- * Board Id
- * @description The id of the board to add to
- */
- board_id: string;
- /**
- * Image Name
- * @description The name of the image to add
- */
- image_name: string;
- };
- /** Body_add_images_to_board */
- Body_add_images_to_board: {
- /**
- * Board Id
- * @description The id of the board to add to
- */
- board_id: string;
- /**
- * Image Names
- * @description The names of the images to add
- */
- image_names: (string)[];
- };
- /** Body_delete_images_from_list */
- Body_delete_images_from_list: {
- /**
- * Image Names
- * @description The list of names of images to delete
- */
- image_names: (string)[];
- };
- /** Body_import_model */
- Body_import_model: {
- /**
- * Location
- * @description A model path, repo_id or URL to import
- */
- location: string;
- /**
- * Prediction Type
- * @description Prediction type for SDv2 checkpoint files
- * @default v_prediction
- * @enum {string}
- */
- prediction_type?: "v_prediction" | "epsilon" | "sample";
- };
- /** Body_merge_models */
- Body_merge_models: {
- /**
- * Model Names
- * @description model name
- */
- model_names: (string)[];
- /**
- * Merged Model Name
- * @description Name of destination model
- */
- merged_model_name: string;
- /**
- * Alpha
- * @description Alpha weighting strength to apply to 2d and 3d models
- * @default 0.5
- */
- alpha?: number;
- /** @description Interpolation method */
- interp: components["schemas"]["MergeInterpolationMethod"];
- /**
- * Force
- * @description Force merging of models created with different versions of diffusers
- * @default false
- */
- force?: boolean;
- /**
- * Merge Dest Directory
- * @description Save the merged model to the designated directory (with 'merged_model_name' appended)
- */
- merge_dest_directory?: string;
- };
- /** Body_remove_image_from_board */
- Body_remove_image_from_board: {
- /**
- * Image Name
- * @description The name of the image to remove
- */
- image_name: string;
- };
- /** Body_remove_images_from_board */
- Body_remove_images_from_board: {
- /**
- * Image Names
- * @description The names of the images to remove
- */
- image_names: (string)[];
- };
- /** Body_star_images_in_list */
- Body_star_images_in_list: {
- /**
- * Image Names
- * @description The list of names of images to star
- */
- image_names: (string)[];
- };
- /** Body_unstar_images_in_list */
- Body_unstar_images_in_list: {
- /**
- * Image Names
- * @description The list of names of images to unstar
- */
- image_names: (string)[];
- };
- /** Body_upload_image */
- Body_upload_image: {
- /**
- * File
- * Format: binary
- */
- file: Blob;
- };
- /**
- * Boolean Primitive Collection
- * @description A collection of boolean primitive values
- */
- BooleanCollectionInvocation: {
- /**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default boolean_collection
+ * Type
+ * @default blank_image
* @enum {string}
*/
- type: "boolean_collection";
+ type: "blank_image";
/**
- * Collection
- * @description The collection of boolean values
- * @default false
+ * Width
+ * @description The width of the image
+ * @default 512
*/
- collection?: (boolean)[];
- };
- /**
- * BooleanCollectionOutput
- * @description Base class for nodes that output a collection of booleans
- */
- BooleanCollectionOutput: {
+ width?: number;
/**
- * Type
- * @default boolean_collection_output
+ * Height
+ * @description The height of the image
+ * @default 512
+ */
+ height?: number;
+ /**
+ * Mode
+ * @description The mode of the image
+ * @default RGB
* @enum {string}
*/
- type?: "boolean_collection_output";
+ mode?: "RGB" | "RGBA";
/**
- * Collection
- * @description The output boolean collection
- */
- collection?: (boolean)[];
- };
- /**
- * Boolean Primitive
- * @description A boolean primitive value
- */
- BooleanInvocation: {
- /**
- * Id
- * @description The id of this node. Must be unique among all nodes.
- */
- id: string;
- /**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
- * @default false
- */
- is_intermediate?: boolean;
- /**
- * Type
- * @default boolean
- * @enum {string}
- */
- type: "boolean";
- /**
- * A
- * @description The boolean value
- * @default false
- */
- a?: boolean;
- };
- /**
- * BooleanOutput
- * @description Base class for nodes that output a single boolean
- */
- BooleanOutput: {
- /**
- * Type
- * @default boolean_output
- * @enum {string}
- */
- type?: "boolean_output";
- /**
- * A
- * @description The output boolean
- */
- a: boolean;
- };
- /**
- * Canny Processor
- * @description Canny edge detection for ControlNet
- */
- CannyImageProcessorInvocation: {
- /**
- * Id
- * @description The id of this node. Must be unique among all nodes.
- */
- id: string;
- /**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
- * @default false
- */
- is_intermediate?: boolean;
- /**
- * Type
- * @default canny_image_processor
- * @enum {string}
- */
- type: "canny_image_processor";
- /**
- * Image
- * @description The image to process
- */
- image?: components["schemas"]["ImageField"];
- /**
- * Low Threshold
- * @description The low threshold of the Canny pixel gradient (0-255)
- * @default 100
- */
- low_threshold?: number;
- /**
- * High Threshold
- * @description The high threshold of the Canny pixel gradient (0-255)
- * @default 200
- */
- high_threshold?: number;
- };
- /** ClipField */
- ClipField: {
- /**
- * Tokenizer
- * @description Info to load tokenizer submodel
- */
- tokenizer: components["schemas"]["ModelInfo"];
- /**
- * Text Encoder
- * @description Info to load text_encoder submodel
- */
- text_encoder: components["schemas"]["ModelInfo"];
- /**
- * Skipped Layers
- * @description Number of skipped layers in text_encoder
- */
- skipped_layers: number;
- /**
- * Loras
- * @description Loras to apply on model loading
- */
- loras: (components["schemas"]["LoraInfo"])[];
- };
- /**
- * CLIP Skip
- * @description Skip layers in clip text_encoder model.
- */
- ClipSkipInvocation: {
- /**
- * Id
- * @description The id of this node. Must be unique among all nodes.
- */
- id: string;
- /**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
- * @default false
- */
- is_intermediate?: boolean;
- /**
- * Type
- * @default clip_skip
- * @enum {string}
- */
- type: "clip_skip";
- /**
- * CLIP
- * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
- */
- clip?: components["schemas"]["ClipField"];
- /**
- * Skipped Layers
- * @description Number of layers to skip in text encoder
- * @default 0
- */
- skipped_layers?: number;
- };
- /**
- * ClipSkipInvocationOutput
- * @description Clip skip node output
- */
- ClipSkipInvocationOutput: {
- /**
- * Type
- * @default clip_skip_output
- * @enum {string}
- */
- type?: "clip_skip_output";
- /**
- * CLIP
- * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
- */
- clip?: components["schemas"]["ClipField"];
- };
- /**
- * CollectInvocation
- * @description Collects values into a collection
- */
- CollectInvocation: {
- /**
- * Id
- * @description The id of this node. Must be unique among all nodes.
- */
- id: string;
- /**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
- * @default false
- */
- is_intermediate?: boolean;
- /**
- * Type
- * @default collect
- * @enum {string}
- */
- type: "collect";
- /**
- * Collection Item
- * @description The item to collect (all inputs must be of the same type)
- */
- item?: unknown;
- /**
- * Collection
- * @description The collection, will be provided on execution
- */
- collection?: (unknown)[];
- };
- /**
- * CollectInvocationOutput
- * @description Base class for all invocation outputs
- */
- CollectInvocationOutput: {
- /**
- * Type
- * @default collect_output
- * @enum {string}
- */
- type?: "collect_output";
- /**
- * Collection
- * @description The collection of input items
- */
- collection: (unknown)[];
- };
- /**
- * ColorCollectionOutput
- * @description Base class for nodes that output a collection of colors
- */
- ColorCollectionOutput: {
- /**
- * Type
- * @default color_collection_output
- * @enum {string}
- */
- type?: "color_collection_output";
- /**
- * Collection
- * @description The output colors
- */
- collection?: (components["schemas"]["ColorField"])[];
- };
- /**
- * Color Correct
- * @description Shifts the colors of a target image to match the reference image, optionally
- * using a mask to only color-correct certain regions of the target image.
- */
- ColorCorrectInvocation: {
- /**
- * Id
- * @description The id of this node. Must be unique among all nodes.
- */
- id: string;
- /**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
- * @default false
- */
- is_intermediate?: boolean;
- /**
- * Type
- * @default color_correct
- * @enum {string}
- */
- type: "color_correct";
- /**
- * Image
- * @description The image to color-correct
- */
- image?: components["schemas"]["ImageField"];
- /**
- * Reference
- * @description Reference image for color-correction
- */
- reference?: components["schemas"]["ImageField"];
- /**
- * Mask
- * @description Mask to use when applying color-correction
- */
- mask?: components["schemas"]["ImageField"];
- /**
- * Mask Blur Radius
- * @description Mask blur radius
- * @default 8
- */
- mask_blur_radius?: number;
- };
- /**
- * ColorField
- * @description A color primitive field
- */
- ColorField: {
- /**
- * R
- * @description The red component
- */
- r: number;
- /**
- * G
- * @description The green component
- */
- g: number;
- /**
- * B
- * @description The blue component
- */
- b: number;
- /**
- * A
- * @description The alpha component
- */
- a: number;
- };
- /**
- * Color Primitive
- * @description A color primitive value
- */
- ColorInvocation: {
- /**
- * Id
- * @description The id of this node. Must be unique among all nodes.
- */
- id: string;
- /**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
- * @default false
- */
- is_intermediate?: boolean;
- /**
- * Type
- * @default color
- * @enum {string}
- */
- type: "color";
- /**
- * Color
- * @description The color value
+ * Color
+ * @description The color of the image
* @default {
* "r": 0,
* "g": 0,
@@ -951,212 +451,803 @@ export type components = {
color?: components["schemas"]["ColorField"];
};
/**
- * ColorOutput
- * @description Base class for nodes that output a single color
+ * Blend Latents
+ * @description Blend two latents using a given alpha. Latents must have same size.
*/
- ColorOutput: {
+ BlendLatentsInvocation: {
/**
- * Type
- * @default color_output
- * @enum {string}
- */
- type?: "color_output";
- /**
- * Color
- * @description The output color
- */
- color: components["schemas"]["ColorField"];
- };
- /**
- * Compel Prompt
- * @description Parse prompt using compel package to conditioning.
- */
- CompelInvocation: {
- /**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default compel
+ * Type
+ * @default lblend
* @enum {string}
*/
- type: "compel";
+ type: "lblend";
/**
- * Prompt
- * @description Prompt to be parsed by Compel to create a conditioning tensor
- * @default
+ * Latents A
+ * @description Latents tensor
*/
- prompt?: string;
+ latents_a?: components["schemas"]["LatentsField"];
/**
- * CLIP
+ * Latents B
+ * @description Latents tensor
+ */
+ latents_b?: components["schemas"]["LatentsField"];
+ /**
+ * Alpha
+ * @description Blending factor. 0.0 = use input A only, 1.0 = use input B only, 0.5 = 50% mix of input A and input B.
+ * @default 0.5
+ */
+ alpha?: number;
+ };
+ /** BoardChanges */
+ BoardChanges: {
+ /**
+ * Board Name
+ * @description The board's new name.
+ */
+ board_name?: string;
+ /**
+ * Cover Image Name
+ * @description The name of the board's new cover image.
+ */
+ cover_image_name?: string;
+ };
+ /**
+ * BoardDTO
+ * @description Deserialized board record with cover image URL and image count.
+ */
+ BoardDTO: {
+ /**
+ * Board Id
+ * @description The unique ID of the board.
+ */
+ board_id: string;
+ /**
+ * Board Name
+ * @description The name of the board.
+ */
+ board_name: string;
+ /**
+ * Created At
+ * @description The created timestamp of the board.
+ */
+ created_at: string;
+ /**
+ * Updated At
+ * @description The updated timestamp of the board.
+ */
+ updated_at: string;
+ /**
+ * Deleted At
+ * @description The deleted timestamp of the board.
+ */
+ deleted_at?: string;
+ /**
+ * Cover Image Name
+ * @description The name of the board's cover image.
+ */
+ cover_image_name?: string;
+ /**
+ * Image Count
+ * @description The number of images in the board.
+ */
+ image_count: number;
+ };
+ /** Body_add_image_to_board */
+ Body_add_image_to_board: {
+ /**
+ * Board Id
+ * @description The id of the board to add to
+ */
+ board_id: string;
+ /**
+ * Image Name
+ * @description The name of the image to add
+ */
+ image_name: string;
+ };
+ /** Body_add_images_to_board */
+ Body_add_images_to_board: {
+ /**
+ * Board Id
+ * @description The id of the board to add to
+ */
+ board_id: string;
+ /**
+ * Image Names
+ * @description The names of the images to add
+ */
+ image_names: string[];
+ };
+ /** Body_delete_images_from_list */
+ Body_delete_images_from_list: {
+ /**
+ * Image Names
+ * @description The list of names of images to delete
+ */
+ image_names: string[];
+ };
+ /** Body_import_model */
+ Body_import_model: {
+ /**
+ * Location
+ * @description A model path, repo_id or URL to import
+ */
+ location: string;
+ /**
+ * Prediction Type
+ * @description Prediction type for SDv2 checkpoint files
+ * @default v_prediction
+ * @enum {string}
+ */
+ prediction_type?: "v_prediction" | "epsilon" | "sample";
+ };
+ /** Body_merge_models */
+ Body_merge_models: {
+ /**
+ * Model Names
+ * @description model name
+ */
+ model_names: string[];
+ /**
+ * Merged Model Name
+ * @description Name of destination model
+ */
+ merged_model_name: string;
+ /**
+ * Alpha
+ * @description Alpha weighting strength to apply to 2d and 3d models
+ * @default 0.5
+ */
+ alpha?: number;
+ /** @description Interpolation method */
+ interp: components["schemas"]["MergeInterpolationMethod"];
+ /**
+ * Force
+ * @description Force merging of models created with different versions of diffusers
+ * @default false
+ */
+ force?: boolean;
+ /**
+ * Merge Dest Directory
+ * @description Save the merged model to the designated directory (with 'merged_model_name' appended)
+ */
+ merge_dest_directory?: string;
+ };
+ /** Body_remove_image_from_board */
+ Body_remove_image_from_board: {
+ /**
+ * Image Name
+ * @description The name of the image to remove
+ */
+ image_name: string;
+ };
+ /** Body_remove_images_from_board */
+ Body_remove_images_from_board: {
+ /**
+ * Image Names
+ * @description The names of the images to remove
+ */
+ image_names: string[];
+ };
+ /** Body_star_images_in_list */
+ Body_star_images_in_list: {
+ /**
+ * Image Names
+ * @description The list of names of images to star
+ */
+ image_names: string[];
+ };
+ /** Body_unstar_images_in_list */
+ Body_unstar_images_in_list: {
+ /**
+ * Image Names
+ * @description The list of names of images to unstar
+ */
+ image_names: string[];
+ };
+ /** Body_upload_image */
+ Body_upload_image: {
+ /**
+ * File
+ * Format: binary
+ */
+ file: Blob;
+ };
+ /**
+ * Boolean Primitive Collection
+ * @description A collection of boolean primitive values
+ */
+ BooleanCollectionInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default boolean_collection
+ * @enum {string}
+ */
+ type: "boolean_collection";
+ /**
+ * Collection
+ * @description The collection of boolean values
+ */
+ collection?: boolean[];
+ };
+ /**
+ * BooleanCollectionOutput
+ * @description Base class for nodes that output a collection of booleans
+ */
+ BooleanCollectionOutput: {
+ /**
+ * Type
+ * @default boolean_collection_output
+ * @enum {string}
+ */
+ type: "boolean_collection_output";
+ /**
+ * Collection
+ * @description The output boolean collection
+ */
+ collection: boolean[];
+ };
+ /**
+ * Boolean Primitive
+ * @description A boolean primitive value
+ */
+ BooleanInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default boolean
+ * @enum {string}
+ */
+ type: "boolean";
+ /**
+ * Value
+ * @description The boolean value
+ * @default false
+ */
+ value?: boolean;
+ };
+ /**
+ * BooleanOutput
+ * @description Base class for nodes that output a single boolean
+ */
+ BooleanOutput: {
+ /**
+ * Type
+ * @default boolean_output
+ * @enum {string}
+ */
+ type: "boolean_output";
+ /**
+ * Value
+ * @description The output boolean
+ */
+ value: boolean;
+ };
+ /**
+ * Canny Processor
+ * @description Canny edge detection for ControlNet
+ */
+ CannyImageProcessorInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default canny_image_processor
+ * @enum {string}
+ */
+ type: "canny_image_processor";
+ /**
+ * Image
+ * @description The image to process
+ */
+ image?: components["schemas"]["ImageField"];
+ /**
+ * Low Threshold
+ * @description The low threshold of the Canny pixel gradient (0-255)
+ * @default 100
+ */
+ low_threshold?: number;
+ /**
+ * High Threshold
+ * @description The high threshold of the Canny pixel gradient (0-255)
+ * @default 200
+ */
+ high_threshold?: number;
+ };
+ /** ClipField */
+ ClipField: {
+ /**
+ * Tokenizer
+ * @description Info to load tokenizer submodel
+ */
+ tokenizer: components["schemas"]["ModelInfo"];
+ /**
+ * Text Encoder
+ * @description Info to load text_encoder submodel
+ */
+ text_encoder: components["schemas"]["ModelInfo"];
+ /**
+ * Skipped Layers
+ * @description Number of skipped layers in text_encoder
+ */
+ skipped_layers: number;
+ /**
+ * Loras
+ * @description Loras to apply on model loading
+ */
+ loras: components["schemas"]["LoraInfo"][];
+ };
+ /**
+ * CLIP Skip
+ * @description Skip layers in clip text_encoder model.
+ */
+ ClipSkipInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default clip_skip
+ * @enum {string}
+ */
+ type: "clip_skip";
+ /**
+ * CLIP
+ * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
+ */
+ clip?: components["schemas"]["ClipField"];
+ /**
+ * Skipped Layers
+ * @description Number of layers to skip in text encoder
+ * @default 0
+ */
+ skipped_layers?: number;
+ };
+ /**
+ * ClipSkipInvocationOutput
+ * @description Clip skip node output
+ */
+ ClipSkipInvocationOutput: {
+ /**
+ * Type
+ * @default clip_skip_output
+ * @enum {string}
+ */
+ type: "clip_skip_output";
+ /**
+ * CLIP
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
};
/**
- * Conditioning Primitive Collection
- * @description A collection of conditioning tensor primitive values
+ * CollectInvocation
+ * @description Collects values into a collection
*/
- ConditioningCollectionInvocation: {
+ CollectInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default conditioning_collection
+ * Type
+ * @default collect
+ * @enum {string}
+ */
+ type: "collect";
+ /**
+ * Collection Item
+ * @description The item to collect (all inputs must be of the same type)
+ */
+ item?: unknown;
+ /**
+ * Collection
+ * @description The collection, will be provided on execution
+ */
+ collection?: unknown[];
+ };
+ /**
+ * CollectInvocationOutput
+ * @description Base class for all invocation outputs
+ */
+ CollectInvocationOutput: {
+ /**
+ * Type
+ * @default collect_output
+ * @enum {string}
+ */
+ type: "collect_output";
+ /**
+ * Collection
+ * @description The collection of input items
+ */
+ collection: unknown[];
+ };
+ /**
+ * ColorCollectionOutput
+ * @description Base class for nodes that output a collection of colors
+ */
+ ColorCollectionOutput: {
+ /**
+ * Type
+ * @default color_collection_output
+ * @enum {string}
+ */
+ type: "color_collection_output";
+ /**
+ * Collection
+ * @description The output colors
+ */
+ collection: components["schemas"]["ColorField"][];
+ };
+ /**
+ * Color Correct
+ * @description Shifts the colors of a target image to match the reference image, optionally
+ * using a mask to only color-correct certain regions of the target image.
+ */
+ ColorCorrectInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default color_correct
+ * @enum {string}
+ */
+ type: "color_correct";
+ /**
+ * Image
+ * @description The image to color-correct
+ */
+ image?: components["schemas"]["ImageField"];
+ /**
+ * Reference
+ * @description Reference image for color-correction
+ */
+ reference?: components["schemas"]["ImageField"];
+ /**
+ * Mask
+ * @description Mask to use when applying color-correction
+ */
+ mask?: components["schemas"]["ImageField"];
+ /**
+ * Mask Blur Radius
+ * @description Mask blur radius
+ * @default 8
+ */
+ mask_blur_radius?: number;
+ };
+ /**
+ * ColorField
+ * @description A color primitive field
+ */
+ ColorField: {
+ /**
+ * R
+ * @description The red component
+ */
+ r: number;
+ /**
+ * G
+ * @description The green component
+ */
+ g: number;
+ /**
+ * B
+ * @description The blue component
+ */
+ b: number;
+ /**
+ * A
+ * @description The alpha component
+ */
+ a: number;
+ };
+ /**
+ * Color Primitive
+ * @description A color primitive value
+ */
+ ColorInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default color
+ * @enum {string}
+ */
+ type: "color";
+ /**
+ * Color
+ * @description The color value
+ * @default {
+ * "r": 0,
+ * "g": 0,
+ * "b": 0,
+ * "a": 255
+ * }
+ */
+ color?: components["schemas"]["ColorField"];
+ };
+ /**
+ * ColorOutput
+ * @description Base class for nodes that output a single color
+ */
+ ColorOutput: {
+ /**
+ * Type
+ * @default color_output
+ * @enum {string}
+ */
+ type: "color_output";
+ /**
+ * Color
+ * @description The output color
+ */
+ color: components["schemas"]["ColorField"];
+ };
+ /**
+ * Compel Prompt
+ * @description Parse prompt using compel package to conditioning.
+ */
+ CompelInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default compel
+ * @enum {string}
+ */
+ type: "compel";
+ /**
+ * Prompt
+ * @description Prompt to be parsed by Compel to create a conditioning tensor
+ * @default
+ */
+ prompt?: string;
+ /**
+ * CLIP
+ * @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
+ */
+ clip?: components["schemas"]["ClipField"];
+ };
+ /**
+ * Conditioning Primitive Collection
+ * @description A collection of conditioning tensor primitive values
+ */
+ ConditioningCollectionInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default conditioning_collection
* @enum {string}
*/
type: "conditioning_collection";
/**
- * Collection
- * @description The collection of conditioning tensors
+ * Collection
+ * @description The collection of conditioning tensors
* @default 0
*/
- collection?: (components["schemas"]["ConditioningField"])[];
+ collection?: components["schemas"]["ConditioningField"][];
};
/**
- * ConditioningCollectionOutput
+ * ConditioningCollectionOutput
* @description Base class for nodes that output a collection of conditioning tensors
*/
ConditioningCollectionOutput: {
/**
- * Type
- * @default conditioning_collection_output
+ * Type
+ * @default conditioning_collection_output
* @enum {string}
*/
- type?: "conditioning_collection_output";
+ type: "conditioning_collection_output";
/**
- * Collection
+ * Collection
* @description The output conditioning tensors
*/
- collection?: (components["schemas"]["ConditioningField"])[];
+ collection: components["schemas"]["ConditioningField"][];
};
/**
- * ConditioningField
+ * ConditioningField
* @description A conditioning tensor primitive value
*/
ConditioningField: {
/**
- * Conditioning Name
+ * Conditioning Name
* @description The name of conditioning tensor
*/
conditioning_name: string;
};
/**
- * Conditioning Primitive
+ * Conditioning Primitive
* @description A conditioning tensor primitive value
*/
ConditioningInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default conditioning
+ * Type
+ * @default conditioning
* @enum {string}
*/
type: "conditioning";
/**
- * Conditioning
+ * Conditioning
* @description Conditioning tensor
*/
conditioning?: components["schemas"]["ConditioningField"];
};
/**
- * ConditioningOutput
+ * ConditioningOutput
* @description Base class for nodes that output a single conditioning tensor
*/
ConditioningOutput: {
/**
- * Type
- * @default conditioning_output
+ * Type
+ * @default conditioning_output
* @enum {string}
*/
- type?: "conditioning_output";
+ type: "conditioning_output";
/**
- * Conditioning
+ * Conditioning
* @description Conditioning tensor
*/
conditioning: components["schemas"]["ConditioningField"];
};
/**
- * Content Shuffle Processor
+ * Content Shuffle Processor
* @description Applies content shuffle processing to image
*/
ContentShuffleImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default content_shuffle_image_processor
+ * Type
+ * @default content_shuffle_image_processor
* @enum {string}
*/
type: "content_shuffle_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
/**
- * H
- * @description Content shuffle `h` parameter
+ * H
+ * @description Content shuffle `h` parameter
* @default 512
*/
h?: number;
/**
- * W
- * @description Content shuffle `w` parameter
+ * W
+ * @description Content shuffle `w` parameter
* @default 512
*/
w?: number;
/**
- * F
- * @description Content shuffle `f` parameter
+ * F
+ * @description Content shuffle `f` parameter
* @default 256
*/
f?: number;
@@ -1164,110 +1255,110 @@ export type components = {
/** ControlField */
ControlField: {
/**
- * Image
+ * Image
* @description The control image
*/
image: components["schemas"]["ImageField"];
/**
- * Control Model
+ * Control Model
* @description The ControlNet model to use
*/
control_model: components["schemas"]["ControlNetModelField"];
/**
- * Control Weight
- * @description The weight given to the ControlNet
+ * Control Weight
+ * @description The weight given to the ControlNet
* @default 1
*/
- control_weight?: number | (number)[];
+ control_weight?: number | number[];
/**
- * Begin Step Percent
- * @description When the ControlNet is first applied (% of total steps)
+ * Begin Step Percent
+ * @description When the ControlNet is first applied (% of total steps)
* @default 0
*/
begin_step_percent?: number;
/**
- * End Step Percent
- * @description When the ControlNet is last applied (% of total steps)
+ * End Step Percent
+ * @description When the ControlNet is last applied (% of total steps)
* @default 1
*/
end_step_percent?: number;
/**
- * Control Mode
- * @description The control mode to use
- * @default balanced
+ * Control Mode
+ * @description The control mode to use
+ * @default balanced
* @enum {string}
*/
control_mode?: "balanced" | "more_prompt" | "more_control" | "unbalanced";
/**
- * Resize Mode
- * @description The resize mode to use
- * @default just_resize
+ * Resize Mode
+ * @description The resize mode to use
+ * @default just_resize
* @enum {string}
*/
resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple";
};
/**
- * ControlNet
+ * ControlNet
* @description Collects ControlNet info to pass to other nodes
*/
ControlNetInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default controlnet
+ * Type
+ * @default controlnet
* @enum {string}
*/
type: "controlnet";
/**
- * Image
+ * Image
* @description The control image
*/
image?: components["schemas"]["ImageField"];
/**
- * Control Model
- * @description ControlNet model to load
+ * Control Model
+ * @description ControlNet model to load
* @default lllyasviel/sd-controlnet-canny
*/
control_model?: components["schemas"]["ControlNetModelField"];
/**
- * Control Weight
- * @description The weight given to the ControlNet
+ * Control Weight
+ * @description The weight given to the ControlNet
* @default 1
*/
- control_weight?: number | (number)[];
+ control_weight?: number | number[];
/**
- * Begin Step Percent
- * @description When the ControlNet is first applied (% of total steps)
+ * Begin Step Percent
+ * @description When the ControlNet is first applied (% of total steps)
* @default 0
*/
begin_step_percent?: number;
/**
- * End Step Percent
- * @description When the ControlNet is last applied (% of total steps)
+ * End Step Percent
+ * @description When the ControlNet is last applied (% of total steps)
* @default 1
*/
end_step_percent?: number;
/**
- * Control Mode
- * @description The control mode used
- * @default balanced
+ * Control Mode
+ * @description The control mode used
+ * @default balanced
* @enum {string}
*/
control_mode?: "balanced" | "more_prompt" | "more_control" | "unbalanced";
/**
- * Resize Mode
- * @description The resize mode used
- * @default just_resize
+ * Resize Mode
+ * @description The resize mode used
+ * @default just_resize
* @enum {string}
*/
resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple";
@@ -1278,7 +1369,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "controlnet";
@@ -1287,7 +1378,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "checkpoint";
@@ -1301,7 +1392,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "controlnet";
@@ -1310,19 +1401,19 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "diffusers";
error?: components["schemas"]["ModelError"];
};
/**
- * ControlNetModelField
+ * ControlNetModelField
* @description ControlNet model field
*/
ControlNetModelField: {
/**
- * Model Name
+ * Model Name
* @description Name of the ControlNet model
*/
model_name: string;
@@ -1330,193 +1421,198 @@ export type components = {
base_model: components["schemas"]["BaseModelType"];
};
/**
- * ControlOutput
+ * ControlOutput
* @description node output for ControlNet info
*/
ControlOutput: {
/**
- * Type
- * @default control_output
+ * Type
+ * @default control_output
* @enum {string}
*/
- type?: "control_output";
+ type: "control_output";
/**
- * Control
+ * Control
* @description ControlNet(s) to apply
*/
control: components["schemas"]["ControlField"];
};
/**
- * CoreMetadata
+ * CoreMetadata
* @description Core generation metadata for an image generated in InvokeAI.
*/
CoreMetadata: {
/**
- * App Version
- * @description The version of InvokeAI used to generate this image
+ * App Version
+ * @description The version of InvokeAI used to generate this image
* @default 3.0.2post1
*/
app_version?: string;
/**
- * Generation Mode
+ * Generation Mode
* @description The generation mode that output this image
*/
generation_mode: string;
/**
- * Positive Prompt
+ * Created By
+ * @description The name of the creator of the image
+ */
+ created_by?: string;
+ /**
+ * Positive Prompt
* @description The positive prompt parameter
*/
positive_prompt: string;
/**
- * Negative Prompt
+ * Negative Prompt
* @description The negative prompt parameter
*/
negative_prompt: string;
/**
- * Width
+ * Width
* @description The width parameter
*/
width: number;
/**
- * Height
+ * Height
* @description The height parameter
*/
height: number;
/**
- * Seed
+ * Seed
* @description The seed used for noise generation
*/
seed: number;
/**
- * Rand Device
+ * Rand Device
* @description The device used for random number generation
*/
rand_device: string;
/**
- * Cfg Scale
+ * Cfg Scale
* @description The classifier-free guidance scale parameter
*/
cfg_scale: number;
/**
- * Steps
+ * Steps
* @description The number of steps used for inference
*/
steps: number;
/**
- * Scheduler
+ * Scheduler
* @description The scheduler used for inference
*/
scheduler: string;
/**
- * Clip Skip
+ * Clip Skip
* @description The number of skipped CLIP layers
*/
clip_skip: number;
/**
- * Model
+ * Model
* @description The main model used for inference
*/
model: components["schemas"]["MainModelField"];
/**
- * Controlnets
+ * Controlnets
* @description The ControlNets used for inference
*/
- controlnets: (components["schemas"]["ControlField"])[];
+ controlnets: components["schemas"]["ControlField"][];
/**
- * Loras
+ * Loras
* @description The LoRAs used for inference
*/
- loras: (components["schemas"]["LoRAMetadataField"])[];
+ loras: components["schemas"]["LoRAMetadataField"][];
/**
- * Vae
+ * Vae
* @description The VAE used for decoding, if the main model's default was not used
*/
vae?: components["schemas"]["VAEModelField"];
/**
- * Strength
+ * Strength
* @description The strength used for latents-to-latents
*/
strength?: number;
/**
- * Init Image
+ * Init Image
* @description The name of the initial image
*/
init_image?: string;
/**
- * Positive Style Prompt
+ * Positive Style Prompt
* @description The positive style prompt parameter
*/
positive_style_prompt?: string;
/**
- * Negative Style Prompt
+ * Negative Style Prompt
* @description The negative style prompt parameter
*/
negative_style_prompt?: string;
/**
- * Refiner Model
+ * Refiner Model
* @description The SDXL Refiner model used
*/
refiner_model?: components["schemas"]["MainModelField"];
/**
- * Refiner Cfg Scale
+ * Refiner Cfg Scale
* @description The classifier-free guidance scale parameter used for the refiner
*/
refiner_cfg_scale?: number;
/**
- * Refiner Steps
+ * Refiner Steps
* @description The number of steps used for the refiner
*/
refiner_steps?: number;
/**
- * Refiner Scheduler
+ * Refiner Scheduler
* @description The scheduler used for the refiner
*/
refiner_scheduler?: string;
/**
- * Refiner Positive Aesthetic Store
+ * Refiner Positive Aesthetic Store
* @description The aesthetic score used for the refiner
*/
refiner_positive_aesthetic_store?: number;
/**
- * Refiner Negative Aesthetic Store
+ * Refiner Negative Aesthetic Store
* @description The aesthetic score used for the refiner
*/
refiner_negative_aesthetic_store?: number;
/**
- * Refiner Start
+ * Refiner Start
* @description The start value used for refiner denoising
*/
refiner_start?: number;
};
/**
- * OpenCV Inpaint
+ * OpenCV Inpaint
* @description Simple inpaint using opencv.
*/
CvInpaintInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default cv_inpaint
+ * Type
+ * @default cv_inpaint
* @enum {string}
*/
type: "cv_inpaint";
/**
- * Image
+ * Image
* @description The image to inpaint
*/
image?: components["schemas"]["ImageField"];
/**
- * Mask
+ * Mask
* @description The mask to use when inpainting
*/
mask?: components["schemas"]["ImageField"];
@@ -1524,221 +1620,221 @@ export type components = {
/** DeleteBoardResult */
DeleteBoardResult: {
/**
- * Board Id
+ * Board Id
* @description The id of the board that was deleted.
*/
board_id: string;
/**
- * Deleted Board Images
+ * Deleted Board Images
* @description The image names of the board-images relationships that were deleted.
*/
- deleted_board_images: (string)[];
+ deleted_board_images: string[];
/**
- * Deleted Images
+ * Deleted Images
* @description The names of the images that were deleted.
*/
- deleted_images: (string)[];
+ deleted_images: string[];
};
/** DeleteImagesFromListResult */
DeleteImagesFromListResult: {
/** Deleted Images */
- deleted_images: (string)[];
+ deleted_images: string[];
};
/**
- * Denoise Latents
+ * Denoise Latents
* @description Denoises noisy latents to decodable images
*/
DenoiseLatentsInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default denoise_latents
+ * Type
+ * @default denoise_latents
* @enum {string}
*/
type: "denoise_latents";
/**
- * Noise
+ * Noise
* @description Noise tensor
*/
noise?: components["schemas"]["LatentsField"];
/**
- * Steps
- * @description Number of steps to run
+ * Steps
+ * @description Number of steps to run
* @default 10
*/
steps?: number;
/**
- * Cfg Scale
- * @description Classifier-Free Guidance scale
+ * CFG Scale
+ * @description Classifier-Free Guidance scale
* @default 7.5
*/
- cfg_scale?: number | (number)[];
+ cfg_scale?: number | number[];
/**
- * Denoising Start
- * @description When to start denoising, expressed a percentage of total steps
+ * Denoising Start
+ * @description When to start denoising, expressed a percentage of total steps
* @default 0
*/
denoising_start?: number;
/**
- * Denoising End
- * @description When to stop denoising, expressed a percentage of total steps
+ * Denoising End
+ * @description When to stop denoising, expressed a percentage of total steps
* @default 1
*/
denoising_end?: number;
/**
- * Scheduler
- * @description Scheduler to use during inference
- * @default euler
+ * Scheduler
+ * @description Scheduler to use during inference
+ * @default euler
* @enum {string}
*/
scheduler?: "ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc";
/**
- * Control
+ * Control
* @description ControlNet(s) to apply
*/
- control?: components["schemas"]["ControlField"] | (components["schemas"]["ControlField"])[];
+ control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][];
/**
- * Latents
+ * Latents
* @description Latents tensor
*/
latents?: components["schemas"]["LatentsField"];
/**
- * Mask
+ * Mask
* @description The mask to use for the operation
*/
mask?: components["schemas"]["ImageField"];
/**
- * Positive Conditioning
+ * Positive Conditioning
* @description Positive conditioning tensor
*/
positive_conditioning?: components["schemas"]["ConditioningField"];
/**
- * Negative Conditioning
+ * Negative Conditioning
* @description Negative conditioning tensor
*/
negative_conditioning?: components["schemas"]["ConditioningField"];
/**
- * Unet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
};
/**
- * Divide Integers
+ * Divide Integers
* @description Divides two numbers
*/
DivideInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default div
+ * Type
+ * @default div
* @enum {string}
*/
type: "div";
/**
- * A
- * @description The first number
+ * A
+ * @description The first number
* @default 0
*/
a?: number;
/**
- * B
- * @description The second number
+ * B
+ * @description The second number
* @default 0
*/
b?: number;
};
/**
- * Dynamic Prompt
+ * Dynamic Prompt
* @description Parses a prompt using adieyal/dynamicprompts' random or combinatorial generator
*/
DynamicPromptInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default dynamic_prompt
+ * Type
+ * @default dynamic_prompt
* @enum {string}
*/
type: "dynamic_prompt";
/**
- * Prompt
+ * Prompt
* @description The prompt to parse with dynamicprompts
*/
prompt?: string;
/**
- * Max Prompts
- * @description The number of prompts to generate
+ * Max Prompts
+ * @description The number of prompts to generate
* @default 1
*/
max_prompts?: number;
/**
- * Combinatorial
- * @description Whether to use the combinatorial generator
+ * Combinatorial
+ * @description Whether to use the combinatorial generator
* @default false
*/
combinatorial?: boolean;
};
/**
- * Upscale (RealESRGAN)
+ * Upscale (RealESRGAN)
* @description Upscales an image using RealESRGAN.
*/
ESRGANInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default esrgan
+ * Type
+ * @default esrgan
* @enum {string}
*/
type: "esrgan";
/**
- * Image
+ * Image
* @description The input image
*/
image?: components["schemas"]["ImageField"];
/**
- * Model Name
- * @description The Real-ESRGAN model to use
- * @default RealESRGAN_x4plus.pth
+ * Model Name
+ * @description The Real-ESRGAN model to use
+ * @default RealESRGAN_x4plus.pth
* @enum {string}
*/
model_name?: "RealESRGAN_x4plus.pth" | "RealESRGAN_x4plus_anime_6B.pth" | "ESRGAN_SRx4_DF2KOST_official-ff704c30.pth" | "RealESRGAN_x2plus.pth";
@@ -1746,12 +1842,12 @@ export type components = {
/** Edge */
Edge: {
/**
- * Source
+ * Source
* @description The connection for the edge's from node and field
*/
source: components["schemas"]["EdgeConnection"];
/**
- * Destination
+ * Destination
* @description The connection for the edge's to node and field
*/
destination: components["schemas"]["EdgeConnection"];
@@ -1759,264 +1855,263 @@ export type components = {
/** EdgeConnection */
EdgeConnection: {
/**
- * Node Id
+ * Node Id
* @description The id of the node for this edge connection
*/
node_id: string;
/**
- * Field
+ * Field
* @description The field for this connection
*/
field: string;
};
/**
- * Float Primitive Collection
+ * Float Primitive Collection
* @description A collection of float primitive values
*/
FloatCollectionInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default float_collection
+ * Type
+ * @default float_collection
* @enum {string}
*/
type: "float_collection";
/**
- * Collection
- * @description The collection of float values
- * @default 0
+ * Collection
+ * @description The collection of float values
*/
- collection?: (number)[];
+ collection?: number[];
};
/**
- * FloatCollectionOutput
+ * FloatCollectionOutput
* @description Base class for nodes that output a collection of floats
*/
FloatCollectionOutput: {
/**
- * Type
- * @default float_collection_output
+ * Type
+ * @default float_collection_output
* @enum {string}
*/
- type?: "float_collection_output";
+ type: "float_collection_output";
/**
- * Collection
+ * Collection
* @description The float collection
*/
- collection?: (number)[];
+ collection: number[];
};
/**
- * Float Primitive
+ * Float Primitive
* @description A float primitive value
*/
FloatInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default float
+ * Type
+ * @default float
* @enum {string}
*/
type: "float";
/**
- * Param
- * @description The float value
+ * Value
+ * @description The float value
* @default 0
*/
- param?: number;
+ value?: number;
};
/**
- * Float Range
+ * Float Range
* @description Creates a range
*/
FloatLinearRangeInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default float_range
+ * Type
+ * @default float_range
* @enum {string}
*/
type: "float_range";
/**
- * Start
- * @description The first value of the range
+ * Start
+ * @description The first value of the range
* @default 5
*/
start?: number;
/**
- * Stop
- * @description The last value of the range
+ * Stop
+ * @description The last value of the range
* @default 10
*/
stop?: number;
/**
- * Steps
- * @description number of values to interpolate over (including start and stop)
+ * Steps
+ * @description number of values to interpolate over (including start and stop)
* @default 30
*/
steps?: number;
};
/**
- * FloatOutput
+ * FloatOutput
* @description Base class for nodes that output a single float
*/
FloatOutput: {
/**
- * Type
- * @default float_output
+ * Type
+ * @default float_output
* @enum {string}
*/
- type?: "float_output";
+ type: "float_output";
/**
- * A
+ * Value
* @description The output float
*/
- a: number;
+ value: number;
};
/** Graph */
Graph: {
/**
- * Id
+ * Id
* @description The id of this graph
*/
id?: string;
/**
- * Nodes
+ * Nodes
* @description The nodes in this graph
*/
nodes?: {
- [key: string]: (components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"]) | undefined;
+ [key: string]: components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"];
};
/**
- * Edges
+ * Edges
* @description The connections between nodes and their fields in this graph
*/
- edges?: (components["schemas"]["Edge"])[];
+ edges?: components["schemas"]["Edge"][];
};
/**
- * GraphExecutionState
+ * GraphExecutionState
* @description Tracks the state of a graph execution
*/
GraphExecutionState: {
/**
- * Id
+ * Id
* @description The id of the execution state
*/
id: string;
/**
- * Graph
+ * Graph
* @description The graph being executed
*/
graph: components["schemas"]["Graph"];
/**
- * Execution Graph
+ * Execution Graph
* @description The expanded graph of activated and executed nodes
*/
execution_graph: components["schemas"]["Graph"];
/**
- * Executed
+ * Executed
* @description The set of node ids that have been executed
*/
- executed: (string)[];
+ executed: string[];
/**
- * Executed History
+ * Executed History
* @description The list of node ids that have been executed, in order of execution
*/
- executed_history: (string)[];
+ executed_history: string[];
/**
- * Results
+ * Results
* @description The results of node executions
*/
results: {
- [key: string]: (components["schemas"]["BooleanOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
+ [key: string]: components["schemas"]["BooleanOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"];
};
/**
- * Errors
+ * Errors
* @description Errors raised when executing nodes
*/
errors: {
- [key: string]: string | undefined;
+ [key: string]: string;
};
/**
- * Prepared Source Mapping
+ * Prepared Source Mapping
* @description The map of prepared nodes to original graph nodes
*/
prepared_source_mapping: {
- [key: string]: string | undefined;
+ [key: string]: string;
};
/**
- * Source Prepared Mapping
+ * Source Prepared Mapping
* @description The map of original graph nodes to prepared nodes
*/
source_prepared_mapping: {
- [key: string]: (string)[] | undefined;
+ [key: string]: string[];
};
};
/**
- * GraphInvocation
+ * GraphInvocation
* @description Execute a graph
*/
GraphInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default graph
+ * Type
+ * @default graph
* @enum {string}
*/
type: "graph";
/**
- * Graph
+ * Graph
* @description The graph to run
*/
graph?: components["schemas"]["Graph"];
};
/**
- * GraphInvocationOutput
+ * GraphInvocationOutput
* @description Base class for all invocation outputs
*/
GraphInvocationOutput: {
/**
- * Type
- * @default graph_output
+ * Type
+ * @default graph_output
* @enum {string}
*/
type: "graph_output";
@@ -2024,292 +2119,292 @@ export type components = {
/** HTTPValidationError */
HTTPValidationError: {
/** Detail */
- detail?: (components["schemas"]["ValidationError"])[];
+ detail?: components["schemas"]["ValidationError"][];
};
/**
- * HED (softedge) Processor
+ * HED (softedge) Processor
* @description Applies HED edge detection to image
*/
HedImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default hed_image_processor
+ * Type
+ * @default hed_image_processor
* @enum {string}
*/
type: "hed_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
/**
- * Scribble
- * @description Whether or not to use scribble mode
+ * Scribble
+ * @description Whether or not to use scribble mode
* @default false
*/
scribble?: boolean;
};
/**
- * Blur Image
+ * Blur Image
* @description Blurs an image
*/
ImageBlurInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_blur
+ * Type
+ * @default img_blur
* @enum {string}
*/
type: "img_blur";
/**
- * Image
+ * Image
* @description The image to blur
*/
image?: components["schemas"]["ImageField"];
/**
- * Radius
- * @description The blur radius
+ * Radius
+ * @description The blur radius
* @default 8
*/
radius?: number;
/**
- * Blur Type
- * @description The type of blur
- * @default gaussian
+ * Blur Type
+ * @description The type of blur
+ * @default gaussian
* @enum {string}
*/
blur_type?: "gaussian" | "box";
};
/**
- * ImageCategory
+ * ImageCategory
* @description The category of an image.
- *
+ *
* - GENERAL: The image is an output, init image, or otherwise an image without a specialized purpose.
* - MASK: The image is a mask image.
* - CONTROL: The image is a ControlNet control image.
* - USER: The image is a user-provide image.
- * - OTHER: The image is some other type of image with a specialized purpose. To be used by external nodes.
+ * - OTHER: The image is some other type of image with a specialized purpose. To be used by external nodes.
* @enum {string}
*/
ImageCategory: "general" | "mask" | "control" | "user" | "other";
/**
- * Extract Image Channel
+ * Extract Image Channel
* @description Gets a channel from an image.
*/
ImageChannelInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_chan
+ * Type
+ * @default img_chan
* @enum {string}
*/
type: "img_chan";
/**
- * Image
+ * Image
* @description The image to get the channel from
*/
image?: components["schemas"]["ImageField"];
/**
- * Channel
- * @description The channel to get
- * @default A
+ * Channel
+ * @description The channel to get
+ * @default A
* @enum {string}
*/
channel?: "A" | "R" | "G" | "B";
};
/**
- * Image Primitive Collection
+ * Image Primitive Collection
* @description A collection of image primitive values
*/
ImageCollectionInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default image_collection
+ * Type
+ * @default image_collection
* @enum {string}
*/
type: "image_collection";
/**
- * Collection
- * @description The collection of image values
+ * Collection
+ * @description The collection of image values
* @default 0
*/
- collection?: (components["schemas"]["ImageField"])[];
+ collection?: components["schemas"]["ImageField"][];
};
/**
- * ImageCollectionOutput
+ * ImageCollectionOutput
* @description Base class for nodes that output a collection of images
*/
ImageCollectionOutput: {
/**
- * Type
- * @default image_collection_output
+ * Type
+ * @default image_collection_output
* @enum {string}
*/
- type?: "image_collection_output";
+ type: "image_collection_output";
/**
- * Collection
+ * Collection
* @description The output images
*/
- collection?: (components["schemas"]["ImageField"])[];
+ collection: components["schemas"]["ImageField"][];
};
/**
- * Convert Image Mode
+ * Convert Image Mode
* @description Converts an image to a different mode.
*/
ImageConvertInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_conv
+ * Type
+ * @default img_conv
* @enum {string}
*/
type: "img_conv";
/**
- * Image
+ * Image
* @description The image to convert
*/
image?: components["schemas"]["ImageField"];
/**
- * Mode
- * @description The mode to convert to
- * @default L
+ * Mode
+ * @description The mode to convert to
+ * @default L
* @enum {string}
*/
mode?: "L" | "RGB" | "RGBA" | "CMYK" | "YCbCr" | "LAB" | "HSV" | "I" | "F";
};
/**
- * Crop Image
+ * Crop Image
* @description Crops an image to a specified box. The box can be outside of the image.
*/
ImageCropInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_crop
+ * Type
+ * @default img_crop
* @enum {string}
*/
type: "img_crop";
/**
- * Image
+ * Image
* @description The image to crop
*/
image?: components["schemas"]["ImageField"];
/**
- * X
- * @description The left x coordinate of the crop rectangle
+ * X
+ * @description The left x coordinate of the crop rectangle
* @default 0
*/
x?: number;
/**
- * Y
- * @description The top y coordinate of the crop rectangle
+ * Y
+ * @description The top y coordinate of the crop rectangle
* @default 0
*/
y?: number;
/**
- * Width
- * @description The width of the crop rectangle
+ * Width
+ * @description The width of the crop rectangle
* @default 512
*/
width?: number;
/**
- * Height
- * @description The height of the crop rectangle
+ * Height
+ * @description The height of the crop rectangle
* @default 512
*/
height?: number;
};
/**
- * ImageDTO
+ * ImageDTO
* @description Deserialized image record, enriched for the frontend.
*/
ImageDTO: {
/**
- * Image Name
+ * Image Name
* @description The unique name of the image.
*/
image_name: string;
/**
- * Image Url
+ * Image Url
* @description The URL of the image.
*/
image_url: string;
/**
- * Thumbnail Url
+ * Thumbnail Url
* @description The URL of the image's thumbnail.
*/
thumbnail_url: string;
@@ -2318,434 +2413,434 @@ export type components = {
/** @description The category of the image. */
image_category: components["schemas"]["ImageCategory"];
/**
- * Width
+ * Width
* @description The width of the image in px.
*/
width: number;
/**
- * Height
+ * Height
* @description The height of the image in px.
*/
height: number;
/**
- * Created At
+ * Created At
* @description The created timestamp of the image.
*/
created_at: string;
/**
- * Updated At
+ * Updated At
* @description The updated timestamp of the image.
*/
updated_at: string;
/**
- * Deleted At
+ * Deleted At
* @description The deleted timestamp of the image.
*/
deleted_at?: string;
/**
- * Is Intermediate
+ * Is Intermediate
* @description Whether this is an intermediate image.
*/
is_intermediate: boolean;
/**
- * Session Id
+ * Session Id
* @description The session ID that generated this image, if it is a generated image.
*/
session_id?: string;
/**
- * Node Id
+ * Node Id
* @description The node ID that generated this image, if it is a generated image.
*/
node_id?: string;
/**
- * Starred
+ * Starred
* @description Whether this image is starred.
*/
starred: boolean;
/**
- * Board Id
+ * Board Id
* @description The id of the board the image belongs to, if one exists.
*/
board_id?: string;
};
/**
- * ImageField
+ * ImageField
* @description An image primitive field
*/
ImageField: {
/**
- * Image Name
+ * Image Name
* @description The name of the image
*/
image_name: string;
};
/**
- * Image Hue Adjustment
+ * Image Hue Adjustment
* @description Adjusts the Hue of an image.
*/
ImageHueAdjustmentInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_hue_adjust
+ * Type
+ * @default img_hue_adjust
* @enum {string}
*/
type: "img_hue_adjust";
/**
- * Image
+ * Image
* @description The image to adjust
*/
image?: components["schemas"]["ImageField"];
/**
- * Hue
- * @description The degrees by which to rotate the hue, 0-360
+ * Hue
+ * @description The degrees by which to rotate the hue, 0-360
* @default 0
*/
hue?: number;
};
/**
- * Inverse Lerp Image
+ * Inverse Lerp Image
* @description Inverse linear interpolation of all pixels of an image
*/
ImageInverseLerpInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_ilerp
+ * Type
+ * @default img_ilerp
* @enum {string}
*/
type: "img_ilerp";
/**
- * Image
+ * Image
* @description The image to lerp
*/
image?: components["schemas"]["ImageField"];
/**
- * Min
- * @description The minimum input value
+ * Min
+ * @description The minimum input value
* @default 0
*/
min?: number;
/**
- * Max
- * @description The maximum input value
+ * Max
+ * @description The maximum input value
* @default 255
*/
max?: number;
};
/**
- * Image Primitive
+ * Image Primitive
* @description An image primitive value
*/
ImageInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default image
+ * Type
+ * @default image
* @enum {string}
*/
type: "image";
/**
- * Image
+ * Image
* @description The image to load
*/
image?: components["schemas"]["ImageField"];
};
/**
- * Lerp Image
+ * Lerp Image
* @description Linear interpolation of all pixels of an image
*/
ImageLerpInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_lerp
+ * Type
+ * @default img_lerp
* @enum {string}
*/
type: "img_lerp";
/**
- * Image
+ * Image
* @description The image to lerp
*/
image?: components["schemas"]["ImageField"];
/**
- * Min
- * @description The minimum output value
+ * Min
+ * @description The minimum output value
* @default 0
*/
min?: number;
/**
- * Max
- * @description The maximum output value
+ * Max
+ * @description The maximum output value
* @default 255
*/
max?: number;
};
/**
- * Image Luminosity Adjustment
+ * Image Luminosity Adjustment
* @description Adjusts the Luminosity (Value) of an image.
*/
ImageLuminosityAdjustmentInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_luminosity_adjust
+ * Type
+ * @default img_luminosity_adjust
* @enum {string}
*/
type: "img_luminosity_adjust";
/**
- * Image
+ * Image
* @description The image to adjust
*/
image?: components["schemas"]["ImageField"];
/**
- * Luminosity
- * @description The factor by which to adjust the luminosity (value)
+ * Luminosity
+ * @description The factor by which to adjust the luminosity (value)
* @default 1
*/
luminosity?: number;
};
/**
- * ImageMetadata
+ * ImageMetadata
* @description An image's generation metadata
*/
ImageMetadata: {
/**
- * Metadata
+ * Metadata
* @description The image's core metadata, if it was created in the Linear or Canvas UI
*/
metadata?: Record;
/**
- * Graph
+ * Graph
* @description The graph that created the image
*/
graph?: Record;
};
/**
- * Multiply Images
+ * Multiply Images
* @description Multiplies two images together using `PIL.ImageChops.multiply()`.
*/
ImageMultiplyInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_mul
+ * Type
+ * @default img_mul
* @enum {string}
*/
type: "img_mul";
/**
- * Image1
+ * Image1
* @description The first image to multiply
*/
image1?: components["schemas"]["ImageField"];
/**
- * Image2
+ * Image2
* @description The second image to multiply
*/
image2?: components["schemas"]["ImageField"];
};
/**
- * Blur NSFW Image
+ * Blur NSFW Image
* @description Add blur to NSFW-flagged images
*/
ImageNSFWBlurInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_nsfw
+ * Type
+ * @default img_nsfw
* @enum {string}
*/
type: "img_nsfw";
/**
- * Metadata
+ * Metadata
* @description Optional core metadata to be written to image
*/
metadata?: components["schemas"]["CoreMetadata"];
/**
- * Image
+ * Image
* @description The image to check
*/
image?: components["schemas"]["ImageField"];
};
/**
- * ImageOutput
+ * ImageOutput
* @description Base class for nodes that output a single image
*/
ImageOutput: {
/**
- * Type
- * @default image_output
+ * Type
+ * @default image_output
* @enum {string}
*/
- type?: "image_output";
+ type: "image_output";
/**
- * Image
+ * Image
* @description The output image
*/
image: components["schemas"]["ImageField"];
/**
- * Width
+ * Width
* @description The width of the image in pixels
*/
width: number;
/**
- * Height
+ * Height
* @description The height of the image in pixels
*/
height: number;
};
/**
- * Paste Image
+ * Paste Image
* @description Pastes an image into another image.
*/
ImagePasteInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_paste
+ * Type
+ * @default img_paste
* @enum {string}
*/
type: "img_paste";
/**
- * Base Image
+ * Base Image
* @description The base image
*/
base_image?: components["schemas"]["ImageField"];
/**
- * Image
+ * Image
* @description The image to paste
*/
image?: components["schemas"]["ImageField"];
/**
- * Mask
+ * Mask
* @description The mask to use when pasting
*/
mask?: components["schemas"]["ImageField"];
/**
- * X
- * @description The left x coordinate at which to paste the image
+ * X
+ * @description The left x coordinate at which to paste the image
* @default 0
*/
x?: number;
/**
- * Y
- * @description The top y coordinate at which to paste the image
+ * Y
+ * @description The top y coordinate at which to paste the image
* @default 0
*/
y?: number;
};
/**
- * ImageProcessorInvocation
+ * ImageProcessorInvocation
* @description Base class for invocations that preprocess images for ControlNet
*/
ImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default image_processor
+ * Type
+ * @default image_processor
* @enum {string}
*/
type: "image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
};
/**
- * ImageRecordChanges
+ * ImageRecordChanges
* @description A set of changes to apply to an image record.
- *
+ *
* Only limited changes are valid:
* - `image_category`: change the category of an image
* - `session_id`: change the session associated with an image
@@ -2756,244 +2851,244 @@ export type components = {
/** @description The image's new category. */
image_category?: components["schemas"]["ImageCategory"];
/**
- * Session Id
+ * Session Id
* @description The image's new session ID.
*/
session_id?: string;
/**
- * Is Intermediate
+ * Is Intermediate
* @description The image's new `is_intermediate` flag.
*/
is_intermediate?: boolean;
/**
- * Starred
+ * Starred
* @description The image's new `starred` state
*/
starred?: boolean;
};
/**
- * Resize Image
+ * Resize Image
* @description Resizes an image to specific dimensions
*/
ImageResizeInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_resize
+ * Type
+ * @default img_resize
* @enum {string}
*/
type: "img_resize";
/**
- * Image
+ * Image
* @description The image to resize
*/
image?: components["schemas"]["ImageField"];
/**
- * Width
- * @description The width to resize to (px)
+ * Width
+ * @description The width to resize to (px)
* @default 512
*/
width?: number;
/**
- * Height
- * @description The height to resize to (px)
+ * Height
+ * @description The height to resize to (px)
* @default 512
*/
height?: number;
/**
- * Resample Mode
- * @description The resampling mode
- * @default bicubic
+ * Resample Mode
+ * @description The resampling mode
+ * @default bicubic
* @enum {string}
*/
resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos";
};
/**
- * Image Saturation Adjustment
+ * Image Saturation Adjustment
* @description Adjusts the Saturation of an image.
*/
ImageSaturationAdjustmentInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_saturation_adjust
+ * Type
+ * @default img_saturation_adjust
* @enum {string}
*/
type: "img_saturation_adjust";
/**
- * Image
+ * Image
* @description The image to adjust
*/
image?: components["schemas"]["ImageField"];
/**
- * Saturation
- * @description The factor by which to adjust the saturation
+ * Saturation
+ * @description The factor by which to adjust the saturation
* @default 1
*/
saturation?: number;
};
/**
- * Scale Image
+ * Scale Image
* @description Scales an image by a factor
*/
ImageScaleInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_scale
+ * Type
+ * @default img_scale
* @enum {string}
*/
type: "img_scale";
/**
- * Image
+ * Image
* @description The image to scale
*/
image?: components["schemas"]["ImageField"];
/**
- * Scale Factor
- * @description The factor by which to scale the image
+ * Scale Factor
+ * @description The factor by which to scale the image
* @default 2
*/
scale_factor?: number;
/**
- * Resample Mode
- * @description The resampling mode
- * @default bicubic
+ * Resample Mode
+ * @description The resampling mode
+ * @default bicubic
* @enum {string}
*/
resample_mode?: "nearest" | "box" | "bilinear" | "hamming" | "bicubic" | "lanczos";
};
/**
- * Image to Latents
+ * Image to Latents
* @description Encodes an image into latents.
*/
ImageToLatentsInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default i2l
+ * Type
+ * @default i2l
* @enum {string}
*/
type: "i2l";
/**
- * Image
+ * Image
* @description The image to encode
*/
image?: components["schemas"]["ImageField"];
/**
- * Vae
+ * Vae
* @description VAE
*/
vae?: components["schemas"]["VaeField"];
/**
- * Tiled
- * @description Processing using overlapping tiles (reduce memory consumption)
+ * Tiled
+ * @description Processing using overlapping tiles (reduce memory consumption)
* @default false
*/
tiled?: boolean;
/**
- * Fp32
- * @description Whether or not to use full float32 precision
+ * Fp32
+ * @description Whether or not to use full float32 precision
* @default false
*/
fp32?: boolean;
};
/**
- * ImageUrlsDTO
+ * ImageUrlsDTO
* @description The URLs for an image and its thumbnail.
*/
ImageUrlsDTO: {
/**
- * Image Name
+ * Image Name
* @description The unique name of the image.
*/
image_name: string;
/**
- * Image Url
+ * Image Url
* @description The URL of the image.
*/
image_url: string;
/**
- * Thumbnail Url
+ * Thumbnail Url
* @description The URL of the image's thumbnail.
*/
thumbnail_url: string;
};
/**
- * Add Invisible Watermark
+ * Add Invisible Watermark
* @description Add an invisible watermark to an image
*/
ImageWatermarkInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default img_watermark
+ * Type
+ * @default img_watermark
* @enum {string}
*/
type: "img_watermark";
/**
- * Image
+ * Image
* @description The image to check
*/
image?: components["schemas"]["ImageField"];
/**
- * Text
- * @description Watermark text
+ * Text
+ * @description Watermark text
* @default InvokeAI
*/
text?: string;
/**
- * Metadata
+ * Metadata
* @description Optional core metadata to be written to image
*/
metadata?: components["schemas"]["CoreMetadata"];
@@ -3001,41 +3096,41 @@ export type components = {
/** ImagesUpdatedFromListResult */
ImagesUpdatedFromListResult: {
/**
- * Updated Image Names
+ * Updated Image Names
* @description The image names that were updated
*/
- updated_image_names: (string)[];
+ updated_image_names: string[];
};
/**
- * Solid Color Infill
+ * Solid Color Infill
* @description Infills transparent areas of an image with a solid color
*/
InfillColorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default infill_rgba
+ * Type
+ * @default infill_rgba
* @enum {string}
*/
type: "infill_rgba";
/**
- * Image
+ * Image
* @description The image to infill
*/
image?: components["schemas"]["ImageField"];
/**
- * Color
- * @description The color to use to infill
+ * Color
+ * @description The color to use to infill
* @default {
* "r": 127,
* "g": 127,
@@ -3046,538 +3141,565 @@ export type components = {
color?: components["schemas"]["ColorField"];
};
/**
- * PatchMatch Infill
+ * PatchMatch Infill
* @description Infills transparent areas of an image using the PatchMatch algorithm
*/
InfillPatchMatchInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default infill_patchmatch
+ * Type
+ * @default infill_patchmatch
* @enum {string}
*/
type: "infill_patchmatch";
/**
- * Image
+ * Image
* @description The image to infill
*/
image?: components["schemas"]["ImageField"];
};
/**
- * Tile Infill
+ * Tile Infill
* @description Infills transparent areas of an image with tiles of the image
*/
InfillTileInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default infill_tile
+ * Type
+ * @default infill_tile
* @enum {string}
*/
type: "infill_tile";
/**
- * Image
+ * Image
* @description The image to infill
*/
image?: components["schemas"]["ImageField"];
/**
- * Tile Size
- * @description The tile size (px)
+ * Tile Size
+ * @description The tile size (px)
* @default 32
*/
tile_size?: number;
/**
- * Seed
+ * Seed
* @description The seed to use for tile generation (omit for random)
*/
seed?: number;
};
/**
- * Integer Primitive Collection
+ * Integer Primitive Collection
* @description A collection of integer primitive values
*/
IntegerCollectionInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default integer_collection
+ * Type
+ * @default integer_collection
* @enum {string}
*/
type: "integer_collection";
/**
- * Collection
- * @description The collection of integer values
+ * Collection
+ * @description The collection of integer values
* @default 0
*/
- collection?: (number)[];
+ collection?: number[];
};
/**
- * IntegerCollectionOutput
+ * IntegerCollectionOutput
* @description Base class for nodes that output a collection of integers
*/
IntegerCollectionOutput: {
/**
- * Type
- * @default integer_collection_output
+ * Type
+ * @default integer_collection_output
* @enum {string}
*/
- type?: "integer_collection_output";
+ type: "integer_collection_output";
/**
- * Collection
+ * Collection
* @description The int collection
*/
- collection?: (number)[];
+ collection: number[];
};
/**
- * Integer Primitive
+ * Integer Primitive
* @description An integer primitive value
*/
IntegerInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default integer
+ * Type
+ * @default integer
* @enum {string}
*/
type: "integer";
/**
- * A
- * @description The integer value
+ * Value
+ * @description The integer value
* @default 0
*/
- a?: number;
+ value?: number;
};
/**
- * IntegerOutput
+ * IntegerOutput
* @description Base class for nodes that output a single integer
*/
IntegerOutput: {
/**
- * Type
- * @default integer_output
+ * Type
+ * @default integer_output
* @enum {string}
*/
- type?: "integer_output";
+ type: "integer_output";
/**
- * A
+ * Value
* @description The output integer
*/
- a: number;
+ value: number;
};
/**
- * IterateInvocation
+ * IterateInvocation
* @description Iterates over a list of items
*/
IterateInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default iterate
+ * Type
+ * @default iterate
* @enum {string}
*/
type: "iterate";
/**
- * Collection
+ * Collection
* @description The list of items to iterate over
*/
- collection?: (unknown)[];
+ collection?: unknown[];
/**
- * Index
- * @description The index, will be provided on executed iterators
+ * Index
+ * @description The index, will be provided on executed iterators
* @default 0
*/
index?: number;
};
/**
- * IterateInvocationOutput
+ * IterateInvocationOutput
* @description Used to connect iteration outputs. Will be expanded to a specific output.
*/
IterateInvocationOutput: {
/**
- * Type
- * @default iterate_output
+ * Type
+ * @default iterate_output
* @enum {string}
*/
- type?: "iterate_output";
+ type: "iterate_output";
/**
- * Collection Item
+ * Collection Item
* @description The item being iterated over
*/
item?: unknown;
};
/**
- * Latents Primitive Collection
- * @description A collection of latents tensor primitive values
+ * LaMa Infill
+ * @description Infills transparent areas of an image using the LaMa model
*/
- LatentsCollectionInvocation: {
+ LaMaInfillInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default latents_collection
+ * Type
+ * @default infill_lama
+ * @enum {string}
+ */
+ type: "infill_lama";
+ /**
+ * Image
+ * @description The image to infill
+ */
+ image?: components["schemas"]["ImageField"];
+ };
+ /**
+ * Latents Primitive Collection
+ * @description A collection of latents tensor primitive values
+ */
+ LatentsCollectionInvocation: {
+ /**
+ * Id
+ * @description The id of this node. Must be unique among all nodes.
+ */
+ id: string;
+ /**
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
+ * @default false
+ */
+ is_intermediate?: boolean;
+ /**
+ * Type
+ * @default latents_collection
* @enum {string}
*/
type: "latents_collection";
/**
- * Collection
- * @description The collection of latents tensors
- * @default 0
+ * Collection
+ * @description The collection of latents tensors
*/
- collection?: (components["schemas"]["LatentsField"])[];
+ collection?: components["schemas"]["LatentsField"][];
};
/**
- * LatentsCollectionOutput
+ * LatentsCollectionOutput
* @description Base class for nodes that output a collection of latents tensors
*/
LatentsCollectionOutput: {
/**
- * Type
- * @default latents_collection_output
+ * Type
+ * @default latents_collection_output
* @enum {string}
*/
- type?: "latents_collection_output";
+ type: "latents_collection_output";
/**
- * Collection
+ * Collection
* @description Latents tensor
*/
- collection?: (components["schemas"]["LatentsField"])[];
+ collection: components["schemas"]["LatentsField"][];
};
/**
- * LatentsField
+ * LatentsField
* @description A latents tensor primitive field
*/
LatentsField: {
/**
- * Latents Name
+ * Latents Name
* @description The name of the latents
*/
latents_name: string;
/**
- * Seed
+ * Seed
* @description Seed used to generate this latents
*/
seed?: number;
};
/**
- * Latents Primitive
+ * Latents Primitive
* @description A latents tensor primitive value
*/
LatentsInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default latents
+ * Type
+ * @default latents
* @enum {string}
*/
type: "latents";
/**
- * Latents
+ * Latents
* @description The latents tensor
*/
latents?: components["schemas"]["LatentsField"];
};
/**
- * LatentsOutput
+ * LatentsOutput
* @description Base class for nodes that output a single latents tensor
*/
LatentsOutput: {
/**
- * Type
- * @default latents_output
+ * Type
+ * @default latents_output
* @enum {string}
*/
- type?: "latents_output";
+ type: "latents_output";
/**
- * Latents
+ * Latents
* @description Latents tensor
*/
latents: components["schemas"]["LatentsField"];
/**
- * Width
+ * Width
* @description Width of output (px)
*/
width: number;
/**
- * Height
+ * Height
* @description Height of output (px)
*/
height: number;
};
/**
- * Latents to Image
+ * Latents to Image
* @description Generates an image from latents.
*/
LatentsToImageInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default l2i
+ * Type
+ * @default l2i
* @enum {string}
*/
type: "l2i";
/**
- * Tiled
- * @description Processing using overlapping tiles (reduce memory consumption)
+ * Tiled
+ * @description Processing using overlapping tiles (reduce memory consumption)
* @default false
*/
tiled?: boolean;
/**
- * Fp32
- * @description Whether or not to use full float32 precision
+ * Fp32
+ * @description Whether or not to use full float32 precision
* @default false
*/
fp32?: boolean;
/**
- * Metadata
+ * Metadata
* @description Optional core metadata to be written to image
*/
metadata?: components["schemas"]["CoreMetadata"];
/**
- * Latents
+ * Latents
* @description Latents tensor
*/
latents?: components["schemas"]["LatentsField"];
/**
- * Vae
+ * Vae
* @description VAE
*/
vae?: components["schemas"]["VaeField"];
};
/**
- * Leres (Depth) Processor
+ * Leres (Depth) Processor
* @description Applies leres processing to image
*/
LeresImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default leres_image_processor
+ * Type
+ * @default leres_image_processor
* @enum {string}
*/
type: "leres_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Thr A
- * @description Leres parameter `thr_a`
+ * Thr A
+ * @description Leres parameter `thr_a`
* @default 0
*/
thr_a?: number;
/**
- * Thr B
- * @description Leres parameter `thr_b`
+ * Thr B
+ * @description Leres parameter `thr_b`
* @default 0
*/
thr_b?: number;
/**
- * Boost
- * @description Whether to use boost mode
+ * Boost
+ * @description Whether to use boost mode
* @default false
*/
boost?: boolean;
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
};
/**
- * Lineart Anime Processor
+ * Lineart Anime Processor
* @description Applies line art anime processing to image
*/
LineartAnimeImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default lineart_anime_image_processor
+ * Type
+ * @default lineart_anime_image_processor
* @enum {string}
*/
type: "lineart_anime_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
};
/**
- * Lineart Processor
+ * Lineart Processor
* @description Applies line art processing to image
*/
LineartImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default lineart_image_processor
+ * Type
+ * @default lineart_image_processor
* @enum {string}
*/
type: "lineart_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
/**
- * Coarse
- * @description Whether to use coarse mode
+ * Coarse
+ * @description Whether to use coarse mode
* @default false
*/
coarse?: boolean;
};
/**
- * LoRAMetadataField
+ * LoRAMetadataField
* @description LoRA metadata for an image generated in InvokeAI.
*/
LoRAMetadataField: {
/**
- * Lora
+ * Lora
* @description The LoRA model
*/
lora: components["schemas"]["LoRAModelField"];
/**
- * Weight
+ * Weight
* @description The weight of the LoRA model
*/
weight: number;
@@ -3588,7 +3710,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "lora";
@@ -3600,12 +3722,12 @@ export type components = {
error?: components["schemas"]["ModelError"];
};
/**
- * LoRAModelField
+ * LoRAModelField
* @description LoRA model field
*/
LoRAModelField: {
/**
- * Model Name
+ * Model Name
* @description Name of the LoRA model
*/
model_name: string;
@@ -3613,21 +3735,21 @@ export type components = {
base_model: components["schemas"]["BaseModelType"];
};
/**
- * LoRAModelFormat
- * @description An enumeration.
+ * LoRAModelFormat
+ * @description An enumeration.
* @enum {string}
*/
LoRAModelFormat: "lycoris" | "diffusers";
/**
- * LogLevel
- * @description An enumeration.
+ * LogLevel
+ * @description An enumeration.
* @enum {integer}
*/
LogLevel: 0 | 10 | 20 | 30 | 40 | 50;
/** LoraInfo */
LoraInfo: {
/**
- * Model Name
+ * Model Name
* @description Info to load submodel
*/
model_name: string;
@@ -3638,84 +3760,84 @@ export type components = {
/** @description Info to load submodel */
submodel?: components["schemas"]["SubModelType"];
/**
- * Weight
+ * Weight
* @description Lora's weight which to use when apply to model
*/
weight: number;
};
/**
- * LoRA Loader
+ * LoRA
* @description Apply selected lora to unet and text_encoder.
*/
LoraLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default lora_loader
+ * Type
+ * @default lora_loader
* @enum {string}
*/
type: "lora_loader";
/**
- * LoRA
+ * LoRA
* @description LoRA model to load
*/
lora: components["schemas"]["LoRAModelField"];
/**
- * Weight
- * @description The weight at which the LoRA is applied to each model
+ * Weight
+ * @description The weight at which the LoRA is applied to each model
* @default 0.75
*/
weight?: number;
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
/**
- * CLIP
+ * CLIP
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
};
/**
- * LoraLoaderOutput
+ * LoraLoaderOutput
* @description Model loader output
*/
LoraLoaderOutput: {
/**
- * Type
- * @default lora_loader_output
+ * Type
+ * @default lora_loader_output
* @enum {string}
*/
- type?: "lora_loader_output";
+ type: "lora_loader_output";
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
/**
- * CLIP
+ * CLIP
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
};
/**
- * MainModelField
+ * MainModelField
* @description Main model field
*/
MainModelField: {
/**
- * Model Name
+ * Model Name
* @description Name of the model
*/
model_name: string;
@@ -3725,466 +3847,466 @@ export type components = {
model_type: components["schemas"]["ModelType"];
};
/**
- * Main Model Loader
+ * Main Model
* @description Loads a main model, outputting its submodels.
*/
MainModelLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default main_model_loader
+ * Type
+ * @default main_model_loader
* @enum {string}
*/
type: "main_model_loader";
/**
- * Model
+ * Model
* @description Main model (UNet, VAE, CLIP) to load
*/
model: components["schemas"]["MainModelField"];
};
/**
- * Combine Mask
+ * Combine Mask
* @description Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`.
*/
MaskCombineInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default mask_combine
+ * Type
+ * @default mask_combine
* @enum {string}
*/
type: "mask_combine";
/**
- * Mask1
+ * Mask1
* @description The first mask to combine
*/
mask1?: components["schemas"]["ImageField"];
/**
- * Mask2
+ * Mask2
* @description The second image to combine
*/
mask2?: components["schemas"]["ImageField"];
};
/**
- * Mask Edge
+ * Mask Edge
* @description Applies an edge mask to an image
*/
MaskEdgeInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default mask_edge
+ * Type
+ * @default mask_edge
* @enum {string}
*/
type: "mask_edge";
/**
- * Image
+ * Image
* @description The image to apply the mask to
*/
image?: components["schemas"]["ImageField"];
/**
- * Edge Size
+ * Edge Size
* @description The size of the edge
*/
edge_size?: number;
/**
- * Edge Blur
+ * Edge Blur
* @description The amount of blur on the edge
*/
edge_blur?: number;
/**
- * Low Threshold
+ * Low Threshold
* @description First threshold for the hysteresis procedure in Canny edge detection
*/
low_threshold?: number;
/**
- * High Threshold
+ * High Threshold
* @description Second threshold for the hysteresis procedure in Canny edge detection
*/
high_threshold?: number;
};
/**
- * Mask from Alpha
+ * Mask from Alpha
* @description Extracts the alpha channel of an image as a mask.
*/
MaskFromAlphaInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default tomask
+ * Type
+ * @default tomask
* @enum {string}
*/
type: "tomask";
/**
- * Image
+ * Image
* @description The image to create the mask from
*/
image?: components["schemas"]["ImageField"];
/**
- * Invert
- * @description Whether or not to invert the mask
+ * Invert
+ * @description Whether or not to invert the mask
* @default false
*/
invert?: boolean;
};
/**
- * Mediapipe Face Processor
+ * Mediapipe Face Processor
* @description Applies mediapipe face processing to image
*/
MediapipeFaceProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default mediapipe_face_processor
+ * Type
+ * @default mediapipe_face_processor
* @enum {string}
*/
type: "mediapipe_face_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Max Faces
- * @description Maximum number of faces to detect
+ * Max Faces
+ * @description Maximum number of faces to detect
* @default 1
*/
max_faces?: number;
/**
- * Min Confidence
- * @description Minimum confidence for face detection
+ * Min Confidence
+ * @description Minimum confidence for face detection
* @default 0.5
*/
min_confidence?: number;
};
/**
- * MergeInterpolationMethod
- * @description An enumeration.
+ * MergeInterpolationMethod
+ * @description An enumeration.
* @enum {string}
*/
MergeInterpolationMethod: "weighted_sum" | "sigmoid" | "inv_sigmoid" | "add_difference";
/**
- * Metadata Accumulator
+ * Metadata Accumulator
* @description Outputs a Core Metadata Object
*/
MetadataAccumulatorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default metadata_accumulator
+ * Type
+ * @default metadata_accumulator
* @enum {string}
*/
type: "metadata_accumulator";
/**
- * Generation Mode
+ * Generation Mode
* @description The generation mode that output this image
*/
generation_mode?: string;
/**
- * Positive Prompt
+ * Positive Prompt
* @description The positive prompt parameter
*/
positive_prompt?: string;
/**
- * Negative Prompt
+ * Negative Prompt
* @description The negative prompt parameter
*/
negative_prompt?: string;
/**
- * Width
+ * Width
* @description The width parameter
*/
width?: number;
/**
- * Height
+ * Height
* @description The height parameter
*/
height?: number;
/**
- * Seed
+ * Seed
* @description The seed used for noise generation
*/
seed?: number;
/**
- * Rand Device
+ * Rand Device
* @description The device used for random number generation
*/
rand_device?: string;
/**
- * Cfg Scale
+ * Cfg Scale
* @description The classifier-free guidance scale parameter
*/
cfg_scale?: number;
/**
- * Steps
+ * Steps
* @description The number of steps used for inference
*/
steps?: number;
/**
- * Scheduler
+ * Scheduler
* @description The scheduler used for inference
*/
scheduler?: string;
/**
- * Clip Skip
+ * Clip Skip
* @description The number of skipped CLIP layers
*/
clip_skip?: number;
/**
- * Model
+ * Model
* @description The main model used for inference
*/
model?: components["schemas"]["MainModelField"];
/**
- * Controlnets
+ * Controlnets
* @description The ControlNets used for inference
*/
- controlnets?: (components["schemas"]["ControlField"])[];
+ controlnets?: components["schemas"]["ControlField"][];
/**
- * Loras
+ * Loras
* @description The LoRAs used for inference
*/
- loras?: (components["schemas"]["LoRAMetadataField"])[];
+ loras?: components["schemas"]["LoRAMetadataField"][];
/**
- * Strength
+ * Strength
* @description The strength used for latents-to-latents
*/
strength?: number;
/**
- * Init Image
+ * Init Image
* @description The name of the initial image
*/
init_image?: string;
/**
- * Vae
+ * Vae
* @description The VAE used for decoding, if the main model's default was not used
*/
vae?: components["schemas"]["VAEModelField"];
/**
- * Positive Style Prompt
+ * Positive Style Prompt
* @description The positive style prompt parameter
*/
positive_style_prompt?: string;
/**
- * Negative Style Prompt
+ * Negative Style Prompt
* @description The negative style prompt parameter
*/
negative_style_prompt?: string;
/**
- * Refiner Model
+ * Refiner Model
* @description The SDXL Refiner model used
*/
refiner_model?: components["schemas"]["MainModelField"];
/**
- * Refiner Cfg Scale
+ * Refiner Cfg Scale
* @description The classifier-free guidance scale parameter used for the refiner
*/
refiner_cfg_scale?: number;
/**
- * Refiner Steps
+ * Refiner Steps
* @description The number of steps used for the refiner
*/
refiner_steps?: number;
/**
- * Refiner Scheduler
+ * Refiner Scheduler
* @description The scheduler used for the refiner
*/
refiner_scheduler?: string;
/**
- * Refiner Positive Aesthetic Store
+ * Refiner Positive Aesthetic Store
* @description The aesthetic score used for the refiner
*/
refiner_positive_aesthetic_store?: number;
/**
- * Refiner Negative Aesthetic Store
+ * Refiner Negative Aesthetic Store
* @description The aesthetic score used for the refiner
*/
refiner_negative_aesthetic_store?: number;
/**
- * Refiner Start
+ * Refiner Start
* @description The start value used for refiner denoising
*/
refiner_start?: number;
};
/**
- * MetadataAccumulatorOutput
+ * MetadataAccumulatorOutput
* @description The output of the MetadataAccumulator node
*/
MetadataAccumulatorOutput: {
/**
- * Type
- * @default metadata_accumulator_output
+ * Type
+ * @default metadata_accumulator_output
* @enum {string}
*/
- type?: "metadata_accumulator_output";
+ type: "metadata_accumulator_output";
/**
- * Metadata
+ * Metadata
* @description The core metadata for the image
*/
metadata: components["schemas"]["CoreMetadata"];
};
/**
- * Midas (Depth) Processor
+ * Midas (Depth) Processor
* @description Applies Midas depth processing to image
*/
MidasDepthImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default midas_depth_image_processor
+ * Type
+ * @default midas_depth_image_processor
* @enum {string}
*/
type: "midas_depth_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * A Mult
- * @description Midas parameter `a_mult` (a = a_mult * PI)
+ * A Mult
+ * @description Midas parameter `a_mult` (a = a_mult * PI)
* @default 2
*/
a_mult?: number;
/**
- * Bg Th
- * @description Midas parameter `bg_th`
+ * Bg Th
+ * @description Midas parameter `bg_th`
* @default 0.1
*/
bg_th?: number;
};
/**
- * MLSD Processor
+ * MLSD Processor
* @description Applies MLSD processing to image
*/
MlsdImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default mlsd_image_processor
+ * Type
+ * @default mlsd_image_processor
* @enum {string}
*/
type: "mlsd_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
/**
- * Thr V
- * @description MLSD parameter `thr_v`
+ * Thr V
+ * @description MLSD parameter `thr_v`
* @default 0.1
*/
thr_v?: number;
/**
- * Thr D
- * @description MLSD parameter `thr_d`
+ * Thr D
+ * @description MLSD parameter `thr_d`
* @default 0.1
*/
thr_d?: number;
};
/**
- * ModelError
- * @description An enumeration.
+ * ModelError
+ * @description An enumeration.
* @enum {string}
*/
ModelError: "not_found";
/** ModelInfo */
ModelInfo: {
/**
- * Model Name
+ * Model Name
* @description Info to load submodel
*/
model_name: string;
@@ -4196,41 +4318,41 @@ export type components = {
submodel?: components["schemas"]["SubModelType"];
};
/**
- * ModelLoaderOutput
+ * ModelLoaderOutput
* @description Model loader output
*/
ModelLoaderOutput: {
/**
- * Type
- * @default model_loader_output
+ * Type
+ * @default model_loader_output
* @enum {string}
*/
- type?: "model_loader_output";
+ type: "model_loader_output";
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet: components["schemas"]["UNetField"];
/**
- * CLIP
+ * CLIP
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip: components["schemas"]["ClipField"];
/**
- * VAE
+ * VAE
* @description VAE
*/
vae: components["schemas"]["VaeField"];
};
/**
- * ModelType
- * @description An enumeration.
+ * ModelType
+ * @description An enumeration.
* @enum {string}
*/
ModelType: "onnx" | "main" | "vae" | "lora" | "controlnet" | "embedding";
/**
- * ModelVariantType
- * @description An enumeration.
+ * ModelVariantType
+ * @description An enumeration.
* @enum {string}
*/
ModelVariantType: "normal" | "inpaint" | "depth";
@@ -4240,254 +4362,254 @@ export type components = {
models: (components["schemas"]["ONNXStableDiffusion1ModelConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelCheckpointConfig"] | components["schemas"]["ControlNetModelDiffusersConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["ONNXStableDiffusion2ModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusionXLModelCheckpointConfig"] | components["schemas"]["StableDiffusionXLModelDiffusersConfig"])[];
};
/**
- * Multiply Integers
+ * Multiply Integers
* @description Multiplies two numbers
*/
MultiplyInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default mul
+ * Type
+ * @default mul
* @enum {string}
*/
type: "mul";
/**
- * A
- * @description The first number
+ * A
+ * @description The first number
* @default 0
*/
a?: number;
/**
- * B
- * @description The second number
+ * B
+ * @description The second number
* @default 0
*/
b?: number;
};
/**
- * Noise
+ * Noise
* @description Generates latent noise.
*/
NoiseInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default noise
+ * Type
+ * @default noise
* @enum {string}
*/
type: "noise";
/**
- * Seed
+ * Seed
* @description Seed for random number generation
*/
seed?: number;
/**
- * Width
- * @description Width of output (px)
+ * Width
+ * @description Width of output (px)
* @default 512
*/
width?: number;
/**
- * Height
- * @description Height of output (px)
+ * Height
+ * @description Height of output (px)
* @default 512
*/
height?: number;
/**
- * Use Cpu
- * @description Use CPU for noise generation (for reproducible results across platforms)
+ * Use Cpu
+ * @description Use CPU for noise generation (for reproducible results across platforms)
* @default true
*/
use_cpu?: boolean;
};
/**
- * NoiseOutput
+ * NoiseOutput
* @description Invocation noise output
*/
NoiseOutput: {
/**
- * Type
- * @default noise_output
+ * Type
+ * @default noise_output
* @enum {string}
*/
- type?: "noise_output";
+ type: "noise_output";
/**
- * Noise
+ * Noise
* @description Noise tensor
*/
noise?: components["schemas"]["LatentsField"];
/**
- * Width
+ * Width
* @description Width of output (px)
*/
width: number;
/**
- * Height
+ * Height
* @description Height of output (px)
*/
height: number;
};
/**
- * Normal BAE Processor
+ * Normal BAE Processor
* @description Applies NormalBae processing to image
*/
NormalbaeImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default normalbae_image_processor
+ * Type
+ * @default normalbae_image_processor
* @enum {string}
*/
type: "normalbae_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
};
/**
- * ONNX Latents to Image
+ * ONNX Latents to Image
* @description Generates an image from latents.
*/
ONNXLatentsToImageInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default l2i_onnx
+ * Type
+ * @default l2i_onnx
* @enum {string}
*/
type: "l2i_onnx";
/**
- * Latents
+ * Latents
* @description Denoised latents tensor
*/
latents?: components["schemas"]["LatentsField"];
/**
- * Vae
+ * Vae
* @description VAE
*/
vae?: components["schemas"]["VaeField"];
/**
- * Metadata
+ * Metadata
* @description Optional core metadata to be written to image
*/
metadata?: components["schemas"]["CoreMetadata"];
};
/**
- * ONNXModelLoaderOutput
+ * ONNXModelLoaderOutput
* @description Model loader output
*/
ONNXModelLoaderOutput: {
/**
- * Type
- * @default model_loader_output_onnx
+ * Type
+ * @default model_loader_output_onnx
* @enum {string}
*/
- type?: "model_loader_output_onnx";
+ type: "model_loader_output_onnx";
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
/**
- * CLIP
+ * CLIP
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
/**
- * VAE Decoder
+ * VAE Decoder
* @description VAE
*/
vae_decoder?: components["schemas"]["VaeField"];
/**
- * VAE Encoder
+ * VAE Encoder
* @description VAE
*/
vae_encoder?: components["schemas"]["VaeField"];
};
/**
- * ONNX Prompt (Raw)
+ * ONNX Prompt (Raw)
* @description A node to process inputs and produce outputs.
* May use dependency injection in __init__ to receive providers.
*/
ONNXPromptInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default prompt_onnx
+ * Type
+ * @default prompt_onnx
* @enum {string}
*/
type: "prompt_onnx";
/**
- * Prompt
- * @description Raw prompt text (no parsing)
+ * Prompt
+ * @description Raw prompt text (no parsing)
* @default
*/
prompt?: string;
/**
- * Clip
+ * Clip
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
@@ -4498,7 +4620,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "onnx";
@@ -4507,7 +4629,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "onnx";
@@ -4520,7 +4642,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "onnx";
@@ -4529,7 +4651,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "onnx";
@@ -4540,138 +4662,138 @@ export type components = {
upcast_attention: boolean;
};
/**
- * ONNX Text to Latents
+ * ONNX Text to Latents
* @description Generates latents from conditionings.
*/
ONNXTextToLatentsInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default t2l_onnx
+ * Type
+ * @default t2l_onnx
* @enum {string}
*/
type: "t2l_onnx";
/**
- * Positive Conditioning
+ * Positive Conditioning
* @description Positive conditioning tensor
*/
positive_conditioning?: components["schemas"]["ConditioningField"];
/**
- * Negative Conditioning
+ * Negative Conditioning
* @description Negative conditioning tensor
*/
negative_conditioning?: components["schemas"]["ConditioningField"];
/**
- * Noise
+ * Noise
* @description Noise tensor
*/
noise?: components["schemas"]["LatentsField"];
/**
- * Steps
- * @description Number of steps to run
+ * Steps
+ * @description Number of steps to run
* @default 10
*/
steps?: number;
/**
- * Cfg Scale
- * @description Classifier-Free Guidance scale
+ * Cfg Scale
+ * @description Classifier-Free Guidance scale
* @default 7.5
*/
- cfg_scale?: number | (number)[];
+ cfg_scale?: number | number[];
/**
- * Scheduler
- * @description Scheduler to use during inference
- * @default euler
+ * Scheduler
+ * @description Scheduler to use during inference
+ * @default euler
* @enum {string}
*/
scheduler?: "ddim" | "ddpm" | "deis" | "lms" | "lms_k" | "pndm" | "heun" | "heun_k" | "euler" | "euler_k" | "euler_a" | "kdpm_2" | "kdpm_2_a" | "dpmpp_2s" | "dpmpp_2s_k" | "dpmpp_2m" | "dpmpp_2m_k" | "dpmpp_2m_sde" | "dpmpp_2m_sde_k" | "dpmpp_sde" | "dpmpp_sde_k" | "unipc";
/**
- * Precision
- * @description Precision to use
- * @default tensor(float16)
+ * Precision
+ * @description Precision to use
+ * @default tensor(float16)
* @enum {string}
*/
precision?: "tensor(bool)" | "tensor(int8)" | "tensor(uint8)" | "tensor(int16)" | "tensor(uint16)" | "tensor(int32)" | "tensor(uint32)" | "tensor(int64)" | "tensor(uint64)" | "tensor(float16)" | "tensor(float)" | "tensor(double)";
/**
- * Unet
+ * Unet
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
/**
- * Control
+ * Control
* @description ControlNet(s) to apply
*/
- control?: components["schemas"]["ControlField"] | (components["schemas"]["ControlField"])[];
+ control?: components["schemas"]["ControlField"] | components["schemas"]["ControlField"][];
};
/**
- * OffsetPaginatedResults[BoardDTO]
+ * OffsetPaginatedResults[BoardDTO]
* @description Offset-paginated results
*/
OffsetPaginatedResults_BoardDTO_: {
/**
- * Items
+ * Items
* @description Items
*/
- items: (components["schemas"]["BoardDTO"])[];
+ items: components["schemas"]["BoardDTO"][];
/**
- * Offset
+ * Offset
* @description Offset from which to retrieve items
*/
offset: number;
/**
- * Limit
+ * Limit
* @description Limit of items to get
*/
limit: number;
/**
- * Total
+ * Total
* @description Total number of items in result
*/
total: number;
};
/**
- * OffsetPaginatedResults[ImageDTO]
+ * OffsetPaginatedResults[ImageDTO]
* @description Offset-paginated results
*/
OffsetPaginatedResults_ImageDTO_: {
/**
- * Items
+ * Items
* @description Items
*/
- items: (components["schemas"]["ImageDTO"])[];
+ items: components["schemas"]["ImageDTO"][];
/**
- * Offset
+ * Offset
* @description Offset from which to retrieve items
*/
offset: number;
/**
- * Limit
+ * Limit
* @description Limit of items to get
*/
limit: number;
/**
- * Total
+ * Total
* @description Total number of items in result
*/
total: number;
};
/**
- * OnnxModelField
+ * OnnxModelField
* @description Onnx model field
*/
OnnxModelField: {
/**
- * Model Name
+ * Model Name
* @description Name of the model
*/
model_name: string;
@@ -4681,371 +4803,371 @@ export type components = {
model_type: components["schemas"]["ModelType"];
};
/**
- * ONNX Model Loader
+ * ONNX Main Model
* @description Loads a main model, outputting its submodels.
*/
OnnxModelLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default onnx_model_loader
+ * Type
+ * @default onnx_model_loader
* @enum {string}
*/
type: "onnx_model_loader";
/**
- * Model
+ * Model
* @description ONNX Main model (UNet, VAE, CLIP) to load
*/
model: components["schemas"]["OnnxModelField"];
};
/**
- * Openpose Processor
+ * Openpose Processor
* @description Applies Openpose processing to image
*/
OpenposeImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default openpose_image_processor
+ * Type
+ * @default openpose_image_processor
* @enum {string}
*/
type: "openpose_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Hand And Face
- * @description Whether to use hands and face mode
+ * Hand And Face
+ * @description Whether to use hands and face mode
* @default false
*/
hand_and_face?: boolean;
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
};
/**
- * PaginatedResults[GraphExecutionState]
+ * PaginatedResults[GraphExecutionState]
* @description Paginated results
*/
PaginatedResults_GraphExecutionState_: {
/**
- * Items
+ * Items
* @description Items
*/
- items: (components["schemas"]["GraphExecutionState"])[];
+ items: components["schemas"]["GraphExecutionState"][];
/**
- * Page
+ * Page
* @description Current Page
*/
page: number;
/**
- * Pages
+ * Pages
* @description Total number of pages
*/
pages: number;
/**
- * Per Page
+ * Per Page
* @description Number of items per page
*/
per_page: number;
/**
- * Total
+ * Total
* @description Total number of items in result
*/
total: number;
};
/**
- * PIDI Processor
+ * PIDI Processor
* @description Applies PIDI processing to image
*/
PidiImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default pidi_image_processor
+ * Type
+ * @default pidi_image_processor
* @enum {string}
*/
type: "pidi_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Detect Resolution
- * @description Pixel resolution for detection
+ * Detect Resolution
+ * @description Pixel resolution for detection
* @default 512
*/
detect_resolution?: number;
/**
- * Image Resolution
- * @description Pixel resolution for output image
+ * Image Resolution
+ * @description Pixel resolution for output image
* @default 512
*/
image_resolution?: number;
/**
- * Safe
- * @description Whether or not to use safe mode
+ * Safe
+ * @description Whether or not to use safe mode
* @default false
*/
safe?: boolean;
/**
- * Scribble
- * @description Whether or not to use scribble mode
+ * Scribble
+ * @description Whether or not to use scribble mode
* @default false
*/
scribble?: boolean;
};
/**
- * Prompts from File
+ * Prompts from File
* @description Loads prompts from a text file
*/
PromptsFromFileInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default prompt_from_file
+ * Type
+ * @default prompt_from_file
* @enum {string}
*/
type: "prompt_from_file";
/**
- * File Path
+ * File Path
* @description Path to prompt text file
*/
file_path?: string;
/**
- * Pre Prompt
+ * Pre Prompt
* @description String to prepend to each prompt
*/
pre_prompt?: string;
/**
- * Post Prompt
+ * Post Prompt
* @description String to append to each prompt
*/
post_prompt?: string;
/**
- * Start Line
- * @description Line in the file to start start from
+ * Start Line
+ * @description Line in the file to start start from
* @default 1
*/
start_line?: number;
/**
- * Max Prompts
- * @description Max lines to read from file (0=all)
+ * Max Prompts
+ * @description Max lines to read from file (0=all)
* @default 1
*/
max_prompts?: number;
};
/**
- * Random Integer
+ * Random Integer
* @description Outputs a single random integer.
*/
RandomIntInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default rand_int
+ * Type
+ * @default rand_int
* @enum {string}
*/
type: "rand_int";
/**
- * Low
- * @description The inclusive low value
+ * Low
+ * @description The inclusive low value
* @default 0
*/
low?: number;
/**
- * High
- * @description The exclusive high value
+ * High
+ * @description The exclusive high value
* @default 2147483647
*/
high?: number;
};
/**
- * Random Range
+ * Random Range
* @description Creates a collection of random numbers
*/
RandomRangeInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default random_range
+ * Type
+ * @default random_range
* @enum {string}
*/
type: "random_range";
/**
- * Low
- * @description The inclusive low value
+ * Low
+ * @description The inclusive low value
* @default 0
*/
low?: number;
/**
- * High
- * @description The exclusive high value
+ * High
+ * @description The exclusive high value
* @default 2147483647
*/
high?: number;
/**
- * Size
- * @description The number of values to generate
+ * Size
+ * @description The number of values to generate
* @default 1
*/
size?: number;
/**
- * Seed
+ * Seed
* @description The seed for the RNG (omit for random)
*/
seed?: number;
};
/**
- * Integer Range
+ * Integer Range
* @description Creates a range of numbers from start to stop with step
*/
RangeInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default range
+ * Type
+ * @default range
* @enum {string}
*/
type: "range";
/**
- * Start
- * @description The start of the range
+ * Start
+ * @description The start of the range
* @default 0
*/
start?: number;
/**
- * Stop
- * @description The stop of the range
+ * Stop
+ * @description The stop of the range
* @default 10
*/
stop?: number;
/**
- * Step
- * @description The step of the range
+ * Step
+ * @description The step of the range
* @default 1
*/
step?: number;
};
/**
- * Integer Range of Size
+ * Integer Range of Size
* @description Creates a range from start to start + size with step
*/
RangeOfSizeInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default range_of_size
+ * Type
+ * @default range_of_size
* @enum {string}
*/
type: "range_of_size";
/**
- * Start
- * @description The start of the range
+ * Start
+ * @description The start of the range
* @default 0
*/
start?: number;
/**
- * Size
- * @description The number of values
+ * Size
+ * @description The number of values
* @default 1
*/
size?: number;
/**
- * Step
- * @description The step of the range
+ * Step
+ * @description The step of the range
* @default 1
*/
step?: number;
@@ -5053,502 +5175,502 @@ export type components = {
/** RemoveImagesFromBoardResult */
RemoveImagesFromBoardResult: {
/**
- * Removed Image Names
+ * Removed Image Names
* @description The image names that were removed from their board
*/
- removed_image_names: (string)[];
+ removed_image_names: string[];
};
/**
- * Resize Latents
+ * Resize Latents
* @description Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8.
*/
ResizeLatentsInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default lresize
+ * Type
+ * @default lresize
* @enum {string}
*/
type: "lresize";
/**
- * Latents
+ * Latents
* @description Latents tensor
*/
latents?: components["schemas"]["LatentsField"];
/**
- * Width
+ * Width
* @description Width of output (px)
*/
width?: number;
/**
- * Height
+ * Height
* @description Width of output (px)
*/
height?: number;
/**
- * Mode
- * @description Interpolation mode
- * @default bilinear
+ * Mode
+ * @description Interpolation mode
+ * @default bilinear
* @enum {string}
*/
mode?: "nearest" | "linear" | "bilinear" | "bicubic" | "trilinear" | "area" | "nearest-exact";
/**
- * Antialias
- * @description Whether or not to apply antialiasing (bilinear or bicubic only)
+ * Antialias
+ * @description Whether or not to apply antialiasing (bilinear or bicubic only)
* @default false
*/
antialias?: boolean;
};
/**
- * ResourceOrigin
+ * ResourceOrigin
* @description The origin of a resource (eg image).
- *
+ *
* - INTERNAL: The resource was created by the application.
* - EXTERNAL: The resource was not created by the application.
- * This may be a user-initiated upload, or an internal application upload (eg Canvas init image).
+ * This may be a user-initiated upload, or an internal application upload (eg Canvas init image).
* @enum {string}
*/
ResourceOrigin: "internal" | "external";
/**
- * SDXL Compel Prompt
+ * SDXL Compel Prompt
* @description Parse prompt using compel package to conditioning.
*/
SDXLCompelPromptInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default sdxl_compel_prompt
+ * Type
+ * @default sdxl_compel_prompt
* @enum {string}
*/
type: "sdxl_compel_prompt";
/**
- * Prompt
- * @description Prompt to be parsed by Compel to create a conditioning tensor
+ * Prompt
+ * @description Prompt to be parsed by Compel to create a conditioning tensor
* @default
*/
prompt?: string;
/**
- * Style
- * @description Prompt to be parsed by Compel to create a conditioning tensor
+ * Style
+ * @description Prompt to be parsed by Compel to create a conditioning tensor
* @default
*/
style?: string;
/**
- * Original Width
+ * Original Width
* @default 1024
*/
original_width?: number;
/**
- * Original Height
+ * Original Height
* @default 1024
*/
original_height?: number;
/**
- * Crop Top
+ * Crop Top
* @default 0
*/
crop_top?: number;
/**
- * Crop Left
+ * Crop Left
* @default 0
*/
crop_left?: number;
/**
- * Target Width
+ * Target Width
* @default 1024
*/
target_width?: number;
/**
- * Target Height
+ * Target Height
* @default 1024
*/
target_height?: number;
/**
- * Clip
+ * Clip
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
/**
- * Clip2
+ * Clip2
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip2?: components["schemas"]["ClipField"];
};
/**
- * SDXL LoRA Loader
+ * SDXL LoRA
* @description Apply selected lora to unet and text_encoder.
*/
SDXLLoraLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default sdxl_lora_loader
+ * Type
+ * @default sdxl_lora_loader
* @enum {string}
*/
type: "sdxl_lora_loader";
/**
- * LoRA
+ * LoRA
* @description LoRA model to load
*/
lora: components["schemas"]["LoRAModelField"];
/**
- * Weight
- * @description The weight at which the LoRA is applied to each model
+ * Weight
+ * @description The weight at which the LoRA is applied to each model
* @default 0.75
*/
weight?: number;
/**
- * UNET
+ * UNET
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
/**
- * CLIP 1
+ * CLIP 1
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
/**
- * CLIP 2
+ * CLIP 2
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip2?: components["schemas"]["ClipField"];
};
/**
- * SDXLLoraLoaderOutput
+ * SDXLLoraLoaderOutput
* @description SDXL LoRA Loader Output
*/
SDXLLoraLoaderOutput: {
/**
- * Type
- * @default sdxl_lora_loader_output
+ * Type
+ * @default sdxl_lora_loader_output
* @enum {string}
*/
- type?: "sdxl_lora_loader_output";
+ type: "sdxl_lora_loader_output";
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet?: components["schemas"]["UNetField"];
/**
- * CLIP 1
+ * CLIP 1
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip?: components["schemas"]["ClipField"];
/**
- * CLIP 2
+ * CLIP 2
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip2?: components["schemas"]["ClipField"];
};
/**
- * SDXL Main Model Loader
+ * SDXL Main Model
* @description Loads an sdxl base model, outputting its submodels.
*/
SDXLModelLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default sdxl_model_loader
+ * Type
+ * @default sdxl_model_loader
* @enum {string}
*/
type: "sdxl_model_loader";
/**
- * Model
+ * Model
* @description SDXL Main model (UNet, VAE, CLIP1, CLIP2) to load
*/
model: components["schemas"]["MainModelField"];
};
/**
- * SDXLModelLoaderOutput
+ * SDXLModelLoaderOutput
* @description SDXL base model loader output
*/
SDXLModelLoaderOutput: {
/**
- * Type
- * @default sdxl_model_loader_output
+ * Type
+ * @default sdxl_model_loader_output
* @enum {string}
*/
- type?: "sdxl_model_loader_output";
+ type: "sdxl_model_loader_output";
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet: components["schemas"]["UNetField"];
/**
- * CLIP 1
+ * CLIP 1
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip: components["schemas"]["ClipField"];
/**
- * CLIP 2
+ * CLIP 2
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip2: components["schemas"]["ClipField"];
/**
- * VAE
+ * VAE
* @description VAE
*/
vae: components["schemas"]["VaeField"];
};
/**
- * SDXL Refiner Compel Prompt
+ * SDXL Refiner Compel Prompt
* @description Parse prompt using compel package to conditioning.
*/
SDXLRefinerCompelPromptInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default sdxl_refiner_compel_prompt
+ * Type
+ * @default sdxl_refiner_compel_prompt
* @enum {string}
*/
type: "sdxl_refiner_compel_prompt";
/**
- * Style
- * @description Prompt to be parsed by Compel to create a conditioning tensor
+ * Style
+ * @description Prompt to be parsed by Compel to create a conditioning tensor
* @default
*/
style?: string;
/**
- * Original Width
+ * Original Width
* @default 1024
*/
original_width?: number;
/**
- * Original Height
+ * Original Height
* @default 1024
*/
original_height?: number;
/**
- * Crop Top
+ * Crop Top
* @default 0
*/
crop_top?: number;
/**
- * Crop Left
+ * Crop Left
* @default 0
*/
crop_left?: number;
/**
- * Aesthetic Score
- * @description The aesthetic score to apply to the conditioning tensor
+ * Aesthetic Score
+ * @description The aesthetic score to apply to the conditioning tensor
* @default 6
*/
aesthetic_score?: number;
/**
- * Clip2
+ * Clip2
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip2?: components["schemas"]["ClipField"];
};
/**
- * SDXL Refiner Model Loader
+ * SDXL Refiner Model
* @description Loads an sdxl refiner model, outputting its submodels.
*/
SDXLRefinerModelLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default sdxl_refiner_model_loader
+ * Type
+ * @default sdxl_refiner_model_loader
* @enum {string}
*/
type: "sdxl_refiner_model_loader";
/**
- * Model
+ * Model
* @description SDXL Refiner Main Modde (UNet, VAE, CLIP2) to load
*/
model: components["schemas"]["MainModelField"];
};
/**
- * SDXLRefinerModelLoaderOutput
+ * SDXLRefinerModelLoaderOutput
* @description SDXL refiner model loader output
*/
SDXLRefinerModelLoaderOutput: {
/**
- * Type
- * @default sdxl_refiner_model_loader_output
+ * Type
+ * @default sdxl_refiner_model_loader_output
* @enum {string}
*/
- type?: "sdxl_refiner_model_loader_output";
+ type: "sdxl_refiner_model_loader_output";
/**
- * UNet
+ * UNet
* @description UNet (scheduler, LoRAs)
*/
unet: components["schemas"]["UNetField"];
/**
- * CLIP 2
+ * CLIP 2
* @description CLIP (tokenizer, text encoder, LoRAs) and skipped layer count
*/
clip2: components["schemas"]["ClipField"];
/**
- * VAE
+ * VAE
* @description VAE
*/
vae: components["schemas"]["VaeField"];
};
/**
- * Scale Latents
+ * Scale Latents
* @description Scales latents by a given factor.
*/
ScaleLatentsInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default lscale
+ * Type
+ * @default lscale
* @enum {string}
*/
type: "lscale";
/**
- * Latents
+ * Latents
* @description Latents tensor
*/
latents?: components["schemas"]["LatentsField"];
/**
- * Scale Factor
+ * Scale Factor
* @description The factor by which to scale
*/
scale_factor?: number;
/**
- * Mode
- * @description Interpolation mode
- * @default bilinear
+ * Mode
+ * @description Interpolation mode
+ * @default bilinear
* @enum {string}
*/
mode?: "nearest" | "linear" | "bilinear" | "bicubic" | "trilinear" | "area" | "nearest-exact";
/**
- * Antialias
- * @description Whether or not to apply antialiasing (bilinear or bicubic only)
+ * Antialias
+ * @description Whether or not to apply antialiasing (bilinear or bicubic only)
* @default false
*/
antialias?: boolean;
};
/**
- * SchedulerPredictionType
- * @description An enumeration.
+ * SchedulerPredictionType
+ * @description An enumeration.
* @enum {string}
*/
SchedulerPredictionType: "epsilon" | "v_prediction" | "sample";
/**
- * Segment Anything Processor
+ * Segment Anything Processor
* @description Applies segment anything processing to image
*/
SegmentAnythingProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default segment_anything_processor
+ * Type
+ * @default segment_anything_processor
* @enum {string}
*/
type: "segment_anything_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
};
/**
- * Show Image
+ * Show Image
* @description Displays a provided image, and passes it forward in the pipeline.
*/
ShowImageInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default show_image
+ * Type
+ * @default show_image
* @enum {string}
*/
type: "show_image";
/**
- * Image
+ * Image
* @description The image to show
*/
image?: components["schemas"]["ImageField"];
@@ -5559,7 +5681,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "main";
@@ -5568,7 +5690,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "checkpoint";
@@ -5585,7 +5707,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "main";
@@ -5594,7 +5716,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "diffusers";
@@ -5609,7 +5731,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "main";
@@ -5618,7 +5740,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "checkpoint";
@@ -5635,7 +5757,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "main";
@@ -5644,7 +5766,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "diffusers";
@@ -5659,7 +5781,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "main";
@@ -5668,7 +5790,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "checkpoint";
@@ -5685,7 +5807,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "main";
@@ -5694,7 +5816,7 @@ export type components = {
/** Description */
description?: string;
/**
- * Model Format
+ * Model Format
* @enum {string}
*/
model_format: "diffusers";
@@ -5704,216 +5826,215 @@ export type components = {
variant: components["schemas"]["ModelVariantType"];
};
/**
- * Step Param Easing
+ * Step Param Easing
* @description Experimental per-step parameter easing for denoising steps
*/
StepParamEasingInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default step_param_easing
+ * Type
+ * @default step_param_easing
* @enum {string}
*/
type: "step_param_easing";
/**
- * Easing
- * @description The easing function to use
- * @default Linear
+ * Easing
+ * @description The easing function to use
+ * @default Linear
* @enum {string}
*/
easing?: "Linear" | "QuadIn" | "QuadOut" | "QuadInOut" | "CubicIn" | "CubicOut" | "CubicInOut" | "QuarticIn" | "QuarticOut" | "QuarticInOut" | "QuinticIn" | "QuinticOut" | "QuinticInOut" | "SineIn" | "SineOut" | "SineInOut" | "CircularIn" | "CircularOut" | "CircularInOut" | "ExponentialIn" | "ExponentialOut" | "ExponentialInOut" | "ElasticIn" | "ElasticOut" | "ElasticInOut" | "BackIn" | "BackOut" | "BackInOut" | "BounceIn" | "BounceOut" | "BounceInOut";
/**
- * Num Steps
- * @description number of denoising steps
+ * Num Steps
+ * @description number of denoising steps
* @default 20
*/
num_steps?: number;
/**
- * Start Value
- * @description easing starting value
+ * Start Value
+ * @description easing starting value
* @default 0
*/
start_value?: number;
/**
- * End Value
- * @description easing ending value
+ * End Value
+ * @description easing ending value
* @default 1
*/
end_value?: number;
/**
- * Start Step Percent
- * @description fraction of steps at which to start easing
+ * Start Step Percent
+ * @description fraction of steps at which to start easing
* @default 0
*/
start_step_percent?: number;
/**
- * End Step Percent
- * @description fraction of steps after which to end easing
+ * End Step Percent
+ * @description fraction of steps after which to end easing
* @default 1
*/
end_step_percent?: number;
/**
- * Pre Start Value
+ * Pre Start Value
* @description value before easing start
*/
pre_start_value?: number;
/**
- * Post End Value
+ * Post End Value
* @description value after easing end
*/
post_end_value?: number;
/**
- * Mirror
- * @description include mirror of easing function
+ * Mirror
+ * @description include mirror of easing function
* @default false
*/
mirror?: boolean;
/**
- * Show Easing Plot
- * @description show easing plot
+ * Show Easing Plot
+ * @description show easing plot
* @default false
*/
show_easing_plot?: boolean;
};
/**
- * String Primitive Collection
+ * String Primitive Collection
* @description A collection of string primitive values
*/
StringCollectionInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default string_collection
+ * Type
+ * @default string_collection
* @enum {string}
*/
type: "string_collection";
/**
- * Collection
- * @description The collection of string values
- * @default 0
+ * Collection
+ * @description The collection of string values
*/
- collection?: (string)[];
+ collection?: string[];
};
/**
- * StringCollectionOutput
+ * StringCollectionOutput
* @description Base class for nodes that output a collection of strings
*/
StringCollectionOutput: {
/**
- * Type
- * @default string_collection_output
+ * Type
+ * @default string_collection_output
* @enum {string}
*/
- type?: "string_collection_output";
+ type: "string_collection_output";
/**
- * Collection
+ * Collection
* @description The output strings
*/
- collection?: (string)[];
+ collection: string[];
};
/**
- * String Primitive
+ * String Primitive
* @description A string primitive value
*/
StringInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default string
+ * Type
+ * @default string
* @enum {string}
*/
type: "string";
/**
- * Text
- * @description The string value
+ * Value
+ * @description The string value
* @default
*/
- text?: string;
+ value?: string;
};
/**
- * StringOutput
+ * StringOutput
* @description Base class for nodes that output a single string
*/
StringOutput: {
/**
- * Type
- * @default string_output
+ * Type
+ * @default string_output
* @enum {string}
*/
- type?: "string_output";
+ type: "string_output";
/**
- * Text
+ * Value
* @description The output string
*/
- text: string;
+ value: string;
};
/**
- * SubModelType
- * @description An enumeration.
+ * SubModelType
+ * @description An enumeration.
* @enum {string}
*/
SubModelType: "unet" | "text_encoder" | "text_encoder_2" | "tokenizer" | "tokenizer_2" | "vae" | "vae_decoder" | "vae_encoder" | "scheduler" | "safety_checker";
/**
- * Subtract Integers
+ * Subtract Integers
* @description Subtracts two numbers
*/
SubtractInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default sub
+ * Type
+ * @default sub
* @enum {string}
*/
type: "sub";
/**
- * A
- * @description The first number
+ * A
+ * @description The first number
* @default 0
*/
a?: number;
/**
- * B
- * @description The second number
+ * B
+ * @description The second number
* @default 0
*/
b?: number;
@@ -5924,7 +6045,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "embedding";
@@ -5937,35 +6058,35 @@ export type components = {
error?: components["schemas"]["ModelError"];
};
/**
- * Tile Resample Processor
+ * Tile Resample Processor
* @description Tile resampler processor
*/
TileResamplerProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default tile_image_processor
+ * Type
+ * @default tile_image_processor
* @enum {string}
*/
type: "tile_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
/**
- * Down Sampling Rate
- * @description Down sampling rate
+ * Down Sampling Rate
+ * @description Down sampling rate
* @default 1
*/
down_sampling_rate?: number;
@@ -5973,41 +6094,41 @@ export type components = {
/** UNetField */
UNetField: {
/**
- * Unet
+ * Unet
* @description Info to load unet submodel
*/
unet: components["schemas"]["ModelInfo"];
/**
- * Scheduler
+ * Scheduler
* @description Info to load scheduler submodel
*/
scheduler: components["schemas"]["ModelInfo"];
/**
- * Loras
+ * Loras
* @description Loras to apply on model loading
*/
- loras: (components["schemas"]["LoraInfo"])[];
+ loras: components["schemas"]["LoraInfo"][];
};
/** Upscaler */
Upscaler: {
/**
- * Upscaling Method
+ * Upscaling Method
* @description Name of upscaling method
*/
upscaling_method: string;
/**
- * Upscaling Models
+ * Upscaling Models
* @description List of upscaling models for this method
*/
- upscaling_models: (string)[];
+ upscaling_models: string[];
};
/**
- * VAEModelField
+ * VAEModelField
* @description Vae model field
*/
VAEModelField: {
/**
- * Model Name
+ * Model Name
* @description Name of the model
*/
model_name: string;
@@ -6017,52 +6138,52 @@ export type components = {
/** VaeField */
VaeField: {
/**
- * Vae
+ * Vae
* @description Info to load vae submodel
*/
vae: components["schemas"]["ModelInfo"];
};
/**
- * VAE Loader
+ * VAE
* @description Loads a VAE model, outputting a VaeLoaderOutput
*/
VaeLoaderInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default vae_loader
+ * Type
+ * @default vae_loader
* @enum {string}
*/
type: "vae_loader";
/**
- * VAE
+ * VAE
* @description VAE model to load
*/
vae_model: components["schemas"]["VAEModelField"];
};
/**
- * VaeLoaderOutput
+ * VaeLoaderOutput
* @description Model loader output
*/
VaeLoaderOutput: {
/**
- * Type
- * @default vae_loader_output
+ * Type
+ * @default vae_loader_output
* @enum {string}
*/
- type?: "vae_loader_output";
+ type: "vae_loader_output";
/**
- * VAE
+ * VAE
* @description VAE
*/
vae: components["schemas"]["VaeField"];
@@ -6073,7 +6194,7 @@ export type components = {
model_name: string;
base_model: components["schemas"]["BaseModelType"];
/**
- * Model Type
+ * Model Type
* @enum {string}
*/
model_type: "vae";
@@ -6085,8 +6206,8 @@ export type components = {
error?: components["schemas"]["ModelError"];
};
/**
- * VaeModelFormat
- * @description An enumeration.
+ * VaeModelFormat
+ * @description An enumeration.
* @enum {string}
*/
VaeModelFormat: "checkpoint" | "diffusers";
@@ -6100,75 +6221,75 @@ export type components = {
type: string;
};
/**
- * Zoe (Depth) Processor
+ * Zoe (Depth) Processor
* @description Applies Zoe depth processing to image
*/
ZoeDepthImageProcessorInvocation: {
/**
- * Id
+ * Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
- * Is Intermediate
- * @description Whether or not this node is an intermediate node.
+ * Is Intermediate
+ * @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
- * Type
- * @default zoe_depth_image_processor
+ * Type
+ * @default zoe_depth_image_processor
* @enum {string}
*/
type: "zoe_depth_image_processor";
/**
- * Image
+ * Image
* @description The image to process
*/
image?: components["schemas"]["ImageField"];
};
/**
- * UIConfigBase
+ * UIConfigBase
* @description Provides additional node configuration to the UI.
* This is used internally by the @tags and @title decorator logic. You probably want to use those
* decorators, though you may add this class to a node definition to specify the title and tags.
*/
UIConfigBase: {
/**
- * Tags
+ * Tags
* @description The tags to display in the UI
*/
- tags?: (string)[];
+ tags?: string[];
/**
- * Title
+ * Title
* @description The display name of the node
*/
title?: string;
};
/**
- * Input
+ * Input
* @description The type of input a field accepts.
* - `Input.Direct`: The field must have its value provided directly, when the invocation and field are instantiated.
* - `Input.Connection`: The field must have its value provided by a connection.
- * - `Input.Any`: The field may have its value provided either directly or by a connection.
+ * - `Input.Any`: The field may have its value provided either directly or by a connection.
* @enum {string}
*/
Input: "connection" | "direct" | "any";
/**
- * UIType
+ * UIType
* @description Type hints for the UI.
- * If a field should be provided a data type that does not exactly match the python type of the field, use this to provide the type that should be used instead. See the node development docs for detail on adding a new field type, which involves client-side changes.
+ * If a field should be provided a data type that does not exactly match the python type of the field, use this to provide the type that should be used instead. See the node development docs for detail on adding a new field type, which involves client-side changes.
* @enum {string}
*/
- UIType: "integer" | "float" | "boolean" | "string" | "array" | "ImageField" | "LatentsField" | "ConditioningField" | "ControlField" | "ColorField" | "ImageCollection" | "ConditioningCollection" | "ColorCollection" | "LatentsCollection" | "IntegerCollection" | "FloatCollection" | "StringCollection" | "BooleanCollection" | "MainModelField" | "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VaeModelField" | "LoRAModelField" | "ControlNetModelField" | "UNetField" | "VaeField" | "ClipField" | "Collection" | "CollectionItem" | "FilePath" | "enum";
+ UIType: "integer" | "float" | "boolean" | "string" | "array" | "ImageField" | "LatentsField" | "ConditioningField" | "ControlField" | "ColorField" | "ImageCollection" | "ConditioningCollection" | "ColorCollection" | "LatentsCollection" | "IntegerCollection" | "FloatCollection" | "StringCollection" | "BooleanCollection" | "MainModelField" | "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VaeModelField" | "LoRAModelField" | "ControlNetModelField" | "UNetField" | "VaeField" | "ClipField" | "Collection" | "CollectionItem" | "FilePath" | "enum" | "Scheduler";
/**
- * UIComponent
- * @description The type of UI component to use for a field, used to override the default components, which are inferred from the field type.
+ * UIComponent
+ * @description The type of UI component to use for a field, used to override the default components, which are inferred from the field type.
* @enum {string}
*/
UIComponent: "none" | "textarea" | "slider";
/**
- * _InputField
+ * _InputField
* @description *DO NOT USE*
* This helper class is used to tell the client about our custom field attributes via OpenAPI
* schema generation, and Typescript type generation from that schema. It serves no functional
@@ -6180,9 +6301,11 @@ export type components = {
ui_hidden: boolean;
ui_type?: components["schemas"]["UIType"];
ui_component?: components["schemas"]["UIComponent"];
+ /** Ui Order */
+ ui_order?: number;
};
/**
- * _OutputField
+ * _OutputField
* @description *DO NOT USE*
* This helper class is used to tell the client about our custom field attributes via OpenAPI
* schema generation, and Typescript type generation from that schema. It serves no functional
@@ -6192,37 +6315,39 @@ export type components = {
/** Ui Hidden */
ui_hidden: boolean;
ui_type?: components["schemas"]["UIType"];
+ /** Ui Order */
+ ui_order?: number;
};
/**
- * StableDiffusionOnnxModelFormat
- * @description An enumeration.
- * @enum {string}
- */
- StableDiffusionOnnxModelFormat: "olive" | "onnx";
- /**
- * StableDiffusion1ModelFormat
- * @description An enumeration.
- * @enum {string}
- */
- StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
- /**
- * ControlNetModelFormat
- * @description An enumeration.
+ * ControlNetModelFormat
+ * @description An enumeration.
* @enum {string}
*/
ControlNetModelFormat: "checkpoint" | "diffusers";
/**
- * StableDiffusion2ModelFormat
- * @description An enumeration.
+ * StableDiffusion1ModelFormat
+ * @description An enumeration.
* @enum {string}
*/
- StableDiffusion2ModelFormat: "checkpoint" | "diffusers";
+ StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
/**
- * StableDiffusionXLModelFormat
- * @description An enumeration.
+ * StableDiffusionOnnxModelFormat
+ * @description An enumeration.
+ * @enum {string}
+ */
+ StableDiffusionOnnxModelFormat: "olive" | "onnx";
+ /**
+ * StableDiffusionXLModelFormat
+ * @description An enumeration.
* @enum {string}
*/
StableDiffusionXLModelFormat: "checkpoint" | "diffusers";
+ /**
+ * StableDiffusion2ModelFormat
+ * @description An enumeration.
+ * @enum {string}
+ */
+ StableDiffusion2ModelFormat: "checkpoint" | "diffusers";
};
responses: never;
parameters: never;
@@ -6231,12 +6356,14 @@ export type components = {
pathItems: never;
};
+export type $defs = Record;
+
export type external = Record;
export type operations = {
/**
- * List Sessions
+ * List Sessions
* @description Gets a list of sessions, optionally searching
*/
list_sessions: {
@@ -6266,7 +6393,7 @@ export type operations = {
};
};
/**
- * Create Session
+ * Create Session
* @description Creates a new session, optionally initializing it with an invocation graph
*/
create_session: {
@@ -6283,7 +6410,9 @@ export type operations = {
};
};
/** @description Invalid json */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6293,7 +6422,7 @@ export type operations = {
};
};
/**
- * Get Session
+ * Get Session
* @description Gets a session
*/
get_session: {
@@ -6311,7 +6440,9 @@ export type operations = {
};
};
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6321,7 +6452,7 @@ export type operations = {
};
};
/**
- * Add Node
+ * Add Node
* @description Adds a node to the graph
*/
add_node: {
@@ -6333,7 +6464,7 @@ export type operations = {
};
requestBody: {
content: {
- "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"];
+ "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"];
};
};
responses: {
@@ -6344,9 +6475,13 @@ export type operations = {
};
};
/** @description Invalid node or link */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6356,7 +6491,7 @@ export type operations = {
};
};
/**
- * Update Node
+ * Update Node
* @description Updates a node in the graph and removes all linked edges
*/
update_node: {
@@ -6370,7 +6505,7 @@ export type operations = {
};
requestBody: {
content: {
- "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"];
+ "application/json": components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageLuminosityAdjustmentInvocation"] | components["schemas"]["ImageSaturationAdjustmentInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"];
};
};
responses: {
@@ -6381,9 +6516,13 @@ export type operations = {
};
};
/** @description Invalid node or link */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6393,7 +6532,7 @@ export type operations = {
};
};
/**
- * Delete Node
+ * Delete Node
* @description Deletes a node in the graph and removes all linked edges
*/
delete_node: {
@@ -6413,9 +6552,13 @@ export type operations = {
};
};
/** @description Invalid node or link */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6425,7 +6568,7 @@ export type operations = {
};
};
/**
- * Add Edge
+ * Add Edge
* @description Adds an edge to the graph
*/
add_edge: {
@@ -6448,9 +6591,13 @@ export type operations = {
};
};
/** @description Invalid node or link */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6460,7 +6607,7 @@ export type operations = {
};
};
/**
- * Delete Edge
+ * Delete Edge
* @description Deletes an edge from the graph
*/
delete_edge: {
@@ -6486,9 +6633,13 @@ export type operations = {
};
};
/** @description Invalid node or link */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6498,7 +6649,7 @@ export type operations = {
};
};
/**
- * Invoke Session
+ * Invoke Session
* @description Invokes a session
*/
invoke_session: {
@@ -6520,11 +6671,17 @@ export type operations = {
};
};
/** @description The invocation is queued */
- 202: never;
+ 202: {
+ content: never;
+ };
/** @description The session has no invocations ready to invoke */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Session not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6534,7 +6691,7 @@ export type operations = {
};
};
/**
- * Cancel Session Invoke
+ * Cancel Session Invoke
* @description Invokes a session
*/
cancel_session_invoke: {
@@ -6552,7 +6709,9 @@ export type operations = {
};
};
/** @description The invocation is canceled */
- 202: never;
+ 202: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6562,14 +6721,14 @@ export type operations = {
};
};
/**
- * List Models
+ * List Models
* @description Gets a list of models
*/
list_models: {
parameters: {
query?: {
/** @description Base models to include */
- base_models?: (components["schemas"]["BaseModelType"])[];
+ base_models?: components["schemas"]["BaseModelType"][];
/** @description The type of model to get */
model_type?: components["schemas"]["ModelType"];
};
@@ -6590,7 +6749,7 @@ export type operations = {
};
};
/**
- * Delete Model
+ * Delete Model
* @description Delete Model
*/
del_model: {
@@ -6606,9 +6765,13 @@ export type operations = {
};
responses: {
/** @description Model deleted successfully */
- 204: never;
+ 204: {
+ content: never;
+ };
/** @description Model not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6618,7 +6781,7 @@ export type operations = {
};
};
/**
- * Update Model
+ * Update Model
* @description Update model contents with a new config. If the model name or base fields are changed, then the model is renamed.
*/
update_model: {
@@ -6645,11 +6808,17 @@ export type operations = {
};
};
/** @description Bad request */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description The model could not be found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description There is already a model corresponding to the new name */
- 409: never;
+ 409: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6659,7 +6828,7 @@ export type operations = {
};
};
/**
- * Import Model
+ * Import Model
* @description Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically
*/
import_model: {
@@ -6676,11 +6845,17 @@ export type operations = {
};
};
/** @description The model could not be found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description There is already a model corresponding to this path or repo_id */
- 409: never;
+ 409: {
+ content: never;
+ };
/** @description Unrecognized file/folder format */
- 415: never;
+ 415: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6688,11 +6863,13 @@ export type operations = {
};
};
/** @description The model appeared to import successfully, but could not be found in the model manager */
- 424: never;
+ 424: {
+ content: never;
+ };
};
};
/**
- * Add Model
+ * Add Model
* @description Add a model using the configuration information appropriate for its type. Only local models can be added by path
*/
add_model: {
@@ -6709,9 +6886,13 @@ export type operations = {
};
};
/** @description The model could not be found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description There is already a model corresponding to this path or repo_id */
- 409: never;
+ 409: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6719,11 +6900,13 @@ export type operations = {
};
};
/** @description The model appeared to add successfully, but could not be found in the model manager */
- 424: never;
+ 424: {
+ content: never;
+ };
};
};
/**
- * Convert Model
+ * Convert Model
* @description Convert a checkpoint model into a diffusers model, optionally saving to the indicated destination directory, or `models` if none.
*/
convert_model: {
@@ -6749,9 +6932,13 @@ export type operations = {
};
};
/** @description Bad request */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description Model not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6772,11 +6959,13 @@ export type operations = {
/** @description Directory searched successfully */
200: {
content: {
- "application/json": (string)[];
+ "application/json": string[];
};
};
/** @description Invalid directory path */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6786,7 +6975,7 @@ export type operations = {
};
};
/**
- * List Ckpt Configs
+ * List Ckpt Configs
* @description Return a list of the legacy checkpoint configuration files stored in `ROOT/configs/stable-diffusion`, relative to ROOT.
*/
list_ckpt_configs: {
@@ -6794,13 +6983,13 @@ export type operations = {
/** @description paths retrieved successfully */
200: {
content: {
- "application/json": (string)[];
+ "application/json": string[];
};
};
};
};
/**
- * Sync To Config
+ * Sync To Config
* @description Call after making changes to models.yaml, autoimport directories or models directory to synchronize
* in-memory data structures with disk data structures.
*/
@@ -6815,7 +7004,7 @@ export type operations = {
};
};
/**
- * Merge Models
+ * Merge Models
* @description Convert a checkpoint model into a diffusers model
*/
merge_models: {
@@ -6838,9 +7027,13 @@ export type operations = {
};
};
/** @description Incompatible models */
- 400: never;
+ 400: {
+ content: never;
+ };
/** @description One or more models not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6850,7 +7043,7 @@ export type operations = {
};
};
/**
- * Upload Image
+ * Upload Image
* @description Uploads an image
*/
upload_image: {
@@ -6881,7 +7074,9 @@ export type operations = {
};
};
/** @description Image upload failed */
- 415: never;
+ 415: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -6891,7 +7086,7 @@ export type operations = {
};
};
/**
- * Get Image Dto
+ * Get Image Dto
* @description Gets an image's DTO
*/
get_image_dto: {
@@ -6917,7 +7112,7 @@ export type operations = {
};
};
/**
- * Delete Image
+ * Delete Image
* @description Deletes an image
*/
delete_image: {
@@ -6943,7 +7138,7 @@ export type operations = {
};
};
/**
- * Update Image
+ * Update Image
* @description Updates an image
*/
update_image: {
@@ -6974,7 +7169,7 @@ export type operations = {
};
};
/**
- * Clear Intermediates
+ * Clear Intermediates
* @description Clears all intermediates
*/
clear_intermediates: {
@@ -6988,7 +7183,7 @@ export type operations = {
};
};
/**
- * Get Image Metadata
+ * Get Image Metadata
* @description Gets an image's metadata
*/
get_image_metadata: {
@@ -7014,7 +7209,7 @@ export type operations = {
};
};
/**
- * Get Image Full
+ * Get Image Full
* @description Gets a full-resolution image file
*/
get_image_full: {
@@ -7032,7 +7227,9 @@ export type operations = {
};
};
/** @description Image not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -7042,7 +7239,7 @@ export type operations = {
};
};
/**
- * Get Image Thumbnail
+ * Get Image Thumbnail
* @description Gets a thumbnail image file
*/
get_image_thumbnail: {
@@ -7060,7 +7257,9 @@ export type operations = {
};
};
/** @description Image not found */
- 404: never;
+ 404: {
+ content: never;
+ };
/** @description Validation Error */
422: {
content: {
@@ -7070,7 +7269,7 @@ export type operations = {
};
};
/**
- * Get Image Urls
+ * Get Image Urls
* @description Gets an image and thumbnail URL
*/
get_image_urls: {
@@ -7096,7 +7295,7 @@ export type operations = {
};
};
/**
- * List Image Dtos
+ * List Image Dtos
* @description Gets a list of image DTOs
*/
list_image_dtos: {
@@ -7105,7 +7304,7 @@ export type operations = {
/** @description The origin of images to list. */
image_origin?: components["schemas"]["ResourceOrigin"];
/** @description The categories of image to include. */
- categories?: (components["schemas"]["ImageCategory"])[];
+ categories?: components["schemas"]["ImageCategory"][];
/** @description Whether to list intermediate images. */
is_intermediate?: boolean;
/** @description The board id to filter by. Use 'none' to find images without a board. */
@@ -7198,7 +7397,7 @@ export type operations = {
};
};
/**
- * List Boards
+ * List Boards
* @description Gets a list of boards
*/
list_boards: {
@@ -7216,7 +7415,7 @@ export type operations = {
/** @description Successful Response */
200: {
content: {
- "application/json": components["schemas"]["OffsetPaginatedResults_BoardDTO_"] | (components["schemas"]["BoardDTO"])[];
+ "application/json": components["schemas"]["OffsetPaginatedResults_BoardDTO_"] | components["schemas"]["BoardDTO"][];
};
};
/** @description Validation Error */
@@ -7228,7 +7427,7 @@ export type operations = {
};
};
/**
- * Create Board
+ * Create Board
* @description Creates a board
*/
create_board: {
@@ -7254,7 +7453,7 @@ export type operations = {
};
};
/**
- * Get Board
+ * Get Board
* @description Gets a board
*/
get_board: {
@@ -7280,7 +7479,7 @@ export type operations = {
};
};
/**
- * Delete Board
+ * Delete Board
* @description Deletes a board
*/
delete_board: {
@@ -7310,7 +7509,7 @@ export type operations = {
};
};
/**
- * Update Board
+ * Update Board
* @description Updates a board
*/
update_board: {
@@ -7341,7 +7540,7 @@ export type operations = {
};
};
/**
- * List All Board Image Names
+ * List All Board Image Names
* @description Gets a list of images for a board
*/
list_all_board_image_names: {
@@ -7355,7 +7554,7 @@ export type operations = {
/** @description Successful Response */
200: {
content: {
- "application/json": (string)[];
+ "application/json": string[];
};
};
/** @description Validation Error */
@@ -7367,7 +7566,7 @@ export type operations = {
};
};
/**
- * Add Image To Board
+ * Add Image To Board
* @description Creates a board_image
*/
add_image_to_board: {
@@ -7392,7 +7591,7 @@ export type operations = {
};
};
/**
- * Remove Image From Board
+ * Remove Image From Board
* @description Removes an image from its board, if it had one
*/
remove_image_from_board: {
@@ -7417,7 +7616,7 @@ export type operations = {
};
};
/**
- * Add Images To Board
+ * Add Images To Board
* @description Adds a list of images to a board
*/
add_images_to_board: {
@@ -7442,7 +7641,7 @@ export type operations = {
};
};
/**
- * Remove Images From Board
+ * Remove Images From Board
* @description Removes a list of images from their board, if they had one
*/
remove_images_from_board: {
@@ -7489,7 +7688,7 @@ export type operations = {
};
};
/**
- * Get Log Level
+ * Get Log Level
* @description Returns the log level
*/
get_log_level: {
@@ -7503,7 +7702,7 @@ export type operations = {
};
};
/**
- * Set Log Level
+ * Set Log Level
* @description Sets the log verbosity level
*/
set_log_level: {
diff --git a/invokeai/frontend/web/src/services/api/thunks/session.ts b/invokeai/frontend/web/src/services/api/thunks/session.ts
index 29b032d1c3..32c612bbc2 100644
--- a/invokeai/frontend/web/src/services/api/thunks/session.ts
+++ b/invokeai/frontend/web/src/services/api/thunks/session.ts
@@ -30,8 +30,8 @@ export const sessionCreated = createAsyncThunk<
CreateSessionThunkConfig
>('api/sessionCreated', async (arg, { rejectWithValue }) => {
const { graph } = arg;
- const { post } = $client.get();
- const { data, error, response } = await post('/api/v1/sessions/', {
+ const { POST } = $client.get();
+ const { data, error, response } = await POST('/api/v1/sessions/', {
body: graph,
});
@@ -72,8 +72,8 @@ export const sessionInvoked = createAsyncThunk<
InvokedSessionThunkConfig
>('api/sessionInvoked', async (arg, { rejectWithValue }) => {
const { session_id } = arg;
- const { put } = $client.get();
- const { data, error, response } = await put(
+ const { PUT } = $client.get();
+ const { data, error, response } = await PUT(
'/api/v1/sessions/{session_id}/invoke',
{
params: { query: { all: true }, path: { session_id } },
@@ -92,11 +92,12 @@ export const sessionInvoked = createAsyncThunk<
return rejectWithValue({
arg,
status: response.status,
- error: error.detail
+ error: error.detail,
});
}
- if (error)
+ if (error) {
return rejectWithValue({ arg, status: response.status, error });
+ }
}
});
@@ -122,8 +123,8 @@ export const sessionCanceled = createAsyncThunk<
CancelSessionThunkConfig
>('api/sessionCanceled', async (arg, { rejectWithValue }) => {
const { session_id } = arg;
- const { del } = $client.get();
- const { data, error, response } = await del(
+ const { DELETE } = $client.get();
+ const { data, error, response } = await DELETE(
'/api/v1/sessions/{session_id}/invoke',
{
params: {
@@ -162,8 +163,8 @@ export const listedSessions = createAsyncThunk<
ListSessionsThunkConfig
>('api/listSessions', async (arg, { rejectWithValue }) => {
const { params } = arg;
- const { get } = $client.get();
- const { data, error, response } = await get('/api/v1/sessions/', {
+ const { GET } = $client.get();
+ const { data, error, response } = await GET('/api/v1/sessions/', {
params,
});
diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts
index f230354312..4e30794a51 100644
--- a/invokeai/frontend/web/src/services/api/types.ts
+++ b/invokeai/frontend/web/src/services/api/types.ts
@@ -155,6 +155,9 @@ export type ZoeDepthImageProcessorInvocation =
// Node Outputs
export type ImageOutput = s['ImageOutput'];
+export type StringOutput = s['StringOutput'];
+export type FloatOutput = s['FloatOutput'];
+export type IntegerOutput = s['IntegerOutput'];
export type IterateInvocationOutput = s['IterateInvocationOutput'];
export type CollectInvocationOutput = s['CollectInvocationOutput'];
export type LatentsOutput = s['LatentsOutput'];
diff --git a/invokeai/frontend/web/src/theme/components/button.ts b/invokeai/frontend/web/src/theme/components/button.ts
index c01d564494..056f3c145d 100644
--- a/invokeai/frontend/web/src/theme/components/button.ts
+++ b/invokeai/frontend/web/src/theme/components/button.ts
@@ -8,7 +8,16 @@ const invokeAI = defineStyle((props) => {
if (c === 'base') {
const _disabled = {
bg: mode('base.150', 'base.700')(props),
- color: mode('base.500', 'base.500')(props),
+ color: mode('base.300', 'base.500')(props),
+ svg: {
+ fill: mode('base.500', 'base.500')(props),
+ },
+ opacity: 1,
+ };
+
+ const data_progress = {
+ bg: 'none',
+ color: mode('base.300', 'base.500')(props),
svg: {
fill: mode('base.500', 'base.500')(props),
},
@@ -31,6 +40,7 @@ const invokeAI = defineStyle((props) => {
_disabled,
},
_disabled,
+ '&[data-progress="true"]': { ...data_progress, _hover: data_progress },
};
}
@@ -45,6 +55,17 @@ const invokeAI = defineStyle((props) => {
filter: mode(undefined, 'saturate(65%)')(props),
};
+ const data_progress = {
+ // bg: 'none',
+ color: mode(`${c}.50`, `${c}.500`)(props),
+ svg: {
+ fill: mode(`${c}.50`, `${c}.500`)(props),
+ filter: 'unset',
+ },
+ opacity: 0.7,
+ filter: mode(undefined, 'saturate(65%)')(props),
+ };
+
return {
bg: mode(`${c}.400`, `${c}.600`)(props),
color: mode(`base.50`, `base.100`)(props),
@@ -61,6 +82,7 @@ const invokeAI = defineStyle((props) => {
},
_disabled,
},
+ '&[data-progress="true"]': { ...data_progress, _hover: data_progress },
};
});
diff --git a/invokeai/frontend/web/src/theme/components/progress.ts b/invokeai/frontend/web/src/theme/components/progress.ts
index 71231869ce..a2aebc8fb1 100644
--- a/invokeai/frontend/web/src/theme/components/progress.ts
+++ b/invokeai/frontend/web/src/theme/components/progress.ts
@@ -9,7 +9,7 @@ const { defineMultiStyleConfig, definePartsStyle } =
createMultiStyleConfigHelpers(parts.keys);
const invokeAIFilledTrack = defineStyle((_props) => ({
- bg: 'accentAlpha.500',
+ bg: 'accentAlpha.700',
}));
const invokeAITrack = defineStyle((_props) => {
diff --git a/invokeai/frontend/web/src/theme/components/slider.ts b/invokeai/frontend/web/src/theme/components/slider.ts
index 98a2556b9e..6392da6cc1 100644
--- a/invokeai/frontend/web/src/theme/components/slider.ts
+++ b/invokeai/frontend/web/src/theme/components/slider.ts
@@ -22,8 +22,8 @@ const invokeAIFilledTrack = defineStyle((props) => {
const invokeAIThumb = defineStyle((props) => {
return {
- w: 2,
- h: 4,
+ w: props.orientation === 'horizontal' ? 2 : 4,
+ h: props.orientation === 'horizontal' ? 4 : 2,
bg: mode('base.50', 'base.100')(props),
};
});
diff --git a/invokeai/frontend/web/src/theme/theme.ts b/invokeai/frontend/web/src/theme/theme.ts
index f602fcef1c..039f4c928c 100644
--- a/invokeai/frontend/web/src/theme/theme.ts
+++ b/invokeai/frontend/web/src/theme/theme.ts
@@ -45,6 +45,11 @@ export const theme: ThemeOverride = {
color: 'base.900',
'.chakra-ui-dark &': { bg: 'base.800', color: 'base.100' },
},
+ third: {
+ bg: 'base.300',
+ color: 'base.900',
+ '.chakra-ui-dark &': { bg: 'base.750', color: 'base.100' },
+ },
nodeBody: {
bg: 'base.100',
color: 'base.900',
@@ -53,12 +58,12 @@ export const theme: ThemeOverride = {
nodeHeader: {
bg: 'base.200',
color: 'base.900',
- '.chakra-ui-dark &': { bg: 'base.700', color: 'base.100' },
+ '.chakra-ui-dark &': { bg: 'base.900', color: 'base.100' },
},
nodeFooter: {
bg: 'base.200',
color: 'base.900',
- '.chakra-ui-dark &': { bg: 'base.700', color: 'base.100' },
+ '.chakra-ui-dark &': { bg: 'base.900', color: 'base.100' },
},
},
styles: {
@@ -102,10 +107,15 @@ export const theme: ThemeOverride = {
'0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 3px var(--invokeai-colors-accent-500)',
dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 3px var(--invokeai-colors-accent-400)',
},
- nodeSelectedOutline: {
+ nodeSelected: {
light: `0 0 0 2px var(--invokeai-colors-accent-400)`,
dark: `0 0 0 2px var(--invokeai-colors-accent-500)`,
},
+ nodeInProgress: {
+ light:
+ '0 0 0 2px var(--invokeai-colors-accent-500), 0 0 10px 2px var(--invokeai-colors-accent-600)',
+ dark: '0 0 0 2px var(--invokeai-colors-yellow-400), 0 0 20px 2px var(--invokeai-colors-orange-700)',
+ },
},
colors: InvokeAIColors,
components: {
diff --git a/invokeai/frontend/web/yarn.lock b/invokeai/frontend/web/yarn.lock
index 834e6368c4..6d0e19fffc 100644
--- a/invokeai/frontend/web/yarn.lock
+++ b/invokeai/frontend/web/yarn.lock
@@ -7,16 +7,6 @@
resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
-"@apidevtools/json-schema-ref-parser@9.0.9":
- version "9.0.9"
- resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b"
- integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==
- dependencies:
- "@jsdevtools/ono" "^7.1.3"
- "@types/json-schema" "^7.0.6"
- call-me-maybe "^1.0.1"
- js-yaml "^4.1.0"
-
"@babel/code-frame@^7.0.0":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658"
@@ -55,7 +45,12 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae"
integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.9.2":
+"@babel/parser@^7.21.3":
+ version "7.22.10"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55"
+ integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==
+
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.9.2":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438"
integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==
@@ -275,13 +270,6 @@
compute-scroll-into-view "1.0.20"
copy-to-clipboard "3.3.3"
-"@chakra-ui/icon@3.0.16":
- version "3.0.16"
- resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.0.16.tgz#6413ec637c0c3acc204301485f05451b5bcd6ba4"
- integrity sha512-RpA1X5Ptz8Mt39HSyEIW1wxAz2AXyf9H0JJ5HVx/dBdMZaGMDJ0HyyPBVci0m4RCoJuyG1HHG/DXJaVfUTVAeg==
- dependencies:
- "@chakra-ui/shared-utils" "2.0.5"
-
"@chakra-ui/icon@3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.1.0.tgz#48312c071b3a0ed20ce807c8bd24d5f3e9cfdb7f"
@@ -289,12 +277,12 @@
dependencies:
"@chakra-ui/shared-utils" "2.0.5"
-"@chakra-ui/icons@^2.0.19":
- version "2.0.19"
- resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.0.19.tgz#b4581a59c2e2a2b95b01ab251eabb8cf984bb00f"
- integrity sha512-0A6U1ZBZhLIxh3QgdjuvIEhAZi3B9v8g6Qvlfa3mu6vSnXQn2CHBZXmJwxpXxO40NK/2gj/gKXrLeUaFR6H/Qw==
+"@chakra-ui/icons@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.1.0.tgz#52677939e02f9d6b902bd2c2931e5f18d3c8b523"
+ integrity sha512-pGFxFfQ/P5VnSRnTzK8zGAJxoxkxpHo/Br9ohRZdOpuhnIHSW7va0P53UoycEO5/vNJ/7BN0oDY0k9qurChcew==
dependencies:
- "@chakra-ui/icon" "3.0.16"
+ "@chakra-ui/icon" "3.1.0"
"@chakra-ui/image@2.1.0":
version "2.1.0"
@@ -1287,22 +1275,22 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.14.tgz#43f66032e0f189b6f394d4dbc903a188bb0c969f"
integrity sha512-K0QjGbcskx+gY+qp3v4/940qg8JitpXbdxFhRDA1aYoNaPff88+aEwoq45aqJ+ogpxQxmU0ZTjgnrQD/w8iiUg==
-"@eslint-community/eslint-utils@^4.2.0":
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
-"@eslint-community/regexpp@^4.4.0":
- version "4.5.1"
- resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884"
- integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==
+"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.7.0.tgz#96e7c05e738327602ae5942437f9c6b177ec279a"
+ integrity sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA==
-"@eslint/eslintrc@^2.1.0":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.0.tgz#82256f164cc9e0b59669efc19d57f8092706841d"
- integrity sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==
+"@eslint/eslintrc@^2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396"
+ integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
@@ -1314,10 +1302,15 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@8.44.0":
- version "8.44.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.44.0.tgz#961a5903c74139390478bdc808bcde3fc45ab7af"
- integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==
+"@eslint/js@^8.47.0":
+ version "8.47.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d"
+ integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==
+
+"@fastify/deepmerge@^1.0.0":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@fastify/deepmerge/-/deepmerge-1.3.0.tgz#8116858108f0c7d9fd460d05a7d637a13fe3239a"
+ integrity sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==
"@floating-ui/core@^1.3.1":
version "1.3.1"
@@ -1354,15 +1347,15 @@
aria-hidden "^1.1.3"
tabbable "^6.0.1"
-"@fontsource-variable/inter@^5.0.3":
- version "5.0.5"
- resolved "https://registry.yarnpkg.com/@fontsource-variable/inter/-/inter-5.0.5.tgz#a03cf816dc1f0df24f61b30f5936bcc99e0aad03"
- integrity sha512-hmj/jffr+1tabEPmvm+/b89MtbO6hd5PVbQ6HoMGTO7RMF5eD2C9UcprCgZTOF3OWh5uC21C9HZGN0O9wxe+UQ==
+"@fontsource-variable/inter@^5.0.8":
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/@fontsource-variable/inter/-/inter-5.0.8.tgz#bd6d61ece1019c59b0ac330a138d48a34dfa6d8c"
+ integrity sha512-WkYfFNccmEIeL2fNg0mYeLWqOoB7xD8MFxFRc4IwbSP2o8ZaBt36v5aW4by4MyrgGRMNk7uNi5LbvYKq6clPjw==
-"@fontsource/inter@^5.0.3":
- version "5.0.5"
- resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.5.tgz#bd3e923660cc4632d09b1882d104b0cb9430dec6"
- integrity sha512-RE1JmWRB6Kxo+1nXUnORSSH5uKgUZ2QEQE+h/nsNt758C+17G9y26E9QiAsIqsG13NpKhwn22EeECfyC+da5ew==
+"@fontsource/inter@^5.0.8":
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.8.tgz#61b50cb0eb72b14ae1938d47c4a9a91546d2a50c"
+ integrity sha512-28knWH1BfOiRalfLs90U4sge5mpQ8ZH6FS0PTT+IZMKrZ7wNHDHRuKa1kQJg+uHcc6axBppnxll+HXM4c7zo/Q==
"@humanwhocodes/config-array@^0.11.10":
version "0.11.10"
@@ -1383,118 +1376,68 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
-"@jridgewell/gen-mapping@^0.3.0":
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
- integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
- dependencies:
- "@jridgewell/set-array" "^1.0.1"
- "@jridgewell/sourcemap-codec" "^1.4.10"
- "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/resolve-uri@3.1.0":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
- integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
-
-"@jridgewell/set-array@^1.0.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
- integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-
-"@jridgewell/source-map@^0.3.3":
- version "0.3.5"
- resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91"
- integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==
- dependencies:
- "@jridgewell/gen-mapping" "^0.3.0"
- "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/sourcemap-codec@1.4.14":
- version "1.4.14"
- resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
- integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
-
-"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13":
- version "1.4.15"
- resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
- integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
-
-"@jridgewell/trace-mapping@^0.3.9":
- version "0.3.18"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6"
- integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==
- dependencies:
- "@jridgewell/resolve-uri" "3.1.0"
- "@jridgewell/sourcemap-codec" "1.4.14"
-
-"@jsdevtools/ono@^7.1.3":
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
- integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
-
-"@mantine/core@^6.0.14":
- version "6.0.17"
- resolved "https://registry.yarnpkg.com/@mantine/core/-/core-6.0.17.tgz#734b31c79199a9cf2bfb0bbd7482f5c2c411ff9a"
- integrity sha512-g3EDxcTJKisvEGTsGJPCGXiDumwr4O0nGNXwoGLnrg19nh3FAMfEIq18sJJLtRrBuarSbrvgMVYvKx1R6rTOWg==
+"@mantine/core@^6.0.19":
+ version "6.0.19"
+ resolved "https://registry.yarnpkg.com/@mantine/core/-/core-6.0.19.tgz#612413f0e8eb117e6a39068a625c6ccf2ae2ccdd"
+ integrity sha512-SvMZCOgCc315SIg6hkuLM0ZnBaAac4VFDHZ0BM5LIE4MPJUpe4QOLsg/5RGxOa5s7JRCtu/dawH3/9frvfDrhw==
dependencies:
"@floating-ui/react" "^0.19.1"
- "@mantine/styles" "6.0.17"
- "@mantine/utils" "6.0.17"
+ "@mantine/styles" "6.0.19"
+ "@mantine/utils" "6.0.19"
"@radix-ui/react-scroll-area" "1.0.2"
react-remove-scroll "^2.5.5"
react-textarea-autosize "8.3.4"
-"@mantine/form@^6.0.15":
- version "6.0.17"
- resolved "https://registry.yarnpkg.com/@mantine/form/-/form-6.0.17.tgz#ab4fe22ea83976a3e621f0fcc2d36eae19f37141"
- integrity sha512-hrWlBukErklaFSvKfz4PCl3Cd7UgHf5Q/FyZPD+WvBDT0zZ5uMjatQpVs/HAfhFOA5O2DFKAcs654mLzmJJ6Wg==
+"@mantine/form@^6.0.19":
+ version "6.0.19"
+ resolved "https://registry.yarnpkg.com/@mantine/form/-/form-6.0.19.tgz#3d97f08a45b1a8bc8840dbf77defd267abb20e39"
+ integrity sha512-5SFLZEzaBH7yKIDSDt1r9UiN4y7RkFvu+7J7CFPIQM+nTdXeGnugVFM8rASuZI7/FSYty/XoPY+Yymq3xDX+MQ==
dependencies:
fast-deep-equal "^3.1.3"
klona "^2.0.5"
-"@mantine/hooks@^6.0.14":
- version "6.0.17"
- resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.17.tgz#dc942c87e6dcfa14a70e4e4a162c22eeb4ff3724"
- integrity sha512-7vf2w1NlzKlUynSuyI2DAIKoEOYKYC8k+tlSsk3BRdbzhbJAiWxcYzJy5seg5dFW1WIpKAZ0wiVdHXf/WRlRgg==
+"@mantine/hooks@^6.0.19":
+ version "6.0.19"
+ resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-6.0.19.tgz#39f61434304f687d3ba7bf0040c5adf380c7c4b3"
+ integrity sha512-YkmuB6kmoenU1PVuE8tLBA+6RJIY9hIsGyIQG1yuPAy6SLWNFT8g2T9YvI/psqsUbVIYGaNEXg8zq42xbxnD8Q==
-"@mantine/styles@6.0.17":
- version "6.0.17"
- resolved "https://registry.yarnpkg.com/@mantine/styles/-/styles-6.0.17.tgz#fef8a64f0e32b970c397e1c22dceb6ab09fb090f"
- integrity sha512-utNwQJgKHguNS0iPyyeFRJy4nbt280XMbmfUf4GCxXlyl/mQxq+JoaKP/OmU7+8kfbtLS9kHeuBSghrC65Nt1g==
+"@mantine/styles@6.0.19":
+ version "6.0.19"
+ resolved "https://registry.yarnpkg.com/@mantine/styles/-/styles-6.0.19.tgz#7d9a6f2c2a9b345dfd9d12f8fd66af3976d67ab2"
+ integrity sha512-0tg3Dvv/kxCc1mbQVFhZaIhlSbSbV1F/3xG0NRlP2DF23mw9088o5KaIXGKM6XkXU6OEt/f99nDCUHBk2ixtUg==
dependencies:
clsx "1.1.1"
csstype "3.0.9"
-"@mantine/utils@6.0.17":
- version "6.0.17"
- resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.17.tgz#7d4a6c7686a3ee19a0ac248ef14780f00730837b"
- integrity sha512-U6SWV/asYE6NhiHx4ltmVZdQR3HwGVqJxVulhOylMcV1tX/P1LMQUCbGV2Oe4O9jbX4/YW5B/CBb4BbEhENQFQ==
+"@mantine/utils@6.0.19":
+ version "6.0.19"
+ resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.19.tgz#0197fccc5649259787d5468228139f8815909803"
+ integrity sha512-duvtnaW1gDR2gnvUqnWhl6DMW7sN0HEWqS8Z/BbwaMi75U+Xp17Q72R9JtiIrxQbzsq+KvH9L9B/pxMVwbLirg==
-"@microsoft/api-extractor-model@7.27.4":
- version "7.27.4"
- resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.27.4.tgz#ddc566ead99737c1032d692829edd954870f7d35"
- integrity sha512-HjqQFmuGPOS20rtnu+9Jj0QrqZyR59E+piUWXPMZTTn4jaZI+4UmsHSf3Id8vyueAhOBH2cgwBuRTE5R+MfSMw==
+"@microsoft/api-extractor-model@7.27.6":
+ version "7.27.6"
+ resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.27.6.tgz#308e44cd595d2fb446c6357759ee0675ec37d26e"
+ integrity sha512-eiCnlayyum1f7fS2nA9pfIod5VCNR1G+Tq84V/ijDrKrOFVa598BLw145nCsGDMoFenV6ajNi2PR5WCwpAxW6Q==
dependencies:
"@microsoft/tsdoc" "0.14.2"
"@microsoft/tsdoc-config" "~0.16.1"
- "@rushstack/node-core-library" "3.59.5"
+ "@rushstack/node-core-library" "3.59.7"
-"@microsoft/api-extractor@^7.34.4":
- version "7.36.2"
- resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.36.2.tgz#8f7696fcc3c9c0c43469e6f59c56349bc1631193"
- integrity sha512-ONe/jOmTZtR3OjTkWKHmeSV1P5ozbHDxHr6FV3KoWyIl1AcPk2B3dmvVBM5eOlZB5bgM66nxcWQTZ6msQo2hHg==
+"@microsoft/api-extractor@^7.36.3":
+ version "7.36.4"
+ resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.36.4.tgz#3bb9fbbbeacaa48eea49150351905a2677a506d9"
+ integrity sha512-21UECq8C/8CpHT23yiqTBQ10egKUacIpxkPyYR7hdswo/M5yTWdBvbq+77YC9uPKQJOUfOD1FImBQ1DzpsdeQQ==
dependencies:
- "@microsoft/api-extractor-model" "7.27.4"
+ "@microsoft/api-extractor-model" "7.27.6"
"@microsoft/tsdoc" "0.14.2"
"@microsoft/tsdoc-config" "~0.16.1"
- "@rushstack/node-core-library" "3.59.5"
- "@rushstack/rig-package" "0.4.0"
- "@rushstack/ts-command-line" "4.15.1"
+ "@rushstack/node-core-library" "3.59.7"
+ "@rushstack/rig-package" "0.4.1"
+ "@rushstack/ts-command-line" "4.15.2"
colors "~1.2.1"
lodash "~4.17.15"
resolve "~1.22.1"
- semver "~7.3.0"
+ semver "~7.5.4"
source-map "~0.6.1"
typescript "~5.0.4"
@@ -1539,6 +1482,18 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@pkgr/utils@^2.3.1":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc"
+ integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==
+ dependencies:
+ cross-spawn "^7.0.3"
+ fast-glob "^3.3.0"
+ is-glob "^4.0.3"
+ open "^9.1.0"
+ picocolors "^1.0.0"
+ tslib "^2.6.0"
+
"@popperjs/core@^2.9.3":
version "2.11.8"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
@@ -1634,28 +1589,28 @@
dependencies:
"@babel/runtime" "^7.13.10"
-"@reactflow/background@11.2.4":
- version "11.2.4"
- resolved "https://registry.yarnpkg.com/@reactflow/background/-/background-11.2.4.tgz#06cd4c9f222dbeb2d3ffb2a530b6d88bf130dd9c"
- integrity sha512-SYQbCRCU0GuxT/40Tm7ZK+l5wByGnNJSLtZhbL9C/Hl7JhsJXV3UGXr0vrlhVZUBEtkWA7XhZM/5S9XEA5XSFA==
+"@reactflow/background@11.2.8":
+ version "11.2.8"
+ resolved "https://registry.yarnpkg.com/@reactflow/background/-/background-11.2.8.tgz#aa83f87b7d65442b52732f0a04d9da981f978265"
+ integrity sha512-5o41N2LygiNC2/Pk8Ak2rIJjXbKHfQ23/Y9LFsnAlufqwdzFqKA8txExpsMoPVHHlbAdA/xpQaMuoChGPqmyDw==
dependencies:
- "@reactflow/core" "11.7.4"
+ "@reactflow/core" "11.8.3"
classcat "^5.0.3"
- zustand "^4.3.1"
+ zustand "^4.4.1"
-"@reactflow/controls@11.1.15":
- version "11.1.15"
- resolved "https://registry.yarnpkg.com/@reactflow/controls/-/controls-11.1.15.tgz#6dc823eb67f38a50907fffcc21b6a20e4fc00e7c"
- integrity sha512-//33XfBYu8vQ6brfmlZwKrDoh+8hh93xO2d88XiqfIbrPEEb32SYjsb9mS9VuHKNlSIW+eB27fBA1Gt00mEj5w==
+"@reactflow/controls@11.1.19":
+ version "11.1.19"
+ resolved "https://registry.yarnpkg.com/@reactflow/controls/-/controls-11.1.19.tgz#a8bc4b4eafc10d5d230db5286753e867bcf35e5b"
+ integrity sha512-Vo0LFfAYjiSRMLEII/aeBo+1MT2a0Yc7iLVnkuRTLzChC0EX+A2Fa+JlzeOEYKxXlN4qcDxckRNGR7092v1HOQ==
dependencies:
- "@reactflow/core" "11.7.4"
+ "@reactflow/core" "11.8.3"
classcat "^5.0.3"
- zustand "^4.3.1"
+ zustand "^4.4.1"
-"@reactflow/core@11.7.4", "@reactflow/core@^11.6.0":
- version "11.7.4"
- resolved "https://registry.yarnpkg.com/@reactflow/core/-/core-11.7.4.tgz#1a7e4d6cabbd2ea888547133d507f1ab24896520"
- integrity sha512-nt0T8ERp8TE7YCDQViaoEY9lb0StDPrWHVx3zBjhStFYET3wc88t8QRasZdf99xRTmyNtI3U3M40M5EBLNUpMw==
+"@reactflow/core@11.8.3":
+ version "11.8.3"
+ resolved "https://registry.yarnpkg.com/@reactflow/core/-/core-11.8.3.tgz#03ffeb06fbc141b8f786cb4ac8169f8a51a5f00e"
+ integrity sha512-y6DN8Wy4V4KQBGHFqlj9zWRjLJU6CgdnVwWaEA/PdDg/YUkFBMpZnXqTs60czinoA2rAcvsz50syLTPsj5e+Wg==
dependencies:
"@types/d3" "^7.4.0"
"@types/d3-drag" "^3.0.1"
@@ -1665,40 +1620,40 @@
d3-drag "^3.0.0"
d3-selection "^3.0.0"
d3-zoom "^3.0.0"
- zustand "^4.3.1"
+ zustand "^4.4.1"
-"@reactflow/minimap@11.5.4":
- version "11.5.4"
- resolved "https://registry.yarnpkg.com/@reactflow/minimap/-/minimap-11.5.4.tgz#b072094f7d827660f0205796d5f22fbbf6e31cc3"
- integrity sha512-1tDBj2zX2gxu2oHU6qvH5RGNrOWRfRxu8369KhDotuuBN5yJrGXJzWIKikwhzjsNsQJYOB+B0cS44yWAfwSwzw==
+"@reactflow/minimap@11.6.3":
+ version "11.6.3"
+ resolved "https://registry.yarnpkg.com/@reactflow/minimap/-/minimap-11.6.3.tgz#1cfddd87e9afd23ad704167988c66bd683ffc5d2"
+ integrity sha512-PSA28dk09RnBHOA1zb45fjQXz3UozSJZmsIpgq49O3trfVFlSgRapxNdGsughWLs7/emg2M5jmi6Vc+ejcfjvQ==
dependencies:
- "@reactflow/core" "11.7.4"
+ "@reactflow/core" "11.8.3"
"@types/d3-selection" "^3.0.3"
"@types/d3-zoom" "^3.0.1"
classcat "^5.0.3"
d3-selection "^3.0.0"
d3-zoom "^3.0.0"
- zustand "^4.3.1"
+ zustand "^4.4.1"
-"@reactflow/node-resizer@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@reactflow/node-resizer/-/node-resizer-2.1.1.tgz#8f9b4e362e572dcddb54d43a67b5c5919b25937f"
- integrity sha512-5Q+IBmZfpp/bYsw3+KRVJB1nUbj6W3XAp5ycx4uNWH+K98vbssymyQsW0vvKkIhxEPg6tkiMzO4UWRWvwBwt1g==
+"@reactflow/node-resizer@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@reactflow/node-resizer/-/node-resizer-2.1.5.tgz#f4033946ccc9cc8f47a94ed93f10a32befd546f1"
+ integrity sha512-z/hJlsptd2vTx13wKouqvN/Kln08qbkA+YTJLohc2aJ6rx3oGn9yX4E4IqNxhA7zNqYEdrnc1JTEA//ifh9z3w==
dependencies:
- "@reactflow/core" "^11.6.0"
+ "@reactflow/core" "11.8.3"
classcat "^5.0.4"
d3-drag "^3.0.0"
d3-selection "^3.0.0"
- zustand "^4.3.1"
+ zustand "^4.4.1"
-"@reactflow/node-toolbar@1.2.3":
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/@reactflow/node-toolbar/-/node-toolbar-1.2.3.tgz#8ff8408dffee7920752479cd19e7ab7c9c47b4d2"
- integrity sha512-uFQy9xpog92s0G1wsPLniwV9nyH4i/MmL7QoMsWdnKaOi7XMhd8SJcCzUdHC3imR21HltsuQITff/XQ51ApMbg==
+"@reactflow/node-toolbar@1.2.7":
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/@reactflow/node-toolbar/-/node-toolbar-1.2.7.tgz#cf6639945dc42b42416f293d6132e1187bca3424"
+ integrity sha512-vs+Wg1tjy3SuD7eoeTqEtscBfE9RY+APqC28urVvftkrtsN7KlnoQjqDG6aE45jWP4z+8bvFizRWjAhxysNLkg==
dependencies:
- "@reactflow/core" "11.7.4"
+ "@reactflow/core" "11.8.3"
classcat "^5.0.3"
- zustand "^4.3.1"
+ zustand "^4.4.1"
"@reduxjs/toolkit@^1.9.5":
version "1.9.5"
@@ -1736,31 +1691,31 @@
estree-walker "^2.0.2"
picomatch "^2.3.1"
-"@rushstack/node-core-library@3.59.5", "@rushstack/node-core-library@^3.55.2":
- version "3.59.5"
- resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.59.5.tgz#38034d4c38b5ddd7d1c7f04233ce1b2209b7ae1f"
- integrity sha512-1IpV7LufrI1EoVO8hYsb3t6L8L+yp40Sa0OaOV2CIu1zx4e6ZeVNaVIEXFgMXBKdGXkAh21MnCaIzlDNpG6ZQw==
+"@rushstack/node-core-library@3.59.7":
+ version "3.59.7"
+ resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.59.7.tgz#9dcd62b79263e8a5b68465d4bf9124ec86e14b6c"
+ integrity sha512-ln1Drq0h+Hwa1JVA65x5mlSgUrBa1uHL+V89FqVWQgXd1vVIMhrtqtWGQrhTnFHxru5ppX+FY39VWELF/FjQCw==
dependencies:
colors "~1.2.1"
fs-extra "~7.0.1"
import-lazy "~4.0.0"
jju "~1.4.0"
resolve "~1.22.1"
- semver "~7.3.0"
+ semver "~7.5.4"
z-schema "~5.0.2"
-"@rushstack/rig-package@0.4.0":
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.4.0.tgz#1dade94da5cd81321ca9ec630b6ceed2d57cc826"
- integrity sha512-FnM1TQLJYwSiurP6aYSnansprK5l8WUK8VG38CmAaZs29ZeL1msjK0AP1VS4ejD33G0kE/2cpsPsS9jDenBMxw==
+"@rushstack/rig-package@0.4.1":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.4.1.tgz#ff11bf67dad46f9b4f09db91cf45739ab411ee9f"
+ integrity sha512-AGRwpqlXNSp9LhUSz4HKI9xCluqQDt/obsQFdv/NYIekF3pTTPzc+HbQsIsjVjYnJ3DcmxOREVMhvrMEjpiq6g==
dependencies:
resolve "~1.22.1"
strip-json-comments "~3.1.1"
-"@rushstack/ts-command-line@4.15.1":
- version "4.15.1"
- resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.15.1.tgz#8f2ebde6bb19deb2c5b65363854b84aea1bf59f0"
- integrity sha512-EL4jxZe5fhb1uVL/P/wQO+Z8Rc8FMiWJ1G7VgnPDvdIt5GVjRfK7vwzder1CZQiX3x0PY6uxENYLNGTFd1InRQ==
+"@rushstack/ts-command-line@4.15.2":
+ version "4.15.2"
+ resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.15.2.tgz#7920e3fa2ab6af129d995ce4424c600da0bf8a93"
+ integrity sha512-5+C2uoJY8b+odcZD6coEe2XNC4ZjGB4vCMESbqW/8DHRWC/qIHfANdmN9F1wz/lAgxz72i7xRoVtPY2j7e4gpQ==
dependencies:
"@types/argparse" "1.0.38"
argparse "~1.0.9"
@@ -1838,16 +1793,6 @@
"@swc/core-win32-ia32-msvc" "1.3.70"
"@swc/core-win32-x64-msvc" "1.3.70"
-"@ts-morph/common@~0.19.0":
- version "0.19.0"
- resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.19.0.tgz#927fcd81d1bbc09c89c4a310a84577fb55f3694e"
- integrity sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ==
- dependencies:
- fast-glob "^3.2.12"
- minimatch "^7.4.3"
- mkdirp "^2.1.6"
- path-browserify "^1.0.1"
-
"@types/argparse@1.0.38":
version "1.0.38"
resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9"
@@ -2099,7 +2044,7 @@
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
-"@types/json-schema@*", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.9":
+"@types/json-schema@*", "@types/json-schema@^7.0.12":
version "7.0.12"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
@@ -2128,10 +2073,10 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632"
integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==
-"@types/node@^20.3.1":
- version "20.4.2"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.2.tgz#129cc9ae69f93824f92fac653eebfb4812ab4af9"
- integrity sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==
+"@types/node@^20.5.1":
+ version "20.5.1"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.1.tgz#178d58ee7e4834152b0e8b4d30cbfab578b9bb30"
+ integrity sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==
"@types/parse-json@^4.0.0":
version "4.0.0"
@@ -2174,7 +2119,7 @@
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@^18.2.14":
+"@types/react@*":
version "18.2.15"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.15.tgz#14792b35df676c20ec3cf595b262f8c615a73066"
integrity sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==
@@ -2183,12 +2128,21 @@
"@types/scheduler" "*"
csstype "^3.0.2"
+"@types/react@^18.2.20":
+ version "18.2.20"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2"
+ integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==
+ dependencies:
+ "@types/prop-types" "*"
+ "@types/scheduler" "*"
+ csstype "^3.0.2"
+
"@types/scheduler@*":
version "0.16.3"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
-"@types/semver@^7.3.12":
+"@types/semver@^7.5.0":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a"
integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
@@ -2203,49 +2157,51 @@
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b"
integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==
-"@typescript-eslint/eslint-plugin@^5.60.0":
- version "5.62.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db"
- integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
+"@typescript-eslint/eslint-plugin@^6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.1.tgz#bc0c6f000134b53c304ad0bec4ee4753cd3e89d2"
+ integrity sha512-3F5PtBzUW0dYlq77Lcqo13fv+58KDwUib3BddilE8ajPJT+faGgxmI9Sw+I8ZS22BYwoir9ZhNXcLi+S+I2bkw==
dependencies:
- "@eslint-community/regexpp" "^4.4.0"
- "@typescript-eslint/scope-manager" "5.62.0"
- "@typescript-eslint/type-utils" "5.62.0"
- "@typescript-eslint/utils" "5.62.0"
+ "@eslint-community/regexpp" "^4.5.1"
+ "@typescript-eslint/scope-manager" "6.4.1"
+ "@typescript-eslint/type-utils" "6.4.1"
+ "@typescript-eslint/utils" "6.4.1"
+ "@typescript-eslint/visitor-keys" "6.4.1"
debug "^4.3.4"
graphemer "^1.4.0"
- ignore "^5.2.0"
- natural-compare-lite "^1.4.0"
- semver "^7.3.7"
- tsutils "^3.21.0"
+ ignore "^5.2.4"
+ natural-compare "^1.4.0"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
-"@typescript-eslint/parser@^5.60.0":
- version "5.62.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7"
- integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
+"@typescript-eslint/parser@^6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.4.1.tgz#85ad550bf4ac4aa227504f1becb828f8e46c44e3"
+ integrity sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg==
dependencies:
- "@typescript-eslint/scope-manager" "5.62.0"
- "@typescript-eslint/types" "5.62.0"
- "@typescript-eslint/typescript-estree" "5.62.0"
+ "@typescript-eslint/scope-manager" "6.4.1"
+ "@typescript-eslint/types" "6.4.1"
+ "@typescript-eslint/typescript-estree" "6.4.1"
+ "@typescript-eslint/visitor-keys" "6.4.1"
debug "^4.3.4"
-"@typescript-eslint/scope-manager@5.62.0":
- version "5.62.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c"
- integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
+"@typescript-eslint/scope-manager@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.4.1.tgz#4b073a30be2dbe603e44e9ae0cff7e1d3ed19278"
+ integrity sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A==
dependencies:
- "@typescript-eslint/types" "5.62.0"
- "@typescript-eslint/visitor-keys" "5.62.0"
+ "@typescript-eslint/types" "6.4.1"
+ "@typescript-eslint/visitor-keys" "6.4.1"
-"@typescript-eslint/type-utils@5.62.0":
- version "5.62.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a"
- integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==
+"@typescript-eslint/type-utils@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.4.1.tgz#fa21cb13016c8d6f352fe9b2d6c9ab6edc2d1857"
+ integrity sha512-7ON8M8NXh73SGZ5XvIqWHjgX2f+vvaOarNliGhjrJnv1vdjG0LVIz+ToYfPirOoBi56jxAKLfsLm40+RvxVVXA==
dependencies:
- "@typescript-eslint/typescript-estree" "5.62.0"
- "@typescript-eslint/utils" "5.62.0"
+ "@typescript-eslint/typescript-estree" "6.4.1"
+ "@typescript-eslint/utils" "6.4.1"
debug "^4.3.4"
- tsutils "^3.21.0"
+ ts-api-utils "^1.0.1"
"@typescript-eslint/types@4.33.0":
version "4.33.0"
@@ -2257,18 +2213,23 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
-"@typescript-eslint/typescript-estree@5.62.0", "@typescript-eslint/typescript-estree@^5.55.0":
- version "5.62.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
- integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
+"@typescript-eslint/types@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.4.1.tgz#b2c61159f46dda210fed9f117f5d027f65bb5c3b"
+ integrity sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg==
+
+"@typescript-eslint/typescript-estree@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.1.tgz#91ff88101c710adb0f70a317f2f65efa9441da45"
+ integrity sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg==
dependencies:
- "@typescript-eslint/types" "5.62.0"
- "@typescript-eslint/visitor-keys" "5.62.0"
+ "@typescript-eslint/types" "6.4.1"
+ "@typescript-eslint/visitor-keys" "6.4.1"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
- semver "^7.3.7"
- tsutils "^3.21.0"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
"@typescript-eslint/typescript-estree@^4.33.0":
version "4.33.0"
@@ -2283,19 +2244,31 @@
semver "^7.3.5"
tsutils "^3.21.0"
-"@typescript-eslint/utils@5.62.0":
+"@typescript-eslint/typescript-estree@^5.55.0":
version "5.62.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
- integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
+ integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
dependencies:
- "@eslint-community/eslint-utils" "^4.2.0"
- "@types/json-schema" "^7.0.9"
- "@types/semver" "^7.3.12"
- "@typescript-eslint/scope-manager" "5.62.0"
"@typescript-eslint/types" "5.62.0"
- "@typescript-eslint/typescript-estree" "5.62.0"
- eslint-scope "^5.1.1"
+ "@typescript-eslint/visitor-keys" "5.62.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
semver "^7.3.7"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/utils@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.4.1.tgz#81bf62ff0c3119a26c19fab683582e29450717bc"
+ integrity sha512-F/6r2RieNeorU0zhqZNv89s9bDZSovv3bZQpUNOmmQK1L80/cV4KEu95YUJWi75u5PhboFoKUJBnZ4FQcoqhDw==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@types/json-schema" "^7.0.12"
+ "@types/semver" "^7.5.0"
+ "@typescript-eslint/scope-manager" "6.4.1"
+ "@typescript-eslint/types" "6.4.1"
+ "@typescript-eslint/typescript-estree" "6.4.1"
+ semver "^7.5.4"
"@typescript-eslint/visitor-keys@4.33.0":
version "4.33.0"
@@ -2313,6 +2286,14 @@
"@typescript-eslint/types" "5.62.0"
eslint-visitor-keys "^3.3.0"
+"@typescript-eslint/visitor-keys@6.4.1":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.1.tgz#e3ccf7b8d42e625946ac5094ed92a405fb4115e0"
+ integrity sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ==
+ dependencies:
+ "@typescript-eslint/types" "6.4.1"
+ eslint-visitor-keys "^3.4.1"
+
"@vitejs/plugin-react-swc@^3.3.2":
version "3.3.2"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.2.tgz#34a82c1728066f48a86dfecb2f15df60f89207fb"
@@ -2320,6 +2301,79 @@
dependencies:
"@swc/core" "^1.3.61"
+"@volar/language-core@1.10.1", "@volar/language-core@~1.10.0":
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-1.10.1.tgz#76789c5b0c214eeff8add29cbff0333d89b6fc4a"
+ integrity sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==
+ dependencies:
+ "@volar/source-map" "1.10.1"
+
+"@volar/source-map@1.10.1", "@volar/source-map@~1.10.0":
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-1.10.1.tgz#b806845782cc615f2beba94624ff34a700f302f5"
+ integrity sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==
+ dependencies:
+ muggle-string "^0.3.1"
+
+"@volar/typescript@~1.10.0":
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-1.10.1.tgz#b20341c1cc5785b4de0669ea645e1619c97a4764"
+ integrity sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==
+ dependencies:
+ "@volar/language-core" "1.10.1"
+
+"@vue/compiler-core@3.3.4":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128"
+ integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==
+ dependencies:
+ "@babel/parser" "^7.21.3"
+ "@vue/shared" "3.3.4"
+ estree-walker "^2.0.2"
+ source-map-js "^1.0.2"
+
+"@vue/compiler-dom@^3.3.0":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151"
+ integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==
+ dependencies:
+ "@vue/compiler-core" "3.3.4"
+ "@vue/shared" "3.3.4"
+
+"@vue/language-core@1.8.8", "@vue/language-core@^1.8.8":
+ version "1.8.8"
+ resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.8.tgz#5a8aa8363f4dfacdfcd7808a9926744d7c310ae6"
+ integrity sha512-i4KMTuPazf48yMdYoebTkgSOJdFraE4pQf0B+FTOFkbB+6hAfjrSou/UmYWRsWyZV6r4Rc6DDZdI39CJwL0rWw==
+ dependencies:
+ "@volar/language-core" "~1.10.0"
+ "@volar/source-map" "~1.10.0"
+ "@vue/compiler-dom" "^3.3.0"
+ "@vue/reactivity" "^3.3.0"
+ "@vue/shared" "^3.3.0"
+ minimatch "^9.0.0"
+ muggle-string "^0.3.1"
+ vue-template-compiler "^2.7.14"
+
+"@vue/reactivity@^3.3.0":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.3.4.tgz#a27a29c6cd17faba5a0e99fbb86ee951653e2253"
+ integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==
+ dependencies:
+ "@vue/shared" "3.3.4"
+
+"@vue/shared@3.3.4", "@vue/shared@^3.3.0":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780"
+ integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
+
+"@vue/typescript@1.8.8":
+ version "1.8.8"
+ resolved "https://registry.yarnpkg.com/@vue/typescript/-/typescript-1.8.8.tgz#8efb375d448862134492a044f4e96afada547500"
+ integrity sha512-jUnmMB6egu5wl342eaUH236v8tdcEPXXkPgj+eI/F6JwW/lb+yAU6U07ZbQ3MVabZRlupIlPESB7ajgAGixhow==
+ dependencies:
+ "@volar/typescript" "~1.10.0"
+ "@vue/language-core" "1.8.8"
+
"@xobotyi/scrollbar-width@^1.9.5":
version "1.9.5"
resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
@@ -2352,20 +2406,19 @@ acorn-jsx@^5.3.2:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-acorn@^8.8.2, acorn@^8.9.0:
+acorn@^8.9.0:
version "8.10.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
-aggregate-error@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
- integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
+ajv-formats@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+ integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
dependencies:
- clean-stack "^2.0.0"
- indent-string "^4.0.0"
+ ajv "^8.0.0"
-ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@~6.12.6:
+ajv@^6.12.4, ajv@~6.12.6:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -2375,17 +2428,27 @@ ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@~6.12.6:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+ajv@^8.0.0, ajv@^8.10.0:
+ version "8.12.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
+ integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.2.2"
+
ansi-colors@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
-ansi-escapes@^4.3.0:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
- integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ansi-escapes@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6"
+ integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==
dependencies:
- type-fest "^0.21.3"
+ type-fest "^1.0.2"
ansi-regex@^5.0.1:
version "5.0.1"
@@ -2411,7 +2474,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
-ansi-styles@^6.0.0:
+ansi-styles@^6.0.0, ansi-styles@^6.1.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
@@ -2535,10 +2598,12 @@ ast-module-types@^4.0.0:
resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-4.0.0.tgz#17e1cadd5b5b108e7295b0cf0cff21ccc226b639"
integrity sha512-Kd0o8r6CDazJGCRzs8Ivpn0xj19oNKrULhoJFzhGjRsLpekF2zyZs9Ukz+JvZhWD6smszfepakTFhAaYpsI12g==
-astral-regex@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
- integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
+asynciterator.prototype@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62"
+ integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==
+ dependencies:
+ has-symbols "^1.0.3"
asynckit@^0.4.0:
version "0.4.0"
@@ -2596,6 +2661,11 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+big-integer@^1.6.44:
+ version "1.6.51"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
+ integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
+
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
@@ -2615,6 +2685,13 @@ boolean@^3.1.4:
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b"
integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==
+bplist-parser@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
+ integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==
+ dependencies:
+ big-integer "^1.6.44"
+
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -2637,11 +2714,6 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
-buffer-from@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
- integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-
buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
@@ -2650,6 +2722,13 @@ buffer@^5.5.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"
+bundle-name@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a"
+ integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==
+ dependencies:
+ run-applescript "^5.0.0"
+
busboy@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
@@ -2665,30 +2744,15 @@ call-bind@^1.0.0, call-bind@^1.0.2:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
-call-me-maybe@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa"
- integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==
-
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-camelcase@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
- integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-
-chakra-ui-contextmenu@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/chakra-ui-contextmenu/-/chakra-ui-contextmenu-1.0.5.tgz#de54ad83c413a62040a06fefd3d73264a580a987"
- integrity sha512-0pvi2RmNFpaoXPBT8mRDBZ1q6Ic8lE7YIyHBMgx4AubgN7dySww4SlN9g3mKWN3egkBL/ORCmxRfW6AlDeR+Nw==
-
-chalk@5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3"
- integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==
+chalk@5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
+ integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
chalk@^2.0.0, chalk@^2.4.2:
version "2.4.2"
@@ -2740,11 +2804,6 @@ classcat@^5.0.3, classcat@^5.0.4:
resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.4.tgz#e12d1dfe6df6427f260f03b80dc63571a5107ba6"
integrity sha512-sbpkOw6z413p+HDGcBENe498WM9woqWHiJxCq7nvmxe9WmrUmqfAcxpIwAiMtM5Q3AhYkzXcNQHqsWq0mND51g==
-clean-stack@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
- integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
-
clear-any-console@^1.16.0:
version "1.16.2"
resolved "https://registry.yarnpkg.com/clear-any-console/-/clear-any-console-1.16.2.tgz#0543bb068da00151bf77b7a01ebf05d611086bb9"
@@ -2765,6 +2824,13 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
+cli-cursor@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea"
+ integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==
+ dependencies:
+ restore-cursor "^4.0.0"
+
cli-handle-error@^4.1.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/cli-handle-error/-/cli-handle-error-4.4.0.tgz#f65d7d66c3d648a063696b5c83f3b8cc850da25d"
@@ -2785,14 +2851,6 @@ cli-spinners@^2.5.0:
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db"
integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==
-cli-truncate@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
- integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
- dependencies:
- slice-ansi "^3.0.0"
- string-width "^4.2.0"
-
cli-truncate@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389"
@@ -2829,11 +2887,6 @@ clsx@1.1.1:
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
-code-block-writer@^12.0.0:
- version "12.0.0"
- resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770"
- integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==
-
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -2863,7 +2916,7 @@ color2k@^2.0.0:
resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.2.tgz#ac2b4aea11c822a6bcb70c768b5a289f4fffcebb"
integrity sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==
-colorette@^2.0.19:
+colorette@^2.0.20:
version "2.0.20"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
@@ -2880,12 +2933,17 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
+commander@11.0.0:
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67"
+ integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==
+
commander@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
-commander@^2.16.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@^2.8.1:
+commander@^2.16.0, commander@^2.19.0, commander@^2.20.3, commander@^2.8.1:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -2910,11 +2968,6 @@ compute-scroll-into-view@1.0.20:
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
-compute-scroll-into-view@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz#2b444b2b9e4724819d2531efacb7ac094155fdf6"
- integrity sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==
-
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -3080,7 +3133,12 @@ dateformat@^5.0.3:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-5.0.3.tgz#fe2223eff3cc70ce716931cb3038b59a9280696e"
integrity sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA==
-debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
+de-indent@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
+ integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
+
+debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -3107,10 +3165,23 @@ deepmerge@^2.1.1:
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
-deepmerge@^4.2.2:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
- integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+default-browser-id@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c"
+ integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==
+ dependencies:
+ bplist-parser "^0.2.0"
+ untildify "^4.0.0"
+
+default-browser@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da"
+ integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==
+ dependencies:
+ bundle-name "^3.0.0"
+ default-browser-id "^3.0.0"
+ execa "^7.1.1"
+ titleize "^3.0.0"
defaults@^1.0.3:
version "1.0.4"
@@ -3124,6 +3195,11 @@ define-lazy-prop@^2.0.0:
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
+define-lazy-prop@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
+ integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
+
define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5"
@@ -3324,17 +3400,6 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
-downshift@^7.6.0:
- version "7.6.2"
- resolved "https://registry.yarnpkg.com/downshift/-/downshift-7.6.2.tgz#16fc951b7ff8f9c1c47d0f71b5ff10d78fb06e4c"
- integrity sha512-iOv+E1Hyt3JDdL9yYcOgW7nZ7GQ2Uz6YbggwXvKUSleetYhU2nXD482Rz6CzvM4lvI1At34BYruKAL4swRGxaA==
- dependencies:
- "@babel/runtime" "^7.14.8"
- compute-scroll-into-view "^2.0.4"
- prop-types "^15.7.2"
- react-is "^17.0.2"
- tslib "^2.3.0"
-
eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
@@ -3350,21 +3415,21 @@ emoji-regex@^9.2.2:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
-engine.io-client@~6.5.1:
- version "6.5.1"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.1.tgz#1735fb8ae3bae5ae13115e18d2f484daf005dd9c"
- integrity sha512-hE5wKXH8Ru4L19MbM1GgYV/2Qo54JSMh1rlJbfpa40bEWkCKNo3ol2eOtGmowcr+ysgbI7+SGL+by42Q3pt/Ng==
+engine.io-client@~6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.2.tgz#8709e22c291d4297ae80318d3c8baeae71f0e002"
+ integrity sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
- engine.io-parser "~5.1.0"
+ engine.io-parser "~5.2.1"
ws "~8.11.0"
xmlhttprequest-ssl "~2.0.0"
-engine.io-parser@~5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.1.0.tgz#d593d6372d7f79212df48f807b8cace1ea1cb1b8"
- integrity sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==
+engine.io-parser@~5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.1.tgz#9f213c77512ff1a6cc0c7a86108a7ffceb16fcfb"
+ integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==
enhanced-resolve@^5.8.3:
version "5.15.0"
@@ -3388,7 +3453,7 @@ error-stack-parser@^2.0.6:
dependencies:
stackframe "^1.3.4"
-es-abstract@^1.19.0, es-abstract@^1.20.4:
+es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.3:
version "1.22.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc"
integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==
@@ -3433,6 +3498,26 @@ es-abstract@^1.19.0, es-abstract@^1.20.4:
unbox-primitive "^1.0.2"
which-typed-array "^1.1.10"
+es-iterator-helpers@^1.0.12:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.13.tgz#72101046ffc19baf9996adc70e6177a26e6e8084"
+ integrity sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA==
+ dependencies:
+ asynciterator.prototype "^1.0.0"
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ es-abstract "^1.21.3"
+ es-set-tostringtag "^2.0.1"
+ function-bind "^1.1.1"
+ get-intrinsic "^1.2.1"
+ globalthis "^1.0.3"
+ has-property-descriptors "^1.0.0"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.5"
+ iterator.prototype "^1.1.0"
+ safe-array-concat "^1.0.0"
+
es-set-tostringtag@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8"
@@ -3540,32 +3625,34 @@ escodegen@^2.0.0:
optionalDependencies:
source-map "~0.6.1"
-eslint-config-prettier@^8.8.0:
- version "8.8.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348"
- integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==
+eslint-config-prettier@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f"
+ integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==
-eslint-plugin-prettier@^4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
- integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
+eslint-plugin-prettier@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz#6887780ed95f7708340ec79acfdf60c35b9be57a"
+ integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==
dependencies:
prettier-linter-helpers "^1.0.0"
+ synckit "^0.8.5"
eslint-plugin-react-hooks@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
-eslint-plugin-react@^7.32.2:
- version "7.32.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10"
- integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==
+eslint-plugin-react@^7.33.2:
+ version "7.33.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608"
+ integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==
dependencies:
array-includes "^3.1.6"
array.prototype.flatmap "^1.3.1"
array.prototype.tosorted "^1.1.1"
doctrine "^2.1.0"
+ es-iterator-helpers "^1.0.12"
estraverse "^5.3.0"
jsx-ast-utils "^2.4.1 || ^3.0.0"
minimatch "^3.1.2"
@@ -3575,21 +3662,13 @@ eslint-plugin-react@^7.32.2:
object.values "^1.1.6"
prop-types "^15.8.1"
resolve "^2.0.0-next.4"
- semver "^6.3.0"
+ semver "^6.3.1"
string.prototype.matchall "^4.0.8"
-eslint-scope@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
- integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
- dependencies:
- esrecurse "^4.3.0"
- estraverse "^4.1.1"
-
-eslint-scope@^7.2.0:
- version "7.2.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.1.tgz#936821d3462675f25a18ac5fd88a67cc15b393bd"
- integrity sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==
+eslint-scope@^7.2.2:
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
@@ -3604,27 +3683,32 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
-eslint@^8.43.0:
- version "8.45.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.45.0.tgz#bab660f90d18e1364352c0a6b7c6db8edb458b78"
- integrity sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==
+eslint-visitor-keys@^3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+eslint@^8.47.0:
+ version "8.47.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806"
+ integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
- "@eslint-community/regexpp" "^4.4.0"
- "@eslint/eslintrc" "^2.1.0"
- "@eslint/js" "8.44.0"
+ "@eslint-community/regexpp" "^4.6.1"
+ "@eslint/eslintrc" "^2.1.2"
+ "@eslint/js" "^8.47.0"
"@humanwhocodes/config-array" "^0.11.10"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
- ajv "^6.10.0"
+ ajv "^6.12.4"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.3.2"
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
- eslint-scope "^7.2.0"
- eslint-visitor-keys "^3.4.1"
- espree "^9.6.0"
+ eslint-scope "^7.2.2"
+ eslint-visitor-keys "^3.4.3"
+ espree "^9.6.1"
esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
@@ -3647,7 +3731,7 @@ eslint@^8.43.0:
strip-ansi "^6.0.1"
text-table "^0.2.0"
-espree@^9.6.0:
+espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
@@ -3675,11 +3759,6 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
-estraverse@^4.1.1:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
- integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
-
estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
@@ -3695,10 +3774,15 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-execa@^7.0.0:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43"
- integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==
+eventemitter3@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
+ integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
+
+execa@7.2.0, execa@^7.1.1:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
+ integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.1"
@@ -3710,6 +3794,21 @@ execa@^7.0.0:
signal-exit "^3.0.7"
strip-final-newline "^3.0.0"
+execa@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -3720,7 +3819,7 @@ fast-diff@^1.1.2:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
-fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0:
+fast-glob@^3.2.9, fast-glob@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0"
integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==
@@ -3731,20 +3830,33 @@ fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0:
merge2 "^1.3.0"
micromatch "^4.0.4"
+fast-glob@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4"
+ integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
-fast-json-stringify@^2.7.10:
- version "2.7.13"
- resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz#277aa86c2acba4d9851bd6108ed657aa327ed8c0"
- integrity sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==
+fast-json-stringify@^5.8.0:
+ version "5.8.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-5.8.0.tgz#b229ed01ac5f92f3b82001a916c31324652f46d7"
+ integrity sha512-VVwK8CFMSALIvt14U8AvrSzQAwN/0vaVRiFFUVlpnXSnDGrSkOAO5MtzyN8oQNjLd5AqTW5OZRgyjoNuAuR3jQ==
dependencies:
- ajv "^6.11.0"
- deepmerge "^4.2.2"
+ "@fastify/deepmerge" "^1.0.0"
+ ajv "^8.10.0"
+ ajv-formats "^2.1.1"
+ fast-deep-equal "^3.1.3"
+ fast-uri "^2.1.0"
rfdc "^1.2.0"
- string-similarity "^4.0.1"
fast-levenshtein@^2.0.6:
version "2.0.6"
@@ -3768,6 +3880,11 @@ fast-shallow-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b"
integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==
+fast-uri@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-2.2.0.tgz#519a0f849bef714aad10e9753d69d8f758f7445a"
+ integrity sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==
+
fastest-stable-stringify@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76"
@@ -3891,10 +4008,10 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
-formik@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.2.tgz#a1115457cfb012a5c782cea3ad4b40b2fe36fa18"
- integrity sha512-C6nx0hifW2uENP3M6HpPmnAE6HFWCcd8/sqBZEOHZY6lpHJ5qehsfAy43ktpFLEmkBmhiZDei726utcUB9leqg==
+formik@^2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.3.tgz#6020e85eb3e3e8415b3b19d6f4f65793ab754b24"
+ integrity sha512-2Dy79Szw3zlXmZiokUdKsn+n1ow4G8hRrC/n92cOWHNTWXCRpQXlyvz6HcjW7aSQZrldytvDOavYjhfmDnUq8Q==
dependencies:
deepmerge "^2.1.1"
hoist-non-react-statics "^3.3.0"
@@ -3904,10 +4021,10 @@ formik@^2.4.2:
tiny-warning "^1.0.2"
tslib "^2.0.0"
-framer-motion@^10.12.17:
- version "10.12.22"
- resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-10.12.22.tgz#f1e7e36cc24fa5407ea33ccbd6d2996f50ceb503"
- integrity sha512-bBGYPOxvxcfzS7/py9MEqDucmXBkVl2g42HNlXXPieSTSGGkr8L7+MilCnrU6uX3HrNk/tcB++1SkWE8BosHFw==
+framer-motion@^10.16.1:
+ version "10.16.1"
+ resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-10.16.1.tgz#0ff5de554bbb35ee6605357d80f92b27d0271a94"
+ integrity sha512-K6TXr5mZtitC/dxQCBdg7xzdN0d5IAIrlaqCPKtIQVdzVPGC0qBuJKXggHX1vjnP5gPOFwB1KbCCTWcnFc3kWg==
dependencies:
tslib "^2.4.0"
optionalDependencies:
@@ -3920,24 +4037,6 @@ framesync@6.1.2:
dependencies:
tslib "2.4.0"
-fs-extra@^10.1.0:
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
- integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
- dependencies:
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^2.0.0"
-
-fs-extra@^11.1.1:
- version "11.1.1"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
- integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
- dependencies:
- graceful-fs "^4.2.0"
- jsonfile "^6.0.1"
- universalify "^2.0.0"
-
fs-extra@^9.0.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
@@ -4033,7 +4132,7 @@ get-own-enumerable-property-symbols@^3.0.0:
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
-get-stream@^6.0.1:
+get-stream@^6.0.0, get-stream@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
@@ -4127,18 +4226,6 @@ graphemer@^1.4.0:
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
-handlebars@^4.7.7:
- version "4.7.7"
- resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
- integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
- dependencies:
- minimist "^1.2.5"
- neo-async "^2.6.0"
- source-map "^0.6.1"
- wordwrap "^1.0.0"
- optionalDependencies:
- uglify-js "^3.1.4"
-
has-bigints@^1.0.1, has-bigints@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
@@ -4185,6 +4272,11 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
+he@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
@@ -4199,6 +4291,11 @@ html-parse-stringify@^3.0.1:
dependencies:
void-elements "3.1.0"
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
human-signals@^4.3.0:
version "4.3.1"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
@@ -4228,10 +4325,10 @@ i18next-http-backend@^2.2.1:
dependencies:
cross-fetch "3.1.6"
-i18next@^23.2.3:
- version "23.2.11"
- resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.2.11.tgz#0c6f3a637fa87d3243e64b78ad285b7f77d41353"
- integrity sha512-MA4FsxOjyCaOZtRDB4yuwjCvqYEioD4G4LlXOn7SO3rnQUlxTufyLsOqfL9MKakeLRBkefe8bqcs0D6Z/xFk1w==
+i18next@^23.4.4:
+ version "23.4.4"
+ resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.4.4.tgz#ec8fb2b5f3c5d8e3bf3f8ab1b19e743be91300e0"
+ integrity sha512-+c9B0txp/x1m5zn+QlwHaCS9vyFtmIAEXbVSFzwCX7vupm5V7va8F9cJGNJZ46X9ZtoGzhIiRC7eTIIh93TxPA==
dependencies:
"@babel/runtime" "^7.22.5"
@@ -4240,7 +4337,7 @@ ieee754@^1.1.13:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-ignore@^5.2.0:
+ignore@^5.2.0, ignore@^5.2.4:
version "5.2.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
@@ -4268,11 +4365,6 @@ imurmurhash@^0.1.4:
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@@ -4334,6 +4426,13 @@ is-arrayish@^0.2.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+is-async-function@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
+ integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
is-bigint@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
@@ -4368,7 +4467,7 @@ is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.9.0:
dependencies:
has "^1.0.3"
-is-date-object@^1.0.1:
+is-date-object@^1.0.1, is-date-object@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
@@ -4380,6 +4479,11 @@ is-docker@^2.0.0, is-docker@^2.1.1:
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+is-docker@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200"
+ integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==
+
is-extglob@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
@@ -4390,6 +4494,13 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+is-finalizationregistry@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6"
+ integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==
+ dependencies:
+ call-bind "^1.0.2"
+
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
@@ -4400,6 +4511,13 @@ is-fullwidth-code-point@^4.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88"
integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==
+is-generator-function@^1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
is-glob@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
@@ -4414,6 +4532,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
+is-inside-container@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4"
+ integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==
+ dependencies:
+ is-docker "^3.0.0"
+
is-interactive@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
@@ -4426,6 +4551,11 @@ is-invalid-path@^0.1.0:
dependencies:
is-glob "^2.0.0"
+is-map@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
+ integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==
+
is-negative-zero@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
@@ -4471,6 +4601,11 @@ is-relative-path@^1.0.2:
resolved "https://registry.yarnpkg.com/is-relative-path/-/is-relative-path-1.0.2.tgz#091b46a0d67c1ed0fe85f1f8cfdde006bb251d46"
integrity sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==
+is-set@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec"
+ integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==
+
is-shared-array-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
@@ -4478,6 +4613,11 @@ is-shared-array-buffer@^1.0.2:
dependencies:
call-bind "^1.0.2"
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
is-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
@@ -4526,6 +4666,11 @@ is-valid-path@^0.1.1:
dependencies:
is-invalid-path "^0.1.0"
+is-weakmap@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
+ integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
+
is-weakref@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
@@ -4533,6 +4678,14 @@ is-weakref@^1.0.2:
dependencies:
call-bind "^1.0.2"
+is-weakset@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d"
+ integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.1"
+
is-wsl@^2.1.1, is-wsl@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
@@ -4550,6 +4703,17 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+iterator.prototype@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.0.tgz#690c88b043d821f783843aaf725d7ac3b62e3b46"
+ integrity sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==
+ dependencies:
+ define-properties "^1.1.4"
+ get-intrinsic "^1.1.3"
+ has-symbols "^1.0.3"
+ has-tostringtag "^1.0.0"
+ reflect.getprototypeof "^1.0.3"
+
its-fine@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.1.1.tgz#e74b93fddd487441f978a50f64f0f5af4d2fc38e"
@@ -4584,23 +4748,28 @@ json-parse-even-better-errors@^2.3.0:
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-json-schema-ref-parser@^9.0.9:
- version "9.0.9"
- resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#66ea538e7450b12af342fa3d5b8458bc1e1e013f"
- integrity sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==
- dependencies:
- "@apidevtools/json-schema-ref-parser" "9.0.9"
-
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+json-stable-stringify@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0"
+ integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==
+ dependencies:
+ jsonify "^0.0.1"
+
json5@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
@@ -4624,6 +4793,11 @@ jsonfile@^6.0.1:
optionalDependencies:
graceful-fs "^4.1.6"
+jsonify@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978"
+ integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==
+
"jsx-ast-utils@^2.4.1 || ^3.0.0":
version "3.3.4"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz#b896535fed5b867650acce5a9bd4135ffc7b3bf9"
@@ -4646,7 +4820,7 @@ klona@^2.0.5:
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==
-kolorist@^1.7.0:
+kolorist@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c"
integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==
@@ -4674,24 +4848,21 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-lint-staged@^13.2.2:
- version "13.2.3"
- resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.3.tgz#f899aad6c093473467e9c9e316e3c2d8a28f87a7"
- integrity sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==
+lint-staged@^14.0.1:
+ version "14.0.1"
+ resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-14.0.1.tgz#57dfa3013a3d60762d9af5d9c83bdb51291a6232"
+ integrity sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==
dependencies:
- chalk "5.2.0"
- cli-truncate "^3.1.0"
- commander "^10.0.0"
- debug "^4.3.4"
- execa "^7.0.0"
+ chalk "5.3.0"
+ commander "11.0.0"
+ debug "4.3.4"
+ execa "7.2.0"
lilconfig "2.1.0"
- listr2 "^5.0.7"
- micromatch "^4.0.5"
- normalize-path "^3.0.0"
- object-inspect "^1.12.3"
- pidtree "^0.6.0"
- string-argv "^0.3.1"
- yaml "^2.2.2"
+ listr2 "6.6.1"
+ micromatch "4.0.5"
+ pidtree "0.6.0"
+ string-argv "0.3.2"
+ yaml "2.3.1"
liqe@^3.6.0:
version "3.6.1"
@@ -4701,19 +4872,17 @@ liqe@^3.6.0:
nearley "^2.20.1"
ts-error "^1.0.6"
-listr2@^5.0.7:
- version "5.0.8"
- resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23"
- integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==
+listr2@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/listr2/-/listr2-6.6.1.tgz#08b2329e7e8ba6298481464937099f4a2cd7f95d"
+ integrity sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==
dependencies:
- cli-truncate "^2.1.0"
- colorette "^2.0.19"
- log-update "^4.0.0"
- p-map "^4.0.0"
+ cli-truncate "^3.1.0"
+ colorette "^2.0.20"
+ eventemitter3 "^5.0.1"
+ log-update "^5.0.1"
rfdc "^1.3.0"
- rxjs "^7.8.0"
- through "^2.3.8"
- wrap-ansi "^7.0.0"
+ wrap-ansi "^8.1.0"
locate-path@^6.0.0:
version "6.0.0"
@@ -4767,15 +4936,16 @@ log-symbols@^4.1.0:
chalk "^4.1.0"
is-unicode-supported "^0.1.0"
-log-update@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
- integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==
+log-update@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09"
+ integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==
dependencies:
- ansi-escapes "^4.3.0"
- cli-cursor "^3.1.0"
- slice-ansi "^4.0.0"
- wrap-ansi "^6.2.0"
+ ansi-escapes "^5.0.0"
+ cli-cursor "^4.0.0"
+ slice-ansi "^5.0.0"
+ strip-ansi "^7.0.1"
+ wrap-ansi "^8.0.1"
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
@@ -4819,13 +4989,6 @@ madge@^6.1.0:
ts-graphviz "^1.5.0"
walkdir "^0.4.1"
-magic-string@^0.29.0:
- version "0.29.0"
- resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.29.0.tgz#f034f79f8c43dba4ae1730ffb5e8c4e084b16cf3"
- integrity sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==
- dependencies:
- "@jridgewell/sourcemap-codec" "^1.4.13"
-
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
@@ -4841,7 +5004,7 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
+micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
@@ -4878,10 +5041,10 @@ minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
-minimatch@^7.4.3:
- version "7.4.6"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb"
- integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==
+minimatch@^9.0.0:
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
+ integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
dependencies:
brace-expansion "^2.0.1"
@@ -4890,11 +5053,6 @@ minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
-mkdirp@^2.1.6:
- version "2.1.6"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
- integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
-
module-definition@^3.3.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-3.4.0.tgz#953a3861f65df5e43e80487df98bb35b70614c2b"
@@ -4932,6 +5090,11 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+muggle-string@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.3.1.tgz#e524312eb1728c63dd0b2ac49e3282e6ed85963a"
+ integrity sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==
+
nano-css@^5.3.1:
version "5.3.5"
resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.5.tgz#3075ea29ffdeb0c7cb6d25edb21d8f7fa8e8fe8e"
@@ -4956,11 +5119,6 @@ nanostores@^0.9.2:
resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.9.3.tgz#a095de5cb695e027b84657d5e31cabd6c5bb269c"
integrity sha512-KobZjcVyNndNrb5DAjfs0WG0lRcZu5Q1BOrfTOxokFLi25zFrWPjg+joXC6kuDqNfSt9fQwppyjUBkRPtsL+8w==
-natural-compare-lite@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
- integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
-
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -4976,10 +5134,10 @@ nearley@^2.20.1:
railroad-diagrams "^1.0.0"
randexp "0.4.6"
-neo-async@^2.6.0:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
- integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+new-github-issue-url@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/new-github-issue-url/-/new-github-issue-url-1.0.0.tgz#c9e84057c2609b7cbd686d1d8baa53e291292e79"
+ integrity sha512-wa9jlUFg3v6S3ddijQiB18SY4u9eJYcUe5sHa+6SB8m1UUbtX+H/bBglxOLnhhF1zIHuhWXnKBAa8kBeKRIozQ==
node-fetch@^2.6.11:
version "2.6.12"
@@ -5007,6 +5165,13 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
npm-run-path@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00"
@@ -5081,7 +5246,7 @@ once@^1.3.0:
dependencies:
wrappy "1"
-onetime@^5.1.0:
+onetime@^5.1.0, onetime@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
@@ -5112,37 +5277,43 @@ open@^8.4.0:
is-docker "^2.1.1"
is-wsl "^2.2.0"
-openapi-fetch@^0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.6.1.tgz#90d785ead213b82beb8f094a756ad9320ba28b32"
- integrity sha512-CGWPqqtL31uC2e4eEU9NHoqYMXnJ7Jk4H/4Yguil4tO22MIZi91hlQJ/51E8CiaKdSTODh03yF4ndjIOABVHUw==
+open@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6"
+ integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==
+ dependencies:
+ default-browser "^4.0.0"
+ define-lazy-prop "^3.0.0"
+ is-inside-container "^1.0.0"
+ is-wsl "^2.2.0"
+
+openapi-fetch@^0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.7.4.tgz#3676e0c44433bfa6701cd408853fec75599a9f0d"
+ integrity sha512-ACoSikOuFO3sMROtqritJAsGd694gRNXFnWpYAqi+tQzowLOkcQ6SbeAvS+T6qNS92y/OLiiYcNrb/Rh/MrEVw==
+ dependencies:
+ openapi-typescript-helpers "^0.0.1"
openapi-types@^12.1.3:
version "12.1.3"
resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3"
integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==
-openapi-typescript-codegen@^0.24.0:
- version "0.24.0"
- resolved "https://registry.yarnpkg.com/openapi-typescript-codegen/-/openapi-typescript-codegen-0.24.0.tgz#b3e6ade5bae75cd47868e5e3e4dc3bcf899cadab"
- integrity sha512-rSt8t1XbMWhv6Db7GUI24NNli7FU5kzHLxcE8BpzgGWRdWyWt9IB2YoLyPahxNrVA7yOaVgnXPkrcTDRMQtJYg==
- dependencies:
- camelcase "^6.3.0"
- commander "^10.0.0"
- fs-extra "^11.1.1"
- handlebars "^4.7.7"
- json-schema-ref-parser "^9.0.9"
+openapi-typescript-helpers@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.1.tgz#865c9b66f18db89e41cd0d770170719610f68d2d"
+ integrity sha512-WDmxej0eHSZtLgCuyPEn2NXRV7tcvUnBBNP/0c/U66mOlxs6Yn0/dHuWlkVKdHGNahSUwG57A1tyutHWRpWqFg==
-openapi-typescript@^6.2.8:
- version "6.3.4"
- resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-6.3.4.tgz#5351a73666e876206c50d8c100c8e8b2e4718882"
- integrity sha512-icWb7WBBFr8+RxX7NZC5ez0WkTSQAScLnI33vHRLvWxkpOGKLlp94C0wcicZWzh85EoIoFjO+tujcQxo7zeZdA==
+openapi-typescript@^6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-6.5.2.tgz#622e54e6de25bd65c65a1f129be42193160e6e42"
+ integrity sha512-Zz41utYZ3BAyr32QhOATSnN9zcWMsJeA4Jdq7xQjfYOdZbQfI8Fvsvx41Doe9Wvoho1aj5cP9b5Z7kHtG6mYvg==
dependencies:
ansi-colors "^4.1.3"
- fast-glob "^3.3.0"
+ fast-glob "^3.3.1"
js-yaml "^4.1.0"
supports-color "^9.4.0"
- undici "^5.22.1"
+ undici "^5.23.0"
yargs-parser "^21.1.1"
optionator@^0.9.3:
@@ -5201,13 +5372,6 @@ p-locate@^5.0.0:
dependencies:
p-limit "^3.0.2"
-p-map@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
- integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
- dependencies:
- aggregate-error "^3.0.0"
-
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -5230,10 +5394,10 @@ parse-ms@^2.1.0:
resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d"
integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==
-patch-package@^7.0.0:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-7.0.2.tgz#c01589bb6964854b5210506a5845d47900641f5a"
- integrity sha512-PMYfL8LXxGIRmxXLqlEaBxzKPu7/SdP13ld6GSfAUJUZRmBDPp8chZs0dpzaAFn9TSPnFiMwkC6PJt6pBiAl8Q==
+patch-package@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61"
+ integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==
dependencies:
"@yarnpkg/lockfile" "^1.1.0"
chalk "^4.1.2"
@@ -5241,6 +5405,7 @@ patch-package@^7.0.0:
cross-spawn "^7.0.3"
find-yarn-workspace-root "^2.0.0"
fs-extra "^9.0.0"
+ json-stable-stringify "^1.0.2"
klaw-sync "^6.0.0"
minimist "^1.2.6"
open "^7.4.2"
@@ -5250,11 +5415,6 @@ patch-package@^7.0.0:
tmp "^0.0.33"
yaml "^2.2.2"
-path-browserify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
- integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
-
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@@ -5265,7 +5425,7 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-path-key@^3.1.0:
+path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
@@ -5295,7 +5455,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-pidtree@^0.6.0:
+pidtree@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c"
integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
@@ -5323,7 +5483,7 @@ postcss-values-parser@^6.0.2:
is-url-superb "^4.0.0"
quote-unquote "^1.0.0"
-postcss@^8.1.7, postcss@^8.4.23, postcss@^8.4.25:
+postcss@^8.1.7, postcss@^8.4.23:
version "8.4.26"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.26.tgz#1bc62ab19f8e1e5463d98cf74af39702a00a9e94"
integrity sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==
@@ -5332,6 +5492,15 @@ postcss@^8.1.7, postcss@^8.4.23, postcss@^8.4.25:
picocolors "^1.0.0"
source-map-js "^1.0.2"
+postcss@^8.4.27:
+ version "8.4.28"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.28.tgz#c6cc681ed00109072816e1557f889ef51cf950a5"
+ integrity sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==
+ dependencies:
+ nanoid "^3.3.6"
+ picocolors "^1.0.0"
+ source-map-js "^1.0.2"
+
postinstall-postinstall@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3"
@@ -5391,6 +5560,11 @@ prettier@^2.0.5, prettier@^2.8.8:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
+prettier@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.2.tgz#78fcecd6d870551aa5547437cdae39d4701dca5b"
+ integrity sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==
+
pretty-ms@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.1.tgz#7d903eaab281f7d8e03c66f867e239dc32fb73e8"
@@ -5398,7 +5572,7 @@ pretty-ms@^7.0.1:
dependencies:
parse-ms "^2.1.0"
-prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -5459,11 +5633,6 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-re-resizable@^6.9.9:
- version "6.9.9"
- resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216"
- integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA==
-
react-clientside-effect@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a"
@@ -5493,6 +5662,13 @@ react-dropzone@^14.2.3:
file-selector "^0.6.0"
prop-types "^15.8.1"
+react-error-boundary@^4.0.11:
+ version "4.0.11"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.11.tgz#36bf44de7746714725a814630282fee83a7c9a1c"
+ integrity sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
react-fast-compare@3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.1.tgz#53933d9e14f364281d6cba24bfed7a4afb808b5f"
@@ -5515,15 +5691,15 @@ react-focus-lock@^2.9.4:
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
-react-hotkeys-hook@4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.0.tgz#e7c55bb13ecb6ffb447e90ca5525403a5a3ac7b8"
- integrity sha512-wOaCWLwgT/f895CMJrR9hmzVf+gfL8IpjWDXWXKngBp9i6Xqzf0tvLv4VI8l3Vlsg/cc4C/Iik3Ck76L/Hj0tw==
+react-hotkeys-hook@4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz#1f7a7a1c9c21d4fa3280bf340fcca8fd77d81994"
+ integrity sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==
-react-i18next@^13.0.1:
- version "13.0.2"
- resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.0.2.tgz#1708a9bdabc1fe1dd4a8534f4c3a80ab784b01e9"
- integrity sha512-NEVxC32v0oR4egwYM0QM0WE93AiJG5r0NTXTL8mhQfAhsMfDS2fSO6jpluyfsfypP988KzUQrAXncspcJ7+GHA==
+react-i18next@^13.1.2:
+ version "13.1.2"
+ resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.1.2.tgz#dbb1b18c364295af2a9072333ee4e0b43cbc2da8"
+ integrity sha512-D/OJ/8ZQYscabsvbCAiOgvJq8W3feQF/VIV0to1w7V7UvrUE1IZ3hcalOckUYvKBd7BP3b8EPm+hop3J8sS+Mw==
dependencies:
"@babel/runtime" "^7.22.5"
html-parse-stringify "^3.0.1"
@@ -5538,11 +5714,6 @@ react-is@^16.13.1, react-is@^16.7.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-react-is@^17.0.2:
- version "17.0.2"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
- integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-
react-is@^18.0.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
@@ -5566,10 +5737,10 @@ react-reconciler@~0.29.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
-react-redux@^8.1.1:
- version "8.1.1"
- resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.1.tgz#8e740f3fd864a4cd0de5ba9cdc8ad39cc9e7c81a"
- integrity sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==
+react-redux@^8.1.2:
+ version "8.1.2"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188"
+ integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==
dependencies:
"@babel/runtime" "^7.12.1"
"@types/hoist-non-react-statics" "^3.3.1"
@@ -5597,10 +5768,10 @@ react-remove-scroll@^2.5.5:
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
-react-resizable-panels@^0.0.52:
- version "0.0.52"
- resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-0.0.52.tgz#d8b1df75c9c13ebef327e6cdf1cffde7103617f6"
- integrity sha512-2vMvh7lEUCn19mqnmRLBd9BHvtub2zXCrf1UvzD8jLPVNvX9288PsF+vJwmdd7hXPMc9gdd7/CwFMfKvNnpUhQ==
+react-resizable-panels@^0.0.55:
+ version "0.0.55"
+ resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-0.0.55.tgz#adf06d35ae09748ab7051a4bd2c5be8087ef1a66"
+ integrity sha512-J/LTFzUEjJiqwSjVh8gjUXkQDA8MRPjARASfn++d2+KOgA+9UcRYUfE3QBJixer2vkk+ffQ4cq3QzWzzHgqYpQ==
react-style-singleton@^2.2.1:
version "2.2.1"
@@ -5645,10 +5816,10 @@ react-use@^17.4.0:
ts-easing "^0.2.0"
tslib "^2.1.0"
-react-virtuoso@^4.3.11:
- version "4.4.1"
- resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.4.1.tgz#43d7ac35346c4eba947b40858b375d5844b5ae9f"
- integrity sha512-QrZ0JLnZFH8ltMw6q+S7U1+V2vUcSHzoIfLRzQKSv4nMJhEdjiZ+e9PqWCI7xJiy2AmSCAgo7g1V5osuurJo2Q==
+react-virtuoso@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.5.0.tgz#0bc043b4e3e928e7891aa541dd7e55d5b46db8c8"
+ integrity sha512-OMP6XrzJMMos1vbJZC16RxGW7utAxUMP7i5PNPi6epBNVH7nz+CF/DlmecNBep5wyjLud51dQ5epjb2A0w9W/Q==
react-zoom-pan-pinch@^3.0.8:
version "3.1.0"
@@ -5662,17 +5833,17 @@ react@^18.2.0:
dependencies:
loose-envify "^1.1.0"
-reactflow@^11.7.4:
- version "11.7.4"
- resolved "https://registry.yarnpkg.com/reactflow/-/reactflow-11.7.4.tgz#b00159c3471d007bc4865b23005c636b1f08ab26"
- integrity sha512-QI6+oc1Ft6oFeLSdHlp+SmgymbI5Tm49wj5JyE84O4A54yN/ImfYaBhLit9Cmfzxn9Tz6tDqmGMGbk4bdtB8/w==
+reactflow@^11.8.3:
+ version "11.8.3"
+ resolved "https://registry.yarnpkg.com/reactflow/-/reactflow-11.8.3.tgz#ad5cdf22408298956c92ab652929ff92206af9dc"
+ integrity sha512-wuVxJOFqi1vhA4WAEJLK0JWx2TsTiWpxTXTRp/wvpqKInQgQcB49I2QNyNYsKJCQ6jjXektS7H+LXoaVK/pG4A==
dependencies:
- "@reactflow/background" "11.2.4"
- "@reactflow/controls" "11.1.15"
- "@reactflow/core" "11.7.4"
- "@reactflow/minimap" "11.5.4"
- "@reactflow/node-resizer" "2.1.1"
- "@reactflow/node-toolbar" "1.2.3"
+ "@reactflow/background" "11.2.8"
+ "@reactflow/controls" "11.1.19"
+ "@reactflow/core" "11.8.3"
+ "@reactflow/minimap" "11.6.3"
+ "@reactflow/node-resizer" "2.1.5"
+ "@reactflow/node-toolbar" "1.2.7"
readable-stream@^3.4.0:
version "3.6.2"
@@ -5695,10 +5866,10 @@ redux-dynamic-middlewares@^2.2.0:
resolved "https://registry.yarnpkg.com/redux-dynamic-middlewares/-/redux-dynamic-middlewares-2.2.0.tgz#6835dd6d4f2fd975266376b45dcae0141320ae97"
integrity sha512-GHESQC+Y0PV98ZBoaC6br6cDOsNiM1Cu4UleGMqMWCXX03jIr3BoozYVrRkLVVAl4sC216chakMnZOu6SwNdGA==
-redux-remember@^3.3.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/redux-remember/-/redux-remember-3.3.1.tgz#fad0b3af81458d8e40a54cd30be148c17e40bda9"
- integrity sha512-x30eZpdryapH8+hinYcyoTiGCSmtPUPdvL7OxjpMeRgTckJrVW57FgRAmiv41COqi/q4H+qn65Uftsasqj+F9A==
+redux-remember@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/redux-remember/-/redux-remember-4.0.1.tgz#fae416d140a9dccdf84285b957e7062934a337fb"
+ integrity sha512-mP/EWdBVKg0bJfe3srzofp5sNSmWBLjKX+JzJC7J+DBjbLaxTCsLXVq1fnE4rcHXb9Sz/4u5qZ040I/ZhKzjLw==
redux-thunk@^2.4.2:
version "2.4.2"
@@ -5712,6 +5883,18 @@ redux@^4.0.0, redux@^4.2.1:
dependencies:
"@babel/runtime" "^7.9.2"
+reflect.getprototypeof@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz#2738fd896fcc3477ffbd4190b40c2458026b6928"
+ integrity sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+ get-intrinsic "^1.1.1"
+ globalthis "^1.0.3"
+ which-builtin-type "^1.1.3"
+
regenerator-runtime@^0.13.11:
version "0.13.11"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
@@ -5731,6 +5914,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
requirejs-config-file@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/requirejs-config-file/-/requirejs-config-file-4.0.0.tgz#4244da5dd1f59874038cc1091d078d620abb6ebc"
@@ -5798,6 +5986,14 @@ restore-cursor@^3.1.0:
onetime "^5.1.0"
signal-exit "^3.0.2"
+restore-cursor@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9"
+ integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==
+ dependencies:
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@@ -5827,16 +6023,16 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
-roarr@^7.15.0:
- version "7.15.0"
- resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.15.0.tgz#09b792f0cd31b4a7f91030bb1c47550ceec98ee4"
- integrity sha512-CV9WefQfUXTX6wr8CrEMhfNef3sjIt9wNhE/5PNu4tNWsaoDNDXqq+OGn/RW9A1UPb0qc7FQlswXRaJJJsqn8A==
+roarr@^7.15.1:
+ version "7.15.1"
+ resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.15.1.tgz#e4d93105c37b5ea7dd1200d96a3500f757ddc39f"
+ integrity sha512-0ExL9rjOXeQPvQvQo8IcV8SR2GTXmDr1FQFlY2HiAV+gdVQjaVZNOx9d4FI2RqFFsd0sNsiw2TRS/8RU9g0ZfA==
dependencies:
boolean "^3.1.4"
- fast-json-stringify "^2.7.10"
+ fast-json-stringify "^5.8.0"
fast-printf "^1.6.9"
globalthis "^1.0.2"
- safe-stable-stringify "^2.4.1"
+ safe-stable-stringify "^2.4.3"
semver-compare "^1.0.0"
rollup-plugin-visualizer@^5.9.2:
@@ -5856,10 +6052,10 @@ rollup@^2.77.2:
optionalDependencies:
fsevents "~2.3.2"
-rollup@^3.25.2:
- version "3.26.3"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.26.3.tgz#bbc8818cadd0aebca348dbb3d68d296d220967b8"
- integrity sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==
+rollup@^3.27.1:
+ version "3.28.0"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.28.0.tgz#a3c70004b01934760c0cb8df717c7a1d932389a2"
+ integrity sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==
optionalDependencies:
fsevents "~2.3.2"
@@ -5870,6 +6066,13 @@ rtl-css-js@^1.14.0:
dependencies:
"@babel/runtime" "^7.1.2"
+run-applescript@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c"
+ integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==
+ dependencies:
+ execa "^5.0.0"
+
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@@ -5877,7 +6080,7 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
-rxjs@^7.8.0, rxjs@^7.8.1:
+rxjs@^7.8.1:
version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
@@ -5908,7 +6111,7 @@ safe-regex-test@^1.0.0:
get-intrinsic "^1.1.3"
is-regex "^1.1.4"
-safe-stable-stringify@^2.4.1:
+safe-stable-stringify@^2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
@@ -5937,29 +6140,22 @@ semver-compare@^1.0.0:
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
-semver@^6.3.0:
+semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.3.5, semver@^7.3.7, semver@^7.5.3:
+semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.5.4:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
-semver@~7.3.0:
- version "7.3.8"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
- integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
- dependencies:
- lru-cache "^6.0.0"
-
-serialize-error@^11.0.0:
- version "11.0.0"
- resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-11.0.0.tgz#0129f2b07b19b09bc7a5f2d850ffe9cd2d561582"
- integrity sha512-YKrURWDqcT3VGX/s/pCwaWtpfJEEaEw5Y4gAnQDku92b/HjVj4r4UhA5QrMVMFotymK2wIWs5xthny5SMFu7Vw==
+serialize-error@^11.0.1:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-11.0.1.tgz#7cfa2b54f7aca3e4cbfc0137259d94d93793f813"
+ integrity sha512-B5yw3/Lg+Daspbs0f+iO3Qim0+lALnaLS8aZUAy8Y0tO92tkOoMEuwtKo4jpZ5XO16CTwMi4tYN8cZQI3QF2Qw==
dependencies:
type-fest "^2.12.2"
@@ -5994,7 +6190,7 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
-signal-exit@^3.0.2, signal-exit@^3.0.7:
+signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -6009,24 +6205,6 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-slice-ansi@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
- integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==
- dependencies:
- ansi-styles "^4.0.0"
- astral-regex "^2.0.0"
- is-fullwidth-code-point "^3.0.0"
-
-slice-ansi@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
- integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
- dependencies:
- ansi-styles "^4.0.0"
- astral-regex "^2.0.0"
- is-fullwidth-code-point "^3.0.0"
-
slice-ansi@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a"
@@ -6035,14 +6213,14 @@ slice-ansi@^5.0.0:
ansi-styles "^6.0.0"
is-fullwidth-code-point "^4.0.0"
-socket.io-client@^4.7.0:
- version "4.7.1"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.1.tgz#48e5f703abe4fb0402182bcf9c06b7820fb3453b"
- integrity sha512-Qk3Xj8ekbnzKu3faejo4wk2MzXA029XppiXtTF/PkbTg+fcwaTw1PlDrTrrrU4mKoYC4dvlApOnSeyLCKwek2w==
+socket.io-client@^4.7.2:
+ version "4.7.2"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.2.tgz#f2f13f68058bd4e40f94f2a1541f275157ff2c08"
+ integrity sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.2"
- engine.io-client "~6.5.1"
+ engine.io-client "~6.5.2"
socket.io-parser "~4.2.4"
socket.io-parser@~4.2.4:
@@ -6058,14 +6236,6 @@ source-map-js@^1.0.2:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-source-map-support@~0.5.20:
- version "0.5.21"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
- integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
- dependencies:
- buffer-from "^1.0.0"
- source-map "^0.6.0"
-
source-map@0.5.6:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
@@ -6076,7 +6246,7 @@ source-map@^0.5.7:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
+source-map@^0.6.1, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@@ -6147,16 +6317,11 @@ streamsearch@^1.1.0:
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
-string-argv@^0.3.1, string-argv@~0.3.1:
+string-argv@0.3.2, string-argv@~0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
-string-similarity@^4.0.1:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b"
- integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==
-
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@@ -6166,7 +6331,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string-width@^5.0.0:
+string-width@^5.0.0, string-width@^5.0.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
@@ -6251,6 +6416,11 @@ strip-bom@^3.0.0:
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-final-newline@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
@@ -6315,6 +6485,14 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+synckit@^0.8.5:
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3"
+ integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==
+ dependencies:
+ "@pkgr/utils" "^2.3.1"
+ tslib "^2.5.0"
+
tabbable@^6.0.1:
version "6.2.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97"
@@ -6325,16 +6503,6 @@ tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
-terser@^5.18.1:
- version "5.19.1"
- resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.1.tgz#dbd7231f224a9e2401d0f0959542ed74d76d340b"
- integrity sha512-27hxBUVdV6GoNg1pKQ7Z5cbR6V9txPVyBA+FQw3BaZ1Wuzvztce5p156DaP0NVZNrMZZ+6iG9Syf7WgMNKDg2Q==
- dependencies:
- "@jridgewell/source-map" "^0.3.3"
- acorn "^8.8.2"
- commander "^2.20.0"
- source-map-support "~0.5.20"
-
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -6345,11 +6513,6 @@ throttle-debounce@^3.0.1:
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb"
integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==
-through@^2.3.8:
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
- integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
-
tiny-invariant@^1.0.6:
version "1.3.1"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
@@ -6360,6 +6523,11 @@ tiny-warning@^1.0.2:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+titleize@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
+ integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -6394,6 +6562,11 @@ tree-kill@^1.2.2:
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
+ts-api-utils@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99"
+ integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==
+
ts-easing@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec"
@@ -6409,14 +6582,6 @@ ts-graphviz@^1.5.0:
resolved "https://registry.yarnpkg.com/ts-graphviz/-/ts-graphviz-1.8.1.tgz#5d95e58120be8b571847331516327d4840cc44f7"
integrity sha512-54/fe5iu0Jb6X0pmDmzsA2UHLfyHjUEUwfHtZcEOR0fZ6Myf+dFoO6eNsyL8CBDMJ9u7WWEewduVaiaXlvjSVw==
-ts-morph@18.0.0:
- version "18.0.0"
- resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-18.0.0.tgz#b9e7a898ea115064585a8a775d86da6edc9c5b4e"
- integrity sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA==
- dependencies:
- "@ts-morph/common" "~0.19.0"
- code-block-writer "^12.0.0"
-
ts-toolbelt@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5"
@@ -6447,7 +6612,7 @@ tslib@^1.8.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0:
+tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3"
integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==
@@ -6457,6 +6622,11 @@ tslib@^2.0.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410"
integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==
+tslib@^2.5.0, tslib@^2.6.0:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+
tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
@@ -6476,10 +6646,10 @@ type-fest@^0.20.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
-type-fest@^0.21.3:
- version "0.21.3"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
- integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+type-fest@^1.0.2:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
+ integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
type-fest@^2.12.2:
version "2.19.0"
@@ -6540,11 +6710,6 @@ typescript@~5.0.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
-uglify-js@^3.1.4:
- version "3.17.4"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
- integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
-
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
@@ -6555,10 +6720,10 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
-undici@^5.22.1:
- version "5.22.1"
- resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b"
- integrity sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==
+undici@^5.23.0:
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-5.23.0.tgz#e7bdb0ed42cebe7b7aca87ced53e6eaafb8f8ca0"
+ integrity sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==
dependencies:
busboy "^1.6.0"
@@ -6577,6 +6742,11 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+untildify@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
+ integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
+
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
@@ -6646,26 +6816,22 @@ validator@^13.7.0:
resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855"
integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==
-vite-plugin-css-injected-by-js@^3.1.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.2.1.tgz#c23e10e28a1afb78414fa3c162ac8a253cd1a6a4"
- integrity sha512-8UQWy7tcmgwkaUKYfbj/8GOeAD0RPG2tdetAGg7WikWC8IEtNrovs8RRuLjFqdRqORT1XxchBB5tPl6xO/H95g==
+vite-plugin-css-injected-by-js@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.0.tgz#c19480a9e42a95c5bced976a9dde1446f9bd91ff"
+ integrity sha512-xG+jyHNCmUqi/TXp6q88wTJGeAOrNLSyUUTp4qEQ9QZLGcHWQQsCsSSKa59rPMQr8sOzfzmWDd8enGqfH/dBew==
-vite-plugin-dts@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-2.3.0.tgz#6ab2edf56f48261bfede03958704bfaee2fca3e4"
- integrity sha512-WbJgGtsStgQhdm3EosYmIdTGbag5YQpZ3HXWUAPCDyoXI5qN6EY0V7NXq0lAmnv9hVQsvh0htbYcg0Or5Db9JQ==
+vite-plugin-dts@^3.5.2:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-3.5.2.tgz#429612f727f1bf4eff1f22e29c04b52a75d398b8"
+ integrity sha512-iKc851+jdHEoN1ifbOEsoMs+/Zg26PE1EyO2Jc+4apOWRoaeK2zRJnaStgUuJaVaEcAjTqWzpNgCAMq7iO6DWA==
dependencies:
- "@babel/parser" "^7.21.4"
- "@microsoft/api-extractor" "^7.34.4"
+ "@microsoft/api-extractor" "^7.36.3"
"@rollup/pluginutils" "^5.0.2"
- "@rushstack/node-core-library" "^3.55.2"
+ "@vue/language-core" "^1.8.8"
debug "^4.3.4"
- fast-glob "^3.2.12"
- fs-extra "^10.1.0"
- kolorist "^1.7.0"
- magic-string "^0.29.0"
- ts-morph "18.0.0"
+ kolorist "^1.8.0"
+ vue-tsc "^1.8.8"
vite-plugin-eslint@^1.8.1:
version "1.8.1"
@@ -6685,14 +6851,14 @@ vite-tsconfig-paths@^4.2.0:
globrex "^0.1.2"
tsconfck "^2.1.0"
-vite@^4.3.9:
- version "4.4.4"
- resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.4.tgz#b76e6049c0e080cb54e735ad2d18287753752118"
- integrity sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==
+vite@^4.4.9:
+ version "4.4.9"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d"
+ integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
dependencies:
esbuild "^0.18.10"
- postcss "^8.4.25"
- rollup "^3.25.2"
+ postcss "^8.4.27"
+ rollup "^3.27.1"
optionalDependencies:
fsevents "~2.3.2"
@@ -6701,6 +6867,23 @@ void-elements@3.1.0:
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
+vue-template-compiler@^2.7.14:
+ version "2.7.14"
+ resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1"
+ integrity sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==
+ dependencies:
+ de-indent "^1.0.2"
+ he "^1.2.0"
+
+vue-tsc@^1.8.8:
+ version "1.8.8"
+ resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.8.tgz#67317693eb2ef6747e89e6d834eeb6d2deb8871d"
+ integrity sha512-bSydNFQsF7AMvwWsRXD7cBIXaNs/KSjvzWLymq/UtKE36697sboX4EccSHFVxvgdBlI1frYPc/VMKJNB7DFeDQ==
+ dependencies:
+ "@vue/language-core" "1.8.8"
+ "@vue/typescript" "1.8.8"
+ semver "^7.3.8"
+
walkdir@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39"
@@ -6737,7 +6920,35 @@ which-boxed-primitive@^1.0.2:
is-string "^1.0.5"
is-symbol "^1.0.3"
-which-typed-array@^1.1.10, which-typed-array@^1.1.11:
+which-builtin-type@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b"
+ integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==
+ dependencies:
+ function.prototype.name "^1.1.5"
+ has-tostringtag "^1.0.0"
+ is-async-function "^2.0.0"
+ is-date-object "^1.0.5"
+ is-finalizationregistry "^1.0.2"
+ is-generator-function "^1.0.10"
+ is-regex "^1.1.4"
+ is-weakref "^1.0.2"
+ isarray "^2.0.5"
+ which-boxed-primitive "^1.0.2"
+ which-collection "^1.0.1"
+ which-typed-array "^1.1.9"
+
+which-collection@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"
+ integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==
+ dependencies:
+ is-map "^2.0.1"
+ is-set "^2.0.1"
+ is-weakmap "^2.0.1"
+ is-weakset "^2.0.1"
+
+which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.9:
version "1.1.11"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a"
integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==
@@ -6755,20 +6966,6 @@ which@^2.0.1:
dependencies:
isexe "^2.0.0"
-wordwrap@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
- integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
-
-wrap-ansi@^6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
- integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
@@ -6778,6 +6975,15 @@ wrap-ansi@^7.0.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
+wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -6803,16 +7009,16 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+yaml@2.3.1, yaml@^2.2.2:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
+ integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
+
yaml@^1.10.0:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
-yaml@^2.2.2:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
- integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
-
yargs-parser@^21.1.1:
version "21.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
@@ -6852,14 +7058,19 @@ z-schema@~5.0.2:
optionalDependencies:
commander "^10.0.0"
-zod@^3.21.4:
- version "3.21.4"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db"
- integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==
+zod-validation-error@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-1.5.0.tgz#2b355007a1c3b7fb04fa476bfad4e7b3fd5491e3"
+ integrity sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw==
-zustand@^4.3.1:
- version "4.3.9"
- resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.9.tgz#a7d4332bbd75dfd25c6848180b3df1407217f2ad"
- integrity sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw==
+zod@^3.22.2:
+ version "3.22.2"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.2.tgz#3add8c682b7077c05ac6f979fea6998b573e157b"
+ integrity sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==
+
+zustand@^4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.1.tgz#0cd3a3e4756f21811bd956418fdc686877e8b3b0"
+ integrity sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==
dependencies:
use-sync-external-store "1.2.0"
diff --git a/mkdocs.yml b/mkdocs.yml
index 6cbf410971..2888f2e6ba 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -98,6 +98,15 @@ plugins:
'installation/INSTALLING_MODELS.md': 'installation/050_INSTALLING_MODELS.md'
'installation/INSTALL_PATCHMATCH.md': 'installation/060_INSTALL_PATCHMATCH.md'
+extra_javascript:
+ - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js
+ - javascripts/tablesort.js
+
+extra:
+ analytics:
+ provider: google
+ property: G-2X4JR4S4FB
+
nav:
- Home: 'index.md'
- Installation:
@@ -118,9 +127,14 @@ nav:
- Manual Installation on Windows: 'installation/deprecated_documentation/INSTALL_WINDOWS.md'
- Installing Invoke with pip: 'installation/deprecated_documentation/INSTALL_PCP.md'
- Source Installer: 'installation/deprecated_documentation/INSTALL_SOURCE.md'
- - Community Nodes:
+ - Nodes:
- Community Nodes: 'nodes/communityNodes.md'
- - Overview: 'nodes/overview.md'
+ - Example Workflows: 'nodes/exampleWorkflows.md'
+ - Nodes Overview: 'nodes/overview.md'
+ - List of Default Nodes: 'nodes/defaultNodes.md'
+ - Node Editor Usage: 'nodes/NODES.md'
+ - ComfyUI to InvokeAI: 'nodes/comfyToInvoke.md'
+ - Contributing Nodes: 'nodes/contributingNodes.md'
- Features:
- Overview: 'features/index.md'
- New to InvokeAI?: 'help/gettingStartedWithAI.md'
@@ -130,13 +144,12 @@ nav:
- Image-to-Image: 'features/IMG2IMG.md'
- Controlling Logging: 'features/LOGGING.md'
- Model Merging: 'features/MODEL_MERGING.md'
- - Nodes Editor (Experimental): 'features/NODES.md'
- - NSFW Checker: 'features/NSFW.md'
+ - Using Nodes : './nodes/overview'
+ - NSFW Checker: 'features/WATERMARK+NSFW.md'
- Postprocessing: 'features/POSTPROCESS.md'
- Prompting Features: 'features/PROMPTS.md'
- Training: 'features/TRAINING.md'
- Unified Canvas: 'features/UNIFIED_CANVAS.md'
- - Variations: 'features/VARIATIONS.md'
- InvokeAI Web Server: 'features/WEB.md'
- WebUI Hotkeys: "features/WEBUIHOTKEYS.md"
- Other: 'features/OTHER.md'
@@ -148,6 +161,7 @@ nav:
- Frontend Documentation: 'contributing/contribution_guides/development_guides/contributingToFrontend.md'
- Local Development: 'contributing/LOCAL_DEVELOPMENT.md'
- Documentation: 'contributing/contribution_guides/documentation.md'
+ - Nodes: 'contributing/INVOCATIONS.md'
- Translation: 'contributing/contribution_guides/translation.md'
- Tutorials: 'contributing/contribution_guides/tutorials.md'
- Changelog: 'CHANGELOG.md'
@@ -158,6 +172,7 @@ nav:
- Outpainting: 'deprecated/OUTPAINTING.md'
- Help:
- Getting Started: 'help/gettingStartedWithAI.md'
+ - Diffusion Overview: 'help/diffusion.md'
- Sampler Convergence: 'help/SAMPLER_CONVERGENCE.md'
- Other:
- Contributors: 'other/CONTRIBUTORS.md'
diff --git a/pyproject.toml b/pyproject.toml
index 02e53f066a..9aef66a35f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -93,6 +93,7 @@ dependencies = [
"mkdocs-redirects==1.2.0",
]
"dev" = [
+ "jurigged",
"pudb",
]
"test" = [
diff --git a/tests/nodes/test_graph_execution_state.py b/tests/nodes/test_graph_execution_state.py
index cc3cc0288b..cdb9815f83 100644
--- a/tests/nodes/test_graph_execution_state.py
+++ b/tests/nodes/test_graph_execution_state.py
@@ -116,14 +116,14 @@ def test_graph_state_expands_iterator(mock_services):
graph.add_node(AddInvocation(id="3", b=1))
graph.add_edge(create_edge("0", "collection", "1", "collection"))
graph.add_edge(create_edge("1", "item", "2", "a"))
- graph.add_edge(create_edge("2", "a", "3", "a"))
+ graph.add_edge(create_edge("2", "value", "3", "a"))
g = GraphExecutionState(graph=graph)
while not g.is_complete():
invoke_next(g, mock_services)
prepared_add_nodes = g.source_prepared_mapping["3"]
- results = set([g.results[n].a for n in prepared_add_nodes])
+ results = set([g.results[n].value for n in prepared_add_nodes])
expected = set([1, 11, 21])
assert results == expected
diff --git a/tests/nodes/test_node_graph.py b/tests/nodes/test_node_graph.py
index f03e23e1c2..fe6709827f 100644
--- a/tests/nodes/test_node_graph.py
+++ b/tests/nodes/test_node_graph.py
@@ -477,13 +477,13 @@ def test_graph_expands_subgraph():
n1_2 = SubtractInvocation(id="2", b=3)
n1.graph.add_node(n1_1)
n1.graph.add_node(n1_2)
- n1.graph.add_edge(create_edge("1", "a", "2", "a"))
+ n1.graph.add_edge(create_edge("1", "value", "2", "a"))
g.add_node(n1)
n2 = AddInvocation(id="2", b=5)
g.add_node(n2)
- g.add_edge(create_edge("1.2", "a", "2", "a"))
+ g.add_edge(create_edge("1.2", "value", "2", "a"))
dg = g.nx_graph_flat()
assert set(dg.nodes) == set(["1.1", "1.2", "2"])
@@ -500,14 +500,14 @@ def test_graph_subgraph_t2i():
g.add_node(n1)
- n2 = IntegerInvocation(id="2", a=512)
- n3 = IntegerInvocation(id="3", a=256)
+ n2 = IntegerInvocation(id="2", value=512)
+ n3 = IntegerInvocation(id="3", value=256)
g.add_node(n2)
g.add_node(n3)
- g.add_edge(create_edge("2", "a", "1.width", "a"))
- g.add_edge(create_edge("3", "a", "1.height", "a"))
+ g.add_edge(create_edge("2", "value", "1.width", "value"))
+ g.add_edge(create_edge("3", "value", "1.height", "value"))
n4 = ShowImageInvocation(id="4")
g.add_node(n4)
diff --git a/tests/test_config.py b/tests/test_config.py
index 0a8d44ad34..88da7a02ab 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -5,6 +5,8 @@ import pytest
from omegaconf import OmegaConf
from pathlib import Path
+from invokeai.app.services.config import InvokeAIAppConfig
+
@pytest.fixture
def patch_rootdir(tmp_path: Path, monkeypatch: Any) -> None:
@@ -34,6 +36,21 @@ InvokeAI:
"""
)
+init3 = OmegaConf.create(
+ """
+InvokeAI:
+ Generation:
+ sequential_guidance: true
+ attention_type: xformers
+ attention_slice_size: 7
+ forced_tiled_decode: True
+ Device:
+ device: cpu
+ Model Cache:
+ ram: 1.25
+"""
+)
+
def test_use_init(patch_rootdir):
# note that we explicitly set omegaconf dict and argv here
@@ -56,9 +73,18 @@ def test_use_init(patch_rootdir):
assert not hasattr(conf2, "invalid_attribute")
-def test_argv_override(patch_rootdir):
- from invokeai.app.services.config import InvokeAIAppConfig
+def test_legacy():
+ conf = InvokeAIAppConfig.get_config()
+ assert conf
+ conf.parse_args(conf=init3, argv=[])
+ assert conf.xformers_enabled
+ assert conf.device == "cpu"
+ assert conf.use_cpu
+ assert conf.ram == 1.25
+ assert conf.ram_cache_size == 1.25
+
+def test_argv_override():
conf = InvokeAIAppConfig.get_config()
conf.parse_args(conf=init1, argv=["--always_use_cpu", "--max_cache=10"])
assert conf.always_use_cpu