diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index f33bfff26e..99127c4332 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -1,14 +1,12 @@ # Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) import os -from argparse import Namespace -from invokeai.app.services.metadata import PngMetadataService, MetadataServiceBase +import invokeai.backend.util.logging as logger +from typing import types from ..services.default_graphs import create_system_graphs - from ..services.latent_storage import DiskLatentsStorage, ForwardCacheLatentsStorage - from ...backend import Globals from ..services.model_manager_initializer import get_model_manager from ..services.restoration_services import RestorationServices @@ -19,6 +17,7 @@ from ..services.invocation_services import InvocationServices from ..services.invoker import Invoker from ..services.processor import DefaultInvocationProcessor from ..services.sqlite import SqliteItemStorage +from ..services.metadata import PngMetadataService from .events import FastAPIEventService @@ -44,15 +43,16 @@ class ApiDependencies: invoker: Invoker = None @staticmethod - def initialize(config, event_handler_id: int): + def initialize(config, event_handler_id: int, logger: types.ModuleType=logger): Globals.try_patchmatch = config.patchmatch Globals.always_use_cpu = config.always_use_cpu Globals.internet_available = config.internet_available and check_internet() Globals.disable_xformers = not config.xformers Globals.ckpt_convert = config.ckpt_convert - # TODO: Use a logger - print(f">> Internet connectivity is {Globals.internet_available}") + # TO DO: Use the config to select the logger rather than use the default + # invokeai logging module + logger.info(f"Internet connectivity is {Globals.internet_available}") events = FastAPIEventService(event_handler_id) @@ -70,8 +70,9 @@ class ApiDependencies: db_location = os.path.join(output_folder, "invokeai.db") services = InvocationServices( - model_manager=get_model_manager(config), + model_manager=get_model_manager(config,logger), events=events, + logger=logger, latents=latents, images=images, metadata=metadata, @@ -83,7 +84,7 @@ class ApiDependencies: filename=db_location, table_name="graph_executions" ), processor=DefaultInvocationProcessor(), - restoration=RestorationServices(config), + restoration=RestorationServices(config,logger), ) create_system_graphs(services.graph_library) diff --git a/invokeai/app/api/routers/models.py b/invokeai/app/api/routers/models.py index 2de079cd6d..ca83b44bf3 100644 --- a/invokeai/app/api/routers/models.py +++ b/invokeai/app/api/routers/models.py @@ -8,10 +8,6 @@ from fastapi.routing import APIRouter, HTTPException from pydantic import BaseModel, Field, parse_obj_as from pathlib import Path from ..dependencies import ApiDependencies -from invokeai.backend.globals import Globals, global_converted_ckpts_dir -from invokeai.backend.args import Args - - models_router = APIRouter(prefix="/v1/models", tags=["models"]) @@ -112,19 +108,20 @@ async def update_model( async def delete_model(model_name: str) -> None: """Delete Model""" model_names = ApiDependencies.invoker.services.model_manager.model_names() + logger = ApiDependencies.invoker.services.logger model_exists = model_name in model_names # check if model exists - print(f">> Checking for model {model_name}...") + logger.info(f"Checking for model {model_name}...") if model_exists: - print(f">> Deleting Model: {model_name}") + logger.info(f"Deleting Model: {model_name}") ApiDependencies.invoker.services.model_manager.del_model(model_name, delete_files=True) - print(f">> Model Deleted: {model_name}") + logger.info(f"Model Deleted: {model_name}") raise HTTPException(status_code=204, detail=f"Model '{model_name}' deleted successfully") else: - print(f">> Model not found") + logger.error(f"Model not found") raise HTTPException(status_code=404, detail=f"Model '{model_name}' not found") @@ -248,4 +245,4 @@ async def delete_model(model_name: str) -> None: # ) # print(f">> Models Merged: {models_to_merge}") # print(f">> New Model Added: {model_merge_info['merged_model_name']}") - # except Exception as e: \ No newline at end of file + # except Exception as e: diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index ab05cb3344..f935de542e 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -3,6 +3,7 @@ import asyncio from inspect import signature import uvicorn +import invokeai.backend.util.logging as logger from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html @@ -16,7 +17,6 @@ from ..backend import Args from .api.dependencies import ApiDependencies from .api.routers import images, sessions, models from .api.sockets import SocketIO -from .invocations import * from .invocations.baseinvocation import BaseInvocation # Create the app @@ -56,7 +56,7 @@ async def startup_event(): config.parse_args() ApiDependencies.initialize( - config=config, event_handler_id=event_handler_id + config=config, event_handler_id=event_handler_id, logger=logger ) diff --git a/invokeai/app/cli/commands.py b/invokeai/app/cli/commands.py index 5ad4827eb0..01cd99bc35 100644 --- a/invokeai/app/cli/commands.py +++ b/invokeai/app/cli/commands.py @@ -2,14 +2,15 @@ from abc import ABC, abstractmethod import argparse -from typing import Any, Callable, Iterable, Literal, get_args, get_origin, get_type_hints +from typing import Any, Callable, Iterable, Literal, Union, get_args, get_origin, get_type_hints from pydantic import BaseModel, Field import networkx as nx import matplotlib.pyplot as plt +import invokeai.backend.util.logging as logger from ..invocations.baseinvocation import BaseInvocation from ..invocations.image import ImageField -from ..services.graph import GraphExecutionState, LibraryGraph, GraphInvocation, Edge +from ..services.graph import GraphExecutionState, LibraryGraph, Edge from ..services.invoker import Invoker @@ -229,7 +230,7 @@ class HistoryCommand(BaseCommand): for i in range(min(self.count, len(history))): entry_id = history[-1 - i] entry = context.get_session().graph.get_node(entry_id) - print(f"{entry_id}: {get_invocation_command(entry)}") + logger.info(f"{entry_id}: {get_invocation_command(entry)}") class SetDefaultCommand(BaseCommand): diff --git a/invokeai/app/cli/completer.py b/invokeai/app/cli/completer.py index 86d3e100c3..c84c430bd7 100644 --- a/invokeai/app/cli/completer.py +++ b/invokeai/app/cli/completer.py @@ -10,6 +10,7 @@ import shlex from pathlib import Path from typing import List, Dict, Literal, get_args, get_type_hints, get_origin +import invokeai.backend.util.logging as logger from ...backend import ModelManager, Globals from ..invocations.baseinvocation import BaseInvocation from .commands import BaseCommand @@ -160,8 +161,8 @@ def set_autocompleter(model_manager: ModelManager) -> Completer: pass except OSError: # file likely corrupted newname = f"{histfile}.old" - print( - f"## Your history file {histfile} couldn't be loaded and may be corrupted. Renaming it to {newname}" + logger.error( + f"Your history file {histfile} couldn't be loaded and may be corrupted. Renaming it to {newname}" ) histfile.replace(Path(newname)) atexit.register(readline.write_history_file, histfile) diff --git a/invokeai/app/cli_app.py b/invokeai/app/cli_app.py index 9ac156916b..abe672820b 100644 --- a/invokeai/app/cli_app.py +++ b/invokeai/app/cli_app.py @@ -13,21 +13,20 @@ from typing import ( from pydantic import BaseModel from pydantic.fields import Field + +import invokeai.backend.util.logging as logger from invokeai.app.services.metadata import PngMetadataService - from .services.default_graphs import create_system_graphs - from .services.latent_storage import DiskLatentsStorage, ForwardCacheLatentsStorage from ..backend import Args -from .cli.commands import BaseCommand, CliContext, ExitCli, add_graph_parsers, add_parsers, get_graph_execution_history +from .cli.commands import BaseCommand, CliContext, ExitCli, add_graph_parsers, add_parsers from .cli.completer import set_autocompleter -from .invocations import * from .invocations.baseinvocation import BaseInvocation from .services.events import EventServiceBase from .services.model_manager_initializer import get_model_manager from .services.restoration_services import RestorationServices -from .services.graph import Edge, EdgeConnection, ExposedNodeInput, GraphExecutionState, GraphInvocation, LibraryGraph, are_connection_types_compatible +from .services.graph import Edge, EdgeConnection, GraphExecutionState, GraphInvocation, LibraryGraph, are_connection_types_compatible from .services.default_graphs import default_text_to_image_graph_id from .services.image_storage import DiskImageStorage from .services.invocation_queue import MemoryInvocationQueue @@ -182,7 +181,7 @@ def invoke_all(context: CliContext): # Print any errors if context.session.has_error(): for n in context.session.errors: - print( + context.invoker.services.logger.error( f"Error in node {n} (source node {context.session.prepared_source_mapping[n]}): {context.session.errors[n]}" ) @@ -192,13 +191,13 @@ def invoke_all(context: CliContext): def invoke_cli(): config = Args() config.parse_args() - model_manager = get_model_manager(config) + model_manager = get_model_manager(config,logger=logger) # This initializes the autocompleter and returns it. # Currently nothing is done with the returned Completer # object, but the object can be used to change autocompletion # behavior on the fly, if desired. - completer = set_autocompleter(model_manager) + set_autocompleter(model_manager) events = EventServiceBase() @@ -225,7 +224,8 @@ def invoke_cli(): filename=db_location, table_name="graph_executions" ), processor=DefaultInvocationProcessor(), - restoration=RestorationServices(config), + restoration=RestorationServices(config,logger=logger), + logger=logger, ) system_graphs = create_system_graphs(services.graph_library) @@ -365,12 +365,12 @@ def invoke_cli(): invoke_all(context) except InvalidArgs: - print('Invalid command, use "help" to list commands') + invoker.services.logger.warning('Invalid command, use "help" to list commands') continue except SessionError: # Start a new session - print("Session error: creating a new session") + invoker.services.logger.warning("Session error: creating a new session") context.reset() except ExitCli: diff --git a/invokeai/app/invocations/generate.py b/invokeai/app/invocations/generate.py index 0bf48eefcf..580df3987d 100644 --- a/invokeai/app/invocations/generate.py +++ b/invokeai/app/invocations/generate.py @@ -46,8 +46,8 @@ class TextToImageInvocation(BaseInvocation, SDImageInvocation): prompt: Optional[str] = Field(description="The prompt to generate an image from") seed: int = Field(default=-1,ge=-1, le=np.iinfo(np.uint32).max, description="The seed to use (-1 for a random seed)", ) steps: int = Field(default=10, gt=0, description="The number of steps to use to generate the image") - width: int = Field(default=512, multiple_of=64, gt=0, description="The width of the resulting image", ) - height: int = Field(default=512, multiple_of=64, gt=0, description="The height of the resulting image", ) + width: int = Field(default=512, multiple_of=8, gt=0, description="The width of the resulting image", ) + height: int = Field(default=512, multiple_of=8, gt=0, description="The height of the resulting image", ) cfg_scale: float = Field(default=7.5, gt=0, description="The Classifier-Free Guidance, higher values may result in a result closer to the prompt", ) scheduler: SAMPLER_NAME_VALUES = Field(default="k_lms", description="The scheduler to use" ) seamless: bool = Field(default=False, description="Whether or not to generate an image that can tile without seams", ) @@ -150,6 +150,9 @@ class ImageToImageInvocation(TextToImageInvocation): ) mask = None + if self.fit: + image = image.resize((self.width, self.height)) + # Handle invalid model parameter model = choose_model(context.services.model_manager, self.model) diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 3d1c925570..c6ea8a686a 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -113,8 +113,8 @@ class NoiseInvocation(BaseInvocation): # Inputs seed: int = Field(ge=0, le=np.iinfo(np.uint32).max, description="The seed to use", default_factory=random_seed) - width: int = Field(default=512, multiple_of=64, gt=0, description="The width of the resulting noise", ) - height: int = Field(default=512, multiple_of=64, gt=0, description="The height of the resulting noise", ) + width: int = Field(default=512, multiple_of=8, gt=0, description="The width of the resulting noise", ) + height: int = Field(default=512, multiple_of=8, gt=0, description="The height of the resulting noise", ) # Schema customisation @@ -146,11 +146,8 @@ class TextToLatentsInvocation(BaseInvocation): # TODO: consider making prompt optional to enable providing prompt through a link # fmt: off prompt: Optional[str] = Field(description="The prompt to generate an image from") - seed: int = Field(default=-1,ge=-1, le=np.iinfo(np.uint32).max, description="The seed to use (-1 for a random seed)", ) noise: Optional[LatentsField] = Field(description="The noise to use") steps: int = Field(default=10, gt=0, description="The number of steps to use to generate the image") - width: int = Field(default=512, multiple_of=64, gt=0, description="The width of the resulting image", ) - height: int = Field(default=512, multiple_of=64, gt=0, description="The height of the resulting image", ) cfg_scale: float = Field(default=7.5, gt=0, description="The Classifier-Free Guidance, higher values may result in a result closer to the prompt", ) scheduler: SAMPLER_NAME_VALUES = Field(default="k_lms", description="The scheduler to use" ) seamless: bool = Field(default=False, description="Whether or not to generate an image that can tile without seams", ) @@ -363,9 +360,74 @@ class LatentsToImageInvocation(BaseInvocation): session_id=context.graph_execution_state_id, node=self ) + torch.cuda.empty_cache() + context.services.images.save(image_type, image_name, image, metadata) return build_image_output( - image_type=image_type, - image_name=image_name, - image=image + image_type=image_type, image_name=image_name, image=image ) + + +LATENTS_INTERPOLATION_MODE = Literal[ + "nearest", "linear", "bilinear", "bicubic", "trilinear", "area", "nearest-exact" +] + + +class ResizeLatentsInvocation(BaseInvocation): + """Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8.""" + + type: Literal["lresize"] = "lresize" + + # Inputs + latents: Optional[LatentsField] = Field(description="The latents to resize") + width: int = Field(ge=64, multiple_of=8, description="The width to resize to (px)") + height: int = Field(ge=64, multiple_of=8, description="The height to resize to (px)") + mode: Optional[LATENTS_INTERPOLATION_MODE] = Field(default="bilinear", description="The interpolation mode") + antialias: Optional[bool] = Field(default=False, description="Whether or not to antialias (applied in bilinear and bicubic modes only)") + + def invoke(self, context: InvocationContext) -> LatentsOutput: + latents = context.services.latents.get(self.latents.latents_name) + + resized_latents = torch.nn.functional.interpolate( + latents, + size=(self.height // 8, self.width // 8), + mode=self.mode, + antialias=self.antialias if self.mode in ["bilinear", "bicubic"] else False, + ) + + # https://discuss.huggingface.co/t/memory-usage-by-later-pipeline-stages/23699 + torch.cuda.empty_cache() + + name = f"{context.graph_execution_state_id}__{self.id}" + context.services.latents.set(name, resized_latents) + return LatentsOutput(latents=LatentsField(latents_name=name)) + + +class ScaleLatentsInvocation(BaseInvocation): + """Scales latents by a given factor.""" + + type: Literal["lscale"] = "lscale" + + # Inputs + latents: Optional[LatentsField] = Field(description="The latents to scale") + scale_factor: float = Field(gt=0, description="The factor by which to scale the latents") + mode: Optional[LATENTS_INTERPOLATION_MODE] = Field(default="bilinear", description="The interpolation mode") + antialias: Optional[bool] = Field(default=False, description="Whether or not to antialias (applied in bilinear and bicubic modes only)") + + def invoke(self, context: InvocationContext) -> LatentsOutput: + latents = context.services.latents.get(self.latents.latents_name) + + # resizing + resized_latents = torch.nn.functional.interpolate( + latents, + scale_factor=self.scale_factor, + mode=self.mode, + antialias=self.antialias if self.mode in ["bilinear", "bicubic"] else False, + ) + + # https://discuss.huggingface.co/t/memory-usage-by-later-pipeline-stages/23699 + torch.cuda.empty_cache() + + name = f"{context.graph_execution_state_id}__{self.id}" + context.services.latents.set(name, resized_latents) + return LatentsOutput(latents=LatentsField(latents_name=name)) diff --git a/invokeai/app/invocations/util/choose_model.py b/invokeai/app/invocations/util/choose_model.py index f0f2dc7120..cd03ce87a8 100644 --- a/invokeai/app/invocations/util/choose_model.py +++ b/invokeai/app/invocations/util/choose_model.py @@ -3,12 +3,11 @@ from invokeai.backend.model_management.model_manager import ModelManager def choose_model(model_manager: ModelManager, model_name: str): """Returns the default model if the `model_name` not a valid model, else returns the selected model.""" + logger = model_manager.logger if model_manager.valid_model(model_name): model = model_manager.get_model(model_name) else: model = model_manager.get_model() - print( - f"* Warning: '{model_name}' is not a valid model name. Using default model \'{model['model_name']}\' instead." - ) + logger.warning(f"{model_name}' is not a valid model name. Using default model \'{model['model_name']}\' instead.") return model diff --git a/invokeai/app/services/default_graphs.py b/invokeai/app/services/default_graphs.py index 637d906e75..fd0c8f5b8d 100644 --- a/invokeai/app/services/default_graphs.py +++ b/invokeai/app/services/default_graphs.py @@ -23,8 +23,6 @@ def create_text_to_image() -> LibraryGraph: edges=[ Edge(source=EdgeConnection(node_id='width', field='a'), destination=EdgeConnection(node_id='3', field='width')), Edge(source=EdgeConnection(node_id='height', field='a'), destination=EdgeConnection(node_id='3', field='height')), - Edge(source=EdgeConnection(node_id='width', field='a'), destination=EdgeConnection(node_id='4', field='width')), - Edge(source=EdgeConnection(node_id='height', field='a'), destination=EdgeConnection(node_id='4', field='height')), Edge(source=EdgeConnection(node_id='3', field='noise'), destination=EdgeConnection(node_id='4', field='noise')), Edge(source=EdgeConnection(node_id='4', field='latents'), destination=EdgeConnection(node_id='5', field='latents')), ] diff --git a/invokeai/app/services/invocation_services.py b/invokeai/app/services/invocation_services.py index 1ff42f063d..47b3b6cf07 100644 --- a/invokeai/app/services/invocation_services.py +++ b/invokeai/app/services/invocation_services.py @@ -1,4 +1,6 @@ -# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) +# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team + +from typing import types from invokeai.app.services.metadata import MetadataServiceBase from invokeai.backend import ModelManager @@ -29,6 +31,7 @@ class InvocationServices: self, model_manager: ModelManager, events: EventServiceBase, + logger: types.ModuleType, latents: LatentsStorageBase, images: ImageStorageBase, metadata: MetadataServiceBase, @@ -40,6 +43,7 @@ class InvocationServices: ): self.model_manager = model_manager self.events = events + self.logger = logger self.latents = latents self.images = images self.metadata = metadata diff --git a/invokeai/app/services/invoker.py b/invokeai/app/services/invoker.py index e3fa6da851..a7c9ae444d 100644 --- a/invokeai/app/services/invoker.py +++ b/invokeai/app/services/invoker.py @@ -49,7 +49,7 @@ class Invoker: new_state = GraphExecutionState(graph=Graph() if graph is None else graph) self.services.graph_execution_manager.set(new_state) return new_state - + def cancel(self, graph_execution_state_id: str) -> None: """Cancels the given execution state""" self.services.queue.cancel(graph_execution_state_id) @@ -71,18 +71,12 @@ class Invoker: for service in vars(self.services): self.__start_service(getattr(self.services, service)) - for service in vars(self.services): - self.__start_service(getattr(self.services, service)) - def stop(self) -> None: """Stops the invoker. A new invoker will have to be created to execute further.""" # First stop all services for service in vars(self.services): self.__stop_service(getattr(self.services, service)) - for service in vars(self.services): - self.__stop_service(getattr(self.services, service)) - self.services.queue.put(None) diff --git a/invokeai/app/services/model_manager_initializer.py b/invokeai/app/services/model_manager_initializer.py index 3ef79f0b7e..2b1aac1f36 100644 --- a/invokeai/app/services/model_manager_initializer.py +++ b/invokeai/app/services/model_manager_initializer.py @@ -5,6 +5,7 @@ from argparse import Namespace from invokeai.backend import Args from omegaconf import OmegaConf from pathlib import Path +from typing import types import invokeai.version from ...backend import ModelManager @@ -12,16 +13,16 @@ from ...backend.util import choose_precision, choose_torch_device from ...backend import Globals # TODO: Replace with an abstract class base ModelManagerBase -def get_model_manager(config: Args) -> ModelManager: +def get_model_manager(config: Args, logger: types.ModuleType) -> ModelManager: if not config.conf: config_file = os.path.join(Globals.root, "configs", "models.yaml") if not os.path.exists(config_file): report_model_error( - config, FileNotFoundError(f"The file {config_file} could not be found.") + config, FileNotFoundError(f"The file {config_file} could not be found."), logger ) - print(f">> {invokeai.version.__app_name__}, version {invokeai.version.__version__}") - print(f'>> InvokeAI runtime directory is "{Globals.root}"') + logger.info(f"{invokeai.version.__app_name__}, version {invokeai.version.__version__}") + logger.info(f'InvokeAI runtime directory is "{Globals.root}"') # these two lines prevent a horrible warning message from appearing # when the frozen CLIP tokenizer is imported @@ -62,11 +63,12 @@ def get_model_manager(config: Args) -> ModelManager: device_type=device, max_loaded_models=config.max_loaded_models, embedding_path = Path(embedding_path), + logger = logger, ) except (FileNotFoundError, TypeError, AssertionError) as e: - report_model_error(config, e) + report_model_error(config, e, logger) except (IOError, KeyError) as e: - print(f"{e}. Aborting.") + logger.error(f"{e}. Aborting.") sys.exit(-1) # try to autoconvert new models @@ -76,18 +78,18 @@ def get_model_manager(config: Args) -> ModelManager: conf_path=config.conf, weights_directory=path, ) - + logger.info('Model manager initialized') return model_manager -def report_model_error(opt: Namespace, e: Exception): - print(f'** An error occurred while attempting to initialize the model: "{str(e)}"') - print( - "** This can be caused by a missing or corrupted models file, and can sometimes be fixed by (re)installing the models." +def report_model_error(opt: Namespace, e: Exception, logger: types.ModuleType): + logger.error(f'An error occurred while attempting to initialize the model: "{str(e)}"') + logger.error( + "This can be caused by a missing or corrupted models file, and can sometimes be fixed by (re)installing the models." ) yes_to_all = os.environ.get("INVOKE_MODEL_RECONFIGURE") if yes_to_all: - print( - "** Reconfiguration is being forced by environment variable INVOKE_MODEL_RECONFIGURE" + logger.warning( + "Reconfiguration is being forced by environment variable INVOKE_MODEL_RECONFIGURE" ) else: response = input( @@ -96,13 +98,12 @@ def report_model_error(opt: Namespace, e: Exception): if response.startswith(("n", "N")): return - print("invokeai-configure is launching....\n") + logger.info("invokeai-configure is launching....\n") # Match arguments that were set on the CLI # only the arguments accepted by the configuration script are parsed root_dir = ["--root", opt.root_dir] if opt.root_dir is not None else [] config = ["--config", opt.conf] if opt.conf is not None else [] - previous_config = sys.argv sys.argv = ["invokeai-configure"] sys.argv.extend(root_dir) sys.argv.extend(config.to_dict()) diff --git a/invokeai/app/services/processor.py b/invokeai/app/services/processor.py index c622906750..35cbcd5068 100644 --- a/invokeai/app/services/processor.py +++ b/invokeai/app/services/processor.py @@ -1,5 +1,5 @@ import traceback -from threading import Event, Thread +from threading import Event, Thread, BoundedSemaphore from ..invocations.baseinvocation import InvocationContext from .invocation_queue import InvocationQueueItem @@ -10,8 +10,11 @@ class DefaultInvocationProcessor(InvocationProcessorABC): __invoker_thread: Thread __stop_event: Event __invoker: Invoker + __threadLimit: BoundedSemaphore def start(self, invoker) -> None: + # if we do want multithreading at some point, we could make this configurable + self.__threadLimit = BoundedSemaphore(1) self.__invoker = invoker self.__stop_event = Event() self.__invoker_thread = Thread( @@ -20,7 +23,7 @@ class DefaultInvocationProcessor(InvocationProcessorABC): kwargs=dict(stop_event=self.__stop_event), ) self.__invoker_thread.daemon = ( - True # TODO: probably better to just not use threads? + True # TODO: make async and do not use threads ) self.__invoker_thread.start() @@ -29,6 +32,7 @@ class DefaultInvocationProcessor(InvocationProcessorABC): def __process(self, stop_event: Event): try: + self.__threadLimit.acquire() while not stop_event.is_set(): queue_item: InvocationQueueItem = self.__invoker.services.queue.get() if not queue_item: # Probably stopping @@ -110,7 +114,7 @@ class DefaultInvocationProcessor(InvocationProcessorABC): ) pass - + # Check queue to see if this is canceled, and skip if so if self.__invoker.services.queue.is_canceled( graph_execution_state.id @@ -127,4 +131,6 @@ class DefaultInvocationProcessor(InvocationProcessorABC): ) except KeyboardInterrupt: - ... # Log something? + pass # Log something? KeyboardInterrupt is probably not going to be seen by the processor + finally: + self.__threadLimit.release() diff --git a/invokeai/app/services/restoration_services.py b/invokeai/app/services/restoration_services.py index f5fc687c11..7bd264444e 100644 --- a/invokeai/app/services/restoration_services.py +++ b/invokeai/app/services/restoration_services.py @@ -1,6 +1,7 @@ import sys import traceback import torch +from typing import types from ...backend.restoration import Restoration from ...backend.util import choose_torch_device, CPU_DEVICE, MPS_DEVICE @@ -10,7 +11,7 @@ from ...backend.util import choose_torch_device, CPU_DEVICE, MPS_DEVICE class RestorationServices: '''Face restoration and upscaling''' - def __init__(self,args): + def __init__(self,args,logger:types.ModuleType): try: gfpgan, codeformer, esrgan = None, None, None if args.restore or args.esrgan: @@ -20,20 +21,22 @@ class RestorationServices: args.gfpgan_model_path ) else: - print(">> Face restoration disabled") + logger.info("Face restoration disabled") if args.esrgan: esrgan = restoration.load_esrgan(args.esrgan_bg_tile) else: - print(">> Upscaling disabled") + logger.info("Upscaling disabled") else: - print(">> Face restoration and upscaling disabled") + logger.info("Face restoration and upscaling disabled") except (ModuleNotFoundError, ImportError): print(traceback.format_exc(), file=sys.stderr) - print(">> You may need to install the ESRGAN and/or GFPGAN modules") + logger.info("You may need to install the ESRGAN and/or GFPGAN modules") self.device = torch.device(choose_torch_device()) self.gfpgan = gfpgan self.codeformer = codeformer self.esrgan = esrgan + self.logger = logger + self.logger.info('Face restoration initialized') # note that this one method does gfpgan and codepath reconstruction, as well as # esrgan upscaling @@ -58,15 +61,15 @@ class RestorationServices: if self.gfpgan is not None or self.codeformer is not None: if facetool == "gfpgan": if self.gfpgan is None: - print( - ">> GFPGAN not found. Face restoration is disabled." + self.logger.info( + "GFPGAN not found. Face restoration is disabled." ) else: image = self.gfpgan.process(image, strength, seed) if facetool == "codeformer": if self.codeformer is None: - print( - ">> CodeFormer not found. Face restoration is disabled." + self.logger.info( + "CodeFormer not found. Face restoration is disabled." ) else: cf_device = ( @@ -80,7 +83,7 @@ class RestorationServices: fidelity=codeformer_fidelity, ) else: - print(">> Face Restoration is disabled.") + self.logger.info("Face Restoration is disabled.") if upscale is not None: if self.esrgan is not None: if len(upscale) < 2: @@ -93,10 +96,10 @@ class RestorationServices: denoise_str=upscale_denoise_str, ) else: - print(">> ESRGAN is disabled. Image not upscaled.") + self.logger.info("ESRGAN is disabled. Image not upscaled.") except Exception as e: - print( - f">> Error running RealESRGAN or GFPGAN. Your image was not upscaled.\n{e}" + self.logger.info( + f"Error running RealESRGAN or GFPGAN. Your image was not upscaled.\n{e}" ) if image_callback is not None: diff --git a/invokeai/backend/args.py b/invokeai/backend/args.py index b6c2608b20..eb8b396ee0 100644 --- a/invokeai/backend/args.py +++ b/invokeai/backend/args.py @@ -96,6 +96,7 @@ from pathlib import Path from typing import List import invokeai.version +import invokeai.backend.util.logging as logger from invokeai.backend.image_util import retrieve_metadata from .globals import Globals @@ -189,7 +190,7 @@ class Args(object): print(f"{APP_NAME} {APP_VERSION}") sys.exit(0) - print("* Initializing, be patient...") + logger.info("Initializing, be patient...") Globals.root = Path(os.path.abspath(switches.root_dir or Globals.root)) Globals.try_patchmatch = switches.patchmatch @@ -197,14 +198,13 @@ class Args(object): initfile = os.path.expanduser(os.path.join(Globals.root, Globals.initfile)) legacyinit = os.path.expanduser("~/.invokeai") if os.path.exists(initfile): - print( - f">> Initialization file {initfile} found. Loading...", - file=sys.stderr, + logger.info( + f"Initialization file {initfile} found. Loading...", ) sysargs.insert(0, f"@{initfile}") elif os.path.exists(legacyinit): - print( - f">> WARNING: Old initialization file found at {legacyinit}. This location is deprecated. Please move it to {Globals.root}/invokeai.init." + logger.warning( + f"Old initialization file found at {legacyinit}. This location is deprecated. Please move it to {Globals.root}/invokeai.init." ) sysargs.insert(0, f"@{legacyinit}") Globals.log_tokenization = self._arg_parser.parse_args( @@ -214,7 +214,7 @@ class Args(object): self._arg_switches = self._arg_parser.parse_args(sysargs) return self._arg_switches except Exception as e: - print(f"An exception has occurred: {e}") + logger.error(f"An exception has occurred: {e}") return None def parse_cmd(self, cmd_string): @@ -1154,7 +1154,7 @@ class Args(object): def format_metadata(**kwargs): - print("format_metadata() is deprecated. Please use metadata_dumps()") + logger.warning("format_metadata() is deprecated. Please use metadata_dumps()") return metadata_dumps(kwargs) @@ -1326,7 +1326,7 @@ def metadata_loads(metadata) -> list: import sys import traceback - print(">> could not read metadata", file=sys.stderr) + logger.error("Could not read metadata") print(traceback.format_exc(), file=sys.stderr) return results diff --git a/invokeai/backend/generate.py b/invokeai/backend/generate.py index 1b19a1aa7e..4f3df60f1c 100644 --- a/invokeai/backend/generate.py +++ b/invokeai/backend/generate.py @@ -27,6 +27,7 @@ from diffusers.utils.import_utils import is_xformers_available from omegaconf import OmegaConf from pathlib import Path +import invokeai.backend.util.logging as logger from .args import metadata_from_png from .generator import infill_methods from .globals import Globals, global_cache_dir @@ -195,12 +196,12 @@ class Generate: # device to Generate(). However the device was then ignored, so # it wasn't actually doing anything. This logic could be reinstated. self.device = torch.device(choose_torch_device()) - print(f">> Using device_type {self.device.type}") + logger.info(f"Using device_type {self.device.type}") if full_precision: if self.precision != "auto": raise ValueError("Remove --full_precision / -F if using --precision") - print("Please remove deprecated --full_precision / -F") - print("If auto config does not work you can use --precision=float32") + logger.warning("Please remove deprecated --full_precision / -F") + logger.warning("If auto config does not work you can use --precision=float32") self.precision = "float32" if self.precision == "auto": self.precision = choose_precision(self.device) @@ -208,13 +209,13 @@ class Generate: if is_xformers_available(): if torch.cuda.is_available() and not Globals.disable_xformers: - print(">> xformers memory-efficient attention is available and enabled") + logger.info("xformers memory-efficient attention is available and enabled") else: - print( - ">> xformers memory-efficient attention is available but disabled" + logger.info( + "xformers memory-efficient attention is available but disabled" ) else: - print(">> xformers not installed") + logger.info("xformers not installed") # model caching system for fast switching self.model_manager = ModelManager( @@ -229,8 +230,8 @@ class Generate: fallback = self.model_manager.default_model() or FALLBACK_MODEL_NAME model = model or fallback if not self.model_manager.valid_model(model): - print( - f'** "{model}" is not a known model name; falling back to {fallback}.' + logger.warning( + f'"{model}" is not a known model name; falling back to {fallback}.' ) model = None self.model_name = model or fallback @@ -246,10 +247,10 @@ class Generate: # load safety checker if requested if safety_checker: - print(">> Initializing NSFW checker") + logger.info("Initializing NSFW checker") self.safety_checker = SafetyChecker(self.device) else: - print(">> NSFW checker is disabled") + logger.info("NSFW checker is disabled") def prompt2png(self, prompt, outdir, **kwargs): """ @@ -567,7 +568,7 @@ class Generate: self.clear_cuda_cache() if catch_interrupts: - print("**Interrupted** Partial results will be returned.") + logger.warning("Interrupted** Partial results will be returned.") else: raise KeyboardInterrupt except RuntimeError: @@ -575,11 +576,11 @@ class Generate: self.clear_cuda_cache() print(traceback.format_exc(), file=sys.stderr) - print(">> Could not generate image.") + logger.info("Could not generate image.") toc = time.time() - print("\n>> Usage stats:") - print(f">> {len(results)} image(s) generated in", "%4.2fs" % (toc - tic)) + logger.info("Usage stats:") + logger.info(f"{len(results)} image(s) generated in "+"%4.2fs" % (toc - tic)) self.print_cuda_stats() return results @@ -609,16 +610,16 @@ class Generate: def print_cuda_stats(self): if self._has_cuda(): self.gather_cuda_stats() - print( - ">> Max VRAM used for this generation:", - "%4.2fG." % (self.max_memory_allocated / 1e9), - "Current VRAM utilization:", - "%4.2fG" % (self.memory_allocated / 1e9), + logger.info( + "Max VRAM used for this generation: "+ + "%4.2fG. " % (self.max_memory_allocated / 1e9)+ + "Current VRAM utilization: "+ + "%4.2fG" % (self.memory_allocated / 1e9) ) - print( - ">> Max VRAM used since script start: ", - "%4.2fG" % (self.session_peakmem / 1e9), + logger.info( + "Max VRAM used since script start: " + + "%4.2fG" % (self.session_peakmem / 1e9) ) # this needs to be generalized to all sorts of postprocessors, which should be wrapped @@ -647,7 +648,7 @@ class Generate: seed = random.randrange(0, np.iinfo(np.uint32).max) prompt = opt.prompt or args.prompt or "" - print(f'>> using seed {seed} and prompt "{prompt}" for {image_path}') + logger.info(f'using seed {seed} and prompt "{prompt}" for {image_path}') # try to reuse the same filename prefix as the original file. # we take everything up to the first period @@ -696,8 +697,8 @@ class Generate: try: extend_instructions[direction] = int(pixels) except ValueError: - print( - '** invalid extension instruction. Use ..., as in "top 64 left 128 right 64 bottom 64"' + logger.warning( + 'invalid extension instruction. Use ..., as in "top 64 left 128 right 64 bottom 64"' ) opt.seed = seed @@ -720,8 +721,8 @@ class Generate: # fetch the metadata from the image generator = self.select_generator(embiggen=True) opt.strength = opt.embiggen_strength or 0.40 - print( - f">> Setting img2img strength to {opt.strength} for happy embiggening" + logger.info( + f"Setting img2img strength to {opt.strength} for happy embiggening" ) generator.generate( prompt, @@ -748,12 +749,12 @@ class Generate: return restorer.process(opt, args, image_callback=callback, prefix=prefix) elif tool is None: - print( - "* please provide at least one postprocessing option, such as -G or -U" + logger.warning( + "please provide at least one postprocessing option, such as -G or -U" ) return None else: - print(f"* postprocessing tool {tool} is not yet supported") + logger.warning(f"postprocessing tool {tool} is not yet supported") return None def select_generator( @@ -797,8 +798,8 @@ class Generate: image = self._load_img(img) if image.width < self.width and image.height < self.height: - print( - f">> WARNING: img2img and inpainting may produce unexpected results with initial images smaller than {self.width}x{self.height} in both dimensions" + logger.warning( + f"img2img and inpainting may produce unexpected results with initial images smaller than {self.width}x{self.height} in both dimensions" ) # if image has a transparent area and no mask was provided, then try to generate mask @@ -809,8 +810,8 @@ class Generate: if (image.width * image.height) > ( self.width * self.height ) and self.size_matters: - print( - ">> This input is larger than your defaults. If you run out of memory, please use a smaller image." + logger.info( + "This input is larger than your defaults. If you run out of memory, please use a smaller image." ) self.size_matters = False @@ -891,11 +892,11 @@ class Generate: try: model_data = cache.get_model(model_name) except Exception as e: - print(f"** model {model_name} could not be loaded: {str(e)}") + logger.warning(f"model {model_name} could not be loaded: {str(e)}") print(traceback.format_exc(), file=sys.stderr) if previous_model_name is None: raise e - print("** trying to reload previous model") + logger.warning("trying to reload previous model") model_data = cache.get_model(previous_model_name) # load previous if model_data is None: raise e @@ -962,15 +963,15 @@ class Generate: if self.gfpgan is not None or self.codeformer is not None: if facetool == "gfpgan": if self.gfpgan is None: - print( - ">> GFPGAN not found. Face restoration is disabled." + logger.info( + "GFPGAN not found. Face restoration is disabled." ) else: image = self.gfpgan.process(image, strength, seed) if facetool == "codeformer": if self.codeformer is None: - print( - ">> CodeFormer not found. Face restoration is disabled." + logger.info( + "CodeFormer not found. Face restoration is disabled." ) else: cf_device = ( @@ -984,7 +985,7 @@ class Generate: fidelity=codeformer_fidelity, ) else: - print(">> Face Restoration is disabled.") + logger.info("Face Restoration is disabled.") if upscale is not None: if self.esrgan is not None: if len(upscale) < 2: @@ -997,10 +998,10 @@ class Generate: denoise_str=upscale_denoise_str, ) else: - print(">> ESRGAN is disabled. Image not upscaled.") + logger.info("ESRGAN is disabled. Image not upscaled.") except Exception as e: - print( - f">> Error running RealESRGAN or GFPGAN. Your image was not upscaled.\n{e}" + logger.info( + f"Error running RealESRGAN or GFPGAN. Your image was not upscaled.\n{e}" ) if image_callback is not None: @@ -1066,17 +1067,17 @@ class Generate: if self.sampler_name in scheduler_map: sampler_class = scheduler_map[self.sampler_name] msg = ( - f">> Setting Sampler to {self.sampler_name} ({sampler_class.__name__})" + f"Setting Sampler to {self.sampler_name} ({sampler_class.__name__})" ) self.sampler = sampler_class.from_config(self.model.scheduler.config) else: msg = ( - f">> Unsupported Sampler: {self.sampler_name} " + f" Unsupported Sampler: {self.sampler_name} "+ f"Defaulting to {default}" ) self.sampler = default - print(msg) + logger.info(msg) if not hasattr(self.sampler, "uses_inpainting_model"): # FIXME: terrible kludge! @@ -1085,17 +1086,17 @@ class Generate: def _load_img(self, img) -> Image: if isinstance(img, Image.Image): image = img - print(f">> using provided input image of size {image.width}x{image.height}") + logger.info(f"using provided input image of size {image.width}x{image.height}") elif isinstance(img, str): - assert os.path.exists(img), f">> {img}: File not found" + assert os.path.exists(img), f"{img}: File not found" image = Image.open(img) - print( - f">> loaded input image of size {image.width}x{image.height} from {img}" + logger.info( + f"loaded input image of size {image.width}x{image.height} from {img}" ) else: image = Image.open(img) - print(f">> loaded input image of size {image.width}x{image.height}") + logger.info(f"loaded input image of size {image.width}x{image.height}") image = ImageOps.exif_transpose(image) return image @@ -1183,14 +1184,14 @@ class Generate: def _transparency_check_and_warning(self, image, mask, force_outpaint=False): if not mask: - print( - ">> Initial image has transparent areas. Will inpaint in these regions." + logger.info( + "Initial image has transparent areas. Will inpaint in these regions." ) - if (not force_outpaint) and self._check_for_erasure(image): - print( - ">> WARNING: Colors underneath the transparent region seem to have been erased.\n", - ">> Inpainting will be suboptimal. Please preserve the colors when making\n", - ">> a transparency mask, or provide mask explicitly using --init_mask (-M).", + if (not force_outpaint) and self._check_for_erasure(image): + logger.info( + "Colors underneath the transparent region seem to have been erased.\n" + + "Inpainting will be suboptimal. Please preserve the colors when making\n" + + "a transparency mask, or provide mask explicitly using --init_mask (-M)." ) def _squeeze_image(self, image): @@ -1201,11 +1202,11 @@ class Generate: def _fit_image(self, image, max_dimensions): w, h = max_dimensions - print(f">> image will be resized to fit inside a box {w}x{h} in size.") + logger.info(f"image will be resized to fit inside a box {w}x{h} in size.") # note that InitImageResizer does the multiple of 64 truncation internally image = InitImageResizer(image).resize(width=w, height=h) - print( - f">> after adjusting image dimensions to be multiples of 64, init image is {image.width}x{image.height}" + logger.info( + f"after adjusting image dimensions to be multiples of 64, init image is {image.width}x{image.height}" ) return image @@ -1216,8 +1217,8 @@ class Generate: ) # resize to integer multiple of 64 if h != height or w != width: if log: - print( - f">> Provided width and height must be multiples of 64. Auto-resizing to {w}x{h}" + logger.info( + f"Provided width and height must be multiples of 64. Auto-resizing to {w}x{h}" ) height = h width = w diff --git a/invokeai/backend/generator/base.py b/invokeai/backend/generator/base.py index ee56077fa8..8ad9dec026 100644 --- a/invokeai/backend/generator/base.py +++ b/invokeai/backend/generator/base.py @@ -25,6 +25,7 @@ from typing import Callable, List, Iterator, Optional, Type from dataclasses import dataclass, field from diffusers.schedulers import SchedulerMixin as Scheduler +import invokeai.backend.util.logging as logger from ..image_util import configure_model_padding from ..util.util import rand_perlin_2d from ..safety_checker import SafetyChecker @@ -372,7 +373,7 @@ class Generator: try: x_T = self.get_noise(width, height) except: - print("** An error occurred while getting initial noise **") + logger.error("An error occurred while getting initial noise") print(traceback.format_exc()) # Pass on the seed in case a layer beneath us needs to generate noise on its own. @@ -607,7 +608,7 @@ class Generator: image = self.sample_to_image(sample) dirname = os.path.dirname(filepath) or "." if not os.path.exists(dirname): - print(f"** creating directory {dirname}") + logger.info(f"creating directory {dirname}") os.makedirs(dirname, exist_ok=True) image.save(filepath, "PNG") diff --git a/invokeai/backend/generator/embiggen.py b/invokeai/backend/generator/embiggen.py index ce9ef4d1b6..6eae5732b0 100644 --- a/invokeai/backend/generator/embiggen.py +++ b/invokeai/backend/generator/embiggen.py @@ -8,10 +8,11 @@ import torch from PIL import Image from tqdm import trange +import invokeai.backend.util.logging as logger + from .base import Generator from .img2img import Img2Img - class Embiggen(Generator): def __init__(self, model, precision): super().__init__(model, precision) @@ -72,22 +73,22 @@ class Embiggen(Generator): embiggen = [1.0] # If not specified, assume no scaling elif embiggen[0] < 0: embiggen[0] = 1.0 - print( - ">> Embiggen scaling factor cannot be negative, fell back to the default of 1.0 !" + logger.warning( + "Embiggen scaling factor cannot be negative, fell back to the default of 1.0 !" ) if len(embiggen) < 2: embiggen.append(0.75) elif embiggen[1] > 1.0 or embiggen[1] < 0: embiggen[1] = 0.75 - print( - ">> Embiggen upscaling strength for ESRGAN must be between 0 and 1, fell back to the default of 0.75 !" + logger.warning( + "Embiggen upscaling strength for ESRGAN must be between 0 and 1, fell back to the default of 0.75 !" ) if len(embiggen) < 3: embiggen.append(0.25) elif embiggen[2] < 0: embiggen[2] = 0.25 - print( - ">> Overlap size for Embiggen must be a positive ratio between 0 and 1 OR a number of pixels, fell back to the default of 0.25 !" + logger.warning( + "Overlap size for Embiggen must be a positive ratio between 0 and 1 OR a number of pixels, fell back to the default of 0.25 !" ) # Convert tiles from their user-freindly count-from-one to count-from-zero, because we need to do modulo math @@ -97,8 +98,8 @@ class Embiggen(Generator): embiggen_tiles.sort() if strength >= 0.5: - print( - f"* WARNING: Embiggen may produce mirror motifs if the strength (-f) is too high (currently {strength}). Try values between 0.35-0.45." + logger.warning( + f"Embiggen may produce mirror motifs if the strength (-f) is too high (currently {strength}). Try values between 0.35-0.45." ) # Prep img2img generator, since we wrap over it @@ -121,8 +122,8 @@ class Embiggen(Generator): from ..restoration.realesrgan import ESRGAN esrgan = ESRGAN() - print( - f">> ESRGAN upscaling init image prior to cutting with Embiggen with strength {embiggen[1]}" + logger.info( + f"ESRGAN upscaling init image prior to cutting with Embiggen with strength {embiggen[1]}" ) if embiggen[0] > 2: initsuperimage = esrgan.process( @@ -312,10 +313,10 @@ class Embiggen(Generator): def make_image(): # Make main tiles ------------------------------------------------- if embiggen_tiles: - print(f">> Making {len(embiggen_tiles)} Embiggen tiles...") + logger.info(f"Making {len(embiggen_tiles)} Embiggen tiles...") else: - print( - f">> Making {(emb_tiles_x * emb_tiles_y)} Embiggen tiles ({emb_tiles_x}x{emb_tiles_y})..." + logger.info( + f"Making {(emb_tiles_x * emb_tiles_y)} Embiggen tiles ({emb_tiles_x}x{emb_tiles_y})..." ) emb_tile_store = [] @@ -361,11 +362,11 @@ class Embiggen(Generator): # newinitimage.save(newinitimagepath) if embiggen_tiles: - print( + logger.debug( f"Making tile #{tile + 1} ({embiggen_tiles.index(tile) + 1} of {len(embiggen_tiles)} requested)" ) else: - print(f"Starting {tile + 1} of {(emb_tiles_x * emb_tiles_y)} tiles") + logger.debug(f"Starting {tile + 1} of {(emb_tiles_x * emb_tiles_y)} tiles") # create a torch tensor from an Image newinitimage = np.array(newinitimage).astype(np.float32) / 255.0 @@ -547,8 +548,8 @@ class Embiggen(Generator): # Layer tile onto final image outputsuperimage.alpha_composite(intileimage, (left, top)) else: - print( - "Error: could not find all Embiggen output tiles in memory? Something must have gone wrong with img2img generation." + logger.error( + "Could not find all Embiggen output tiles in memory? Something must have gone wrong with img2img generation." ) # after internal loops and patching up return Embiggen image diff --git a/invokeai/backend/generator/txt2img2img.py b/invokeai/backend/generator/txt2img2img.py index 1e24a8b729..1257a44fb1 100644 --- a/invokeai/backend/generator/txt2img2img.py +++ b/invokeai/backend/generator/txt2img2img.py @@ -14,6 +14,8 @@ from ..stable_diffusion.diffusers_pipeline import StableDiffusionGeneratorPipeli from ..stable_diffusion.diffusers_pipeline import ConditioningData from ..stable_diffusion.diffusers_pipeline import trim_to_multiple_of +import invokeai.backend.util.logging as logger + class Txt2Img2Img(Generator): def __init__(self, model, precision): super().__init__(model, precision) @@ -77,8 +79,8 @@ class Txt2Img2Img(Generator): # the message below is accurate. init_width = first_pass_latent_output.size()[3] * self.downsampling_factor init_height = first_pass_latent_output.size()[2] * self.downsampling_factor - print( - f"\n>> Interpolating from {init_width}x{init_height} to {width}x{height} using DDIM sampling" + logger.info( + f"Interpolating from {init_width}x{init_height} to {width}x{height} using DDIM sampling" ) # resizing diff --git a/invokeai/backend/image_util/patchmatch.py b/invokeai/backend/image_util/patchmatch.py index 8753298f51..5b5dd75f68 100644 --- a/invokeai/backend/image_util/patchmatch.py +++ b/invokeai/backend/image_util/patchmatch.py @@ -5,10 +5,9 @@ wraps the actual patchmatch object. It respects the global be suppressed or deferred """ import numpy as np - +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals - class PatchMatch: """ Thin class wrapper around the patchmatch function. @@ -28,12 +27,12 @@ class PatchMatch: from patchmatch import patch_match as pm if pm.patchmatch_available: - print(">> Patchmatch initialized") + logger.info("Patchmatch initialized") else: - print(">> Patchmatch not loaded (nonfatal)") + logger.info("Patchmatch not loaded (nonfatal)") self.patch_match = pm else: - print(">> Patchmatch loading disabled") + logger.info("Patchmatch loading disabled") self.tried_load = True @classmethod diff --git a/invokeai/backend/image_util/txt2mask.py b/invokeai/backend/image_util/txt2mask.py index bc7e56d397..248f19d81d 100644 --- a/invokeai/backend/image_util/txt2mask.py +++ b/invokeai/backend/image_util/txt2mask.py @@ -30,9 +30,9 @@ work fine. import numpy as np import torch from PIL import Image, ImageOps -from torchvision import transforms from transformers import AutoProcessor, CLIPSegForImageSegmentation +import invokeai.backend.util.logging as logger from invokeai.backend.globals import global_cache_dir CLIPSEG_MODEL = "CIDAS/clipseg-rd64-refined" @@ -83,7 +83,7 @@ class Txt2Mask(object): """ def __init__(self, device="cpu", refined=False): - print(">> Initializing clipseg model for text to mask inference") + logger.info("Initializing clipseg model for text to mask inference") # BUG: we are not doing anything with the device option at this time self.device = device @@ -101,18 +101,6 @@ class Txt2Mask(object): provided image and returns a SegmentedGrayscale object in which the brighter pixels indicate where the object is inferred to be. """ - transform = transforms.Compose( - [ - transforms.ToTensor(), - transforms.Normalize( - mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] - ), - transforms.Resize( - (CLIPSEG_SIZE, CLIPSEG_SIZE) - ), # must be multiple of 64... - ] - ) - if type(image) is str: image = Image.open(image).convert("RGB") diff --git a/invokeai/backend/model_management/convert_ckpt_to_diffusers.py b/invokeai/backend/model_management/convert_ckpt_to_diffusers.py index b46586611d..8aec5a01d9 100644 --- a/invokeai/backend/model_management/convert_ckpt_to_diffusers.py +++ b/invokeai/backend/model_management/convert_ckpt_to_diffusers.py @@ -25,6 +25,7 @@ from typing import Union import torch from safetensors.torch import load_file +import invokeai.backend.util.logging as logger from invokeai.backend.globals import global_cache_dir, global_config_dir from .model_manager import ModelManager, SDLegacyType @@ -372,9 +373,9 @@ def convert_ldm_unet_checkpoint(checkpoint, config, path=None, extract_ema=False unet_key = "model.diffusion_model." # at least a 100 parameters have to start with `model_ema` in order for the checkpoint to be EMA if sum(k.startswith("model_ema") for k in keys) > 100: - print(f" | Checkpoint {path} has both EMA and non-EMA weights.") + logger.debug(f"Checkpoint {path} has both EMA and non-EMA weights.") if extract_ema: - print(" | Extracting EMA weights (usually better for inference)") + logger.debug("Extracting EMA weights (usually better for inference)") for key in keys: if key.startswith("model.diffusion_model"): flat_ema_key = "model_ema." + "".join(key.split(".")[1:]) @@ -392,8 +393,8 @@ def convert_ldm_unet_checkpoint(checkpoint, config, path=None, extract_ema=False key ) else: - print( - " | Extracting only the non-EMA weights (usually better for fine-tuning)" + logger.debug( + "Extracting only the non-EMA weights (usually better for fine-tuning)" ) for key in keys: @@ -1115,7 +1116,7 @@ def load_pipeline_from_original_stable_diffusion_ckpt( if "global_step" in checkpoint: global_step = checkpoint["global_step"] else: - print(" | global_step key not found in model") + logger.debug("global_step key not found in model") global_step = None # sometimes there is a state_dict key and sometimes not @@ -1229,15 +1230,15 @@ def load_pipeline_from_original_stable_diffusion_ckpt( # If a replacement VAE path was specified, we'll incorporate that into # the checkpoint model and then convert it if vae_path: - print(f" | Converting VAE {vae_path}") + logger.debug(f"Converting VAE {vae_path}") replace_checkpoint_vae(checkpoint,vae_path) # otherwise we use the original VAE, provided that # an externally loaded diffusers VAE was not passed elif not vae: - print(" | Using checkpoint model's original VAE") + logger.debug("Using checkpoint model's original VAE") if vae: - print(" | Using replacement diffusers VAE") + logger.debug("Using replacement diffusers VAE") else: # convert the original or replacement VAE vae_config = create_vae_diffusers_config( original_config, image_size=image_size diff --git a/invokeai/backend/model_management/model_manager.py b/invokeai/backend/model_management/model_manager.py index 534b526081..a0a899a319 100644 --- a/invokeai/backend/model_management/model_manager.py +++ b/invokeai/backend/model_management/model_manager.py @@ -18,12 +18,13 @@ import warnings from enum import Enum, auto from pathlib import Path from shutil import move, rmtree -from typing import Any, Optional, Union, Callable +from typing import Any, Optional, Union, Callable, types import safetensors import safetensors.torch import torch import transformers +import invokeai.backend.util.logging as logger from diffusers import ( AutoencoderKL, UNet2DConditionModel, @@ -75,6 +76,8 @@ class ModelManager(object): Model manager handles loading, caching, importing, deleting, converting, and editing models. """ + logger: types.ModuleType = logger + def __init__( self, config: OmegaConf | Path, @@ -83,6 +86,7 @@ class ModelManager(object): max_loaded_models=DEFAULT_MAX_MODELS, sequential_offload=False, embedding_path: Path = None, + logger: types.ModuleType = logger, ): """ Initialize with the path to the models.yaml config file or @@ -104,6 +108,7 @@ class ModelManager(object): self.current_model = None self.sequential_offload = sequential_offload self.embedding_path = embedding_path + self.logger = logger def valid_model(self, model_name: str) -> bool: """ @@ -132,8 +137,8 @@ class ModelManager(object): ) if not self.valid_model(model_name): - print( - f'** "{model_name}" is not a known model name. Please check your models.yaml file' + self.logger.error( + f'"{model_name}" is not a known model name. Please check your models.yaml file' ) return self.current_model @@ -144,7 +149,7 @@ class ModelManager(object): if model_name in self.models: requested_model = self.models[model_name]["model"] - print(f">> Retrieving model {model_name} from system RAM cache") + self.logger.info(f"Retrieving model {model_name} from system RAM cache") requested_model.ready() width = self.models[model_name]["width"] height = self.models[model_name]["height"] @@ -379,7 +384,7 @@ class ModelManager(object): """ omega = self.config if model_name not in omega: - print(f"** Unknown model {model_name}") + self.logger.error(f"Unknown model {model_name}") return # save these for use in deletion later conf = omega[model_name] @@ -392,13 +397,13 @@ class ModelManager(object): self.stack.remove(model_name) if delete_files: if weights: - print(f"** Deleting file {weights}") + self.logger.info(f"Deleting file {weights}") Path(weights).unlink(missing_ok=True) elif path: - print(f"** Deleting directory {path}") + self.logger.info(f"Deleting directory {path}") rmtree(path, ignore_errors=True) elif repo_id: - print(f"** Deleting the cached model directory for {repo_id}") + self.logger.info(f"Deleting the cached model directory for {repo_id}") self._delete_model_from_cache(repo_id) def add_model( @@ -439,7 +444,7 @@ class ModelManager(object): def _load_model(self, model_name: str): """Load and initialize the model from configuration variables passed at object creation time""" if model_name not in self.config: - print( + self.logger.error( f'"{model_name}" is not a known model name. Please check your models.yaml file' ) return @@ -457,7 +462,7 @@ class ModelManager(object): model_format = mconfig.get("format", "ckpt") if model_format == "ckpt": weights = mconfig.weights - print(f">> Loading {model_name} from {weights}") + self.logger.info(f"Loading {model_name} from {weights}") model, width, height, model_hash = self._load_ckpt_model( model_name, mconfig ) @@ -473,13 +478,15 @@ class ModelManager(object): # usage statistics toc = time.time() - print(">> Model loaded in", "%4.2fs" % (toc - tic)) + self.logger.info("Model loaded in " + "%4.2fs" % (toc - tic)) if self._has_cuda(): - print( - ">> Max VRAM used to load the model:", - "%4.2fG" % (torch.cuda.max_memory_allocated() / 1e9), - "\n>> Current VRAM usage:" - "%4.2fG" % (torch.cuda.memory_allocated() / 1e9), + self.logger.info( + "Max VRAM used to load the model: "+ + "%4.2fG" % (torch.cuda.max_memory_allocated() / 1e9) + ) + self.logger.info( + "Current VRAM usage: "+ + "%4.2fG" % (torch.cuda.memory_allocated() / 1e9) ) return model, width, height, model_hash @@ -487,11 +494,11 @@ class ModelManager(object): name_or_path = self.model_name_or_path(mconfig) using_fp16 = self.precision == "float16" - print(f">> Loading diffusers model from {name_or_path}") + self.logger.info(f"Loading diffusers model from {name_or_path}") if using_fp16: - print(" | Using faster float16 precision") + self.logger.debug("Using faster float16 precision") else: - print(" | Using more accurate float32 precision") + self.logger.debug("Using more accurate float32 precision") # TODO: scan weights maybe? pipeline_args: dict[str, Any] = dict( @@ -523,8 +530,8 @@ class ModelManager(object): if str(e).startswith("fp16 is not a valid"): pass else: - print( - f"** An unexpected error occurred while downloading the model: {e})" + self.logger.error( + f"An unexpected error occurred while downloading the model: {e})" ) if pipeline: break @@ -542,7 +549,7 @@ class ModelManager(object): # square images??? width = pipeline.unet.config.sample_size * pipeline.vae_scale_factor height = width - print(f" | Default image dimensions = {width} x {height}") + self.logger.debug(f"Default image dimensions = {width} x {height}") return pipeline, width, height, model_hash @@ -559,14 +566,14 @@ class ModelManager(object): weights = os.path.normpath(os.path.join(Globals.root, weights)) # Convert to diffusers and return a diffusers pipeline - print(f">> Converting legacy checkpoint {model_name} into a diffusers model...") + self.logger.info(f"Converting legacy checkpoint {model_name} into a diffusers model...") from . import load_pipeline_from_original_stable_diffusion_ckpt try: if self.list_models()[self.current_model]["status"] == "active": self.offload_model(self.current_model) - except Exception as e: + except Exception: pass vae_path = None @@ -624,7 +631,7 @@ class ModelManager(object): if model_name not in self.models: return - print(f">> Offloading {model_name} to CPU") + self.logger.info(f"Offloading {model_name} to CPU") model = self.models[model_name]["model"] model.offload_all() self.current_model = None @@ -640,30 +647,26 @@ class ModelManager(object): and option to exit if an infected file is identified. """ # scan model - print(f" | Scanning Model: {model_name}") + self.logger.debug(f"Scanning Model: {model_name}") scan_result = scan_file_path(checkpoint) if scan_result.infected_files != 0: if scan_result.infected_files == 1: - print(f"\n### Issues Found In Model: {scan_result.issues_count}") - print( - "### WARNING: The model you are trying to load seems to be infected." - ) - print("### For your safety, InvokeAI will not load this model.") - print("### Please use checkpoints from trusted sources.") - print("### Exiting InvokeAI") + self.logger.critical(f"Issues Found In Model: {scan_result.issues_count}") + self.logger.critical("The model you are trying to load seems to be infected.") + self.logger.critical("For your safety, InvokeAI will not load this model.") + self.logger.critical("Please use checkpoints from trusted sources.") + self.logger.critical("Exiting InvokeAI") sys.exit() else: - print( - "\n### WARNING: InvokeAI was unable to scan the model you are using." - ) + self.logger.warning("InvokeAI was unable to scan the model you are using.") model_safe_check_fail = ask_user( "Do you want to to continue loading the model?", ["y", "n"] ) if model_safe_check_fail.lower() != "y": - print("### Exiting InvokeAI") + self.logger.critical("Exiting InvokeAI") sys.exit() else: - print(" | Model scanned ok") + self.logger.debug("Model scanned ok") def import_diffuser_model( self, @@ -780,26 +783,24 @@ class ModelManager(object): model_path: Path = None thing = path_url_or_repo # to save typing - print(f">> Probing {thing} for import") + self.logger.info(f"Probing {thing} for import") if thing.startswith(("http:", "https:", "ftp:")): - print(f" | {thing} appears to be a URL") + self.logger.info(f"{thing} appears to be a URL") model_path = self._resolve_path( thing, "models/ldm/stable-diffusion-v1" ) # _resolve_path does a download if needed elif Path(thing).is_file() and thing.endswith((".ckpt", ".safetensors")): if Path(thing).stem in ["model", "diffusion_pytorch_model"]: - print( - f" | {Path(thing).name} appears to be part of a diffusers model. Skipping import" - ) + self.logger.debug(f"{Path(thing).name} appears to be part of a diffusers model. Skipping import") return else: - print(f" | {thing} appears to be a checkpoint file on disk") + self.logger.debug(f"{thing} appears to be a checkpoint file on disk") model_path = self._resolve_path(thing, "models/ldm/stable-diffusion-v1") elif Path(thing).is_dir() and Path(thing, "model_index.json").exists(): - print(f" | {thing} appears to be a diffusers file on disk") + self.logger.debug(f"{thing} appears to be a diffusers file on disk") model_name = self.import_diffuser_model( thing, vae=dict(repo_id="stabilityai/sd-vae-ft-mse"), @@ -810,34 +811,30 @@ class ModelManager(object): elif Path(thing).is_dir(): if (Path(thing) / "model_index.json").exists(): - print(f" | {thing} appears to be a diffusers model.") + self.logger.debug(f"{thing} appears to be a diffusers model.") model_name = self.import_diffuser_model( thing, commit_to_conf=commit_to_conf ) else: - print( - f" |{thing} appears to be a directory. Will scan for models to import" - ) + self.logger.debug(f"{thing} appears to be a directory. Will scan for models to import") for m in list(Path(thing).rglob("*.ckpt")) + list( Path(thing).rglob("*.safetensors") ): if model_name := self.heuristic_import( str(m), commit_to_conf=commit_to_conf ): - print(f" >> {model_name} successfully imported") + self.logger.info(f"{model_name} successfully imported") return model_name elif re.match(r"^[\w.+-]+/[\w.+-]+$", thing): - print(f" | {thing} appears to be a HuggingFace diffusers repo_id") + self.logger.debug(f"{thing} appears to be a HuggingFace diffusers repo_id") model_name = self.import_diffuser_model( thing, commit_to_conf=commit_to_conf ) pipeline, _, _, _ = self._load_diffusers_model(self.config[model_name]) return model_name else: - print( - f"** {thing}: Unknown thing. Please provide a URL, file path, directory or HuggingFace repo_id" - ) + self.logger.warning(f"{thing}: Unknown thing. Please provide a URL, file path, directory or HuggingFace repo_id") # Model_path is set in the event of a legacy checkpoint file. # If not set, we're all done @@ -845,7 +842,7 @@ class ModelManager(object): return if model_path.stem in self.config: # already imported - print(" | Already imported. Skipping") + self.logger.debug("Already imported. Skipping") return model_path.stem # another round of heuristics to guess the correct config file. @@ -861,39 +858,39 @@ class ModelManager(object): # look for a like-named .yaml file in same directory if model_path.with_suffix(".yaml").exists(): model_config_file = model_path.with_suffix(".yaml") - print(f" | Using config file {model_config_file.name}") + self.logger.debug(f"Using config file {model_config_file.name}") else: model_type = self.probe_model_type(checkpoint) if model_type == SDLegacyType.V1: - print(" | SD-v1 model detected") + self.logger.debug("SD-v1 model detected") model_config_file = Path( Globals.root, "configs/stable-diffusion/v1-inference.yaml" ) elif model_type == SDLegacyType.V1_INPAINT: - print(" | SD-v1 inpainting model detected") + self.logger.debug("SD-v1 inpainting model detected") model_config_file = Path( Globals.root, "configs/stable-diffusion/v1-inpainting-inference.yaml", ) elif model_type == SDLegacyType.V2_v: - print(" | SD-v2-v model detected") + self.logger.debug("SD-v2-v model detected") model_config_file = Path( Globals.root, "configs/stable-diffusion/v2-inference-v.yaml" ) elif model_type == SDLegacyType.V2_e: - print(" | SD-v2-e model detected") + self.logger.debug("SD-v2-e model detected") model_config_file = Path( Globals.root, "configs/stable-diffusion/v2-inference.yaml" ) elif model_type == SDLegacyType.V2: - print( - f"** {thing} is a V2 checkpoint file, but its parameterization cannot be determined. Please provide configuration file path." + self.logger.warning( + f"{thing} is a V2 checkpoint file, but its parameterization cannot be determined. Please provide configuration file path." ) return else: - print( - f"** {thing} is a legacy checkpoint file but not a known Stable Diffusion model. Please provide configuration file path." + self.logger.warning( + f"{thing} is a legacy checkpoint file but not a known Stable Diffusion model. Please provide configuration file path." ) return @@ -909,7 +906,7 @@ class ModelManager(object): for suffix in ["pt", "ckpt", "safetensors"]: if (model_path.with_suffix(f".vae.{suffix}")).exists(): vae_path = model_path.with_suffix(f".vae.{suffix}") - print(f" | Using VAE file {vae_path.name}") + self.logger.debug(f"Using VAE file {vae_path.name}") vae = None if vae_path else dict(repo_id="stabilityai/sd-vae-ft-mse") diffuser_path = Path( @@ -955,14 +952,14 @@ class ModelManager(object): from . import convert_ckpt_to_diffusers if diffusers_path.exists(): - print( - f"ERROR: The path {str(diffusers_path)} already exists. Please move or remove it and try again." + self.logger.error( + f"The path {str(diffusers_path)} already exists. Please move or remove it and try again." ) return model_name = model_name or diffusers_path.name model_description = model_description or f"Converted version of {model_name}" - print(f" | Converting {model_name} to diffusers (30-60s)") + self.logger.debug(f"Converting {model_name} to diffusers (30-60s)") try: # By passing the specified VAE to the conversion function, the autoencoder # will be built into the model rather than tacked on afterward via the config file @@ -979,10 +976,10 @@ class ModelManager(object): vae_path=vae_path, scan_needed=scan_needed, ) - print( - f" | Success. Converted model is now located at {str(diffusers_path)}" + self.logger.debug( + f"Success. Converted model is now located at {str(diffusers_path)}" ) - print(f" | Writing new config file entry for {model_name}") + self.logger.debug(f"Writing new config file entry for {model_name}") new_config = dict( path=str(diffusers_path), description=model_description, @@ -993,17 +990,17 @@ class ModelManager(object): self.add_model(model_name, new_config, True) if commit_to_conf: self.commit(commit_to_conf) - print(" | Conversion succeeded") + self.logger.debug("Conversion succeeded") except Exception as e: - print(f"** Conversion failed: {str(e)}") - print( - "** If you are trying to convert an inpainting or 2.X model, please indicate the correct config file (e.g. v1-inpainting-inference.yaml)" + self.logger.warning(f"Conversion failed: {str(e)}") + self.logger.warning( + "If you are trying to convert an inpainting or 2.X model, please indicate the correct config file (e.g. v1-inpainting-inference.yaml)" ) return model_name def search_models(self, search_folder): - print(f">> Finding Models In: {search_folder}") + self.logger.info(f"Finding Models In: {search_folder}") models_folder_ckpt = Path(search_folder).glob("**/*.ckpt") models_folder_safetensors = Path(search_folder).glob("**/*.safetensors") @@ -1027,8 +1024,8 @@ class ModelManager(object): num_loaded_models = len(self.models) if num_loaded_models >= self.max_loaded_models: least_recent_model = self._pop_oldest_model() - print( - f">> Cache limit (max={self.max_loaded_models}) reached. Purging {least_recent_model}" + self.logger.info( + f"Cache limit (max={self.max_loaded_models}) reached. Purging {least_recent_model}" ) if least_recent_model is not None: del self.models[least_recent_model] @@ -1036,8 +1033,8 @@ class ModelManager(object): def print_vram_usage(self) -> None: if self._has_cuda: - print( - ">> Current VRAM usage: ", + self.logger.info( + "Current VRAM usage:"+ "%4.2fG" % (torch.cuda.memory_allocated() / 1e9), ) @@ -1126,10 +1123,10 @@ class ModelManager(object): dest = hub / model.stem if dest.exists() and not source.exists(): continue - print(f"** {source} => {dest}") + cls.logger.info(f"{source} => {dest}") if source.exists(): if dest.is_symlink(): - print(f"** Found symlink at {dest.name}. Not migrating.") + logger.warning(f"Found symlink at {dest.name}. Not migrating.") elif dest.exists(): if source.is_dir(): rmtree(source) @@ -1146,7 +1143,7 @@ class ModelManager(object): ] for d in empty: os.rmdir(d) - print("** Migration is done. Continuing...") + cls.logger.info("Migration is done. Continuing...") def _resolve_path( self, source: Union[str, Path], dest_directory: str @@ -1189,15 +1186,15 @@ class ModelManager(object): def _add_embeddings_to_model(self, model: StableDiffusionGeneratorPipeline): if self.embedding_path is not None: - print(f">> Loading embeddings from {self.embedding_path}") + self.logger.info(f"Loading embeddings from {self.embedding_path}") for root, _, files in os.walk(self.embedding_path): for name in files: ti_path = os.path.join(root, name) model.textual_inversion_manager.load_textual_inversion( ti_path, defer_injecting_tokens=True ) - print( - f'>> Textual inversion triggers: {", ".join(sorted(model.textual_inversion_manager.get_all_trigger_strings()))}' + self.logger.info( + f'Textual inversion triggers: {", ".join(sorted(model.textual_inversion_manager.get_all_trigger_strings()))}' ) def _has_cuda(self) -> bool: @@ -1219,7 +1216,7 @@ class ModelManager(object): with open(hashpath) as f: hash = f.read() return hash - print(" | Calculating sha256 hash of model files") + self.logger.debug("Calculating sha256 hash of model files") tic = time.time() sha = hashlib.sha256() count = 0 @@ -1231,7 +1228,7 @@ class ModelManager(object): sha.update(chunk) hash = sha.hexdigest() toc = time.time() - print(f" | sha256 = {hash} ({count} files hashed in", "%4.2fs)" % (toc - tic)) + self.logger.debug(f"sha256 = {hash} ({count} files hashed in", "%4.2fs)" % (toc - tic)) with open(hashpath, "w") as f: f.write(hash) return hash @@ -1249,13 +1246,13 @@ class ModelManager(object): hash = f.read() return hash - print(" | Calculating sha256 hash of weights file") + self.logger.debug("Calculating sha256 hash of weights file") tic = time.time() sha = hashlib.sha256() sha.update(data) hash = sha.hexdigest() toc = time.time() - print(f">> sha256 = {hash}", "(%4.2fs)" % (toc - tic)) + self.logger.debug(f"sha256 = {hash} "+"(%4.2fs)" % (toc - tic)) with open(hashpath, "w") as f: f.write(hash) @@ -1276,12 +1273,12 @@ class ModelManager(object): local_files_only=not Globals.internet_available, ) - print(f" | Loading diffusers VAE from {name_or_path}") + self.logger.debug(f"Loading diffusers VAE from {name_or_path}") if using_fp16: vae_args.update(torch_dtype=torch.float16) fp_args_list = [{"revision": "fp16"}, {}] else: - print(" | Using more accurate float32 precision") + self.logger.debug("Using more accurate float32 precision") fp_args_list = [{}] vae = None @@ -1305,12 +1302,12 @@ class ModelManager(object): break if not vae and deferred_error: - print(f"** Could not load VAE {name_or_path}: {str(deferred_error)}") + self.logger.warning(f"Could not load VAE {name_or_path}: {str(deferred_error)}") return vae - @staticmethod - def _delete_model_from_cache(repo_id): + @classmethod + def _delete_model_from_cache(cls,repo_id): cache_info = scan_cache_dir(global_cache_dir("hub")) # I'm sure there is a way to do this with comprehensions @@ -1321,8 +1318,8 @@ class ModelManager(object): for revision in repo.revisions: hashes_to_delete.add(revision.commit_hash) strategy = cache_info.delete_revisions(*hashes_to_delete) - print( - f"** Deletion of this model is expected to free {strategy.expected_freed_size_str}" + cls.logger.warning( + f"Deletion of this model is expected to free {strategy.expected_freed_size_str}" ) strategy.execute() diff --git a/invokeai/backend/prompting/conditioning.py b/invokeai/backend/prompting/conditioning.py index 1ddae1e93d..d9130ace04 100644 --- a/invokeai/backend/prompting/conditioning.py +++ b/invokeai/backend/prompting/conditioning.py @@ -18,6 +18,7 @@ from compel.prompt_parser import ( PromptParser, ) +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals from ..stable_diffusion import InvokeAIDiffuserComponent @@ -162,8 +163,8 @@ def log_tokenization( negative_prompt: Union[Blend, FlattenedPrompt], tokenizer, ): - print(f"\n>> [TOKENLOG] Parsed Prompt: {positive_prompt}") - print(f"\n>> [TOKENLOG] Parsed Negative Prompt: {negative_prompt}") + logger.info(f"[TOKENLOG] Parsed Prompt: {positive_prompt}") + logger.info(f"[TOKENLOG] Parsed Negative Prompt: {negative_prompt}") log_tokenization_for_prompt_object(positive_prompt, tokenizer) log_tokenization_for_prompt_object( @@ -237,12 +238,12 @@ def log_tokenization_for_text(text, tokenizer, display_label=None, truncate_if_t usedTokens += 1 if usedTokens > 0: - print(f'\n>> [TOKENLOG] Tokens {display_label or ""} ({usedTokens}):') - print(f"{tokenized}\x1b[0m") + logger.info(f'[TOKENLOG] Tokens {display_label or ""} ({usedTokens}):') + logger.debug(f"{tokenized}\x1b[0m") if discarded != "": - print(f"\n>> [TOKENLOG] Tokens Discarded ({totalTokens - usedTokens}):") - print(f"{discarded}\x1b[0m") + logger.info(f"[TOKENLOG] Tokens Discarded ({totalTokens - usedTokens}):") + logger.debug(f"{discarded}\x1b[0m") def try_parse_legacy_blend(text: str, skip_normalize: bool = False) -> Optional[Blend]: @@ -295,8 +296,8 @@ def split_weighted_subprompts(text, skip_normalize=False) -> list: return parsed_prompts weight_sum = sum(map(lambda x: x[1], parsed_prompts)) if weight_sum == 0: - print( - "* Warning: Subprompt weights add up to zero. Discarding and using even weights instead." + logger.warning( + "Subprompt weights add up to zero. Discarding and using even weights instead." ) equal_weight = 1 / max(len(parsed_prompts), 1) return [(x[0], equal_weight) for x in parsed_prompts] diff --git a/invokeai/backend/restoration/base.py b/invokeai/backend/restoration/base.py index 0957811fc3..f6f01da17d 100644 --- a/invokeai/backend/restoration/base.py +++ b/invokeai/backend/restoration/base.py @@ -1,3 +1,5 @@ +import invokeai.backend.util.logging as logger + class Restoration: def __init__(self) -> None: pass @@ -8,17 +10,17 @@ class Restoration: # Load GFPGAN gfpgan = self.load_gfpgan(gfpgan_model_path) if gfpgan.gfpgan_model_exists: - print(">> GFPGAN Initialized") + logger.info("GFPGAN Initialized") else: - print(">> GFPGAN Disabled") + logger.info("GFPGAN Disabled") gfpgan = None # Load CodeFormer codeformer = self.load_codeformer() if codeformer.codeformer_model_exists: - print(">> CodeFormer Initialized") + logger.info("CodeFormer Initialized") else: - print(">> CodeFormer Disabled") + logger.info("CodeFormer Disabled") codeformer = None return gfpgan, codeformer @@ -39,5 +41,5 @@ class Restoration: from .realesrgan import ESRGAN esrgan = ESRGAN(esrgan_bg_tile) - print(">> ESRGAN Initialized") + logger.info("ESRGAN Initialized") return esrgan diff --git a/invokeai/backend/restoration/codeformer.py b/invokeai/backend/restoration/codeformer.py index 94add72b00..5b578af082 100644 --- a/invokeai/backend/restoration/codeformer.py +++ b/invokeai/backend/restoration/codeformer.py @@ -5,6 +5,7 @@ import warnings import numpy as np import torch +import invokeai.backend.util.logging as logger from ..globals import Globals pretrained_model_url = ( @@ -23,12 +24,12 @@ class CodeFormerRestoration: self.codeformer_model_exists = os.path.isfile(self.model_path) if not self.codeformer_model_exists: - print("## NOT FOUND: CodeFormer model not found at " + self.model_path) + logger.error("NOT FOUND: CodeFormer model not found at " + self.model_path) sys.path.append(os.path.abspath(codeformer_dir)) def process(self, image, strength, device, seed=None, fidelity=0.75): if seed is not None: - print(f">> CodeFormer - Restoring Faces for image seed:{seed}") + logger.info(f"CodeFormer - Restoring Faces for image seed:{seed}") with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) warnings.filterwarnings("ignore", category=UserWarning) @@ -97,7 +98,7 @@ class CodeFormerRestoration: del output torch.cuda.empty_cache() except RuntimeError as error: - print(f"\tFailed inference for CodeFormer: {error}.") + logger.error(f"Failed inference for CodeFormer: {error}.") restored_face = cropped_face restored_face = restored_face.astype("uint8") diff --git a/invokeai/backend/restoration/gfpgan.py b/invokeai/backend/restoration/gfpgan.py index d13745d0c6..b5c0278362 100644 --- a/invokeai/backend/restoration/gfpgan.py +++ b/invokeai/backend/restoration/gfpgan.py @@ -6,9 +6,9 @@ import numpy as np import torch from PIL import Image +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals - class GFPGAN: def __init__(self, gfpgan_model_path="models/gfpgan/GFPGANv1.4.pth") -> None: if not os.path.isabs(gfpgan_model_path): @@ -19,7 +19,7 @@ class GFPGAN: self.gfpgan_model_exists = os.path.isfile(self.model_path) if not self.gfpgan_model_exists: - print("## NOT FOUND: GFPGAN model not found at " + self.model_path) + logger.error("NOT FOUND: GFPGAN model not found at " + self.model_path) return None def model_exists(self): @@ -27,7 +27,7 @@ class GFPGAN: def process(self, image, strength: float, seed: str = None): if seed is not None: - print(f">> GFPGAN - Restoring Faces for image seed:{seed}") + logger.info(f"GFPGAN - Restoring Faces for image seed:{seed}") with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) @@ -47,14 +47,14 @@ class GFPGAN: except Exception: import traceback - print(">> Error loading GFPGAN:", file=sys.stderr) + logger.error("Error loading GFPGAN:", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) os.chdir(cwd) if self.gfpgan is None: - print(f">> WARNING: GFPGAN not initialized.") - print( - f">> Download https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth to {self.model_path}" + logger.warning("WARNING: GFPGAN not initialized.") + logger.warning( + f"Download https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth to {self.model_path}" ) image = image.convert("RGB") diff --git a/invokeai/backend/restoration/outcrop.py b/invokeai/backend/restoration/outcrop.py index e0f110f71e..07f76d6bf9 100644 --- a/invokeai/backend/restoration/outcrop.py +++ b/invokeai/backend/restoration/outcrop.py @@ -1,7 +1,7 @@ import math from PIL import Image - +import invokeai.backend.util.logging as logger class Outcrop(object): def __init__( @@ -82,7 +82,7 @@ class Outcrop(object): pixels = extents[direction] # round pixels up to the nearest 64 pixels = math.ceil(pixels / 64) * 64 - print(f">> extending image {direction}ward by {pixels} pixels") + logger.info(f"extending image {direction}ward by {pixels} pixels") image = self._rotate(image, direction) image = self._extend(image, pixels) image = self._rotate(image, direction, reverse=True) diff --git a/invokeai/backend/restoration/realesrgan.py b/invokeai/backend/restoration/realesrgan.py index ad6ad556f1..9f26cc63ac 100644 --- a/invokeai/backend/restoration/realesrgan.py +++ b/invokeai/backend/restoration/realesrgan.py @@ -6,18 +6,13 @@ import torch from PIL import Image from PIL.Image import Image as ImageType +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals - class ESRGAN: def __init__(self, bg_tile_size=400) -> None: self.bg_tile_size = bg_tile_size - if not torch.cuda.is_available(): # CPU or MPS on M1 - use_half_precision = False - else: - use_half_precision = True - def load_esrgan_bg_upsampler(self, denoise_str): if not torch.cuda.is_available(): # CPU or MPS on M1 use_half_precision = False @@ -74,16 +69,16 @@ class ESRGAN: import sys import traceback - print(">> Error loading Real-ESRGAN:", file=sys.stderr) + logger.error("Error loading Real-ESRGAN:") print(traceback.format_exc(), file=sys.stderr) if upsampler_scale == 0: - print(">> Real-ESRGAN: Invalid scaling option. Image not upscaled.") + logger.warning("Real-ESRGAN: Invalid scaling option. Image not upscaled.") return image if seed is not None: - print( - f">> Real-ESRGAN Upscaling seed:{seed}, scale:{upsampler_scale}x, tile:{self.bg_tile_size}, denoise:{denoise_str}" + logger.info( + f"Real-ESRGAN Upscaling seed:{seed}, scale:{upsampler_scale}x, tile:{self.bg_tile_size}, denoise:{denoise_str}" ) # ESRGAN outputs images with partial transparency if given RGBA images; convert to RGB image = image.convert("RGB") diff --git a/invokeai/backend/safety_checker.py b/invokeai/backend/safety_checker.py index 2e6c4fd479..3003981888 100644 --- a/invokeai/backend/safety_checker.py +++ b/invokeai/backend/safety_checker.py @@ -14,6 +14,7 @@ from PIL import Image, ImageFilter from transformers import AutoFeatureExtractor import invokeai.assets.web as web_assets +import invokeai.backend.util.logging as logger from .globals import global_cache_dir from .util import CPU_DEVICE @@ -40,8 +41,8 @@ class SafetyChecker(object): cache_dir=safety_model_path, ) except Exception: - print( - "** An error was encountered while installing the safety checker:" + logger.error( + "An error was encountered while installing the safety checker:" ) print(traceback.format_exc()) @@ -65,8 +66,8 @@ class SafetyChecker(object): ) self.safety_checker.to(CPU_DEVICE) # offload if has_nsfw_concept[0]: - print( - "** An image with potential non-safe content has been detected. A blurred image will be returned. **" + logger.warning( + "An image with potential non-safe content has been detected. A blurred image will be returned." ) return self.blur(image) else: diff --git a/invokeai/backend/stable_diffusion/concepts_lib.py b/invokeai/backend/stable_diffusion/concepts_lib.py index 129dd430f4..ebbcc9c3e9 100644 --- a/invokeai/backend/stable_diffusion/concepts_lib.py +++ b/invokeai/backend/stable_diffusion/concepts_lib.py @@ -17,6 +17,7 @@ from huggingface_hub import ( hf_hub_url, ) +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals @@ -66,11 +67,11 @@ class HuggingFaceConceptsLibrary(object): # when init, add all in dir. when not init, add only concepts added between init and now self.concept_list.extend(list(local_concepts_to_add)) except Exception as e: - print( - f" ** WARNING: Hugging Face textual inversion concepts libraries could not be loaded. The error was {str(e)}." + logger.warning( + f"Hugging Face textual inversion concepts libraries could not be loaded. The error was {str(e)}." ) - print( - " ** You may load .bin and .pt file(s) manually using the --embedding_directory argument." + logger.warning( + "You may load .bin and .pt file(s) manually using the --embedding_directory argument." ) return self.concept_list else: @@ -83,7 +84,7 @@ class HuggingFaceConceptsLibrary(object): be downloaded. """ if not concept_name in self.list_concepts(): - print( + logger.warning( f"{concept_name} is not a local embedding trigger, nor is it a HuggingFace concept. Generation will continue without the concept." ) return None @@ -221,7 +222,7 @@ class HuggingFaceConceptsLibrary(object): if chunk == 0: bytes += total - print(f">> Downloading {repo_id}...", end="") + logger.info(f"Downloading {repo_id}...", end="") try: for file in ( "README.md", @@ -235,22 +236,22 @@ class HuggingFaceConceptsLibrary(object): ) except ul_error.HTTPError as e: if e.code == 404: - print( + logger.warning( f"Concept {concept_name} is not known to the Hugging Face library. Generation will continue without the concept." ) else: - print( + logger.warning( f"Failed to download {concept_name}/{file} ({str(e)}. Generation will continue without the concept.)" ) os.rmdir(dest) return False except ul_error.URLError as e: - print( - f"ERROR while downloading {concept_name}: {str(e)}. This may reflect a network issue. Generation will continue without the concept." + logger.error( + f"an error occurred while downloading {concept_name}: {str(e)}. This may reflect a network issue. Generation will continue without the concept." ) os.rmdir(dest) return False - print("...{:.2f}Kb".format(bytes / 1024)) + logger.info("...{:.2f}Kb".format(bytes / 1024)) return succeeded def _concept_id(self, concept_name: str) -> str: diff --git a/invokeai/backend/stable_diffusion/diffusion/cross_attention_control.py b/invokeai/backend/stable_diffusion/diffusion/cross_attention_control.py index d6c90503fe..dfd19ea964 100644 --- a/invokeai/backend/stable_diffusion/diffusion/cross_attention_control.py +++ b/invokeai/backend/stable_diffusion/diffusion/cross_attention_control.py @@ -13,9 +13,9 @@ from compel.cross_attention_control import Arguments from diffusers.models.attention_processor import AttentionProcessor from torch import nn +import invokeai.backend.util.logging as logger from ...util import torch_dtype - class CrossAttentionType(enum.Enum): SELF = 1 TOKENS = 2 @@ -421,7 +421,7 @@ def get_cross_attention_modules( expected_count = 16 if cross_attention_modules_in_model_count != expected_count: # non-fatal error but .swap() won't work. - print( + logger.error( f"Error! CrossAttentionControl found an unexpected number of {cross_attention_class} modules in the model " + f"(expected {expected_count}, found {cross_attention_modules_in_model_count}). Either monkey-patching failed " + "or some assumption has changed about the structure of the model itself. Please fix the monkey-patching, " diff --git a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py index 1137aa52e4..b0c85e9fd3 100644 --- a/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py +++ b/invokeai/backend/stable_diffusion/diffusion/shared_invokeai_diffusion.py @@ -8,6 +8,7 @@ import torch from diffusers.models.attention_processor import AttentionProcessor from typing_extensions import TypeAlias +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals from .cross_attention_control import ( @@ -466,10 +467,14 @@ class InvokeAIDiffuserComponent: outside = torch.count_nonzero( (latents < -current_threshold) | (latents > current_threshold) ) - print( - f"\nThreshold: %={percent_through} threshold={current_threshold:.3f} (of {threshold:.3f})\n" - f" | min, mean, max = {minval:.3f}, {mean:.3f}, {maxval:.3f}\tstd={std}\n" - f" | {outside / latents.numel() * 100:.2f}% values outside threshold" + logger.info( + f"Threshold: %={percent_through} threshold={current_threshold:.3f} (of {threshold:.3f})" + ) + logger.debug( + f"min, mean, max = {minval:.3f}, {mean:.3f}, {maxval:.3f}\tstd={std}" + ) + logger.debug( + f"{outside / latents.numel() * 100:.2f}% values outside threshold" ) if maxval < current_threshold and minval > -current_threshold: @@ -496,9 +501,11 @@ class InvokeAIDiffuserComponent: ) if self.debug_thresholding: - print( - f" | min, , max = {minval:.3f}, , {maxval:.3f}\t(scaled by {scale})\n" - f" | {num_altered / latents.numel() * 100:.2f}% values altered" + logger.debug( + f"min, , max = {minval:.3f}, , {maxval:.3f}\t(scaled by {scale})" + ) + logger.debug( + f"{num_altered / latents.numel() * 100:.2f}% values altered" ) return latents diff --git a/invokeai/backend/stable_diffusion/image_degradation/utils_image.py b/invokeai/backend/stable_diffusion/image_degradation/utils_image.py index 08505edde0..c4d37a24bf 100644 --- a/invokeai/backend/stable_diffusion/image_degradation/utils_image.py +++ b/invokeai/backend/stable_diffusion/image_degradation/utils_image.py @@ -10,7 +10,7 @@ from torchvision.utils import make_grid # import matplotlib.pyplot as plt # TODO: check with Dominik, also bsrgan.py vs bsrgan_light.py - +import invokeai.backend.util.logging as logger os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" @@ -191,7 +191,7 @@ def mkdirs(paths): def mkdir_and_rename(path): if os.path.exists(path): new_name = path + "_archived_" + get_timestamp() - print("Path already exists. Rename it to [{:s}]".format(new_name)) + logger.error("Path already exists. Rename it to [{:s}]".format(new_name)) os.replace(path, new_name) os.makedirs(path) diff --git a/invokeai/backend/stable_diffusion/textual_inversion_manager.py b/invokeai/backend/stable_diffusion/textual_inversion_manager.py index 2dba2b88d3..9476c12dc5 100644 --- a/invokeai/backend/stable_diffusion/textual_inversion_manager.py +++ b/invokeai/backend/stable_diffusion/textual_inversion_manager.py @@ -10,6 +10,7 @@ from compel.embeddings_provider import BaseTextualInversionManager from picklescan.scanner import scan_file_path from transformers import CLIPTextModel, CLIPTokenizer +import invokeai.backend.util.logging as logger from .concepts_lib import HuggingFaceConceptsLibrary @dataclass @@ -59,12 +60,12 @@ class TextualInversionManager(BaseTextualInversionManager): or self.has_textual_inversion_for_trigger_string(concept_name) or self.has_textual_inversion_for_trigger_string(f"<{concept_name}>") ): # in case a token with literal angle brackets encountered - print(f">> Loaded local embedding for trigger {concept_name}") + logger.info(f"Loaded local embedding for trigger {concept_name}") continue bin_file = self.hf_concepts_library.get_concept_model_path(concept_name) if not bin_file: continue - print(f">> Loaded remote embedding for trigger {concept_name}") + logger.info(f"Loaded remote embedding for trigger {concept_name}") self.load_textual_inversion(bin_file) self.hf_concepts_library.concepts_loaded[concept_name] = True @@ -85,8 +86,8 @@ class TextualInversionManager(BaseTextualInversionManager): embedding_list = self._parse_embedding(str(ckpt_path)) for embedding_info in embedding_list: if (self.text_encoder.get_input_embeddings().weight.data[0].shape[0] != embedding_info.token_dim): - print( - f" ** Notice: {ckpt_path.parents[0].name}/{ckpt_path.name} was trained on a model with an incompatible token dimension: {self.text_encoder.get_input_embeddings().weight.data[0].shape[0]} vs {embedding_info.token_dim}." + logger.warning( + f"Notice: {ckpt_path.parents[0].name}/{ckpt_path.name} was trained on a model with an incompatible token dimension: {self.text_encoder.get_input_embeddings().weight.data[0].shape[0]} vs {embedding_info.token_dim}." ) continue @@ -105,8 +106,8 @@ class TextualInversionManager(BaseTextualInversionManager): if ckpt_path.name == "learned_embeds.bin" else f"<{ckpt_path.stem}>" ) - print( - f">> {sourcefile}: Trigger token '{trigger_str}' is already claimed by '{self.trigger_to_sourcefile[trigger_str]}'. Trigger this concept with {replacement_trigger_str}" + logger.info( + f"{sourcefile}: Trigger token '{trigger_str}' is already claimed by '{self.trigger_to_sourcefile[trigger_str]}'. Trigger this concept with {replacement_trigger_str}" ) trigger_str = replacement_trigger_str @@ -120,8 +121,8 @@ class TextualInversionManager(BaseTextualInversionManager): self.trigger_to_sourcefile[trigger_str] = sourcefile except ValueError as e: - print(f' | Ignoring incompatible embedding {embedding_info["name"]}') - print(f" | The error was {str(e)}") + logger.debug(f'Ignoring incompatible embedding {embedding_info["name"]}') + logger.debug(f"The error was {str(e)}") def _add_textual_inversion( self, trigger_str, embedding, defer_injecting_tokens=False @@ -133,8 +134,8 @@ class TextualInversionManager(BaseTextualInversionManager): :return: The token id for the added embedding, either existing or newly-added. """ if trigger_str in [ti.trigger_string for ti in self.textual_inversions]: - print( - f"** TextualInversionManager refusing to overwrite already-loaded token '{trigger_str}'" + logger.warning( + f"TextualInversionManager refusing to overwrite already-loaded token '{trigger_str}'" ) return if not self.full_precision: @@ -155,11 +156,11 @@ class TextualInversionManager(BaseTextualInversionManager): except ValueError as e: if str(e).startswith("Warning"): - print(f">> {str(e)}") + logger.warning(f"{str(e)}") else: traceback.print_exc() - print( - f"** TextualInversionManager was unable to add a textual inversion with trigger string {trigger_str}." + logger.error( + f"TextualInversionManager was unable to add a textual inversion with trigger string {trigger_str}." ) raise @@ -219,16 +220,16 @@ class TextualInversionManager(BaseTextualInversionManager): for ti in self.textual_inversions: if ti.trigger_token_id is None and ti.trigger_string in prompt_string: if ti.embedding_vector_length > 1: - print( - f">> Preparing tokens for textual inversion {ti.trigger_string}..." + logger.info( + f"Preparing tokens for textual inversion {ti.trigger_string}..." ) try: self._inject_tokens_and_assign_embeddings(ti) except ValueError as e: - print( - f" | Ignoring incompatible embedding trigger {ti.trigger_string}" + logger.debug( + f"Ignoring incompatible embedding trigger {ti.trigger_string}" ) - print(f" | The error was {str(e)}") + logger.debug(f"The error was {str(e)}") continue injected_token_ids.append(ti.trigger_token_id) injected_token_ids.extend(ti.pad_token_ids) @@ -306,16 +307,16 @@ class TextualInversionManager(BaseTextualInversionManager): if suffix in [".pt",".ckpt",".bin"]: scan_result = scan_file_path(embedding_file) if scan_result.infected_files > 0: - print( - f" ** Security Issues Found in Model: {scan_result.issues_count}" + logger.critical( + f"Security Issues Found in Model: {scan_result.issues_count}" ) - print(" ** For your safety, InvokeAI will not load this embed.") + logger.critical("For your safety, InvokeAI will not load this embed.") return list() ckpt = torch.load(embedding_file,map_location="cpu") else: ckpt = safetensors.torch.load_file(embedding_file) except Exception as e: - print(f" ** Notice: unrecognized embedding file format: {embedding_file}: {e}") + logger.warning(f"Notice: unrecognized embedding file format: {embedding_file}: {e}") return list() # try to figure out what kind of embedding file it is and parse accordingly @@ -334,7 +335,7 @@ class TextualInversionManager(BaseTextualInversionManager): def _parse_embedding_v1(self, embedding_ckpt: dict, file_path: str)->List[EmbeddingInfo]: basename = Path(file_path).stem - print(f' | Loading v1 embedding file: {basename}') + logger.debug(f'Loading v1 embedding file: {basename}') embeddings = list() token_counter = -1 @@ -342,7 +343,7 @@ class TextualInversionManager(BaseTextualInversionManager): if token_counter < 0: trigger = embedding_ckpt["name"] elif token_counter == 0: - trigger = f'' + trigger = '' else: trigger = f'<{basename}-{int(token_counter:=token_counter)}>' token_counter += 1 @@ -365,7 +366,7 @@ class TextualInversionManager(BaseTextualInversionManager): This handles embedding .pt file variant #2. """ basename = Path(file_path).stem - print(f' | Loading v2 embedding file: {basename}') + logger.debug(f'Loading v2 embedding file: {basename}') embeddings = list() if isinstance( @@ -384,7 +385,7 @@ class TextualInversionManager(BaseTextualInversionManager): ) embeddings.append(embedding_info) else: - print(f" ** {basename}: Unrecognized embedding format") + logger.warning(f"{basename}: Unrecognized embedding format") return embeddings @@ -393,7 +394,7 @@ class TextualInversionManager(BaseTextualInversionManager): Parse 'version 3' of the .pt textual inversion embedding files. """ basename = Path(file_path).stem - print(f' | Loading v3 embedding file: {basename}') + logger.debug(f'Loading v3 embedding file: {basename}') embedding = embedding_ckpt['emb_params'] embedding_info = EmbeddingInfo( name = f'<{basename}>', @@ -411,11 +412,11 @@ class TextualInversionManager(BaseTextualInversionManager): basename = Path(filepath).stem short_path = Path(filepath).parents[0].name+'/'+Path(filepath).name - print(f' | Loading v4 embedding file: {short_path}') + logger.debug(f'Loading v4 embedding file: {short_path}') embeddings = list() if list(embedding_ckpt.keys()) == 0: - print(f" ** Invalid embeddings file: {short_path}") + logger.warning(f"Invalid embeddings file: {short_path}") else: for token,embedding in embedding_ckpt.items(): embedding_info = EmbeddingInfo( diff --git a/invokeai/backend/util/logging.py b/invokeai/backend/util/logging.py new file mode 100644 index 0000000000..73f980aeff --- /dev/null +++ b/invokeai/backend/util/logging.py @@ -0,0 +1,109 @@ +# Copyright (c) 2023 Lincoln D. Stein and The InvokeAI Development Team + +"""invokeai.util.logging + +Logging class for InvokeAI that produces console messages that follow +the conventions established in InvokeAI 1.X through 2.X. + + +One way to use it: + +from invokeai.backend.util.logging import InvokeAILogger + +logger = InvokeAILogger.getLogger(__name__) +logger.critical('this is critical') +logger.error('this is an error') +logger.warning('this is a warning') +logger.info('this is info') +logger.debug('this is debugging') + +Console messages: + ### this is critical + *** this is an error *** + ** this is a warning + >> this is info + | this is debugging + +Another way: +import invokeai.backend.util.logging as ialog +ialogger.debug('this is a debugging message') +""" +import logging + +# module level functions +def debug(msg, *args, **kwargs): + InvokeAILogger.getLogger().debug(msg, *args, **kwargs) + +def info(msg, *args, **kwargs): + InvokeAILogger.getLogger().info(msg, *args, **kwargs) + +def warning(msg, *args, **kwargs): + InvokeAILogger.getLogger().warning(msg, *args, **kwargs) + +def error(msg, *args, **kwargs): + InvokeAILogger.getLogger().error(msg, *args, **kwargs) + +def critical(msg, *args, **kwargs): + InvokeAILogger.getLogger().critical(msg, *args, **kwargs) + +def log(level, msg, *args, **kwargs): + InvokeAILogger.getLogger().log(level, msg, *args, **kwargs) + +def disable(level=logging.CRITICAL): + InvokeAILogger.getLogger().disable(level) + +def basicConfig(**kwargs): + InvokeAILogger.getLogger().basicConfig(**kwargs) + +def getLogger(name: str=None)->logging.Logger: + return InvokeAILogger.getLogger(name) + +class InvokeAILogFormatter(logging.Formatter): + ''' + Repurposed from: + https://stackoverflow.com/questions/14844970/modifying-logging-message-format-based-on-message-logging-level-in-python3 + ''' + crit_fmt = "### %(msg)s" + err_fmt = "*** %(msg)s" + warn_fmt = "** %(msg)s" + info_fmt = ">> %(msg)s" + dbg_fmt = " | %(msg)s" + + def __init__(self): + super().__init__(fmt="%(levelno)d: %(msg)s", datefmt=None, style='%') + + def format(self, record): + # Remember the format used when the logging module + # was installed (in the event that this formatter is + # used with the vanilla logging module. + format_orig = self._style._fmt + if record.levelno == logging.DEBUG: + self._style._fmt = InvokeAILogFormatter.dbg_fmt + if record.levelno == logging.INFO: + self._style._fmt = InvokeAILogFormatter.info_fmt + if record.levelno == logging.WARNING: + self._style._fmt = InvokeAILogFormatter.warn_fmt + if record.levelno == logging.ERROR: + self._style._fmt = InvokeAILogFormatter.err_fmt + if record.levelno == logging.CRITICAL: + self._style._fmt = InvokeAILogFormatter.crit_fmt + + # parent class does the work + result = super().format(record) + self._style._fmt = format_orig + return result + +class InvokeAILogger(object): + loggers = dict() + + @classmethod + def getLogger(self, name:str='invokeai')->logging.Logger: + if name not in self.loggers: + logger = logging.getLogger(name) + logger.setLevel(logging.DEBUG) + ch = logging.StreamHandler() + fmt = InvokeAILogFormatter() + ch.setFormatter(fmt) + logger.addHandler(ch) + self.loggers[name] = logger + return self.loggers[name] diff --git a/invokeai/backend/util/util.py b/invokeai/backend/util/util.py index d5239af834..edc6a7b04b 100644 --- a/invokeai/backend/util/util.py +++ b/invokeai/backend/util/util.py @@ -18,6 +18,7 @@ import torch from PIL import Image, ImageDraw, ImageFont from tqdm import tqdm +import invokeai.backend.util.logging as logger from .devices import torch_dtype @@ -38,7 +39,7 @@ def log_txt_as_img(wh, xc, size=10): try: draw.text((0, 0), lines, fill="black", font=font) except UnicodeEncodeError: - print("Cant encode string for logging. Skipping.") + logger.warning("Cant encode string for logging. Skipping.") txt = np.array(txt).transpose(2, 0, 1) / 127.5 - 1.0 txts.append(txt) @@ -80,8 +81,8 @@ def mean_flat(tensor): def count_params(model, verbose=False): total_params = sum(p.numel() for p in model.parameters()) if verbose: - print( - f" | {model.__class__.__name__} has {total_params * 1.e-6:.2f} M params." + logger.debug( + f"{model.__class__.__name__} has {total_params * 1.e-6:.2f} M params." ) return total_params @@ -132,8 +133,8 @@ def parallel_data_prefetch( raise ValueError("list expected but function got ndarray.") elif isinstance(data, abc.Iterable): if isinstance(data, dict): - print( - 'WARNING:"data" argument passed to parallel_data_prefetch is a dict: Using only its values and disregarding keys.' + logger.warning( + '"data" argument passed to parallel_data_prefetch is a dict: Using only its values and disregarding keys.' ) data = list(data.values()) if target_data_type == "ndarray": @@ -175,7 +176,7 @@ def parallel_data_prefetch( processes += [p] # start processes - print("Start prefetching...") + logger.info("Start prefetching...") import time start = time.time() @@ -194,7 +195,7 @@ def parallel_data_prefetch( gather_res[res[0]] = res[1] except Exception as e: - print("Exception: ", e) + logger.error("Exception: ", e) for p in processes: p.terminate() @@ -202,7 +203,7 @@ def parallel_data_prefetch( finally: for p in processes: p.join() - print(f"Prefetching complete. [{time.time() - start} sec.]") + logger.info(f"Prefetching complete. [{time.time() - start} sec.]") if target_data_type == "ndarray": if not isinstance(gather_res[0], np.ndarray): @@ -318,23 +319,23 @@ def download_with_resume(url: str, dest: Path, access_token: str = None) -> Path resp = requests.get(url, headers=header, stream=True) # new request with range if exist_size > content_length: - print("* corrupt existing file found. re-downloading") + logger.warning("corrupt existing file found. re-downloading") os.remove(dest) exist_size = 0 if resp.status_code == 416 or exist_size == content_length: - print(f"* {dest}: complete file found. Skipping.") + logger.warning(f"{dest}: complete file found. Skipping.") return dest elif resp.status_code == 206 or exist_size > 0: - print(f"* {dest}: partial file found. Resuming...") + logger.warning(f"{dest}: partial file found. Resuming...") elif resp.status_code != 200: - print(f"** An error occurred during downloading {dest}: {resp.reason}") + logger.error(f"An error occurred during downloading {dest}: {resp.reason}") else: - print(f"* {dest}: Downloading...") + logger.error(f"{dest}: Downloading...") try: if content_length < 2000: - print(f"*** ERROR DOWNLOADING {url}: {resp.text}") + logger.error(f"ERROR DOWNLOADING {url}: {resp.text}") return None with open(dest, open_mode) as file, tqdm( @@ -349,7 +350,7 @@ def download_with_resume(url: str, dest: Path, access_token: str = None) -> Path size = file.write(data) bar.update(size) except Exception as e: - print(f"An error occurred while downloading {dest}: {str(e)}") + logger.error(f"An error occurred while downloading {dest}: {str(e)}") return None return dest diff --git a/invokeai/backend/web/invoke_ai_web_server.py b/invokeai/backend/web/invoke_ai_web_server.py index 7209e31449..84478d5cb6 100644 --- a/invokeai/backend/web/invoke_ai_web_server.py +++ b/invokeai/backend/web/invoke_ai_web_server.py @@ -19,6 +19,7 @@ from PIL import Image from PIL.Image import Image as ImageType from werkzeug.utils import secure_filename +import invokeai.backend.util.logging as logger import invokeai.frontend.web.dist as frontend from .. import Generate @@ -213,7 +214,7 @@ class InvokeAIWebServer: self.load_socketio_listeners(self.socketio) if args.gui: - print(">> Launching Invoke AI GUI") + logger.info("Launching Invoke AI GUI") try: from flaskwebgui import FlaskUI @@ -231,17 +232,17 @@ class InvokeAIWebServer: sys.exit(0) else: useSSL = args.certfile or args.keyfile - print(">> Started Invoke AI Web Server") + logger.info("Started Invoke AI Web Server") if self.host == "0.0.0.0": - print( + logger.info( f"Point your browser at http{'s' if useSSL else ''}://localhost:{self.port} or use the host's DNS name or IP address." ) else: - print( - ">> Default host address now 127.0.0.1 (localhost). Use --host 0.0.0.0 to bind any address." + logger.info( + "Default host address now 127.0.0.1 (localhost). Use --host 0.0.0.0 to bind any address." ) - print( - f">> Point your browser at http{'s' if useSSL else ''}://{self.host}:{self.port}" + logger.info( + f"Point your browser at http{'s' if useSSL else ''}://{self.host}:{self.port}" ) if not useSSL: self.socketio.run(app=self.app, host=self.host, port=self.port) @@ -273,7 +274,7 @@ class InvokeAIWebServer: # path for thumbnail images self.thumbnail_image_path = os.path.join(self.result_path, "thumbnails/") # txt log - self.log_path = os.path.join(self.result_path, "invoke_log.txt") + self.log_path = os.path.join(self.result_path, "invoke_logger.txt") # make all output paths [ os.makedirs(path, exist_ok=True) @@ -290,7 +291,7 @@ class InvokeAIWebServer: def load_socketio_listeners(self, socketio): @socketio.on("requestSystemConfig") def handle_request_capabilities(): - print(">> System config requested") + logger.info("System config requested") config = self.get_system_config() config["model_list"] = self.generate.model_manager.list_models() config["infill_methods"] = infill_methods() @@ -330,7 +331,7 @@ class InvokeAIWebServer: if model_name in current_model_list: update = True - print(f">> Adding New Model: {model_name}") + logger.info(f"Adding New Model: {model_name}") self.generate.model_manager.add_model( model_name=model_name, @@ -348,14 +349,14 @@ class InvokeAIWebServer: "update": update, }, ) - print(f">> New Model Added: {model_name}") + logger.info(f"New Model Added: {model_name}") except Exception as e: self.handle_exceptions(e) @socketio.on("deleteModel") def handle_delete_model(model_name: str): try: - print(f">> Deleting Model: {model_name}") + logger.info(f"Deleting Model: {model_name}") self.generate.model_manager.del_model(model_name) self.generate.model_manager.commit(opt.conf) updated_model_list = self.generate.model_manager.list_models() @@ -366,14 +367,14 @@ class InvokeAIWebServer: "model_list": updated_model_list, }, ) - print(f">> Model Deleted: {model_name}") + logger.info(f"Model Deleted: {model_name}") except Exception as e: self.handle_exceptions(e) @socketio.on("requestModelChange") def handle_set_model(model_name: str): try: - print(f">> Model change requested: {model_name}") + logger.info(f"Model change requested: {model_name}") model = self.generate.set_model(model_name) model_list = self.generate.model_manager.list_models() if model is None: @@ -454,7 +455,7 @@ class InvokeAIWebServer: "update": True, }, ) - print(f">> Model Converted: {model_name}") + logger.info(f"Model Converted: {model_name}") except Exception as e: self.handle_exceptions(e) @@ -490,7 +491,7 @@ class InvokeAIWebServer: if vae := self.generate.model_manager.config[models_to_merge[0]].get( "vae", None ): - print(f">> Using configured VAE assigned to {models_to_merge[0]}") + logger.info(f"Using configured VAE assigned to {models_to_merge[0]}") merged_model_config.update(vae=vae) self.generate.model_manager.import_diffuser_model( @@ -507,8 +508,8 @@ class InvokeAIWebServer: "update": True, }, ) - print(f">> Models Merged: {models_to_merge}") - print(f">> New Model Added: {model_merge_info['merged_model_name']}") + logger.info(f"Models Merged: {models_to_merge}") + logger.info(f"New Model Added: {model_merge_info['merged_model_name']}") except Exception as e: self.handle_exceptions(e) @@ -698,7 +699,7 @@ class InvokeAIWebServer: } ) except Exception as e: - print(f">> Unable to load {path}") + logger.info(f"Unable to load {path}") socketio.emit( "error", {"message": f"Unable to load {path}: {str(e)}"} ) @@ -735,9 +736,9 @@ class InvokeAIWebServer: printable_parameters["init_mask"][:64] + "..." ) - print(f"\n>> Image Generation Parameters:\n\n{printable_parameters}\n") - print(f">> ESRGAN Parameters: {esrgan_parameters}") - print(f">> Facetool Parameters: {facetool_parameters}") + logger.info(f"Image Generation Parameters:\n\n{printable_parameters}\n") + logger.info(f"ESRGAN Parameters: {esrgan_parameters}") + logger.info(f"Facetool Parameters: {facetool_parameters}") self.generate_images( generation_parameters, @@ -750,8 +751,8 @@ class InvokeAIWebServer: @socketio.on("runPostprocessing") def handle_run_postprocessing(original_image, postprocessing_parameters): try: - print( - f'>> Postprocessing requested for "{original_image["url"]}": {postprocessing_parameters}' + logger.info( + f'Postprocessing requested for "{original_image["url"]}": {postprocessing_parameters}' ) progress = Progress() @@ -861,14 +862,14 @@ class InvokeAIWebServer: @socketio.on("cancel") def handle_cancel(): - print(">> Cancel processing requested") + logger.info("Cancel processing requested") self.canceled.set() # TODO: I think this needs a safety mechanism. @socketio.on("deleteImage") def handle_delete_image(url, thumbnail, uuid, category): try: - print(f'>> Delete requested "{url}"') + logger.info(f'Delete requested "{url}"') from send2trash import send2trash path = self.get_image_path_from_url(url) @@ -1263,7 +1264,7 @@ class InvokeAIWebServer: image, os.path.basename(path), self.thumbnail_image_path ) - print(f'\n\n>> Image generated: "{path}"\n') + logger.info(f'Image generated: "{path}"\n') self.write_log_message(f'[Generated] "{path}": {command}') if progress.total_iterations > progress.current_iteration: @@ -1329,7 +1330,7 @@ class InvokeAIWebServer: except Exception as e: # Clear the CUDA cache on an exception self.empty_cuda_cache() - print(e) + logger.error(e) self.handle_exceptions(e) def empty_cuda_cache(self): diff --git a/invokeai/frontend/CLI/CLI.py b/invokeai/frontend/CLI/CLI.py index 352ee83812..aa0c4bea5f 100644 --- a/invokeai/frontend/CLI/CLI.py +++ b/invokeai/frontend/CLI/CLI.py @@ -16,6 +16,7 @@ if sys.platform == "darwin": import pyparsing # type: ignore import invokeai.version as invokeai +import invokeai.backend.util.logging as logger from ...backend import Generate, ModelManager from ...backend.args import Args, dream_cmd_from_png, metadata_dumps, metadata_from_png @@ -69,7 +70,7 @@ def main(): # run any post-install patches needed run_patches() - print(f">> Internet connectivity is {Globals.internet_available}") + logger.info(f"Internet connectivity is {Globals.internet_available}") if not args.conf: config_file = os.path.join(Globals.root, "configs", "models.yaml") @@ -78,8 +79,8 @@ def main(): opt, FileNotFoundError(f"The file {config_file} could not be found.") ) - print(f">> {invokeai.__app_name__}, version {invokeai.__version__}") - print(f'>> InvokeAI runtime directory is "{Globals.root}"') + logger.info(f"{invokeai.__app_name__}, version {invokeai.__version__}") + logger.info(f'InvokeAI runtime directory is "{Globals.root}"') # loading here to avoid long delays on startup # these two lines prevent a horrible warning message from appearing @@ -121,7 +122,7 @@ def main(): else: raise FileNotFoundError(f"{opt.infile} not found.") except (FileNotFoundError, IOError) as e: - print(f"{e}. Aborting.") + logger.critical('Aborted',exc_info=True) sys.exit(-1) # creating a Generate object: @@ -142,12 +143,12 @@ def main(): ) except (FileNotFoundError, TypeError, AssertionError) as e: report_model_error(opt, e) - except (IOError, KeyError) as e: - print(f"{e}. Aborting.") + except (IOError, KeyError): + logger.critical("Aborted",exc_info=True) sys.exit(-1) if opt.seamless: - print(">> changed to seamless tiling mode") + logger.info("Changed to seamless tiling mode") # preload the model try: @@ -180,9 +181,7 @@ def main(): f'\nGoodbye!\nYou can start InvokeAI again by running the "invoke.bat" (or "invoke.sh") script from {Globals.root}' ) except Exception: - print(">> An error occurred:") - traceback.print_exc() - + logger.error("An error occurred",exc_info=True) # TODO: main_loop() has gotten busy. Needs to be refactored. def main_loop(gen, opt): @@ -248,7 +247,7 @@ def main_loop(gen, opt): if not opt.prompt: oldargs = metadata_from_png(opt.init_img) opt.prompt = oldargs.prompt - print(f'>> Retrieved old prompt "{opt.prompt}" from {opt.init_img}') + logger.info(f'Retrieved old prompt "{opt.prompt}" from {opt.init_img}') except (OSError, AttributeError, KeyError): pass @@ -265,9 +264,9 @@ def main_loop(gen, opt): if opt.init_img is not None and re.match("^-\\d+$", opt.init_img): try: opt.init_img = last_results[int(opt.init_img)][0] - print(f">> Reusing previous image {opt.init_img}") + logger.info(f"Reusing previous image {opt.init_img}") except IndexError: - print(f">> No previous initial image at position {opt.init_img} found") + logger.info(f"No previous initial image at position {opt.init_img} found") opt.init_img = None continue @@ -288,9 +287,9 @@ def main_loop(gen, opt): if opt.seed is not None and opt.seed < 0 and operation != "postprocess": try: opt.seed = last_results[opt.seed][1] - print(f">> Reusing previous seed {opt.seed}") + logger.info(f"Reusing previous seed {opt.seed}") except IndexError: - print(f">> No previous seed at position {opt.seed} found") + logger.info(f"No previous seed at position {opt.seed} found") opt.seed = None continue @@ -309,7 +308,7 @@ def main_loop(gen, opt): subdir = subdir[: (path_max - 39 - len(os.path.abspath(opt.outdir)))] current_outdir = os.path.join(opt.outdir, subdir) - print('Writing files to directory: "' + current_outdir + '"') + logger.info('Writing files to directory: "' + current_outdir + '"') # make sure the output directory exists if not os.path.exists(current_outdir): @@ -438,15 +437,14 @@ def main_loop(gen, opt): catch_interrupts=catch_ctrl_c, **vars(opt), ) - except (PromptParser.ParsingException, pyparsing.ParseException) as e: - print("** An error occurred while processing your prompt **") - print(f"** {str(e)} **") + except (PromptParser.ParsingException, pyparsing.ParseException): + logger.error("An error occurred while processing your prompt",exc_info=True) elif operation == "postprocess": - print(f">> fixing {opt.prompt}") + logger.info(f"fixing {opt.prompt}") opt.last_operation = do_postprocess(gen, opt, image_writer) elif operation == "mask": - print(f">> generating masks from {opt.prompt}") + logger.info(f"generating masks from {opt.prompt}") do_textmask(gen, opt, image_writer) if opt.grid and len(grid_images) > 0: @@ -469,12 +467,12 @@ def main_loop(gen, opt): ) results = [[path, formatted_dream_prompt]] - except AssertionError as e: - print(e) + except AssertionError: + logger.error(e) continue except OSError as e: - print(e) + logger.error(e) continue print("Outputs:") @@ -513,7 +511,7 @@ def do_command(command: str, gen, opt: Args, completer) -> tuple: gen.set_model(model_name) add_embedding_terms(gen, completer) except KeyError as e: - print(str(e)) + logger.error(e) except Exception as e: report_model_error(opt, e) completer.add_history(command) @@ -527,8 +525,8 @@ def do_command(command: str, gen, opt: Args, completer) -> tuple: elif command.startswith("!import"): path = shlex.split(command) if len(path) < 2: - print( - "** please provide (1) a URL to a .ckpt file to import; (2) a local path to a .ckpt file; or (3) a diffusers repository id in the form stabilityai/stable-diffusion-2-1" + logger.warning( + "please provide (1) a URL to a .ckpt file to import; (2) a local path to a .ckpt file; or (3) a diffusers repository id in the form stabilityai/stable-diffusion-2-1" ) else: try: @@ -541,7 +539,7 @@ def do_command(command: str, gen, opt: Args, completer) -> tuple: elif command.startswith(("!convert", "!optimize")): path = shlex.split(command) if len(path) < 2: - print("** please provide the path to a .ckpt or .safetensors model") + logger.warning("please provide the path to a .ckpt or .safetensors model") else: try: convert_model(path[1], gen, opt, completer) @@ -553,7 +551,7 @@ def do_command(command: str, gen, opt: Args, completer) -> tuple: elif command.startswith("!edit"): path = shlex.split(command) if len(path) < 2: - print("** please provide the name of a model") + logger.warning("please provide the name of a model") else: edit_model(path[1], gen, opt, completer) completer.add_history(command) @@ -562,7 +560,7 @@ def do_command(command: str, gen, opt: Args, completer) -> tuple: elif command.startswith("!del"): path = shlex.split(command) if len(path) < 2: - print("** please provide the name of a model") + logger.warning("please provide the name of a model") else: del_config(path[1], gen, opt, completer) completer.add_history(command) @@ -642,8 +640,8 @@ def import_model(model_path: str, gen, opt, completer): try: default_name = url_attachment_name(model_path) default_name = Path(default_name).stem - except Exception as e: - print(f"** URL: {str(e)}") + except Exception: + logger.warning(f"A problem occurred while assigning the name of the downloaded model",exc_info=True) model_name, model_desc = _get_model_name_and_desc( gen.model_manager, completer, @@ -664,11 +662,11 @@ def import_model(model_path: str, gen, opt, completer): model_config_file=config_file, ) if not imported_name: - print("** Aborting import.") + logger.error("Aborting import.") return if not _verify_load(imported_name, gen): - print("** model failed to load. Discarding configuration entry") + logger.error("model failed to load. Discarding configuration entry") gen.model_manager.del_model(imported_name) return if click.confirm("Make this the default model?", default=False): @@ -676,7 +674,7 @@ def import_model(model_path: str, gen, opt, completer): gen.model_manager.commit(opt.conf) completer.update_models(gen.model_manager.list_models()) - print(f">> {imported_name} successfully installed") + logger.info(f"{imported_name} successfully installed") def _pick_configuration_file(completer)->Path: print( @@ -720,21 +718,21 @@ Please select the type of this model: return choice def _verify_load(model_name: str, gen) -> bool: - print(">> Verifying that new model loads...") + logger.info("Verifying that new model loads...") current_model = gen.model_name try: if not gen.set_model(model_name): return except Exception as e: - print(f"** model failed to load: {str(e)}") - print( + logger.warning(f"model failed to load: {str(e)}") + logger.warning( "** note that importing 2.X checkpoints is not supported. Please use !convert_model instead." ) return False if click.confirm("Keep model loaded?", default=True): gen.set_model(model_name) else: - print(">> Restoring previous model") + logger.info("Restoring previous model") gen.set_model(current_model) return True @@ -757,7 +755,7 @@ def convert_model(model_name_or_path: Union[Path, str], gen, opt, completer): ckpt_path = None original_config_file = None if model_name_or_path == gen.model_name: - print("** Can't convert the active model. !switch to another model first. **") + logger.warning("Can't convert the active model. !switch to another model first. **") return elif model_info := manager.model_info(model_name_or_path): if "weights" in model_info: @@ -767,7 +765,7 @@ def convert_model(model_name_or_path: Union[Path, str], gen, opt, completer): model_description = model_info["description"] vae_path = model_info.get("vae") else: - print(f"** {model_name_or_path} is not a legacy .ckpt weights file") + logger.warning(f"{model_name_or_path} is not a legacy .ckpt weights file") return model_name = manager.convert_and_import( ckpt_path, @@ -788,16 +786,16 @@ def convert_model(model_name_or_path: Union[Path, str], gen, opt, completer): manager.commit(opt.conf) if click.confirm(f"Delete the original .ckpt file at {ckpt_path}?", default=False): ckpt_path.unlink(missing_ok=True) - print(f"{ckpt_path} deleted") + logger.warning(f"{ckpt_path} deleted") def del_config(model_name: str, gen, opt, completer): current_model = gen.model_name if model_name == current_model: - print("** Can't delete active model. !switch to another model first. **") + logger.warning("Can't delete active model. !switch to another model first. **") return if model_name not in gen.model_manager.config: - print(f"** Unknown model {model_name}") + logger.warning(f"Unknown model {model_name}") return if not click.confirm( @@ -810,17 +808,17 @@ def del_config(model_name: str, gen, opt, completer): ) gen.model_manager.del_model(model_name, delete_files=delete_completely) gen.model_manager.commit(opt.conf) - print(f"** {model_name} deleted") + logger.warning(f"{model_name} deleted") completer.update_models(gen.model_manager.list_models()) def edit_model(model_name: str, gen, opt, completer): manager = gen.model_manager if not (info := manager.model_info(model_name)): - print(f"** Unknown model {model_name}") + logger.warning(f"** Unknown model {model_name}") return - - print(f"\n>> Editing model {model_name} from configuration file {opt.conf}") + print() + logger.info(f"Editing model {model_name} from configuration file {opt.conf}") new_name = _get_model_name(manager.list_models(), completer, model_name) for attribute in info.keys(): @@ -858,7 +856,7 @@ def edit_model(model_name: str, gen, opt, completer): manager.set_default_model(new_name) manager.commit(opt.conf) completer.update_models(manager.list_models()) - print(">> Model successfully updated") + logger.info("Model successfully updated") def _get_model_name(existing_names, completer, default_name: str = "") -> str: @@ -869,11 +867,11 @@ def _get_model_name(existing_names, completer, default_name: str = "") -> str: if len(model_name) == 0: model_name = default_name if not re.match("^[\w._+:/-]+$", model_name): - print( - '** model name must contain only words, digits and the characters "._+:/-" **' + logger.warning( + 'model name must contain only words, digits and the characters "._+:/-" **' ) elif model_name != default_name and model_name in existing_names: - print(f"** the name {model_name} is already in use. Pick another.") + logger.warning(f"the name {model_name} is already in use. Pick another.") else: done = True return model_name @@ -940,11 +938,10 @@ def do_postprocess(gen, opt, callback): opt=opt, ) except OSError: - print(traceback.format_exc(), file=sys.stderr) - print(f"** {file_path}: file could not be read") + logger.error(f"{file_path}: file could not be read",exc_info=True) return except (KeyError, AttributeError): - print(traceback.format_exc(), file=sys.stderr) + logger.error(f"an error occurred while applying the {tool} postprocessor",exc_info=True) return return opt.last_operation @@ -999,13 +996,13 @@ def prepare_image_metadata( try: filename = opt.fnformat.format(**wildcards) except KeyError as e: - print( - f"** The filename format contains an unknown key '{e.args[0]}'. Will use {{prefix}}.{{seed}}.png' instead" + logger.error( + f"The filename format contains an unknown key '{e.args[0]}'. Will use {{prefix}}.{{seed}}.png' instead" ) filename = f"{prefix}.{seed}.png" except IndexError: - print( - "** The filename format is broken or complete. Will use '{prefix}.{seed}.png' instead" + logger.error( + "The filename format is broken or complete. Will use '{prefix}.{seed}.png' instead" ) filename = f"{prefix}.{seed}.png" @@ -1094,14 +1091,14 @@ def split_variations(variations_string) -> list: for part in variations_string.split(","): seed_and_weight = part.split(":") if len(seed_and_weight) != 2: - print(f'** Could not parse with_variation part "{part}"') + logger.warning(f'Could not parse with_variation part "{part}"') broken = True break try: seed = int(seed_and_weight[0]) weight = float(seed_and_weight[1]) except ValueError: - print(f'** Could not parse with_variation part "{part}"') + logger.warning(f'Could not parse with_variation part "{part}"') broken = True break parts.append([seed, weight]) @@ -1125,23 +1122,23 @@ def load_face_restoration(opt): opt.gfpgan_model_path ) else: - print(">> Face restoration disabled") + logger.info("Face restoration disabled") if opt.esrgan: esrgan = restoration.load_esrgan(opt.esrgan_bg_tile) else: - print(">> Upscaling disabled") + logger.info("Upscaling disabled") else: - print(">> Face restoration and upscaling disabled") + logger.info("Face restoration and upscaling disabled") except (ModuleNotFoundError, ImportError): print(traceback.format_exc(), file=sys.stderr) - print(">> You may need to install the ESRGAN and/or GFPGAN modules") + logger.info("You may need to install the ESRGAN and/or GFPGAN modules") return gfpgan, codeformer, esrgan def make_step_callback(gen, opt, prefix): destination = os.path.join(opt.outdir, "intermediates", prefix) os.makedirs(destination, exist_ok=True) - print(f">> Intermediate images will be written into {destination}") + logger.info(f"Intermediate images will be written into {destination}") def callback(state: PipelineIntermediateState): latents = state.latents @@ -1183,21 +1180,20 @@ def retrieve_dream_command(opt, command, completer): try: cmd = dream_cmd_from_png(path) except OSError: - print(f"## {tokens[0]}: file could not be read") + logger.error(f"{tokens[0]}: file could not be read") except (KeyError, AttributeError, IndexError): - print(f"## {tokens[0]}: file has no metadata") + logger.error(f"{tokens[0]}: file has no metadata") except: - print(f"## {tokens[0]}: file could not be processed") + logger.error(f"{tokens[0]}: file could not be processed") if len(cmd) > 0: completer.set_line(cmd) - def write_commands(opt, file_path: str, outfilepath: str): dir, basename = os.path.split(file_path) try: paths = sorted(list(Path(dir).glob(basename))) except ValueError: - print(f'## "{basename}": unacceptable pattern') + logger.error(f'"{basename}": unacceptable pattern') return commands = [] @@ -1206,9 +1202,9 @@ def write_commands(opt, file_path: str, outfilepath: str): try: cmd = dream_cmd_from_png(path) except (KeyError, AttributeError, IndexError): - print(f"## {path}: file has no metadata") + logger.error(f"{path}: file has no metadata") except: - print(f"## {path}: file could not be processed") + logger.error(f"{path}: file could not be processed") if cmd: commands.append(f"# {path}") commands.append(cmd) @@ -1218,18 +1214,18 @@ def write_commands(opt, file_path: str, outfilepath: str): outfilepath = os.path.join(opt.outdir, basename) with open(outfilepath, "w", encoding="utf-8") as f: f.write("\n".join(commands)) - print(f">> File {outfilepath} with commands created") + logger.info(f"File {outfilepath} with commands created") def report_model_error(opt: Namespace, e: Exception): - print(f'** An error occurred while attempting to initialize the model: "{str(e)}"') - print( - "** This can be caused by a missing or corrupted models file, and can sometimes be fixed by (re)installing the models." + logger.warning(f'An error occurred while attempting to initialize the model: "{str(e)}"') + logger.warning( + "This can be caused by a missing or corrupted models file, and can sometimes be fixed by (re)installing the models." ) yes_to_all = os.environ.get("INVOKE_MODEL_RECONFIGURE") if yes_to_all: - print( - "** Reconfiguration is being forced by environment variable INVOKE_MODEL_RECONFIGURE" + logger.warning( + "Reconfiguration is being forced by environment variable INVOKE_MODEL_RECONFIGURE" ) else: if not click.confirm( @@ -1238,7 +1234,7 @@ def report_model_error(opt: Namespace, e: Exception): ): return - print("invokeai-configure is launching....\n") + logger.info("invokeai-configure is launching....\n") # Match arguments that were set on the CLI # only the arguments accepted by the configuration script are parsed @@ -1255,7 +1251,7 @@ def report_model_error(opt: Namespace, e: Exception): from ..install import invokeai_configure invokeai_configure() - print("** InvokeAI will now restart") + logger.warning("InvokeAI will now restart") sys.argv = previous_args main() # would rather do a os.exec(), but doesn't exist? sys.exit(0) diff --git a/invokeai/frontend/install/model_install.py b/invokeai/frontend/install/model_install.py index 18ec6d55df..c12104033f 100644 --- a/invokeai/frontend/install/model_install.py +++ b/invokeai/frontend/install/model_install.py @@ -22,6 +22,7 @@ import torch from npyscreen import widget from omegaconf import OmegaConf +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals, global_config_dir from ...backend.config.model_install_backend import ( @@ -455,8 +456,8 @@ def main(): Globals.root = os.path.expanduser(get_root(opt.root) or "") if not global_config_dir().exists(): - print( - ">> Your InvokeAI root directory is not set up. Calling invokeai-configure." + logger.info( + "Your InvokeAI root directory is not set up. Calling invokeai-configure." ) from invokeai.frontend.install import invokeai_configure @@ -466,18 +467,18 @@ def main(): try: select_and_download_models(opt) except AssertionError as e: - print(str(e)) + logger.error(e) sys.exit(-1) except KeyboardInterrupt: - print("\nGoodbye! Come back soon.") + logger.info("Goodbye! Come back soon.") except widget.NotEnoughSpaceForWidget as e: if str(e).startswith("Height of 1 allocated"): - print( - "** Insufficient vertical space for the interface. Please make your window taller and try again" + logger.error( + "Insufficient vertical space for the interface. Please make your window taller and try again" ) elif str(e).startswith("addwstr"): - print( - "** Insufficient horizontal space for the interface. Please make your window wider and try again." + logger.error( + "Insufficient horizontal space for the interface. Please make your window wider and try again." ) diff --git a/invokeai/frontend/merge/merge_diffusers.py b/invokeai/frontend/merge/merge_diffusers.py index 1538826d54..524118ba7c 100644 --- a/invokeai/frontend/merge/merge_diffusers.py +++ b/invokeai/frontend/merge/merge_diffusers.py @@ -27,6 +27,8 @@ from ...backend.globals import ( global_models_dir, global_set_root, ) + +import invokeai.backend.util.logging as logger from ...backend.model_management import ModelManager from ...frontend.install.widgets import FloatTitleSlider @@ -113,7 +115,7 @@ def merge_diffusion_models_and_commit( model_name=merged_model_name, description=f'Merge of models {", ".join(models)}' ) if vae := model_manager.config[models[0]].get("vae", None): - print(f">> Using configured VAE assigned to {models[0]}") + logger.info(f"Using configured VAE assigned to {models[0]}") import_args.update(vae=vae) model_manager.import_diffuser_model(dump_path, **import_args) model_manager.commit(config_file) @@ -391,10 +393,8 @@ class mergeModelsForm(npyscreen.FormMultiPageAction): for name in self.model_manager.model_names() if self.model_manager.model_info(name).get("format") == "diffusers" ] - print(model_names) return sorted(model_names) - class Mergeapp(npyscreen.NPSAppManaged): def __init__(self): super().__init__() @@ -414,7 +414,7 @@ def run_gui(args: Namespace): args = mergeapp.merge_arguments merge_diffusion_models_and_commit(**args) - print(f'>> Models merged into new model: "{args["merged_model_name"]}".') + logger.info(f'Models merged into new model: "{args["merged_model_name"]}".') def run_cli(args: Namespace): @@ -425,8 +425,8 @@ def run_cli(args: Namespace): if not args.merged_model_name: args.merged_model_name = "+".join(args.models) - print( - f'>> No --merged_model_name provided. Defaulting to "{args.merged_model_name}"' + logger.info( + f'No --merged_model_name provided. Defaulting to "{args.merged_model_name}"' ) model_manager = ModelManager(OmegaConf.load(global_config_file())) @@ -435,7 +435,7 @@ def run_cli(args: Namespace): ), f'A model named "{args.merged_model_name}" already exists. Use --clobber to overwrite.' merge_diffusion_models_and_commit(**vars(args)) - print(f'>> Models merged into new model: "{args.merged_model_name}".') + logger.info(f'Models merged into new model: "{args.merged_model_name}".') def main(): @@ -455,17 +455,16 @@ def main(): run_cli(args) except widget.NotEnoughSpaceForWidget as e: if str(e).startswith("Height of 1 allocated"): - print( - "** You need to have at least two diffusers models defined in models.yaml in order to merge" + logger.error( + "You need to have at least two diffusers models defined in models.yaml in order to merge" ) else: - print( - "** Not enough room for the user interface. Try making this window larger." + logger.error( + "Not enough room for the user interface. Try making this window larger." ) sys.exit(-1) - except Exception: - print(">> An error occurred:") - traceback.print_exc() + except Exception as e: + logger.error(e) sys.exit(-1) except KeyboardInterrupt: sys.exit(-1) diff --git a/invokeai/frontend/training/textual_inversion.py b/invokeai/frontend/training/textual_inversion.py index e97284da3d..23134d2736 100755 --- a/invokeai/frontend/training/textual_inversion.py +++ b/invokeai/frontend/training/textual_inversion.py @@ -20,6 +20,7 @@ import npyscreen from npyscreen import widget from omegaconf import OmegaConf +import invokeai.backend.util.logging as logger from invokeai.backend.globals import Globals, global_set_root from ...backend.training import do_textual_inversion_training, parse_args @@ -368,14 +369,14 @@ def copy_to_embeddings_folder(args: dict): dest_dir_name = args["placeholder_token"].strip("<>") destination = Path(Globals.root, "embeddings", dest_dir_name) os.makedirs(destination, exist_ok=True) - print(f">> Training completed. Copying learned_embeds.bin into {str(destination)}") + logger.info(f"Training completed. Copying learned_embeds.bin into {str(destination)}") shutil.copy(source, destination) if ( input("Delete training logs and intermediate checkpoints? [y] ") or "y" ).startswith(("y", "Y")): shutil.rmtree(Path(args["output_dir"])) else: - print(f'>> Keeping {args["output_dir"]}') + logger.info(f'Keeping {args["output_dir"]}') def save_args(args: dict): @@ -422,10 +423,10 @@ def do_front_end(args: Namespace): do_textual_inversion_training(**args) copy_to_embeddings_folder(args) except Exception as e: - print("** An exception occurred during training. The exception was:") - print(str(e)) - print("** DETAILS:") - print(traceback.format_exc()) + logger.error("An exception occurred during training. The exception was:") + logger.error(str(e)) + logger.error("DETAILS:") + logger.error(traceback.format_exc()) def main(): @@ -437,21 +438,21 @@ def main(): else: do_textual_inversion_training(**vars(args)) except AssertionError as e: - print(str(e)) + logger.error(e) sys.exit(-1) except KeyboardInterrupt: pass except (widget.NotEnoughSpaceForWidget, Exception) as e: if str(e).startswith("Height of 1 allocated"): - print( - "** You need to have at least one diffusers models defined in models.yaml in order to train" + logger.error( + "You need to have at least one diffusers models defined in models.yaml in order to train" ) elif str(e).startswith("addwstr"): - print( - "** Not enough window space for the interface. Please make your window larger and try again." + logger.error( + "Not enough window space for the interface. Please make your window larger and try again." ) else: - print(f"** An error has occurred: {str(e)}") + logger.error(e) sys.exit(-1) diff --git a/invokeai/frontend/web/config/vite.app.config.ts b/invokeai/frontend/web/config/vite.app.config.ts new file mode 100644 index 0000000000..e6c4df79fd --- /dev/null +++ b/invokeai/frontend/web/config/vite.app.config.ts @@ -0,0 +1,40 @@ +import react from '@vitejs/plugin-react-swc'; +import { visualizer } from 'rollup-plugin-visualizer'; +import { PluginOption, UserConfig } from 'vite'; +import eslint from 'vite-plugin-eslint'; +import tsconfigPaths from 'vite-tsconfig-paths'; + +export const appConfig: UserConfig = { + base: './', + plugins: [ + react(), + eslint(), + tsconfigPaths(), + visualizer() as unknown as PluginOption, + ], + build: { + chunkSizeWarningLimit: 1500, + }, + server: { + // Proxy HTTP requests to the flask server + proxy: { + // Proxy socket.io to the nodes socketio server + '/ws/socket.io': { + target: 'ws://127.0.0.1:9090', + ws: true, + }, + // Proxy openapi schema definiton + '/openapi.json': { + target: 'http://127.0.0.1:9090/openapi.json', + rewrite: (path) => path.replace(/^\/openapi.json/, ''), + changeOrigin: true, + }, + // proxy nodes api + '/api/v1': { + target: 'http://127.0.0.1:9090/api/v1', + rewrite: (path) => path.replace(/^\/api\/v1/, ''), + changeOrigin: true, + }, + }, + }, +}; diff --git a/invokeai/frontend/web/config/vite.package.config.ts b/invokeai/frontend/web/config/vite.package.config.ts new file mode 100644 index 0000000000..5865461b06 --- /dev/null +++ b/invokeai/frontend/web/config/vite.package.config.ts @@ -0,0 +1,47 @@ +import react from '@vitejs/plugin-react-swc'; +import path from 'path'; +import { visualizer } from 'rollup-plugin-visualizer'; +import { PluginOption, UserConfig } from 'vite'; +import dts from 'vite-plugin-dts'; +import eslint from 'vite-plugin-eslint'; +import tsconfigPaths from 'vite-tsconfig-paths'; + +export const packageConfig: UserConfig = { + base: './', + plugins: [ + react(), + eslint(), + tsconfigPaths(), + visualizer() as unknown as PluginOption, + dts({ + insertTypesEntry: true, + }), + ], + build: { + chunkSizeWarningLimit: 1500, + lib: { + entry: path.resolve(__dirname, '../src/index.ts'), + name: 'InvokeAIUI', + fileName: (format) => `invoke-ai-ui.${format}.js`, + }, + rollupOptions: { + external: ['react', 'react-dom', '@emotion/react'], + output: { + globals: { + react: 'React', + 'react-dom': 'ReactDOM', + }, + }, + }, + }, + resolve: { + alias: { + app: path.resolve(__dirname, '../src/app'), + assets: path.resolve(__dirname, '../src/assets'), + common: path.resolve(__dirname, '../src/common'), + features: path.resolve(__dirname, '../src/features'), + services: path.resolve(__dirname, '../src/services'), + theme: path.resolve(__dirname, '../src/theme'), + }, + }, +}; diff --git a/invokeai/frontend/web/index.d.ts b/invokeai/frontend/web/index.d.ts deleted file mode 100644 index 3006a22d93..0000000000 --- a/invokeai/frontend/web/index.d.ts +++ /dev/null @@ -1,98 +0,0 @@ -import React, { PropsWithChildren } from 'react'; -import { IAIPopoverProps } from '../web/src/common/components/IAIPopover'; -import { IAIIconButtonProps } from '../web/src/common/components/IAIIconButton'; -import { InvokeTabName } from 'features/ui/store/tabMap'; - -export {}; - -declare module 'redux-socket.io-middleware'; - -declare global { - /* eslint-disable @typescript-eslint/no-explicit-any */ - interface Array { - /** - * Returns the value of the last element in the array where predicate is true, and undefined - * otherwise. - * @param predicate findLast calls predicate once for each element of the array, in descending - * order, until it finds one where predicate returns true. If such an element is found, findLast - * immediately returns that element value. Otherwise, findLast returns undefined. - * @param thisArg If provided, it will be used as the this value for each invocation of - * predicate. If it is not provided, undefined is used instead. - */ - findLast( - predicate: (value: T, index: number, array: T[]) => value is S, - thisArg?: any - ): S | undefined; - findLast( - predicate: (value: T, index: number, array: T[]) => unknown, - thisArg?: any - ): T | undefined; - - /** - * Returns the index of the last element in the array where predicate is true, and -1 - * otherwise. - * @param predicate findLastIndex calls predicate once for each element of the array, in descending - * order, until it finds one where predicate returns true. If such an element is found, - * findLastIndex immediately returns that element index. Otherwise, findLastIndex returns -1. - * @param thisArg If provided, it will be used as the this value for each invocation of - * predicate. If it is not provided, undefined is used instead. - */ - findLastIndex( - predicate: (value: T, index: number, array: T[]) => unknown, - thisArg?: any - ): number; - } - /* eslint-enable @typescript-eslint/no-explicit-any */ -} - -declare module '@invoke-ai/invoke-ai-ui' { - declare class ThemeChanger extends React.Component { - public constructor(props: ThemeChangerProps); - } - - declare class InvokeAiLogoComponent extends React.Component { - public constructor(props: InvokeAILogoComponentProps); - } - - declare class IAIPopover extends React.Component { - public constructor(props: IAIPopoverProps); - } - - declare class IAIIconButton extends React.Component { - public constructor(props: IAIIconButtonProps); - } - - declare class SettingsModal extends React.Component { - public constructor(props: SettingsModalProps); - } - - declare class StatusIndicator extends React.Component { - public constructor(props: StatusIndicatorProps); - } - - declare class ModelSelect extends React.Component { - public constructor(props: ModelSelectProps); - } -} - -interface InvokeProps extends PropsWithChildren { - apiUrl?: string; - disabledPanels?: string[]; - disabledTabs?: InvokeTabName[]; - token?: string; - shouldTransformUrls?: boolean; - shouldFetchImages?: boolean; -} - -declare function Invoke(props: InvokeProps): JSX.Element; - -export { - ThemeChanger, - InvokeAiLogoComponent, - IAIPopover, - IAIIconButton, - SettingsModal, - StatusIndicator, - ModelSelect, -}; -export = Invoke; diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index 5ac1c7f9d3..ef61f65cf4 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -1,7 +1,23 @@ { - "name": "invoke-ai-ui", + "name": "@invoke-ai/invoke-ai-ui", "private": true, "version": "0.0.1", + "publishConfig": { + "access": "restricted", + "registry": "https://npm.pkg.github.com" + }, + "main": "./dist/invoke-ai-ui.umd.js", + "module": "./dist/invoke-ai-ui.es.js", + "exports": { + ".": { + "import": "./dist/invoke-ai-ui.es.js", + "require": "./dist/invoke-ai-ui.umd.js" + } + }, + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], "scripts": { "prepare": "cd ../../../ && husky install invokeai/frontend/web/.husky", "dev": "concurrently \"vite dev\" \"yarn run theme:watch\"", @@ -40,81 +56,96 @@ }, "dependencies": { "@chakra-ui/anatomy": "^2.1.1", - "@chakra-ui/cli": "^2.3.0", - "@chakra-ui/icons": "^2.0.17", - "@chakra-ui/react": "^2.5.1", - "@chakra-ui/styled-system": "^2.6.1", + "@chakra-ui/icons": "^2.0.19", + "@chakra-ui/react": "^2.6.0", + "@chakra-ui/styled-system": "^2.9.0", "@chakra-ui/theme-tools": "^2.0.16", "@dagrejs/graphlib": "^2.1.12", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@fontsource/inter": "^4.5.15", - "@reduxjs/toolkit": "^1.9.3", + "@reduxjs/toolkit": "^1.9.5", + "@roarr/browser-log-writer": "^1.1.5", "chakra-ui-contextmenu": "^1.0.5", "dateformat": "^5.0.3", "formik": "^2.2.9", - "framer-motion": "^9.0.4", + "framer-motion": "^10.12.4", "fuse.js": "^6.6.2", - "i18next": "^22.4.10", + "i18next": "^22.4.15", "i18next-browser-languagedetector": "^7.0.1", - "i18next-http-backend": "^2.1.1", - "konva": "^8.4.2", - "lodash": "^4.17.21", - "patch-package": "^6.5.1", + "i18next-http-backend": "^2.2.0", + "konva": "^9.0.1", + "lodash-es": "^4.17.21", + "overlayscrollbars": "^2.1.1", + "overlayscrollbars-react": "^0.5.0", + "patch-package": "^7.0.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.3.5", - "react-i18next": "^12.1.5", + "react-hotkeys-hook": "4.4.0", + "react-i18next": "^12.2.2", "react-icons": "^4.7.1", - "react-konva": "^18.2.4", - "react-konva-utils": "^0.3.2", + "react-konva": "^18.2.7", + "react-konva-utils": "^1.0.4", "react-redux": "^8.0.5", + "react-rnd": "^10.4.1", "react-transition-group": "^4.4.5", - "react-zoom-pan-pinch": "^2.6.1", + "react-use": "^17.4.0", + "react-virtuoso": "^4.3.5", + "react-zoom-pan-pinch": "^3.0.7", "reactflow": "^11.7.0", "redux-deep-persist": "^1.0.7", "redux-dynamic-middlewares": "^2.2.0", "redux-persist": "^6.0.0", + "roarr": "^7.15.0", + "serialize-error": "^11.0.0", "socket.io-client": "^4.6.0", "use-image": "^1.1.0", "uuid": "^9.0.0" }, + "peerDependencies": { + "@chakra-ui/cli": "^2.4.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "ts-toolbelt": "^9.6.0" + }, "devDependencies": { + "@chakra-ui/cli": "^2.4.0", "@types/dateformat": "^5.0.0", - "@types/lodash": "^4.14.194", - "@types/react": "^18.0.28", - "@types/react-dom": "^18.0.11", + "@types/lodash-es": "^4.14.194", + "@types/node": "^18.16.2", + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.1", "@types/react-transition-group": "^4.4.5", "@types/uuid": "^9.0.0", - "@typescript-eslint/eslint-plugin": "^5.52.0", - "@typescript-eslint/parser": "^5.52.0", - "@vitejs/plugin-react-swc": "^3.2.0", - "axios": "^1.3.4", + "@typescript-eslint/eslint-plugin": "^5.59.1", + "@typescript-eslint/parser": "^5.59.1", + "@vitejs/plugin-react-swc": "^3.3.0", + "axios": "^1.4.0", "babel-plugin-transform-imports": "^2.0.0", - "concurrently": "^7.6.0", - "eslint": "^8.34.0", - "eslint-config-prettier": "^8.6.0", + "concurrently": "^8.0.1", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "form-data": "^4.0.0", "husky": "^8.0.3", - "lint-staged": "^13.1.2", + "lint-staged": "^13.2.2", "madge": "^6.0.0", "openapi-types": "^12.1.0", - "openapi-typescript-codegen": "^0.23.0", + "openapi-typescript-codegen": "^0.24.0", "postinstall-postinstall": "^2.1.0", - "prettier": "^2.8.4", + "prettier": "^2.8.8", "rollup-plugin-visualizer": "^5.9.0", - "terser": "^5.16.4", + "terser": "^5.17.1", "ts-toolbelt": "^9.6.0", - "typescript": "4.9.5", - "vite": "^4.1.2", + "vite": "^4.3.3", + "vite-plugin-dts": "^2.3.0", "vite-plugin-eslint": "^1.8.1", - "vite-tsconfig-paths": "^4.0.5", + "vite-tsconfig-paths": "^4.2.0", "yarn": "^1.22.19" } } diff --git a/invokeai/frontend/web/patches/@chakra-ui+cli+2.3.0.patch b/invokeai/frontend/web/patches/@chakra-ui+cli+2.4.0.patch similarity index 100% rename from invokeai/frontend/web/patches/@chakra-ui+cli+2.3.0.patch rename to invokeai/frontend/web/patches/@chakra-ui+cli+2.4.0.patch diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index e5245c7ad5..876cd96b39 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -527,10 +527,15 @@ "useCanvasBeta": "Use Canvas Beta Layout", "enableImageDebugging": "Enable Image Debugging", "useSlidersForAll": "Use Sliders For All Options", + "autoShowProgress": "Auto Show Progress Images", "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. Refresh the page to reload.", + "consoleLogLevel": "Log Level", + "shouldLogToConsole": "Console Logging", + "developer": "Developer", + "general": "General" }, "toast": { "serverError": "Server Error", @@ -641,5 +646,9 @@ "betaDarkenOutside": "Darken Outside", "betaLimitToBox": "Limit To Box", "betaPreserveMasked": "Preserve Masked" + }, + "ui": { + "showProgressImages": "Show Progress Images", + "hideProgressImages": "Hide Progress Images" } } diff --git a/invokeai/frontend/web/src/app/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx similarity index 82% rename from invokeai/frontend/web/src/app/App.tsx rename to invokeai/frontend/web/src/app/components/App.tsx index f30bdc0eb3..3aebfa4097 100644 --- a/invokeai/frontend/web/src/app/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -1,9 +1,7 @@ import ImageUploader from 'common/components/ImageUploader'; -import Console from 'features/system/components/Console'; import ProgressBar from 'features/system/components/ProgressBar'; import SiteHeader from 'features/system/components/SiteHeader'; import InvokeTabs from 'features/ui/components/InvokeTabs'; -import { keepGUIAlive } from './utils'; import useToastWatcher from 'features/system/hooks/useToastWatcher'; @@ -13,25 +11,34 @@ import { Box, Flex, Grid, Portal, useColorMode } from '@chakra-ui/react'; import { APP_HEIGHT, APP_WIDTH } from 'theme/util/constants'; import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel'; import Lightbox from 'features/lightbox/components/Lightbox'; -import { useAppDispatch, useAppSelector } from './storeHooks'; -import { PropsWithChildren, useCallback, useEffect, useState } from 'react'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { + memo, + PropsWithChildren, + useCallback, + useEffect, + useState, +} from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import Loading from 'common/components/Loading/Loading'; import { useIsApplicationReady } from 'features/system/hooks/useIsApplicationReady'; -import { PartialAppConfig } from './invokeai'; +import { PartialAppConfig } from 'app/types/invokeai'; import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys'; import { configChanged } from 'features/system/store/configSlice'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; +import { useLogger } from 'app/logging/useLogger'; +import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview'; -keepGUIAlive(); +const DEFAULT_CONFIG = {}; interface Props extends PropsWithChildren { config?: PartialAppConfig; } -const App = ({ config = {}, children }: Props) => { +const App = ({ config = DEFAULT_CONFIG, children }: Props) => { useToastWatcher(); useGlobalHotkeys(); + const log = useLogger(); const currentTheme = useAppSelector((state) => state.ui.currentTheme); @@ -45,9 +52,9 @@ const App = ({ config = {}, children }: Props) => { const dispatch = useAppDispatch(); useEffect(() => { - console.log('Received config: ', config); + log.info({ namespace: 'App', data: config }, 'Received config'); dispatch(configChanged(config)); - }, [dispatch, config]); + }, [dispatch, config, log]); useEffect(() => { setColorMode(['light'].includes(currentTheme) ? 'light' : 'dark'); @@ -58,7 +65,7 @@ const App = ({ config = {}, children }: Props) => { }, []); return ( - + {isLightboxEnabled && } @@ -114,11 +121,9 @@ const App = ({ config = {}, children }: Props) => { - - - + ); }; -export default App; +export default memo(App); diff --git a/invokeai/frontend/web/src/component.tsx b/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx similarity index 73% rename from invokeai/frontend/web/src/component.tsx rename to invokeai/frontend/web/src/app/components/InvokeAIUI.tsx index ae962b4ba1..97a8be6fc1 100644 --- a/invokeai/frontend/web/src/component.tsx +++ b/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx @@ -1,8 +1,8 @@ -import React, { lazy, PropsWithChildren, useEffect } from 'react'; +import React, { lazy, memo, PropsWithChildren, useEffect } from 'react'; import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; -import { buildMiddleware, store } from './app/store'; -import { persistor } from './persistor'; +import { store } from 'app/store/store'; +import { persistor } from '../store/persistor'; import { OpenAPI } from 'services/api'; import '@fontsource/inter/100.css'; import '@fontsource/inter/200.css'; @@ -14,14 +14,15 @@ import '@fontsource/inter/700.css'; import '@fontsource/inter/800.css'; import '@fontsource/inter/900.css'; -import Loading from './common/components/Loading/Loading'; +import Loading from '../../common/components/Loading/Loading'; import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares'; -import { PartialAppConfig } from 'app/invokeai'; +import { PartialAppConfig } from 'app/types/invokeai'; -import './i18n'; +import '../../i18n'; +import { socketMiddleware } from 'services/events/middleware'; -const App = lazy(() => import('./app/App')); -const ThemeLocaleProvider = lazy(() => import('./app/ThemeLocaleProvider')); +const App = lazy(() => import('./App')); +const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider')); interface Props extends PropsWithChildren { apiUrl?: string; @@ -29,7 +30,7 @@ interface Props extends PropsWithChildren { config?: PartialAppConfig; } -export default function Component({ apiUrl, token, config, children }: Props) { +const InvokeAIUI = ({ apiUrl, token, config, children }: Props) => { useEffect(() => { // configure API client token if (token) { @@ -50,7 +51,7 @@ export default function Component({ apiUrl, token, config, children }: Props) { // the `apiUrl`/`token` dynamically. // rebuild socket middleware with token and apiUrl - addMiddleware(buildMiddleware()); + addMiddleware(socketMiddleware()); }, [apiUrl, token]); return ( @@ -66,4 +67,6 @@ export default function Component({ apiUrl, token, config, children }: Props) { ); -} +}; + +export default memo(InvokeAIUI); diff --git a/invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx b/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx similarity index 88% rename from invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx rename to invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx index e7054edcc4..f0e2e75240 100644 --- a/invokeai/frontend/web/src/app/ThemeLocaleProvider.tsx +++ b/invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx @@ -2,8 +2,8 @@ import { ChakraProvider, extendTheme } from '@chakra-ui/react'; import { ReactNode, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { theme as invokeAITheme } from 'theme/theme'; -import { RootState } from './store'; -import { useAppSelector } from './storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { greenTeaThemeColors } from 'theme/colors/greenTea'; import { invokeAIThemeColors } from 'theme/colors/invokeAI'; @@ -18,6 +18,8 @@ import '@fontsource/inter/600.css'; import '@fontsource/inter/700.css'; import '@fontsource/inter/800.css'; import '@fontsource/inter/900.css'; +import 'overlayscrollbars/overlayscrollbars.css'; +import 'theme/css/overlayscrollbars.css'; type ThemeLocaleProviderProps = { children: ReactNode; diff --git a/invokeai/frontend/web/src/app/constants.ts b/invokeai/frontend/web/src/app/constants.ts index b9cd5839df..534ca9e29a 100644 --- a/invokeai/frontend/web/src/app/constants.ts +++ b/invokeai/frontend/web/src/app/constants.ts @@ -1,23 +1,6 @@ // TODO: use Enums? -import { InProgressImageType } from 'features/system/store/systemSlice'; - -// Valid samplers -export const SAMPLERS: Array = [ - 'ddim', - 'plms', - 'k_lms', - 'k_dpm_2', - 'k_dpm_2_a', - 'k_dpmpp_2', - 'k_dpmpp_2_a', - 'k_euler', - 'k_euler_a', - 'k_heun', -]; - -// Valid Diffusers Samplers -export const DIFFUSERS_SAMPLERS: Array = [ +export const DIFFUSERS_SCHEDULERS: Array = [ 'ddim', 'plms', 'k_lms', @@ -48,17 +31,8 @@ export const UPSCALING_LEVELS: Array<{ key: string; value: number }> = [ export const NUMPY_RAND_MIN = 0; -export const NUMPY_RAND_MAX = 4294967295; +export const NUMPY_RAND_MAX = 2147483647; export const FACETOOL_TYPES = ['gfpgan', 'codeformer'] as const; -export const IN_PROGRESS_IMAGE_TYPES: Array<{ - key: string; - value: InProgressImageType; -}> = [ - { key: 'None', value: 'none' }, - { key: 'Fast', value: 'latents' }, - { key: 'Accurate', value: 'full-res' }, -]; - export const NODE_MIN_WIDTH = 250; diff --git a/invokeai/frontend/web/src/app/logging/useLogger.ts b/invokeai/frontend/web/src/app/logging/useLogger.ts new file mode 100644 index 0000000000..c69b13dc72 --- /dev/null +++ b/invokeai/frontend/web/src/app/logging/useLogger.ts @@ -0,0 +1,94 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { useAppSelector } from 'app/store/storeHooks'; +import { systemSelector } from 'features/system/store/systemSelectors'; +import { isEqual } from 'lodash-es'; +import { useEffect } from 'react'; +import { LogLevelName, ROARR, Roarr } from 'roarr'; +import { createLogWriter } from '@roarr/browser-log-writer'; + +// Base logging context includes only the package name +const baseContext = { package: '@invoke-ai/invoke-ai-ui' }; + +// Create browser log writer +ROARR.write = createLogWriter(); + +// Module-scoped logger - can be imported and used anywhere +export let log = Roarr.child(baseContext); + +// Translate human-readable log levels to numbers, used for log filtering +export const LOG_LEVEL_MAP: Record = { + trace: 10, + debug: 20, + info: 30, + warn: 40, + error: 50, + fatal: 60, +}; + +export const VALID_LOG_LEVELS = [ + 'trace', + 'debug', + 'info', + 'warn', + 'error', + 'fatal', +] as const; + +export type InvokeLogLevel = (typeof VALID_LOG_LEVELS)[number]; + +const selector = createSelector( + systemSelector, + (system) => { + const { app_version, consoleLogLevel, shouldLogToConsole } = system; + + return { + version: app_version, + consoleLogLevel, + shouldLogToConsole, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +export const useLogger = () => { + const { version, consoleLogLevel, shouldLogToConsole } = + useAppSelector(selector); + + // The provided Roarr browser log writer uses localStorage to config logging to console + useEffect(() => { + if (shouldLogToConsole) { + // Enable console log output + localStorage.setItem('ROARR_LOG', 'true'); + + // Use a filter to show only logs of the given level + localStorage.setItem( + 'ROARR_FILTER', + `context.logLevel:>=${LOG_LEVEL_MAP[consoleLogLevel]}` + ); + } else { + // Disable console log output + localStorage.setItem('ROARR_LOG', 'false'); + } + ROARR.write = createLogWriter(); + }, [consoleLogLevel, shouldLogToConsole]); + + // Update the module-scoped logger context as needed + useEffect(() => { + const newContext: Record = { + ...baseContext, + }; + + if (version) { + newContext.version = version; + } + + log = Roarr.child(newContext); + }, [version]); + + // Use the logger within components - no different than just importing it directly + return log; +}; diff --git a/invokeai/frontend/web/src/app/selectors/readinessSelector.ts b/invokeai/frontend/web/src/app/selectors/readinessSelector.ts index 82672756c8..d70043e545 100644 --- a/invokeai/frontend/web/src/app/selectors/readinessSelector.ts +++ b/invokeai/frontend/web/src/app/selectors/readinessSelector.ts @@ -4,7 +4,7 @@ import { initialCanvasImageSelector } from 'features/canvas/store/canvasSelector import { generationSelector } from 'features/parameters/store/generationSelectors'; import { systemSelector } from 'features/system/store/systemSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; export const readinessSelector = createSelector( [ diff --git a/invokeai/frontend/web/src/app/socketio/actions.ts b/invokeai/frontend/web/src/app/socketio/actions.ts index 4907595c75..bb2a0dd0cb 100644 --- a/invokeai/frontend/web/src/app/socketio/actions.ts +++ b/invokeai/frontend/web/src/app/socketio/actions.ts @@ -1,65 +1,67 @@ -import { createAction } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; -import { GalleryCategory } from 'features/gallery/store/gallerySlice'; -import { InvokeTabName } from 'features/ui/store/tabMap'; +// import { createAction } from '@reduxjs/toolkit'; +// import * as InvokeAI from 'app/types/invokeai'; +// import { GalleryCategory } from 'features/gallery/store/gallerySlice'; +// import { InvokeTabName } from 'features/ui/store/tabMap'; -/** - * We can't use redux-toolkit's createSlice() to make these actions, - * because they have no associated reducer. They only exist to dispatch - * requests to the server via socketio. These actions will be handled - * by the middleware. - */ +// /** +// * We can't use redux-toolkit's createSlice() to make these actions, +// * because they have no associated reducer. They only exist to dispatch +// * requests to the server via socketio. These actions will be handled +// * by the middleware. +// */ -export const generateImage = createAction( - 'socketio/generateImage' -); -export const runESRGAN = createAction('socketio/runESRGAN'); -export const runFacetool = createAction( - 'socketio/runFacetool' -); -export const deleteImage = createAction( - 'socketio/deleteImage' -); -export const requestImages = createAction( - 'socketio/requestImages' -); -export const requestNewImages = createAction( - 'socketio/requestNewImages' -); -export const cancelProcessing = createAction( - 'socketio/cancelProcessing' -); +// export const generateImage = createAction( +// 'socketio/generateImage' +// ); +// export const runESRGAN = createAction('socketio/runESRGAN'); +// export const runFacetool = createAction( +// 'socketio/runFacetool' +// ); +// export const deleteImage = createAction( +// 'socketio/deleteImage' +// ); +// export const requestImages = createAction( +// 'socketio/requestImages' +// ); +// export const requestNewImages = createAction( +// 'socketio/requestNewImages' +// ); +// export const cancelProcessing = createAction( +// 'socketio/cancelProcessing' +// ); -export const requestSystemConfig = createAction( - 'socketio/requestSystemConfig' -); +// export const requestSystemConfig = createAction( +// 'socketio/requestSystemConfig' +// ); -export const searchForModels = createAction('socketio/searchForModels'); +// export const searchForModels = createAction('socketio/searchForModels'); -export const addNewModel = createAction< - InvokeAI.InvokeModelConfigProps | InvokeAI.InvokeDiffusersModelConfigProps ->('socketio/addNewModel'); +// export const addNewModel = createAction< +// InvokeAI.InvokeModelConfigProps | InvokeAI.InvokeDiffusersModelConfigProps +// >('socketio/addNewModel'); -export const deleteModel = createAction('socketio/deleteModel'); +// export const deleteModel = createAction('socketio/deleteModel'); -export const convertToDiffusers = - createAction( - 'socketio/convertToDiffusers' - ); +// export const convertToDiffusers = +// createAction( +// 'socketio/convertToDiffusers' +// ); -export const mergeDiffusersModels = - createAction( - 'socketio/mergeDiffusersModels' - ); +// export const mergeDiffusersModels = +// createAction( +// 'socketio/mergeDiffusersModels' +// ); -export const requestModelChange = createAction( - 'socketio/requestModelChange' -); +// export const requestModelChange = createAction( +// 'socketio/requestModelChange' +// ); -export const saveStagingAreaImageToGallery = createAction( - 'socketio/saveStagingAreaImageToGallery' -); +// export const saveStagingAreaImageToGallery = createAction( +// 'socketio/saveStagingAreaImageToGallery' +// ); -export const emptyTempFolder = createAction( - 'socketio/requestEmptyTempFolder' -); +// export const emptyTempFolder = createAction( +// 'socketio/requestEmptyTempFolder' +// ); + +export default {}; diff --git a/invokeai/frontend/web/src/app/socketio/emitters.ts b/invokeai/frontend/web/src/app/socketio/emitters.ts index cd25319aee..ad7979503f 100644 --- a/invokeai/frontend/web/src/app/socketio/emitters.ts +++ b/invokeai/frontend/web/src/app/socketio/emitters.ts @@ -1,208 +1,209 @@ -import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; -import type { RootState } from 'app/store'; -import { - frontendToBackendParameters, - FrontendToBackendParametersConfig, -} from 'common/util/parameterTranslation'; -import dateFormat from 'dateformat'; -import { - GalleryCategory, - GalleryState, - removeImage, -} from 'features/gallery/store/gallerySlice'; -import { - addLogEntry, - generationRequested, - modelChangeRequested, - modelConvertRequested, - modelMergingRequested, - setIsProcessing, -} from 'features/system/store/systemSlice'; -import { InvokeTabName } from 'features/ui/store/tabMap'; -import { Socket } from 'socket.io-client'; +// import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit'; +// import * as InvokeAI from 'app/types/invokeai'; +// import type { RootState } from 'app/store/store'; +// import { +// frontendToBackendParameters, +// FrontendToBackendParametersConfig, +// } from 'common/util/parameterTranslation'; +// import dateFormat from 'dateformat'; +// import { +// GalleryCategory, +// GalleryState, +// removeImage, +// } from 'features/gallery/store/gallerySlice'; +// import { +// generationRequested, +// modelChangeRequested, +// modelConvertRequested, +// modelMergingRequested, +// setIsProcessing, +// } from 'features/system/store/systemSlice'; +// import { InvokeTabName } from 'features/ui/store/tabMap'; +// import { Socket } from 'socket.io-client'; -/** - * Returns an object containing all functions which use `socketio.emit()`. - * i.e. those which make server requests. - */ -const makeSocketIOEmitters = ( - store: MiddlewareAPI, RootState>, - socketio: Socket -) => { - // We need to dispatch actions to redux and get pieces of state from the store. - const { dispatch, getState } = store; +// /** +// * Returns an object containing all functions which use `socketio.emit()`. +// * i.e. those which make server requests. +// */ +// const makeSocketIOEmitters = ( +// store: MiddlewareAPI, RootState>, +// socketio: Socket +// ) => { +// // We need to dispatch actions to redux and get pieces of state from the store. +// const { dispatch, getState } = store; - return { - emitGenerateImage: (generationMode: InvokeTabName) => { - dispatch(setIsProcessing(true)); +// return { +// emitGenerateImage: (generationMode: InvokeTabName) => { +// dispatch(setIsProcessing(true)); - const state: RootState = getState(); +// const state: RootState = getState(); - const { - generation: generationState, - postprocessing: postprocessingState, - system: systemState, - canvas: canvasState, - } = state; +// const { +// generation: generationState, +// postprocessing: postprocessingState, +// system: systemState, +// canvas: canvasState, +// } = state; - const frontendToBackendParametersConfig: FrontendToBackendParametersConfig = - { - generationMode, - generationState, - postprocessingState, - canvasState, - systemState, - }; +// const frontendToBackendParametersConfig: FrontendToBackendParametersConfig = +// { +// generationMode, +// generationState, +// postprocessingState, +// canvasState, +// systemState, +// }; - dispatch(generationRequested()); +// dispatch(generationRequested()); - const { generationParameters, esrganParameters, facetoolParameters } = - frontendToBackendParameters(frontendToBackendParametersConfig); +// const { generationParameters, esrganParameters, facetoolParameters } = +// frontendToBackendParameters(frontendToBackendParametersConfig); - socketio.emit( - 'generateImage', - generationParameters, - esrganParameters, - facetoolParameters - ); +// socketio.emit( +// 'generateImage', +// generationParameters, +// esrganParameters, +// facetoolParameters +// ); - // we need to truncate the init_mask base64 else it takes up the whole log - // TODO: handle maintaining masks for reproducibility in future - if (generationParameters.init_mask) { - generationParameters.init_mask = generationParameters.init_mask - .substr(0, 64) - .concat('...'); - } - if (generationParameters.init_img) { - generationParameters.init_img = generationParameters.init_img - .substr(0, 64) - .concat('...'); - } +// // we need to truncate the init_mask base64 else it takes up the whole log +// // TODO: handle maintaining masks for reproducibility in future +// if (generationParameters.init_mask) { +// generationParameters.init_mask = generationParameters.init_mask +// .substr(0, 64) +// .concat('...'); +// } +// if (generationParameters.init_img) { +// generationParameters.init_img = generationParameters.init_img +// .substr(0, 64) +// .concat('...'); +// } - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Image generation requested: ${JSON.stringify({ - ...generationParameters, - ...esrganParameters, - ...facetoolParameters, - })}`, - }) - ); - }, - emitRunESRGAN: (imageToProcess: InvokeAI._Image) => { - dispatch(setIsProcessing(true)); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Image generation requested: ${JSON.stringify({ +// ...generationParameters, +// ...esrganParameters, +// ...facetoolParameters, +// })}`, +// }) +// ); +// }, +// emitRunESRGAN: (imageToProcess: InvokeAI._Image) => { +// dispatch(setIsProcessing(true)); - const { - postprocessing: { - upscalingLevel, - upscalingDenoising, - upscalingStrength, - }, - } = getState(); +// const { +// postprocessing: { +// upscalingLevel, +// upscalingDenoising, +// upscalingStrength, +// }, +// } = getState(); - const esrganParameters = { - upscale: [upscalingLevel, upscalingDenoising, upscalingStrength], - }; - socketio.emit('runPostprocessing', imageToProcess, { - type: 'esrgan', - ...esrganParameters, - }); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `ESRGAN upscale requested: ${JSON.stringify({ - file: imageToProcess.url, - ...esrganParameters, - })}`, - }) - ); - }, - emitRunFacetool: (imageToProcess: InvokeAI._Image) => { - dispatch(setIsProcessing(true)); +// const esrganParameters = { +// upscale: [upscalingLevel, upscalingDenoising, upscalingStrength], +// }; +// socketio.emit('runPostprocessing', imageToProcess, { +// type: 'esrgan', +// ...esrganParameters, +// }); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `ESRGAN upscale requested: ${JSON.stringify({ +// file: imageToProcess.url, +// ...esrganParameters, +// })}`, +// }) +// ); +// }, +// emitRunFacetool: (imageToProcess: InvokeAI._Image) => { +// dispatch(setIsProcessing(true)); - const { - postprocessing: { facetoolType, facetoolStrength, codeformerFidelity }, - } = getState(); +// const { +// postprocessing: { facetoolType, facetoolStrength, codeformerFidelity }, +// } = getState(); - const facetoolParameters: Record = { - facetool_strength: facetoolStrength, - }; +// const facetoolParameters: Record = { +// facetool_strength: facetoolStrength, +// }; - if (facetoolType === 'codeformer') { - facetoolParameters.codeformer_fidelity = codeformerFidelity; - } +// if (facetoolType === 'codeformer') { +// facetoolParameters.codeformer_fidelity = codeformerFidelity; +// } - socketio.emit('runPostprocessing', imageToProcess, { - type: facetoolType, - ...facetoolParameters, - }); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Face restoration (${facetoolType}) requested: ${JSON.stringify( - { - file: imageToProcess.url, - ...facetoolParameters, - } - )}`, - }) - ); - }, - emitDeleteImage: (imageToDelete: InvokeAI._Image) => { - const { url, uuid, category, thumbnail } = imageToDelete; - dispatch(removeImage(imageToDelete)); - socketio.emit('deleteImage', url, thumbnail, uuid, category); - }, - emitRequestImages: (category: GalleryCategory) => { - const gallery: GalleryState = getState().gallery; - const { earliest_mtime } = gallery.categories[category]; - socketio.emit('requestImages', category, earliest_mtime); - }, - emitRequestNewImages: (category: GalleryCategory) => { - const gallery: GalleryState = getState().gallery; - const { latest_mtime } = gallery.categories[category]; - socketio.emit('requestLatestImages', category, latest_mtime); - }, - emitCancelProcessing: () => { - socketio.emit('cancel'); - }, - emitRequestSystemConfig: () => { - socketio.emit('requestSystemConfig'); - }, - emitSearchForModels: (modelFolder: string) => { - socketio.emit('searchForModels', modelFolder); - }, - emitAddNewModel: (modelConfig: InvokeAI.InvokeModelConfigProps) => { - socketio.emit('addNewModel', modelConfig); - }, - emitDeleteModel: (modelName: string) => { - socketio.emit('deleteModel', modelName); - }, - emitConvertToDiffusers: ( - modelToConvert: InvokeAI.InvokeModelConversionProps - ) => { - dispatch(modelConvertRequested()); - socketio.emit('convertToDiffusers', modelToConvert); - }, - emitMergeDiffusersModels: ( - modelMergeInfo: InvokeAI.InvokeModelMergingProps - ) => { - dispatch(modelMergingRequested()); - socketio.emit('mergeDiffusersModels', modelMergeInfo); - }, - emitRequestModelChange: (modelName: string) => { - dispatch(modelChangeRequested()); - socketio.emit('requestModelChange', modelName); - }, - emitSaveStagingAreaImageToGallery: (url: string) => { - socketio.emit('requestSaveStagingAreaImageToGallery', url); - }, - emitRequestEmptyTempFolder: () => { - socketio.emit('requestEmptyTempFolder'); - }, - }; -}; +// socketio.emit('runPostprocessing', imageToProcess, { +// type: facetoolType, +// ...facetoolParameters, +// }); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Face restoration (${facetoolType}) requested: ${JSON.stringify( +// { +// file: imageToProcess.url, +// ...facetoolParameters, +// } +// )}`, +// }) +// ); +// }, +// emitDeleteImage: (imageToDelete: InvokeAI._Image) => { +// const { url, uuid, category, thumbnail } = imageToDelete; +// dispatch(removeImage(imageToDelete)); +// socketio.emit('deleteImage', url, thumbnail, uuid, category); +// }, +// emitRequestImages: (category: GalleryCategory) => { +// const gallery: GalleryState = getState().gallery; +// const { earliest_mtime } = gallery.categories[category]; +// socketio.emit('requestImages', category, earliest_mtime); +// }, +// emitRequestNewImages: (category: GalleryCategory) => { +// const gallery: GalleryState = getState().gallery; +// const { latest_mtime } = gallery.categories[category]; +// socketio.emit('requestLatestImages', category, latest_mtime); +// }, +// emitCancelProcessing: () => { +// socketio.emit('cancel'); +// }, +// emitRequestSystemConfig: () => { +// socketio.emit('requestSystemConfig'); +// }, +// emitSearchForModels: (modelFolder: string) => { +// socketio.emit('searchForModels', modelFolder); +// }, +// emitAddNewModel: (modelConfig: InvokeAI.InvokeModelConfigProps) => { +// socketio.emit('addNewModel', modelConfig); +// }, +// emitDeleteModel: (modelName: string) => { +// socketio.emit('deleteModel', modelName); +// }, +// emitConvertToDiffusers: ( +// modelToConvert: InvokeAI.InvokeModelConversionProps +// ) => { +// dispatch(modelConvertRequested()); +// socketio.emit('convertToDiffusers', modelToConvert); +// }, +// emitMergeDiffusersModels: ( +// modelMergeInfo: InvokeAI.InvokeModelMergingProps +// ) => { +// dispatch(modelMergingRequested()); +// socketio.emit('mergeDiffusersModels', modelMergeInfo); +// }, +// emitRequestModelChange: (modelName: string) => { +// dispatch(modelChangeRequested()); +// socketio.emit('requestModelChange', modelName); +// }, +// emitSaveStagingAreaImageToGallery: (url: string) => { +// socketio.emit('requestSaveStagingAreaImageToGallery', url); +// }, +// emitRequestEmptyTempFolder: () => { +// socketio.emit('requestEmptyTempFolder'); +// }, +// }; +// }; -export default makeSocketIOEmitters; +// export default makeSocketIOEmitters; + +export default {}; diff --git a/invokeai/frontend/web/src/app/socketio/listeners.ts b/invokeai/frontend/web/src/app/socketio/listeners.ts index dc6c35d862..cb6db260fc 100644 --- a/invokeai/frontend/web/src/app/socketio/listeners.ts +++ b/invokeai/frontend/web/src/app/socketio/listeners.ts @@ -1,501 +1,502 @@ -import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit'; -import dateFormat from 'dateformat'; -import i18n from 'i18n'; -import { v4 as uuidv4 } from 'uuid'; +// import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit'; +// import dateFormat from 'dateformat'; +// import i18n from 'i18n'; +// import { v4 as uuidv4 } from 'uuid'; -import * as InvokeAI from 'app/invokeai'; +// import * as InvokeAI from 'app/types/invokeai'; -import { - addLogEntry, - addToast, - errorOccurred, - processingCanceled, - setCurrentStatus, - setFoundModels, - setIsCancelable, - setIsConnected, - setIsProcessing, - setModelList, - setSearchFolder, - setSystemConfig, - setSystemStatus, -} from 'features/system/store/systemSlice'; +// import { +// addToast, +// errorOccurred, +// processingCanceled, +// setCurrentStatus, +// setFoundModels, +// setIsCancelable, +// setIsConnected, +// setIsProcessing, +// setModelList, +// setSearchFolder, +// setSystemConfig, +// setSystemStatus, +// } from 'features/system/store/systemSlice'; -import { - addGalleryImages, - addImage, - clearIntermediateImage, - GalleryState, - removeImage, - setIntermediateImage, -} from 'features/gallery/store/gallerySlice'; +// import { +// addGalleryImages, +// addImage, +// clearIntermediateImage, +// GalleryState, +// removeImage, +// setIntermediateImage, +// } from 'features/gallery/store/gallerySlice'; -import type { RootState } from 'app/store'; -import { addImageToStagingArea } from 'features/canvas/store/canvasSlice'; -import { - clearInitialImage, - initialImageSelected, - setInfillMethod, - // setInitialImage, - setMaskPath, -} from 'features/parameters/store/generationSlice'; -import { tabMap } from 'features/ui/store/tabMap'; -import { - requestImages, - requestNewImages, - requestSystemConfig, -} from './actions'; +// import type { RootState } from 'app/store/store'; +// import { addImageToStagingArea } from 'features/canvas/store/canvasSlice'; +// import { +// clearInitialImage, +// initialImageSelected, +// setInfillMethod, +// // setInitialImage, +// setMaskPath, +// } from 'features/parameters/store/generationSlice'; +// import { tabMap } from 'features/ui/store/tabMap'; +// import { +// requestImages, +// requestNewImages, +// requestSystemConfig, +// } from './actions'; -/** - * Returns an object containing listener callbacks for socketio events. - * TODO: This file is large, but simple. Should it be split up further? - */ -const makeSocketIOListeners = ( - store: MiddlewareAPI, RootState> -) => { - const { dispatch, getState } = store; +// /** +// * Returns an object containing listener callbacks for socketio events. +// * TODO: This file is large, but simple. Should it be split up further? +// */ +// const makeSocketIOListeners = ( +// store: MiddlewareAPI, RootState> +// ) => { +// const { dispatch, getState } = store; - return { - /** - * Callback to run when we receive a 'connect' event. - */ - onConnect: () => { - try { - dispatch(setIsConnected(true)); - dispatch(setCurrentStatus(i18n.t('common.statusConnected'))); - dispatch(requestSystemConfig()); - const gallery: GalleryState = getState().gallery; +// return { +// /** +// * Callback to run when we receive a 'connect' event. +// */ +// onConnect: () => { +// try { +// dispatch(setIsConnected(true)); +// dispatch(setCurrentStatus(i18n.t('common.statusConnected'))); +// dispatch(requestSystemConfig()); +// const gallery: GalleryState = getState().gallery; - if (gallery.categories.result.latest_mtime) { - dispatch(requestNewImages('result')); - } else { - dispatch(requestImages('result')); - } +// if (gallery.categories.result.latest_mtime) { +// dispatch(requestNewImages('result')); +// } else { +// dispatch(requestImages('result')); +// } - if (gallery.categories.user.latest_mtime) { - dispatch(requestNewImages('user')); - } else { - dispatch(requestImages('user')); - } - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive a 'disconnect' event. - */ - onDisconnect: () => { - try { - dispatch(setIsConnected(false)); - dispatch(setCurrentStatus(i18n.t('common.statusDisconnected'))); +// if (gallery.categories.user.latest_mtime) { +// dispatch(requestNewImages('user')); +// } else { +// dispatch(requestImages('user')); +// } +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive a 'disconnect' event. +// */ +// onDisconnect: () => { +// try { +// dispatch(setIsConnected(false)); +// dispatch(setCurrentStatus(i18n.t('common.statusDisconnected'))); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Disconnected from server`, - level: 'warning', - }) - ); - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive a 'generationResult' event. - */ - onGenerationResult: (data: InvokeAI.ImageResultResponse) => { - try { - const state = getState(); - const { activeTab } = state.ui; - const { shouldLoopback } = state.postprocessing; - const { boundingBox: _, generationMode, ...rest } = data; +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Disconnected from server`, +// level: 'warning', +// }) +// ); +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive a 'generationResult' event. +// */ +// onGenerationResult: (data: InvokeAI.ImageResultResponse) => { +// try { +// const state = getState(); +// const { activeTab } = state.ui; +// const { shouldLoopback } = state.postprocessing; +// const { boundingBox: _, generationMode, ...rest } = data; - const newImage = { - uuid: uuidv4(), - ...rest, - }; +// const newImage = { +// uuid: uuidv4(), +// ...rest, +// }; - if (['txt2img', 'img2img'].includes(generationMode)) { - dispatch( - addImage({ - category: 'result', - image: { ...newImage, category: 'result' }, - }) - ); - } +// if (['txt2img', 'img2img'].includes(generationMode)) { +// dispatch( +// addImage({ +// category: 'result', +// image: { ...newImage, category: 'result' }, +// }) +// ); +// } - if (generationMode === 'unifiedCanvas' && data.boundingBox) { - const { boundingBox } = data; - dispatch( - addImageToStagingArea({ - image: { ...newImage, category: 'temp' }, - boundingBox, - }) - ); +// if (generationMode === 'unifiedCanvas' && data.boundingBox) { +// const { boundingBox } = data; +// dispatch( +// addImageToStagingArea({ +// image: { ...newImage, category: 'temp' }, +// boundingBox, +// }) +// ); - if (state.canvas.shouldAutoSave) { - dispatch( - addImage({ - image: { ...newImage, category: 'result' }, - category: 'result', - }) - ); - } - } +// if (state.canvas.shouldAutoSave) { +// dispatch( +// addImage({ +// image: { ...newImage, category: 'result' }, +// category: 'result', +// }) +// ); +// } +// } - // TODO: fix - // if (shouldLoopback) { - // const activeTabName = tabMap[activeTab]; - // switch (activeTabName) { - // case 'img2img': { - // dispatch(initialImageSelected(newImage.uuid)); - // // dispatch(setInitialImage(newImage)); - // break; - // } - // } - // } +// // TODO: fix +// // if (shouldLoopback) { +// // const activeTabName = tabMap[activeTab]; +// // switch (activeTabName) { +// // case 'img2img': { +// // dispatch(initialImageSelected(newImage.uuid)); +// // // dispatch(setInitialImage(newImage)); +// // break; +// // } +// // } +// // } - dispatch(clearIntermediateImage()); +// dispatch(clearIntermediateImage()); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Image generated: ${data.url}`, - }) - ); - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive a 'intermediateResult' event. - */ - onIntermediateResult: (data: InvokeAI.ImageResultResponse) => { - try { - dispatch( - setIntermediateImage({ - uuid: uuidv4(), - ...data, - category: 'result', - }) - ); - if (!data.isBase64) { - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Intermediate image generated: ${data.url}`, - }) - ); - } - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive an 'esrganResult' event. - */ - onPostprocessingResult: (data: InvokeAI.ImageResultResponse) => { - try { - dispatch( - addImage({ - category: 'result', - image: { - uuid: uuidv4(), - ...data, - category: 'result', - }, - }) - ); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Image generated: ${data.url}`, +// }) +// ); +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive a 'intermediateResult' event. +// */ +// onIntermediateResult: (data: InvokeAI.ImageResultResponse) => { +// try { +// dispatch( +// setIntermediateImage({ +// uuid: uuidv4(), +// ...data, +// category: 'result', +// }) +// ); +// if (!data.isBase64) { +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Intermediate image generated: ${data.url}`, +// }) +// ); +// } +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive an 'esrganResult' event. +// */ +// onPostprocessingResult: (data: InvokeAI.ImageResultResponse) => { +// try { +// dispatch( +// addImage({ +// category: 'result', +// image: { +// uuid: uuidv4(), +// ...data, +// category: 'result', +// }, +// }) +// ); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Postprocessed: ${data.url}`, - }) - ); - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive a 'progressUpdate' event. - * TODO: Add additional progress phases - */ - onProgressUpdate: (data: InvokeAI.SystemStatus) => { - try { - dispatch(setIsProcessing(true)); - dispatch(setSystemStatus(data)); - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive a 'progressUpdate' event. - */ - onError: (data: InvokeAI.ErrorResponse) => { - const { message, additionalData } = data; +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Postprocessed: ${data.url}`, +// }) +// ); +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive a 'progressUpdate' event. +// * TODO: Add additional progress phases +// */ +// onProgressUpdate: (data: InvokeAI.SystemStatus) => { +// try { +// dispatch(setIsProcessing(true)); +// dispatch(setSystemStatus(data)); +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive a 'progressUpdate' event. +// */ +// onError: (data: InvokeAI.ErrorResponse) => { +// const { message, additionalData } = data; - if (additionalData) { - // TODO: handle more data than short message - } +// if (additionalData) { +// // TODO: handle more data than short message +// } - try { - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Server error: ${message}`, - level: 'error', - }) - ); - dispatch(errorOccurred()); - dispatch(clearIntermediateImage()); - } catch (e) { - console.error(e); - } - }, - /** - * Callback to run when we receive a 'galleryImages' event. - */ - onGalleryImages: (data: InvokeAI.GalleryImagesResponse) => { - const { images, areMoreImagesAvailable, category } = data; +// try { +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Server error: ${message}`, +// level: 'error', +// }) +// ); +// dispatch(errorOccurred()); +// dispatch(clearIntermediateImage()); +// } catch (e) { +// console.error(e); +// } +// }, +// /** +// * Callback to run when we receive a 'galleryImages' event. +// */ +// onGalleryImages: (data: InvokeAI.GalleryImagesResponse) => { +// const { images, areMoreImagesAvailable, category } = data; - /** - * the logic here ideally would be in the reducer but we have a side effect: - * generating a uuid. so the logic needs to be here, outside redux. - */ +// /** +// * the logic here ideally would be in the reducer but we have a side effect: +// * generating a uuid. so the logic needs to be here, outside redux. +// */ - // Generate a UUID for each image - const preparedImages = images.map((image): InvokeAI._Image => { - return { - uuid: uuidv4(), - ...image, - }; - }); +// // Generate a UUID for each image +// const preparedImages = images.map((image): InvokeAI._Image => { +// return { +// uuid: uuidv4(), +// ...image, +// }; +// }); - dispatch( - addGalleryImages({ - images: preparedImages, - areMoreImagesAvailable, - category, - }) - ); +// dispatch( +// addGalleryImages({ +// images: preparedImages, +// areMoreImagesAvailable, +// category, +// }) +// ); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Loaded ${images.length} images`, - }) - ); - }, - /** - * Callback to run when we receive a 'processingCanceled' event. - */ - onProcessingCanceled: () => { - dispatch(processingCanceled()); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Loaded ${images.length} images`, +// }) +// ); +// }, +// /** +// * Callback to run when we receive a 'processingCanceled' event. +// */ +// onProcessingCanceled: () => { +// dispatch(processingCanceled()); - const { intermediateImage } = getState().gallery; +// const { intermediateImage } = getState().gallery; - if (intermediateImage) { - if (!intermediateImage.isBase64) { - dispatch( - addImage({ - category: 'result', - image: intermediateImage, - }) - ); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Intermediate image saved: ${intermediateImage.url}`, - }) - ); - } - dispatch(clearIntermediateImage()); - } +// if (intermediateImage) { +// if (!intermediateImage.isBase64) { +// dispatch( +// addImage({ +// category: 'result', +// image: intermediateImage, +// }) +// ); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Intermediate image saved: ${intermediateImage.url}`, +// }) +// ); +// } +// dispatch(clearIntermediateImage()); +// } - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Processing canceled`, - level: 'warning', - }) - ); - }, - /** - * Callback to run when we receive a 'imageDeleted' event. - */ - onImageDeleted: (data: InvokeAI.ImageDeletedResponse) => { - const { url } = data; +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Processing canceled`, +// level: 'warning', +// }) +// ); +// }, +// /** +// * Callback to run when we receive a 'imageDeleted' event. +// */ +// onImageDeleted: (data: InvokeAI.ImageDeletedResponse) => { +// const { url } = data; - // remove image from gallery - dispatch(removeImage(data)); +// // remove image from gallery +// dispatch(removeImage(data)); - // remove references to image in options - const { - generation: { initialImage, maskPath }, - } = getState(); +// // remove references to image in options +// const { +// generation: { initialImage, maskPath }, +// } = getState(); - if ( - initialImage === url || - (initialImage as InvokeAI._Image)?.url === url - ) { - dispatch(clearInitialImage()); - } +// if ( +// initialImage === url || +// (initialImage as InvokeAI._Image)?.url === url +// ) { +// dispatch(clearInitialImage()); +// } - if (maskPath === url) { - dispatch(setMaskPath('')); - } +// if (maskPath === url) { +// dispatch(setMaskPath('')); +// } - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Image deleted: ${url}`, - }) - ); - }, - onSystemConfig: (data: InvokeAI.SystemConfig) => { - dispatch(setSystemConfig(data)); - if (!data.infill_methods.includes('patchmatch')) { - dispatch(setInfillMethod(data.infill_methods[0])); - } - }, - onFoundModels: (data: InvokeAI.FoundModelResponse) => { - const { search_folder, found_models } = data; - dispatch(setSearchFolder(search_folder)); - dispatch(setFoundModels(found_models)); - }, - onNewModelAdded: (data: InvokeAI.ModelAddedResponse) => { - const { new_model_name, model_list, update } = data; - dispatch(setModelList(model_list)); - dispatch(setIsProcessing(false)); - dispatch(setCurrentStatus(i18n.t('modelManager.modelAdded'))); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Model Added: ${new_model_name}`, - level: 'info', - }) - ); - dispatch( - addToast({ - title: !update - ? `${i18n.t('modelManager.modelAdded')}: ${new_model_name}` - : `${i18n.t('modelManager.modelUpdated')}: ${new_model_name}`, - status: 'success', - duration: 2500, - isClosable: true, - }) - ); - }, - onModelDeleted: (data: InvokeAI.ModelDeletedResponse) => { - const { deleted_model_name, model_list } = data; - dispatch(setModelList(model_list)); - dispatch(setIsProcessing(false)); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `${i18n.t( - 'modelManager.modelAdded' - )}: ${deleted_model_name}`, - level: 'info', - }) - ); - dispatch( - addToast({ - title: `${i18n.t( - 'modelManager.modelEntryDeleted' - )}: ${deleted_model_name}`, - status: 'success', - duration: 2500, - isClosable: true, - }) - ); - }, - onModelConverted: (data: InvokeAI.ModelConvertedResponse) => { - const { converted_model_name, model_list } = data; - dispatch(setModelList(model_list)); - dispatch(setCurrentStatus(i18n.t('common.statusModelConverted'))); - dispatch(setIsProcessing(false)); - dispatch(setIsCancelable(true)); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Model converted: ${converted_model_name}`, - level: 'info', - }) - ); - dispatch( - addToast({ - title: `${i18n.t( - 'modelManager.modelConverted' - )}: ${converted_model_name}`, - status: 'success', - duration: 2500, - isClosable: true, - }) - ); - }, - onModelsMerged: (data: InvokeAI.ModelsMergedResponse) => { - const { merged_models, merged_model_name, model_list } = data; - dispatch(setModelList(model_list)); - dispatch(setCurrentStatus(i18n.t('common.statusMergedModels'))); - dispatch(setIsProcessing(false)); - dispatch(setIsCancelable(true)); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Models merged: ${merged_models}`, - level: 'info', - }) - ); - dispatch( - addToast({ - title: `${i18n.t('modelManager.modelsMerged')}: ${merged_model_name}`, - status: 'success', - duration: 2500, - isClosable: true, - }) - ); - }, - onModelChanged: (data: InvokeAI.ModelChangeResponse) => { - const { model_name, model_list } = data; - dispatch(setModelList(model_list)); - dispatch(setCurrentStatus(i18n.t('common.statusModelChanged'))); - dispatch(setIsProcessing(false)); - dispatch(setIsCancelable(true)); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Model changed: ${model_name}`, - level: 'info', - }) - ); - }, - onModelChangeFailed: (data: InvokeAI.ModelChangeResponse) => { - const { model_name, model_list } = data; - dispatch(setModelList(model_list)); - dispatch(setIsProcessing(false)); - dispatch(setIsCancelable(true)); - dispatch(errorOccurred()); - dispatch( - addLogEntry({ - timestamp: dateFormat(new Date(), 'isoDateTime'), - message: `Model change failed: ${model_name}`, - level: 'error', - }) - ); - }, - onTempFolderEmptied: () => { - dispatch( - addToast({ - title: i18n.t('toast.tempFoldersEmptied'), - status: 'success', - duration: 2500, - isClosable: true, - }) - ); - }, - }; -}; +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Image deleted: ${url}`, +// }) +// ); +// }, +// onSystemConfig: (data: InvokeAI.SystemConfig) => { +// dispatch(setSystemConfig(data)); +// if (!data.infill_methods.includes('patchmatch')) { +// dispatch(setInfillMethod(data.infill_methods[0])); +// } +// }, +// onFoundModels: (data: InvokeAI.FoundModelResponse) => { +// const { search_folder, found_models } = data; +// dispatch(setSearchFolder(search_folder)); +// dispatch(setFoundModels(found_models)); +// }, +// onNewModelAdded: (data: InvokeAI.ModelAddedResponse) => { +// const { new_model_name, model_list, update } = data; +// dispatch(setModelList(model_list)); +// dispatch(setIsProcessing(false)); +// dispatch(setCurrentStatus(i18n.t('modelManager.modelAdded'))); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Model Added: ${new_model_name}`, +// level: 'info', +// }) +// ); +// dispatch( +// addToast({ +// title: !update +// ? `${i18n.t('modelManager.modelAdded')}: ${new_model_name}` +// : `${i18n.t('modelManager.modelUpdated')}: ${new_model_name}`, +// status: 'success', +// duration: 2500, +// isClosable: true, +// }) +// ); +// }, +// onModelDeleted: (data: InvokeAI.ModelDeletedResponse) => { +// const { deleted_model_name, model_list } = data; +// dispatch(setModelList(model_list)); +// dispatch(setIsProcessing(false)); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `${i18n.t( +// 'modelManager.modelAdded' +// )}: ${deleted_model_name}`, +// level: 'info', +// }) +// ); +// dispatch( +// addToast({ +// title: `${i18n.t( +// 'modelManager.modelEntryDeleted' +// )}: ${deleted_model_name}`, +// status: 'success', +// duration: 2500, +// isClosable: true, +// }) +// ); +// }, +// onModelConverted: (data: InvokeAI.ModelConvertedResponse) => { +// const { converted_model_name, model_list } = data; +// dispatch(setModelList(model_list)); +// dispatch(setCurrentStatus(i18n.t('common.statusModelConverted'))); +// dispatch(setIsProcessing(false)); +// dispatch(setIsCancelable(true)); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Model converted: ${converted_model_name}`, +// level: 'info', +// }) +// ); +// dispatch( +// addToast({ +// title: `${i18n.t( +// 'modelManager.modelConverted' +// )}: ${converted_model_name}`, +// status: 'success', +// duration: 2500, +// isClosable: true, +// }) +// ); +// }, +// onModelsMerged: (data: InvokeAI.ModelsMergedResponse) => { +// const { merged_models, merged_model_name, model_list } = data; +// dispatch(setModelList(model_list)); +// dispatch(setCurrentStatus(i18n.t('common.statusMergedModels'))); +// dispatch(setIsProcessing(false)); +// dispatch(setIsCancelable(true)); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Models merged: ${merged_models}`, +// level: 'info', +// }) +// ); +// dispatch( +// addToast({ +// title: `${i18n.t('modelManager.modelsMerged')}: ${merged_model_name}`, +// status: 'success', +// duration: 2500, +// isClosable: true, +// }) +// ); +// }, +// onModelChanged: (data: InvokeAI.ModelChangeResponse) => { +// const { model_name, model_list } = data; +// dispatch(setModelList(model_list)); +// dispatch(setCurrentStatus(i18n.t('common.statusModelChanged'))); +// dispatch(setIsProcessing(false)); +// dispatch(setIsCancelable(true)); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Model changed: ${model_name}`, +// level: 'info', +// }) +// ); +// }, +// onModelChangeFailed: (data: InvokeAI.ModelChangeResponse) => { +// const { model_name, model_list } = data; +// dispatch(setModelList(model_list)); +// dispatch(setIsProcessing(false)); +// dispatch(setIsCancelable(true)); +// dispatch(errorOccurred()); +// dispatch( +// addLogEntry({ +// timestamp: dateFormat(new Date(), 'isoDateTime'), +// message: `Model change failed: ${model_name}`, +// level: 'error', +// }) +// ); +// }, +// onTempFolderEmptied: () => { +// dispatch( +// addToast({ +// title: i18n.t('toast.tempFoldersEmptied'), +// status: 'success', +// duration: 2500, +// isClosable: true, +// }) +// ); +// }, +// }; +// }; -export default makeSocketIOListeners; +// export default makeSocketIOListeners; + +export default {}; diff --git a/invokeai/frontend/web/src/app/socketio/middleware.ts b/invokeai/frontend/web/src/app/socketio/middleware.ts index 46dafc7656..88013ea222 100644 --- a/invokeai/frontend/web/src/app/socketio/middleware.ts +++ b/invokeai/frontend/web/src/app/socketio/middleware.ts @@ -1,246 +1,248 @@ -import { Middleware } from '@reduxjs/toolkit'; -import { io } from 'socket.io-client'; +// import { Middleware } from '@reduxjs/toolkit'; +// import { io } from 'socket.io-client'; -import makeSocketIOEmitters from './emitters'; -import makeSocketIOListeners from './listeners'; +// import makeSocketIOEmitters from './emitters'; +// import makeSocketIOListeners from './listeners'; -import * as InvokeAI from 'app/invokeai'; +// import * as InvokeAI from 'app/types/invokeai'; -/** - * Creates a socketio middleware to handle communication with server. - * - * Special `socketio/actionName` actions are created in actions.ts and - * exported for use by the application, which treats them like any old - * action, using `dispatch` to dispatch them. - * - * These actions are intercepted here, where `socketio.emit()` calls are - * made on their behalf - see `emitters.ts`. The emitter functions - * are the outbound communication to the server. - * - * Listeners are also established here - see `listeners.ts`. The listener - * functions receive communication from the server and usually dispatch - * some new action to handle whatever data was sent from the server. - */ -export const socketioMiddleware = () => { - const { origin } = new URL(window.location.href); +// /** +// * Creates a socketio middleware to handle communication with server. +// * +// * Special `socketio/actionName` actions are created in actions.ts and +// * exported for use by the application, which treats them like any old +// * action, using `dispatch` to dispatch them. +// * +// * These actions are intercepted here, where `socketio.emit()` calls are +// * made on their behalf - see `emitters.ts`. The emitter functions +// * are the outbound communication to the server. +// * +// * Listeners are also established here - see `listeners.ts`. The listener +// * functions receive communication from the server and usually dispatch +// * some new action to handle whatever data was sent from the server. +// */ +// export const socketioMiddleware = () => { +// const { origin } = new URL(window.location.href); - const socketio = io(origin, { - timeout: 60000, - path: `${window.location.pathname}socket.io`, - }); +// const socketio = io(origin, { +// timeout: 60000, +// path: `${window.location.pathname}socket.io`, +// }); - socketio.disconnect(); +// socketio.disconnect(); - let areListenersSet = false; +// let areListenersSet = false; - const middleware: Middleware = (store) => (next) => (action) => { - const { - onConnect, - onDisconnect, - onError, - onPostprocessingResult, - onGenerationResult, - onIntermediateResult, - onProgressUpdate, - onGalleryImages, - onProcessingCanceled, - onImageDeleted, - onSystemConfig, - onModelChanged, - onFoundModels, - onNewModelAdded, - onModelDeleted, - onModelConverted, - onModelsMerged, - onModelChangeFailed, - onTempFolderEmptied, - } = makeSocketIOListeners(store); +// const middleware: Middleware = (store) => (next) => (action) => { +// const { +// onConnect, +// onDisconnect, +// onError, +// onPostprocessingResult, +// onGenerationResult, +// onIntermediateResult, +// onProgressUpdate, +// onGalleryImages, +// onProcessingCanceled, +// onImageDeleted, +// onSystemConfig, +// onModelChanged, +// onFoundModels, +// onNewModelAdded, +// onModelDeleted, +// onModelConverted, +// onModelsMerged, +// onModelChangeFailed, +// onTempFolderEmptied, +// } = makeSocketIOListeners(store); - const { - emitGenerateImage, - emitRunESRGAN, - emitRunFacetool, - emitDeleteImage, - emitRequestImages, - emitRequestNewImages, - emitCancelProcessing, - emitRequestSystemConfig, - emitSearchForModels, - emitAddNewModel, - emitDeleteModel, - emitConvertToDiffusers, - emitMergeDiffusersModels, - emitRequestModelChange, - emitSaveStagingAreaImageToGallery, - emitRequestEmptyTempFolder, - } = makeSocketIOEmitters(store, socketio); +// const { +// emitGenerateImage, +// emitRunESRGAN, +// emitRunFacetool, +// emitDeleteImage, +// emitRequestImages, +// emitRequestNewImages, +// emitCancelProcessing, +// emitRequestSystemConfig, +// emitSearchForModels, +// emitAddNewModel, +// emitDeleteModel, +// emitConvertToDiffusers, +// emitMergeDiffusersModels, +// emitRequestModelChange, +// emitSaveStagingAreaImageToGallery, +// emitRequestEmptyTempFolder, +// } = makeSocketIOEmitters(store, socketio); - /** - * If this is the first time the middleware has been called (e.g. during store setup), - * initialize all our socket.io listeners. - */ - if (!areListenersSet) { - socketio.on('connect', () => onConnect()); +// /** +// * If this is the first time the middleware has been called (e.g. during store setup), +// * initialize all our socket.io listeners. +// */ +// if (!areListenersSet) { +// socketio.on('connect', () => onConnect()); - socketio.on('disconnect', () => onDisconnect()); +// socketio.on('disconnect', () => onDisconnect()); - socketio.on('error', (data: InvokeAI.ErrorResponse) => onError(data)); +// socketio.on('error', (data: InvokeAI.ErrorResponse) => onError(data)); - socketio.on('generationResult', (data: InvokeAI.ImageResultResponse) => - onGenerationResult(data) - ); +// socketio.on('generationResult', (data: InvokeAI.ImageResultResponse) => +// onGenerationResult(data) +// ); - socketio.on( - 'postprocessingResult', - (data: InvokeAI.ImageResultResponse) => onPostprocessingResult(data) - ); +// socketio.on( +// 'postprocessingResult', +// (data: InvokeAI.ImageResultResponse) => onPostprocessingResult(data) +// ); - socketio.on('intermediateResult', (data: InvokeAI.ImageResultResponse) => - onIntermediateResult(data) - ); +// socketio.on('intermediateResult', (data: InvokeAI.ImageResultResponse) => +// onIntermediateResult(data) +// ); - socketio.on('progressUpdate', (data: InvokeAI.SystemStatus) => - onProgressUpdate(data) - ); +// socketio.on('progressUpdate', (data: InvokeAI.SystemStatus) => +// onProgressUpdate(data) +// ); - socketio.on('galleryImages', (data: InvokeAI.GalleryImagesResponse) => - onGalleryImages(data) - ); +// socketio.on('galleryImages', (data: InvokeAI.GalleryImagesResponse) => +// onGalleryImages(data) +// ); - socketio.on('processingCanceled', () => { - onProcessingCanceled(); - }); +// socketio.on('processingCanceled', () => { +// onProcessingCanceled(); +// }); - socketio.on('imageDeleted', (data: InvokeAI.ImageDeletedResponse) => { - onImageDeleted(data); - }); +// socketio.on('imageDeleted', (data: InvokeAI.ImageDeletedResponse) => { +// onImageDeleted(data); +// }); - socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => { - onSystemConfig(data); - }); +// socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => { +// onSystemConfig(data); +// }); - socketio.on('foundModels', (data: InvokeAI.FoundModelResponse) => { - onFoundModels(data); - }); +// socketio.on('foundModels', (data: InvokeAI.FoundModelResponse) => { +// onFoundModels(data); +// }); - socketio.on('newModelAdded', (data: InvokeAI.ModelAddedResponse) => { - onNewModelAdded(data); - }); +// socketio.on('newModelAdded', (data: InvokeAI.ModelAddedResponse) => { +// onNewModelAdded(data); +// }); - socketio.on('modelDeleted', (data: InvokeAI.ModelDeletedResponse) => { - onModelDeleted(data); - }); +// socketio.on('modelDeleted', (data: InvokeAI.ModelDeletedResponse) => { +// onModelDeleted(data); +// }); - socketio.on('modelConverted', (data: InvokeAI.ModelConvertedResponse) => { - onModelConverted(data); - }); +// socketio.on('modelConverted', (data: InvokeAI.ModelConvertedResponse) => { +// onModelConverted(data); +// }); - socketio.on('modelsMerged', (data: InvokeAI.ModelsMergedResponse) => { - onModelsMerged(data); - }); +// socketio.on('modelsMerged', (data: InvokeAI.ModelsMergedResponse) => { +// onModelsMerged(data); +// }); - socketio.on('modelChanged', (data: InvokeAI.ModelChangeResponse) => { - onModelChanged(data); - }); +// socketio.on('modelChanged', (data: InvokeAI.ModelChangeResponse) => { +// onModelChanged(data); +// }); - socketio.on('modelChangeFailed', (data: InvokeAI.ModelChangeResponse) => { - onModelChangeFailed(data); - }); +// socketio.on('modelChangeFailed', (data: InvokeAI.ModelChangeResponse) => { +// onModelChangeFailed(data); +// }); - socketio.on('tempFolderEmptied', () => { - onTempFolderEmptied(); - }); +// socketio.on('tempFolderEmptied', () => { +// onTempFolderEmptied(); +// }); - areListenersSet = true; - } +// areListenersSet = true; +// } - /** - * Handle redux actions caught by middleware. - */ - switch (action.type) { - case 'socketio/generateImage': { - emitGenerateImage(action.payload); - break; - } +// /** +// * Handle redux actions caught by middleware. +// */ +// switch (action.type) { +// case 'socketio/generateImage': { +// emitGenerateImage(action.payload); +// break; +// } - case 'socketio/runESRGAN': { - emitRunESRGAN(action.payload); - break; - } +// case 'socketio/runESRGAN': { +// emitRunESRGAN(action.payload); +// break; +// } - case 'socketio/runFacetool': { - emitRunFacetool(action.payload); - break; - } +// case 'socketio/runFacetool': { +// emitRunFacetool(action.payload); +// break; +// } - case 'socketio/deleteImage': { - emitDeleteImage(action.payload); - break; - } +// case 'socketio/deleteImage': { +// emitDeleteImage(action.payload); +// break; +// } - case 'socketio/requestImages': { - emitRequestImages(action.payload); - break; - } +// case 'socketio/requestImages': { +// emitRequestImages(action.payload); +// break; +// } - case 'socketio/requestNewImages': { - emitRequestNewImages(action.payload); - break; - } +// case 'socketio/requestNewImages': { +// emitRequestNewImages(action.payload); +// break; +// } - case 'socketio/cancelProcessing': { - emitCancelProcessing(); - break; - } +// case 'socketio/cancelProcessing': { +// emitCancelProcessing(); +// break; +// } - case 'socketio/requestSystemConfig': { - emitRequestSystemConfig(); - break; - } +// case 'socketio/requestSystemConfig': { +// emitRequestSystemConfig(); +// break; +// } - case 'socketio/searchForModels': { - emitSearchForModels(action.payload); - break; - } +// case 'socketio/searchForModels': { +// emitSearchForModels(action.payload); +// break; +// } - case 'socketio/addNewModel': { - emitAddNewModel(action.payload); - break; - } +// case 'socketio/addNewModel': { +// emitAddNewModel(action.payload); +// break; +// } - case 'socketio/deleteModel': { - emitDeleteModel(action.payload); - break; - } +// case 'socketio/deleteModel': { +// emitDeleteModel(action.payload); +// break; +// } - case 'socketio/convertToDiffusers': { - emitConvertToDiffusers(action.payload); - break; - } +// case 'socketio/convertToDiffusers': { +// emitConvertToDiffusers(action.payload); +// break; +// } - case 'socketio/mergeDiffusersModels': { - emitMergeDiffusersModels(action.payload); - break; - } +// case 'socketio/mergeDiffusersModels': { +// emitMergeDiffusersModels(action.payload); +// break; +// } - case 'socketio/requestModelChange': { - emitRequestModelChange(action.payload); - break; - } +// case 'socketio/requestModelChange': { +// emitRequestModelChange(action.payload); +// break; +// } - case 'socketio/saveStagingAreaImageToGallery': { - emitSaveStagingAreaImageToGallery(action.payload); - break; - } +// case 'socketio/saveStagingAreaImageToGallery': { +// emitSaveStagingAreaImageToGallery(action.payload); +// break; +// } - case 'socketio/requestEmptyTempFolder': { - emitRequestEmptyTempFolder(); - break; - } - } +// case 'socketio/requestEmptyTempFolder': { +// emitRequestEmptyTempFolder(); +// break; +// } +// } - next(action); - }; +// next(action); +// }; - return middleware; -}; +// return middleware; +// }; + +export default {}; diff --git a/invokeai/frontend/web/src/persistor.ts b/invokeai/frontend/web/src/app/store/persistor.ts similarity index 69% rename from invokeai/frontend/web/src/persistor.ts rename to invokeai/frontend/web/src/app/store/persistor.ts index ee860da3f3..85dc934943 100644 --- a/invokeai/frontend/web/src/persistor.ts +++ b/invokeai/frontend/web/src/app/store/persistor.ts @@ -1,4 +1,4 @@ -import { store } from 'app/store'; +import { store } from 'app/store/store'; import { persistStore } from 'redux-persist'; export const persistor = persistStore(store); diff --git a/invokeai/frontend/web/src/app/store.ts b/invokeai/frontend/web/src/app/store/store.ts similarity index 90% rename from invokeai/frontend/web/src/app/store.ts rename to invokeai/frontend/web/src/app/store/store.ts index 3b9ab2eea1..b0f73a759e 100644 --- a/invokeai/frontend/web/src/app/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -19,8 +19,6 @@ import hotkeysReducer from 'features/ui/store/hotkeysSlice'; import modelsReducer from 'features/system/store/modelSlice'; import nodesReducer from 'features/nodes/store/nodesSlice'; -import { socketioMiddleware } from './socketio/middleware'; -import { socketMiddleware } from 'services/events/middleware'; import { canvasDenylist } from 'features/canvas/store/canvasPersistDenylist'; import { galleryDenylist } from 'features/gallery/store/galleryPersistDenylist'; import { generationDenylist } from 'features/parameters/store/generationPersistDenylist'; @@ -28,8 +26,10 @@ import { lightboxDenylist } from 'features/lightbox/store/lightboxPersistDenylis import { modelsDenylist } from 'features/system/store/modelsPersistDenylist'; import { nodesDenylist } from 'features/nodes/store/nodesPersistDenylist'; import { postprocessingDenylist } from 'features/parameters/store/postprocessingPersistDenylist'; -import { systemDenylist } from 'features/system/store/systemPersistsDenylist'; +import { systemDenylist } from 'features/system/store/systemPersistDenylist'; import { uiDenylist } from 'features/ui/store/uiPersistDenylist'; +import { resultsDenylist } from 'features/gallery/store/resultsPersistDenylist'; +import { uploadsDenylist } from 'features/gallery/store/uploadsPersistDenylist'; /** * redux-persist provides an easy and reliable way to persist state across reloads. @@ -82,19 +82,18 @@ const rootPersistConfig = getPersistConfig({ 'hotkeys', 'config', ], - debounce: 300, }); const persistedReducer = persistReducer(rootPersistConfig, rootReducer); // TODO: rip the old middleware out when nodes is complete -export function buildMiddleware() { - if (import.meta.env.MODE === 'nodes' || import.meta.env.MODE === 'package') { - return socketMiddleware(); - } else { - return socketioMiddleware(); - } -} +// export function buildMiddleware() { +// if (import.meta.env.MODE === 'nodes' || import.meta.env.MODE === 'package') { +// return socketMiddleware(); +// } else { +// return socketioMiddleware(); +// } +// } export const store = configureStore({ reducer: persistedReducer, @@ -114,6 +113,7 @@ export const store = configureStore({ 'canvas/setBoundingBoxDimensions', 'canvas/setIsDrawing', 'canvas/addPointToCurrentLine', + 'socket/generatorProgress', ], }, }); diff --git a/invokeai/frontend/web/src/app/storeHooks.ts b/invokeai/frontend/web/src/app/store/storeHooks.ts similarity index 83% rename from invokeai/frontend/web/src/app/storeHooks.ts rename to invokeai/frontend/web/src/app/store/storeHooks.ts index 391929d74b..387bc7ea68 100644 --- a/invokeai/frontend/web/src/app/storeHooks.ts +++ b/invokeai/frontend/web/src/app/store/storeHooks.ts @@ -1,5 +1,5 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; -import { AppDispatch, RootState } from './store'; +import { AppDispatch, RootState } from 'app/store/store'; // Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch: () => AppDispatch = useDispatch; diff --git a/invokeai/frontend/web/src/app/storeUtils.ts b/invokeai/frontend/web/src/app/store/storeUtils.ts similarity index 82% rename from invokeai/frontend/web/src/app/storeUtils.ts rename to invokeai/frontend/web/src/app/store/storeUtils.ts index 851c0ba09d..1ccaad9f89 100644 --- a/invokeai/frontend/web/src/app/storeUtils.ts +++ b/invokeai/frontend/web/src/app/store/storeUtils.ts @@ -1,5 +1,5 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { AppDispatch, RootState } from './store'; +import { AppDispatch, RootState } from 'app/store/store'; // https://redux-toolkit.js.org/usage/usage-with-typescript#defining-a-pre-typed-createasyncthunk export const createAppAsyncThunk = createAsyncThunk.withTypes<{ diff --git a/invokeai/frontend/web/src/app/invokeai.d.ts b/invokeai/frontend/web/src/app/types/invokeai.ts similarity index 62% rename from invokeai/frontend/web/src/app/invokeai.d.ts rename to invokeai/frontend/web/src/app/types/invokeai.ts index 0e7fa55a36..05e6e088d6 100644 --- a/invokeai/frontend/web/src/app/invokeai.d.ts +++ b/invokeai/frontend/web/src/app/types/invokeai.ts @@ -12,10 +12,11 @@ * 'gfpgan'. */ +import { GalleryCategory } from 'features/gallery/store/gallerySlice'; import { FacetoolType } from 'features/parameters/store/postprocessingSlice'; import { InvokeTabName } from 'features/ui/store/tabMap'; import { IRect } from 'konva/lib/types'; -import { ImageMetadata, ImageType } from 'services/api'; +import { ImageResponseMetadata, ImageType } from 'services/api'; import { AnyInvocation } from 'services/events/types'; import { O } from 'ts-toolbelt'; @@ -28,24 +29,24 @@ import { O } from 'ts-toolbelt'; * TODO: Better documentation of types. */ -export declare type PromptItem = { +export type PromptItem = { prompt: string; weight: number; }; // TECHDEBT: We need to retain compatibility with plain prompt strings and the structure Prompt type -export declare type Prompt = Array | string; +export type Prompt = Array | string; -export declare type SeedWeightPair = { +export type SeedWeightPair = { seed: number; weight: number; }; -export declare type SeedWeights = Array; +export type SeedWeights = Array; // All generated images contain these metadata. -export declare type CommonGeneratedImageMetadata = { - postprocessing: null | Array; +export type CommonGeneratedImageMetadata = { + postprocessing: null | Array; sampler: | 'ddim' | 'k_dpm_2_a' @@ -70,11 +71,11 @@ export declare type CommonGeneratedImageMetadata = { }; // txt2img and img2img images have some unique attributes. -export declare type Txt2ImgMetadata = GeneratedImageMetadata & { +export type Txt2ImgMetadata = CommonGeneratedImageMetadata & { type: 'txt2img'; }; -export declare type Img2ImgMetadata = GeneratedImageMetadata & { +export type Img2ImgMetadata = CommonGeneratedImageMetadata & { type: 'img2img'; orig_hash: string; strength: number; @@ -84,102 +85,80 @@ export declare type Img2ImgMetadata = GeneratedImageMetadata & { }; // Superset of generated image metadata types. -export declare type GeneratedImageMetadata = Txt2ImgMetadata | Img2ImgMetadata; +export type GeneratedImageMetadata = Txt2ImgMetadata | Img2ImgMetadata; // All post processed images contain these metadata. -export declare type CommonPostProcessedImageMetadata = { +export type CommonPostProcessedImageMetadata = { orig_path: string; orig_hash: string; }; // esrgan and gfpgan images have some unique attributes. -export declare type ESRGANMetadata = CommonPostProcessedImageMetadata & { +export type ESRGANMetadata = CommonPostProcessedImageMetadata & { type: 'esrgan'; scale: 2 | 4; strength: number; denoise_str: number; }; -export declare type FacetoolMetadata = CommonPostProcessedImageMetadata & { +export type FacetoolMetadata = CommonPostProcessedImageMetadata & { type: 'gfpgan' | 'codeformer'; strength: number; fidelity?: number; }; // Superset of all postprocessed image metadata types.. -export declare type PostProcessedImageMetadata = - | ESRGANMetadata - | FacetoolMetadata; +export type PostProcessedImageMetadata = ESRGANMetadata | FacetoolMetadata; // Metadata includes the system config and image metadata. -export declare type Metadata = SystemGenerationMetadata & { - image: GeneratedImageMetadata | PostProcessedImageMetadata; -}; - -// An Image has a UUID, url, modified timestamp, width, height and maybe metadata -export declare type _Image = { - uuid: string; - url: string; - thumbnail: string; - mtime: number; - metadata?: Metadata; - width: number; - height: number; - category: GalleryCategory; - isBase64?: boolean; - dreamPrompt?: 'string'; - name?: string; -}; +// export type Metadata = SystemGenerationMetadata & { +// image: GeneratedImageMetadata | PostProcessedImageMetadata; +// }; /** * ResultImage */ -export declare type Image = { +export type Image = { name: string; type: ImageType; url: string; thumbnail: string; - metadata: ImageMetadata; -}; - -// GalleryImages is an array of Image. -export declare type GalleryImages = { - images: Array<_Image>; + metadata: ImageResponseMetadata; }; /** * Types related to the system status. */ -// This represents the processing status of the backend. -export declare type SystemStatus = { - isProcessing: boolean; - currentStep: number; - totalSteps: number; - currentIteration: number; - totalIterations: number; - currentStatus: string; - currentStatusHasSteps: boolean; - hasError: boolean; -}; +// // This represents the processing status of the backend. +// export type SystemStatus = { +// isProcessing: boolean; +// currentStep: number; +// totalSteps: number; +// currentIteration: number; +// totalIterations: number; +// currentStatus: string; +// currentStatusHasSteps: boolean; +// hasError: boolean; +// }; -export declare type SystemGenerationMetadata = { - model: string; - model_weights?: string; - model_id?: string; - model_hash: string; - app_id: string; - app_version: string; -}; +// export type SystemGenerationMetadata = { +// model: string; +// model_weights?: string; +// model_id?: string; +// model_hash: string; +// app_id: string; +// app_version: string; +// }; -export declare type SystemConfig = SystemGenerationMetadata & { - model_list: ModelList; - infill_methods: string[]; -}; +// export type SystemConfig = SystemGenerationMetadata & { +// model_list: ModelList; +// infill_methods: string[]; +// }; -export declare type ModelStatus = 'active' | 'cached' | 'not loaded'; +export type ModelStatus = 'active' | 'cached' | 'not loaded'; -export declare type Model = { +export type Model = { status: ModelStatus; description: string; weights: string; @@ -191,7 +170,7 @@ export declare type Model = { format?: string; }; -export declare type DiffusersModel = { +export type DiffusersModel = { status: ModelStatus; description: string; repo_id?: string; @@ -204,14 +183,14 @@ export declare type DiffusersModel = { default?: boolean; }; -export declare type ModelList = Record; +export type ModelList = Record; -export declare type FoundModel = { +export type FoundModel = { name: string; location: string; }; -export declare type InvokeModelConfigProps = { +export type InvokeModelConfigProps = { name: string | undefined; description: string | undefined; config: string | undefined; @@ -223,7 +202,7 @@ export declare type InvokeModelConfigProps = { format: string | undefined; }; -export declare type InvokeDiffusersModelConfigProps = { +export type InvokeDiffusersModelConfigProps = { name: string | undefined; description: string | undefined; repo_id: string | undefined; @@ -236,13 +215,13 @@ export declare type InvokeDiffusersModelConfigProps = { }; }; -export declare type InvokeModelConversionProps = { +export type InvokeModelConversionProps = { model_name: string; save_location: string; custom_location: string | null; }; -export declare type InvokeModelMergingProps = { +export type InvokeModelMergingProps = { models_to_merge: string[]; alpha: number; interp: 'weighted_sum' | 'sigmoid' | 'inv_sigmoid' | 'add_difference'; @@ -255,48 +234,48 @@ export declare type InvokeModelMergingProps = { * These types type data received from the server via socketio. */ -export declare type ModelChangeResponse = { +export type ModelChangeResponse = { model_name: string; model_list: ModelList; }; -export declare type ModelConvertedResponse = { +export type ModelConvertedResponse = { converted_model_name: string; model_list: ModelList; }; -export declare type ModelsMergedResponse = { +export type ModelsMergedResponse = { merged_models: string[]; merged_model_name: string; model_list: ModelList; }; -export declare type ModelAddedResponse = { +export type ModelAddedResponse = { new_model_name: string; model_list: ModelList; update: boolean; }; -export declare type ModelDeletedResponse = { +export type ModelDeletedResponse = { deleted_model_name: string; model_list: ModelList; }; -export declare type FoundModelResponse = { +export type FoundModelResponse = { search_folder: string; found_models: FoundModel[]; }; -export declare type SystemStatusResponse = SystemStatus; +// export type SystemStatusResponse = SystemStatus; -export declare type SystemConfigResponse = SystemConfig; +// export type SystemConfigResponse = SystemConfig; -export declare type ImageResultResponse = Omit<_Image, 'uuid'> & { +export type ImageResultResponse = Omit<_Image, 'uuid'> & { boundingBox?: IRect; generationMode: InvokeTabName; }; -export declare type ImageUploadResponse = { +export type ImageUploadResponse = { // image: Omit; url: string; mtime: number; @@ -306,33 +285,16 @@ export declare type ImageUploadResponse = { // bbox: [number, number, number, number]; }; -export declare type ErrorResponse = { +export type ErrorResponse = { message: string; additionalData?: string; }; -export declare type GalleryImagesResponse = { - images: Array>; - areMoreImagesAvailable: boolean; - category: GalleryCategory; -}; - -export declare type ImageDeletedResponse = { - uuid: string; - url: string; - category: GalleryCategory; -}; - -export declare type ImageUrlResponse = { +export type ImageUrlResponse = { url: string; }; -export declare type UploadImagePayload = { - file: File; - destination?: ImageUploadDestination; -}; - -export declare type UploadOutpaintingMergeImagePayload = { +export type UploadOutpaintingMergeImagePayload = { dataURL: string; name: string; }; @@ -340,7 +302,7 @@ export declare type UploadOutpaintingMergeImagePayload = { /** * A disable-able application feature */ -export declare type AppFeature = +export type AppFeature = | 'faceRestore' | 'upscaling' | 'lightbox' @@ -353,7 +315,7 @@ export declare type AppFeature = /** * A disable-able Stable Diffusion feature */ -export declare type StableDiffusionFeature = +export type StableDiffusionFeature = | 'noiseConfig' | 'variations' | 'symmetry' @@ -364,7 +326,7 @@ export declare type StableDiffusionFeature = * Configuration options for the InvokeAI UI. * Distinct from system settings which may be changed inside the app. */ -export declare type AppConfig = { +export type AppConfig = { /** * Whether or not URLs should be transformed to use a different host */ @@ -428,4 +390,4 @@ export declare type AppConfig = { }; }; -export declare type PartialAppConfig = O.Partial; +export type PartialAppConfig = O.Partial; diff --git a/invokeai/frontend/web/src/app/utils.ts b/invokeai/frontend/web/src/app/utils.ts deleted file mode 100644 index 6bc959f2f7..0000000000 --- a/invokeai/frontend/web/src/app/utils.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function keepGUIAlive() { - async function getRequest(url = '') { - const response = await fetch(url, { - method: 'GET', - cache: 'no-cache', - }); - return response; - } - - const keepAliveServer = () => { - const url = document.location; - const route = '/flaskwebgui-keep-server-alive'; - getRequest(url + route).then((data) => { - return data; - }); - }; - - if (!import.meta.env.NODE_ENV || import.meta.env.NODE_ENV === 'production') { - document.addEventListener('DOMContentLoaded', () => { - const intervalRequest = 3 * 1000; - keepAliveServer(); - setInterval(keepAliveServer, intervalRequest); - }); - } -} diff --git a/invokeai/frontend/web/src/common/components/GuidePopover.tsx b/invokeai/frontend/web/src/common/components/GuidePopover.tsx index 7fa0709321..1cfb60a830 100644 --- a/invokeai/frontend/web/src/common/components/GuidePopover.tsx +++ b/invokeai/frontend/web/src/common/components/GuidePopover.tsx @@ -8,7 +8,7 @@ import { } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { Feature, useFeatureHelpInfo } from 'app/features'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { systemSelector } from 'features/system/store/systemSelectors'; import { SystemState } from 'features/system/store/systemSlice'; import { memo, ReactElement } from 'react'; diff --git a/invokeai/frontend/web/src/common/components/IAINumberInput.tsx b/invokeai/frontend/web/src/common/components/IAINumberInput.tsx index 4f468eb354..762182eb47 100644 --- a/invokeai/frontend/web/src/common/components/IAINumberInput.tsx +++ b/invokeai/frontend/web/src/common/components/IAINumberInput.tsx @@ -14,7 +14,7 @@ import { Tooltip, TooltipProps, } from '@chakra-ui/react'; -import { clamp } from 'lodash'; +import { clamp } from 'lodash-es'; import { FocusEvent, memo, useEffect, useState } from 'react'; diff --git a/invokeai/frontend/web/src/common/components/IAISelect.tsx b/invokeai/frontend/web/src/common/components/IAISelect.tsx index f0998b8937..7bc8952d94 100644 --- a/invokeai/frontend/web/src/common/components/IAISelect.tsx +++ b/invokeai/frontend/web/src/common/components/IAISelect.tsx @@ -16,13 +16,23 @@ type IAISelectProps = SelectProps & { validValues: | Array | Array<{ key: string; value: string | number }>; + horizontal?: boolean; + spaceEvenly?: boolean; }; /** * Customized Chakra FormControl + Select multi-part component. */ const IAISelect = (props: IAISelectProps) => { - const { label, isDisabled, validValues, tooltip, tooltipProps, ...rest } = - props; + const { + label, + isDisabled, + validValues, + tooltip, + tooltipProps, + horizontal, + spaceEvenly, + ...rest + } = props; return ( { e.nativeEvent.stopPropagation(); e.nativeEvent.cancelBubble = true; }} + sx={ + horizontal + ? { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + gap: 4, + } + : {} + } > - {label && {label}} + {label && ( + + {label} + + )} - {validValues.map((opt) => { return typeof opt === 'string' || typeof opt === 'number' ? ( diff --git a/invokeai/frontend/web/src/common/components/IAISlider.tsx b/invokeai/frontend/web/src/common/components/IAISlider.tsx index 643c5616c2..48080e8970 100644 --- a/invokeai/frontend/web/src/common/components/IAISlider.tsx +++ b/invokeai/frontend/web/src/common/components/IAISlider.tsx @@ -23,7 +23,7 @@ import { Tooltip, TooltipProps, } from '@chakra-ui/react'; -import { clamp } from 'lodash'; +import { clamp } from 'lodash-es'; import { useTranslation } from 'react-i18next'; import { @@ -233,7 +233,7 @@ const IAISlider = (props: IAIFullSliderProps) => { hidden={hideTooltip} {...sliderTooltipProps} > - + diff --git a/invokeai/frontend/web/src/common/components/ImageToImageOverlay.tsx b/invokeai/frontend/web/src/common/components/ImageToImageOverlay.tsx index 27ce11d3b3..45a45e37d3 100644 --- a/invokeai/frontend/web/src/common/components/ImageToImageOverlay.tsx +++ b/invokeai/frontend/web/src/common/components/ImageToImageOverlay.tsx @@ -1,32 +1,11 @@ -import { Badge, Box, ButtonGroup, Flex } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { clearInitialImage } from 'features/parameters/store/generationSlice'; -import { useCallback } from 'react'; -import IAIIconButton from 'common/components/IAIIconButton'; -import { FaUndo, FaUpload } from 'react-icons/fa'; -import { useTranslation } from 'react-i18next'; -import { Image } from 'app/invokeai'; +import { Badge, Box, Flex } from '@chakra-ui/react'; +import { Image } from 'app/types/invokeai'; type ImageToImageOverlayProps = { - setIsLoaded: (isLoaded: boolean) => void; image: Image; }; -const ImageToImageOverlay = ({ - setIsLoaded, - image, -}: ImageToImageOverlayProps) => { - const isImageToImageEnabled = useAppSelector( - (state: RootState) => state.generation.isImageToImageEnabled - ); - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - const handleResetInitialImage = useCallback(() => { - dispatch(clearInitialImage()); - setIsLoaded(false); - }, [dispatch, setIsLoaded]); - +const ImageToImageOverlay = ({ image }: ImageToImageOverlayProps) => { return ( { - const isImageToImageEnabled = useAppSelector( - (state: RootState) => state.generation.isImageToImageEnabled - ); const dispatch = useAppDispatch(); const { t } = useTranslation(); diff --git a/invokeai/frontend/web/src/common/components/ImageUploader.tsx b/invokeai/frontend/web/src/common/components/ImageUploader.tsx index beaa5f02d2..8ff88c7ecf 100644 --- a/invokeai/frontend/web/src/common/components/ImageUploader.tsx +++ b/invokeai/frontend/web/src/common/components/ImageUploader.tsx @@ -1,6 +1,6 @@ import { Box, useToast } from '@chakra-ui/react'; import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import useImageUploader from 'common/hooks/useImageUploader'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { ResourceKey } from 'i18next'; diff --git a/invokeai/frontend/web/src/common/components/Loading/Loading.tsx b/invokeai/frontend/web/src/common/components/Loading/Loading.tsx index 45a304747b..8625e5b49b 100644 --- a/invokeai/frontend/web/src/common/components/Loading/Loading.tsx +++ b/invokeai/frontend/web/src/common/components/Loading/Loading.tsx @@ -1,5 +1,6 @@ import { Flex, Image, Spinner } from '@chakra-ui/react'; import InvokeAILogoImage from 'assets/images/logo.png'; +import { memo } from 'react'; // This component loads before the theme so we cannot use theme tokens here @@ -29,4 +30,4 @@ const Loading = () => { ); }; -export default Loading; +export default memo(Loading); diff --git a/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts b/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts index e13215c3f7..5078c8d358 100644 --- a/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts +++ b/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts @@ -1,8 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook'; const globalHotkeysSelector = createSelector( diff --git a/invokeai/frontend/web/src/common/util/getPromptAndNegative.ts b/invokeai/frontend/web/src/common/util/getPromptAndNegative.ts index 7400e63bfc..4683d44428 100644 --- a/invokeai/frontend/web/src/common/util/getPromptAndNegative.ts +++ b/invokeai/frontend/web/src/common/util/getPromptAndNegative.ts @@ -1,4 +1,4 @@ -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import promptToString from './promptToString'; export function getPromptAndNegative(inputPrompt: InvokeAI.Prompt) { diff --git a/invokeai/frontend/web/src/common/util/getUrl.ts b/invokeai/frontend/web/src/common/util/getUrl.ts index a684c4041b..72607057e4 100644 --- a/invokeai/frontend/web/src/common/util/getUrl.ts +++ b/invokeai/frontend/web/src/common/util/getUrl.ts @@ -1,5 +1,6 @@ -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { useCallback } from 'react'; import { OpenAPI } from 'services/api'; export const getUrlAlt = (url: string, shouldTransformUrls: boolean) => { @@ -15,14 +16,19 @@ export const useGetUrl = () => { (state: RootState) => state.config.shouldTransformUrls ); - return { - shouldTransformUrls, - getUrl: (url?: string) => { + const getUrl = useCallback( + (url?: string) => { if (OpenAPI.BASE && shouldTransformUrls) { return [OpenAPI.BASE, url].join('/'); } return url; }, + [shouldTransformUrls] + ); + + return { + shouldTransformUrls, + getUrl, }; }; diff --git a/invokeai/frontend/web/src/common/util/parseMetadata.ts b/invokeai/frontend/web/src/common/util/parseMetadata.ts index 433aa9b2a1..210c1f85ab 100644 --- a/invokeai/frontend/web/src/common/util/parseMetadata.ts +++ b/invokeai/frontend/web/src/common/util/parseMetadata.ts @@ -1,4 +1,4 @@ -import { forEach, size } from 'lodash'; +import { forEach, size } from 'lodash-es'; import { ImageField, LatentsField } from 'services/api'; const OBJECT_TYPESTRING = '[object Object]'; diff --git a/invokeai/frontend/web/src/common/util/promptToString.ts b/invokeai/frontend/web/src/common/util/promptToString.ts index 5121e25eef..cb86af2988 100644 --- a/invokeai/frontend/web/src/common/util/promptToString.ts +++ b/invokeai/frontend/web/src/common/util/promptToString.ts @@ -1,4 +1,4 @@ -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; const promptToString = (prompt: InvokeAI.Prompt): string => { if (typeof prompt === 'string') { diff --git a/invokeai/frontend/web/src/common/util/seedWeightPairs.ts b/invokeai/frontend/web/src/common/util/seedWeightPairs.ts index e35e69ac9a..3a8af5c11d 100644 --- a/invokeai/frontend/web/src/common/util/seedWeightPairs.ts +++ b/invokeai/frontend/web/src/common/util/seedWeightPairs.ts @@ -1,4 +1,4 @@ -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; export const stringToSeedWeights = ( string: string diff --git a/invokeai/frontend/web/src/exports.tsx b/invokeai/frontend/web/src/exports.tsx deleted file mode 100644 index ffab33ead7..0000000000 --- a/invokeai/frontend/web/src/exports.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import Component from './component'; - -import InvokeAiLogoComponent from './features/system/components/InvokeAILogoComponent'; -import ThemeChanger from './features/system/components/ThemeChanger'; -import IAIPopover from './common/components/IAIPopover'; -import IAIIconButton from './common/components/IAIIconButton'; -import SettingsModal from './features/system/components/SettingsModal/SettingsModal'; -import StatusIndicator from './features/system/components/StatusIndicator'; -import ModelSelect from 'features/system/components/ModelSelect'; - -export default Component; -export { - InvokeAiLogoComponent, - ThemeChanger, - IAIPopover, - IAIIconButton, - SettingsModal, - StatusIndicator, - ModelSelect, -}; diff --git a/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx b/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx index 46b4227589..49a13c401c 100644 --- a/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/ClearCanvasHistoryButtonModal.tsx @@ -1,4 +1,4 @@ -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIAlertDialog from 'common/components/IAIAlertDialog'; import IAIButton from 'common/components/IAIButton'; import { clearCanvasHistory } from 'features/canvas/store/canvasSlice'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx index 657f407b5d..1850b4bfe4 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/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, isStagingSelector, @@ -8,7 +8,7 @@ import { import Konva from 'konva'; import { KonvaEventObject } from 'konva/lib/Node'; import { Vector2d } from 'konva/lib/types'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useCallback, useRef } from 'react'; import { Layer, Stage } from 'react-konva'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx index cfdbddb1e2..e90d2c4d25 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasBoundingBoxOverlay.tsx @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; -import { isEqual } from 'lodash'; +import { useAppSelector } from 'app/store/storeHooks'; +import { isEqual } from 'lodash-es'; import { Group, Rect } from 'react-konva'; import { canvasSelector } from '../store/canvasSelectors'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx index 26fb6f7823..ad47b77041 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasGrid.tsx @@ -2,10 +2,10 @@ import { useToken } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; -import { isEqual, range } from 'lodash'; +import { isEqual, range } from 'lodash-es'; import { ReactNode, useCallback, useLayoutEffect, useState } from 'react'; import { Group, Line as KonvaLine } from 'react-konva'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx index cb7ab5fee8..745825a975 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasIntermediateImage.tsx @@ -1,10 +1,10 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { useGetUrl } from 'common/util/getUrl'; import { GalleryState } from 'features/gallery/store/gallerySlice'; import { ImageConfig } from 'konva/lib/shapes/Image'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useEffect, useState } from 'react'; import { Image as KonvaImage } from 'react-konva'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx index 5417e101f8..e374d2aa7b 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskCompositer.tsx @@ -1,12 +1,12 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { RectConfig } from 'konva/lib/shapes/Rect'; import { Rect } from 'react-konva'; import { rgbaColorToString } from 'features/canvas/util/colorToString'; import Konva from 'konva'; -import { isNumber } from 'lodash'; +import { isNumber } from 'lodash-es'; import { useCallback, useEffect, useRef, useState } from 'react'; export const canvasMaskCompositerSelector = createSelector( diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx index 0ff1101626..a553653901 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasMaskLines.tsx @@ -1,8 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { GroupConfig } from 'konva/lib/Group'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { Group, Line } from 'react-konva'; import { isCanvasMaskLine } from '../store/canvasTypes'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx index 1d2852eef6..32d2b36324 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasObjectRenderer.tsx @@ -1,9 +1,9 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { useGetUrl } from 'common/util/getUrl'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { rgbaColorToString } from 'features/canvas/util/colorToString'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { Group, Line, Rect } from 'react-konva'; import { diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx index 3062abae91..013d689182 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasResizer.tsx @@ -1,6 +1,6 @@ import { Flex, Spinner } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, initialCanvasImageSelector, diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx index 1a84aa88bb..7bd4782840 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingArea.tsx @@ -1,9 +1,9 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { useGetUrl } from 'common/util/getUrl'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { GroupConfig } from 'konva/lib/Group'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { Group, Rect } from 'react-konva'; import IAICanvasImage from './IAICanvasImage'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx index 74d6382308..eeb51d955b 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStagingAreaToolbar.tsx @@ -1,7 +1,7 @@ import { ButtonGroup, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { saveStagingAreaImageToGallery } from 'app/socketio/actions'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +// import { saveStagingAreaImageToGallery } from 'app/socketio/actions'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { @@ -12,7 +12,7 @@ import { setShouldShowStagingImage, setShouldShowStagingOutline, } from 'features/canvas/store/canvasSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx index 72f532217f..8e3edadd01 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx @@ -1,8 +1,8 @@ import { Box, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; import roundToHundreth from '../util/roundToHundreth'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText/IAICanvasStatusTextCursorPos.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText/IAICanvasStatusTextCursorPos.tsx index 2570290393..8c37be85bd 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText/IAICanvasStatusTextCursorPos.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText/IAICanvasStatusTextCursorPos.tsx @@ -1,9 +1,9 @@ import { Box } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import roundToHundreth from 'features/canvas/util/roundToHundreth'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx index 04ec21e57c..8ad58e020c 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolPreview.tsx @@ -1,9 +1,9 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { rgbaColorToString } from 'features/canvas/util/colorToString'; import { GroupConfig } from 'konva/lib/Group'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { Circle, Group } from 'react-konva'; import { 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 58577f999f..0241f3eb55 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { roundDownToMultiple, roundToMultiple, @@ -16,7 +16,7 @@ import Konva from 'konva'; import { GroupConfig } from 'konva/lib/Group'; import { KonvaEventObject } from 'konva/lib/Node'; import { Vector2d } from 'konva/lib/types'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useCallback, useEffect, useRef, useState } from 'react'; import { Group, Rect, Transformer } from 'react-konva'; 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 70b919f4f6..b345f2cda0 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx @@ -1,6 +1,6 @@ import { ButtonGroup, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import IAICheckbox from 'common/components/IAICheckbox'; import IAIColorPicker from 'common/components/IAIColorPicker'; @@ -18,7 +18,7 @@ import { setShouldPreserveMaskedArea, } from 'features/canvas/store/canvasSlice'; import { rgbaColorToString } from 'features/canvas/util/colorToString'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx index bae875f34d..72f4a19479 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasRedoButton.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; @@ -9,7 +9,7 @@ import { FaRedo } from 'react-icons/fa'; import { redo } from 'features/canvas/store/canvasSlice'; import { systemSelector } from 'features/system/store/systemSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; const canvasRedoSelector = createSelector( 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 f7ed8929c7..87e3435127 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx @@ -1,6 +1,6 @@ import { Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAICheckbox from 'common/components/IAICheckbox'; import IAIIconButton from 'common/components/IAIIconButton'; import IAIPopover from 'common/components/IAIPopover'; @@ -16,7 +16,7 @@ import { setShouldSnapToGrid, } from 'features/canvas/store/canvasSlice'; import EmptyTempFolderButtonModal from 'features/system/components/ClearTempFolderButtonModal'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { ChangeEvent } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; 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 b8ca929c85..eee462dd2d 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx @@ -1,6 +1,6 @@ import { ButtonGroup, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIColorPicker from 'common/components/IAIColorPicker'; import IAIIconButton from 'common/components/IAIIconButton'; import IAIPopover from 'common/components/IAIPopover'; @@ -17,7 +17,7 @@ import { setTool, } from 'features/canvas/store/canvasSlice'; import { systemSelector } from 'features/system/store/systemSelectors'; -import { clamp, isEqual } from 'lodash'; +import { clamp, isEqual } from 'lodash-es'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; 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 4e53039e38..dd8963de7b 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolbar.tsx @@ -1,6 +1,6 @@ import { ButtonGroup, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import IAISelect from 'common/components/IAISelect'; import useImageUploader from 'common/hooks/useImageUploader'; @@ -24,7 +24,7 @@ import { import { mergeAndUploadCanvas } from 'features/canvas/store/thunks/mergeAndUploadCanvas'; import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider'; import { systemSelector } from 'features/system/store/systemSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { ChangeEvent } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx index e5a69f70e9..9feb2dfcb5 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasUndoButton.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -9,7 +9,7 @@ import { undo } from 'features/canvas/store/canvasSlice'; import { systemSelector } from 'features/system/store/systemSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; const canvasUndoSelector = createSelector( diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts index 6a14e4ebc9..6861c25842 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasDragMove.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, isStagingSelector, @@ -9,7 +9,7 @@ import { setStageCoordinates, } from 'features/canvas/store/canvasSlice'; import { KonvaEventObject } from 'konva/lib/Node'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useCallback } from 'react'; diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts index d082da3ae9..6f4669a42a 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasHotkeys.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, isStagingSelector, @@ -13,7 +13,7 @@ import { setTool, } from 'features/canvas/store/canvasSlice'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useRef } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts index a64faefafc..67bf7a8539 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseDown.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, isStagingSelector, @@ -12,7 +12,7 @@ import { import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import Konva from 'konva'; import { KonvaEventObject } from 'konva/lib/Node'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { MutableRefObject, useCallback } from 'react'; import getScaledCursorPosition from '../util/getScaledCursorPosition'; diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts index 2adb02fd6d..abeab825e4 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseMove.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, isStagingSelector, @@ -11,7 +11,7 @@ import { import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import Konva from 'konva'; import { Vector2d } from 'konva/lib/types'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { MutableRefObject, useCallback } from 'react'; import getScaledCursorPosition from '../util/getScaledCursorPosition'; diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseOut.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseOut.ts index edea9cfff1..fcb3b3223f 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseOut.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseOut.ts @@ -1,4 +1,4 @@ -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { mouseLeftCanvas } from 'features/canvas/store/canvasSlice'; import { useCallback } from 'react'; diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts index 0284f42a79..8e70543c6f 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasMouseUp.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector, isStagingSelector, @@ -12,7 +12,7 @@ import { } from 'features/canvas/store/canvasSlice'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import Konva from 'konva'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { MutableRefObject, useCallback } from 'react'; import getScaledCursorPosition from '../util/getScaledCursorPosition'; diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts index 14f9d37d7d..3d6a1d7804 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useCanvasZoom.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { setStageCoordinates, @@ -7,7 +7,7 @@ import { } from 'features/canvas/store/canvasSlice'; import Konva from 'konva'; import { KonvaEventObject } from 'konva/lib/Node'; -import { clamp, isEqual } from 'lodash'; +import { clamp, isEqual } from 'lodash-es'; import { MutableRefObject, useCallback } from 'react'; import { diff --git a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts index 00f7a2b46a..1356b24416 100644 --- a/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts +++ b/invokeai/frontend/web/src/features/canvas/hooks/useColorUnderCursor.ts @@ -1,4 +1,4 @@ -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import Konva from 'konva'; import { commitColorPickerColor, diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts index 3f81f71fad..dbcdde00d5 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSelectors.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { systemSelector } from 'features/system/store/systemSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { CanvasImage, CanvasState, isCanvasBaseImage } from './canvasTypes'; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts index 34688ef659..ab3ab0c4e9 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts @@ -1,12 +1,12 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import { roundDownToMultiple, roundToMultiple, } from 'common/util/roundDownToMultiple'; import { IRect, Vector2d } from 'konva/lib/types'; -import { clamp, cloneDeep } from 'lodash'; +import { clamp, cloneDeep } from 'lodash-es'; // import { RgbaColor } from 'react-colorful'; import calculateCoordinates from '../util/calculateCoordinates'; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts index 95cf573c3b..2eec0e9bed 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts @@ -1,4 +1,4 @@ -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import { IRect, Vector2d } from 'konva/lib/types'; import { RgbaColor } from 'react-colorful'; diff --git a/invokeai/frontend/web/src/features/canvas/store/thunks/mergeAndUploadCanvas.ts b/invokeai/frontend/web/src/features/canvas/store/thunks/mergeAndUploadCanvas.ts index a1a7bd3989..e14871e11b 100644 --- a/invokeai/frontend/web/src/features/canvas/store/thunks/mergeAndUploadCanvas.ts +++ b/invokeai/frontend/web/src/features/canvas/store/thunks/mergeAndUploadCanvas.ts @@ -1,7 +1,7 @@ import { AnyAction, ThunkAction } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; -import { RootState } from 'app/store'; -import { addImage } from 'features/gallery/store/gallerySlice'; +import * as InvokeAI from 'app/types/invokeai'; +import { RootState } from 'app/store/store'; +// import { addImage } from 'features/gallery/store/gallerySlice'; import { addToast, setCurrentStatus, diff --git a/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts b/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts index d592c3c14c..f16c92651a 100644 --- a/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts +++ b/invokeai/frontend/web/src/features/canvas/store/thunks/requestCanvasScale.ts @@ -1,6 +1,6 @@ -import { AppDispatch, AppGetState } from 'app/store'; +import { AppDispatch, AppGetState } from 'app/store/store'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { debounce } from 'lodash'; +import { debounce } from 'lodash-es'; import { setDoesCanvasNeedScaling } from '../canvasSlice'; const debouncedCanvasScale = debounce((dispatch: AppDispatch) => { diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx index 462982b91d..4fef811d46 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { isEqual } from 'lodash'; +import { get, isEqual, isNumber, isString } from 'lodash-es'; import { ButtonGroup, @@ -10,8 +10,8 @@ import { useDisclosure, useToast, } from '@chakra-ui/react'; -import { runESRGAN, runFacetool } from 'app/socketio/actions'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +// import { runESRGAN, runFacetool } from 'app/socketio/actions'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import IAIIconButton from 'common/components/IAIIconButton'; import IAIPopover from 'common/components/IAIPopover'; @@ -63,11 +63,11 @@ import { } from '../store/gallerySelectors'; import DeleteImageModal from './DeleteImageModal'; import { useCallback } from 'react'; -import useSetBothPrompts from 'features/parameters/hooks/usePrompt'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { useGetUrl } from 'common/util/getUrl'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { imageDeleted } from 'services/thunks/image'; +import { useParameters } from 'features/parameters/hooks/useParameters'; const currentImageButtonsSelector = createSelector( [ @@ -112,6 +112,8 @@ const currentImageButtonsSelector = createSelector( isLightboxOpen, shouldHidePreview, image, + seed: image?.metadata?.invokeai?.node?.seed, + prompt: image?.metadata?.invokeai?.node?.prompt, }; }, { @@ -161,18 +163,10 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { const toast = useToast(); const { t } = useTranslation(); - const setBothPrompts = useSetBothPrompts(); - const handleClickUseAsInitialImage = () => { - if (!image) return; - if (isLightboxOpen) dispatch(setIsLightboxOpen(false)); - dispatch(initialImageSelected(image.name)); - // dispatch(setInitialImage(currentImage)); + const { recallPrompt, recallSeed, sendToImageToImage } = useParameters(); - // dispatch(setActiveTab('img2img')); - }; - - const handleCopyImage = async () => { + const handleCopyImage = useCallback(async () => { if (!image?.url) { return; } @@ -194,9 +188,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { duration: 2500, isClosable: true, }); - }; + }, [getUrl, t, image?.url, toast]); - const handleCopyImageLink = () => { + const handleCopyImageLink = useCallback(() => { const url = image ? shouldTransformUrls ? getUrl(image.url) @@ -215,37 +209,13 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { isClosable: true, }); }); - }; + }, [toast, shouldTransformUrls, getUrl, t, image]); - useHotkeys( - 'shift+i', - () => { - if (image) { - handleClickUseAsInitialImage(); - toast({ - title: t('toast.sentToImageToImage'), - status: 'success', - duration: 2500, - isClosable: true, - }); - } else { - toast({ - title: t('toast.imageNotLoaded'), - description: t('toast.imageNotLoadedDesc'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } - }, - [image] - ); - - const handlePreviewVisibility = () => { + const handlePreviewVisibility = useCallback(() => { dispatch(setShouldHidePreview(!shouldHidePreview)); - }; + }, [dispatch, shouldHidePreview]); - const handleClickUseAllParameters = () => { + const handleClickUseAllParameters = useCallback(() => { if (!image) return; // selectedImage.metadata && // dispatch(setAllParameters(selectedImage.metadata)); @@ -254,12 +224,13 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { // } else if (selectedImage.metadata?.image.type === 'txt2img') { // dispatch(setActiveTab('txt2img')); // } - }; + }, [image]); useHotkeys( 'a', () => { - if (['txt2img', 'img2img'].includes(image?.metadata?.sd_metadata?.type)) { + const type = image?.metadata?.invokeai?.node?.types; + if (isString(type) && ['txt2img', 'img2img'].includes(type)) { handleClickUseAllParameters(); toast({ title: t('toast.parametersSet'), @@ -280,67 +251,27 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { [image] ); - const handleClickUseSeed = () => { - image?.metadata && dispatch(setSeed(image.metadata.sd_metadata.seed)); - }; + const handleUseSeed = useCallback(() => { + recallSeed(image?.metadata?.invokeai?.node?.seed); + }, [image, recallSeed]); - useHotkeys( - 's', - () => { - if (image?.metadata?.sd_metadata?.seed) { - handleClickUseSeed(); - toast({ - title: t('toast.seedSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - } else { - toast({ - title: t('toast.seedNotSet'), - description: t('toast.seedNotSetDesc'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } - }, - [image] - ); + useHotkeys('s', handleUseSeed, [image]); - const handleClickUsePrompt = useCallback(() => { - if (image?.metadata?.sd_metadata?.prompt) { - setBothPrompts(image?.metadata?.sd_metadata?.prompt); - } - }, [image?.metadata?.sd_metadata?.prompt, setBothPrompts]); + const handleUsePrompt = useCallback(() => { + recallPrompt(image?.metadata?.invokeai?.node?.prompt); + }, [image, recallPrompt]); - useHotkeys( - 'p', - () => { - if (image?.metadata?.sd_metadata?.prompt) { - handleClickUsePrompt(); - toast({ - title: t('toast.promptSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - } else { - toast({ - title: t('toast.promptNotSet'), - description: t('toast.promptNotSetDesc'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } - }, - [image] - ); + useHotkeys('p', handleUsePrompt, [image]); - const handleClickUpscale = () => { + const handleSendToImageToImage = useCallback(() => { + sendToImageToImage(image); + }, [image, sendToImageToImage]); + + useHotkeys('shift+i', handleSendToImageToImage, [image]); + + const handleClickUpscale = useCallback(() => { // selectedImage && dispatch(runESRGAN(selectedImage)); - }; + }, []); useHotkeys( 'Shift+U', @@ -369,9 +300,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { ] ); - const handleClickFixFaces = () => { + const handleClickFixFaces = useCallback(() => { // selectedImage && dispatch(runFacetool(selectedImage)); - }; + }, []); useHotkeys( 'Shift+R', @@ -401,10 +332,12 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { ] ); - const handleClickShowImageDetails = () => - dispatch(setShouldShowImageDetails(!shouldShowImageDetails)); + const handleClickShowImageDetails = useCallback( + () => dispatch(setShouldShowImageDetails(!shouldShowImageDetails)), + [dispatch, shouldShowImageDetails] + ); - const handleSendToCanvas = () => { + const handleSendToCanvas = useCallback(() => { if (!image) return; if (isLightboxOpen) dispatch(setIsLightboxOpen(false)); @@ -421,7 +354,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { duration: 2500, isClosable: true, }); - }; + }, [image, isLightboxOpen, dispatch, activeTabName, toast, t]); useHotkeys( 'i', @@ -440,19 +373,19 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { [image, shouldShowImageDetails] ); - const handleInitiateDelete = () => { + const handleDelete = useCallback(() => { + if (canDeleteImage && image) { + dispatch(imageDeleted({ imageType: image.type, imageName: image.name })); + } + }, [image, canDeleteImage, dispatch]); + + const handleInitiateDelete = useCallback(() => { if (shouldConfirmOnDelete) { onDeleteDialogOpen(); } else { handleDelete(); } - }; - - const handleDelete = () => { - if (canDeleteImage && image) { - dispatch(imageDeleted({ imageType: image.type, imageName: image.name })); - } - }; + }, [shouldConfirmOnDelete, onDeleteDialogOpen, handleDelete]); useHotkeys('delete', handleInitiateDelete, [ image, @@ -461,9 +394,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { isProcessing, ]); - const handleLightBox = () => { + const handleLightBox = useCallback(() => { dispatch(setIsLightboxOpen(!isLightboxOpen)); - }; + }, [dispatch, isLightboxOpen]); return ( <> @@ -494,7 +427,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { > } > {t('parameters.sendToImg2Img')} @@ -568,16 +501,16 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { icon={} tooltip={`${t('parameters.usePrompt')} (P)`} aria-label={`${t('parameters.usePrompt')} (P)`} - isDisabled={!image?.metadata?.sd_metadata?.prompt} - onClick={handleClickUsePrompt} + isDisabled={!image?.metadata?.invokeai?.node?.prompt} + onClick={handleUsePrompt} /> } tooltip={`${t('parameters.useSeed')} (S)`} aria-label={`${t('parameters.useSeed')} (S)`} - isDisabled={!image?.metadata?.sd_metadata?.seed} - onClick={handleClickUseSeed} + isDisabled={!image?.metadata?.invokeai?.node?.seed} + onClick={handleUseSeed} /> { const { shouldShowImageDetails, shouldHidePreview } = ui; - const { progressImage } = system; - - // TODO: Clean this up, this is really gross - const imageToDisplay = progressImage - ? { - url: progressImage.dataURL, - width: progressImage.width, - height: progressImage.height, - isProgressImage: true, - image: progressImage, - } - : selectedImage - ? { - url: selectedImage.url, - width: selectedImage.metadata.width, - height: selectedImage.metadata.height, - isProgressImage: false, - image: selectedImage, - } - : null; return { shouldShowImageDetails, shouldHidePreview, - imageToDisplay, + image: selectedImage, }; }, { @@ -50,8 +31,8 @@ export const imagesSelector = createSelector( } ); -export default function CurrentImagePreview() { - const { shouldShowImageDetails, imageToDisplay, shouldHidePreview } = +const CurrentImagePreview = () => { + const { shouldShowImageDetails, image, shouldHidePreview } = useAppSelector(imagesSelector); const { getUrl } = useGetUrl(); @@ -65,54 +46,39 @@ export default function CurrentImagePreview() { height: '100%', }} > - {imageToDisplay && ( + {image && ( - ) : !imageToDisplay.isProgressImage ? ( - - ) : undefined - } + src={shouldHidePreview ? undefined : getUrl(image.url)} + width={image.metadata.width} + height={image.metadata.height} + fallback={shouldHidePreview ? : undefined} sx={{ objectFit: 'contain', maxWidth: '100%', maxHeight: '100%', height: 'auto', position: 'absolute', - imageRendering: imageToDisplay.isProgressImage - ? 'pixelated' - : 'initial', borderRadius: 'base', }} /> )} + {shouldShowImageDetails && image && 'metadata' in image && ( + + + + )} {!shouldShowImageDetails && } - {shouldShowImageDetails && - imageToDisplay && - 'metadata' in imageToDisplay.image && ( - - - - )} ); -} +}; + +export default memo(CurrentImagePreview); diff --git a/invokeai/frontend/web/src/features/gallery/components/DeleteImageModal.tsx b/invokeai/frontend/web/src/features/gallery/components/DeleteImageModal.tsx index 35effd95be..12038f4179 100644 --- a/invokeai/frontend/web/src/features/gallery/components/DeleteImageModal.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/DeleteImageModal.tsx @@ -9,13 +9,13 @@ import { Text, } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import IAISwitch from 'common/components/IAISwitch'; import { configSelector } from 'features/system/store/configSelectors'; import { systemSelector } from 'features/system/store/systemSelectors'; import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { ChangeEvent, memo, useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx b/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx index 659b59c91d..032784fbf9 100644 --- a/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx @@ -5,65 +5,38 @@ import { Image, MenuItem, MenuList, - Text, + Skeleton, useDisclosure, useTheme, useToast, } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { - imageSelected, - setCurrentImage, -} from 'features/gallery/store/gallerySlice'; -import { - initialImageSelected, - setAllImageToImageParameters, - setAllParameters, - setSeed, -} from 'features/parameters/store/generationSlice'; -import { DragEvent, memo, useState } from 'react'; -import { - FaCheck, - FaExpand, - FaLink, - FaShare, - FaTrash, - FaTrashAlt, -} from 'react-icons/fa'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { imageSelected } from 'features/gallery/store/gallerySlice'; +import { DragEvent, memo, useCallback, useState } from 'react'; +import { FaCheck, FaExpand, FaImage, FaShare, FaTrash } from 'react-icons/fa'; import DeleteImageModal from './DeleteImageModal'; import { ContextMenu } from 'chakra-ui-contextmenu'; -import * as InvokeAI from 'app/invokeai'; -import { - resizeAndScaleCanvas, - setInitialCanvasImage, -} from 'features/canvas/store/canvasSlice'; +import * as InvokeAI from 'app/types/invokeai'; +import { resizeAndScaleCanvas } from 'features/canvas/store/canvasSlice'; import { gallerySelector } from 'features/gallery/store/gallerySelectors'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { useTranslation } from 'react-i18next'; -import useSetBothPrompts from 'features/parameters/hooks/usePrompt'; -import { setIsLightboxOpen } from 'features/lightbox/store/lightboxSlice'; import IAIIconButton from 'common/components/IAIIconButton'; import { useGetUrl } from 'common/util/getUrl'; import { ExternalLinkIcon } from '@chakra-ui/icons'; -import { BiZoomIn } from 'react-icons/bi'; import { IoArrowUndoCircleOutline } from 'react-icons/io5'; import { imageDeleted } from 'services/thunks/image'; import { createSelector } from '@reduxjs/toolkit'; import { systemSelector } from 'features/system/store/systemSelectors'; -import { configSelector } from 'features/system/store/configSelectors'; import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; +import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; +import { useParameters } from 'features/parameters/hooks/useParameters'; export const selector = createSelector( - [ - gallerySelector, - systemSelector, - configSelector, - lightboxSelector, - activeTabNameSelector, - ], - (gallery, system, config, lightbox, activeTabName) => { + [gallerySelector, systemSelector, lightboxSelector, activeTabNameSelector], + (gallery, system, lightbox, activeTabName) => { const { galleryImageObjectFit, galleryImageMinimumWidth, @@ -71,7 +44,6 @@ export const selector = createSelector( } = gallery; const { isLightboxOpen } = lightbox; - const { disabledFeatures } = config; const { isConnected, isProcessing, shouldConfirmOnDelete } = system; return { @@ -82,7 +54,6 @@ export const selector = createSelector( shouldUseSingleGalleryColumn, activeTabName, isLightboxOpen, - disabledFeatures, }; }, { @@ -113,14 +84,15 @@ const HoverableImage = memo((props: HoverableImageProps) => { galleryImageMinimumWidth, canDeleteImage, shouldUseSingleGalleryColumn, - disabledFeatures, shouldConfirmOnDelete, } = useAppSelector(selector); + const { isOpen: isDeleteDialogOpen, onOpen: onDeleteDialogOpen, onClose: onDeleteDialogClose, } = useDisclosure(); + const { image, isSelected } = props; const { url, thumbnail, name, metadata } = image; const { getUrl } = useGetUrl(); @@ -130,53 +102,62 @@ const HoverableImage = memo((props: HoverableImageProps) => { const toast = useToast(); const { direction } = useTheme(); const { t } = useTranslation(); - const setBothPrompts = useSetBothPrompts(); + const { isFeatureEnabled: isLightboxEnabled } = useFeatureStatus('lightbox'); + const { recallSeed, recallPrompt, sendToImageToImage, recallInitialImage } = + useParameters(); const handleMouseOver = () => setIsHovered(true); - const handleMouseOut = () => setIsHovered(false); - const handleInitiateDelete = () => { + // Immediately deletes an image + const handleDelete = useCallback(() => { + if (canDeleteImage && image) { + dispatch(imageDeleted({ imageType: image.type, imageName: image.name })); + } + }, [dispatch, image, canDeleteImage]); + + // Opens the alert dialog to check if user is sure they want to delete + const handleInitiateDelete = useCallback(() => { if (shouldConfirmOnDelete) { onDeleteDialogOpen(); } else { handleDelete(); } - }; + }, [handleDelete, onDeleteDialogOpen, shouldConfirmOnDelete]); - const handleDelete = () => { - if (canDeleteImage && image) { - dispatch(imageDeleted({ imageType: image.type, imageName: image.name })); - } - }; + const handleSelectImage = useCallback(() => { + dispatch(imageSelected(image)); + }, [image, dispatch]); - const handleUsePrompt = () => { - if (image.metadata?.sd_metadata?.prompt) { - setBothPrompts(image.metadata?.sd_metadata?.prompt); - } - toast({ - title: t('toast.promptSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - }; + const handleDragStart = useCallback( + (e: DragEvent) => { + e.dataTransfer.setData('invokeai/imageName', image.name); + e.dataTransfer.setData('invokeai/imageType', image.type); + e.dataTransfer.effectAllowed = 'move'; + }, + [image] + ); - const handleUseSeed = () => { - image.metadata.sd_metadata && - dispatch(setSeed(image.metadata.sd_metadata.image.seed)); - toast({ - title: t('toast.seedSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - }; + // Recall parameters handlers + const handleRecallPrompt = useCallback(() => { + recallPrompt(image.metadata?.invokeai?.node?.prompt); + }, [image, recallPrompt]); - const handleSendToImageToImage = () => { - dispatch(initialImageSelected(image.name)); - }; + const handleRecallSeed = useCallback(() => { + recallSeed(image.metadata.invokeai?.node?.seed); + }, [image, recallSeed]); + const handleSendToImageToImage = useCallback(() => { + sendToImageToImage(image); + }, [image, sendToImageToImage]); + + const handleRecallInitialImage = useCallback(() => { + recallInitialImage(image.metadata.invokeai?.node?.image); + }, [image, recallInitialImage]); + + /** + * TODO: the rest of these + */ const handleSendToCanvas = () => { // dispatch(setInitialCanvasImage(image)); @@ -195,48 +176,14 @@ const HoverableImage = memo((props: HoverableImageProps) => { }; const handleUseAllParameters = () => { - metadata.sd_metadata && dispatch(setAllParameters(metadata.sd_metadata)); - toast({ - title: t('toast.parametersSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - }; - - const handleUseInitialImage = async () => { - if (metadata.sd_metadata?.image?.init_image_path) { - const response = await fetch( - metadata.sd_metadata?.image?.init_image_path - ); - if (response.ok) { - dispatch(setAllImageToImageParameters(metadata?.sd_metadata)); - toast({ - title: t('toast.initialImageSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - return; - } - } - toast({ - title: t('toast.initialImageNotSet'), - description: t('toast.initialImageNotSetDesc'), - status: 'error', - duration: 2500, - isClosable: true, - }); - }; - - const handleSelectImage = () => { - dispatch(imageSelected(image.name)); - }; - - const handleDragStart = (e: DragEvent) => { - e.dataTransfer.setData('invokeai/imageName', image.name); - e.dataTransfer.setData('invokeai/imageType', image.type); - e.dataTransfer.effectAllowed = 'move'; + // metadata.invokeai?.node && + // dispatch(setAllParameters(metadata.invokeai?.node)); + // toast({ + // title: t('toast.parametersSet'), + // status: 'success', + // duration: 2500, + // isClosable: true, + // }); }; const handleLightBox = () => { @@ -253,37 +200,37 @@ const HoverableImage = memo((props: HoverableImageProps) => { menuProps={{ size: 'sm', isLazy: true }} renderMenu={() => ( - + } onClickCapture={handleOpenInNewTab} > {t('common.openInNewTab')} - {!disabledFeatures.includes('lightbox') && ( + {isLightboxEnabled && ( } onClickCapture={handleLightBox}> {t('parameters.openInViewer')} )} } - onClickCapture={handleUsePrompt} - isDisabled={image?.metadata?.sd_metadata?.prompt === undefined} + onClickCapture={handleRecallPrompt} + isDisabled={image?.metadata?.invokeai?.node?.prompt === undefined} > {t('parameters.usePrompt')} } - onClickCapture={handleUseSeed} - isDisabled={image?.metadata?.sd_metadata?.seed === undefined} + onClickCapture={handleRecallSeed} + isDisabled={image?.metadata?.invokeai?.node?.seed === undefined} > {t('parameters.useSeed')} } - onClickCapture={handleUseInitialImage} - isDisabled={image?.metadata?.sd_metadata?.type !== 'img2img'} + onClickCapture={handleRecallInitialImage} + isDisabled={image?.metadata?.invokeai?.node?.type !== 'img2img'} > {t('parameters.useInitImg')} @@ -292,7 +239,7 @@ const HoverableImage = memo((props: HoverableImageProps) => { onClickCapture={handleUseAllParameters} isDisabled={ !['txt2img', 'img2img'].includes( - image?.metadata?.sd_metadata?.type + String(image?.metadata?.invokeai?.node?.type) ) } > @@ -322,58 +269,48 @@ const HoverableImage = memo((props: HoverableImageProps) => { userSelect="none" draggable={true} onDragStart={handleDragStart} + onClick={handleSelectImage} ref={ref} sx={{ - padding: 2, display: 'flex', justifyContent: 'center', + alignItems: 'center', + w: 'full', + h: 'full', transition: 'transform 0.2s ease-out', - _hover: { - cursor: 'pointer', - - zIndex: 2, - }, - _before: { - content: '""', - display: 'block', - paddingBottom: '100%', - }, + aspectRatio: '1/1', }} > } sx={{ - position: 'absolute', width: '100%', height: '100%', maxWidth: '100%', maxHeight: '100%', - top: '50%', - transform: 'translate(-50%,-50%)', - ...(direction === 'rtl' - ? { insetInlineEnd: '50%' } - : { insetInlineStart: '50%' }), }} /> - - {isSelected && ( + {isSelected && ( + { fill: 'ok.500', }} /> - )} - - {isHovered && galleryImageMinimumWidth >= 64 && ( + + )} + {isHovered && galleryImageMinimumWidth >= 100 && ( { const { currentCategory } = gallery; - return currentCategory === 'result' + return currentCategory === 'results' ? { images: resultsAdapter.getSelectors().selectAll(results), isLoading: results.isLoading, @@ -68,32 +81,41 @@ const ImageGalleryContent = () => { const { t } = useTranslation(); const resizeObserverRef = useRef(null); const [shouldShouldIconButtons, setShouldShouldIconButtons] = useState(true); + const rootRef = useRef(null); + const [scroller, setScroller] = useState(null); + const [initialize, osInstance] = useOverlayScrollbars({ + defer: true, + options: { + scrollbars: { + visibility: 'auto', + autoHide: 'leave', + autoHideDelay: 1300, + theme: 'os-theme-dark', + }, + overflow: { x: 'hidden' }, + }, + }); const { // images, currentCategory, - currentImageUuid, shouldPinGallery, galleryImageMinimumWidth, - galleryGridTemplateColumns, galleryImageObjectFit, shouldAutoSwitchToNewImages, - // areMoreImagesAvailable, shouldUseSingleGalleryColumn, + selectedImage, } = useAppSelector(imageGallerySelector); const { images, areMoreImagesAvailable, isLoading } = useAppSelector(gallerySelector); - // const handleClickLoadMore = () => { - // dispatch(requestImages(currentCategory)); - // }; const handleClickLoadMore = () => { - if (currentCategory === 'result') { + if (currentCategory === 'results') { dispatch(receivedResultImagesPage()); } - if (currentCategory === 'user') { + if (currentCategory === 'uploads') { dispatch(receivedUploadImagesPage()); } }; @@ -129,6 +151,25 @@ const ImageGalleryContent = () => { return () => resizeObserver.disconnect(); // clean up }, []); + useEffect(() => { + const { current: root } = rootRef; + if (scroller && root) { + initialize({ + target: root, + elements: { + viewport: scroller, + }, + }); + } + return () => osInstance()?.destroy(); + }, [scroller, initialize, osInstance]); + + const setScrollerRef = useCallback((ref: HTMLElement | Window | null) => { + if (ref instanceof HTMLElement) { + setScroller(ref); + } + }, []); + return ( { } - onClick={() => dispatch(setCurrentCategory('result'))} + onClick={() => dispatch(setCurrentCategory('results'))} /> } - onClick={() => dispatch(setCurrentCategory('user'))} + onClick={() => dispatch(setCurrentCategory('uploads'))} /> ) : ( <> dispatch(setCurrentCategory('result'))} + isChecked={currentCategory === 'results'} + onClick={() => dispatch(setCurrentCategory('results'))} flexGrow={1} > {t('gallery.generations')} dispatch(setCurrentCategory('user'))} + isChecked={currentCategory === 'uploads'} + onClick={() => dispatch(setCurrentCategory('uploads'))} flexGrow={1} > {t('gallery.uploads')} @@ -241,65 +282,119 @@ const ImageGalleryContent = () => { /> - - - {images.length || areMoreImagesAvailable ? ( - <> - - {images.map((image) => { - const { name } = image; - const isSelected = currentImageUuid === name; - return ( - - ); - })} - - - {areMoreImagesAvailable - ? t('gallery.loadMore') - : t('gallery.allImagesLoaded')} - - - ) : ( - + {images.length || areMoreImagesAvailable ? ( + <> + + {shouldUseSingleGalleryColumn ? ( + setScrollerRef(ref)} + itemContent={(index, image) => { + const { name } = image; + const isSelected = selectedImage?.name === name; + + return ( + + + + ); + }} + /> + ) : ( + { + const { name } = image; + const isSelected = selectedImage?.name === name; + + return ( + + ); + }} + /> + )} + + - - {t('gallery.noImagesInGallery')} - - )} - - + {areMoreImagesAvailable + ? t('gallery.loadMore') + : t('gallery.allImagesLoaded')} + + + ) : ( + + + {t('gallery.noImagesInGallery')} + + )} + ); }; -ImageGalleryContent.displayName = 'ImageGalleryContent'; -export default ImageGalleryContent; +type ItemContainerProps = PropsWithChildren & FlexProps; +const ItemContainer = forwardRef((props: ItemContainerProps, ref) => ( + + {props.children} + +)); + +type ListContainerProps = PropsWithChildren & FlexProps; +const ListContainer = forwardRef((props: ListContainerProps, ref) => { + const galleryImageMinimumWidth = useAppSelector( + (state: RootState) => state.gallery.galleryImageMinimumWidth + ); + + return ( + + {props.children} + + ); +}); + +export default memo(ImageGalleryContent); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryPanel.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryPanel.tsx index 2a557240ef..76442d340b 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryPanel.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryPanel.tsx @@ -1,13 +1,13 @@ -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { gallerySelector } from 'features/gallery/store/gallerySelectors'; import { - selectNextImage, - selectPrevImage, + // selectNextImage, + // selectPrevImage, setGalleryImageMinimumWidth, } from 'features/gallery/store/gallerySlice'; import { InvokeTabName } from 'features/ui/store/tabMap'; -import { clamp, isEqual } from 'lodash'; +import { clamp, isEqual } from 'lodash-es'; import { useHotkeys } from 'react-hotkeys-hook'; import './ImageGallery.css'; @@ -28,6 +28,7 @@ import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvas import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import useResolution from 'common/hooks/useResolution'; import { Flex } from '@chakra-ui/react'; +import { memo } from 'react'; const GALLERY_TAB_WIDTHS: Record< InvokeTabName, @@ -72,7 +73,7 @@ const galleryPanelSelector = createSelector( } ); -export default function ImageGalleryPanel() { +export const ImageGalleryPanel = () => { const dispatch = useAppDispatch(); const { shouldPinGallery, @@ -109,28 +110,6 @@ export default function ImageGalleryPanel() { [shouldPinGallery] ); - useHotkeys( - 'left', - () => { - dispatch(selectPrevImage()); - }, - { - enabled: !isStaging || activeTabName !== 'unifiedCanvas', - }, - [isStaging, activeTabName] - ); - - useHotkeys( - 'right', - () => { - dispatch(selectNextImage()); - }, - { - enabled: !isStaging || activeTabName !== 'unifiedCanvas', - }, - [isStaging, activeTabName] - ); - useHotkeys( 'shift+g', () => { @@ -232,4 +211,6 @@ export default function ImageGalleryPanel() { }; return renderImageGallery(); -} +}; + +export default memo(ImageGalleryPanel); 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 1909dc56a7..eedbf63081 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetaDataViewer/ImageMetadataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetaDataViewer/ImageMetadataViewer.tsx @@ -9,8 +9,8 @@ import { Text, Tooltip, } from '@chakra-ui/react'; -import * as InvokeAI from 'app/invokeai'; -import { useAppDispatch } from 'app/storeHooks'; +import * as InvokeAI from 'app/types/invokeai'; +import { useAppDispatch } from 'app/store/storeHooks'; import { useGetUrl } from 'common/util/getUrl'; import promptToString from 'common/util/promptToString'; import { seedWeightsToString } from 'common/util/seedWeightPairs'; @@ -159,6 +159,7 @@ const ImageMetadataViewer = memo(({ image }: ImageMetadataViewerProps) => { _dark: { bg: 'blackAlpha.600', }, + overflow: 'scroll', }} > diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetaDataViewer/OLD_ImageMetadataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetaDataViewer/OLD_ImageMetadataViewer.tsx index 3339140a52..c76ee7f078 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetaDataViewer/OLD_ImageMetadataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetaDataViewer/OLD_ImageMetadataViewer.tsx @@ -9,8 +9,8 @@ import { Text, Tooltip, } from '@chakra-ui/react'; -import * as InvokeAI from 'app/invokeai'; -import { useAppDispatch } from 'app/storeHooks'; +import * as InvokeAI from 'app/types/invokeai'; +import { useAppDispatch } from 'app/store/storeHooks'; import { useGetUrl } from 'common/util/getUrl'; import promptToString from 'common/util/promptToString'; import { seedWeightsToString } from 'common/util/seedWeightPairs'; diff --git a/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx index 2da7579fd9..d0d25f8bc6 100644 --- a/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/NextPrevImageButtons.tsx @@ -1,16 +1,14 @@ import { ChakraProps, Flex, Grid, IconButton } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { isEqual } from 'lodash'; -import { useState } from 'react'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { clamp, isEqual } from 'lodash-es'; +import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FaAngleLeft, FaAngleRight } from 'react-icons/fa'; import { gallerySelector } from '../store/gallerySelectors'; -import { - GalleryCategory, - selectNextImage, - selectPrevImage, -} from '../store/gallerySlice'; +import { RootState } from 'app/store/store'; +import { imageSelected } from '../store/gallerySlice'; +import { useHotkeys } from 'react-hotkeys-hook'; const nextPrevButtonTriggerAreaStyles: ChakraProps['sx'] = { height: '100%', @@ -23,24 +21,47 @@ const nextPrevButtonStyles: ChakraProps['sx'] = { }; export const nextPrevImageButtonsSelector = createSelector( - gallerySelector, - (gallery) => { - const { currentImage } = gallery; + [(state: RootState) => state, gallerySelector], + (state, gallery) => { + const { selectedImage, currentCategory } = gallery; - const tempImages = - gallery.categories[ - currentImage ? (currentImage.category as GalleryCategory) : 'result' - ].images; + if (!selectedImage) { + return { + isOnFirstImage: true, + isOnLastImage: true, + }; + } - const currentImageIndex = tempImages.findIndex( - (i) => i.uuid === gallery?.currentImage?.uuid + const currentImageIndex = state[currentCategory].ids.findIndex( + (i) => i === selectedImage.name ); - const imagesLength = tempImages.length; + + const nextImageIndex = clamp( + currentImageIndex + 1, + 0, + state[currentCategory].ids.length - 1 + ); + + const prevImageIndex = clamp( + currentImageIndex - 1, + 0, + state[currentCategory].ids.length - 1 + ); + + const nextImageId = state[currentCategory].ids[nextImageIndex]; + const prevImageId = state[currentCategory].ids[prevImageIndex]; + + const nextImage = state[currentCategory].entities[nextImageId]; + const prevImage = state[currentCategory].entities[prevImageId]; + + const imagesLength = state[currentCategory].ids.length; return { isOnFirstImage: currentImageIndex === 0, isOnLastImage: !isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1, + nextImage, + prevImage, }; }, { @@ -54,34 +75,48 @@ const NextPrevImageButtons = () => { const dispatch = useAppDispatch(); const { t } = useTranslation(); - const { isOnFirstImage, isOnLastImage } = useAppSelector( - nextPrevImageButtonsSelector - ); + const { isOnFirstImage, isOnLastImage, nextImage, prevImage } = + useAppSelector(nextPrevImageButtonsSelector); const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] = useState(false); - const handleCurrentImagePreviewMouseOver = () => { + const handleCurrentImagePreviewMouseOver = useCallback(() => { setShouldShowNextPrevButtons(true); - }; + }, []); - const handleCurrentImagePreviewMouseOut = () => { + const handleCurrentImagePreviewMouseOut = useCallback(() => { setShouldShowNextPrevButtons(false); - }; + }, []); - const handleClickPrevButton = () => { - dispatch(selectPrevImage()); - }; + const handlePrevImage = useCallback(() => { + dispatch(imageSelected(prevImage)); + }, [dispatch, prevImage]); - const handleClickNextButton = () => { - dispatch(selectNextImage()); - }; + const handleNextImage = useCallback(() => { + dispatch(imageSelected(nextImage)); + }, [dispatch, nextImage]); + + useHotkeys( + 'left', + () => { + handlePrevImage(); + }, + [prevImage] + ); + + useHotkeys( + 'right', + () => { + handleNextImage(); + }, + [nextImage] + ); return ( { aria-label={t('accessibility.previousImage')} icon={} variant="unstyled" - onClick={handleClickPrevButton} + onClick={handlePrevImage} boxSize={16} sx={nextPrevButtonStyles} /> @@ -119,7 +154,7 @@ const NextPrevImageButtons = () => { aria-label={t('accessibility.nextImage')} icon={} variant="unstyled" - onClick={handleClickNextButton} + onClick={handleNextImage} boxSize={16} sx={nextPrevButtonStyles} /> diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByName.ts b/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByName.ts index b662cf02c1..d15c3fb51f 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByName.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByName.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { ImageType } from 'services/api'; import { selectResultsEntities } from '../store/resultsSlice'; import { selectUploadsEntities } from '../store/uploadsSlice'; diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByUuid.ts b/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByUuid.ts index 1c7c43ac70..27b2635e31 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByUuid.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useGetImageByUuid.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { gallerySelector } from '../store/gallerySelectors'; const selector = createSelector(gallerySelector, (gallery) => ({ diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySelectors.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySelectors.ts index 48ef22fd14..0fc8d300e9 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySelectors.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySelectors.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import { configSelector } from 'features/system/store/configSelectors'; import { systemSelector } from 'features/system/store/systemSelectors'; @@ -7,7 +7,7 @@ import { activeTabNameSelector, uiSelector, } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { selectResultsAll, selectResultsById, @@ -22,17 +22,22 @@ import { export const gallerySelector = (state: RootState) => state.gallery; export const imageGallerySelector = createSelector( - [gallerySelector, uiSelector, lightboxSelector, activeTabNameSelector], - (gallery, ui, lightbox, activeTabName) => { + [ + (state: RootState) => state, + gallerySelector, + uiSelector, + lightboxSelector, + activeTabNameSelector, + ], + (state, gallery, ui, lightbox, activeTabName) => { const { - categories, currentCategory, - currentImageUuid, galleryImageMinimumWidth, galleryImageObjectFit, shouldAutoSwitchToNewImages, galleryWidth, shouldUseSingleGalleryColumn, + selectedImage, } = gallery; const { shouldPinGallery } = ui; @@ -40,7 +45,6 @@ export const imageGallerySelector = createSelector( const { isLightboxOpen } = lightbox; return { - currentImageUuid, shouldPinGallery, galleryImageMinimumWidth, galleryImageObjectFit, @@ -49,9 +53,7 @@ export const imageGallerySelector = createSelector( : `repeat(auto-fill, minmax(${galleryImageMinimumWidth}px, auto))`, shouldAutoSwitchToNewImages, currentCategory, - images: categories[currentCategory].images, - areMoreImagesAvailable: - categories[currentCategory].areMoreImagesAvailable, + images: state[currentCategory].entities, galleryWidth, shouldEnableResize: isLightboxOpen || @@ -59,6 +61,7 @@ export const imageGallerySelector = createSelector( ? false : true, shouldUseSingleGalleryColumn, + selectedImage, }; }, { @@ -69,16 +72,16 @@ export const imageGallerySelector = createSelector( ); export const selectedImageSelector = createSelector( - [gallerySelector, selectResultsEntities, selectUploadsEntities], - (gallery, allResults, allUploads) => { - const selectedImageName = gallery.selectedImageName; + [(state: RootState) => state, gallerySelector], + (state, gallery) => { + const selectedImage = gallery.selectedImage; - if (selectedImageName in allResults) { - return allResults[selectedImageName]; + if (selectedImage?.type === 'results') { + return selectResultsById(state, selectedImage.name); } - if (selectedImageName in allUploads) { - return allUploads[selectedImageName]; + if (selectedImage?.type === 'uploads') { + return selectUploadsById(state, selectedImage.name); } } ); diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts index d0336379fc..47c2c4e0fd 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts @@ -1,259 +1,47 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; import { invocationComplete } from 'services/events/actions'; -import { InvokeTabName } from 'features/ui/store/tabMap'; -import { IRect } from 'konva/lib/types'; -import { clamp } from 'lodash'; import { isImageOutput } from 'services/types/guards'; import { deserializeImageResponse } from 'services/util/deserializeImageResponse'; import { imageUploaded } from 'services/thunks/image'; - -export type GalleryCategory = 'user' | 'result'; - -export type AddImagesPayload = { - images: Array; - areMoreImagesAvailable: boolean; - category: GalleryCategory; -}; +import { SelectedImage } from 'features/parameters/store/generationSlice'; type GalleryImageObjectFitType = 'contain' | 'cover'; -export type Gallery = { - images: InvokeAI._Image[]; - latest_mtime?: number; - earliest_mtime?: number; - areMoreImagesAvailable: boolean; -}; - export interface GalleryState { /** - * The selected image's unique name - * Use `selectedImageSelector` to access the image + * The selected image */ - selectedImageName: string; - /** - * The currently selected image - * @deprecated See `state.gallery.selectedImageName` - */ - currentImage?: InvokeAI._Image; - /** - * The currently selected image's uuid. - * @deprecated See `state.gallery.selectedImageName`, use `selectedImageSelector` to access the image - */ - currentImageUuid: string; - /** - * The current progress image - * @deprecated See `state.system.progressImage` - */ - intermediateImage?: InvokeAI._Image & { - boundingBox?: IRect; - generationMode?: InvokeTabName; - }; + selectedImage?: SelectedImage; galleryImageMinimumWidth: number; galleryImageObjectFit: GalleryImageObjectFitType; shouldAutoSwitchToNewImages: boolean; - categories: { - user: Gallery; - result: Gallery; - }; - currentCategory: GalleryCategory; galleryWidth: number; shouldUseSingleGalleryColumn: boolean; + currentCategory: 'results' | 'uploads'; } const initialState: GalleryState = { - selectedImageName: '', - currentImageUuid: '', + selectedImage: undefined, galleryImageMinimumWidth: 64, galleryImageObjectFit: 'cover', shouldAutoSwitchToNewImages: true, - currentCategory: 'result', - categories: { - user: { - images: [], - latest_mtime: undefined, - earliest_mtime: undefined, - areMoreImagesAvailable: true, - }, - result: { - images: [], - latest_mtime: undefined, - earliest_mtime: undefined, - areMoreImagesAvailable: true, - }, - }, galleryWidth: 300, shouldUseSingleGalleryColumn: false, + currentCategory: 'results', }; export const gallerySlice = createSlice({ name: 'gallery', initialState, reducers: { - imageSelected: (state, action: PayloadAction) => { - state.selectedImageName = action.payload; - }, - setCurrentImage: (state, action: PayloadAction) => { - state.currentImage = action.payload; - state.currentImageUuid = action.payload.uuid; - }, - removeImage: ( + imageSelected: ( state, - action: PayloadAction + action: PayloadAction ) => { - const { uuid, category } = action.payload; - - const tempImages = state.categories[category as GalleryCategory].images; - - const newImages = tempImages.filter((image) => image.uuid !== uuid); - - if (uuid === state.currentImageUuid) { - /** - * We are deleting the currently selected image. - * - * We want the new currentl selected image to be under the cursor in the - * gallery, so we need to do some fanagling. The currently selected image - * is set by its UUID, not its index in the image list. - * - * Get the currently selected image's index. - */ - const imageToDeleteIndex = tempImages.findIndex( - (image) => image.uuid === uuid - ); - - /** - * New current image needs to be in the same spot, but because the gallery - * is sorted in reverse order, the new current image's index will actuall be - * one less than the deleted image's index. - * - * Clamp the new index to ensure it is valid.. - */ - const newCurrentImageIndex = clamp( - imageToDeleteIndex, - 0, - newImages.length - 1 - ); - - state.currentImage = newImages.length - ? newImages[newCurrentImageIndex] - : undefined; - - state.currentImageUuid = newImages.length - ? newImages[newCurrentImageIndex].uuid - : ''; - } - - state.categories[category as GalleryCategory].images = newImages; - }, - addImage: ( - state, - action: PayloadAction<{ - image: InvokeAI._Image; - category: GalleryCategory; - }> - ) => { - const { image: newImage, category } = action.payload; - const { uuid, url, mtime } = newImage; - - const tempCategory = state.categories[category as GalleryCategory]; - - // Do not add duplicate images - if (tempCategory.images.find((i) => i.url === url && i.mtime === mtime)) { - return; - } - - tempCategory.images.unshift(newImage); - if (state.shouldAutoSwitchToNewImages) { - state.currentImageUuid = uuid; - state.currentImage = newImage; - state.currentCategory = category; - } - state.intermediateImage = undefined; - tempCategory.latest_mtime = mtime; - }, - setIntermediateImage: ( - state, - action: PayloadAction< - InvokeAI._Image & { - boundingBox?: IRect; - generationMode?: InvokeTabName; - } - > - ) => { - state.intermediateImage = action.payload; - }, - clearIntermediateImage: (state) => { - state.intermediateImage = undefined; - }, - selectNextImage: (state) => { - const { currentImage } = state; - if (!currentImage) return; - const tempImages = - state.categories[currentImage.category as GalleryCategory].images; - - if (currentImage) { - const currentImageIndex = tempImages.findIndex( - (i) => i.uuid === currentImage.uuid - ); - if (currentImageIndex < tempImages.length - 1) { - const newCurrentImage = tempImages[currentImageIndex + 1]; - state.currentImage = newCurrentImage; - state.currentImageUuid = newCurrentImage.uuid; - } - } - }, - selectPrevImage: (state) => { - const { currentImage } = state; - if (!currentImage) return; - const tempImages = - state.categories[currentImage.category as GalleryCategory].images; - - if (currentImage) { - const currentImageIndex = tempImages.findIndex( - (i) => i.uuid === currentImage.uuid - ); - if (currentImageIndex > 0) { - const newCurrentImage = tempImages[currentImageIndex - 1]; - state.currentImage = newCurrentImage; - state.currentImageUuid = newCurrentImage.uuid; - } - } - }, - addGalleryImages: (state, action: PayloadAction) => { - const { images, areMoreImagesAvailable, category } = action.payload; - const tempImages = state.categories[category].images; - - // const prevImages = category === 'user' ? state.userImages : state.resultImages - - if (images.length > 0) { - // Filter images that already exist in the gallery - const newImages = images.filter( - (newImage) => - !tempImages.find( - (i) => i.url === newImage.url && i.mtime === newImage.mtime - ) - ); - state.categories[category].images = tempImages - .concat(newImages) - .sort((a, b) => b.mtime - a.mtime); - - if (!state.currentImage) { - const newCurrentImage = images[0]; - state.currentImage = newCurrentImage; - state.currentImageUuid = newCurrentImage.uuid; - } - - // keep track of the timestamps of latest and earliest images received - state.categories[category].latest_mtime = images[0].mtime; - state.categories[category].earliest_mtime = - images[images.length - 1].mtime; - } - - if (areMoreImagesAvailable !== undefined) { - state.categories[category].areMoreImagesAvailable = - areMoreImagesAvailable; - } + state.selectedImage = action.payload; + // TODO: if the user selects an image, disable the auto switch? + // state.shouldAutoSwitchToNewImages = false; }, setGalleryImageMinimumWidth: (state, action: PayloadAction) => { state.galleryImageMinimumWidth = action.payload; @@ -267,7 +55,10 @@ export const gallerySlice = createSlice({ setShouldAutoSwitchToNewImages: (state, action: PayloadAction) => { state.shouldAutoSwitchToNewImages = action.payload; }, - setCurrentCategory: (state, action: PayloadAction) => { + setCurrentCategory: ( + state, + action: PayloadAction<'results' | 'uploads'> + ) => { state.currentCategory = action.payload; }, setGalleryWidth: (state, action: PayloadAction) => { @@ -286,9 +77,11 @@ export const gallerySlice = createSlice({ */ builder.addCase(invocationComplete, (state, action) => { const { data } = action.payload; - if (isImageOutput(data.result)) { - state.selectedImageName = data.result.image.image_name; - state.intermediateImage = undefined; + if (isImageOutput(data.result) && state.shouldAutoSwitchToNewImages) { + state.selectedImage = { + name: data.result.image.image_name, + type: 'results', + }; } }); @@ -299,27 +92,19 @@ export const gallerySlice = createSlice({ const { response } = action.payload; const uploadedImage = deserializeImageResponse(response); - state.selectedImageName = uploadedImage.name; + state.selectedImage = { name: uploadedImage.name, type: 'uploads' }; }); }, }); export const { imageSelected, - addImage, - clearIntermediateImage, - removeImage, - setCurrentImage, - addGalleryImages, - setIntermediateImage, - selectNextImage, - selectPrevImage, setGalleryImageMinimumWidth, setGalleryImageObjectFit, setShouldAutoSwitchToNewImages, - setCurrentCategory, setGalleryWidth, setShouldUseSingleGalleryColumn, + setCurrentCategory, } = gallerySlice.actions; export default gallerySlice.reducer; diff --git a/invokeai/frontend/web/src/features/gallery/store/resultsPersistDenylist.ts b/invokeai/frontend/web/src/features/gallery/store/resultsPersistDenylist.ts index ef21f4b7b2..b62a199b33 100644 --- a/invokeai/frontend/web/src/features/gallery/store/resultsPersistDenylist.ts +++ b/invokeai/frontend/web/src/features/gallery/store/resultsPersistDenylist.ts @@ -5,7 +5,7 @@ import { ResultsState } from './resultsSlice'; * * Currently denylisting results slice entirely, see persist config in store.ts */ -const itemsToDenylist: (keyof ResultsState)[] = []; +const itemsToDenylist: (keyof ResultsState)[] = ['isLoading']; export const resultsDenylist = itemsToDenylist.map( (denylistItem) => `results.${denylistItem}` diff --git a/invokeai/frontend/web/src/features/gallery/store/resultsSlice.ts b/invokeai/frontend/web/src/features/gallery/store/resultsSlice.ts index e4b89144f4..26af366e03 100644 --- a/invokeai/frontend/web/src/features/gallery/store/resultsSlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/resultsSlice.ts @@ -1,8 +1,8 @@ import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'; -import { Image } from 'app/invokeai'; +import { Image } from 'app/types/invokeai'; import { invocationComplete } from 'services/events/actions'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { receivedResultImagesPage, IMAGES_PER_PAGE, @@ -65,7 +65,7 @@ const resultsSlice = createSlice({ deserializeImageResponse(image) ); - resultsAdapter.addMany(state, resultImages); + resultsAdapter.setMany(state, resultImages); state.page = page; state.pages = pages; @@ -107,7 +107,7 @@ const resultsSlice = createSlice({ }, }; - resultsAdapter.addOne(state, image); + resultsAdapter.setOne(state, image); } }); diff --git a/invokeai/frontend/web/src/features/gallery/store/uploadsPersistDenylist.ts b/invokeai/frontend/web/src/features/gallery/store/uploadsPersistDenylist.ts index ec4248e99c..6e2ac1c3aa 100644 --- a/invokeai/frontend/web/src/features/gallery/store/uploadsPersistDenylist.ts +++ b/invokeai/frontend/web/src/features/gallery/store/uploadsPersistDenylist.ts @@ -5,7 +5,7 @@ import { UploadsState } from './uploadsSlice'; * * Currently denylisting uploads slice entirely, see persist config in store.ts */ -const itemsToDenylist: (keyof UploadsState)[] = []; +const itemsToDenylist: (keyof UploadsState)[] = ['isLoading']; export const uploadsDenylist = itemsToDenylist.map( (denylistItem) => `uploads.${denylistItem}` diff --git a/invokeai/frontend/web/src/features/gallery/store/uploadsSlice.ts b/invokeai/frontend/web/src/features/gallery/store/uploadsSlice.ts index e2d21d3afd..bb77844f42 100644 --- a/invokeai/frontend/web/src/features/gallery/store/uploadsSlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/uploadsSlice.ts @@ -1,7 +1,7 @@ import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'; -import { Image } from 'app/invokeai'; +import { Image } from 'app/types/invokeai'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { receivedUploadImagesPage, IMAGES_PER_PAGE, @@ -53,7 +53,7 @@ const uploadsSlice = createSlice({ const images = items.map((image) => deserializeImageResponse(image)); - uploadsAdapter.addMany(state, images); + uploadsAdapter.setMany(state, images); state.page = page; state.pages = pages; @@ -69,7 +69,7 @@ const uploadsSlice = createSlice({ const uploadedImage = deserializeImageResponse(response); - uploadsAdapter.addOne(state, uploadedImage); + uploadsAdapter.setOne(state, uploadedImage); }); /** diff --git a/invokeai/frontend/web/src/features/lightbox/components/Lightbox.tsx b/invokeai/frontend/web/src/features/lightbox/components/Lightbox.tsx index 9ca4196fa3..cd0ce55b1e 100644 --- a/invokeai/frontend/web/src/features/lightbox/components/Lightbox.tsx +++ b/invokeai/frontend/web/src/features/lightbox/components/Lightbox.tsx @@ -1,7 +1,7 @@ import { Box, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import CurrentImageButtons from 'features/gallery/components/CurrentImageButtons'; import ImageMetadataViewer from 'features/gallery/components/ImageMetaDataViewer/ImageMetadataViewer'; @@ -10,7 +10,7 @@ import { gallerySelector } from 'features/gallery/store/gallerySelectors'; import { setIsLightboxOpen } from 'features/lightbox/store/lightboxSlice'; import { uiSelector } from 'features/ui/store/uiSelectors'; import { AnimatePresence, motion } from 'framer-motion'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useHotkeys } from 'react-hotkeys-hook'; import { BiExit } from 'react-icons/bi'; import { TransformWrapper } from 'react-zoom-pan-pinch'; diff --git a/invokeai/frontend/web/src/features/lightbox/components/ReactPanZoomImage.tsx b/invokeai/frontend/web/src/features/lightbox/components/ReactPanZoomImage.tsx index 660b07d75f..1eea014dfd 100644 --- a/invokeai/frontend/web/src/features/lightbox/components/ReactPanZoomImage.tsx +++ b/invokeai/frontend/web/src/features/lightbox/components/ReactPanZoomImage.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { TransformComponent, useTransformContext } from 'react-zoom-pan-pinch'; -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import { useGetUrl } from 'common/util/getUrl'; type ReactPanZoomProps = { diff --git a/invokeai/frontend/web/src/features/lightbox/store/lightboxSelectors.ts b/invokeai/frontend/web/src/features/lightbox/store/lightboxSelectors.ts index 10ee245866..f7d7e0129a 100644 --- a/invokeai/frontend/web/src/features/lightbox/store/lightboxSelectors.ts +++ b/invokeai/frontend/web/src/features/lightbox/store/lightboxSelectors.ts @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { isEqual } from 'lodash'; +import { RootState } from 'app/store/store'; +import { isEqual } from 'lodash-es'; export const lightboxSelector = createSelector( (state: RootState) => state.lightbox, diff --git a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx index 5acd0c0530..3265a2620f 100644 --- a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx @@ -11,15 +11,15 @@ import { IconButton, } from '@chakra-ui/react'; import { FaEllipsisV, FaPlus } from 'react-icons/fa'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { nodeAdded } from '../store/nodesSlice'; -import { cloneDeep, map } from 'lodash'; -import { RootState } from 'app/store'; +import { cloneDeep, map } from 'lodash-es'; +import { RootState } from 'app/store/store'; import { useBuildInvocation } from '../hooks/useBuildInvocation'; import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/hooks/useToastWatcher'; -import { IAIIconButton } from 'exports'; import { AnyInvocationType } from 'services/events/types'; +import IAIIconButton from 'common/components/IAIIconButton'; const AddNodeMenu = () => { const dispatch = useAppDispatch(); diff --git a/invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx b/invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx index 1e86ebfd97..c14c7ebccf 100644 --- a/invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/FieldTypeLegend.tsx @@ -1,6 +1,6 @@ import 'reactflow/dist/style.css'; import { Tooltip, Badge, Flex } from '@chakra-ui/react'; -import { map } from 'lodash'; +import { map } from 'lodash-es'; import { FIELDS } from '../types/constants'; import { memo } from 'react'; diff --git a/invokeai/frontend/web/src/features/nodes/components/Flow.tsx b/invokeai/frontend/web/src/features/nodes/components/Flow.tsx index 5c433ad488..4554f334c2 100644 --- a/invokeai/frontend/web/src/features/nodes/components/Flow.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/Flow.tsx @@ -7,8 +7,8 @@ import { OnConnectStart, OnConnectEnd, } from 'reactflow'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { RootState } from 'app/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { RootState } from 'app/store/store'; import { connectionEnded, connectionMade, diff --git a/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeInputs.tsx b/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeInputs.tsx index 6d47cad919..9ea383c09d 100644 --- a/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeInputs.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeInputs.tsx @@ -4,9 +4,9 @@ import { InvocationTemplate, } from 'features/nodes/types/types'; import { memo, ReactNode, useCallback } from 'react'; -import { map } from 'lodash'; -import { useAppSelector } from 'app/storeHooks'; -import { RootState } from 'app/store'; +import { map } from 'lodash-es'; +import { useAppSelector } from 'app/store/storeHooks'; +import { RootState } from 'app/store/store'; import { Box, Flex, diff --git a/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeOutputs.tsx b/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeOutputs.tsx index 38a3a169b8..2cb0bcde8d 100644 --- a/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeOutputs.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeOutputs.tsx @@ -4,9 +4,9 @@ import { OutputFieldValue, } from 'features/nodes/types/types'; import { memo, ReactNode, useCallback } from 'react'; -import { map } from 'lodash'; -import { useAppSelector } from 'app/storeHooks'; -import { RootState } from 'app/store'; +import { map } from 'lodash-es'; +import { useAppSelector } from 'app/store/storeHooks'; +import { RootState } from 'app/store/store'; import { Box, Flex, FormControl, FormLabel, HStack } from '@chakra-ui/react'; import FieldHandle from '../FieldHandle'; import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection'; diff --git a/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx index e6d54a72c5..909fd4b556 100644 --- a/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx @@ -8,10 +8,10 @@ import IAINodeOutputs from './IAINode/IAINodeOutputs'; import IAINodeInputs from './IAINode/IAINodeInputs'; import IAINodeHeader from './IAINode/IAINodeHeader'; import IAINodeResizer from './IAINode/IAINodeResizer'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { AnyInvocationType } from 'services/events/types'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { NODE_MIN_WIDTH } from 'app/constants'; type InvocationComponentWrapperProps = PropsWithChildren & { diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx b/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx index 88a125e542..90c8e1396f 100644 --- a/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/NodeGraphOverlay.tsx @@ -1,6 +1,6 @@ import { Box } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { memo } from 'react'; import { buildNodesGraph } from '../util/nodesGraphBuilder/buildNodesGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx b/invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx index 249e8d4c78..5f688722de 100644 --- a/invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/ViewportControls.tsx @@ -1,6 +1,6 @@ import { ButtonGroup } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { IAIIconButton } from 'exports'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIIconButton from 'common/components/IAIIconButton'; import { memo, useCallback } from 'react'; import { FaCode, FaExpand, FaMinus, FaPlus } from 'react-icons/fa'; import { useReactFlow } from 'reactflow'; diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/BooleanInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/BooleanInputFieldComponent.tsx index ceb2364e46..52a60253ba 100644 --- a/invokeai/frontend/web/src/features/nodes/components/fields/BooleanInputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/fields/BooleanInputFieldComponent.tsx @@ -1,5 +1,5 @@ import { Switch } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { fieldValueChanged } from 'features/nodes/store/nodesSlice'; import { BooleanInputFieldTemplate, diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/EnumInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/EnumInputFieldComponent.tsx index 15602e7cad..5f26bc4f2a 100644 --- a/invokeai/frontend/web/src/features/nodes/components/fields/EnumInputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/fields/EnumInputFieldComponent.tsx @@ -1,5 +1,5 @@ import { Select } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { fieldValueChanged } from 'features/nodes/store/nodesSlice'; import { EnumInputFieldTemplate, diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/ImageInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/ImageInputFieldComponent.tsx index 1dc0296139..74967c20d8 100644 --- a/invokeai/frontend/web/src/features/nodes/components/fields/ImageInputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/fields/ImageInputFieldComponent.tsx @@ -1,5 +1,5 @@ import { Box, Image, Icon, Flex } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import SelectImagePlaceholder from 'common/components/SelectImagePlaceholder'; import { useGetUrl } from 'common/util/getUrl'; import useGetImageByNameAndType from 'features/gallery/hooks/useGetImageByName'; diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/ModelInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/ModelInputFieldComponent.tsx index 14f2816e1c..3ce790171a 100644 --- a/invokeai/frontend/web/src/features/nodes/components/fields/ModelInputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/fields/ModelInputFieldComponent.tsx @@ -1,7 +1,7 @@ import { Select } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { fieldValueChanged } from 'features/nodes/store/nodesSlice'; import { ModelInputFieldTemplate, @@ -11,7 +11,7 @@ import { selectModelsById, selectModelsIds, } from 'features/system/store/modelSlice'; -import { isEqual, map } from 'lodash'; +import { isEqual, map } from 'lodash-es'; import { ChangeEvent, memo } from 'react'; import { FieldComponentProps } from './types'; diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/NumberInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/NumberInputFieldComponent.tsx index ad59667419..f5df8989f5 100644 --- a/invokeai/frontend/web/src/features/nodes/components/fields/NumberInputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/fields/NumberInputFieldComponent.tsx @@ -5,7 +5,7 @@ import { NumberInputField, NumberInputStepper, } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { fieldValueChanged } from 'features/nodes/store/nodesSlice'; import { FloatInputFieldTemplate, diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/StringInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/StringInputFieldComponent.tsx index f371e8e58d..58a201062b 100644 --- a/invokeai/frontend/web/src/features/nodes/components/fields/StringInputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/fields/StringInputFieldComponent.tsx @@ -1,5 +1,5 @@ import { Input } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { fieldValueChanged } from 'features/nodes/store/nodesSlice'; import { StringInputFieldTemplate, diff --git a/invokeai/frontend/web/src/features/nodes/components/panels/MinimapPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/panels/MinimapPanel.tsx index 33c5605310..2d76e2911f 100644 --- a/invokeai/frontend/web/src/features/nodes/components/panels/MinimapPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/panels/MinimapPanel.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { CSSProperties, memo } from 'react'; import { MiniMap } from 'reactflow'; diff --git a/invokeai/frontend/web/src/features/nodes/components/panels/TopCenterPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/panels/TopCenterPanel.tsx index 1d007e3657..4bb7abf982 100644 --- a/invokeai/frontend/web/src/features/nodes/components/panels/TopCenterPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/panels/TopCenterPanel.tsx @@ -1,5 +1,5 @@ import { HStack } from '@chakra-ui/react'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import { memo, useCallback } from 'react'; import { Panel } from 'reactflow'; diff --git a/invokeai/frontend/web/src/features/nodes/components/panels/TopRightPanel.tsx b/invokeai/frontend/web/src/features/nodes/components/panels/TopRightPanel.tsx index 7e51e3e00e..3fe8c49880 100644 --- a/invokeai/frontend/web/src/features/nodes/components/panels/TopRightPanel.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/panels/TopRightPanel.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { memo } from 'react'; import { Panel } from 'reactflow'; import FieldTypeLegend from '../FieldTypeLegend'; diff --git a/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx b/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx index c301a1a863..66b1d72014 100644 --- a/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx @@ -1,9 +1,9 @@ import { Box, Flex } from '@chakra-ui/layout'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIInput from 'common/components/IAIInput'; import { Panel } from 'reactflow'; -import { map } from 'lodash'; +import { map } from 'lodash-es'; import { ChangeEvent, FocusEvent, diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useBuildInvocation.ts b/invokeai/frontend/web/src/features/nodes/hooks/useBuildInvocation.ts index a44f703364..0526eee969 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useBuildInvocation.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useBuildInvocation.ts @@ -1,7 +1,7 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; -import { reduce } from 'lodash'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { reduce } from 'lodash-es'; import { useCallback } from 'react'; import { Node, useReactFlow } from 'reactflow'; import { AnyInvocationType } from 'services/events/types'; diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useIsValidConnection.ts b/invokeai/frontend/web/src/features/nodes/hooks/useIsValidConnection.ts index dec9120d08..a24267d9d9 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useIsValidConnection.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useIsValidConnection.ts @@ -14,77 +14,77 @@ export const useIsValidConnection = () => { return true; - // Connection must have valid targets - if (!(source && sourceHandle && target && targetHandle)) { - return false; - } + // // Connection must have valid targets + // if (!(source && sourceHandle && target && targetHandle)) { + // return false; + // } - // Connection is invalid if target already has a connection - if ( - edges.find((edge) => { - return edge.target === target && edge.targetHandle === targetHandle; - }) - ) { - return false; - } + // // Connection is invalid if target already has a connection + // if ( + // edges.find((edge) => { + // return edge.target === target && edge.targetHandle === targetHandle; + // }) + // ) { + // return false; + // } - // Find the source and target nodes - const sourceNode = flow.getNode(source) as Node; + // // Find the source and target nodes + // const sourceNode = flow.getNode(source) as Node; - const targetNode = flow.getNode(target) as Node; + // const targetNode = flow.getNode(target) as Node; - // Conditional guards against undefined nodes/handles - if (!(sourceNode && targetNode && sourceNode.data && targetNode.data)) { - return false; - } + // // Conditional guards against undefined nodes/handles + // if (!(sourceNode && targetNode && sourceNode.data && targetNode.data)) { + // return false; + // } - // Connection types must be the same for a connection - if ( - sourceNode.data.outputs[sourceHandle].type !== - targetNode.data.inputs[targetHandle].type - ) { - return false; - } + // // Connection types must be the same for a connection + // if ( + // sourceNode.data.outputs[sourceHandle].type !== + // targetNode.data.inputs[targetHandle].type + // ) { + // return false; + // } - // Graphs much be acyclic (no loops!) + // // Graphs much be acyclic (no loops!) - /** - * TODO: use `graphlib.alg.findCycles()` to identify strong connections - * - * this validation func only runs when the cursor hits the second handle of the connection, - * and only on that second handle - so it cannot tell us exhaustively which connections - * are valid. - * - * ideally, we check when the connection starts to calculate all invalid handles at once. - * - * requires making a new graphlib graph - and calling `findCycles()` - for each potential - * handle. instead of using the `isValidConnection` prop, it would use the `onConnectStart` - * prop. - * - * the strong connections should be stored in global state. - * - * then, `isValidConnection` would simple loop through the strong connections and if the - * source and target are in a single strong connection, return false. - * - * and also, we can use this knowledge to style every handle when a connection starts, - * which is otherwise not possible. - */ + // /** + // * TODO: use `graphlib.alg.findCycles()` to identify strong connections + // * + // * this validation func only runs when the cursor hits the second handle of the connection, + // * and only on that second handle - so it cannot tell us exhaustively which connections + // * are valid. + // * + // * ideally, we check when the connection starts to calculate all invalid handles at once. + // * + // * requires making a new graphlib graph - and calling `findCycles()` - for each potential + // * handle. instead of using the `isValidConnection` prop, it would use the `onConnectStart` + // * prop. + // * + // * the strong connections should be stored in global state. + // * + // * then, `isValidConnection` would simple loop through the strong connections and if the + // * source and target are in a single strong connection, return false. + // * + // * and also, we can use this knowledge to style every handle when a connection starts, + // * which is otherwise not possible. + // */ - // build a graphlib graph - const g = new graphlib.Graph(); + // // build a graphlib graph + // const g = new graphlib.Graph(); - nodes.forEach((n) => { - g.setNode(n.id); - }); + // nodes.forEach((n) => { + // g.setNode(n.id); + // }); - edges.forEach((e) => { - g.setEdge(e.source, e.target); - }); + // edges.forEach((e) => { + // g.setEdge(e.source, e.target); + // }); - // Add the candidate edge to the graph - g.setEdge(source, target); + // // Add the candidate edge to the graph + // g.setEdge(source, target); - return graphlib.alg.isAcyclic(g); + // return graphlib.alg.isAcyclic(g); }, [flow] ); diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index a886274489..d0202a5932 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -16,6 +16,8 @@ import { receivedOpenAPISchema } from 'services/thunks/schema'; import { isFulfilledAnyGraphBuilt } from 'services/thunks/session'; import { InvocationTemplate, InvocationValue } from '../types/types'; import { parseSchema } from '../util/parseSchema'; +import { log } from 'app/logging/useLogger'; +import { size } from 'lodash-es'; export type NodesState = { nodes: Node[]; @@ -82,10 +84,24 @@ const nodesSlice = createSlice({ shouldShowGraphOverlayChanged: (state, action: PayloadAction) => { state.shouldShowGraphOverlay = action.payload; }, + parsedOpenAPISchema: (state, action: PayloadAction) => { + try { + const parsedSchema = parseSchema(action.payload); + + // TODO: Achtung! Side effect in a reducer! + log.info( + { namespace: 'schema', nodes: parsedSchema }, + `Parsed ${size(parsedSchema)} nodes` + ); + state.invocationTemplates = parsedSchema; + } catch (err) { + console.error(err); + } + }, }, extraReducers(builder) { builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => { - state.invocationTemplates = action.payload; + state.schema = action.payload; }); builder.addMatcher(isFulfilledAnyGraphBuilt, (state, action) => { @@ -103,6 +119,7 @@ export const { connectionStarted, connectionEnded, shouldShowGraphOverlayChanged, + parsedOpenAPISchema, } = nodesSlice.actions; export default nodesSlice.reducer; diff --git a/invokeai/frontend/web/src/features/nodes/store/selectors/invocationTemplatesSelector.ts b/invokeai/frontend/web/src/features/nodes/store/selectors/invocationTemplatesSelector.ts index 0ffc4ac5bb..803cdbfb74 100644 --- a/invokeai/frontend/web/src/features/nodes/store/selectors/invocationTemplatesSelector.ts +++ b/invokeai/frontend/web/src/features/nodes/store/selectors/invocationTemplatesSelector.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; export const invocationTemplatesSelector = createSelector( (state: RootState) => state.nodes, diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts index e37f446e00..df895ba4af 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts @@ -1,4 +1,4 @@ -import { reduce } from 'lodash'; +import { reduce } from 'lodash-es'; import { OpenAPIV3 } from 'openapi-types'; import { FIELD_TYPE_MAP } from '../types/constants'; import { isSchemaObject } from '../types/typeGuards'; diff --git a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildImageToImageNode.ts b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildImageToImageNode.ts index f04f177d5b..f9213dfeae 100644 --- a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildImageToImageNode.ts +++ b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildImageToImageNode.ts @@ -1,11 +1,11 @@ import { v4 as uuidv4 } from 'uuid'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { Edge, ImageToImageInvocation, TextToImageInvocation, } from 'services/api'; -import { _Image } from 'app/invokeai'; +import { _Image } from 'app/types/invokeai'; import { initialImageSelector } from 'features/parameters/store/generationSelectors'; export const buildImg2ImgNode = (state: RootState): ImageToImageInvocation => { @@ -16,6 +16,7 @@ export const buildImg2ImgNode = (state: RootState): ImageToImageInvocation => { const { prompt, + negativePrompt, seed, steps, width, @@ -38,7 +39,7 @@ export const buildImg2ImgNode = (state: RootState): ImageToImageInvocation => { const imageToImageNode: ImageToImageInvocation = { id: nodeId, type: 'img2img', - prompt, + prompt: `${prompt} [${negativePrompt}]`, steps, width, height, diff --git a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildLinearGraph.ts index 9667dfa2b3..3e638c8239 100644 --- a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildLinearGraph.ts @@ -1,4 +1,4 @@ -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { Graph } from 'services/api'; import { buildImg2ImgNode } from './buildImageToImageNode'; import { buildTxt2ImgNode } from './buildTextToImageNode'; diff --git a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildRangeNode.ts b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildRangeNode.ts index 1f87ec785e..735c0ef726 100644 --- a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildRangeNode.ts +++ b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildRangeNode.ts @@ -1,6 +1,6 @@ import { v4 as uuidv4 } from 'uuid'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { RandomRangeInvocation, RangeInvocation } from 'services/api'; export const buildRangeNode = ( diff --git a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildTextToImageNode.ts b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildTextToImageNode.ts index 057d35dbcb..08952bcfb1 100644 --- a/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildTextToImageNode.ts +++ b/invokeai/frontend/web/src/features/nodes/util/linearGraphBuilder/buildTextToImageNode.ts @@ -1,5 +1,5 @@ import { v4 as uuidv4 } from 'uuid'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; import { TextToImageInvocation } from 'services/api'; export const buildTxt2ImgNode = (state: RootState): TextToImageInvocation => { @@ -10,6 +10,7 @@ export const buildTxt2ImgNode = (state: RootState): TextToImageInvocation => { const { prompt, + negativePrompt, seed, steps, width, @@ -23,7 +24,7 @@ export const buildTxt2ImgNode = (state: RootState): TextToImageInvocation => { const textToImageNode: NonNullable = { id: nodeId, type: 'txt2img', - prompt, + prompt: `${prompt} [${negativePrompt}]`, steps, width, height, diff --git a/invokeai/frontend/web/src/features/nodes/util/nodesGraphBuilder/buildNodesGraph.ts b/invokeai/frontend/web/src/features/nodes/util/nodesGraphBuilder/buildNodesGraph.ts index 848615277d..f12b141e09 100644 --- a/invokeai/frontend/web/src/features/nodes/util/nodesGraphBuilder/buildNodesGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/nodesGraphBuilder/buildNodesGraph.ts @@ -1,7 +1,7 @@ import { Graph } from 'services/api'; import { v4 as uuidv4 } from 'uuid'; -import { reduce } from 'lodash'; -import { RootState } from 'app/store'; +import { reduce } from 'lodash-es'; +import { RootState } from 'app/store/store'; import { AnyInvocation } from 'services/events/types'; /** diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index ffdf4710b5..7cb8132b65 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -1,4 +1,4 @@ -import { filter, reduce } from 'lodash'; +import { filter, reduce } from 'lodash-es'; import { OpenAPIV3 } from 'openapi-types'; import { isSchemaObject } from '../types/typeGuards'; import { diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/BoundingBox/BoundingBoxSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/BoundingBox/BoundingBoxSettings.tsx index 67740cbc02..35a325e74e 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/BoundingBox/BoundingBoxSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/BoundingBox/BoundingBoxSettings.tsx @@ -1,10 +1,10 @@ import { Box, VStack } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/InfillAndScalingSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/InfillAndScalingSettings.tsx index 866038c993..c18934e22b 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/InfillAndScalingSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/InfillAndScalingSettings.tsx @@ -1,6 +1,6 @@ import { VStack } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISelect from 'common/components/IAISelect'; import IAISlider from 'common/components/IAISlider'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; @@ -18,7 +18,7 @@ import { setTileSize, } from 'features/parameters/store/generationSlice'; import { systemSelector } from 'features/system/store/systemSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { ChangeEvent } from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamBlur.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamBlur.tsx index 1f5237615a..693313e606 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamBlur.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamBlur.tsx @@ -1,5 +1,5 @@ -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +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 { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSize.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSize.tsx index 25d14e5eac..02403ac5ec 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSize.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSize.tsx @@ -1,5 +1,5 @@ -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +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 { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSteps.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSteps.tsx index ff58ff6837..0319b26820 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSteps.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamSteps.tsx @@ -1,5 +1,5 @@ -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +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 { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamStrength.tsx index 0fa37b69b0..7d447cfda1 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Canvas/SeamCorrection/SeamStrength.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { 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 { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/CodeformerFidelity.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/CodeformerFidelity.tsx index 5558c39da7..f154477932 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/CodeformerFidelity.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/CodeformerFidelity.tsx @@ -1,5 +1,5 @@ -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import type { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setCodeformerFidelity } from 'features/parameters/store/postprocessingSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings.tsx index 357e6cbcc9..f4d5ca07bc 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings.tsx @@ -1,6 +1,6 @@ import { VStack } from '@chakra-ui/react'; -import { useAppSelector } from 'app/storeHooks'; -import type { RootState } from 'app/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import type { RootState } from 'app/store/store'; import FaceRestoreType from './FaceRestoreType'; import FaceRestoreStrength from './FaceRestoreStrength'; import CodeformerFidelity from './CodeformerFidelity'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreStrength.tsx index 4bc730e085..eeb5417c6e 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreStrength.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setFacetoolStrength } from 'features/parameters/store/postprocessingSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle.tsx index 2514eac8b0..a314c0ad73 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setShouldRunFacetool } from 'features/parameters/store/postprocessingSlice'; import { ChangeEvent } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreType.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreType.tsx index 85231c381f..aa4231eb4b 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreType.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreType.tsx @@ -1,6 +1,6 @@ import { FACETOOL_TYPES } from 'app/constants'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISelect from 'common/components/IAISelect'; import { FacetoolType, diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageFit.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageFit.tsx index f127afeda3..f479def1ab 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageFit.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageFit.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setShouldFitToWidthHeight } from 'features/parameters/store/generationSlice'; import { ChangeEvent } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings.tsx index 95d6272408..71b853f162 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings.tsx @@ -29,7 +29,7 @@ export default function ImageToImageSettings() { - + ); diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength.tsx index 18f5caf652..284aa9a5c0 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { generationSelector } from 'features/parameters/store/generationSelectors'; import { setImg2imgStrength } from 'features/parameters/store/generationSlice'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageToggle.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageToggle.tsx index 07d100be96..89da0ae8b0 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageToggle.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageToggle.tsx @@ -1,6 +1,6 @@ import { Flex } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { isImageToImageEnabledChanged } from 'features/parameters/store/generationSlice'; import { ChangeEvent } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview.tsx index 19eae13ca6..9682d2eb0b 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/ImageToImage/InitialImagePreview.tsx @@ -1,30 +1,27 @@ import { Box, Flex, Image, Spinner, Text } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import SelectImagePlaceholder from 'common/components/SelectImagePlaceholder'; import { useGetUrl } from 'common/util/getUrl'; import useGetImageByNameAndType from 'features/gallery/hooks/useGetImageByName'; -import { selectResultsById } from 'features/gallery/store/resultsSlice'; import { clearInitialImage, initialImageSelected, } from 'features/parameters/store/generationSlice'; import { addToast } from 'features/system/store/systemSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { DragEvent, useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ImageType } from 'services/api'; import ImageToImageOverlay from 'common/components/ImageToImageOverlay'; +import { initialImageSelector } from 'features/parameters/store/generationSelectors'; -const initialImagePreviewSelector = createSelector( - [(state: RootState) => state], - (state) => { - const { initialImage } = state.generation; - const image = selectResultsById(state, initialImage as string); - +const selector = createSelector( + [initialImageSelector], + (initialImage) => { return { - initialImage: image, + initialImage, }; }, { memoizeOptions: { resultEqualityCheck: isEqual } } @@ -34,7 +31,7 @@ const InitialImagePreview = () => { const isImageToImageEnabled = useAppSelector( (state: RootState) => state.generation.isImageToImageEnabled ); - const { initialImage } = useAppSelector(initialImagePreviewSelector); + const { initialImage } = useAppSelector(selector); const { getUrl } = useGetUrl(); const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -71,7 +68,7 @@ const InitialImagePreview = () => { return; } - dispatch(initialImageSelected(image.name)); + dispatch(initialImageSelected({ name, type })); }, [getImageByNameAndType, dispatch] ); @@ -116,12 +113,7 @@ const InitialImagePreview = () => { } /> - {isLoaded && ( - - )} + {isLoaded && } )} {!initialImage?.url && } diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/HiresSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/HiresSettings.tsx index 172acaab68..7f20a1d6c3 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/HiresSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/HiresSettings.tsx @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import type { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import IAISwitch from 'common/components/IAISwitch'; import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors'; @@ -8,7 +8,7 @@ import { setHiresFix, setHiresStrength, } from 'features/parameters/store/postprocessingSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { ChangeEvent } from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SeamlessSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SeamlessSettings.tsx index ddd6a4b24b..fb333c6f00 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SeamlessSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SeamlessSettings.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setSeamless } from 'features/parameters/store/generationSlice'; import { ChangeEvent } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetrySettings.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetrySettings.tsx index e23385d0bc..21e014b715 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetrySettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetrySettings.tsx @@ -1,6 +1,6 @@ import { VStack } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setHorizontalSymmetrySteps, diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetryToggle.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetryToggle.tsx index 9446271a0e..c155336c1e 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetryToggle.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Output/SymmetryToggle.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setShouldUseSymmetry } from 'features/parameters/store/generationSlice'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Perlin.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Perlin.tsx index c340acac32..d2f4ea4249 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Perlin.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Perlin.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setPerlin } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/RandomizeSeed.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/RandomizeSeed.tsx index 576ac61aba..ea60124f74 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/RandomizeSeed.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/RandomizeSeed.tsx @@ -1,7 +1,7 @@ import { ChangeEvent, memo } from 'react'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setShouldRandomizeSeed } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Seed.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Seed.tsx index 7aac200b26..96c929a462 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Seed.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Seed.tsx @@ -1,7 +1,7 @@ import { HStack } from '@chakra-ui/react'; import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAINumberInput from 'common/components/IAINumberInput'; import { setSeed } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/ShuffleSeed.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/ShuffleSeed.tsx index 675640050b..f2d222de7c 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/ShuffleSeed.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/ShuffleSeed.tsx @@ -1,9 +1,9 @@ import { Button } from '@chakra-ui/react'; import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import IAIIconButton from 'common/components/IAIIconButton'; import randomInt from 'common/util/randomInt'; -import { IAIIconButton } from 'exports'; import { setSeed } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; import { FaRandom } from 'react-icons/fa'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Threshold.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Threshold.tsx index dbcf201d04..14ca46b53c 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Threshold.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Seed/Threshold.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setThreshold } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleDenoisingStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleDenoisingStrength.tsx index 0cb5a12524..7abcd55c03 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleDenoisingStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleDenoisingStrength.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setUpscalingDenoising } from 'features/parameters/store/postprocessingSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleScale.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleScale.tsx index 9bbc7f4b65..180b90f021 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleScale.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleScale.tsx @@ -1,6 +1,6 @@ import { UPSCALING_LEVELS } from 'app/constants'; -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import type { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISelect from 'common/components/IAISelect'; import { setUpscalingLevel, diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleStrength.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleStrength.tsx index 819c4fda57..68f61cf1e0 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleStrength.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleStrength.tsx @@ -1,5 +1,5 @@ -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import type { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setUpscalingStrength } from 'features/parameters/store/postprocessingSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleToggle.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleToggle.tsx index bcd4c0d8b2..172a9f2de9 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleToggle.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Upscale/UpscaleToggle.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setShouldRunESRGAN } from 'features/parameters/store/postprocessingSlice'; import { ChangeEvent } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/GenerateVariations.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/GenerateVariations.tsx index 90c872d4a7..ec9a8ae276 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/GenerateVariations.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/GenerateVariations.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISwitch from 'common/components/IAISwitch'; import { setShouldGenerateVariations } from 'features/parameters/store/generationSlice'; import { ChangeEvent } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/SeedWeights.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/SeedWeights.tsx index 01fddf157f..7f8b096757 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/SeedWeights.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/SeedWeights.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIInput from 'common/components/IAIInput'; import { validateSeedWeights } from 'common/util/seedWeightPairs'; import { setSeedWeights } from 'features/parameters/store/generationSlice'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/VariationAmount.tsx b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/VariationAmount.tsx index 27a39757f9..21b5001d6a 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/VariationAmount.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AdvancedParameters/Variations/VariationAmount.tsx @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setVariationAmount } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/AnimatedImageToImagePanel.tsx b/invokeai/frontend/web/src/features/parameters/components/AnimatedImageToImagePanel.tsx index d1e07220ae..da9262ac0f 100644 --- a/invokeai/frontend/web/src/features/parameters/components/AnimatedImageToImagePanel.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/AnimatedImageToImagePanel.tsx @@ -2,8 +2,8 @@ import { memo, useState } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import ImageToImageSettings from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageSettings'; -import { useAppSelector } from 'app/storeHooks'; -import { RootState } from 'app/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { RootState } from 'app/store/store'; import { Box } from '@chakra-ui/react'; const AnimatedImageToImagePanel = () => { @@ -15,9 +15,9 @@ const AnimatedImageToImagePanel = () => { {isImageToImageEnabled && ( diff --git a/invokeai/frontend/web/src/features/parameters/components/ImageDimensions/DimensionsSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/ImageDimensions/DimensionsSettings.tsx index b6b1e206b6..a187eecd83 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ImageDimensions/DimensionsSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ImageDimensions/DimensionsSettings.tsx @@ -1,7 +1,7 @@ import { Box, Flex, FormControl, FormLabel, Select } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { setWidth } from 'features/parameters/store/generationSlice'; import { memo, useState } from 'react'; diff --git a/invokeai/frontend/web/src/features/parameters/components/MainParameters/HeightSlider.tsx b/invokeai/frontend/web/src/features/parameters/components/MainParameters/HeightSlider.tsx index ac9a483d21..35e97fb266 100644 --- a/invokeai/frontend/web/src/features/parameters/components/MainParameters/HeightSlider.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/MainParameters/HeightSlider.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { generationSelector } from 'features/parameters/store/generationSelectors'; import { setHeight } from 'features/parameters/store/generationSlice'; @@ -13,17 +13,35 @@ const selector = createSelector( (generation, hotkeys, config) => { const { initial, min, sliderMax, inputMax, fineStep, coarseStep } = config.sd.height; - const { height } = generation; + const { height, shouldFitToWidthHeight, isImageToImageEnabled } = + generation; const step = hotkeys.shift ? fineStep : coarseStep; - return { height, initial, min, sliderMax, inputMax, step }; + return { + height, + initial, + min, + sliderMax, + inputMax, + step, + shouldFitToWidthHeight, + isImageToImageEnabled, + }; } ); const HeightSlider = () => { - const { height, initial, min, sliderMax, inputMax, step } = - useAppSelector(selector); + const { + height, + initial, + min, + sliderMax, + inputMax, + step, + shouldFitToWidthHeight, + isImageToImageEnabled, + } = useAppSelector(selector); const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -40,6 +58,7 @@ const HeightSlider = () => { return ( { label={t('parameters.sampler')} value={sampler} onChange={handleChange} - validValues={DIFFUSERS_SAMPLERS} + validValues={DIFFUSERS_SCHEDULERS} minWidth={36} /> ); diff --git a/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSettings.tsx b/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSettings.tsx index dbd95a196b..db2701e0c9 100644 --- a/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSettings.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSettings.tsx @@ -1,7 +1,7 @@ import { Box, Flex, VStack } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; -import { ModelSelect } from 'exports'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import ModelSelect from 'features/system/components/ModelSelect'; import { memo } from 'react'; import HeightSlider from './HeightSlider'; import MainCFGScale from './MainCFGScale'; diff --git a/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSteps.tsx b/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSteps.tsx index 9a68e14ad3..43e399848e 100644 --- a/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSteps.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainSteps.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAINumberInput from 'common/components/IAINumberInput'; import IAISlider from 'common/components/IAISlider'; diff --git a/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainWidth.tsx b/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainWidth.tsx index 81942b83f9..7a8534147c 100644 --- a/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainWidth.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/MainParameters/MainWidth.tsx @@ -1,6 +1,6 @@ import { WIDTHS } from 'app/constants'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISelect from 'common/components/IAISelect'; import IAISlider from 'common/components/IAISlider'; import { setWidth } from 'features/parameters/store/generationSlice'; diff --git a/invokeai/frontend/web/src/features/parameters/components/MainParameters/WidthSlider.tsx b/invokeai/frontend/web/src/features/parameters/components/MainParameters/WidthSlider.tsx index 9c2c2d571e..0b871245c7 100644 --- a/invokeai/frontend/web/src/features/parameters/components/MainParameters/WidthSlider.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/MainParameters/WidthSlider.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISlider from 'common/components/IAISlider'; import { generationSelector } from 'features/parameters/store/generationSelectors'; import { setWidth } from 'features/parameters/store/generationSlice'; @@ -13,17 +13,34 @@ const selector = createSelector( (generation, hotkeys, config) => { const { initial, min, sliderMax, inputMax, fineStep, coarseStep } = config.sd.width; - const { width } = generation; + const { width, shouldFitToWidthHeight, isImageToImageEnabled } = generation; const step = hotkeys.shift ? fineStep : coarseStep; - return { width, initial, min, sliderMax, inputMax, step }; + return { + width, + initial, + min, + sliderMax, + inputMax, + step, + shouldFitToWidthHeight, + isImageToImageEnabled, + }; } ); const WidthSlider = () => { - const { width, initial, min, sliderMax, inputMax, step } = - useAppSelector(selector); + const { + width, + initial, + min, + sliderMax, + inputMax, + step, + shouldFitToWidthHeight, + isImageToImageEnabled, + } = useAppSelector(selector); const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -40,6 +57,7 @@ const WidthSlider = () => { return ( { const newCancelType = Array.isArray(value) ? value[0] : value; - dispatch(cancelTypeChanged(newCancelType as CancelType)); + dispatch(cancelTypeChanged(newCancelType as CancelStrategy)); }, [dispatch] ); - // const isCancelScheduled = cancelAfter === null ? false : true; useHotkeys( 'shift+x', @@ -117,23 +102,6 @@ const CancelButton = ( [isConnected, isProcessing, isCancelable] ); - // useEffect(() => { - // if (cancelAfter !== null && cancelAfter < currentIteration) { - // handleClickCancel(); - // } - // }, [cancelAfter, currentIteration, handleClickCancel]); - - // const cancelMenuItems = [ - // { - // item: t('parameters.cancel.immediate'), - // onClick: () => dispatch(cancelTypeChanged('immediate')), - // }, - // { - // item: t('parameters.cancel.schedule'), - // onClick: () => dispatch(cancelTypeChanged('scheduled')), - // }, - // ]; - return ( {cancelType === 'immediate' ? ( @@ -170,7 +138,7 @@ const CancelButton = ( } diff --git a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx index ab1953dcc6..d2002eb04f 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/InvokeButton.tsx @@ -1,17 +1,17 @@ import { Box } from '@chakra-ui/react'; import { readinessSelector } from 'app/selectors/readinessSelector'; -import { generateImage } from 'app/socketio/actions'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton, { IAIButtonProps } from 'common/components/IAIButton'; import IAIIconButton, { IAIIconButtonProps, } from 'common/components/IAIIconButton'; import { clampSymmetrySteps } from 'features/parameters/store/generationSlice'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; +import { useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { FaPlay } from 'react-icons/fa'; -import { generateGraphBuilt, sessionCreated } from 'services/thunks/session'; +import { generateGraphBuilt } from 'services/thunks/session'; interface InvokeButton extends Omit { @@ -24,19 +24,16 @@ export default function InvokeButton(props: InvokeButton) { const { isReady } = useAppSelector(readinessSelector); const activeTabName = useAppSelector(activeTabNameSelector); - const handleClickGenerate = () => { - // dispatch(generateImage(activeTabName)); + const handleInvoke = useCallback(() => { + dispatch(clampSymmetrySteps()); dispatch(generateGraphBuilt()); - }; + }, [dispatch]); const { t } = useTranslation(); useHotkeys( ['ctrl+enter', 'meta+enter'], - () => { - dispatch(clampSymmetrySteps()); - dispatch(generateImage(activeTabName)); - }, + handleInvoke, { enabled: () => isReady, preventDefault: true, @@ -53,7 +50,7 @@ export default function InvokeButton(props: InvokeButton) { type="submit" icon={} isDisabled={!isReady} - onClick={handleClickGenerate} + onClick={handleInvoke} flexGrow={1} w="100%" tooltip={t('parameters.invoke')} @@ -66,7 +63,7 @@ export default function InvokeButton(props: InvokeButton) { aria-label={t('parameters.invoke')} type="submit" isDisabled={!isReady} - onClick={handleClickGenerate} + onClick={handleInvoke} flexGrow={1} w="100%" colorScheme="accent" diff --git a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/Loopback.tsx b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/Loopback.tsx index 09cc991653..3bd405d1ce 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/Loopback.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/Loopback.tsx @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors'; import { setShouldLoopback } from 'features/parameters/store/postprocessingSlice'; 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 e4b3798548..ba8522f0bf 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ProcessButtons/ProcessButtons.tsx @@ -1,5 +1,5 @@ import { Flex } from '@chakra-ui/react'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import CancelButton from './CancelButton'; import InvokeButton from './InvokeButton'; @@ -14,7 +14,7 @@ const ProcessButtons = () => { return ( - {activeTabName === 'img2img' && } + {/* {activeTabName === 'img2img' && } */} ); diff --git a/invokeai/frontend/web/src/features/parameters/components/ProgressImage.tsx b/invokeai/frontend/web/src/features/parameters/components/ProgressImage.tsx new file mode 100644 index 0000000000..869f4dbc63 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/ProgressImage.tsx @@ -0,0 +1,67 @@ +import { Flex, Icon, Image } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { useAppSelector } from 'app/store/storeHooks'; +import { systemSelector } from 'features/system/store/systemSelectors'; +import { isEqual } from 'lodash-es'; +import { memo } from 'react'; +import { FaImage } from 'react-icons/fa'; + +const selector = createSelector( + [systemSelector], + (system) => { + const { progressImage } = system; + + return { + progressImage, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +const ProgressImage = () => { + const { progressImage } = useAppSelector(selector); + return progressImage ? ( + + + + ) : ( + + + + ); +}; + +export default memo(ProgressImage); diff --git a/invokeai/frontend/web/src/features/parameters/components/ProgressImagePreview.tsx b/invokeai/frontend/web/src/features/parameters/components/ProgressImagePreview.tsx new file mode 100644 index 0000000000..c31215a13e --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/ProgressImagePreview.tsx @@ -0,0 +1,160 @@ +import { Flex, Text } from '@chakra-ui/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { systemSelector } from 'features/system/store/systemSelectors'; +import { memo } from 'react'; +import { FaStopwatch } from 'react-icons/fa'; +import { uiSelector } from 'features/ui/store/uiSelectors'; +import IAIIconButton from 'common/components/IAIIconButton'; +import { CloseIcon } from '@chakra-ui/icons'; +import { useTranslation } from 'react-i18next'; +import { + floatingProgressImageMoved, + floatingProgressImageResized, + setShouldShowProgressImages, +} from 'features/ui/store/uiSlice'; +import { Rnd } from 'react-rnd'; +import { Rect } from 'features/ui/store/uiTypes'; +import { isEqual } from 'lodash'; +import ProgressImage from './ProgressImage'; + +const selector = createSelector( + [systemSelector, uiSelector], + (system, ui) => { + const { isProcessing } = system; + const { + floatingProgressImageRect, + shouldShowProgressImages, + shouldAutoShowProgressImages, + } = ui; + + const showProgressWindow = + shouldAutoShowProgressImages && isProcessing + ? true + : shouldShowProgressImages; + + return { + floatingProgressImageRect, + showProgressWindow, + }; + }, + { + memoizeOptions: { + resultEqualityCheck: isEqual, + }, + } +); + +const ProgressImagePreview = () => { + const dispatch = useAppDispatch(); + + const { showProgressWindow, floatingProgressImageRect } = + useAppSelector(selector); + + const { t } = useTranslation(); + + return ( + <> + {' '} + + dispatch(setShouldShowProgressImages(!showProgressWindow)) + } + tooltip={t('ui.showProgressImages')} + isChecked={showProgressWindow} + sx={{ + position: 'absolute', + bottom: 4, + insetInlineStart: 4, + }} + aria-label={t('ui.showProgressImages')} + icon={} + /> + {showProgressWindow && ( + { + dispatch(floatingProgressImageMoved({ x: d.x, y: d.y })); + }} + onResizeStop={(e, direction, ref, delta, position) => { + const newRect: Partial = {}; + + if (ref.style.width) { + newRect.width = ref.style.width; + } + if (ref.style.height) { + newRect.height = ref.style.height; + } + if (position.x) { + newRect.x = position.x; + } + if (position.x) { + newRect.y = position.y; + } + + dispatch(floatingProgressImageResized(newRect)); + }} + > + + + + + Progress Images + + + dispatch(setShouldShowProgressImages(false))} + aria-label={t('ui.hideProgressImages')} + size="xs" + icon={} + variant="ghost" + /> + + + + + )} + + ); +}; + +export default memo(ProgressImagePreview); diff --git a/invokeai/frontend/web/src/features/parameters/components/PromptInput/NegativePromptInput.tsx b/invokeai/frontend/web/src/features/parameters/components/PromptInput/NegativePromptInput.tsx index da22fa5594..ea3f12db42 100644 --- a/invokeai/frontend/web/src/features/parameters/components/PromptInput/NegativePromptInput.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/PromptInput/NegativePromptInput.tsx @@ -1,6 +1,6 @@ import { FormControl, Textarea } from '@chakra-ui/react'; -import type { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import type { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { setNegativePrompt } from 'features/parameters/store/generationSlice'; import { useTranslation } from 'react-i18next'; diff --git a/invokeai/frontend/web/src/features/parameters/components/PromptInput/PromptInput.tsx b/invokeai/frontend/web/src/features/parameters/components/PromptInput/PromptInput.tsx index 69efddf106..b54106733c 100644 --- a/invokeai/frontend/web/src/features/parameters/components/PromptInput/PromptInput.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/PromptInput/PromptInput.tsx @@ -1,20 +1,21 @@ import { Box, FormControl, Textarea } from '@chakra-ui/react'; -import { generateImage } from 'app/socketio/actions'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { ChangeEvent, KeyboardEvent, useRef } from 'react'; import { createSelector } from '@reduxjs/toolkit'; import { readinessSelector } from 'app/selectors/readinessSelector'; import { GenerationState, + clampSymmetrySteps, setPrompt, } from 'features/parameters/store/generationSlice'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; +import { generateGraphBuilt } from 'services/thunks/session'; const promptInputSelector = createSelector( [(state: RootState) => state.generation, activeTabNameSelector], @@ -36,7 +37,7 @@ const promptInputSelector = createSelector( */ const PromptInput = () => { const dispatch = useAppDispatch(); - const { prompt, activeTabName } = useAppSelector(promptInputSelector); + const { prompt } = useAppSelector(promptInputSelector); const { isReady } = useAppSelector(readinessSelector); const promptRef = useRef(null); @@ -58,7 +59,8 @@ const PromptInput = () => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Enter' && e.shiftKey === false && isReady) { e.preventDefault(); - dispatch(generateImage(activeTabName)); + dispatch(clampSymmetrySteps()); + dispatch(generateGraphBuilt()); } }; diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts b/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts new file mode 100644 index 0000000000..7c45f159b2 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts @@ -0,0 +1,129 @@ +import { UseToastOptions, useToast } from '@chakra-ui/react'; +import { useAppDispatch } from 'app/store/storeHooks'; +import { isFinite, isString } from 'lodash-es'; +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import useSetBothPrompts from './usePrompt'; +import { initialImageSelected, setSeed } from '../store/generationSlice'; +import { isImage, isImageField } from 'services/types/guards'; +import { NUMPY_RAND_MAX } from 'app/constants'; + +export const useParameters = () => { + const dispatch = useAppDispatch(); + const toast = useToast(); + const { t } = useTranslation(); + const setBothPrompts = useSetBothPrompts(); + + /** + * Sets prompt with toast + */ + const recallPrompt = useCallback( + (prompt: unknown) => { + if (!isString(prompt)) { + toast({ + title: t('toast.promptNotSet'), + description: t('toast.promptNotSetDesc'), + status: 'warning', + duration: 2500, + isClosable: true, + }); + return; + } + + setBothPrompts(prompt); + toast({ + title: t('toast.promptSet'), + status: 'info', + duration: 2500, + isClosable: true, + }); + }, + [t, toast, setBothPrompts] + ); + + /** + * Sets seed with toast + */ + const recallSeed = useCallback( + (seed: unknown) => { + const s = Number(seed); + if (!isFinite(s) || (isFinite(s) && !(s >= 0 && s <= NUMPY_RAND_MAX))) { + toast({ + title: t('toast.seedNotSet'), + description: t('toast.seedNotSetDesc'), + status: 'warning', + duration: 2500, + isClosable: true, + }); + return; + } + + dispatch(setSeed(s)); + toast({ + title: t('toast.seedSet'), + status: 'info', + duration: 2500, + isClosable: true, + }); + }, + [t, toast, dispatch] + ); + + /** + * Sets initial image with toast + */ + const recallInitialImage = useCallback( + async (image: unknown) => { + if (!isImageField(image)) { + toast({ + title: t('toast.initialImageNotSet'), + description: t('toast.initialImageNotSetDesc'), + status: 'warning', + duration: 2500, + isClosable: true, + }); + return; + } + + dispatch( + initialImageSelected({ name: image.image_name, type: image.image_type }) + ); + toast({ + title: t('toast.initialImageSet'), + status: 'info', + duration: 2500, + isClosable: true, + }); + }, + [t, toast, dispatch] + ); + + /** + * Sets image as initial image with toast + */ + const sendToImageToImage = useCallback( + (image: unknown) => { + if (!isImage(image)) { + toast({ + title: t('toast.imageNotLoaded'), + description: t('toast.imageNotLoadedDesc'), + status: 'warning', + duration: 2500, + isClosable: true, + }); + return; + } + + dispatch(initialImageSelected({ name: image.name, type: image.type })); + toast({ + title: t('toast.sentToImageToImage'), + status: 'info', + duration: 2500, + isClosable: true, + }); + }, + [t, toast, dispatch] + ); + + return { recallPrompt, recallSeed, recallInitialImage, sendToImageToImage }; +}; diff --git a/invokeai/frontend/web/src/features/parameters/hooks/usePrompt.ts b/invokeai/frontend/web/src/features/parameters/hooks/usePrompt.ts index 310f9a9209..40080b77c7 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/usePrompt.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/usePrompt.ts @@ -1,26 +1,30 @@ import { getPromptAndNegative } from 'common/util/getPromptAndNegative'; -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import promptToString from 'common/util/promptToString'; -import { useAppDispatch } from 'app/storeHooks'; +import { useAppDispatch } from 'app/store/storeHooks'; import { setNegativePrompt, setPrompt } from '../store/generationSlice'; +import { useCallback } from 'react'; // TECHDEBT: We have two metadata prompt formats and need to handle recalling either of them. // This hook provides a function to do that. const useSetBothPrompts = () => { const dispatch = useAppDispatch(); - return (inputPrompt: InvokeAI.Prompt) => { - const promptString = - typeof inputPrompt === 'string' - ? inputPrompt - : promptToString(inputPrompt); + return useCallback( + (inputPrompt: InvokeAI.Prompt) => { + const promptString = + typeof inputPrompt === 'string' + ? inputPrompt + : promptToString(inputPrompt); - const [prompt, negativePrompt] = getPromptAndNegative(promptString); + const [prompt, negativePrompt] = getPromptAndNegative(promptString); - dispatch(setPrompt(prompt)); - dispatch(setNegativePrompt(negativePrompt)); - }; + dispatch(setPrompt(prompt)); + dispatch(setNegativePrompt(negativePrompt)); + }, + [dispatch] + ); }; export default useSetBothPrompts; diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSelectors.ts b/invokeai/frontend/web/src/features/parameters/store/generationSelectors.ts index 39550c5ad6..dbf5eec791 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSelectors.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSelectors.ts @@ -1,12 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { gallerySelector } from 'features/gallery/store/gallerySelectors'; -import { - selectResultsById, - selectResultsEntities, -} from 'features/gallery/store/resultsSlice'; +import { RootState } from 'app/store/store'; +import { selectResultsById } from 'features/gallery/store/resultsSlice'; import { selectUploadsById } from 'features/gallery/store/uploadsSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; export const generationSelector = (state: RootState) => state.generation; @@ -25,11 +21,14 @@ export const mayGenerateMultipleImagesSelector = createSelector( export const initialImageSelector = createSelector( [(state: RootState) => state, generationSelector], (state, generation) => { - const { initialImage: initialImageName } = generation; + const { initialImage } = generation; - return ( - selectResultsById(state, initialImageName as string) ?? - selectUploadsById(state, initialImageName as string) - ); + if (initialImage?.type === 'results') { + return selectResultsById(state, initialImage.name); + } + + if (initialImage?.type === 'uploads') { + return selectUploadsById(state, initialImage.name); + } } ); diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index e4a92f0b10..9d9d689cb0 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -1,17 +1,23 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import { getPromptAndNegative } from 'common/util/getPromptAndNegative'; import promptToString from 'common/util/promptToString'; import { seedWeightsToString } from 'common/util/seedWeightPairs'; -import { clamp } from 'lodash'; +import { clamp } from 'lodash-es'; +import { ImageField, ImageType } from 'services/api'; + +export type SelectedImage = { + name: string; + type: ImageType; +}; export interface GenerationState { cfgScale: number; height: number; img2imgStrength: number; infillMethod: string; - initialImage?: InvokeAI._Image | string; // can be an Image or url + initialImage?: SelectedImage; // can be an Image or url iterations: number; maskPath: string; perlin: number; @@ -179,136 +185,126 @@ export const generationSlice = createSlice({ state, action: PayloadAction ) => { - const { - sampler, - prompt, - seed, - variations, - steps, - cfg_scale, - threshold, - perlin, - seamless, - _hires_fix, - width, - height, - } = action.payload.image; - - if (variations && variations.length > 0) { - state.seedWeights = seedWeightsToString(variations); - state.shouldGenerateVariations = true; - state.variationAmount = 0; - } else { - state.shouldGenerateVariations = false; - } - - if (seed) { - state.seed = seed; - state.shouldRandomizeSeed = false; - } - - if (prompt) state.prompt = promptToString(prompt); - if (sampler) state.sampler = sampler; - if (steps) state.steps = steps; - if (cfg_scale) state.cfgScale = cfg_scale; - if (typeof threshold === 'undefined') { - state.threshold = 0; - } else { - state.threshold = threshold; - } - if (typeof perlin === 'undefined') { - state.perlin = 0; - } else { - state.perlin = perlin; - } - if (typeof seamless === 'boolean') state.seamless = seamless; - // if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg - if (width) state.width = width; - if (height) state.height = height; + // const { + // sampler, + // prompt, + // seed, + // variations, + // steps, + // cfg_scale, + // threshold, + // perlin, + // seamless, + // _hires_fix, + // width, + // height, + // } = action.payload.image; + // if (variations && variations.length > 0) { + // state.seedWeights = seedWeightsToString(variations); + // state.shouldGenerateVariations = true; + // state.variationAmount = 0; + // } else { + // state.shouldGenerateVariations = false; + // } + // if (seed) { + // state.seed = seed; + // state.shouldRandomizeSeed = false; + // } + // if (prompt) state.prompt = promptToString(prompt); + // if (sampler) state.sampler = sampler; + // if (steps) state.steps = steps; + // if (cfg_scale) state.cfgScale = cfg_scale; + // if (typeof threshold === 'undefined') { + // state.threshold = 0; + // } else { + // state.threshold = threshold; + // } + // if (typeof perlin === 'undefined') { + // state.perlin = 0; + // } else { + // state.perlin = perlin; + // } + // if (typeof seamless === 'boolean') state.seamless = seamless; + // // if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg + // if (width) state.width = width; + // if (height) state.height = height; }, setAllImageToImageParameters: ( state, action: PayloadAction ) => { - const { type, strength, fit, init_image_path, mask_image_path } = - action.payload.image; - - if (type === 'img2img') { - if (init_image_path) state.initialImage = init_image_path; - if (mask_image_path) state.maskPath = mask_image_path; - if (strength) state.img2imgStrength = strength; - if (typeof fit === 'boolean') state.shouldFitToWidthHeight = fit; - } + // const { type, strength, fit, init_image_path, mask_image_path } = + // action.payload.image; + // if (type === 'img2img') { + // if (init_image_path) state.initialImage = init_image_path; + // if (mask_image_path) state.maskPath = mask_image_path; + // if (strength) state.img2imgStrength = strength; + // if (typeof fit === 'boolean') state.shouldFitToWidthHeight = fit; + // } }, setAllParameters: (state, action: PayloadAction) => { - const { - type, - sampler, - prompt, - seed, - variations, - steps, - cfg_scale, - threshold, - perlin, - seamless, - _hires_fix, - width, - height, - strength, - fit, - init_image_path, - mask_image_path, - } = action.payload.image; - - if (type === 'img2img') { - if (init_image_path) state.initialImage = init_image_path; - if (mask_image_path) state.maskPath = mask_image_path; - if (strength) state.img2imgStrength = strength; - if (typeof fit === 'boolean') state.shouldFitToWidthHeight = fit; - } - - if (variations && variations.length > 0) { - state.seedWeights = seedWeightsToString(variations); - state.shouldGenerateVariations = true; - state.variationAmount = 0; - } else { - state.shouldGenerateVariations = false; - } - - if (seed) { - state.seed = seed; - state.shouldRandomizeSeed = false; - } - - if (prompt) { - const [promptOnly, negativePrompt] = getPromptAndNegative(prompt); - if (promptOnly) state.prompt = promptOnly; - negativePrompt - ? (state.negativePrompt = negativePrompt) - : (state.negativePrompt = ''); - } - - if (sampler) state.sampler = sampler; - if (steps) state.steps = steps; - if (cfg_scale) state.cfgScale = cfg_scale; - if (typeof threshold === 'undefined') { - state.threshold = 0; - } else { - state.threshold = threshold; - } - if (typeof perlin === 'undefined') { - state.perlin = 0; - } else { - state.perlin = perlin; - } - if (typeof seamless === 'boolean') state.seamless = seamless; - // if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg - if (width) state.width = width; - if (height) state.height = height; - - // state.shouldRunESRGAN = false; // TODO: Needs to be fixed after reorg - // state.shouldRunFacetool = false; // TODO: Needs to be fixed after reorg + // const { + // type, + // sampler, + // prompt, + // seed, + // variations, + // steps, + // cfg_scale, + // threshold, + // perlin, + // seamless, + // _hires_fix, + // width, + // height, + // strength, + // fit, + // init_image_path, + // mask_image_path, + // } = action.payload.image; + // if (type === 'img2img') { + // if (init_image_path) state.initialImage = init_image_path; + // if (mask_image_path) state.maskPath = mask_image_path; + // if (strength) state.img2imgStrength = strength; + // if (typeof fit === 'boolean') state.shouldFitToWidthHeight = fit; + // } + // if (variations && variations.length > 0) { + // state.seedWeights = seedWeightsToString(variations); + // state.shouldGenerateVariations = true; + // state.variationAmount = 0; + // } else { + // state.shouldGenerateVariations = false; + // } + // if (seed) { + // state.seed = seed; + // state.shouldRandomizeSeed = false; + // } + // if (prompt) { + // const [promptOnly, negativePrompt] = getPromptAndNegative(prompt); + // if (promptOnly) state.prompt = promptOnly; + // negativePrompt + // ? (state.negativePrompt = negativePrompt) + // : (state.negativePrompt = ''); + // } + // if (sampler) state.sampler = sampler; + // if (steps) state.steps = steps; + // if (cfg_scale) state.cfgScale = cfg_scale; + // if (typeof threshold === 'undefined') { + // state.threshold = 0; + // } else { + // state.threshold = threshold; + // } + // if (typeof perlin === 'undefined') { + // state.perlin = 0; + // } else { + // state.perlin = perlin; + // } + // if (typeof seamless === 'boolean') state.seamless = seamless; + // // if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg + // if (width) state.width = width; + // if (height) state.height = height; + // // state.shouldRunESRGAN = false; // TODO: Needs to be fixed after reorg + // // state.shouldRunFacetool = false; // TODO: Needs to be fixed after reorg }, resetParametersState: (state) => { return { @@ -355,7 +351,7 @@ export const generationSlice = createSlice({ setVerticalSymmetrySteps: (state, action: PayloadAction) => { state.verticalSymmetrySteps = action.payload; }, - initialImageSelected: (state, action: PayloadAction) => { + initialImageSelected: (state, action: PayloadAction) => { state.initialImage = action.payload; state.isImageToImageEnabled = true; }, diff --git a/invokeai/frontend/web/src/features/parameters/store/postprocessingSelectors.ts b/invokeai/frontend/web/src/features/parameters/store/postprocessingSelectors.ts index 7cc346cbee..2908d16c54 100644 --- a/invokeai/frontend/web/src/features/parameters/store/postprocessingSelectors.ts +++ b/invokeai/frontend/web/src/features/parameters/store/postprocessingSelectors.ts @@ -1,4 +1,4 @@ -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; export const postprocessingSelector = (state: RootState) => state.postprocessing; diff --git a/invokeai/frontend/web/src/features/system/components/ClearTempFolderButtonModal.tsx b/invokeai/frontend/web/src/features/system/components/ClearTempFolderButtonModal.tsx index e644487178..a220c93b3f 100644 --- a/invokeai/frontend/web/src/features/system/components/ClearTempFolderButtonModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/ClearTempFolderButtonModal.tsx @@ -1,5 +1,5 @@ -import { emptyTempFolder } from 'app/socketio/actions'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +// import { emptyTempFolder } from 'app/socketio/actions'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIAlertDialog from 'common/components/IAIAlertDialog'; import IAIButton from 'common/components/IAIButton'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; diff --git a/invokeai/frontend/web/src/features/system/components/Console.tsx b/invokeai/frontend/web/src/features/system/components/Console.tsx deleted file mode 100644 index 7c227be226..0000000000 --- a/invokeai/frontend/web/src/features/system/components/Console.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import { Flex, Text, Tooltip } from '@chakra-ui/react'; -import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import IAIIconButton from 'common/components/IAIIconButton'; -import { - errorSeen, - setShouldShowLogViewer, - SystemState, -} from 'features/system/store/systemSlice'; -import { isEqual } from 'lodash'; -import { Resizable } from 're-resizable'; -import { useLayoutEffect, useRef, useState } from 'react'; -import { useHotkeys } from 'react-hotkeys-hook'; -import { useTranslation } from 'react-i18next'; -import { FaAngleDoubleDown, FaCode, FaMinus } from 'react-icons/fa'; -import { systemSelector } from '../store/systemSelectors'; - -const logSelector = createSelector( - systemSelector, - (system: SystemState) => system.log, - { - memoizeOptions: { - // We don't need a deep equality check for this selector. - resultEqualityCheck: (a, b) => a.length === b.length, - }, - } -); - -const consoleSelector = createSelector( - systemSelector, - (system: SystemState) => { - return { - shouldShowLogViewer: system.shouldShowLogViewer, - hasError: system.hasError, - wasErrorSeen: system.wasErrorSeen, - }; - }, - { - memoizeOptions: { - resultEqualityCheck: isEqual, - }, - } -); - -/** - * Basic log viewer, floats on bottom of page. - */ -const Console = () => { - const dispatch = useAppDispatch(); - const { t } = useTranslation(); - const log = useAppSelector(logSelector); - const { shouldShowLogViewer, hasError, wasErrorSeen } = - useAppSelector(consoleSelector); - - // Rudimentary autoscroll - const [shouldAutoscroll, setShouldAutoscroll] = useState(true); - const viewerRef = useRef(null); - - /** - * If autoscroll is on, scroll to the bottom when: - * - log updates - * - viewer is toggled - * - * Also scroll to the bottom whenever autoscroll is turned on. - */ - useLayoutEffect(() => { - if (viewerRef.current !== null && shouldAutoscroll) { - viewerRef.current.scrollTop = viewerRef.current.scrollHeight; - } - }, [shouldAutoscroll, log, shouldShowLogViewer]); - - const handleClickLogViewerToggle = () => { - dispatch(errorSeen()); - dispatch(setShouldShowLogViewer(!shouldShowLogViewer)); - }; - - useHotkeys( - '`', - () => { - dispatch(setShouldShowLogViewer(!shouldShowLogViewer)); - }, - [shouldShowLogViewer] - ); - - useHotkeys('esc', () => { - dispatch(setShouldShowLogViewer(false)); - }); - - const handleOnScroll = () => { - if (!viewerRef.current) return; - if ( - shouldAutoscroll && - viewerRef.current.scrollTop < - viewerRef.current.scrollHeight - viewerRef.current.clientHeight - ) { - setShouldAutoscroll(false); - } - }; - - return ( - <> - {shouldShowLogViewer && ( - - - {log.map((entry, i) => { - const { timestamp, message, level } = entry; - const colorScheme = level === 'info' ? 'base' : level; - return ( - - {timestamp}: - {message} - - ); - })} - - - )} - {shouldShowLogViewer && ( - - } - onClick={() => setShouldAutoscroll(!shouldAutoscroll)} - isChecked={shouldAutoscroll} - sx={{ - position: 'fixed', - insetInlineStart: 2, - bottom: 12, - zIndex: 1, - }} - /> - - )} - - : } - onClick={handleClickLogViewerToggle} - sx={{ - position: 'fixed', - insetInlineStart: 2, - bottom: 2, - zIndex: 1, - }} - colorScheme={hasError || !wasErrorSeen ? 'error' : 'base'} - /> - - - ); -}; - -export default Console; diff --git a/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx b/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx index 2c54d9d42a..e736450563 100644 --- a/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx +++ b/invokeai/frontend/web/src/features/system/components/InvokeAILogoComponent.tsx @@ -1,6 +1,6 @@ import { Flex, Text, Image } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import InvokeAILogoImage from 'assets/images/logo.png'; const InvokeAILogoComponent = () => { diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/AddCheckpointModel.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/AddCheckpointModel.tsx index 5fc877891e..bb5db0302d 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/AddCheckpointModel.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/AddCheckpointModel.tsx @@ -17,15 +17,15 @@ import React from 'react'; import SearchModels from './SearchModels'; -import { addNewModel } from 'app/socketio/actions'; +// import { addNewModel } from 'app/socketio/actions'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { Field, Formik } from 'formik'; import { useTranslation } from 'react-i18next'; -import type { InvokeModelConfigProps } from 'app/invokeai'; -import type { RootState } from 'app/store'; +import type { InvokeModelConfigProps } from 'app/types/invokeai'; +import type { RootState } from 'app/store/store'; import { setAddNewModelUIOption } from 'features/ui/store/uiSlice'; import type { FieldInputProps, FormikProps } from 'formik'; import IAIForm from 'common/components/IAIForm'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/AddDiffusersModel.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/AddDiffusersModel.tsx index 14cd488b72..cb3af5f176 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/AddDiffusersModel.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/AddDiffusersModel.tsx @@ -7,16 +7,16 @@ import { Text, VStack, } from '@chakra-ui/react'; -import { InvokeDiffusersModelConfigProps } from 'app/invokeai'; -import { addNewModel } from 'app/socketio/actions'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { InvokeDiffusersModelConfigProps } from 'app/types/invokeai'; +// import { addNewModel } from 'app/socketio/actions'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import IAIInput from 'common/components/IAIInput'; import { setAddNewModelUIOption } from 'features/ui/store/uiSlice'; import { Field, Formik } from 'formik'; import { useTranslation } from 'react-i18next'; -import type { RootState } from 'app/store'; +import type { RootState } from 'app/store/store'; import IAIForm from 'common/components/IAIForm'; import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/AddModel.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/AddModel.tsx index f0d46a89fa..bd0d0e5d3a 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/AddModel.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/AddModel.tsx @@ -16,10 +16,10 @@ import IAIButton from 'common/components/IAIButton'; import { FaArrowLeft, FaPlus } from 'react-icons/fa'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useTranslation } from 'react-i18next'; -import type { RootState } from 'app/store'; +import type { RootState } from 'app/store/store'; import { setAddNewModelUIOption } from 'features/ui/store/uiSlice'; import AddCheckpointModel from './AddCheckpointModel'; import AddDiffusersModel from './AddDiffusersModel'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/CheckpointModelEdit.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/CheckpointModelEdit.tsx index cfb94dd044..b860a0848c 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/CheckpointModelEdit.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/CheckpointModelEdit.tsx @@ -5,7 +5,7 @@ import IAIInput from 'common/components/IAIInput'; import IAINumberInput from 'common/components/IAINumberInput'; import { useEffect, useState } from 'react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { systemSelector } from 'features/system/store/systemSelectors'; import { @@ -17,14 +17,14 @@ import { VStack, } from '@chakra-ui/react'; -import { addNewModel } from 'app/socketio/actions'; +// import { addNewModel } from 'app/socketio/actions'; import { Field, Formik } from 'formik'; import { useTranslation } from 'react-i18next'; -import type { InvokeModelConfigProps } from 'app/invokeai'; -import type { RootState } from 'app/store'; +import type { InvokeModelConfigProps } from 'app/types/invokeai'; +import type { RootState } from 'app/store/store'; import type { FieldInputProps, FormikProps } from 'formik'; -import { isEqual, pickBy } from 'lodash'; +import { isEqual, pickBy } from 'lodash-es'; import ModelConvert from './ModelConvert'; import IAIFormHelperText from 'common/components/IAIForms/IAIFormHelperText'; import IAIFormErrorMessage from 'common/components/IAIForms/IAIFormErrorMessage'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/DiffusersModelEdit.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/DiffusersModelEdit.tsx index 4b86583d61..81998e4976 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/DiffusersModelEdit.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/DiffusersModelEdit.tsx @@ -4,18 +4,18 @@ import IAIButton from 'common/components/IAIButton'; import IAIInput from 'common/components/IAIInput'; import { useEffect, useState } from 'react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { systemSelector } from 'features/system/store/systemSelectors'; import { Flex, FormControl, FormLabel, Text, VStack } from '@chakra-ui/react'; -import { addNewModel } from 'app/socketio/actions'; +// import { addNewModel } from 'app/socketio/actions'; import { Field, Formik } from 'formik'; import { useTranslation } from 'react-i18next'; -import type { InvokeDiffusersModelConfigProps } from 'app/invokeai'; -import type { RootState } from 'app/store'; -import { isEqual, pickBy } from 'lodash'; +import type { InvokeDiffusersModelConfigProps } from 'app/types/invokeai'; +import type { RootState } from 'app/store/store'; +import { isEqual, pickBy } from 'lodash-es'; import IAIFormHelperText from 'common/components/IAIForms/IAIFormHelperText'; import IAIFormErrorMessage from 'common/components/IAIForms/IAIFormErrorMessage'; import IAIForm from 'common/components/IAIForm'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/MergeModels.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/MergeModels.tsx index 3b1905979c..6ba148cac4 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/MergeModels.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/MergeModels.tsx @@ -13,16 +13,16 @@ import { Tooltip, useDisclosure, } from '@chakra-ui/react'; -import { mergeDiffusersModels } from 'app/socketio/actions'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +// import { mergeDiffusersModels } from 'app/socketio/actions'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import IAIInput from 'common/components/IAIInput'; import IAISelect from 'common/components/IAISelect'; import { diffusersModelsSelector } from 'features/system/store/systemSelectors'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import IAISlider from 'common/components/IAISlider'; import IAICheckbox from 'common/components/IAICheckbox'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelConvert.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelConvert.tsx index 5896e634ea..820ad546b3 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelConvert.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelConvert.tsx @@ -7,9 +7,9 @@ import { UnorderedList, Tooltip, } from '@chakra-ui/react'; -import { convertToDiffusers } from 'app/socketio/actions'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +// import { convertToDiffusers } from 'app/socketio/actions'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIAlertDialog from 'common/components/IAIAlertDialog'; import IAIButton from 'common/components/IAIButton'; import IAIInput from 'common/components/IAIInput'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelList.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelList.tsx index ad5b9b9072..4ef311e1d4 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelList.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelList.tsx @@ -6,13 +6,13 @@ import AddModel from './AddModel'; import ModelListItem from './ModelListItem'; import MergeModels from './MergeModels'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { useTranslation } from 'react-i18next'; import { createSelector } from '@reduxjs/toolkit'; import { systemSelector } from 'features/system/store/systemSelectors'; import type { SystemState } from 'features/system/store/systemSlice'; -import { isEqual, map } from 'lodash'; +import { isEqual, map } from 'lodash-es'; import React, { useMemo, useState, useTransition } from 'react'; import type { ChangeEvent, ReactNode } from 'react'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelListItem.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelListItem.tsx index 6b9e4d1cfd..aa9f87816c 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelListItem.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelListItem.tsx @@ -1,9 +1,9 @@ import { DeleteIcon, EditIcon } from '@chakra-ui/icons'; import { Box, Button, Flex, Spacer, Text, Tooltip } from '@chakra-ui/react'; -import { ModelStatus } from 'app/invokeai'; -import { deleteModel, requestModelChange } from 'app/socketio/actions'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { ModelStatus } from 'app/types/invokeai'; +// import { deleteModel, requestModelChange } from 'app/socketio/actions'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIAlertDialog from 'common/components/IAIAlertDialog'; import IAIIconButton from 'common/components/IAIIconButton'; import { setOpenModel } from 'features/system/store/systemSlice'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelManagerModal.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelManagerModal.tsx index 5de4faa80b..440e5ad4db 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/ModelManagerModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/ModelManagerModal.tsx @@ -11,8 +11,8 @@ import { } from '@chakra-ui/react'; import { cloneElement } from 'react'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { useTranslation } from 'react-i18next'; import type { ReactElement } from 'react'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelManager/SearchModels.tsx b/invokeai/frontend/web/src/features/system/components/ModelManager/SearchModels.tsx index 510c4de147..3a99997ac8 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelManager/SearchModels.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelManager/SearchModels.tsx @@ -14,24 +14,24 @@ import { Text, } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { systemSelector } from 'features/system/store/systemSelectors'; import { useTranslation } from 'react-i18next'; import { FaSearch, FaTrash } from 'react-icons/fa'; -import { addNewModel, searchForModels } from 'app/socketio/actions'; +// import { addNewModel, searchForModels } from 'app/socketio/actions'; import { setFoundModels, setSearchFolder, } from 'features/system/store/systemSlice'; import { setShouldShowExistingModelsInSearch } from 'features/ui/store/uiSlice'; -import type { FoundModel } from 'app/invokeai'; -import type { RootState } from 'app/store'; +import type { FoundModel } from 'app/types/invokeai'; +import type { RootState } from 'app/store/store'; import IAIInput from 'common/components/IAIInput'; import { Field, Formik } from 'formik'; -import { forEach, remove } from 'lodash'; +import { forEach, remove } from 'lodash-es'; import type { ChangeEvent, ReactNode } from 'react'; import IAIForm from 'common/components/IAIForm'; diff --git a/invokeai/frontend/web/src/features/system/components/ModelSelect.tsx b/invokeai/frontend/web/src/features/system/components/ModelSelect.tsx index 9e06d2bff3..d0ad89ba36 100644 --- a/invokeai/frontend/web/src/features/system/components/ModelSelect.tsx +++ b/invokeai/frontend/web/src/features/system/components/ModelSelect.tsx @@ -1,16 +1,16 @@ import { createSelector } from '@reduxjs/toolkit'; import { ChangeEvent, memo } from 'react'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAISelect from 'common/components/IAISelect'; import { modelSelected, selectedModelSelector, selectModelsIds, } from '../store/modelSlice'; -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; const selector = createSelector( [(state: RootState) => state], diff --git a/invokeai/frontend/web/src/features/system/components/ProgressBar.tsx b/invokeai/frontend/web/src/features/system/components/ProgressBar.tsx index 7fa3d961fa..03e78965a3 100644 --- a/invokeai/frontend/web/src/features/system/components/ProgressBar.tsx +++ b/invokeai/frontend/web/src/features/system/components/ProgressBar.tsx @@ -1,8 +1,9 @@ import { Progress } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppSelector } from 'app/storeHooks'; +import { useAppSelector } from 'app/store/storeHooks'; import { SystemState } from 'features/system/store/systemSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { PROGRESS_BAR_THICKNESS } from 'theme/util/constants'; import { systemSelector } from '../store/systemSelectors'; @@ -40,4 +41,4 @@ const ProgressBar = () => { ); }; -export default ProgressBar; +export default memo(ProgressBar); 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 c203edfc37..0ca0b496fc 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx @@ -1,7 +1,6 @@ import { ChakraProps, Flex, - Grid, Heading, Modal, ModalBody, @@ -14,57 +13,59 @@ import { useDisclosure, } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { IN_PROGRESS_IMAGE_TYPES } from 'app/constants'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; -import IAINumberInput from 'common/components/IAINumberInput'; import IAISelect from 'common/components/IAISelect'; import IAISwitch from 'common/components/IAISwitch'; import { systemSelector } from 'features/system/store/systemSelectors'; import { - InProgressImageType, + consoleLogLevelChanged, setEnableImageDebugging, - setSaveIntermediatesInterval, setShouldConfirmOnDelete, setShouldDisplayGuides, - setShouldDisplayInProgressType, + shouldLogToConsoleChanged, SystemState, } from 'features/system/store/systemSlice'; import { uiSelector } from 'features/ui/store/uiSelectors'; import { + setShouldAutoShowProgressImages, setShouldUseCanvasBetaLayout, setShouldUseSliders, } from 'features/ui/store/uiSlice'; import { UIState } from 'features/ui/store/uiTypes'; -import { isEqual, map } from 'lodash'; -import { persistor } from 'persistor'; -import { ChangeEvent, cloneElement, ReactElement } from 'react'; +import { isEqual } from 'lodash-es'; +import { persistor } from 'app/store/persistor'; +import { ChangeEvent, cloneElement, ReactElement, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; +import { VALID_LOG_LEVELS } from 'app/logging/useLogger'; +import { LogLevelName } from 'roarr'; const selector = createSelector( [systemSelector, uiSelector], (system: SystemState, ui: UIState) => { const { - shouldDisplayInProgressType, shouldConfirmOnDelete, shouldDisplayGuides, - model_list, - saveIntermediatesInterval, enableImageDebugging, + consoleLogLevel, + shouldLogToConsole, } = system; - const { shouldUseCanvasBetaLayout, shouldUseSliders } = ui; + const { + shouldUseCanvasBetaLayout, + shouldUseSliders, + shouldAutoShowProgressImages, + } = ui; return { - shouldDisplayInProgressType, shouldConfirmOnDelete, shouldDisplayGuides, - models: map(model_list, (_model, key) => key), - saveIntermediatesInterval, enableImageDebugging, shouldUseCanvasBetaLayout, shouldUseSliders, + shouldAutoShowProgressImages, + consoleLogLevel, + shouldLogToConsole, }; }, { @@ -77,6 +78,7 @@ const modalSectionStyles: ChakraProps['sx'] = { gap: 2, p: 4, bg: 'base.900', + borderRadius: 'base', }; type SettingsModalProps = { @@ -94,8 +96,6 @@ const SettingsModal = ({ children }: SettingsModalProps) => { const dispatch = useAppDispatch(); const { t } = useTranslation(); - const steps = useAppSelector((state: RootState) => state.generation.steps); - const { isOpen: isSettingsModalOpen, onOpen: onSettingsModalOpen, @@ -109,31 +109,40 @@ const SettingsModal = ({ children }: SettingsModalProps) => { } = useDisclosure(); const { - shouldDisplayInProgressType, shouldConfirmOnDelete, shouldDisplayGuides, - saveIntermediatesInterval, enableImageDebugging, shouldUseCanvasBetaLayout, shouldUseSliders, + shouldAutoShowProgressImages, + consoleLogLevel, + shouldLogToConsole, } = useAppSelector(selector); /** * Resets localstorage, then opens a secondary modal informing user to * refresh their browser. * */ - const handleClickResetWebUI = () => { + const handleClickResetWebUI = useCallback(() => { persistor.purge().then(() => { onSettingsModalClose(); onRefreshModalOpen(); }); - }; + }, [onSettingsModalClose, onRefreshModalOpen]); - const handleChangeIntermediateSteps = (value: number) => { - if (value > steps) value = steps; - if (value < 1) value = 1; - dispatch(setSaveIntermediatesInterval(value)); - }; + const handleLogLevelChanged = useCallback( + (e: ChangeEvent) => { + dispatch(consoleLogLevelChanged(e.target.value as LogLevelName)); + }, + [dispatch] + ); + + const handleLogToConsoleChanged = useCallback( + (e: ChangeEvent) => { + dispatch(shouldLogToConsoleChanged(e.target.checked)); + }, + [dispatch] + ); return ( <> @@ -145,38 +154,17 @@ const SettingsModal = ({ children }: SettingsModalProps) => { isOpen={isSettingsModalOpen} onClose={onSettingsModalClose} size="xl" + isCentered > {t('common.settingsLabel')} - + - ) => - dispatch( - setShouldDisplayInProgressType( - e.target.value as InProgressImageType - ) - ) - } - /> - {shouldDisplayInProgressType === 'full-res' && ( - - )} + {t('settings.general')} + { dispatch(setShouldUseSliders(e.target.checked)) } /> + ) => + dispatch(setShouldAutoShowProgressImages(e.target.checked)) + } + /> - - Developer - + {t('settings.developer')} + + { {t('settings.resetWebUIDesc1')} {t('settings.resetWebUIDesc2')} - + diff --git a/invokeai/frontend/web/src/features/system/components/SiteHeader.tsx b/invokeai/frontend/web/src/features/system/components/SiteHeader.tsx index af7a4ce33f..350e1291aa 100644 --- a/invokeai/frontend/web/src/features/system/components/SiteHeader.tsx +++ b/invokeai/frontend/web/src/features/system/components/SiteHeader.tsx @@ -1,5 +1,5 @@ import { Flex, Grid } from '@chakra-ui/react'; -import { useState } from 'react'; +import { memo, useState } from 'react'; import ModelSelect from './ModelSelect'; import StatusIndicator from './StatusIndicator'; @@ -7,8 +7,8 @@ import InvokeAILogoComponent from './InvokeAILogoComponent'; import SiteHeaderMenu from './SiteHeaderMenu'; import useResolution from 'common/hooks/useResolution'; import { FaBars } from 'react-icons/fa'; -import { IAIIconButton } from 'exports'; import { useTranslation } from 'react-i18next'; +import IAIIconButton from 'common/components/IAIIconButton'; /** * Header, includes color mode toggle, settings button, status message. @@ -65,5 +65,4 @@ const SiteHeader = () => { ); }; -SiteHeader.displayName = 'SiteHeader'; -export default SiteHeader; +export default memo(SiteHeader); diff --git a/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx b/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx index a8a87bc39a..48418c9f19 100644 --- a/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx +++ b/invokeai/frontend/web/src/features/system/components/StatusIndicator.tsx @@ -1,22 +1,34 @@ -import { Text, Tooltip } from '@chakra-ui/react'; +import { Flex, Icon, Text } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; -import { errorSeen, SystemState } from 'features/system/store/systemSlice'; -import { isEqual } from 'lodash'; +import { useAppSelector } from 'app/store/storeHooks'; +import { isEqual } from 'lodash-es'; import { useTranslation } from 'react-i18next'; import { systemSelector } from '../store/systemSelectors'; +import { ResourceKey } from 'i18next'; +import { AnimatePresence, motion } from 'framer-motion'; +import { useMemo, useRef } from 'react'; +import { FaCircle } from 'react-icons/fa'; +import { useHoverDirty } from 'react-use'; const statusIndicatorSelector = createSelector( systemSelector, - (system: SystemState) => { + (system) => { + const { + isConnected, + isProcessing, + statusTranslationKey, + currentIteration, + totalIterations, + currentStatusHasSteps, + } = system; + return { - isConnected: system.isConnected, - isProcessing: system.isProcessing, - currentIteration: system.currentIteration, - totalIterations: system.totalIterations, - currentStatus: system.currentStatus, - hasError: system.hasError, - wasErrorSeen: system.wasErrorSeen, + isConnected, + isProcessing, + currentIteration, + totalIterations, + statusTranslationKey, + currentStatusHasSteps, }; }, { @@ -30,64 +42,69 @@ const StatusIndicator = () => { isProcessing, currentIteration, totalIterations, - currentStatus, - hasError, - wasErrorSeen, + statusTranslationKey, + currentStatusHasSteps, } = useAppSelector(statusIndicatorSelector); - const dispatch = useAppDispatch(); const { t } = useTranslation(); + const ref = useRef(null); - let statusIdentifier; - - if (isConnected && !hasError) { - statusIdentifier = 'ok'; - } else { - statusIdentifier = 'error'; - } - - let statusMessage = currentStatus; - - if (isProcessing) { - statusIdentifier = 'working'; - } - - if (statusMessage) + const statusColorScheme = useMemo(() => { if (isProcessing) { - if (totalIterations > 1) { - statusMessage = `${t( - statusMessage as keyof typeof t - )} (${currentIteration}/${totalIterations})`; - } + return 'working'; } - const tooltipLabel = - hasError && !wasErrorSeen - ? 'Click to clear, check logs for details' - : undefined; - - const statusIndicatorCursor = - hasError && !wasErrorSeen ? 'pointer' : 'initial'; - - const handleClickStatusIndicator = () => { - if (hasError || !wasErrorSeen) { - dispatch(errorSeen()); + if (isConnected) { + return 'ok'; } - }; + + return 'error'; + }, [isProcessing, isConnected]); + + const iterationsText = useMemo(() => { + if (!(currentIteration && totalIterations)) { + return; + } + + return ` (${currentIteration}/${totalIterations})`; + }, [currentIteration, totalIterations]); + + const isHovered = useHoverDirty(ref); return ( - - - {t(statusMessage as keyof typeof t)} - - + + + {isHovered && ( + + + {t(statusTranslationKey as ResourceKey)} + {iterationsText} + + + )} + + + ); }; diff --git a/invokeai/frontend/web/src/features/system/components/ThemeChanger.tsx b/invokeai/frontend/web/src/features/system/components/ThemeChanger.tsx index dd8b19b93e..ff825e9bf0 100644 --- a/invokeai/frontend/web/src/features/system/components/ThemeChanger.tsx +++ b/invokeai/frontend/web/src/features/system/components/ThemeChanger.tsx @@ -1,6 +1,6 @@ import { VStack } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIButton from 'common/components/IAIButton'; import IAIIconButton from 'common/components/IAIIconButton'; import IAIPopover from 'common/components/IAIPopover'; diff --git a/invokeai/frontend/web/src/features/system/hooks/useFeatureStatus.ts b/invokeai/frontend/web/src/features/system/hooks/useFeatureStatus.ts index 1006844dcf..2e0cfb3d20 100644 --- a/invokeai/frontend/web/src/features/system/hooks/useFeatureStatus.ts +++ b/invokeai/frontend/web/src/features/system/hooks/useFeatureStatus.ts @@ -1,6 +1,6 @@ -import { AppFeature } from 'app/invokeai'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { AppFeature } from 'app/types/invokeai'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { useMemo } from 'react'; export const useFeatureStatus = (feature: AppFeature) => { diff --git a/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts b/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts index 52821425f3..cecd739278 100644 --- a/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts +++ b/invokeai/frontend/web/src/features/system/hooks/useIsApplicationReady.ts @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { useMemo } from 'react'; import { configSelector } from '../store/configSelectors'; import { systemSelector } from '../store/systemSelectors'; diff --git a/invokeai/frontend/web/src/features/system/hooks/useIsTabDisabled.ts b/invokeai/frontend/web/src/features/system/hooks/useIsTabDisabled.ts index b4b2a390b1..1d14ac2243 100644 --- a/invokeai/frontend/web/src/features/system/hooks/useIsTabDisabled.ts +++ b/invokeai/frontend/web/src/features/system/hooks/useIsTabDisabled.ts @@ -1,5 +1,5 @@ -import { RootState } from 'app/store'; -import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; import { InvokeTabName } from 'features/ui/store/tabMap'; import { useCallback } from 'react'; diff --git a/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts b/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts index 0c99eec0a4..b51bf48a36 100644 --- a/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts +++ b/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts @@ -1,5 +1,5 @@ import { useToast, UseToastOptions } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { toastQueueSelector } from 'features/system/store/systemSelectors'; import { clearToastQueue } from 'features/system/store/systemSlice'; import { useEffect } from 'react'; diff --git a/invokeai/frontend/web/src/features/system/store/configSelectors.ts b/invokeai/frontend/web/src/features/system/store/configSelectors.ts index 399f974611..e96775321a 100644 --- a/invokeai/frontend/web/src/features/system/store/configSelectors.ts +++ b/invokeai/frontend/web/src/features/system/store/configSelectors.ts @@ -1,3 +1,3 @@ -import { RootState } from 'app/store'; +import { RootState } from 'app/store/store'; export const configSelector = (state: RootState) => state.config; diff --git a/invokeai/frontend/web/src/features/system/store/configSlice.ts b/invokeai/frontend/web/src/features/system/store/configSlice.ts index 9f2bec606b..d668a59574 100644 --- a/invokeai/frontend/web/src/features/system/store/configSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/configSlice.ts @@ -1,7 +1,7 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import { AppConfig, PartialAppConfig } from 'app/invokeai'; -import { merge } from 'lodash'; +import { AppConfig, PartialAppConfig } from 'app/types/invokeai'; +import { merge } from 'lodash-es'; const initialConfigState: AppConfig = { shouldTransformUrls: false, diff --git a/invokeai/frontend/web/src/features/system/store/modelSelectors.ts b/invokeai/frontend/web/src/features/system/store/modelSelectors.ts index 74027d631b..8b502fb3b6 100644 --- a/invokeai/frontend/web/src/features/system/store/modelSelectors.ts +++ b/invokeai/frontend/web/src/features/system/store/modelSelectors.ts @@ -1,5 +1,5 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { reduce } from 'lodash'; +import { RootState } from 'app/store/store'; +import { reduce } from 'lodash-es'; export const modelSelector = (state: RootState) => state.models; diff --git a/invokeai/frontend/web/src/features/system/store/modelSlice.ts b/invokeai/frontend/web/src/features/system/store/modelSlice.ts index 843e27a435..cb1cf05328 100644 --- a/invokeai/frontend/web/src/features/system/store/modelSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/modelSlice.ts @@ -1,7 +1,7 @@ import { createEntityAdapter, PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { keys, sample } from 'lodash'; +import { RootState } from 'app/store/store'; +import { keys, sample } from 'lodash-es'; import { CkptModelInfo, DiffusersModelInfo } from 'services/api'; import { receivedModels } from 'services/thunks/model'; diff --git a/invokeai/frontend/web/src/features/system/store/systemPersistsDenylist.ts b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts similarity index 97% rename from invokeai/frontend/web/src/features/system/store/systemPersistsDenylist.ts rename to invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts index 84dbd0ecc7..8a4d381775 100644 --- a/invokeai/frontend/web/src/features/system/store/systemPersistsDenylist.ts +++ b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts @@ -17,7 +17,6 @@ const itemsToDenylist: (keyof SystemState)[] = [ 'totalSteps', 'openModel', 'isCancelScheduled', - 'sessionId', 'progressImage', 'wereModelsReceived', 'wasSchemaParsed', diff --git a/invokeai/frontend/web/src/features/system/store/systemSelectors.ts b/invokeai/frontend/web/src/features/system/store/systemSelectors.ts index b1f670c075..68265aa2dc 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSelectors.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSelectors.ts @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { isEqual, reduce, pickBy } from 'lodash'; +import { RootState } from 'app/store/store'; +import { isEqual, reduce, pickBy } from 'lodash-es'; export const systemSelector = (state: RootState) => state.system; diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index 6f1da80dfe..a74e6dca7e 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -1,9 +1,10 @@ -import { ExpandedIndex, UseToastOptions } from '@chakra-ui/react'; +import { UseToastOptions } from '@chakra-ui/react'; import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import * as InvokeAI from 'app/invokeai'; +import * as InvokeAI from 'app/types/invokeai'; import { generatorProgress, + graphExecutionStateComplete, invocationComplete, invocationError, invocationStarted, @@ -13,63 +14,37 @@ import { socketUnsubscribed, } from 'services/events/actions'; -import i18n from 'i18n'; -import { isImageOutput } from 'services/types/guards'; import { ProgressImage } from 'services/events/types'; import { initialImageSelected } from 'features/parameters/store/generationSlice'; import { makeToast } from '../hooks/useToastWatcher'; import { sessionCanceled, sessionInvoked } from 'services/thunks/session'; -import { InvokeTabName } from 'features/ui/store/tabMap'; import { receivedModels } from 'services/thunks/model'; -import { receivedOpenAPISchema } from 'services/thunks/schema'; +import { parsedOpenAPISchema } from 'features/nodes/store/nodesSlice'; +import { LogLevelName } from 'roarr'; +import { InvokeLogLevel } from 'app/logging/useLogger'; +import { TFuncKey } from 'i18next'; +import { t } from 'i18next'; -export type LogLevel = 'info' | 'warning' | 'error'; +export type CancelStrategy = 'immediate' | 'scheduled'; -export interface LogEntry { - timestamp: string; - level: LogLevel; - message: string; -} - -export interface Log { - [index: number]: LogEntry; -} - -export type InProgressImageType = 'none' | 'full-res' | 'latents'; - -export type CancelType = 'immediate' | 'scheduled'; - -export interface SystemState - extends InvokeAI.SystemStatus, - InvokeAI.SystemConfig { - shouldDisplayInProgressType: InProgressImageType; - log: Array; - shouldShowLogViewer: boolean; +export interface SystemState { isGFPGANAvailable: boolean; isESRGANAvailable: boolean; isConnected: boolean; - socketId: string; + isProcessing: boolean; shouldConfirmOnDelete: boolean; - openAccordions: ExpandedIndex; currentStep: number; totalSteps: number; currentIteration: number; totalIterations: number; - currentStatus: string; currentStatusHasSteps: boolean; shouldDisplayGuides: boolean; - wasErrorSeen: boolean; isCancelable: boolean; - saveIntermediatesInterval: number; enableImageDebugging: boolean; toastQueue: UseToastOptions[]; searchFolder: string | null; foundModels: InvokeAI.FoundModel[] | null; openModel: string | null; - cancelOptions: { - cancelType: CancelType; - cancelAfter: number | null; - }; /** * The current progress image */ @@ -81,7 +56,7 @@ export interface SystemState /** * Cancel strategy */ - cancelType: CancelType; + cancelType: CancelStrategy; /** * Whether or not a scheduled cancelation is pending */ @@ -90,18 +65,6 @@ export interface SystemState * Array of node IDs that we want to handle when events received */ subscribedNodeIds: string[]; - // /** - // * Whether or not URLs should be transformed to use a different host - // */ - // shouldTransformUrls: boolean; - // /** - // * Array of disabled tabs - // */ - // disabledTabs: InvokeTabName[]; - // /** - // * Array of disabled features - // */ - // disabledFeatures: InvokeAI.AppFeature[]; /** * Whether or not the available models were received */ @@ -110,81 +73,57 @@ export interface SystemState * Whether or not the OpenAPI schema was received and parsed */ wasSchemaParsed: boolean; + /** + * The console output logging level + */ + consoleLogLevel: InvokeLogLevel; + shouldLogToConsole: boolean; + statusTranslationKey: TFuncKey; + canceledSession: string; } const initialSystemState: SystemState = { isConnected: false, isProcessing: false, - log: [], - shouldShowLogViewer: false, - shouldDisplayInProgressType: 'latents', shouldDisplayGuides: true, isGFPGANAvailable: true, isESRGANAvailable: true, - socketId: '', shouldConfirmOnDelete: true, - openAccordions: [0], currentStep: 0, totalSteps: 0, currentIteration: 0, totalIterations: 0, - currentStatus: i18n.isInitialized - ? i18n.t('common.statusDisconnected') - : 'Disconnected', currentStatusHasSteps: false, - model: '', - model_id: '', - model_hash: '', - app_id: '', - app_version: '', - model_list: {}, - infill_methods: [], - hasError: false, - wasErrorSeen: true, isCancelable: true, - saveIntermediatesInterval: 5, enableImageDebugging: false, toastQueue: [], searchFolder: null, foundModels: null, openModel: null, - cancelOptions: { - cancelType: 'immediate', - cancelAfter: null, - }, progressImage: null, sessionId: null, cancelType: 'immediate', isCancelScheduled: false, subscribedNodeIds: [], - // shouldTransformUrls: false, - // disabledTabs: [], - // disabledFeatures: [], wereModelsReceived: false, wasSchemaParsed: false, + consoleLogLevel: 'error', + shouldLogToConsole: true, + statusTranslationKey: 'common.statusDisconnected', + canceledSession: '', }; export const systemSlice = createSlice({ name: 'system', initialState: initialSystemState, reducers: { - setShouldDisplayInProgressType: ( - state, - action: PayloadAction - ) => { - state.shouldDisplayInProgressType = action.payload; - }, setIsProcessing: (state, action: PayloadAction) => { state.isProcessing = action.payload; }, - setCurrentStatus: (state, action: PayloadAction) => { - state.currentStatus = action.payload; - }, - setSystemStatus: (state, action: PayloadAction) => { - return { ...state, ...action.payload }; + setCurrentStatus: (state, action: PayloadAction) => { + state.statusTranslationKey = action.payload; }, errorOccurred: (state) => { - state.hasError = true; state.isProcessing = false; state.isCancelable = true; state.currentStep = 0; @@ -192,37 +131,7 @@ export const systemSlice = createSlice({ state.currentIteration = 0; state.totalIterations = 0; state.currentStatusHasSteps = false; - state.currentStatus = i18n.t('common.statusError'); - state.wasErrorSeen = false; - }, - errorSeen: (state) => { - state.hasError = false; - state.wasErrorSeen = true; - state.currentStatus = state.isConnected - ? i18n.t('common.statusConnected') - : i18n.t('common.statusDisconnected'); - }, - addLogEntry: ( - state, - action: PayloadAction<{ - timestamp: string; - message: string; - level?: LogLevel; - }> - ) => { - const { timestamp, message, level } = action.payload; - const logLevel = level || 'info'; - - const entry: LogEntry = { - timestamp, - message, - level: logLevel, - }; - - state.log.push(entry); - }, - setShouldShowLogViewer: (state, action: PayloadAction) => { - state.shouldShowLogViewer = action.payload; + state.statusTranslationKey = 'common.statusError'; }, setIsConnected: (state, action: PayloadAction) => { state.isConnected = action.payload; @@ -233,23 +142,10 @@ export const systemSlice = createSlice({ state.currentIteration = 0; state.totalIterations = 0; state.currentStatusHasSteps = false; - state.hasError = false; - }, - setSocketId: (state, action: PayloadAction) => { - state.socketId = action.payload; }, setShouldConfirmOnDelete: (state, action: PayloadAction) => { state.shouldConfirmOnDelete = action.payload; }, - setOpenAccordions: (state, action: PayloadAction) => { - state.openAccordions = action.payload; - }, - setSystemConfig: (state, action: PayloadAction) => { - return { - ...state, - ...action.payload, - }; - }, setShouldDisplayGuides: (state, action: PayloadAction) => { state.shouldDisplayGuides = action.payload; }, @@ -261,7 +157,7 @@ export const systemSlice = createSlice({ state.currentIteration = 0; state.totalIterations = 0; state.currentStatusHasSteps = false; - state.currentStatus = i18n.t('common.statusProcessingCanceled'); + state.statusTranslationKey = 'common.statusProcessingCanceled'; }, generationRequested: (state) => { state.isProcessing = true; @@ -271,38 +167,29 @@ export const systemSlice = createSlice({ state.currentIteration = 0; state.totalIterations = 0; state.currentStatusHasSteps = false; - state.currentStatus = i18n.t('common.statusPreparing'); - }, - setModelList: ( - state, - action: PayloadAction> - ) => { - state.model_list = action.payload; + state.statusTranslationKey = 'common.statusPreparing'; }, setIsCancelable: (state, action: PayloadAction) => { state.isCancelable = action.payload; }, modelChangeRequested: (state) => { - state.currentStatus = i18n.t('common.statusLoadingModel'); + state.statusTranslationKey = 'common.statusLoadingModel'; state.isCancelable = false; state.isProcessing = true; state.currentStatusHasSteps = false; }, modelConvertRequested: (state) => { - state.currentStatus = i18n.t('common.statusConvertingModel'); + state.statusTranslationKey = 'common.statusConvertingModel'; state.isCancelable = false; state.isProcessing = true; state.currentStatusHasSteps = false; }, modelMergingRequested: (state) => { - state.currentStatus = i18n.t('common.statusMergingModels'); + state.statusTranslationKey = 'common.statusMergingModels'; state.isCancelable = false; state.isProcessing = true; state.currentStatusHasSteps = false; }, - setSaveIntermediatesInterval: (state, action: PayloadAction) => { - state.saveIntermediatesInterval = action.payload; - }, setEnableImageDebugging: (state, action: PayloadAction) => { state.enableImageDebugging = action.payload; }, @@ -312,9 +199,12 @@ export const systemSlice = createSlice({ clearToastQueue: (state) => { state.toastQueue = []; }, - setProcessingIndeterminateTask: (state, action: PayloadAction) => { + setProcessingIndeterminateTask: ( + state, + action: PayloadAction + ) => { state.isProcessing = true; - state.currentStatus = action.payload; + state.statusTranslationKey = action.payload; state.currentStatusHasSteps = false; }, setSearchFolder: (state, action: PayloadAction) => { @@ -329,12 +219,6 @@ export const systemSlice = createSlice({ setOpenModel: (state, action: PayloadAction) => { state.openModel = action.payload; }, - setCancelType: (state, action: PayloadAction) => { - state.cancelOptions.cancelType = action.payload; - }, - setCancelAfter: (state, action: PayloadAction) => { - state.cancelOptions.cancelAfter = action.payload; - }, /** * A cancel was scheduled */ @@ -350,7 +234,7 @@ export const systemSlice = createSlice({ /** * The cancel type was changed */ - cancelTypeChanged: (state, action: PayloadAction) => { + cancelTypeChanged: (state, action: PayloadAction) => { state.cancelType = action.payload; }, /** @@ -359,27 +243,12 @@ export const systemSlice = createSlice({ subscribedNodeIdsSet: (state, action: PayloadAction) => { state.subscribedNodeIds = action.payload; }, - // /** - // * `shouldTransformUrls` was changed - // */ - // shouldTransformUrlsChanged: (state, action: PayloadAction) => { - // state.shouldTransformUrls = action.payload; - // }, - // /** - // * `disabledTabs` was changed - // */ - // disabledTabsChanged: (state, action: PayloadAction) => { - // state.disabledTabs = action.payload; - // }, - // /** - // * `disabledFeatures` was changed - // */ - // disabledFeaturesChanged: ( - // state, - // action: PayloadAction - // ) => { - // state.disabledFeatures = action.payload; - // }, + consoleLogLevelChanged: (state, action: PayloadAction) => { + state.consoleLogLevel = action.payload; + }, + shouldLogToConsoleChanged: (state, action: PayloadAction) => { + state.shouldLogToConsole = action.payload; + }, }, extraReducers(builder) { /** @@ -387,6 +256,7 @@ export const systemSlice = createSlice({ */ builder.addCase(socketSubscribed, (state, action) => { state.sessionId = action.payload.sessionId; + state.canceledSession = ''; }); /** @@ -401,17 +271,15 @@ export const systemSlice = createSlice({ */ builder.addCase(socketConnected, (state, action) => { const { timestamp } = action.payload; - state.isConnected = true; - state.currentStatus = i18n.t('common.statusConnected'); - state.log.push({ - timestamp, - message: `Connected to server`, - level: 'info', - }); - state.toastQueue.push( - makeToast({ title: i18n.t('toast.connected'), status: 'success' }) - ); + state.isCancelable = true; + state.isProcessing = false; + state.currentStatusHasSteps = false; + state.currentStep = 0; + state.totalSteps = 0; + state.currentIteration = 0; + state.totalIterations = 0; + state.statusTranslationKey = 'common.statusConnected'; }); /** @@ -421,25 +289,28 @@ export const systemSlice = createSlice({ const { timestamp } = action.payload; state.isConnected = false; - state.currentStatus = i18n.t('common.statusDisconnected'); - state.log.push({ - timestamp, - message: `Disconnected from server`, - level: 'error', - }); - state.toastQueue.push( - makeToast({ title: i18n.t('toast.disconnected'), status: 'error' }) - ); + state.isProcessing = false; + state.isCancelable = true; + state.currentStatusHasSteps = false; + state.currentStep = 0; + state.totalSteps = 0; + // state.currentIteration = 0; + // state.totalIterations = 0; + state.statusTranslationKey = 'common.statusDisconnected'; }); /** * Invocation Started */ - builder.addCase(invocationStarted, (state) => { - state.isProcessing = true; + builder.addCase(invocationStarted, (state, action) => { state.isCancelable = true; + state.isProcessing = true; state.currentStatusHasSteps = false; - state.currentStatus = i18n.t('common.statusGenerating'); + state.currentStep = 0; + state.totalSteps = 0; + // state.currentIteration = 0; + // state.totalIterations = 0; + state.statusTranslationKey = 'common.statusGenerating'; }); /** @@ -455,10 +326,15 @@ export const systemSlice = createSlice({ graph_execution_state_id, } = action.payload.data; + state.isProcessing = true; + state.isCancelable = true; + // state.currentIteration = 0; + // state.totalIterations = 0; state.currentStatusHasSteps = true; state.currentStep = step + 1; // TODO: step starts at -1, think this is a bug state.totalSteps = total_steps; state.progressImage = progress_image ?? null; + state.statusTranslationKey = 'common.statusGenerating'; }); /** @@ -467,19 +343,16 @@ export const systemSlice = createSlice({ builder.addCase(invocationComplete, (state, action) => { const { data, timestamp } = action.payload; - state.isProcessing = false; + // state.currentIteration = 0; + // state.totalIterations = 0; + state.currentStatusHasSteps = false; state.currentStep = 0; state.totalSteps = 0; - state.progressImage = null; - state.currentStatus = i18n.t('common.statusProcessingComplete'); + state.statusTranslationKey = 'common.statusProcessingComplete'; - // TODO: handle logging for other invocation types - if (isImageOutput(data.result)) { - state.log.push({ - timestamp, - message: `Generated: ${data.result.image.image_name}`, - level: 'info', - }); + if (state.canceledSession === data.graph_execution_state_id) { + state.isProcessing = false; + state.isCancelable = true; } }); @@ -489,25 +362,18 @@ export const systemSlice = createSlice({ builder.addCase(invocationError, (state, action) => { const { data, timestamp } = action.payload; - state.log.push({ - timestamp, - message: `Server error: ${data.error}`, - level: 'error', - }); - - state.wasErrorSeen = true; - state.progressImage = null; state.isProcessing = false; + state.isCancelable = true; + // state.currentIteration = 0; + // state.totalIterations = 0; + state.currentStatusHasSteps = false; + state.currentStep = 0; + state.totalSteps = 0; + state.statusTranslationKey = 'common.statusError'; state.toastQueue.push( - makeToast({ title: i18n.t('toast.serverError'), status: 'error' }) + makeToast({ title: t('toast.serverError'), status: 'error' }) ); - - state.log.push({ - timestamp, - message: `Server error: ${data.error}`, - level: 'error', - }); }); /** @@ -515,7 +381,7 @@ export const systemSlice = createSlice({ */ builder.addCase(sessionInvoked.pending, (state) => { - state.currentStatus = i18n.t('common.statusPreparing'); + state.statusTranslationKey = 'common.statusPreparing'; }); /** @@ -524,69 +390,68 @@ export const systemSlice = createSlice({ builder.addCase(sessionCanceled.fulfilled, (state, action) => { const { timestamp } = action.payload; + state.canceledSession = action.meta.arg.sessionId; state.isProcessing = false; state.isCancelable = false; state.isCancelScheduled = false; state.currentStep = 0; state.totalSteps = 0; - state.progressImage = null; + state.statusTranslationKey = 'common.statusConnected'; state.toastQueue.push( - makeToast({ title: i18n.t('toast.canceled'), status: 'warning' }) + makeToast({ title: t('toast.canceled'), status: 'warning' }) ); + }); - state.log.push({ - timestamp, - message: `Processing canceled`, - level: 'warning', - }); + /** + * Session Canceled + */ + builder.addCase(graphExecutionStateComplete, (state, action) => { + const { timestamp } = action.payload; + + state.isProcessing = false; + state.isCancelable = false; + state.isCancelScheduled = false; + state.currentStep = 0; + state.totalSteps = 0; + state.statusTranslationKey = 'common.statusConnected'; }); /** * Initial Image Selected */ builder.addCase(initialImageSelected, (state) => { - state.toastQueue.push(makeToast(i18n.t('toast.sentToImageToImage'))); + state.toastQueue.push(makeToast(t('toast.sentToImageToImage'))); }); /** * Received available models from the backend */ - builder.addCase(receivedModels.fulfilled, (state, action) => { + builder.addCase(receivedModels.fulfilled, (state) => { state.wereModelsReceived = true; }); /** - * OpenAPI schema was received and parsed + * OpenAPI schema was parsed */ - builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => { + builder.addCase(parsedOpenAPISchema, (state) => { state.wasSchemaParsed = true; }); }, }); export const { - setShouldDisplayInProgressType, setIsProcessing, - addLogEntry, - setShouldShowLogViewer, setIsConnected, - setSocketId, setShouldConfirmOnDelete, - setOpenAccordions, - setSystemStatus, setCurrentStatus, - setSystemConfig, setShouldDisplayGuides, processingCanceled, errorOccurred, - errorSeen, - setModelList, setIsCancelable, modelChangeRequested, modelConvertRequested, modelMergingRequested, - setSaveIntermediatesInterval, setEnableImageDebugging, generationRequested, addToast, @@ -595,15 +460,12 @@ export const { setSearchFolder, setFoundModels, setOpenModel, - setCancelType, - setCancelAfter, cancelScheduled, scheduledCancelAborted, cancelTypeChanged, subscribedNodeIdsSet, - // shouldTransformUrlsChanged, - // disabledTabsChanged, - // disabledFeaturesChanged, + consoleLogLevelChanged, + shouldLogToConsoleChanged, } = systemSlice.actions; export default systemSlice.reducer; diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx index e0dd3eadd3..83a699aca0 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingGalleryButton.tsx @@ -1,12 +1,13 @@ import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton from 'common/components/IAIIconButton'; import { useTranslation } from 'react-i18next'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { setShouldShowGallery } from 'features/ui/store/uiSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { MdPhotoLibrary } from 'react-icons/md'; import { activeTabNameSelector, uiSelector } from '../store/uiSelectors'; +import { memo } from 'react'; const floatingGalleryButtonSelector = createSelector( [activeTabNameSelector, uiSelector], @@ -58,4 +59,4 @@ const FloatingGalleryButton = () => { ) : null; }; -export default FloatingGalleryButton; +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 77855cd05f..3055216b66 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx @@ -1,6 +1,6 @@ import { ChakraProps, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +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'; @@ -10,7 +10,8 @@ import { uiSelector, } from 'features/ui/store/uiSelectors'; import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { FaSlidersH } from 'react-icons/fa'; @@ -94,4 +95,4 @@ const FloatingParametersPanelButtons = () => { ) : null; }; -export default FloatingParametersPanelButtons; +export default memo(FloatingParametersPanelButtons); diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx index 3e0ee9ed85..0c65a99293 100644 --- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx +++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx @@ -9,12 +9,12 @@ import { Tooltip, VisuallyHidden, } from '@chakra-ui/react'; -import { RootState } from 'app/store'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { setIsLightboxOpen } from 'features/lightbox/store/lightboxSlice'; import { InvokeTabName } from 'features/ui/store/tabMap'; import { setActiveTab, togglePanels } from 'features/ui/store/uiSlice'; -import { ReactNode, useMemo } from 'react'; +import { memo, ReactNode, useMemo } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { MdDeviceHub, MdGridOn } from 'react-icons/md'; import { activeTabIndexSelector } from '../store/uiSelectors'; @@ -24,10 +24,10 @@ import { ResourceKey } from 'i18next'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import NodeEditor from 'features/nodes/components/NodeEditor'; import GenerateWorkspace from './tabs/Generate/GenerateWorkspace'; -import { FaImage } from 'react-icons/fa'; import { createSelector } from '@reduxjs/toolkit'; -import { BsLightningChargeFill, BsLightningFill } from 'react-icons/bs'; +import { BsLightningChargeFill } from 'react-icons/bs'; import { configSelector } from 'features/system/store/configSelectors'; +import { isEqual } from 'lodash'; export interface InvokeTabInfo { id: InvokeTabName; @@ -35,10 +35,6 @@ export interface InvokeTabInfo { workarea: ReactNode; } -const tabIconStyles: ChakraProps['sx'] = { - boxSize: 6, -}; - const tabs: InvokeTabInfo[] = [ { id: 'generate', @@ -57,13 +53,19 @@ const tabs: InvokeTabInfo[] = [ }, ]; -const enabledTabsSelector = createSelector(configSelector, (config) => { - const { disabledTabs } = config; +const enabledTabsSelector = createSelector( + configSelector, + (config) => { + const { disabledTabs } = config; - return tabs.filter((tab) => !disabledTabs.includes(tab.id)); -}); + return tabs.filter((tab) => !disabledTabs.includes(tab.id)); + }, + { + memoizeOptions: { resultEqualityCheck: isEqual }, + } +); -export default function InvokeTabs() { +const InvokeTabs = () => { const activeTab = useAppSelector(activeTabIndexSelector); const enabledTabs = useAppSelector(enabledTabsSelector); const isLightBoxOpen = useAppSelector( @@ -160,4 +162,6 @@ export default function InvokeTabs() { {tabPanels} ); -} +}; + +export default memo(InvokeTabs); diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx index 8ed443a345..f59028c8ca 100644 --- a/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx +++ b/invokeai/frontend/web/src/features/ui/components/InvokeWorkarea.tsx @@ -1,6 +1,6 @@ import { Box, BoxProps, Grid, GridItem } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { initialImageSelected } from 'features/parameters/store/generationSlice'; import { activeTabNameSelector, @@ -10,7 +10,7 @@ import { DragEvent, ReactNode } from 'react'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import useGetImageByUuid from 'features/gallery/hooks/useGetImageByUuid'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { APP_CONTENT_HEIGHT } from 'theme/util/constants'; import ParametersPanel from './ParametersPanel'; diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx index 09d4d6c316..b36199e263 100644 --- a/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx +++ b/invokeai/frontend/web/src/features/ui/components/ParametersPanel.tsx @@ -1,5 +1,5 @@ import { Flex } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { memo, ReactNode } from 'react'; @@ -17,7 +17,7 @@ import PinParametersPanelButton from './PinParametersPanelButton'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { createSelector } from '@reduxjs/toolkit'; import { activeTabNameSelector, uiSelector } from '../store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import useResolution from 'common/hooks/useResolution'; diff --git a/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx b/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx index a385f29c35..46d0fa3f93 100644 --- a/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx +++ b/invokeai/frontend/web/src/features/ui/components/PinParametersPanelButton.tsx @@ -1,5 +1,5 @@ import { Tooltip } from '@chakra-ui/react'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIIconButton, { IAIIconButtonProps, } from 'common/components/IAIIconButton'; diff --git a/invokeai/frontend/web/src/features/ui/components/common/ParametersSlide.tsx b/invokeai/frontend/web/src/features/ui/components/common/ParametersSlide.tsx index 0889e779f1..3342a9338b 100644 --- a/invokeai/frontend/web/src/features/ui/components/common/ParametersSlide.tsx +++ b/invokeai/frontend/web/src/features/ui/components/common/ParametersSlide.tsx @@ -1,9 +1,9 @@ import { Box, Flex, useOutsideClick } from '@chakra-ui/react'; import { Slide } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; -import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { uiSelector } from 'features/ui/store/uiSelectors'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { memo, PropsWithChildren, useRef } from 'react'; import PinParametersPanelButton from 'features/ui/components/PinParametersPanelButton'; import { diff --git a/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx b/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx index 0fdcff742f..91a9b14e31 100644 --- a/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx +++ b/invokeai/frontend/web/src/features/ui/components/common/Scrollable.tsx @@ -1,5 +1,5 @@ import { Box, ChakraProps } from '@chakra-ui/react'; -import { throttle } from 'lodash'; +import { throttle } from 'lodash-es'; import { ReactNode, useEffect, useRef } from 'react'; const scrollShadowBaseStyles: ChakraProps['sx'] = { diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/Generate/GenerateContent.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/Generate/GenerateContent.tsx index 53fdcb4a49..de7b738956 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/Generate/GenerateContent.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/Generate/GenerateContent.tsx @@ -1,10 +1,12 @@ import { Box, Flex } from '@chakra-ui/react'; import CurrentImageDisplay from 'features/gallery/components/CurrentImageDisplay'; +import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview'; const GenerateContent = () => { return ( `ui.${denylistItem}` diff --git a/invokeai/frontend/web/src/features/ui/store/uiSelectors.ts b/invokeai/frontend/web/src/features/ui/store/uiSelectors.ts index d474bf6f27..fa152e9ce5 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSelectors.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSelectors.ts @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store'; -import { isEqual } from 'lodash'; +import { RootState } from 'app/store/store'; +import { isEqual } from 'lodash-es'; import { tabMap } from './tabMap'; import { UIState } from './uiTypes'; diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index 965fa21eb0..11abf6a20d 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -2,7 +2,7 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; import { setActiveTabReducer } from './extraReducers'; import { InvokeTabName, tabMap } from './tabMap'; -import { AddNewModelType, UIState } from './uiTypes'; +import { AddNewModelType, Coordinates, Rect, UIState } from './uiTypes'; const initialUIState: UIState = { activeTab: 0, @@ -21,6 +21,9 @@ const initialUIState: UIState = { openLinearAccordionItems: [], openGenerateAccordionItems: [], openUnifiedCanvasAccordionItems: [], + floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 }, + shouldShowProgressImages: false, + shouldAutoShowProgressImages: false, }; const initialState: UIState = initialUIState; @@ -105,6 +108,30 @@ export const uiSlice = createSlice({ state.openUnifiedCanvasAccordionItems = action.payload; } }, + floatingProgressImageMoved: (state, action: PayloadAction) => { + state.floatingProgressImageRect = { + ...state.floatingProgressImageRect, + ...action.payload, + }; + }, + floatingProgressImageResized: ( + state, + action: PayloadAction> + ) => { + state.floatingProgressImageRect = { + ...state.floatingProgressImageRect, + ...action.payload, + }; + }, + setShouldShowProgressImages: (state, action: PayloadAction) => { + state.shouldShowProgressImages = action.payload; + }, + setShouldAutoShowProgressImages: ( + state, + action: PayloadAction + ) => { + state.shouldAutoShowProgressImages = action.payload; + }, }, }); @@ -128,6 +155,10 @@ export const { toggleParametersPanel, toggleGalleryPanel, openAccordionItemsChanged, + floatingProgressImageMoved, + floatingProgressImageResized, + setShouldShowProgressImages, + setShouldAutoShowProgressImages, } = 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 66e85ce71b..bdcf0a3c30 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -1,7 +1,17 @@ -import { InvokeTabName } from './tabMap'; - export type AddNewModelType = 'ckpt' | 'diffusers' | null; +export type Coordinates = { + x: number; + y: number; +}; + +export type Dimensions = { + width: number | string; + height: number | string; +}; + +export type Rect = Coordinates & Dimensions; + export interface UIState { activeTab: number; currentTheme: string; @@ -19,4 +29,7 @@ export interface UIState { openLinearAccordionItems: number[]; openGenerateAccordionItems: number[]; openUnifiedCanvasAccordionItems: number[]; + floatingProgressImageRect: Rect; + shouldShowProgressImages: boolean; + shouldAutoShowProgressImages: boolean; } diff --git a/invokeai/frontend/web/src/index.ts b/invokeai/frontend/web/src/index.ts new file mode 100644 index 0000000000..274f9d5a0b --- /dev/null +++ b/invokeai/frontend/web/src/index.ts @@ -0,0 +1,9 @@ +export { default as InvokeAiLogoComponent } from './features/system/components/InvokeAILogoComponent'; +export { default as ThemeChanger } from './features/system/components/ThemeChanger'; +export { default as IAIPopover } from './common/components/IAIPopover'; +export { default as IAIIconButton } from './common/components/IAIIconButton'; +export { default as SettingsModal } from './features/system/components/SettingsModal/SettingsModal'; +export { default as StatusIndicator } from './features/system/components/StatusIndicator'; +export { default as ModelSelect } from './features/system/components/ModelSelect'; +export { default as InvokeAIUI } from './app/components/InvokeAIUI'; +export type { PartialAppConfig } from './app/types/invokeai'; diff --git a/invokeai/frontend/web/src/main.tsx b/invokeai/frontend/web/src/main.tsx index e0423d7e4e..c07decae63 100644 --- a/invokeai/frontend/web/src/main.tsx +++ b/invokeai/frontend/web/src/main.tsx @@ -1,7 +1,7 @@ import ReactDOM from 'react-dom/client'; -import Component from './component'; +import InvokeAIUI from './app/components/InvokeAIUI'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - + ); diff --git a/invokeai/frontend/web/src/services/api/core/CancelablePromise.ts b/invokeai/frontend/web/src/services/api/core/CancelablePromise.ts index b923479fea..a0f92e01b7 100644 --- a/invokeai/frontend/web/src/services/api/core/CancelablePromise.ts +++ b/invokeai/frontend/web/src/services/api/core/CancelablePromise.ts @@ -22,15 +22,13 @@ export interface OnCancel { } export class CancelablePromise implements Promise { - readonly [Symbol.toStringTag]!: string; - - private _isResolved: boolean; - private _isRejected: boolean; - private _isCancelled: boolean; - private readonly _cancelHandlers: (() => void)[]; - private readonly _promise: Promise; - private _resolve?: (value: T | PromiseLike) => void; - private _reject?: (reason?: any) => void; + #isResolved: boolean; + #isRejected: boolean; + #isCancelled: boolean; + readonly #cancelHandlers: (() => void)[]; + readonly #promise: Promise; + #resolve?: (value: T | PromiseLike) => void; + #reject?: (reason?: any) => void; constructor( executor: ( @@ -39,78 +37,82 @@ export class CancelablePromise implements Promise { onCancel: OnCancel ) => void ) { - this._isResolved = false; - this._isRejected = false; - this._isCancelled = false; - this._cancelHandlers = []; - this._promise = new Promise((resolve, reject) => { - this._resolve = resolve; - this._reject = reject; + this.#isResolved = false; + this.#isRejected = false; + this.#isCancelled = false; + this.#cancelHandlers = []; + this.#promise = new Promise((resolve, reject) => { + this.#resolve = resolve; + this.#reject = reject; const onResolve = (value: T | PromiseLike): void => { - if (this._isResolved || this._isRejected || this._isCancelled) { + if (this.#isResolved || this.#isRejected || this.#isCancelled) { return; } - this._isResolved = true; - this._resolve?.(value); + this.#isResolved = true; + this.#resolve?.(value); }; const onReject = (reason?: any): void => { - if (this._isResolved || this._isRejected || this._isCancelled) { + if (this.#isResolved || this.#isRejected || this.#isCancelled) { return; } - this._isRejected = true; - this._reject?.(reason); + this.#isRejected = true; + this.#reject?.(reason); }; const onCancel = (cancelHandler: () => void): void => { - if (this._isResolved || this._isRejected || this._isCancelled) { + if (this.#isResolved || this.#isRejected || this.#isCancelled) { return; } - this._cancelHandlers.push(cancelHandler); + this.#cancelHandlers.push(cancelHandler); }; Object.defineProperty(onCancel, 'isResolved', { - get: (): boolean => this._isResolved, + get: (): boolean => this.#isResolved, }); Object.defineProperty(onCancel, 'isRejected', { - get: (): boolean => this._isRejected, + get: (): boolean => this.#isRejected, }); Object.defineProperty(onCancel, 'isCancelled', { - get: (): boolean => this._isCancelled, + get: (): boolean => this.#isCancelled, }); return executor(onResolve, onReject, onCancel as OnCancel); }); } + get [Symbol.toStringTag]() { + return "Cancellable Promise"; + } + public then( onFulfilled?: ((value: T) => TResult1 | PromiseLike) | null, onRejected?: ((reason: any) => TResult2 | PromiseLike) | null ): Promise { - return this._promise.then(onFulfilled, onRejected); + return this.#promise.then(onFulfilled, onRejected); } public catch( onRejected?: ((reason: any) => TResult | PromiseLike) | null ): Promise { - return this._promise.catch(onRejected); + return this.#promise.catch(onRejected); } public finally(onFinally?: (() => void) | null): Promise { - return this._promise.finally(onFinally); + return this.#promise.finally(onFinally); } public cancel(): void { - if (this._isResolved || this._isRejected || this._isCancelled) { + if (this.#isResolved || this.#isRejected || this.#isCancelled) { return; } - this._isCancelled = true; - if (this._cancelHandlers.length) { + this.#isCancelled = true; + if (this.#cancelHandlers.length) { try { - for (const cancelHandler of this._cancelHandlers) { + for (const cancelHandler of this.#cancelHandlers) { cancelHandler(); } } catch (error) { @@ -118,11 +120,11 @@ export class CancelablePromise implements Promise { return; } } - this._cancelHandlers.length = 0; - this._reject?.(new CancelError('Request aborted')); + this.#cancelHandlers.length = 0; + this.#reject?.(new CancelError('Request aborted')); } public get isCancelled(): boolean { - return this._isCancelled; + return this.#isCancelled; } } diff --git a/invokeai/frontend/web/src/services/api/index.ts b/invokeai/frontend/web/src/services/api/index.ts index f1b84f8465..2a34837715 100644 --- a/invokeai/frontend/web/src/services/api/index.ts +++ b/invokeai/frontend/web/src/services/api/index.ts @@ -58,7 +58,9 @@ export type { PasteImageInvocation } from './models/PasteImageInvocation'; export type { PromptOutput } from './models/PromptOutput'; export type { RandomRangeInvocation } from './models/RandomRangeInvocation'; export type { RangeInvocation } from './models/RangeInvocation'; +export type { ResizeLatentsInvocation } from './models/ResizeLatentsInvocation'; export type { RestoreFaceInvocation } from './models/RestoreFaceInvocation'; +export type { ScaleLatentsInvocation } from './models/ScaleLatentsInvocation'; export type { ShowImageInvocation } from './models/ShowImageInvocation'; export type { SubtractInvocation } from './models/SubtractInvocation'; export type { TextToImageInvocation } from './models/TextToImageInvocation'; @@ -119,7 +121,9 @@ export { $PasteImageInvocation } from './schemas/$PasteImageInvocation'; export { $PromptOutput } from './schemas/$PromptOutput'; export { $RandomRangeInvocation } from './schemas/$RandomRangeInvocation'; export { $RangeInvocation } from './schemas/$RangeInvocation'; +export { $ResizeLatentsInvocation } from './schemas/$ResizeLatentsInvocation'; export { $RestoreFaceInvocation } from './schemas/$RestoreFaceInvocation'; +export { $ScaleLatentsInvocation } from './schemas/$ScaleLatentsInvocation'; export { $ShowImageInvocation } from './schemas/$ShowImageInvocation'; export { $SubtractInvocation } from './schemas/$SubtractInvocation'; export { $TextToImageInvocation } from './schemas/$TextToImageInvocation'; diff --git a/invokeai/frontend/web/src/services/api/models/Graph.ts b/invokeai/frontend/web/src/services/api/models/Graph.ts index 1e590e4ba9..57a9178290 100644 --- a/invokeai/frontend/web/src/services/api/models/Graph.ts +++ b/invokeai/frontend/web/src/services/api/models/Graph.ts @@ -25,7 +25,9 @@ import type { ParamIntInvocation } from './ParamIntInvocation'; import type { PasteImageInvocation } from './PasteImageInvocation'; import type { RandomRangeInvocation } from './RandomRangeInvocation'; import type { RangeInvocation } from './RangeInvocation'; +import type { ResizeLatentsInvocation } from './ResizeLatentsInvocation'; import type { RestoreFaceInvocation } from './RestoreFaceInvocation'; +import type { ScaleLatentsInvocation } from './ScaleLatentsInvocation'; import type { ShowImageInvocation } from './ShowImageInvocation'; import type { SubtractInvocation } from './SubtractInvocation'; import type { TextToImageInvocation } from './TextToImageInvocation'; @@ -40,7 +42,7 @@ export type Graph = { /** * The nodes in this graph */ - nodes?: Record; + nodes?: Record; /** * The connections between nodes and their fields in this graph */ diff --git a/invokeai/frontend/web/src/services/api/models/LatentsToLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/models/LatentsToLatentsInvocation.ts index 8210f01bb6..d04885bf85 100644 --- a/invokeai/frontend/web/src/services/api/models/LatentsToLatentsInvocation.ts +++ b/invokeai/frontend/web/src/services/api/models/LatentsToLatentsInvocation.ts @@ -17,10 +17,6 @@ export type LatentsToLatentsInvocation = { * The prompt to generate an image from */ prompt?: string; - /** - * The seed to use (-1 for a random seed) - */ - seed?: number; /** * The noise to use */ @@ -29,14 +25,6 @@ export type LatentsToLatentsInvocation = { * The number of steps to use to generate the image */ steps?: number; - /** - * The width of the resulting image - */ - width?: number; - /** - * The height of the resulting image - */ - height?: number; /** * The Classifier-Free Guidance, higher values may result in a result closer to the prompt */ diff --git a/invokeai/frontend/web/src/services/api/models/ResizeLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/models/ResizeLatentsInvocation.ts new file mode 100644 index 0000000000..c0fabb4984 --- /dev/null +++ b/invokeai/frontend/web/src/services/api/models/ResizeLatentsInvocation.ts @@ -0,0 +1,37 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { LatentsField } from './LatentsField'; + +/** + * Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8. + */ +export type ResizeLatentsInvocation = { + /** + * The id of this node. Must be unique among all nodes. + */ + id: string; + type?: 'lresize'; + /** + * The latents to resize + */ + latents?: LatentsField; + /** + * The width to resize to (px) + */ + width: number; + /** + * The height to resize to (px) + */ + height: number; + /** + * The interpolation mode + */ + mode?: 'nearest' | 'linear' | 'bilinear' | 'bicubic' | 'trilinear' | 'area' | 'nearest-exact'; + /** + * Whether or not to antialias (applied in bilinear and bicubic modes only) + */ + antialias?: boolean; +}; + diff --git a/invokeai/frontend/web/src/services/api/models/ScaleLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/models/ScaleLatentsInvocation.ts new file mode 100644 index 0000000000..f398eaf408 --- /dev/null +++ b/invokeai/frontend/web/src/services/api/models/ScaleLatentsInvocation.ts @@ -0,0 +1,33 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { LatentsField } from './LatentsField'; + +/** + * Scales latents by a given factor. + */ +export type ScaleLatentsInvocation = { + /** + * The id of this node. Must be unique among all nodes. + */ + id: string; + type?: 'lscale'; + /** + * The latents to scale + */ + latents?: LatentsField; + /** + * The factor by which to scale the latents + */ + scale_factor: number; + /** + * The interpolation mode + */ + mode?: 'nearest' | 'linear' | 'bilinear' | 'bicubic' | 'trilinear' | 'area' | 'nearest-exact'; + /** + * Whether or not to antialias (applied in bilinear and bicubic modes only) + */ + antialias?: boolean; +}; + diff --git a/invokeai/frontend/web/src/services/api/models/TextToLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/models/TextToLatentsInvocation.ts index 63754db163..217b917f18 100644 --- a/invokeai/frontend/web/src/services/api/models/TextToLatentsInvocation.ts +++ b/invokeai/frontend/web/src/services/api/models/TextToLatentsInvocation.ts @@ -17,10 +17,6 @@ export type TextToLatentsInvocation = { * The prompt to generate an image from */ prompt?: string; - /** - * The seed to use (-1 for a random seed) - */ - seed?: number; /** * The noise to use */ @@ -29,14 +25,6 @@ export type TextToLatentsInvocation = { * The number of steps to use to generate the image */ steps?: number; - /** - * The width of the resulting image - */ - width?: number; - /** - * The height of the resulting image - */ - height?: number; /** * The Classifier-Free Guidance, higher values may result in a result closer to the prompt */ diff --git a/invokeai/frontend/web/src/services/api/schemas/$Graph.ts b/invokeai/frontend/web/src/services/api/schemas/$Graph.ts index b431011ba6..6fd8117db8 100644 --- a/invokeai/frontend/web/src/services/api/schemas/$Graph.ts +++ b/invokeai/frontend/web/src/services/api/schemas/$Graph.ts @@ -33,6 +33,10 @@ export const $Graph = { type: 'TextToLatentsInvocation', }, { type: 'LatentsToImageInvocation', + }, { + type: 'ResizeLatentsInvocation', + }, { + type: 'ScaleLatentsInvocation', }, { type: 'AddInvocation', }, { diff --git a/invokeai/frontend/web/src/services/api/schemas/$LatentsToLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/schemas/$LatentsToLatentsInvocation.ts index d27fdc7c1f..b20ee88a52 100644 --- a/invokeai/frontend/web/src/services/api/schemas/$LatentsToLatentsInvocation.ts +++ b/invokeai/frontend/web/src/services/api/schemas/$LatentsToLatentsInvocation.ts @@ -16,12 +16,6 @@ export const $LatentsToLatentsInvocation = { type: 'string', description: `The prompt to generate an image from`, }, - seed: { - type: 'number', - description: `The seed to use (-1 for a random seed)`, - maximum: 4294967295, - minimum: -1, - }, noise: { type: 'all-of', description: `The noise to use`, @@ -33,16 +27,6 @@ export const $LatentsToLatentsInvocation = { type: 'number', description: `The number of steps to use to generate the image`, }, - width: { - type: 'number', - description: `The width of the resulting image`, - multipleOf: 64, - }, - height: { - type: 'number', - description: `The height of the resulting image`, - multipleOf: 64, - }, cfg_scale: { type: 'number', description: `The Classifier-Free Guidance, higher values may result in a result closer to the prompt`, diff --git a/invokeai/frontend/web/src/services/api/schemas/$ResizeLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/schemas/$ResizeLatentsInvocation.ts new file mode 100644 index 0000000000..2609b1a681 --- /dev/null +++ b/invokeai/frontend/web/src/services/api/schemas/$ResizeLatentsInvocation.ts @@ -0,0 +1,44 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ResizeLatentsInvocation = { + description: `Resizes latents to explicit width/height (in pixels). Provided dimensions are floor-divided by 8.`, + properties: { + id: { + type: 'string', + description: `The id of this node. Must be unique among all nodes.`, + isRequired: true, + }, + type: { + type: 'Enum', + }, + latents: { + type: 'all-of', + description: `The latents to resize`, + contains: [{ + type: 'LatentsField', + }], + }, + width: { + type: 'number', + description: `The width to resize to (px)`, + isRequired: true, + minimum: 64, + multipleOf: 8, + }, + height: { + type: 'number', + description: `The height to resize to (px)`, + isRequired: true, + minimum: 64, + multipleOf: 8, + }, + mode: { + type: 'Enum', + }, + antialias: { + type: 'boolean', + description: `Whether or not to antialias (applied in bilinear and bicubic modes only)`, + }, + }, +} as const; diff --git a/invokeai/frontend/web/src/services/api/schemas/$ScaleLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/schemas/$ScaleLatentsInvocation.ts new file mode 100644 index 0000000000..8d4d15e2e8 --- /dev/null +++ b/invokeai/frontend/web/src/services/api/schemas/$ScaleLatentsInvocation.ts @@ -0,0 +1,35 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ScaleLatentsInvocation = { + description: `Scales latents by a given factor.`, + properties: { + id: { + type: 'string', + description: `The id of this node. Must be unique among all nodes.`, + isRequired: true, + }, + type: { + type: 'Enum', + }, + latents: { + type: 'all-of', + description: `The latents to scale`, + contains: [{ + type: 'LatentsField', + }], + }, + scale_factor: { + type: 'number', + description: `The factor by which to scale the latents`, + isRequired: true, + }, + mode: { + type: 'Enum', + }, + antialias: { + type: 'boolean', + description: `Whether or not to antialias (applied in bilinear and bicubic modes only)`, + }, + }, +} as const; diff --git a/invokeai/frontend/web/src/services/api/schemas/$TextToLatentsInvocation.ts b/invokeai/frontend/web/src/services/api/schemas/$TextToLatentsInvocation.ts index 7b6dd155ca..06376824c6 100644 --- a/invokeai/frontend/web/src/services/api/schemas/$TextToLatentsInvocation.ts +++ b/invokeai/frontend/web/src/services/api/schemas/$TextToLatentsInvocation.ts @@ -16,12 +16,6 @@ export const $TextToLatentsInvocation = { type: 'string', description: `The prompt to generate an image from`, }, - seed: { - type: 'number', - description: `The seed to use (-1 for a random seed)`, - maximum: 4294967295, - minimum: -1, - }, noise: { type: 'all-of', description: `The noise to use`, @@ -33,16 +27,6 @@ export const $TextToLatentsInvocation = { type: 'number', description: `The number of steps to use to generate the image`, }, - width: { - type: 'number', - description: `The width of the resulting image`, - multipleOf: 64, - }, - height: { - type: 'number', - description: `The height of the resulting image`, - multipleOf: 64, - }, cfg_scale: { type: 'number', description: `The Classifier-Free Guidance, higher values may result in a result closer to the prompt`, diff --git a/invokeai/frontend/web/src/services/api/services/SessionsService.ts b/invokeai/frontend/web/src/services/api/services/SessionsService.ts index 269092c6d9..dad455fc80 100644 --- a/invokeai/frontend/web/src/services/api/services/SessionsService.ts +++ b/invokeai/frontend/web/src/services/api/services/SessionsService.ts @@ -27,7 +27,9 @@ import type { ParamIntInvocation } from '../models/ParamIntInvocation'; import type { PasteImageInvocation } from '../models/PasteImageInvocation'; import type { RandomRangeInvocation } from '../models/RandomRangeInvocation'; import type { RangeInvocation } from '../models/RangeInvocation'; +import type { ResizeLatentsInvocation } from '../models/ResizeLatentsInvocation'; import type { RestoreFaceInvocation } from '../models/RestoreFaceInvocation'; +import type { ScaleLatentsInvocation } from '../models/ScaleLatentsInvocation'; import type { ShowImageInvocation } from '../models/ShowImageInvocation'; import type { SubtractInvocation } from '../models/SubtractInvocation'; import type { TextToImageInvocation } from '../models/TextToImageInvocation'; @@ -142,7 +144,7 @@ export class SessionsService { * The id of the session */ sessionId: string, - requestBody: (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | ParamIntInvocation | CvInpaintInvocation | RangeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation), + requestBody: (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | ParamIntInvocation | CvInpaintInvocation | RangeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation), }): CancelablePromise { return __request(OpenAPI, { method: 'POST', @@ -179,7 +181,7 @@ export class SessionsService { * The path to the node in the graph */ nodePath: string, - requestBody: (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | ParamIntInvocation | CvInpaintInvocation | RangeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation), + requestBody: (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | ParamIntInvocation | CvInpaintInvocation | RangeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation), }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', diff --git a/invokeai/frontend/web/src/services/events/actions.ts b/invokeai/frontend/web/src/services/events/actions.ts index 5ea0a1e9e1..84268773a9 100644 --- a/invokeai/frontend/web/src/services/events/actions.ts +++ b/invokeai/frontend/web/src/services/events/actions.ts @@ -1,6 +1,7 @@ import { createAction } from '@reduxjs/toolkit'; import { GeneratorProgressEvent, + GraphExecutionStateCompleteEvent, InvocationCompleteEvent, InvocationErrorEvent, InvocationStartedEvent, @@ -45,6 +46,10 @@ export const invocationError = createAction< BaseSocketPayload & { data: InvocationErrorEvent } >('socket/invocationError'); +export const graphExecutionStateComplete = createAction< + BaseSocketPayload & { data: GraphExecutionStateCompleteEvent } +>('socket/graphExecutionStateComplete'); + export const generatorProgress = createAction< BaseSocketPayload & { data: GeneratorProgressEvent } >('socket/generatorProgress'); diff --git a/invokeai/frontend/web/src/services/events/middleware.ts b/invokeai/frontend/web/src/services/events/middleware.ts index d7ca579f2e..dab2e756f3 100644 --- a/invokeai/frontend/web/src/services/events/middleware.ts +++ b/invokeai/frontend/web/src/services/events/middleware.ts @@ -6,32 +6,23 @@ import { ServerToClientEvents, } from 'services/events/types'; import { - generatorProgress, invocationComplete, - invocationError, - invocationStarted, - socketConnected, - socketDisconnected, - socketReset, socketSubscribed, socketUnsubscribed, } from './actions'; -import { - receivedResultImagesPage, - receivedUploadImagesPage, -} from 'services/thunks/gallery'; -import { AppDispatch, RootState } from 'app/store'; +import { AppDispatch, RootState } from 'app/store/store'; import { getTimestamp } from 'common/util/getTimestamp'; import { sessionInvoked, isFulfilledSessionCreatedAction, - sessionCanceled, } from 'services/thunks/session'; import { OpenAPI } from 'services/api'; -import { receivedModels } from 'services/thunks/model'; -import { receivedOpenAPISchema } from 'services/thunks/schema'; import { isImageOutput } from 'services/types/guards'; import { imageReceived, thumbnailReceived } from 'services/thunks/image'; +import { setEventListeners } from 'services/events/util/setEventListeners'; +import { log } from 'app/logging/useLogger'; + +const socketioLog = log.child({ namespace: 'socketio' }); export const socketMiddleware = () => { let areListenersSet = false; @@ -66,82 +57,27 @@ export const socketMiddleware = () => { (store: MiddlewareAPI) => (next) => (action) => { const { dispatch, getState } = store; - // Nothing dispatches `socketReset` actions yet, so this is a noop, but including anyways - if (socketReset.match(action)) { - const { sessionId } = getState().system; - - if (sessionId) { - socket.emit('unsubscribe', { session: sessionId }); - dispatch( - socketUnsubscribed({ sessionId, timestamp: getTimestamp() }) - ); - } - - if (socket.connected) { - socket.disconnect(); - dispatch(socketDisconnected({ timestamp: getTimestamp() })); - } - - socket.removeAllListeners(); - areListenersSet = false; - } - // Set listeners for `connect` and `disconnect` events once // Must happen in middleware to get access to `dispatch` if (!areListenersSet) { - socket.on('connect', () => { - dispatch(socketConnected({ timestamp: getTimestamp() })); - - const { results, uploads, models, nodes, config } = getState(); - - const { disabledTabs } = config; - - // These thunks need to be dispatch in middleware; cannot handle in a reducer - if (!results.ids.length) { - dispatch(receivedResultImagesPage()); - } - - if (!uploads.ids.length) { - dispatch(receivedUploadImagesPage()); - } - - if (!models.ids.length) { - dispatch(receivedModels()); - } - - if (!nodes.schema && !disabledTabs.includes('nodes')) { - dispatch(receivedOpenAPISchema()); - } - }); - - socket.on('disconnect', () => { - dispatch(socketDisconnected({ timestamp: getTimestamp() })); - }); + setEventListeners({ store, socket, log: socketioLog }); areListenersSet = true; - // must manually connect socket.connect(); } - // Everything else only happens once we have created a session if (isFulfilledSessionCreatedAction(action)) { + const sessionId = action.payload.id; + const sessionLog = socketioLog.child({ sessionId }); const oldSessionId = getState().system.sessionId; - // temp disable event subscription - const shouldHandleEvent = (id: string): boolean => true; - - // const subscribedNodeIds = getState().system.subscribedNodeIds; - // const shouldHandleEvent = (id: string): boolean => { - // if (subscribedNodeIds.length === 1 && subscribedNodeIds[0] === '*') { - // return true; - // } - - // return subscribedNodeIds.includes(id); - // }; - if (oldSessionId) { - // Unsubscribe when invocations complete + sessionLog.debug( + { oldSessionId }, + `Unsubscribed from old session (${oldSessionId})` + ); + socket.emit('unsubscribe', { session: oldSessionId, }); @@ -152,74 +88,19 @@ export const socketMiddleware = () => { timestamp: getTimestamp(), }) ); - - const listenersToRemove: (keyof ServerToClientEvents)[] = [ - 'invocation_started', - 'generator_progress', - 'invocation_error', - 'invocation_complete', - ]; - - // Remove listeners for these events; we need to set them up fresh whenever we subscribe - listenersToRemove.forEach((event: keyof ServerToClientEvents) => { - socket.removeAllListeners(event); - }); } - const sessionId = action.payload.id; + sessionLog.debug(`Subscribe to new session (${sessionId})`); - // After a session is created, we immediately subscribe to events and then invoke the session socket.emit('subscribe', { session: sessionId }); - // Always dispatch the event actions for other consumers who want to know when we subscribed dispatch( socketSubscribed({ - sessionId, + sessionId: sessionId, timestamp: getTimestamp(), }) ); - // Set up listeners for the present subscription - socket.on('invocation_started', (data) => { - if (shouldHandleEvent(data.node.id)) { - dispatch(invocationStarted({ data, timestamp: getTimestamp() })); - } - }); - - socket.on('generator_progress', (data) => { - if (shouldHandleEvent(data.node.id)) { - dispatch(generatorProgress({ data, timestamp: getTimestamp() })); - } - }); - - socket.on('invocation_error', (data) => { - if (shouldHandleEvent(data.node.id)) { - dispatch(invocationError({ data, timestamp: getTimestamp() })); - } - }); - - socket.on('invocation_complete', (data) => { - if (shouldHandleEvent(data.node.id)) { - const sessionId = data.graph_execution_state_id; - - const { cancelType, isCancelScheduled } = getState().system; - const { shouldFetchImages } = getState().config; - - // Handle scheduled cancelation - if (cancelType === 'scheduled' && isCancelScheduled) { - dispatch(sessionCanceled({ sessionId })); - } - - dispatch( - invocationComplete({ - data, - timestamp: getTimestamp(), - shouldFetchImages, - }) - ); - } - }); - // Finally we actually invoke the session, starting processing dispatch(sessionInvoked({ sessionId })); } @@ -234,12 +115,16 @@ export const socketMiddleware = () => { const imageType = result.image.image_type; dispatch(imageReceived({ imageName, imageType })); - dispatch(thumbnailReceived({ imageName, imageType })); + dispatch( + thumbnailReceived({ + thumbnailName: imageName, + thumbnailType: imageType, + }) + ); } } } - // Always pass the action on so other middleware and reducers can handle it next(action); }; diff --git a/invokeai/frontend/web/src/services/events/types.ts b/invokeai/frontend/web/src/services/events/types.ts index 8452c46340..2577b7fe92 100644 --- a/invokeai/frontend/web/src/services/events/types.ts +++ b/invokeai/frontend/web/src/services/events/types.ts @@ -1,4 +1,4 @@ -import { Graph, GraphExecutionState } from '../api'; +import { Graph, GraphExecutionState, InvokeAIMetadata } from '../api'; /** * A progress image, we get one for each step in the generation @@ -15,14 +15,14 @@ export type AnyInvocationType = NonNullable< export type AnyInvocation = NonNullable[string]; -// export type AnyInvocation = { -// id: string; -// type: AnyInvocationType | string; -// [key: string]: any; -// }; - export type AnyResult = GraphExecutionState['results'][string]; +export type BaseNode = { + id: string; + type: string; + [key: string]: NonNullable[string]; +}; + /** * A `generator_progress` socket.io event. * @@ -30,7 +30,7 @@ export type AnyResult = GraphExecutionState['results'][string]; */ export type GeneratorProgressEvent = { graph_execution_state_id: string; - node: AnyInvocation; + node: BaseNode; source_node_id: string; progress_image?: ProgressImage; step: number; @@ -46,7 +46,7 @@ export type GeneratorProgressEvent = { */ export type InvocationCompleteEvent = { graph_execution_state_id: string; - node: AnyInvocation; + node: BaseNode; source_node_id: string; result: AnyResult; }; @@ -58,7 +58,7 @@ export type InvocationCompleteEvent = { */ export type InvocationErrorEvent = { graph_execution_state_id: string; - node: AnyInvocation; + node: BaseNode; source_node_id: string; error: string; }; @@ -70,7 +70,7 @@ export type InvocationErrorEvent = { */ export type InvocationStartedEvent = { graph_execution_state_id: string; - node: AnyInvocation; + node: BaseNode; source_node_id: string; }; diff --git a/invokeai/frontend/web/src/services/events/util/setEventListeners.ts b/invokeai/frontend/web/src/services/events/util/setEventListeners.ts new file mode 100644 index 0000000000..89bbc717a3 --- /dev/null +++ b/invokeai/frontend/web/src/services/events/util/setEventListeners.ts @@ -0,0 +1,175 @@ +import { MiddlewareAPI } from '@reduxjs/toolkit'; +import { AppDispatch, RootState } from 'app/store/store'; +import { getTimestamp } from 'common/util/getTimestamp'; +import { sessionCanceled } from 'services/thunks/session'; +import { Socket } from 'socket.io-client'; +import { + generatorProgress, + graphExecutionStateComplete, + invocationComplete, + invocationError, + invocationStarted, + socketConnected, + socketDisconnected, + socketSubscribed, +} from '../actions'; +import { ClientToServerEvents, ServerToClientEvents } from '../types'; +import { Logger } from 'roarr'; +import { JsonObject } from 'roarr/dist/types'; +import { + receivedResultImagesPage, + receivedUploadImagesPage, +} from 'services/thunks/gallery'; +import { receivedModels } from 'services/thunks/model'; +import { receivedOpenAPISchema } from 'services/thunks/schema'; + +type SetEventListenersArg = { + socket: Socket; + store: MiddlewareAPI; + log: Logger; +}; + +export const setEventListeners = (arg: SetEventListenersArg) => { + const { socket, store, log } = arg; + const { dispatch, getState } = store; + + /** + * Connect + */ + socket.on('connect', () => { + log.debug('Connected'); + + dispatch(socketConnected({ timestamp: getTimestamp() })); + + const { results, uploads, models, nodes, config, system } = getState(); + + const { disabledTabs } = config; + + // These thunks need to be dispatch in middleware; cannot handle in a reducer + if (!results.ids.length) { + dispatch(receivedResultImagesPage()); + } + + if (!uploads.ids.length) { + dispatch(receivedUploadImagesPage()); + } + + if (!models.ids.length) { + dispatch(receivedModels()); + } + + if (!nodes.schema && !disabledTabs.includes('nodes')) { + dispatch(receivedOpenAPISchema()); + } + + if (system.sessionId) { + log.debug( + { sessionId: system.sessionId }, + `Subscribed to existing session (${system.sessionId})` + ); + + socket.emit('subscribe', { session: system.sessionId }); + dispatch( + socketSubscribed({ + sessionId: system.sessionId, + timestamp: getTimestamp(), + }) + ); + } + }); + + /** + * Disconnect + */ + socket.on('disconnect', () => { + log.debug('Disconnected'); + dispatch(socketDisconnected({ timestamp: getTimestamp() })); + }); + + /** + * Invocation started + */ + socket.on('invocation_started', (data) => { + if (getState().system.canceledSession === data.graph_execution_state_id) { + log.trace( + { data, sessionId: data.graph_execution_state_id }, + `Ignored invocation started (${data.node.type}) for canceled session (${data.graph_execution_state_id})` + ); + return; + } + + log.info( + { data, sessionId: data.graph_execution_state_id }, + `Invocation started (${data.node.type})` + ); + dispatch(invocationStarted({ data, timestamp: getTimestamp() })); + }); + + /** + * Generator progress + */ + socket.on('generator_progress', (data) => { + if (getState().system.canceledSession === data.graph_execution_state_id) { + log.trace( + { data, sessionId: data.graph_execution_state_id }, + `Ignored generator progress (${data.node.type}) for canceled session (${data.graph_execution_state_id})` + ); + return; + } + + log.trace( + { data, sessionId: data.graph_execution_state_id }, + `Generator progress (${data.node.type})` + ); + dispatch(generatorProgress({ data, timestamp: getTimestamp() })); + }); + + /** + * Invocation error + */ + socket.on('invocation_error', (data) => { + log.error( + { data, sessionId: data.graph_execution_state_id }, + `Invocation error (${data.node.type})` + ); + dispatch(invocationError({ data, timestamp: getTimestamp() })); + }); + + /** + * Invocation complete + */ + socket.on('invocation_complete', (data) => { + log.info( + { data, sessionId: data.graph_execution_state_id }, + `Invocation complete (${data.node.type})` + ); + const sessionId = data.graph_execution_state_id; + + const { cancelType, isCancelScheduled } = getState().system; + const { shouldFetchImages } = getState().config; + + // Handle scheduled cancelation + if (cancelType === 'scheduled' && isCancelScheduled) { + dispatch(sessionCanceled({ sessionId })); + } + + dispatch( + invocationComplete({ + data, + timestamp: getTimestamp(), + shouldFetchImages, + }) + ); + }); + + /** + * Graph complete + */ + socket.on('graph_execution_state_complete', (data) => { + log.info( + { data, sessionId: data.graph_execution_state_id }, + `Graph execution state complete (${data.graph_execution_state_id})` + ); + dispatch(graphExecutionStateComplete({ data, timestamp: getTimestamp() })); + }); +}; diff --git a/invokeai/frontend/web/src/services/thunks/gallery.ts b/invokeai/frontend/web/src/services/thunks/gallery.ts index 3badee2549..f908cbddcb 100644 --- a/invokeai/frontend/web/src/services/thunks/gallery.ts +++ b/invokeai/frontend/web/src/services/thunks/gallery.ts @@ -1,8 +1,11 @@ -import { createAppAsyncThunk } from 'app/storeUtils'; +import { log } from 'app/logging/useLogger'; +import { createAppAsyncThunk } from 'app/store/storeUtils'; import { ImagesService } from 'services/api'; export const IMAGES_PER_PAGE = 20; +const galleryLog = log.child({ namespace: 'gallery' }); + export const receivedResultImagesPage = createAppAsyncThunk( 'results/receivedResultImagesPage', async (_arg, { getState }) => { @@ -12,6 +15,8 @@ export const receivedResultImagesPage = createAppAsyncThunk( perPage: IMAGES_PER_PAGE, }); + galleryLog.info({ response }, `Received ${response.items.length} results`); + return response; } ); @@ -25,6 +30,8 @@ export const receivedUploadImagesPage = createAppAsyncThunk( perPage: IMAGES_PER_PAGE, }); + galleryLog.info({ response }, `Received ${response.items.length} uploads`); + return response; } ); diff --git a/invokeai/frontend/web/src/services/thunks/image.ts b/invokeai/frontend/web/src/services/thunks/image.ts index 7288429ca0..a0d8f504b7 100644 --- a/invokeai/frontend/web/src/services/thunks/image.ts +++ b/invokeai/frontend/web/src/services/thunks/image.ts @@ -1,10 +1,13 @@ import { isFulfilled, isRejected } from '@reduxjs/toolkit'; -import { createAppAsyncThunk } from 'app/storeUtils'; +import { log } from 'app/logging/useLogger'; +import { createAppAsyncThunk } from 'app/store/storeUtils'; import { imageSelected } from 'features/gallery/store/gallerySlice'; -import { clamp } from 'lodash'; +import { clamp, isString } from 'lodash-es'; import { ImagesService } from 'services/api'; import { getHeaders } from 'services/util/getHeaders'; +const imagesLog = log.child({ namespace: 'image' }); + type ImageReceivedArg = Parameters<(typeof ImagesService)['getImage']>[0]; /** @@ -14,6 +17,9 @@ export const imageReceived = createAppAsyncThunk( 'api/imageReceived', async (arg: ImageReceivedArg, _thunkApi) => { const response = await ImagesService.getImage(arg); + + imagesLog.info({ arg, response }, 'Received image'); + return response; } ); @@ -29,6 +35,9 @@ export const thumbnailReceived = createAppAsyncThunk( 'api/thumbnailReceived', async (arg: ThumbnailReceivedArg, _thunkApi) => { const response = await ImagesService.getThumbnail(arg); + + imagesLog.info({ arg, response }, 'Received thumbnail'); + return response; } ); @@ -43,6 +52,12 @@ export const imageUploaded = createAppAsyncThunk( async (arg: ImageUploadedArg, _thunkApi) => { const response = await ImagesService.uploadImage(arg); const { location } = getHeaders(response); + + imagesLog.info( + { arg: '', response, location }, + `Image uploaded (${response.image_name})` + ); + return { response, location }; } ); @@ -70,7 +85,7 @@ export const imageDeleted = createAppAsyncThunk( // Determine which image should replace the deleted image, if the deleted image is the selected image. // Unfortunately, we have to do this here, because the resultsSlice and uploadsSlice cannot change // the selected image. - const selectedImageName = getState().gallery.selectedImageName; + const selectedImageName = getState().gallery.selectedImage?.name; if (selectedImageName === imageName) { const allIds = getState()[imageType].ids; @@ -89,13 +104,22 @@ export const imageDeleted = createAppAsyncThunk( const newSelectedImageId = filteredIds[newSelectedImageIndex]; - dispatch( - imageSelected(newSelectedImageId ? newSelectedImageId.toString() : '') - ); + if (newSelectedImageId) { + dispatch( + imageSelected({ name: newSelectedImageId as string, type: imageType }) + ); + } else { + dispatch(imageSelected()); + } } const response = await ImagesService.deleteImage(arg); + imagesLog.info( + { arg, response }, + `Image deleted (${arg.imageType} - ${arg.imageName})` + ); + return response; } ); diff --git a/invokeai/frontend/web/src/services/thunks/model.ts b/invokeai/frontend/web/src/services/thunks/model.ts index f5ee522593..84f7a24e81 100644 --- a/invokeai/frontend/web/src/services/thunks/model.ts +++ b/invokeai/frontend/web/src/services/thunks/model.ts @@ -1,14 +1,18 @@ -import { createAppAsyncThunk } from 'app/storeUtils'; +import { log } from 'app/logging/useLogger'; +import { createAppAsyncThunk } from 'app/store/storeUtils'; import { Model } from 'features/system/store/modelSlice'; -import { reduce } from 'lodash'; +import { reduce, size } from 'lodash-es'; import { ModelsService } from 'services/api'; +const models = log.child({ namespace: 'model' }); + export const IMAGES_PER_PAGE = 20; export const receivedModels = createAppAsyncThunk( 'models/receivedModels', - async (_arg) => { + async (_) => { const response = await ModelsService.listModels(); + const deserializedModels = reduce( response.models, (modelsAccumulator, model, modelName) => { @@ -19,6 +23,8 @@ export const receivedModels = createAppAsyncThunk( {} as Record ); + models.info({ response }, `Received ${size(response.models)} models`); + return deserializedModels; } ); diff --git a/invokeai/frontend/web/src/services/thunks/schema.ts b/invokeai/frontend/web/src/services/thunks/schema.ts index bd5135cdf9..bc93fa0fae 100644 --- a/invokeai/frontend/web/src/services/thunks/schema.ts +++ b/invokeai/frontend/web/src/services/thunks/schema.ts @@ -1,19 +1,20 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { parseSchema } from 'features/nodes/util/parseSchema'; +import { log } from 'app/logging/useLogger'; +import { parsedOpenAPISchema } from 'features/nodes/store/nodesSlice'; import { OpenAPIV3 } from 'openapi-types'; +const schemaLog = log.child({ namespace: 'schema' }); + export const receivedOpenAPISchema = createAsyncThunk( 'nodes/receivedOpenAPISchema', - async () => { + async (_, { dispatch }): Promise => { const response = await fetch(`openapi.json`); - const jsonData = (await response.json()) as OpenAPIV3.Document; + const openAPISchema = await response.json(); - console.debug('OpenAPI schema: ', jsonData); + schemaLog.info({ openAPISchema }, 'Received OpenAPI schema'); - const parsedSchema = parseSchema(jsonData); + dispatch(parsedOpenAPISchema(openAPISchema as OpenAPIV3.Document)); - console.debug('Parsed schema: ', parsedSchema); - - return parsedSchema; + return openAPISchema; } ); diff --git a/invokeai/frontend/web/src/services/thunks/session.ts b/invokeai/frontend/web/src/services/thunks/session.ts index 6267f66ac2..af03045967 100644 --- a/invokeai/frontend/web/src/services/thunks/session.ts +++ b/invokeai/frontend/web/src/services/thunks/session.ts @@ -1,28 +1,44 @@ -import { createAppAsyncThunk } from 'app/storeUtils'; +import { createAppAsyncThunk } from 'app/store/storeUtils'; import { SessionsService } from 'services/api'; import { buildLinearGraph as buildGenerateGraph } from 'features/nodes/util/linearGraphBuilder/buildLinearGraph'; import { isAnyOf, isFulfilled } from '@reduxjs/toolkit'; import { buildNodesGraph } from 'features/nodes/util/nodesGraphBuilder/buildNodesGraph'; +import { log } from 'app/logging/useLogger'; +import { serializeError } from 'serialize-error'; + +const sessionLog = log.child({ namespace: 'session' }); export const generateGraphBuilt = createAppAsyncThunk( 'api/generateGraphBuilt', - async (_, { dispatch, getState }) => { - const graph = buildGenerateGraph(getState()); - - dispatch(sessionCreated({ graph })); - - return graph; + async (_, { dispatch, getState, rejectWithValue }) => { + try { + const graph = buildGenerateGraph(getState()); + dispatch(sessionCreated({ graph })); + return graph; + } catch (err: any) { + sessionLog.error( + { error: serializeError(err) }, + 'Problem building graph' + ); + return rejectWithValue(err.message); + } } ); export const nodesGraphBuilt = createAppAsyncThunk( 'api/nodesGraphBuilt', - async (_, { dispatch, getState }) => { - const graph = buildNodesGraph(getState()); - - dispatch(sessionCreated({ graph })); - - return graph; + async (_, { dispatch, getState, rejectWithValue }) => { + try { + const graph = buildNodesGraph(getState()); + dispatch(sessionCreated({ graph })); + return graph; + } catch (err: any) { + sessionLog.error( + { error: serializeError(err) }, + 'Problem building graph' + ); + return rejectWithValue(err.message); + } } ); @@ -43,12 +59,12 @@ type SessionCreatedArg = { export const sessionCreated = createAppAsyncThunk( 'api/sessionCreated', async (arg: SessionCreatedArg, { dispatch, getState }) => { - console.log('Session created, graph: ', arg.graph); - const response = await SessionsService.createSession({ requestBody: arg.graph, }); + sessionLog.info({ arg, response }, `Session created (${response.id})`); + return response; } ); @@ -74,6 +90,8 @@ export const nodeAdded = createAppAsyncThunk( sessionId: arg.sessionId, }); + sessionLog.info({ arg, response }, `Node added (${response})`); + return response; } ); @@ -91,6 +109,8 @@ export const sessionInvoked = createAppAsyncThunk( all: true, }); + sessionLog.info({ arg, response }, `Session invoked (${sessionId})`); + return response; } ); @@ -111,6 +131,8 @@ export const sessionCanceled = createAppAsyncThunk( sessionId, }); + sessionLog.info({ arg, response }, `Session canceled (${sessionId})`); + return response; } ); @@ -127,6 +149,11 @@ export const listedSessions = createAppAsyncThunk( async (arg: SessionsListedArg, _thunkApi) => { const response = await SessionsService.listSessions(arg); + sessionLog.info( + { arg, response }, + `Sessions listed (${response.items.length})` + ); + return response; } ); diff --git a/invokeai/frontend/web/src/services/types/guards.ts b/invokeai/frontend/web/src/services/types/guards.ts index 5a9d891395..72cf1108fb 100644 --- a/invokeai/frontend/web/src/services/types/guards.ts +++ b/invokeai/frontend/web/src/services/types/guards.ts @@ -1,3 +1,5 @@ +import { Image } from 'app/types/invokeai'; +import { get, isObject, isString } from 'lodash-es'; import { GraphExecutionState, GraphInvocationOutput, @@ -6,6 +8,8 @@ import { PromptOutput, IterateInvocationOutput, CollectInvocationOutput, + ImageType, + ImageField, } from 'services/api'; export const isImageOutput = ( @@ -31,3 +35,16 @@ export const isIterateOutput = ( export const isCollectOutput = ( output: GraphExecutionState['results'][string] ): output is CollectInvocationOutput => output.type === 'collect_output'; + +export const isImageType = (t: unknown): t is ImageType => + isString(t) && ['results', 'uploads', 'intermediates'].includes(t); + +export const isImage = (image: unknown): image is Image => + isObject(image) && + isString(get(image, 'name')) && + isImageType(get(image, 'type')); + +export const isImageField = (imageField: unknown): imageField is ImageField => + isObject(imageField) && + isString(get(imageField, 'image_name')) && + isImageType(get(imageField, 'image_type')); diff --git a/invokeai/frontend/web/src/services/util/deserializeImageField.ts b/invokeai/frontend/web/src/services/util/deserializeImageField.ts index 0d50a78e49..adda71ccdd 100644 --- a/invokeai/frontend/web/src/services/util/deserializeImageField.ts +++ b/invokeai/frontend/web/src/services/util/deserializeImageField.ts @@ -1,4 +1,4 @@ -import { Image } from 'app/invokeai'; +import { Image } from 'app/types/invokeai'; import { ImageField, ImageType } from 'services/api'; import { AnyInvocation } from 'services/events/types'; diff --git a/invokeai/frontend/web/src/services/util/deserializeImageResponse.ts b/invokeai/frontend/web/src/services/util/deserializeImageResponse.ts index ec90fb6793..8d2a6df49e 100644 --- a/invokeai/frontend/web/src/services/util/deserializeImageResponse.ts +++ b/invokeai/frontend/web/src/services/util/deserializeImageResponse.ts @@ -1,4 +1,4 @@ -import { Image } from 'app/invokeai'; +import { Image } from 'app/types/invokeai'; import { parseInvokeAIMetadata } from 'common/util/parseMetadata'; import { ImageResponse } from 'services/api'; diff --git a/invokeai/frontend/web/src/theme/css/overlayscrollbars.css b/invokeai/frontend/web/src/theme/css/overlayscrollbars.css new file mode 100644 index 0000000000..b5acaca75d --- /dev/null +++ b/invokeai/frontend/web/src/theme/css/overlayscrollbars.css @@ -0,0 +1,48 @@ +.os-scrollbar { + /* The size of the scrollbar */ + /* --os-size: 0; */ + /* The axis-perpedicular padding of the scrollbar (horizontal: padding-y, vertical: padding-x) */ + /* --os-padding-perpendicular: 0; */ + /* The axis padding of the scrollbar (horizontal: padding-x, vertical: padding-y) */ + /* --os-padding-axis: 0; */ + /* The border radius of the scrollbar track */ + /* --os-track-border-radius: 0; */ + /* The background of the scrollbar track */ + --os-track-bg: rgba(0, 0, 0, 0.3); + /* The :hover background of the scrollbar track */ + --os-track-bg-hover: rgba(0, 0, 0, 0.3); + /* The :active background of the scrollbar track */ + --os-track-bg-active: rgba(0, 0, 0, 0.3); + /* The border of the scrollbar track */ + /* --os-track-border: none; */ + /* The :hover background of the scrollbar track */ + /* --os-track-border-hover: none; */ + /* The :active background of the scrollbar track */ + /* --os-track-border-active: none; */ + /* The border radius of the scrollbar handle */ + /* --os-handle-border-radius: 0; */ + /* The background of the scrollbar handle */ + --os-handle-bg: var(--invokeai-colors-accent-500); + /* The :hover background of the scrollbar handle */ + --os-handle-bg-hover: var(--invokeai-colors-accent-450); + /* The :active background of the scrollbar handle */ + --os-handle-bg-active: var(--invokeai-colors-accent-400); + /* The border of the scrollbar handle */ + /* --os-handle-border: none; */ + /* The :hover border of the scrollbar handle */ + /* --os-handle-border-hover: none; */ + /* The :active border of the scrollbar handle */ + /* --os-handle-border-active: none; */ + /* The min size of the scrollbar handle */ + --os-handle-min-size: 50px; + /* The max size of the scrollbar handle */ + /* --os-handle-max-size: none; */ + /* The axis-perpedicular size of the scrollbar handle (horizontal: height, vertical: width) */ + /* --os-handle-perpendicular-size: 100%; */ + /* The :hover axis-perpedicular size of the scrollbar handle (horizontal: height, vertical: width) */ + /* --os-handle-perpendicular-size-hover: 100%; */ + /* The :active axis-perpedicular size of the scrollbar handle (horizontal: height, vertical: width) */ + /* --os-handle-perpendicular-size-active: 100%; */ + /* Increases the interactive area of the scrollbar handle. */ + /* --os-handle-interactive-area-offset: 0; */ +} \ No newline at end of file diff --git a/invokeai/frontend/web/src/theme/theme.ts b/invokeai/frontend/web/src/theme/theme.ts index 1ac868c272..c5b127f040 100644 --- a/invokeai/frontend/web/src/theme/theme.ts +++ b/invokeai/frontend/web/src/theme/theme.ts @@ -1,7 +1,7 @@ import { ThemeOverride } from '@chakra-ui/react'; import type { StyleFunctionProps } from '@chakra-ui/styled-system'; -import { invokeAIThemeColors } from './colors/invokeAI'; +import { invokeAIThemeColors } from 'theme/colors/invokeAI'; import { accordionTheme } from './components/accordion'; import { buttonTheme } from './components/button'; import { checkboxTheme } from './components/checkbox'; diff --git a/invokeai/frontend/web/tsconfig.json b/invokeai/frontend/web/tsconfig.json index 9731a64d3d..8276f461eb 100644 --- a/invokeai/frontend/web/tsconfig.json +++ b/invokeai/frontend/web/tsconfig.json @@ -14,10 +14,13 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "baseUrl": "src", - "jsx": "react-jsx" + "jsx": "react-jsx", + "baseUrl": "./", + "paths": { + "*": ["./src/*"] + } }, - "include": ["src", "index.d.ts"], - "exclude": ["src/services/fixtures/*"], + "include": ["src/**/*.ts", "src/**/*.tsx", "*.d.ts"], + "exclude": ["src/services/fixtures/*", "node_modules", "dist"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/invokeai/frontend/web/tsconfig.node.json b/invokeai/frontend/web/tsconfig.node.json index a375708f74..4b04192240 100644 --- a/invokeai/frontend/web/tsconfig.node.json +++ b/invokeai/frontend/web/tsconfig.node.json @@ -3,8 +3,12 @@ "composite": true, "module": "ESNext", "moduleResolution": "Node", - "allowSyntheticDefaultImports": true, - "baseUrl": "src" + "allowSyntheticDefaultImports": true }, - "include": ["vite.config.ts"] + "include": [ + "vite.config.ts", + "./config/vite.app.config.ts", + "./config/vite.package.config.ts", + "./config/vite.common.config.ts" + ] } diff --git a/invokeai/frontend/web/vite.config.ts b/invokeai/frontend/web/vite.config.ts index 2128593f10..6491eb72e7 100644 --- a/invokeai/frontend/web/vite.config.ts +++ b/invokeai/frontend/web/vite.config.ts @@ -1,82 +1,11 @@ -import react from '@vitejs/plugin-react-swc'; -import { visualizer } from 'rollup-plugin-visualizer'; -import { defineConfig, PluginOption } from 'vite'; -import eslint from 'vite-plugin-eslint'; -import tsconfigPaths from 'vite-tsconfig-paths'; +import { defineConfig } from 'vite'; +import { appConfig } from './config/vite.app.config'; +import { packageConfig } from './config/vite.package.config'; -// https://vitejs.dev/config/ export default defineConfig(({ mode }) => { - const common = { - base: '', - plugins: [ - react(), - eslint(), - tsconfigPaths(), - visualizer() as unknown as PluginOption, - ], - server: { - // Proxy HTTP requests to the flask server - proxy: { - '/outputs': { - target: 'http://127.0.0.1:9090/outputs', - changeOrigin: true, - rewrite: (path) => path.replace(/^\/outputs/, ''), - }, - '/upload': { - target: 'http://127.0.0.1:9090/upload', - changeOrigin: true, - rewrite: (path) => path.replace(/^\/upload/, ''), - }, - '/flaskwebgui-keep-server-alive': { - target: 'http://127.0.0.1:9090/flaskwebgui-keep-server-alive', - changeOrigin: true, - rewrite: (path) => - path.replace(/^\/flaskwebgui-keep-server-alive/, ''), - }, - // Proxy socket.io to the flask-socketio server - '/socket.io': { - target: 'ws://127.0.0.1:9090', - ws: true, - }, - // Proxy socket.io to the nodes socketio server - '/ws/socket.io': { - target: 'ws://127.0.0.1:9090', - ws: true, - }, - // Proxy openapi schema definiton - '/openapi.json': { - target: 'http://127.0.0.1:9090/openapi.json', - rewrite: (path) => path.replace(/^\/openapi.json/, ''), - changeOrigin: true, - }, - // proxy nodes api - '/api/v1': { - target: 'http://127.0.0.1:9090/api/v1', - rewrite: (path) => path.replace(/^\/api\/v1/, ''), - changeOrigin: true, - }, - }, - }, - build: { - /** - * We need to polyfill for Array.prototype.findLast(); the polyfill plugin above - * overrides any target specified here. - */ - // target: 'esnext', - chunkSizeWarningLimit: 1500, // we don't really care about chunk size, - }, - }; - if (mode == 'development') { - return { - ...common, - build: { - ...common.build, - // sourcemap: true, // this can be enabled if needed, it adds ovwer 15MB to the commit - }, - }; - } else { - return { - ...common, - }; + if (mode === 'package') { + return packageConfig; } + + return appConfig; }); diff --git a/invokeai/frontend/web/yarn.lock b/invokeai/frontend/web/yarn.lock index 7cc6ab769b..59a2607db7 100644 --- a/invokeai/frontend/web/yarn.lock +++ b/invokeai/frontend/web/yarn.lock @@ -13,18 +13,18 @@ js-yaml "^4.1.0" "@babel/code-frame@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== dependencies: "@babel/highlight" "^7.18.6" "@babel/helper-module-imports@^7.16.7": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" + integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.21.4" "@babel/helper-string-parser@^7.19.4": version "7.19.4" @@ -45,10 +45,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.0.0": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" - integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== +"@babel/parser@^7.0.0", "@babel/parser@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" + integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== "@babel/runtime@^7.0.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.21.0" @@ -57,35 +57,42 @@ dependencies: regenerator-runtime "^0.13.11" -"@babel/types@^7.18.6", "@babel/types@^7.4": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" - integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== +"@babel/runtime@^7.1.2": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" + integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/types@^7.21.4", "@babel/types@^7.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4" + integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA== dependencies: "@babel/helper-string-parser" "^7.19.4" "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@chakra-ui/accordion@2.1.9": - version "2.1.9" - resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.1.9.tgz#20fa86d94dc034251df2f7c8595ae4dd541a29d9" - integrity sha512-a9CKIAUHezc0f5FR/SQ4GVxnWuIb2HbDTxTEKTp58w/J9pecIbJaNrJ5TUZ0MVbDU9jkgO9RsZ29jkja8PomAw== +"@chakra-ui/accordion@2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.1.11.tgz#c6df0100c543645d0631df3aefde2ea2b8ed6313" + integrity sha512-mfVPmqETp9pyRDHJ33AdF19oHv/LyxVzQJtlxUByuvs8Cj9QQZ2LQLg5kejm+b3mj03A7A6yfbuo3RNaI4Bhsg== dependencies: - "@chakra-ui/descendant" "3.0.13" + "@chakra-ui/descendant" "3.0.14" "@chakra-ui/icon" "3.0.16" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-controllable-state" "2.0.8" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/transition" "2.0.15" + "@chakra-ui/transition" "2.0.16" -"@chakra-ui/alert@2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-2.0.17.tgz#b129732ec308db6a6a1afa7c06a6595ad853c967" - integrity sha512-0Y5vw+HkeXpwbL1roVpSSNM6luMRmUbwduUSHEA4OnX1ismvsDb1ZBfpi4Vxp6w8euJ2Uj6df3krbd5tbCP6tg== +"@chakra-ui/alert@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-2.1.0.tgz#7a234ac6426231b39243088648455cbcf1cbdf24" + integrity sha512-OcfHwoXI5VrmM+tHJTHT62Bx6TfyfCxSa0PWUOueJzSyhlUOKBND5we6UtrOB7D0jwX45qKKEDJOLG5yCG21jQ== dependencies: "@chakra-ui/icon" "3.0.16" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/spinner" "2.0.13" @@ -99,23 +106,23 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/anatomy/-/anatomy-2.1.2.tgz#ea66b1841e7195da08ddc862daaa3f3e56e565f5" integrity sha512-pKfOS/mztc4sUXHNc8ypJ1gPWSolWT770jrgVRfolVbYlki8y5Y+As996zMF6k5lewTu6j9DQequ7Cc9a69IVQ== -"@chakra-ui/avatar@2.2.5": - version "2.2.5" - resolved "https://registry.yarnpkg.com/@chakra-ui/avatar/-/avatar-2.2.5.tgz#50eb7cc5a172d394b301fa0abd5f607b7f5d3563" - integrity sha512-TEHXuGE79+fEn61qJ7J/A0Ec+WjyNwobrDTATcLg9Zx2/WEMmZNfrWIAlI5ANQAwVbdSWeGVbyoLAK5mbcrE0A== +"@chakra-ui/avatar@2.2.9": + version "2.2.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/avatar/-/avatar-2.2.9.tgz#7dc21f432f3ab52d05c3ac66641412896cd08b19" + integrity sha512-fjO25iNeMxSZKYGvbAqdMjsRus9Hgvhb+Ux8jNwKcfg47nqT+wVieMqsPdpQ0ggAuh1872oVvg2q1GfDdieMmA== dependencies: - "@chakra-ui/image" "2.0.15" + "@chakra-ui/image" "2.0.16" "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/breadcrumb@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@chakra-ui/breadcrumb/-/breadcrumb-2.1.4.tgz#0d249dc2a92639bd2bf46d097dd5445112bd2367" - integrity sha512-vyBx5TAxPnHhb0b8nyRGfqyjleD//9mySFhk96c9GL+T6YDO4swHw5y/kvDv3Ngc/iRwJ9hdI49PZKwPxLqsEg== +"@chakra-ui/breadcrumb@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@chakra-ui/breadcrumb/-/breadcrumb-2.1.5.tgz#a43b22cc8005291a615696a8c88efc37064562f3" + integrity sha512-p3eQQrHQBkRB69xOmNyBJqEdfCrMt+e0eOH+Pm/DjFWfIVIbnIaFbmDCeWClqlLa21Ypc6h1hR9jEmvg8kmOog== dependencies: "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/breakpoint-utils@2.0.8": @@ -125,12 +132,12 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/button@2.0.16": - version "2.0.16" - resolved "https://registry.yarnpkg.com/@chakra-ui/button/-/button-2.0.16.tgz#ff315b57ee47c3511a6507fcfb6f00bb93e2ac7d" - integrity sha512-NjuTKa7gNhnGSUutKuTc8HoAOe9WWIigpciBG7yj3ok67kg8bXtSzPyQFZlgTY6XGdAckWTT+Do4tvhwa5LA+g== +"@chakra-ui/button@2.0.18": + version "2.0.18" + resolved "https://registry.yarnpkg.com/@chakra-ui/button/-/button-2.0.18.tgz#c13d2e404e22a9873ba5373fde494bedafe32fdd" + integrity sha512-E3c99+lOm6ou4nQVOTLkG+IdOPMjsQK+Qe7VyP8A/xeAMFONuibrWPRPpprr4ZkB4kEoLMfNuyH2+aEza3ScUA== dependencies: - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/spinner" "2.0.13" @@ -142,13 +149,13 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/checkbox@2.2.10": - version "2.2.10" - resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.2.10.tgz#e4f773e7d2464f1d6e9d18dd88b679290cb33171" - integrity sha512-vzxEjw99qj7loxAdP1WuHNt4EAvj/t6cc8oxyOB2mEvkAzhxI34rLR+3zWDuHWsmhyUO+XEDh4FiWdR+DK5Siw== +"@chakra-ui/checkbox@2.2.15": + version "2.2.15" + resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.2.15.tgz#e5ff65159f698d50edecee6b661b87e341eace70" + integrity sha512-Ju2yQjX8azgFa5f6VLPuwdGYobZ+rdbcYqjiks848JvPc75UsPhpS05cb4XlrKT7M16I8txDA5rPJdqqFicHCA== dependencies: - "@chakra-ui/form-control" "2.0.17" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/form-control" "2.0.18" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-callback-ref" "2.0.7" "@chakra-ui/react-use-controllable-state" "2.0.8" @@ -157,12 +164,12 @@ "@chakra-ui/react-use-update-effect" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/visually-hidden" "2.0.15" - "@zag-js/focus-visible" "0.2.1" + "@zag-js/focus-visible" "0.2.2" -"@chakra-ui/cli@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/cli/-/cli-2.3.0.tgz#66f229b91c53c9738fb1592ba8b0bc4b1c55f16f" - integrity sha512-63Xs4aMYxc17U8GfyPuQnAv8qRg/z2oCd8lgAdn6m755lvQ0e5RZ+mNecfJN1uNXRs3BmKXWnmGh1NvfQ6q1UQ== +"@chakra-ui/cli@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/cli/-/cli-2.4.0.tgz#720b6cd36b96ebc13894a659c566c3a31dd87961" + integrity sha512-Ko8bnQ4lbSwoldHyf2aHANuITL09XTlLJFAKCvgN/e/G+ZuL9ciHnITNG9nchLZKiK6mNj7o8pVfRbxkLm5xVw== dependencies: "@swc/core" "^1.2.177" chokidar "^3.5.3" @@ -214,17 +221,17 @@ "@chakra-ui/react-use-callback-ref" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/css-reset@2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.0.12.tgz#6eebcbe9e971facd215e174e063ace29f647a045" - integrity sha512-Q5OYIMvqTl2vZ947kIYxcS5DhQXeStB84BzzBd6C10wOx1gFUu9pL+jLpOnHR3hhpWRMdX5o7eT+gMJWIYUZ0Q== +"@chakra-ui/css-reset@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.1.1.tgz#c61f3d2103c13e62a86fd2d359682092e961852c" + integrity sha512-jwEOfIAWmQsnChHQTW/eRE+dfE4MjmhvSvoUug5nkV1pI7veC/20noFlIZxzi82EbiQI8Fs0+Jnusgxr2yaOHA== -"@chakra-ui/descendant@3.0.13": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@chakra-ui/descendant/-/descendant-3.0.13.tgz#e883a2233ee07fe1ae6c014567824c0f79df11cf" - integrity sha512-9nzxZVxUSMc4xPL5fSaRkEOQjDQWUGjGvrZI7VzWk9eq63cojOtIxtWMSW383G9148PzWJjJYt30Eud5tdZzlg== +"@chakra-ui/descendant@3.0.14": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@chakra-ui/descendant/-/descendant-3.0.14.tgz#fe8bac3f0e1ffe562e3e73eac393dbf222d57e13" + integrity sha512-+Ahvp9H4HMpfScIv9w1vaecGz7qWAaK1YFHHolz/SIsGLaLGlbdp+5UNabQC7L6TUnzzJDQDxzwif78rTD7ang== dependencies: - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/dom-utils@2.0.6": @@ -232,12 +239,12 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/dom-utils/-/dom-utils-2.0.6.tgz#68f49f3b4a0bdebd5e416d6fd2c012c9ad64b76a" integrity sha512-PVtDkPrDD5b8aoL6Atg7SLjkwhWb7BwMcLOF1L449L3nZN+DAO3nyAh6iUhZVJyunELj9d0r65CDlnMREyJZmA== -"@chakra-ui/editable@2.0.19": - version "2.0.19" - resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-2.0.19.tgz#1af2fe3c215111f61f7872fb5f599f4d8da24e7d" - integrity sha512-YxRJsJ2JQd42zfPBgTKzIhg1HugT+gfQz1ZosmUN+IZT9YZXL2yodHTUz6Lee04Vc/CdEqgBFLuREXEUNBfGtA== +"@chakra-ui/editable@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-3.0.0.tgz#b61d4fba5a581b41856ebd85fd5d17c96a224323" + integrity sha512-q/7C/TM3iLaoQKlEiM8AY565i9NoaXtS6N6N4HWIEL5mZJPbMeHKxrCHUZlHxYuQJqFOGc09ZPD9fAFx1GkYwQ== dependencies: - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-callback-ref" "2.0.7" "@chakra-ui/react-use-controllable-state" "2.0.8" @@ -260,21 +267,21 @@ "@chakra-ui/dom-utils" "2.0.6" react-focus-lock "^2.9.2" -"@chakra-ui/form-control@2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-2.0.17.tgz#2f710325e77ce35067337616d440f903b137bdd5" - integrity sha512-34ptCaJ2LNvQNOlB6MAKsmH1AkT1xo7E+3Vw10Urr81yTOjDTM/iU6vG3JKPfRDMyXeowPjXmutlnuk72SSjRg== +"@chakra-ui/form-control@2.0.18": + version "2.0.18" + resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-2.0.18.tgz#1923f293afde70b2b07ca731d98fef3660098c56" + integrity sha512-I0a0jG01IAtRPccOXSNugyRdUAe8Dy40ctqedZvznMweOXzbMCF1m+sHPLdWeWC/VI13VoAispdPY0/zHOdjsQ== dependencies: "@chakra-ui/icon" "3.0.16" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/hooks@2.1.6": - version "2.1.6" - resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.1.6.tgz#4d829535868148912ef7a4ff274e03b8d1cf7c72" - integrity sha512-oMSOeoOF6/UpwTVlDFHSROAA4hPY8WgJ0erdHs1ZkuwAwHv7UzjDkvrb6xYzAAH9qHoFzc5RIBm6jVoh3LCc+Q== +"@chakra-ui/hooks@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.2.0.tgz#f779bf85542dacd607abe7e67f4571cf8a1102fa" + integrity sha512-GZE64mcr20w+3KbCUPqQJHHmiFnX5Rcp8jS3YntGA4D5X2qU85jka7QkjfBwv/iduZ5Ei0YpCMYGCpi91dhD1Q== dependencies: "@chakra-ui/react-utils" "2.0.12" "@chakra-ui/utils" "2.0.15" @@ -288,42 +295,42 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/icons@^2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.0.17.tgz#625a46d169707aad36d65c04a4626a422f92e5ae" - integrity sha512-HMJP0WrJgAmFR9+Xh/CBH0nVnGMsJ4ZC8MK6tMgxPKd9/muvn0I4hsicHqdPlLpmB0TlxlhkBAKaVMtOdz6F0w== +"@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== dependencies: "@chakra-ui/icon" "3.0.16" -"@chakra-ui/image@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@chakra-ui/image/-/image-2.0.15.tgz#7f275f8f3edbb420e0613afd5023ad9cf442d09d" - integrity sha512-w2rElXtI3FHXuGpMCsSklus+pO1Pl2LWDwsCGdpBQUvGFbnHfl7MftQgTlaGHeD5OS95Pxva39hKrA2VklKHiQ== +"@chakra-ui/image@2.0.16": + version "2.0.16" + resolved "https://registry.yarnpkg.com/@chakra-ui/image/-/image-2.0.16.tgz#0e3a48c3caa6dc1d340502ea96766d9ef31e27e8" + integrity sha512-iFypk1slgP3OK7VIPOtkB0UuiqVxNalgA59yoRM43xLIeZAEZpKngUVno4A2kFS61yKN0eIY4hXD3Xjm+25EJA== dependencies: "@chakra-ui/react-use-safe-layout-effect" "2.0.5" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/input@2.0.20": - version "2.0.20" - resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-2.0.20.tgz#8db3ec46b52be901c94599b3659a9003bdb2dd07" - integrity sha512-ypmsy4n4uNBVgn6Gd24Zrpi+qRf/T9WEzWkysuYC9Qfxo+i7yuf3snp7XmBy8KSGVSiXE11eO8ZN5oCg6Xg0jg== +"@chakra-ui/input@2.0.22": + version "2.0.22" + resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-2.0.22.tgz#4c1f166f53555c698bb65950772314f78c147450" + integrity sha512-dCIC0/Q7mjZf17YqgoQsnXn0bus6vgriTRn8VmxOc+WcVl+KBSTBWujGrS5yu85WIFQ0aeqQvziDnDQybPqAbA== dependencies: - "@chakra-ui/form-control" "2.0.17" - "@chakra-ui/object-utils" "2.0.8" + "@chakra-ui/form-control" "2.0.18" + "@chakra-ui/object-utils" "2.1.0" "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/layout@2.1.16": - version "2.1.16" - resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-2.1.16.tgz#9d90f25cf9f0537d19cd36a417f7ddc1461e8591" - integrity sha512-QFS3feozIGsvB0H74lUocev55aRF26eNrdmhfJifwikZAiq+zzZAMdBdNU9UJhHClnMOU8/iGZ0MF7ti4zQS1A== +"@chakra-ui/layout@2.1.19": + version "2.1.19" + resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-2.1.19.tgz#4cd07c64239bf83c89a49487fdbd44227737b4eb" + integrity sha512-g7xMVKbQFCODwKCkEF4/OmdPsr/fAavWUV+DGc1ZWVPdroUlg1FGTpK9bOTwkC/gnko7cMClILA+BIPR3Ylu9Q== dependencies: "@chakra-ui/breakpoint-utils" "2.0.8" "@chakra-ui/icon" "3.0.16" - "@chakra-ui/object-utils" "2.0.8" + "@chakra-ui/object-utils" "2.1.0" "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/lazy-utils@2.0.5": @@ -345,52 +352,52 @@ "@chakra-ui/react-env" "3.0.0" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/menu@2.1.9": - version "2.1.9" - resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.1.9.tgz#2f3239a9b2855fd77fc317d9e6b904c1ad50d7c6" - integrity sha512-ue5nD4QJcl3H3UwN0zZNJmH89XUebnvEdW6THAUL41hDjJ0J/Fjpg9Sgzwug2aBbBXBNbVMsUuhcCj6x91d+IQ== +"@chakra-ui/menu@2.1.13": + version "2.1.13" + resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.1.13.tgz#c76bab6ba1daf33974e3467fd590319d1973bc3b" + integrity sha512-O7ESUIxbqWINRaO9jkPbZ8vJVW+lxZIZ9K0q828XgYBMh5o7BS82XhT7li7CxWaSQNqBxS4XE9BU7btp1ADMrQ== dependencies: "@chakra-ui/clickable" "2.0.14" - "@chakra-ui/descendant" "3.0.13" + "@chakra-ui/descendant" "3.0.14" "@chakra-ui/lazy-utils" "2.0.5" "@chakra-ui/popper" "3.0.13" "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-animation-state" "2.0.8" "@chakra-ui/react-use-controllable-state" "2.0.8" "@chakra-ui/react-use-disclosure" "2.0.8" - "@chakra-ui/react-use-focus-effect" "2.0.9" + "@chakra-ui/react-use-focus-effect" "2.0.10" "@chakra-ui/react-use-merge-refs" "2.0.7" - "@chakra-ui/react-use-outside-click" "2.0.7" + "@chakra-ui/react-use-outside-click" "2.1.0" "@chakra-ui/react-use-update-effect" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/transition" "2.0.15" + "@chakra-ui/transition" "2.0.16" -"@chakra-ui/modal@2.2.9": - version "2.2.9" - resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-2.2.9.tgz#aad65a2c60aa974e023f8b3facc0e79eb742e006" - integrity sha512-nTfNp7XsVwn5+xJOtstoFA8j0kq/9sJj7KesyYzjEDaMKvCZvIOntRYowoydho43jb4+YC7ebKhp0KOIINS0gg== +"@chakra-ui/modal@2.2.11": + version "2.2.11" + resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-2.2.11.tgz#8a964288759f3d681e23bfc3a837a3e2c7523f8e" + integrity sha512-2J0ZUV5tEzkPiawdkgPz6bmex7NXAde1VXooMwdvK+vuT8PV3U61yorTJOZVLdw7TjjI1Yo94mzsp6UwBud43Q== dependencies: "@chakra-ui/close-button" "2.0.17" "@chakra-ui/focus-lock" "2.0.16" - "@chakra-ui/portal" "2.0.15" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/portal" "2.0.16" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/transition" "2.0.15" + "@chakra-ui/transition" "2.0.16" aria-hidden "^1.2.2" react-remove-scroll "^2.5.5" -"@chakra-ui/number-input@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-2.0.18.tgz#072a00ef869ebafa4960cfdee8caae8208864289" - integrity sha512-cPkyAFFHHzeFBselrT1BtjlzMkJ6TKrTDUnHFlzqXy6aqeXuhrjFhMfXucjedSpOqedsP9ZbKFTdIAhu9DdL/A== +"@chakra-ui/number-input@2.0.19": + version "2.0.19" + resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-2.0.19.tgz#82d4522036904c04d07e7050822fc522f9b32233" + integrity sha512-HDaITvtMEqOauOrCPsARDxKD9PSHmhWywpcyCSOX0lMe4xx2aaGhU0QQFhsJsykj8Er6pytMv6t0KZksdDv3YA== dependencies: "@chakra-ui/counter" "2.0.14" - "@chakra-ui/form-control" "2.0.17" + "@chakra-ui/form-control" "2.0.18" "@chakra-ui/icon" "3.0.16" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-callback-ref" "2.0.7" "@chakra-ui/react-use-event-listener" "2.0.7" @@ -405,36 +412,36 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/number-utils/-/number-utils-2.0.7.tgz#aaee979ca2fb1923a0373a91619473811315db11" integrity sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg== -"@chakra-ui/object-utils@2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@chakra-ui/object-utils/-/object-utils-2.0.8.tgz#307f927f6434f99feb32ba92bdf451a6b59a6199" - integrity sha512-2upjT2JgRuiupdrtBWklKBS6tqeGMA77Nh6Q0JaoQuH/8yq+15CGckqn3IUWkWoGI0Fg3bK9LDlbbD+9DLw95Q== +"@chakra-ui/object-utils@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/object-utils/-/object-utils-2.1.0.tgz#a4ecf9cea92f1de09f5531f53ffdc41e0b19b6c3" + integrity sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ== -"@chakra-ui/pin-input@2.0.19": - version "2.0.19" - resolved "https://registry.yarnpkg.com/@chakra-ui/pin-input/-/pin-input-2.0.19.tgz#f9b196174f0518feec5c1ee3fcaf2134c301148a" - integrity sha512-6O7s4vWz4cqQ6zvMov9sYj6ZqWAsTxR/MNGe3DNgu1zWQg8veNCYtj1rNGhNS3eZNUMAa8uM2dXIphGTP53Xow== +"@chakra-ui/pin-input@2.0.20": + version "2.0.20" + resolved "https://registry.yarnpkg.com/@chakra-ui/pin-input/-/pin-input-2.0.20.tgz#5bf115bf4282b69fc6532a9c542cbf41f815d200" + integrity sha512-IHVmerrtHN8F+jRB3W1HnMir1S1TUCWhI7qDInxqPtoRffHt6mzZgLZ0izx8p1fD4HkW4c1d4/ZLEz9uH9bBRg== dependencies: - "@chakra-ui/descendant" "3.0.13" + "@chakra-ui/descendant" "3.0.14" "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-controllable-state" "2.0.8" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/popover@2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.1.8.tgz#e906ce0533693d735b6e13a3a6ffe16d8e0a9ab4" - integrity sha512-ob7fAz+WWmXIq7iGHVB3wDKzZTj+T+noYBT/U1Q+jIf+jMr2WOpJLTfb0HTZcfhvn4EBFlfBg7Wk5qbXNaOn7g== +"@chakra-ui/popover@2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.1.10.tgz#0079d4dbbabaf1a549c2385e3580d710de7c45e2" + integrity sha512-UCEW+zp2GEuNYvyK42+cQECSMSBFWcA0CD7Ip6TUL32BLF8EkYz5U5Gdx5Nhd/mlSE2lxo7c72/LOQd0emsO/A== dependencies: "@chakra-ui/close-button" "2.0.17" "@chakra-ui/lazy-utils" "2.0.5" "@chakra-ui/popper" "3.0.13" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-animation-state" "2.0.8" "@chakra-ui/react-use-disclosure" "2.0.8" - "@chakra-ui/react-use-focus-effect" "2.0.9" + "@chakra-ui/react-use-focus-effect" "2.0.10" "@chakra-ui/react-use-focus-on-pointer-down" "2.0.6" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" @@ -448,53 +455,53 @@ "@chakra-ui/react-use-merge-refs" "2.0.7" "@popperjs/core" "^2.9.3" -"@chakra-ui/portal@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@chakra-ui/portal/-/portal-2.0.15.tgz#21e1f97c4407fc15df8c365cb5cf799dac73ce41" - integrity sha512-z8v7K3j1/nMuBzp2+wRIIw7s/eipVtnXLdjK5yqbMxMRa44E8Mu5VNJLz3aQFLHXEUST+ifqrjImQeli9do6LQ== +"@chakra-ui/portal@2.0.16": + version "2.0.16" + resolved "https://registry.yarnpkg.com/@chakra-ui/portal/-/portal-2.0.16.tgz#e5ce3f9d9e559f17a95276e0c006d0e9b7703442" + integrity sha512-bVID0qbQ0l4xq38LdqAN4EKD4/uFkDnXzFwOlviC9sl0dNhzICDb1ltuH/Adl1d2HTMqyN60O3GO58eHy7plnQ== dependencies: - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-safe-layout-effect" "2.0.5" -"@chakra-ui/progress@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-2.1.5.tgz#eb6a47adf2bff93971262d163461d390782a04ff" - integrity sha512-jj5Vp4lxUchuwp4RPCepM0yAyKi344bgsOd3Apd+ldxclDcewPc82fbwDu7g/Xv27LqJkT+7E/SlQy04wGrk0g== +"@chakra-ui/progress@2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-2.1.6.tgz#398db20440979c37adb0a34821f805ae3471873b" + integrity sha512-hHh5Ysv4z6bK+j2GJbi/FT9CVyto2PtNUNwBmr3oNMVsoOUMoRjczfXvvYqp0EHr9PCpxqrq7sRwgQXUzhbDSw== dependencies: - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" -"@chakra-ui/provider@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.1.2.tgz#b025cb718826b003b3c9535b6961e8f3be70ebd5" - integrity sha512-4lLlz8QuJv00BhfyKzWpzfoti9MDOdJ/MqXixJV/EZ02RMBOdE9qy9bSz/WckPC2MVhtRUuwMkxH+0QY21PXuw== +"@chakra-ui/provider@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.2.3.tgz#a061891c26b38a1ac5a30e92e5c0b249ad1bc0cd" + integrity sha512-vLvs69tkq3D7sjmGV5ry8c93TKK0K5XfT2hTWr0QRPRvsccDSoEbYtCI8lb36kOZdXhYa/K8nd81vM+UBp0tzw== dependencies: - "@chakra-ui/css-reset" "2.0.12" - "@chakra-ui/portal" "2.0.15" + "@chakra-ui/css-reset" "2.1.1" + "@chakra-ui/portal" "2.0.16" "@chakra-ui/react-env" "3.0.0" - "@chakra-ui/system" "2.5.1" + "@chakra-ui/system" "2.5.6" "@chakra-ui/utils" "2.0.15" -"@chakra-ui/radio@2.0.19": - version "2.0.19" - resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-2.0.19.tgz#8d5c02eae8eddbced4476b1b50921ade62f0a744" - integrity sha512-PlJiV59eGSmeKP4v/4+ccQUWGRd0cjPKkj/p3L+UbOf8pl9dWm8y9kIeL5TYbghQSDv0nzkrH4+yMnnDTZjdMQ== +"@chakra-ui/radio@2.0.22": + version "2.0.22" + resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-2.0.22.tgz#fad0ce7c9ba4051991ed517cac4cfe526d6d47d9" + integrity sha512-GsQ5WAnLwivWl6gPk8P1x+tCcpVakCt5R5T0HumF7DGPXKdJbjS+RaFySrbETmyTJsKY4QrfXn+g8CWVrMjPjw== dependencies: - "@chakra-ui/form-control" "2.0.17" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/form-control" "2.0.18" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" - "@zag-js/focus-visible" "0.2.1" + "@zag-js/focus-visible" "0.2.2" "@chakra-ui/react-children-utils@2.0.6": version "2.0.6" resolved "https://registry.yarnpkg.com/@chakra-ui/react-children-utils/-/react-children-utils-2.0.6.tgz#6c480c6a60678fcb75cb7d57107c7a79e5179b92" integrity sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA== -"@chakra-ui/react-context@2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-context/-/react-context-2.0.7.tgz#f79a2b072d04d4280ec8799dc03a8a1af521ca2e" - integrity sha512-i7EGmSU+h2GB30cwrKB4t1R5BMHyGoJM5L2Zz7b+ZUX4aAqyPcfe97wPiQB6Rgr1ImGXrUeov4CDVrRZ2FPgLQ== +"@chakra-ui/react-context@2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-context/-/react-context-2.0.8.tgz#5e0ed33ac3995875a21dea0e12b0ee5fc4c2e3cc" + integrity sha512-tRTKdn6lCTXM6WPjSokAAKCw2ioih7Eg8cNgaYRSwKBck8nkz9YqxgIIEj3dJD7MGtpl24S/SNI98iRWkRwR/A== "@chakra-ui/react-env@3.0.0": version "3.0.0" @@ -542,10 +549,10 @@ dependencies: "@chakra-ui/react-use-callback-ref" "2.0.7" -"@chakra-ui/react-use-focus-effect@2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.0.9.tgz#9f94c0cb54e6e14ac9f048ca4d32a1fdcea067c1" - integrity sha512-20nfNkpbVwyb41q9wxp8c4jmVp6TUGAPE3uFTDpiGcIOyPW5aecQtPmTXPMJH+2aa8Nu1wyoT1btxO+UYiQM3g== +"@chakra-ui/react-use-focus-effect@2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.0.10.tgz#0328a85e05fd6f8927359a544184494b5cb947bd" + integrity sha512-HswfpzjP8gCQM3/fbeR+8wrYqt0B3ChnVTqssnYXqp9Fa/5Y1Kx1ZADUWW93zMs5SF7hIEuNt8uKeh1/3HTcqQ== dependencies: "@chakra-ui/dom-utils" "2.0.6" "@chakra-ui/react-use-event-listener" "2.0.7" @@ -576,10 +583,10 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.0.7.tgz#1a1fe800fb5501ec3da4088fbac78c03bbad13a7" integrity sha512-zds4Uhsc+AMzdH8JDDkLVet9baUBgtOjPbhC5r3A0ZXjZvGhCztFAVE3aExYiVoMPoHLKbLcqvCWE6ioFKz1lw== -"@chakra-ui/react-use-outside-click@2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.0.7.tgz#56c668f020fbc6331db4c3b61c8b845a68c4a134" - integrity sha512-MsAuGLkwYNxNJ5rb8lYNvXApXxYMnJ3MzqBpQj1kh5qP/+JSla9XMjE/P94ub4fSEttmNSqs43SmPPrmPuihsQ== +"@chakra-ui/react-use-outside-click@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.1.0.tgz#f7e27653c470e516c55d79df67ed8b0ba2c4ec8d" + integrity sha512-JanCo4QtWvMl9ZZUpKJKV62RlMWDFdPCE0Q64a7eWTOQgWWcpyBW7TOYRunQTqrK30FqkYFJCOlAWOtn+6Rw7A== dependencies: "@chakra-ui/react-use-callback-ref" "2.0.7" @@ -602,12 +609,12 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.0.5.tgz#6cf388c37fd2a42b5295a292e149b32f860a00a7" integrity sha512-MwAQBz3VxoeFLaesaSEN87reVNVbjcQBDex2WGexAg6hUB6n4gc1OWYH/iXp4tzp4kuggBNhEHkk9BMYXWfhJQ== -"@chakra-ui/react-use-size@2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-size/-/react-use-size-2.0.9.tgz#00717867b98a24c3bdcfaa0c3e70732404193486" - integrity sha512-Jce7QmO1jlQZq+Y77VKckWzroRnajChzUQ8xhLQZO6VbYvrpg3cu+X2QCz3G+MZzB+1/hnvvAqmZ+uJLd8rEJg== +"@chakra-ui/react-use-size@2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-size/-/react-use-size-2.0.10.tgz#6131950852490c06e5fb3760bf64097c8057391f" + integrity sha512-fdIkH14GDnKQrtQfxX8N3gxbXRPXEl67Y3zeD9z4bKKcQUAYIMqs0MsPZY+FMpGQw8QqafM44nXfL038aIrC5w== dependencies: - "@zag-js/element-size" "0.3.1" + "@zag-js/element-size" "0.3.2" "@chakra-ui/react-use-timeout@2.0.5": version "2.0.5" @@ -628,69 +635,70 @@ dependencies: "@chakra-ui/utils" "2.0.15" -"@chakra-ui/react@^2.5.1": - version "2.5.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.5.1.tgz#05414db2b512bd4402e42eecc6b915d85102c576" - integrity sha512-ugkaqfcNMb9L4TkalWiF3rnqfr0TlUUD46JZaDIZiORVisaSwXTZTQrVfG40VghhaJT28rnC5WtiE8kd567ZBQ== +"@chakra-ui/react@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.6.0.tgz#67bea840ff97b2820798f52e706423ccc49f8b7e" + integrity sha512-dhufu/A4O5tQ65p//XGfvUqSrf0qRAgTmFRlBZ7HucyxF5RStQ65FXiTXV0s4Pj0X5hgSJm3oCasV6UD6MXYbw== dependencies: - "@chakra-ui/accordion" "2.1.9" - "@chakra-ui/alert" "2.0.17" - "@chakra-ui/avatar" "2.2.5" - "@chakra-ui/breadcrumb" "2.1.4" - "@chakra-ui/button" "2.0.16" + "@chakra-ui/accordion" "2.1.11" + "@chakra-ui/alert" "2.1.0" + "@chakra-ui/avatar" "2.2.9" + "@chakra-ui/breadcrumb" "2.1.5" + "@chakra-ui/button" "2.0.18" "@chakra-ui/card" "2.1.6" - "@chakra-ui/checkbox" "2.2.10" + "@chakra-ui/checkbox" "2.2.15" "@chakra-ui/close-button" "2.0.17" "@chakra-ui/control-box" "2.0.13" "@chakra-ui/counter" "2.0.14" - "@chakra-ui/css-reset" "2.0.12" - "@chakra-ui/editable" "2.0.19" + "@chakra-ui/css-reset" "2.1.1" + "@chakra-ui/editable" "3.0.0" "@chakra-ui/focus-lock" "2.0.16" - "@chakra-ui/form-control" "2.0.17" - "@chakra-ui/hooks" "2.1.6" + "@chakra-ui/form-control" "2.0.18" + "@chakra-ui/hooks" "2.2.0" "@chakra-ui/icon" "3.0.16" - "@chakra-ui/image" "2.0.15" - "@chakra-ui/input" "2.0.20" - "@chakra-ui/layout" "2.1.16" + "@chakra-ui/image" "2.0.16" + "@chakra-ui/input" "2.0.22" + "@chakra-ui/layout" "2.1.19" "@chakra-ui/live-region" "2.0.13" "@chakra-ui/media-query" "3.2.12" - "@chakra-ui/menu" "2.1.9" - "@chakra-ui/modal" "2.2.9" - "@chakra-ui/number-input" "2.0.18" - "@chakra-ui/pin-input" "2.0.19" - "@chakra-ui/popover" "2.1.8" + "@chakra-ui/menu" "2.1.13" + "@chakra-ui/modal" "2.2.11" + "@chakra-ui/number-input" "2.0.19" + "@chakra-ui/pin-input" "2.0.20" + "@chakra-ui/popover" "2.1.10" "@chakra-ui/popper" "3.0.13" - "@chakra-ui/portal" "2.0.15" - "@chakra-ui/progress" "2.1.5" - "@chakra-ui/provider" "2.1.2" - "@chakra-ui/radio" "2.0.19" + "@chakra-ui/portal" "2.0.16" + "@chakra-ui/progress" "2.1.6" + "@chakra-ui/provider" "2.2.3" + "@chakra-ui/radio" "2.0.22" "@chakra-ui/react-env" "3.0.0" - "@chakra-ui/select" "2.0.18" + "@chakra-ui/select" "2.0.19" "@chakra-ui/skeleton" "2.0.24" - "@chakra-ui/slider" "2.0.21" + "@chakra-ui/slider" "2.0.23" "@chakra-ui/spinner" "2.0.13" - "@chakra-ui/stat" "2.0.17" - "@chakra-ui/styled-system" "2.6.1" - "@chakra-ui/switch" "2.0.22" - "@chakra-ui/system" "2.5.1" - "@chakra-ui/table" "2.0.16" - "@chakra-ui/tabs" "2.1.8" - "@chakra-ui/tag" "2.0.17" - "@chakra-ui/textarea" "2.0.18" - "@chakra-ui/theme" "2.2.5" - "@chakra-ui/theme-utils" "2.0.11" - "@chakra-ui/toast" "6.0.1" - "@chakra-ui/tooltip" "2.2.6" - "@chakra-ui/transition" "2.0.15" + "@chakra-ui/stat" "2.0.18" + "@chakra-ui/stepper" "2.1.0" + "@chakra-ui/styled-system" "2.9.0" + "@chakra-ui/switch" "2.0.27" + "@chakra-ui/system" "2.5.6" + "@chakra-ui/table" "2.0.17" + "@chakra-ui/tabs" "2.1.9" + "@chakra-ui/tag" "3.0.0" + "@chakra-ui/textarea" "2.0.19" + "@chakra-ui/theme" "3.1.0" + "@chakra-ui/theme-utils" "2.0.16" + "@chakra-ui/toast" "6.1.2" + "@chakra-ui/tooltip" "2.2.7" + "@chakra-ui/transition" "2.0.16" "@chakra-ui/utils" "2.0.15" "@chakra-ui/visually-hidden" "2.0.15" -"@chakra-ui/select@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-2.0.18.tgz#4eb6092610067c1b4131353fe39b4466e251395b" - integrity sha512-1d2lUT5LM6oOs5x4lzBh4GFDuXX62+lr+sgV7099g951/5UNbb0CS2hSZHsO7yZThLNbr7QTWZvAOAayVcGzdw== +"@chakra-ui/select@2.0.19": + version "2.0.19" + resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-2.0.19.tgz#957e95a17a890d8c0a851e2f00a8d8dd17932d66" + integrity sha512-eAlFh+JhwtJ17OrB6fO6gEAGOMH18ERNrXLqWbYLrs674Le7xuREgtuAYDoxUzvYXYYTTdOJtVbcHGriI3o6rA== dependencies: - "@chakra-ui/form-control" "2.0.17" + "@chakra-ui/form-control" "2.0.18" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/shared-utils@2.0.4": @@ -712,20 +720,20 @@ "@chakra-ui/react-use-previous" "2.0.5" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/slider@2.0.21": - version "2.0.21" - resolved "https://registry.yarnpkg.com/@chakra-ui/slider/-/slider-2.0.21.tgz#f65b15bf0d5f827699ff9a2d6faee35006e2bfce" - integrity sha512-Mm76yJxEqJl21+3waEcKg3tM8Y4elJ7mcViN6Brj35PTfzUJfSJxeBGo1nLPJ+X5jLj7o/L4kfBmUk3lY4QYEQ== +"@chakra-ui/slider@2.0.23": + version "2.0.23" + resolved "https://registry.yarnpkg.com/@chakra-ui/slider/-/slider-2.0.23.tgz#9130c7aee8ca876be64d1aeba6b84fe421c8207b" + integrity sha512-/eyRUXLla+ZdBUPXpakE3SAS2JS8mIJR6qcUYiPVKSpRAi6tMyYeQijAXn2QC1AUVd2JrG8Pz+1Jy7Po3uA7cA== dependencies: "@chakra-ui/number-utils" "2.0.7" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-callback-ref" "2.0.7" "@chakra-ui/react-use-controllable-state" "2.0.8" "@chakra-ui/react-use-latest-ref" "2.0.5" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/react-use-pan-event" "2.0.9" - "@chakra-ui/react-use-size" "2.0.9" + "@chakra-ui/react-use-size" "2.0.10" "@chakra-ui/react-use-update-effect" "2.0.7" "@chakra-ui/spinner@2.0.13": @@ -735,82 +743,91 @@ dependencies: "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/stat@2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-2.0.17.tgz#2cd712cc7e0d58d9cbd542deea911f1b0925074f" - integrity sha512-PhD+5oVLWjQmGLfeZSmexp3AtLcaggWBwoMZ4z8QMZIQzf/fJJWMk0bMqxlpTv8ORDkfY/4ImuFB/RJHvcqlcA== +"@chakra-ui/stat@2.0.18": + version "2.0.18" + resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-2.0.18.tgz#9e5d21d162b7cf2cf92065c19291ead2d4660772" + integrity sha512-wKyfBqhVlIs9bkSerUc6F9KJMw0yTIEKArW7dejWwzToCLPr47u+CtYO6jlJHV6lRvkhi4K4Qc6pyvtJxZ3VpA== dependencies: "@chakra-ui/icon" "3.0.16" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/styled-system@2.6.1", "@chakra-ui/styled-system@^2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/styled-system/-/styled-system-2.6.1.tgz#302d496d34c0b7b30c646a7e3c9b113a2f4588da" - integrity sha512-jy/1dVi1LxjoRCm+Eo5mqBgvPy5SCWMlIcz6GbIZBDpkGeKZwtqrZLjekxxLBCy8ORY+kJlUB0FT6AzVR/1tjw== +"@chakra-ui/stepper@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/stepper/-/stepper-2.1.0.tgz#10ae7ea6c0b5edf554e9b2bfe5ec67fb7b7c67ec" + integrity sha512-Xo/3U+nduhLWNUAAQ0XuIeJjXhSCrxyEJ0PSGwR+2I8PJq82GDIxXjvfpeDLCHoB225l3Wyuy4paeIHkUQhDxA== + dependencies: + "@chakra-ui/icon" "3.0.16" + "@chakra-ui/react-context" "2.0.8" + "@chakra-ui/shared-utils" "2.0.5" + +"@chakra-ui/styled-system@2.9.0", "@chakra-ui/styled-system@^2.9.0": + version "2.9.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/styled-system/-/styled-system-2.9.0.tgz#b3bace83c78cf9c072c461cc963bf73c0e7ccd3d" + integrity sha512-rToN30eOezrTZ5qBHmWqEwsYPenHtc3WU6ODAfMUwNnmCJQiu2erRGv8JwIjmRJnKSOEnNKccI2UXe2EwI6+JA== dependencies: "@chakra-ui/shared-utils" "2.0.5" csstype "^3.0.11" lodash.mergewith "4.6.2" -"@chakra-ui/switch@2.0.22": - version "2.0.22" - resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.0.22.tgz#7b35e2b10ea4cf91fb49f5175b4335c61dcd25b3" - integrity sha512-+/Yy6y7VFD91uSPruF8ZvePi3tl5D8UNVATtWEQ+QBI92DLSM+PtgJ2F0Y9GMZ9NzMxpZ80DqwY7/kqcPCfLvw== +"@chakra-ui/switch@2.0.27": + version "2.0.27" + resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.0.27.tgz#e76e5afdfc837c83fce34480de4431ff8c19fcb8" + integrity sha512-z76y2fxwMlvRBrC5W8xsZvo3gP+zAEbT3Nqy5P8uh/IPd5OvDsGeac90t5cgnQTyxMOpznUNNK+1eUZqtLxWnQ== dependencies: - "@chakra-ui/checkbox" "2.2.10" + "@chakra-ui/checkbox" "2.2.15" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/system@2.5.1": - version "2.5.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.5.1.tgz#bc03a11ae31e795966c7618280548d5cd866f47e" - integrity sha512-4+86OrcSoq7lGkm5fh+sJ3IWXSTzjz+HOllRbCW2Rtnmcg7ritiXVNV2VygEg2DrCcx5+tNqRHDM764zW+AEug== +"@chakra-ui/system@2.5.6": + version "2.5.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.5.6.tgz#244eef56be3d3d546ef3d1b93e5f9b9a591ef3fd" + integrity sha512-sKzonHUbjOnRxZvcysN8pqa3y0OkTb9xWPhNFnvye/Km8vZhw4SfHKbVpRXedMPVp5Q3PHOxqAXOs6Q0kpo6KA== dependencies: "@chakra-ui/color-mode" "2.1.12" - "@chakra-ui/object-utils" "2.0.8" + "@chakra-ui/object-utils" "2.1.0" "@chakra-ui/react-utils" "2.0.12" - "@chakra-ui/styled-system" "2.6.1" - "@chakra-ui/theme-utils" "2.0.11" + "@chakra-ui/styled-system" "2.9.0" + "@chakra-ui/theme-utils" "2.0.16" "@chakra-ui/utils" "2.0.15" - react-fast-compare "3.2.0" + react-fast-compare "3.2.1" -"@chakra-ui/table@2.0.16": - version "2.0.16" - resolved "https://registry.yarnpkg.com/@chakra-ui/table/-/table-2.0.16.tgz#e69736cba5cfb218c5e40592ad9280c6e32f6fe7" - integrity sha512-vWDXZ6Ad3Aj66curp1tZBHvCfQHX2FJ4ijLiqGgQszWFIchfhJ5vMgEBJaFMZ+BN1draAjuRTZqaQefOApzvRg== +"@chakra-ui/table@2.0.17": + version "2.0.17" + resolved "https://registry.yarnpkg.com/@chakra-ui/table/-/table-2.0.17.tgz#ad394dc6dcbe5a8a9e6d899997ecca3471603977" + integrity sha512-OScheTEp1LOYvTki2NFwnAYvac8siAhW9BI5RKm5f5ORL2gVJo4I72RUqE0aKe1oboxgm7CYt5afT5PS5cG61A== dependencies: - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/tabs@2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-2.1.8.tgz#e83071380f9a3633810308d45de51be7a74f5eb9" - integrity sha512-B7LeFN04Ny2jsSy5TFOQxnbZ6ITxGxLxsB2PE0vvQjMSblBrUryOxdjw80HZhfiw6od0ikK9CeKQOIt9QCguSw== +"@chakra-ui/tabs@2.1.9": + version "2.1.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-2.1.9.tgz#2e5214cb453c6cc0c240e82bd88af1042fc6fe0e" + integrity sha512-Yf8e0kRvaGM6jfkJum0aInQ0U3ZlCafmrYYni2lqjcTtThqu+Yosmo3iYlnullXxCw5MVznfrkb9ySvgQowuYg== dependencies: "@chakra-ui/clickable" "2.0.14" - "@chakra-ui/descendant" "3.0.13" + "@chakra-ui/descendant" "3.0.14" "@chakra-ui/lazy-utils" "2.0.5" "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-controllable-state" "2.0.8" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/react-use-safe-layout-effect" "2.0.5" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/tag@2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-2.0.17.tgz#97adb86db190ddb3526060b78c590392e0ac8b4c" - integrity sha512-A47zE9Ft9qxOJ+5r1cUseKRCoEdqCRzFm0pOtZgRcckqavglk75Xjgz8HbBpUO2zqqd49MlqdOwR8o87fXS1vg== +"@chakra-ui/tag@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-3.0.0.tgz#d86cdab59bb3ff7fc628c2dbe7a5ff1b36bd3e96" + integrity sha512-YWdMmw/1OWRwNkG9pX+wVtZio+B89odaPj6XeMn5nfNN8+jyhIEpouWv34+CO9G0m1lupJTxPSfgLAd7cqXZMA== dependencies: "@chakra-ui/icon" "3.0.16" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/react-context" "2.0.8" -"@chakra-ui/textarea@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-2.0.18.tgz#da6d629b465f65bbc7b48039c2e48a4ae1d853b4" - integrity sha512-aGHHb29vVifO0OtcK/k8cMykzjOKo/coDTU0NJqz7OOLAWIMNV2eGenvmO1n9tTZbmbqHiX+Sa1nPRX+pd14lg== +"@chakra-ui/textarea@2.0.19": + version "2.0.19" + resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-2.0.19.tgz#470b459f9cb3255d2abbe07d46b0a5b60a6a32c5" + integrity sha512-adJk+qVGsFeJDvfn56CcJKKse8k7oMGlODrmpnpTdF+xvlsiTM+1GfaJvgNSpHHuQFdz/A0z1uJtfGefk0G2ZA== dependencies: - "@chakra-ui/form-control" "2.0.17" + "@chakra-ui/form-control" "2.0.18" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/theme-tools@2.0.17": @@ -831,57 +848,57 @@ "@chakra-ui/shared-utils" "2.0.4" color2k "^2.0.0" -"@chakra-ui/theme-utils@2.0.11": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.11.tgz#c01b1d14fdd63326d1ad11fd8f0872921ea43872" - integrity sha512-lBAay6Sq3/fl7exd3mFxWAbzgdQowytor0fnlHrpNStn1HgFjXukwsf6356XQOie2Vd8qaMM7qZtMh4AiC0dcg== +"@chakra-ui/theme-utils@2.0.16": + version "2.0.16" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.16.tgz#9686b6b307ae8928a686df8df79bee16c4e0d25c" + integrity sha512-xVrQ8YEhIX51PB27kbEGHoQ3G78erSykqOeIPkoxaEfWBV4Ba83o7RwEZG8/Qa7c7S4qYPmCSGynegBWrsQpHA== dependencies: "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/styled-system" "2.6.1" - "@chakra-ui/theme" "2.2.5" + "@chakra-ui/styled-system" "2.9.0" + "@chakra-ui/theme" "3.1.0" lodash.mergewith "4.6.2" -"@chakra-ui/theme@2.2.5": - version "2.2.5" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-2.2.5.tgz#18ed1755ff27c1ff1f1a77083ffc546c361c926e" - integrity sha512-hYASZMwu0NqEv6PPydu+F3I+kMNd44yR4TwjR/lXBz/LEh64L6UPY6kQjebCfgdVtsGdl3HKg+eLlfa7SvfRgw== +"@chakra-ui/theme@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-3.1.0.tgz#ebb097c350ca9827b2efcc81df5f4b712729b9a0" + integrity sha512-lO2p37lyEGVmGUrr+lakHpnvrJHkkfPnSM+w9MGmR0V0rqIGTIBrirBO07vDccNRS17jcXjA8d9QZEBYzIVyNw== dependencies: "@chakra-ui/anatomy" "2.1.2" "@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/theme-tools" "2.0.17" -"@chakra-ui/toast@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-6.0.1.tgz#726b67a57cdd592320bb3f450c66d007a2a1d902" - integrity sha512-ej2kJXvu/d2h6qnXU5D8XTyw0qpsfmbiU7hUffo/sPxkz89AUOQ08RUuUmB1ssW/FZcQvNMJ5WgzCTKHGBxtxw== +"@chakra-ui/toast@6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-6.1.2.tgz#9a41dd01baf790232f07a4237ef49bc019d7a836" + integrity sha512-hKSv6tX0zgZIZDMpIzs0kZM56sYrD5lvlLQ5JfERLi0KTSTeP+vbYh4+Vg3GTXPCn1JBF7mZRX0gU22WEMfJ8A== dependencies: - "@chakra-ui/alert" "2.0.17" + "@chakra-ui/alert" "2.1.0" "@chakra-ui/close-button" "2.0.17" - "@chakra-ui/portal" "2.0.15" - "@chakra-ui/react-context" "2.0.7" + "@chakra-ui/portal" "2.0.16" + "@chakra-ui/react-context" "2.0.8" "@chakra-ui/react-use-timeout" "2.0.5" "@chakra-ui/react-use-update-effect" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/styled-system" "2.6.1" - "@chakra-ui/theme" "2.2.5" + "@chakra-ui/styled-system" "2.9.0" + "@chakra-ui/theme" "3.1.0" -"@chakra-ui/tooltip@2.2.6": - version "2.2.6" - resolved "https://registry.yarnpkg.com/@chakra-ui/tooltip/-/tooltip-2.2.6.tgz#a38f9ff2dd8a574c8cf49526c3846533455f8ddd" - integrity sha512-4cbneidZ5+HCWge3OZzewRQieIvhDjSsl+scrl4Scx7E0z3OmqlTIESU5nGIZDBLYqKn/UirEZhqaQ33FOS2fw== +"@chakra-ui/tooltip@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/tooltip/-/tooltip-2.2.7.tgz#7c305efb057a5fe4694b1b8d82395aec776d8f57" + integrity sha512-ImUJ6NnVqARaYqpgtO+kzucDRmxo8AF3jMjARw0bx2LxUkKwgRCOEaaRK5p5dHc0Kr6t5/XqjDeUNa19/sLauA== dependencies: "@chakra-ui/popper" "3.0.13" - "@chakra-ui/portal" "2.0.15" + "@chakra-ui/portal" "2.0.16" "@chakra-ui/react-types" "2.0.7" "@chakra-ui/react-use-disclosure" "2.0.8" "@chakra-ui/react-use-event-listener" "2.0.7" "@chakra-ui/react-use-merge-refs" "2.0.7" "@chakra-ui/shared-utils" "2.0.5" -"@chakra-ui/transition@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@chakra-ui/transition/-/transition-2.0.15.tgz#c640df2ea82f5ad58c55a6e1a7c338f377cb96d8" - integrity sha512-o9LBK/llQfUDHF/Ty3cQ6nShpekKTqHUoJlUOzNKhoTsNpoRerr9v0jwojrX1YI02KtVjfhFU6PiqXlDfREoNw== +"@chakra-ui/transition@2.0.16": + version "2.0.16" + resolved "https://registry.yarnpkg.com/@chakra-ui/transition/-/transition-2.0.16.tgz#498c91e6835bb5d950fd1d1402f483b85f7dcd87" + integrity sha512-E+RkwlPc3H7P1crEXmXwDXMB2lqY2LLia2P5siQ4IEnRWIgZXlIw+8Em+NtHNgusel2N+9yuB0wT9SeZZeZ3CQ== dependencies: "@chakra-ui/shared-utils" "2.0.5" @@ -912,10 +929,18 @@ resolved "https://registry.yarnpkg.com/@dagrejs/graphlib/-/graphlib-2.1.12.tgz#97d29eae006e4efcb68863505464e0e3f28fa5c7" integrity sha512-yHk2G7ZNzDEHhQTlYtbtEy5PqlIoioCxZUKcrlBgubMvrLmewXqSV3v4rhc8RAt5s8lr8PcWbiovEPuORxe2KA== -"@emotion/babel-plugin@^11.10.6": - version "11.10.6" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz#a68ee4b019d661d6f37dec4b8903255766925ead" - integrity sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ== +"@dependents/detective-less@^3.0.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@dependents/detective-less/-/detective-less-3.0.2.tgz#c6e46997010fe03a5dc98351a7e99a46d34f5832" + integrity sha512-1YUvQ+e0eeTWAHoN8Uz2x2U37jZs6IGutiIE5LXId7cxfUGhtZjzxE06FdUiuiRrW+UE0vNCdSNPH2lY4dQCOQ== + dependencies: + gonzales-pe "^4.3.0" + node-source-walk "^5.0.1" + +"@emotion/babel-plugin@^11.10.8": + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.8.tgz#bae325c902937665d00684038fd5294223ef9e1d" + integrity sha512-gxNky50AJL3AlkbjvTARiwAqei6/tNUxDZPSKd+3jqWVM3AmdVTTdpjHorR/an/M0VJqdsuq5oGcFH+rjtyujQ== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/runtime" "^7.18.3" @@ -927,18 +952,18 @@ escape-string-regexp "^4.0.0" find-root "^1.1.0" source-map "^0.5.7" - stylis "4.1.3" + stylis "4.1.4" -"@emotion/cache@^11.10.5": - version "11.10.5" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12" - integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA== +"@emotion/cache@^11.10.8": + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.8.tgz#3b39b4761bea0ae2f4f07f0a425eec8b6977c03e" + integrity sha512-5fyqGHi51LU95o7qQ/vD1jyvC4uCY5GcBT+UgP4LHdpO9jPDlXqhrRr9/wCKmfoAvh5G/F7aOh4MwQa+8uEqhA== dependencies: "@emotion/memoize" "^0.8.0" "@emotion/sheet" "^1.2.1" "@emotion/utils" "^1.2.0" "@emotion/weak-memoize" "^0.3.0" - stylis "4.1.3" + stylis "4.1.4" "@emotion/hash@^0.9.0": version "0.9.0" @@ -970,13 +995,13 @@ integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== "@emotion/react@^11.10.6": - version "11.10.6" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.6.tgz#dbe5e650ab0f3b1d2e592e6ab1e006e75fd9ac11" - integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw== + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.8.tgz#02e274ecb45e03ab9d7a8eb9f0f0c064613eaf7b" + integrity sha512-ZfGfiABtJ1P1OXqOBsW08EgCDp5fK6C5I8hUJauc/VcJBGSzqAirMnFslhFWnZJ/w5HxPI36XbvMV0l4KZHl+w== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.10.6" - "@emotion/cache" "^11.10.5" + "@emotion/babel-plugin" "^11.10.8" + "@emotion/cache" "^11.10.8" "@emotion/serialize" "^1.1.1" "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" "@emotion/utils" "^1.2.0" @@ -1000,12 +1025,12 @@ integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== "@emotion/styled@^11.10.6": - version "11.10.6" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.6.tgz#d886afdc51ef4d66c787ebde848f3cc8b117ebba" - integrity sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og== + version "11.10.8" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.8.tgz#a3fd68efd90bd7e8a06b82b95adec643d386fa69" + integrity sha512-gow0lF4Uw/QEdX2REMhI8v6wLOabPKJ+4HKNF0xdJ2DJdznN6fxaXpQOx6sNkyBhSUL558Rmcu1Lq/MYlVo4vw== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.10.6" + "@emotion/babel-plugin" "^11.10.8" "@emotion/is-prop-valid" "^1.2.0" "@emotion/serialize" "^1.1.1" "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" @@ -1031,124 +1056,136 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== -"@esbuild/android-arm64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23" - integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg== +"@esbuild/android-arm64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz#4aa8d8afcffb4458736ca9b32baa97d7cb5861ea" + integrity sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw== -"@esbuild/android-arm@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2" - integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw== +"@esbuild/android-arm@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.18.tgz#74a7e95af4ee212ebc9db9baa87c06a594f2a427" + integrity sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw== -"@esbuild/android-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e" - integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ== +"@esbuild/android-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.18.tgz#1dcd13f201997c9fe0b204189d3a0da4eb4eb9b6" + integrity sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg== -"@esbuild/darwin-arm64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220" - integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w== +"@esbuild/darwin-arm64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz#444f3b961d4da7a89eb9bd35cfa4415141537c2a" + integrity sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ== -"@esbuild/darwin-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4" - integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg== +"@esbuild/darwin-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz#a6da308d0ac8a498c54d62e0b2bfb7119b22d315" + integrity sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A== -"@esbuild/freebsd-arm64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27" - integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw== +"@esbuild/freebsd-arm64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz#b83122bb468889399d0d63475d5aea8d6829c2c2" + integrity sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA== -"@esbuild/freebsd-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72" - integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug== +"@esbuild/freebsd-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz#af59e0e03fcf7f221b34d4c5ab14094862c9c864" + integrity sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew== -"@esbuild/linux-arm64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca" - integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g== +"@esbuild/linux-arm64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz#8551d72ba540c5bce4bab274a81c14ed01eafdcf" + integrity sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ== -"@esbuild/linux-arm@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196" - integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ== +"@esbuild/linux-arm@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz#e09e76e526df4f665d4d2720d28ff87d15cdf639" + integrity sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg== -"@esbuild/linux-ia32@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54" - integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg== +"@esbuild/linux-ia32@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz#47878860ce4fe73a36fd8627f5647bcbbef38ba4" + integrity sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ== -"@esbuild/linux-loong64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8" - integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ== +"@esbuild/linux-loong64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz#3f8fbf5267556fc387d20b2e708ce115de5c967a" + integrity sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ== -"@esbuild/linux-mips64el@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726" - integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw== +"@esbuild/linux-mips64el@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz#9d896d8f3c75f6c226cbeb840127462e37738226" + integrity sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA== -"@esbuild/linux-ppc64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8" - integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g== +"@esbuild/linux-ppc64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz#3d9deb60b2d32c9985bdc3e3be090d30b7472783" + integrity sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ== -"@esbuild/linux-riscv64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9" - integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw== +"@esbuild/linux-riscv64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz#8a943cf13fd24ff7ed58aefb940ef178f93386bc" + integrity sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA== -"@esbuild/linux-s390x@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87" - integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w== +"@esbuild/linux-s390x@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz#66cb01f4a06423e5496facabdce4f7cae7cb80e5" + integrity sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw== -"@esbuild/linux-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f" - integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw== +"@esbuild/linux-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz#23c26050c6c5d1359c7b774823adc32b3883b6c9" + integrity sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA== -"@esbuild/netbsd-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775" - integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA== +"@esbuild/netbsd-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz#789a203d3115a52633ff6504f8cbf757f15e703b" + integrity sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg== -"@esbuild/openbsd-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35" - integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg== +"@esbuild/openbsd-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz#d7b998a30878f8da40617a10af423f56f12a5e90" + integrity sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA== -"@esbuild/sunos-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c" - integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw== +"@esbuild/sunos-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz#ecad0736aa7dae07901ba273db9ef3d3e93df31f" + integrity sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg== -"@esbuild/win32-arm64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a" - integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw== +"@esbuild/win32-arm64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz#58dfc177da30acf956252d7c8ae9e54e424887c4" + integrity sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg== -"@esbuild/win32-ia32@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09" - integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig== +"@esbuild/win32-ia32@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz#340f6163172b5272b5ae60ec12c312485f69232b" + integrity sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw== -"@esbuild/win32-x64@0.16.17": - version "0.16.17" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091" - integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q== +"@esbuild/win32-x64@0.17.18": + version "0.17.18" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz#3a8e57153905308db357fd02f57c180ee3a0a1fa" + integrity sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg== -"@eslint/eslintrc@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff" - integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A== +"@eslint-community/eslint-utils@^4.2.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.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" + integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== + +"@eslint/eslintrc@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02" + integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" + espree "^9.5.1" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -1156,10 +1193,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.35.0": - version "8.35.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7" - integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw== +"@eslint/js@8.39.0": + version "8.39.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b" + integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng== "@fontsource/inter@^4.5.15": version "4.5.15" @@ -1186,37 +1223,47 @@ integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@jridgewell/gen-mapping@^0.3.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + 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", "@jridgewell/resolve-uri@^3.0.3": +"@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/resolve-uri@^3.0.3": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + "@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.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" + integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== dependencies: "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@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.9" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" @@ -1226,9 +1273,9 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + 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" @@ -1238,6 +1285,48 @@ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== +"@microsoft/api-extractor-model@7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.26.5.tgz#b3d0939b4dab6897ce27c966bd394a582f1871e7" + integrity sha512-sv1dF9B3AeMURTW0xubvmrX/tLFe2bpmHJBXKiqfOl2YOoLNjreIqmPHPe1vDSq9MDxAJLqvyurjOf87abVJBQ== + dependencies: + "@microsoft/tsdoc" "0.14.2" + "@microsoft/tsdoc-config" "~0.16.1" + "@rushstack/node-core-library" "3.56.0" + +"@microsoft/api-extractor@^7.34.4": + version "7.34.5" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.34.5.tgz#06ee82834a7ccdc104b096cc44ef74d877b68d07" + integrity sha512-0CUMSHvJ3Tq7ZJg09vn3kwvZN41k6dbe4zcPrDpZwQKh/dXIL5oQ7hbrbrASBDlE5DSPHs+7iGYa9FGGdgyrCA== + dependencies: + "@microsoft/api-extractor-model" "7.26.5" + "@microsoft/tsdoc" "0.14.2" + "@microsoft/tsdoc-config" "~0.16.1" + "@rushstack/node-core-library" "3.56.0" + "@rushstack/rig-package" "0.3.18" + "@rushstack/ts-command-line" "4.13.2" + colors "~1.2.1" + lodash "~4.17.15" + resolve "~1.22.1" + semver "~7.3.0" + source-map "~0.6.1" + typescript "~4.8.4" + +"@microsoft/tsdoc-config@~0.16.1": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" + integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw== + dependencies: + "@microsoft/tsdoc" "0.14.2" + ajv "~6.12.6" + jju "~1.4.0" + resolve "~1.19.0" + +"@microsoft/tsdoc@0.14.2": + version "0.14.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" + integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1260,9 +1349,9 @@ fastq "^1.6.0" "@popperjs/core@^2.9.3": - version "2.11.6" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" - integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== + version "2.11.7" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7" + integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw== "@reactflow/background@11.2.0": version "11.2.0" @@ -1329,15 +1418,24 @@ classcat "^5.0.3" zustand "^4.3.1" -"@reduxjs/toolkit@^1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.3.tgz#27e1a33072b5a312e4f7fa19247fec160bbb2df9" - integrity sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg== +"@reduxjs/toolkit@^1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" + integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== dependencies: - immer "^9.0.16" - redux "^4.2.0" + immer "^9.0.21" + redux "^4.2.1" redux-thunk "^2.4.2" - reselect "^4.1.7" + reselect "^4.1.8" + +"@roarr/browser-log-writer@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@roarr/browser-log-writer/-/browser-log-writer-1.1.5.tgz#755ff62ddaa297bb3488067408a7085db382352b" + integrity sha512-yLn//DRjh1/rUgZpZkwmT/5RqHYfkdOwGXWXnKBR3l/HE04DIhSVeYin3sc8aWHBa7s7WglQpYX/uw/WI6POpw== + dependencies: + boolean "^3.1.4" + globalthis "^1.0.2" + liqe "^3.6.0" "@rollup/pluginutils@^4.2.1": version "4.2.1" @@ -1347,6 +1445,46 @@ estree-walker "^2.0.1" picomatch "^2.2.2" +"@rollup/pluginutils@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33" + integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + +"@rushstack/node-core-library@3.56.0", "@rushstack/node-core-library@^3.55.2": + version "3.56.0" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.56.0.tgz#61136eaeac442194822fc075c63fee426019896d" + integrity sha512-HyaRfgL77I8y6HCFYkLnAUWjsniDrIHlomic570TJ/ehd+pOdrRr95APAYGFw+nVwXE4qyEUTyYMWxsOnV14VA== + 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" + z-schema "~5.0.2" + +"@rushstack/rig-package@0.3.18": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.3.18.tgz#2b59eb8ed482e8cd6ad8d396414bf3200efdd682" + integrity sha512-SGEwNTwNq9bI3pkdd01yCaH+gAsHqs0uxfGvtw9b0LJXH52qooWXnrFTRRLG1aL9pf+M2CARdrA9HLHJys3jiQ== + dependencies: + resolve "~1.22.1" + strip-json-comments "~3.1.1" + +"@rushstack/ts-command-line@4.13.2": + version "4.13.2" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.13.2.tgz#2dfdcf418d58256671433b1da4a3b67e1814cc7a" + integrity sha512-bCU8qoL9HyWiciltfzg7GqdfODUeda/JpI0602kbN5YH22rzTxyqYvv7aRLENCM7XCQ1VRs7nMkEqgJUOU8Sag== + dependencies: + "@types/argparse" "1.0.38" + argparse "~1.0.9" + colors "~1.2.1" + string-argv "~0.3.1" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -1357,71 +1495,71 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== -"@swc/core-darwin-arm64@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.37.tgz#a92e075ae35f18a64aaf3823ea175f03564f8da1" - integrity sha512-iIyVqqioUpVeT/hbBVfkrsjfCyL4idNH+LVKGmoTAWaTTSB0+UNhNuA7Wh2CqIHWh1Mv7IlumitWPcqsVDdoEw== +"@swc/core-darwin-arm64@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz#bd7fdf838a8d27c3df98d279017710a2da6af6a3" + integrity sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ== -"@swc/core-darwin-x64@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.37.tgz#a3cc06c87140a2ca0b8e7ef1f3d5cc34dd080429" - integrity sha512-dao5nXPWKxtaxqak4ZkRyBoApNIelW/glantQhPhj0FjMjuIQc+v03ldJ8XDByWOG+6xuVUTheANCtEccxoQBw== +"@swc/core-darwin-x64@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz#da7e4076cce35e42f2688f7aae1fd26ecb5dcbef" + integrity sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g== -"@swc/core-linux-arm-gnueabihf@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.37.tgz#f7d8f8523830c6be653f608839d4bd5598457f1f" - integrity sha512-/mVrc8H/f062CUkqKGmBiil2VIYu4mKawHxERfeP1y38X5K/OwjG5s9MgO9TVxy+Ly6vejwj70kRhSa3hVp1Bw== +"@swc/core-linux-arm-gnueabihf@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz#fd9214d5050987b312cbe9aa105d48365899c1d8" + integrity sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ== -"@swc/core-linux-arm64-gnu@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.37.tgz#b162febd9de14fb08000c722b063be2bb5aefa6b" - integrity sha512-eRQ3KaZI0j5LidTfOIi/kUVOOMuVmw1HCdt/Z1TAUKoHMLVxY8xcJ3pEE3/+ednI60EmHpwpJRs6LelXyL6uzQ== +"@swc/core-linux-arm64-gnu@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz#214a4c1c89d9bab9277843b526b32463a98c516b" + integrity sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q== -"@swc/core-linux-arm64-musl@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.37.tgz#3b1a628e880fbb1a5e2a7a46d42e8aa878c6bfdd" - integrity sha512-w2BRLODyxNQY2rfHZMZ5ir6QrrnGBPlnIslTrgKmVbn1OjZoxUCtuqhrYnCmybaAc4DOkeH02TqynEFXrm+EMw== +"@swc/core-linux-arm64-musl@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz#21a11fd919883bc0dc0ceb686f2627c1dc279b71" + integrity sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q== -"@swc/core-linux-x64-gnu@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.37.tgz#ed443ad77dc90e415267d02a38e4113047b2d3d8" - integrity sha512-CfoH8EsZJZ9kunjMUjBNYD5fFuO86zw+K/o4wEw72Yg6ZEiqPmeIlCKU8tpTv4sK+CbhUXrmVzMB5tqsb2jALQ== +"@swc/core-linux-x64-gnu@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz#3cdf5e669e8d1ef3a1fd4249e535d53d4768a009" + integrity sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g== -"@swc/core-linux-x64-musl@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.37.tgz#de607a4985458bd6e8b0e40f0d62d0e26bd8df1e" - integrity sha512-9YPrHYNdoG7PK11gV51GfL45biI2dic+YTqHUDKyykemsD7Ot1zUFX7Ty//pdvpKcKSff6SrHbfFACD5ziNirA== +"@swc/core-linux-x64-musl@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz#099f75a04827afe59c8755498c749ac667635749" + integrity sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ== -"@swc/core-win32-arm64-msvc@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.37.tgz#d5851a47d7df183929b9746d56f76c282f940e6a" - integrity sha512-h17Ek8/wCDje6BrXOvCXBM80oBRmTSMMdLyt87whTl5xqYlWYYs9oQIzZndNRTlNpTgjGO8Ns2eo4kwVxIkBIA== +"@swc/core-win32-arm64-msvc@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz#e70b3cc06bbd6c04ebb7c1af1da1301d52dc5260" + integrity sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA== -"@swc/core-win32-ia32-msvc@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.37.tgz#06ad7016f61b56aec4abf60eab3a91b786f9e294" - integrity sha512-1BR175E1olGy/zdt94cgdb6ps/lBNissAOaxyBk8taFpcjy3zpdP30yAoH0GIsC6isnZ5JfArbOJNRXXO5tE0Q== +"@swc/core-win32-ia32-msvc@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz#d2780198baec4aff1d01cb89a53dab53003e127c" + integrity sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ== -"@swc/core-win32-x64-msvc@1.3.37": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.37.tgz#60139a7089003a7447a4efef9704ae8fde21995e" - integrity sha512-1siDQ7dccQ1pesJmgAL3BUBbRPtfbNInOWnZOkiie/DfFqGQ117QKnCVyjUvwFKfTQx1+3UUTDmMSlRd00SlXg== +"@swc/core-win32-x64-msvc@1.3.55": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz#6f9b9ac3f820f5a8476f93863b558c3b727be3d0" + integrity sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg== -"@swc/core@^1.2.177", "@swc/core@^1.3.35": - version "1.3.37" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.37.tgz#644653fa7deb20c7c342e7fd019c7abc44ecf1bf" - integrity sha512-VOFlEQ1pReOM73N9A7R8rt561GU8Rxsq833jiimWDUB2sXEN3V6n6wFTgYmZuMz2T4/R0cQA1nV48KkaT4gkFw== +"@swc/core@^1.2.177", "@swc/core@^1.3.42": + version "1.3.55" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.55.tgz#0886c07fb6d32803fee85cf135c1a3352142d51f" + integrity sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ== optionalDependencies: - "@swc/core-darwin-arm64" "1.3.37" - "@swc/core-darwin-x64" "1.3.37" - "@swc/core-linux-arm-gnueabihf" "1.3.37" - "@swc/core-linux-arm64-gnu" "1.3.37" - "@swc/core-linux-arm64-musl" "1.3.37" - "@swc/core-linux-x64-gnu" "1.3.37" - "@swc/core-linux-x64-musl" "1.3.37" - "@swc/core-win32-arm64-msvc" "1.3.37" - "@swc/core-win32-ia32-msvc" "1.3.37" - "@swc/core-win32-x64-msvc" "1.3.37" + "@swc/core-darwin-arm64" "1.3.55" + "@swc/core-darwin-x64" "1.3.55" + "@swc/core-linux-arm-gnueabihf" "1.3.55" + "@swc/core-linux-arm64-gnu" "1.3.55" + "@swc/core-linux-arm64-musl" "1.3.55" + "@swc/core-linux-x64-gnu" "1.3.55" + "@swc/core-linux-x64-musl" "1.3.55" + "@swc/core-win32-arm64-msvc" "1.3.55" + "@swc/core-win32-ia32-msvc" "1.3.55" + "@swc/core-win32-x64-msvc" "1.3.55" "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -1430,6 +1568,16 @@ dependencies: defer-to-connect "^1.0.1" +"@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" + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -1450,6 +1598,11 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== +"@types/argparse@1.0.38": + version "1.0.38" + resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" + integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA== + "@types/d3-array@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.4.tgz#44eebe40be57476cad6a0cd6a85b0f57d54185a2" @@ -1666,17 +1819,17 @@ integrity sha512-SZg4JdHIWHQGEokbYGZSDvo5wA4TLYPXaqhigs/wH+REDOejcJzgH+qyY+HtEUtWOZxEUkbhbdYPqQDiEgrXeA== "@types/eslint@^8.4.5": - version "8.21.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.21.1.tgz#110b441a210d53ab47795124dbc3e9bb993d1e7c" - integrity sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ== + version "8.37.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.37.0.tgz#29cebc6c2a3ac7fea7113207bf5a828fdf4d7ef1" + integrity sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== "@types/geojson@*": version "7946.0.10" @@ -1691,6 +1844,11 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/js-cookie@^2.2.6": + version "2.2.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": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -1701,6 +1859,13 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/lodash-es@^4.14.194": + version "4.17.7" + resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.7.tgz#22edcae9f44aff08546e71db8925f05b33c7cc40" + integrity sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ== + dependencies: + "@types/lodash" "*" + "@types/lodash.mergewith@4.6.7": version "4.6.7" resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz#eaa65aa5872abdd282f271eae447b115b2757212" @@ -1709,15 +1874,15 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.14.191" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" - integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== - -"@types/lodash@^4.14.194": version "4.14.194" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76" integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g== +"@types/node@^18.16.2": + version "18.16.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.2.tgz#2f610ea71034b3971c312192377f8a7178eb57f1" + integrity sha512-GQW/JL/5Fz/0I8RpeBG9lKp0+aNcXEaVL71c0D2Q0QHDTFvlYKT7an0onCUXj85anv7b4/WesqdfchLc0jtsCg== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -1728,10 +1893,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/react-dom@^18.0.11": - version "18.0.11" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.11.tgz#321351c1459bc9ca3d216aefc8a167beec334e33" - integrity sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw== +"@types/react-dom@^18.2.1": + version "18.2.1" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.1.tgz#663b2612feb5f6431a70207430d7c04881b87f29" + integrity sha512-8QZEV9+Kwy7tXFmjJrp3XUKQSs9LTnE0KnoUb0YCguWBiNW0Yfb2iBMYZ08WPg35IR6P3Z0s00B15SwZnO26+w== dependencies: "@types/react" "*" @@ -1749,19 +1914,19 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.0.28": - version "18.0.28" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065" - integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew== +"@types/react@*", "@types/react@^18.2.0": + version "18.2.0" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.0.tgz#15cda145354accfc09a18d2f2305f9fc099ada21" + integrity sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + 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": version "7.3.13" @@ -1778,47 +1943,47 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6" integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA== -"@typescript-eslint/eslint-plugin@^5.52.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz#2c821ad81b2c786d142279a8292090f77d1881f4" - integrity sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw== +"@typescript-eslint/eslint-plugin@^5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz#9b09ee1541bff1d2cebdcb87e7ce4a4003acde08" + integrity sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg== dependencies: - "@typescript-eslint/scope-manager" "5.54.0" - "@typescript-eslint/type-utils" "5.54.0" - "@typescript-eslint/utils" "5.54.0" + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.59.1" + "@typescript-eslint/type-utils" "5.59.1" + "@typescript-eslint/utils" "5.59.1" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" natural-compare-lite "^1.4.0" - regexpp "^3.2.0" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.52.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.54.0.tgz#def186eb1b1dbd0439df0dacc44fb6d8d5c417fe" - integrity sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ== +"@typescript-eslint/parser@^5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.1.tgz#73c2c12127c5c1182d2e5b71a8fa2a85d215cbb4" + integrity sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g== dependencies: - "@typescript-eslint/scope-manager" "5.54.0" - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/typescript-estree" "5.54.0" + "@typescript-eslint/scope-manager" "5.59.1" + "@typescript-eslint/types" "5.59.1" + "@typescript-eslint/typescript-estree" "5.59.1" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz#74b28ac9a3fc8166f04e806c957adb8c1fd00536" - integrity sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg== +"@typescript-eslint/scope-manager@5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz#8a20222719cebc5198618a5d44113705b51fd7fe" + integrity sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA== dependencies: - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/visitor-keys" "5.54.0" + "@typescript-eslint/types" "5.59.1" + "@typescript-eslint/visitor-keys" "5.59.1" -"@typescript-eslint/type-utils@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz#390717216eb61393a0cad2995da154b613ba7b26" - integrity sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ== +"@typescript-eslint/type-utils@5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz#63981d61684fd24eda2f9f08c0a47ecb000a2111" + integrity sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw== dependencies: - "@typescript-eslint/typescript-estree" "5.54.0" - "@typescript-eslint/utils" "5.54.0" + "@typescript-eslint/typescript-estree" "5.59.1" + "@typescript-eslint/utils" "5.59.1" debug "^4.3.4" tsutils "^3.21.0" @@ -1827,18 +1992,18 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== -"@typescript-eslint/types@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.0.tgz#7d519df01f50739254d89378e0dcac504cab2740" - integrity sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ== +"@typescript-eslint/types@5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.1.tgz#03f3fedd1c044cb336ebc34cc7855f121991f41d" + integrity sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg== -"@typescript-eslint/typescript-estree@5.54.0", "@typescript-eslint/typescript-estree@^5.13.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz#f6f3440cabee8a43a0b25fa498213ebb61fdfe99" - integrity sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ== +"@typescript-eslint/typescript-estree@5.59.1", "@typescript-eslint/typescript-estree@^5.55.0": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz#4aa546d27fd0d477c618f0ca00b483f0ec84c43c" + integrity sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA== dependencies: - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/visitor-keys" "5.54.0" + "@typescript-eslint/types" "5.59.1" + "@typescript-eslint/visitor-keys" "5.59.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -1858,18 +2023,18 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.0.tgz#3db758aae078be7b54b8ea8ea4537ff6cd3fbc21" - integrity sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw== +"@typescript-eslint/utils@5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.1.tgz#d89fc758ad23d2157cfae53f0b429bdf15db9473" + integrity sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA== dependencies: + "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.54.0" - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/typescript-estree" "5.54.0" + "@typescript-eslint/scope-manager" "5.59.1" + "@typescript-eslint/types" "5.59.1" + "@typescript-eslint/typescript-estree" "5.59.1" eslint-scope "^5.1.1" - eslint-utils "^3.0.0" semver "^7.3.7" "@typescript-eslint/visitor-keys@4.33.0": @@ -1880,35 +2045,40 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz#846878afbf0cd67c19cfa8d75947383d4490db8f" - integrity sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA== +"@typescript-eslint/visitor-keys@5.59.1": + version "5.59.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz#0d96c36efb6560d7fb8eb85de10442c10d8f6058" + integrity sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA== dependencies: - "@typescript-eslint/types" "5.54.0" + "@typescript-eslint/types" "5.59.1" eslint-visitor-keys "^3.3.0" -"@vitejs/plugin-react-swc@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.2.0.tgz#7c4f6e116a296c27f680d05750f9dbf798cf7709" - integrity sha512-IcBoXL/mcH7JdQr/nfDlDwTdIaH8Rg7LpfQDF4nAht+juHWIuv6WhpKPCSfY4+zztAaB07qdBoFz1XCZsgo3pQ== +"@vitejs/plugin-react-swc@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.0.tgz#d443a4bbb423542c5a089c65a58dca597170c549" + integrity sha512-Ycg+n2eyCOTpn/wRy+evVo859+hw7qCj9iaX5CMny6x1fx1Uoq0xBG+a98lFtwLNGfGEnpI0F26YigRuxCRkwg== dependencies: - "@swc/core" "^1.3.35" + "@swc/core" "^1.3.42" + +"@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" + integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -"@zag-js/element-size@0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@zag-js/element-size/-/element-size-0.3.1.tgz#f9f6ae98355e2250d18d0f6e2f1134a0ae4c6a2f" - integrity sha512-jR5j4G//bRzcxwAACWi9EfITnwjNmn10LxF4NmALrdZU7/PNWP3uUCdhCxd/0SCyeiJXUl0yvD57rWAbKPs1nw== +"@zag-js/element-size@0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@zag-js/element-size/-/element-size-0.3.2.tgz#ebb76af2a024230482406db41344598d1a9f54f4" + integrity sha512-bVvvigUGvAuj7PCkE5AbzvTJDTw5f3bg9nQdv+ErhVN8SfPPppLJEmmWdxqsRzrHXgx8ypJt/+Ty0kjtISVDsQ== -"@zag-js/focus-visible@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@zag-js/focus-visible/-/focus-visible-0.2.1.tgz#bf4f1009f4fd35a9728dfaa9214d8cb318fe8b1e" - integrity sha512-19uTjoZGP4/Ax7kSNhhay9JA83BirKzpqLkeEAilrpdI1hE5xuq6q+tzJOsrMOOqJrm7LkmZp5lbsTQzvK2pYg== +"@zag-js/focus-visible@0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@zag-js/focus-visible/-/focus-visible-0.2.2.tgz#56233480ca1275d3218fb2e10696a33d1a6b9e64" + integrity sha512-0j2gZq8HiZ51z4zNnSkF1iSkqlwRDvdH+son3wHdoz+7IUdMN/5Exd4TxMJ+gq2Of1DiXReYLL9qqh2PdQ4wgA== acorn-jsx@^5.3.2: version "5.3.2" @@ -1933,7 +2103,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.11.0, 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== @@ -2014,13 +2184,28 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +argparse@~1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + aria-hidden@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.2.tgz#8c4f7cc88d73ca42114106fdf6f47e68d31475b8" - integrity sha512-6y/ogyDTk/7YAe91T3E2PR1ALVKyM2QbTio5HwM+N1Q6CMlCKhvClyIjkckBswa0f2xJhjsfzIGa1yVSe1UMVA== + version "1.2.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" + integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== dependencies: tslib "^2.0.0" +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-includes@^3.1.5, array-includes@^3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" @@ -2068,6 +2253,11 @@ ast-module-types@^3.0.0: resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-3.0.0.tgz#9a6d8a80f438b6b8fe4995699d700297f398bf81" integrity sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ== +ast-module-types@^4.0.0: + version "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" @@ -2093,10 +2283,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axios@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" - integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ== +axios@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -2143,6 +2333,11 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +boolean@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" + integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== + boxen@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" @@ -2165,6 +2360,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -2226,6 +2428,11 @@ chakra-ui-contextmenu@^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@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2271,6 +2478,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.7.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + classcat@^5.0.3, classcat@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.4.tgz#e12d1dfe6df6427f260f03b80dc63571a5107ba6" @@ -2322,9 +2534,9 @@ cli-handle-unhandled@^1.1.1: cli-handle-error "^4.1.0" cli-spinners@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" - integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== + version "2.8.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.8.0.tgz#e97a3e2bd00e6d85aa0c13d7f9e3ce236f7787fc" + integrity sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ== cli-truncate@^2.1.0: version "2.1.0" @@ -2372,6 +2584,16 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== +clsx@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + +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" @@ -2402,9 +2624,14 @@ color2k@^2.0.0: integrity sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w== colorette@^2.0.19: - version "2.0.19" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +colors@~1.2.1: + version "1.2.5" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc" + integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== combined-stream@^1.0.8: version "1.0.8" @@ -2413,7 +2640,12 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^2.16.0, commander@^2.20.0, commander@^2.20.3, commander@^2.8.1: +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: 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== @@ -2423,7 +2655,7 @@ commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commander@^9.1.0, commander@^9.3.0, commander@^9.4.1: +commander@^9.3.0, commander@^9.5.0: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== @@ -2443,20 +2675,20 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concurrently@^7.6.0: - version "7.6.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.6.0.tgz#531a6f5f30cf616f355a4afb8f8fcb2bba65a49a" - integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw== +concurrently@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.0.1.tgz#80c0591920a9fa3e68ba0dd8aa6eac8487eb904c" + integrity sha512-Sh8bGQMEL0TAmAm2meAXMjcASHZa7V0xXQVDBLknCPa9TPtkY9yYs+0cnGGgfdkW0SV1Mlg+hVGfXcoI8d3MJA== dependencies: - chalk "^4.1.0" - date-fns "^2.29.1" + chalk "^4.1.2" + date-fns "^2.29.3" lodash "^4.17.21" - rxjs "^7.0.0" - shell-quote "^1.7.3" - spawn-command "^0.0.2-1" - supports-color "^8.1.0" + rxjs "^7.8.0" + shell-quote "^1.8.0" + spawn-command "0.0.2-1" + supports-color "^8.1.1" tree-kill "^1.2.2" - yargs "^17.3.1" + yargs "^17.7.1" configstore@^5.0.1: version "5.0.1" @@ -2475,7 +2707,7 @@ convert-source-map@^1.5.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== -copy-to-clipboard@3.3.3: +copy-to-clipboard@3.3.3, copy-to-clipboard@^3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== @@ -2505,17 +2737,6 @@ cross-fetch@3.1.5: dependencies: node-fetch "2.6.7" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2537,10 +2758,25 @@ css-box-model@1.2.1: dependencies: tiny-invariant "^1.0.6" -csstype@^3.0.11, csstype@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" - integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== +css-in-js-utils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz#640ae6a33646d401fc720c54fc61c42cd76ae2bb" + integrity sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A== + dependencies: + hyphenate-style-name "^1.0.3" + +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +csstype@^3.0.11, csstype@^3.0.2, csstype@^3.0.6: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== "d3-color@1 - 3": version "3.1.0" @@ -2604,7 +2840,7 @@ d3-zoom@^3.0.0: d3-selection "2 - 3" d3-transition "2 - 3" -date-fns@^2.29.1: +date-fns@^2.29.3: version "2.29.3" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== @@ -2643,6 +2879,11 @@ 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== + defaults@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" @@ -2660,7 +2901,7 @@ 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-properties@^1.1.3, define-properties@^1.1.4: +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" integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== @@ -2699,15 +2940,15 @@ detective-amd@^3.1.0: get-amd-module-type "^3.0.0" node-source-walk "^4.2.0" -detective-amd@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-4.0.1.tgz#1a827d9e4fa2f832506bd87aa392f124155bca3a" - integrity sha512-bDo22IYbJ8yzALB0Ow5CQLtyhU1BpDksLB9dsWHI9Eh0N3OQR6aQqhjPsNDd69ncYwRfL1sTo7OA9T3VRVSe2Q== +detective-amd@^4.0.1, detective-amd@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-4.2.0.tgz#21c43465669f06cf894eef047a27e6e72ba6bc13" + integrity sha512-RbuEJHz78A8nW7CklkqTzd8lDCN42En53dgEIsya0DilpkwslamSZDasLg8dJyxbw46OxhSQeY+C2btdSkCvQQ== dependencies: - ast-module-types "^3.0.0" + ast-module-types "^4.0.0" escodegen "^2.0.0" - get-amd-module-type "^4.0.0" - node-source-walk "^5.0.0" + get-amd-module-type "^4.1.0" + node-source-walk "^5.0.1" detective-cjs@^3.1.1: version "3.1.3" @@ -2717,13 +2958,13 @@ detective-cjs@^3.1.1: ast-module-types "^3.0.0" node-source-walk "^4.0.0" -detective-cjs@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detective-cjs/-/detective-cjs-4.0.0.tgz#316e2c7ae14276a5dcfe0c43dc05d8cf9a0e5cf9" - integrity sha512-VsD6Yo1+1xgxJWoeDRyut7eqZ8EWaJI70C5eanSAPcBHzenHZx0uhjxaaEfIm0cHII7dBiwU98Orh44bwXN2jg== +detective-cjs@^4.0.0, detective-cjs@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/detective-cjs/-/detective-cjs-4.1.0.tgz#56b1558ca0910933c7fc47c740b957f0280ff302" + integrity sha512-QxzMwt5MfPLwS7mG30zvnmOvHLx5vyVvjsAV6gQOyuMoBR5G1DhS1eJZ4P10AlH+HSnk93mTcrg3l39+24XCtg== dependencies: - ast-module-types "^3.0.0" - node-source-walk "^5.0.0" + ast-module-types "^4.0.0" + node-source-walk "^5.0.1" detective-es6@^2.2.1: version "2.2.2" @@ -2732,10 +2973,10 @@ detective-es6@^2.2.1: dependencies: node-source-walk "^4.0.0" -detective-es6@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-3.0.0.tgz#78c9ef5492d5b59748b411aecaaf52b5ca0f0bc2" - integrity sha512-Uv2b5Uih7vorYlqGzCX+nTPUb4CMzUAn3VPHTV5p5lBkAN4cAApLGgUz4mZE2sXlBfv4/LMmeP7qzxHV/ZcfWA== +detective-es6@^3.0.0, detective-es6@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-3.0.1.tgz#53a15fbb2f298c4a106d9fe7427da8a57162dde6" + integrity sha512-evPeYIEdK1jK3Oji5p0hX4sPV/1vK+o4ihcWZkMQE6voypSW/cIBiynOLxQk5KOOQbdP8oOAsYqouMTYO5l1sw== dependencies: node-source-walk "^5.0.0" @@ -2758,13 +2999,13 @@ detective-postcss@^4.0.0: postcss "^8.1.7" postcss-values-parser "^2.0.1" -detective-postcss@^6.0.1, detective-postcss@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/detective-postcss/-/detective-postcss-6.1.0.tgz#01ca6f83dbc3158540fb0e6a6c631f3998946e54" - integrity sha512-ZFZnEmUrL2XHAC0j/4D1fdwZbo/anAcK84soJh7qc7xfx2Kc8gFO5Bk5I9jU7NLC/OAF1Yho1GLxEDnmQnRH2A== +detective-postcss@^6.1.0, detective-postcss@^6.1.1: + version "6.1.3" + resolved "https://registry.yarnpkg.com/detective-postcss/-/detective-postcss-6.1.3.tgz#51a2d4419327ad85d0af071c7054c79fafca7e73" + integrity sha512-7BRVvE5pPEvk2ukUWNQ+H2XOq43xENWbH0LcdCE14mwgTBEAMoAx+Fc1rdp76SmyZ4Sp48HlV7VedUnP6GA1Tw== dependencies: is-url "^1.2.4" - postcss "^8.4.12" + postcss "^8.4.23" postcss-values-parser "^6.0.2" detective-sass@^3.0.1: @@ -2775,13 +3016,13 @@ detective-sass@^3.0.1: gonzales-pe "^4.3.0" node-source-walk "^4.0.0" -detective-sass@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/detective-sass/-/detective-sass-4.0.1.tgz#2a9e303a0bd472d00aaa79512334845e3acbaffc" - integrity sha512-80zfpxux1krOrkxCHbtwvIs2gNHUBScnSqlGl0FvUuHVz8HD6vD2ov66OroMctyvzhM67fxhuEeVjIk18s6yTQ== +detective-sass@^4.0.1, detective-sass@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/detective-sass/-/detective-sass-4.1.3.tgz#6cdcc27ae8a90d15704e0ba83683048f77f10b75" + integrity sha512-xGRbwGaGte57gvEqM8B9GDiURY3El/H49vA6g9wFkxq9zalmTlTAuqWu+BsH0iwonGPruLt55tZZDEZqPc6lag== dependencies: gonzales-pe "^4.3.0" - node-source-walk "^5.0.0" + node-source-walk "^5.0.1" detective-scss@^2.0.1: version "2.0.2" @@ -2791,24 +3032,29 @@ detective-scss@^2.0.1: gonzales-pe "^4.3.0" node-source-walk "^4.0.0" -detective-scss@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/detective-scss/-/detective-scss-3.0.0.tgz#c3c7bc4799f51515a4f0ed1e8ca491151364230f" - integrity sha512-37MB/mhJyS45ngqfzd6eTbuLMoDgdZnH03ZOMW2m9WqJ/Rlbuc8kZAr0Ypovaf1DJiTRzy5mmxzOTja85jbzlA== +detective-scss@^3.0.0, detective-scss@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/detective-scss/-/detective-scss-3.1.1.tgz#b49f05cadfb0837b04e23baba292581b7c7f65e1" + integrity sha512-FWkfru1jZBhUeuBsOeGKXKAVDrzYFSQFK2o2tuG/nCCFQ0U/EcXC157MNAcR5mmj+mCeneZzlkBOFJTesDjrww== dependencies: gonzales-pe "^4.3.0" - node-source-walk "^5.0.0" + node-source-walk "^5.0.1" detective-stylus@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-1.0.3.tgz#20a702936c9fd7d4203fd7a903314b5dd43ac713" integrity sha512-4/bfIU5kqjwugymoxLXXLltzQNeQfxGoLm2eIaqtnkWxqbhap9puDVpJPVDx96hnptdERzS5Cy6p9N8/08A69Q== -detective-stylus@^2.0.0, detective-stylus@^2.0.1: +detective-stylus@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-2.0.1.tgz#d528dfa7ef3c4eb2fbc9a7249d54906ec4e05d09" integrity sha512-/Tvs1pWLg8eYwwV6kZQY5IslGaYqc/GACxjcaGudiNtN5nKCH6o2WnJK3j0gA3huCnoQcbv8X7oz/c1lnvE3zQ== +detective-stylus@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-3.0.0.tgz#c869795a7d6df7043ab6aee8b1a6f3dd66764232" + integrity sha512-1xYTzbrduExqMYmte7Qk99IRA3Aa6oV7PYzd+3yDcQXkmENvyGF/arripri6lxRDdNYEb4fZFuHtNRAXbz3iAA== + detective-typescript@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-7.0.2.tgz#c6e00b4c28764741ef719662250e6b014a5f3c8e" @@ -2819,15 +3065,15 @@ detective-typescript@^7.0.0: node-source-walk "^4.2.0" typescript "^3.9.10" -detective-typescript@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-9.0.0.tgz#57d674cec49ec775460ab975b5bcbb5c2d32ff8e" - integrity sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA== +detective-typescript@^9.0.0, detective-typescript@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-9.1.1.tgz#b99c0122cbb35b39de2c5f58447f1e93ac28c6d5" + integrity sha512-Uc1yVutTF0RRm1YJ3g//i1Cn2vx1kwHj15cnzQP6ff5koNzQ0idc1zAC73ryaWEulA0ElRXFTq6wOqe8vUQ3MA== dependencies: - "@typescript-eslint/typescript-estree" "^5.13.0" - ast-module-types "^3.0.0" - node-source-walk "^5.0.0" - typescript "^4.5.5" + "@typescript-eslint/typescript-estree" "^5.55.0" + ast-module-types "^4.0.0" + node-source-walk "^5.0.1" + typescript "^4.9.5" diff@^4.0.1: version "4.0.2" @@ -2841,6 +3087,11 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +discontinuous-range@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" + integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ== + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -2914,9 +3165,9 @@ engine.io-parser@~5.0.3: integrity sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw== enhanced-resolve@^5.8.3: - version "5.12.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" - integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== + version "5.13.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz#26d1ecc448c02de997133217b5c1053f34a0a275" + integrity sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -2928,18 +3179,25 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== +error-stack-parser@^2.0.6: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== dependencies: + stackframe "^1.3.4" + +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== + dependencies: + array-buffer-byte-length "^1.0.0" available-typed-arrays "^1.0.5" call-bind "^1.0.2" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" @@ -2947,8 +3205,8 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" @@ -2956,11 +3214,12 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: is-string "^1.0.7" is-typed-array "^1.1.10" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.4.3" safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" string.prototype.trimend "^1.0.6" string.prototype.trimstart "^1.0.6" typed-array-length "^1.0.4" @@ -2992,33 +3251,33 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild@^0.16.14: - version "0.16.17" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259" - integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg== +esbuild@^0.17.5: + version "0.17.18" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.18.tgz#f4f8eb6d77384d68cd71c53eb6601c7efe05e746" + integrity sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w== optionalDependencies: - "@esbuild/android-arm" "0.16.17" - "@esbuild/android-arm64" "0.16.17" - "@esbuild/android-x64" "0.16.17" - "@esbuild/darwin-arm64" "0.16.17" - "@esbuild/darwin-x64" "0.16.17" - "@esbuild/freebsd-arm64" "0.16.17" - "@esbuild/freebsd-x64" "0.16.17" - "@esbuild/linux-arm" "0.16.17" - "@esbuild/linux-arm64" "0.16.17" - "@esbuild/linux-ia32" "0.16.17" - "@esbuild/linux-loong64" "0.16.17" - "@esbuild/linux-mips64el" "0.16.17" - "@esbuild/linux-ppc64" "0.16.17" - "@esbuild/linux-riscv64" "0.16.17" - "@esbuild/linux-s390x" "0.16.17" - "@esbuild/linux-x64" "0.16.17" - "@esbuild/netbsd-x64" "0.16.17" - "@esbuild/openbsd-x64" "0.16.17" - "@esbuild/sunos-x64" "0.16.17" - "@esbuild/win32-arm64" "0.16.17" - "@esbuild/win32-ia32" "0.16.17" - "@esbuild/win32-x64" "0.16.17" + "@esbuild/android-arm" "0.17.18" + "@esbuild/android-arm64" "0.17.18" + "@esbuild/android-x64" "0.17.18" + "@esbuild/darwin-arm64" "0.17.18" + "@esbuild/darwin-x64" "0.17.18" + "@esbuild/freebsd-arm64" "0.17.18" + "@esbuild/freebsd-x64" "0.17.18" + "@esbuild/linux-arm" "0.17.18" + "@esbuild/linux-arm64" "0.17.18" + "@esbuild/linux-ia32" "0.17.18" + "@esbuild/linux-loong64" "0.17.18" + "@esbuild/linux-mips64el" "0.17.18" + "@esbuild/linux-ppc64" "0.17.18" + "@esbuild/linux-riscv64" "0.17.18" + "@esbuild/linux-s390x" "0.17.18" + "@esbuild/linux-x64" "0.17.18" + "@esbuild/netbsd-x64" "0.17.18" + "@esbuild/openbsd-x64" "0.17.18" + "@esbuild/sunos-x64" "0.17.18" + "@esbuild/win32-arm64" "0.17.18" + "@esbuild/win32-ia32" "0.17.18" + "@esbuild/win32-x64" "0.17.18" escalade@^3.1.1: version "3.1.1" @@ -3052,10 +3311,10 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz#dec1d29ab728f4fa63061774e1672ac4e363d207" - integrity sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA== +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-plugin-prettier@^4.2.1: version "4.2.1" @@ -3098,38 +3357,33 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - eslint-visitor-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" + integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== -eslint@^8.34.0: - version "8.35.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323" - integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw== +eslint@^8.39.0: + version "8.39.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.39.0.tgz#7fd20a295ef92d43809e914b70c39fd5a23cf3f1" + integrity sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og== dependencies: - "@eslint/eslintrc" "^2.0.0" - "@eslint/js" "8.35.0" + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.2" + "@eslint/js" "8.39.0" "@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -3139,10 +3393,9 @@ eslint@^8.34.0: debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.0" + espree "^9.5.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -3164,19 +3417,18 @@ eslint@^8.34.0: minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - regexpp "^3.2.0" strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4" + integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg== dependencies: acorn "^8.8.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" @@ -3207,7 +3459,7 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^2.0.1: +estree-walker@^2.0.1, estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== @@ -3217,14 +3469,14 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -execa@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" - integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== +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== dependencies: cross-spawn "^7.0.3" get-stream "^6.0.1" - human-signals "^3.0.1" + human-signals "^4.3.0" is-stream "^3.0.0" merge-stream "^2.0.0" npm-run-path "^5.1.0" @@ -3242,7 +3494,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@^3.2.9: +fast-glob@^3.2.12, fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== @@ -3258,11 +3510,48 @@ fast-json-stable-stringify@^2.0.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== + dependencies: + ajv "^6.11.0" + deepmerge "^4.2.2" + rfdc "^1.2.0" + string-similarity "^4.0.1" + fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-loops@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-loops/-/fast-loops-1.1.3.tgz#ce96adb86d07e7bf9b4822ab9c6fac9964981f75" + integrity sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g== + +fast-memoize@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.5.2.tgz#79e3bb6a4ec867ea40ba0e7146816f6cdce9b57e" + integrity sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw== + +fast-printf@^1.6.9: + version "1.6.9" + resolved "https://registry.yarnpkg.com/fast-printf/-/fast-printf-1.6.9.tgz#212f56570d2dc8ccdd057ee93d50dd414d07d676" + integrity sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg== + dependencies: + boolean "^3.1.4" + +fast-shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" + integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== + +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" + integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q== + fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -3285,9 +3574,9 @@ file-selector@^0.6.0: tslib "^2.4.0" filing-cabinet@^3.0.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/filing-cabinet/-/filing-cabinet-3.3.0.tgz#365294d2d3d6ab01b4273e62fb6d23388a70cc0f" - integrity sha512-Tnbpbme1ONaHXV5DGcw0OFpcfP3p2itRf5VXO1bguBXdIewDbK6ZFBK//DGKM0BuCzaQLQNY4f5gljzxY1VCUw== + version "3.3.1" + resolved "https://registry.yarnpkg.com/filing-cabinet/-/filing-cabinet-3.3.1.tgz#45d87bb273a0e0a7dd6ac6bac9111059186e2e9c" + integrity sha512-renEK4Hh6DUl9Vl22Y3cxBq1yh8oNvbAdXnhih0wVpmea+uyKjC9K4QeRjUaybIiIewdzfum+Fg15ZqJ/GyCaA== dependencies: app-module-path "^2.2.0" commander "^2.20.3" @@ -3389,10 +3678,10 @@ formik@^2.2.9: tiny-warning "^1.0.2" tslib "^1.10.0" -framer-motion@^9.0.4: - version "9.1.7" - resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-9.1.7.tgz#1dc7dbd5bca086c90d09847c3fcaec3ecb7906af" - integrity sha512-nKxBkIO4IPkMEqcBbbATxsVjwPYShKl051yhBv9628iAH6JLeHD0siBHxkL62oQzMC1+GNX73XtPjgP753ufuw== +framer-motion@^10.12.4: + version "10.12.4" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-10.12.4.tgz#905fdfa5b63dae53a63d2549b29aef6193eb78c7" + integrity sha512-9gLtv8T6dui0tujHROR+VM3kdJyKiFCFiD94IQE+0OuX6LaIyXtdVpviokVdrHSb1giWhmmX4yzoucALMx6mtw== dependencies: tslib "^2.4.0" optionalDependencies: @@ -3414,6 +3703,15 @@ fs-extra@^10.1.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" @@ -3424,6 +3722,15 @@ fs-extra@^9.0.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@~7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3449,7 +3756,7 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" -functions-have-names@^1.2.2: +functions-have-names@^1.2.2, functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -3467,13 +3774,13 @@ get-amd-module-type@^3.0.0: ast-module-types "^3.0.0" node-source-walk "^4.2.2" -get-amd-module-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/get-amd-module-type/-/get-amd-module-type-4.0.0.tgz#3d4e5b44eec81f8337157d7c52c4fa9389aff78b" - integrity sha512-GbBawUCuA2tY8ztiMiVo3e3P95gc2TVrfYFfpUHdHQA8WyxMCckK29bQsVKhYX8SUf+w6JLhL2LG8tSC0ANt9Q== +get-amd-module-type@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-amd-module-type/-/get-amd-module-type-4.1.0.tgz#af1396d02cd935cb6fafdc4a5282395db3422db6" + integrity sha512-0e/eK6vTGCnSfQ6eYs3wtH05KotJYIP7ZIZEueP/KlA+0dIAEs8bYFvOd/U56w1vfjhJqBagUxVMyy9Tr/cViQ== dependencies: - ast-module-types "^3.0.0" - node-source-walk "^5.0.0" + ast-module-types "^4.0.0" + node-source-walk "^5.0.1" get-caller-file@^2.0.5: version "2.0.5" @@ -3566,7 +3873,7 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globalthis@^1.0.3: +globalthis@^1.0.2, globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== @@ -3622,9 +3929,9 @@ got@^9.6.0: url-parse-lax "^3.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== grapheme-splitter@^1.0.4: version "1.0.4" @@ -3713,16 +4020,21 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -human-signals@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" - integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ== +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== husky@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== +hyphenate-style-name@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" + integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== + i18next-browser-languagedetector@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz#ead34592edc96c6c3a618a51cb57ad027c5b5d87" @@ -3730,17 +4042,17 @@ i18next-browser-languagedetector@^7.0.1: dependencies: "@babel/runtime" "^7.19.4" -i18next-http-backend@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.1.1.tgz#72a21d61c2e96eea9ad45ba1b9dd0090e119709a" - integrity sha512-jByfUCDVgQ8+/Wens7queQhYYvMcGTW/lR4IJJNEDDXnmqjLrwi8ubXKpmp76/JIWEZHffNdWqnxFJcTVGeaOw== +i18next-http-backend@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-2.2.0.tgz#f77c06dc8e766c7588bb38da2f5fa0614ba67b3f" + integrity sha512-Z4sM7R6tzdLknSPER9GisEBxKPg5FkI07UrQniuroZmS15PHQrcCPLyuGKj8SS68tf+O2aEDYSUnmy1TZqZSbw== dependencies: cross-fetch "3.1.5" -i18next@^22.4.10: - version "22.4.10" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.10.tgz#cfbfc412c6bc83e3c16564f47e6a5c145255960e" - integrity sha512-3EqgGK6fAJRjnGgfkNSStl4mYLCjUoJID338yVyLMj5APT67HUtWoqSayZewiiC5elzMUB1VEUwcmSCoeQcNEA== +i18next@^22.4.15: + version "22.4.15" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.15.tgz#951882b751872994f8502b5a6ef6f796e6a7d7f8" + integrity sha512-yYudtbFrrmWKLEhl6jvKUYyYunj4bTBCe2qIUYAxbXoPusY7YmdwPvOE6fx6UIfWvmlbCWDItr7wIs8KEBZ5Zg== dependencies: "@babel/runtime" "^7.20.6" @@ -3754,10 +4066,10 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -immer@^9.0.16: - version "9.0.19" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b" - integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ== +immer@^9.0.21: + version "9.0.21" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" + integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -3772,6 +4084,11 @@ import-lazy@^2.1.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" integrity sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A== +import-lazy@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3810,7 +4127,15 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -internal-slot@^1.0.3, internal-slot@^1.0.4: +inline-style-prefixer@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz#4290ed453ab0e4441583284ad86e41ad88384f44" + integrity sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg== + dependencies: + css-in-js-utils "^3.1.0" + fast-loops "^1.1.3" + +internal-slot@^1.0.3, internal-slot@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== @@ -3826,7 +4151,7 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -is-array-buffer@^3.0.1: +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== @@ -3874,10 +4199,10 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== +is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.9.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" + integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== dependencies: has "^1.0.3" @@ -4091,16 +4416,26 @@ isexe@^2.0.0: integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== its-fine@^1.0.6: - version "1.0.9" - resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.0.9.tgz#f4ca0ad5bdbf896764d35f7cf24c16287b6c6d31" - integrity sha512-Ph+vcp1R100JOM4raXmDx/wCTi4kMkMXiFE108qGzsLdghXFPqad82UJJtqT1jwdyWYkTU6eDpDnol/ZIzW+1g== + version "1.1.1" + resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.1.1.tgz#e74b93fddd487441f978a50f64f0f5af4d2fc38e" + integrity sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw== dependencies: "@types/react-reconciler" "^0.28.0" +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== + +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-sdsl@^4.1.4: - version "4.3.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" - integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== + version "4.4.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" + integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -4153,6 +4488,13 @@ json5@^2.2.2: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -4184,10 +4526,15 @@ klaw-sync@^6.0.0: dependencies: graceful-fs "^4.1.11" -konva@^8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/konva/-/konva-8.4.2.tgz#6de2b9d54f2b56b8c7c76eba66955f7255dd9afb" - integrity sha512-4VQcrgj/PI8ydJjtLcTuinHBE8o0WGX0YoRwbiN5mpYQiC52aOzJ0XbpKNDJdRvORQphK5LP+jeM0hQJEYIuUA== +kolorist@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +konva@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/konva/-/konva-9.0.1.tgz#92b4171beaa94273b108bd87b08c4d3e51a0da22" + integrity sha512-wzpkprJ8idE42TDF9Lu9RNjVVYNXrj0apvTK3pujdHQhX1iNV+MUquSxYN8HqjYSG95QQ51jhFzRLWhnhf44Mw== latest-version@^5.1.0: version "5.1.0" @@ -4212,39 +4559,47 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lilconfig@2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" - integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.1.2.tgz#443636a0cfd834d5518d57d228130dc04c83d6fb" - integrity sha512-K9b4FPbWkpnupvK3WXZLbgu9pchUJ6N7TtVZjbaPsoizkqFUDkUReUL25xdrCljJs7uLUF3tZ7nVPeo/6lp+6w== +lint-staged@^13.2.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.2.tgz#5e711d3139c234f73402177be2f8dd312e6508ca" + integrity sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA== dependencies: + chalk "5.2.0" cli-truncate "^3.1.0" - colorette "^2.0.19" - commander "^9.4.1" + commander "^10.0.0" debug "^4.3.4" - execa "^6.1.0" - lilconfig "2.0.6" - listr2 "^5.0.5" + execa "^7.0.0" + lilconfig "2.1.0" + listr2 "^5.0.7" micromatch "^4.0.5" normalize-path "^3.0.0" - object-inspect "^1.12.2" + object-inspect "^1.12.3" pidtree "^0.6.0" string-argv "^0.3.1" - yaml "^2.1.3" + yaml "^2.2.2" -listr2@^5.0.5: - version "5.0.7" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.7.tgz#de69ccc4caf6bea7da03c74f7a2ffecf3904bd53" - integrity sha512-MD+qXHPmtivrHIDRwPYdfNkrzqDiuaKU/rfBcec3WMyMF3xylQj3jMq344OtvQxz7zaCFViRAeqlr2AFhPvXHw== +liqe@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/liqe/-/liqe-3.6.0.tgz#2d05376e93ff9f4bfdb3e76481f6456d165b499f" + integrity sha512-CYVQr0bk5CCTkX3wW2MdyEWdr9FHLpiE/1cQXQ36Sdjn5gv7JIpm9jnkovFwiVzumw7f6JDFXpljwUY+fAcFYQ== + dependencies: + 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== dependencies: cli-truncate "^2.1.0" colorette "^2.0.19" @@ -4267,6 +4622,16 @@ lodash-es@^4.17.21: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -4282,7 +4647,7 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== -lodash@^4.17.21: +lodash@^4.17.21, lodash@~4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4365,6 +4730,13 @@ madge@^6.0.0: typescript "^3.9.5" 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" + make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -4377,6 +4749,11 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -4429,11 +4806,23 @@ 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== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" 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" @@ -4442,13 +4831,13 @@ module-definition@^3.3.1: ast-module-types "^3.0.0" node-source-walk "^4.0.0" -module-definition@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-4.0.0.tgz#5b39cca9be28c5b0fec768eb2d9fd8de08a2550b" - integrity sha512-wntiAHV4lDn24BQn2kX6LKq0y85phHLHiv3aOPDF+lIs06kVjEMTe/ZTdrbVLnQV5FQsjik21taknvMhKY1Cug== +module-definition@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-4.1.0.tgz#148ff9348e3401867229dcbe5947f4f6d5ccd3a2" + integrity sha512-rHXi/DpMcD2qcKbPCTklDbX9lBKJrUSl971TW5l6nMpqKCIlzJqmQ8cfEF5M923h2OOLHPDVlh5pJxNyV+AJlw== dependencies: - ast-module-types "^3.0.0" - node-source-walk "^5.0.0" + ast-module-types "^4.0.0" + node-source-walk "^5.0.1" module-lookup-amd@^7.0.1: version "7.0.1" @@ -4461,15 +4850,34 @@ module-lookup-amd@^7.0.1: requirejs "^2.3.5" requirejs-config-file "^4.0.0" +moo@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c" + integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== +nano-css@^5.3.1: + version "5.3.5" + resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.5.tgz#3075ea29ffdeb0c7cb6d25edb21d8f7fa8e8fe8e" + integrity sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg== + dependencies: + css-tree "^1.1.2" + csstype "^3.0.6" + fastest-stable-stringify "^2.0.2" + inline-style-prefixer "^6.0.0" + rtl-css-js "^1.14.0" + sourcemap-codec "^1.4.8" + stacktrace-js "^2.0.2" + stylis "^4.0.6" + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== natural-compare-lite@^1.4.0: version "1.4.0" @@ -4481,16 +4889,21 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +nearley@^2.20.1: + version "2.20.1" + resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474" + integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ== + dependencies: + commander "^2.19.0" + moo "^0.5.0" + 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== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -4505,12 +4918,12 @@ node-source-walk@^4.0.0, node-source-walk@^4.2.0, node-source-walk@^4.2.2: dependencies: "@babel/parser" "^7.0.0" -node-source-walk@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-5.0.0.tgz#7cf93a0d12408081531fc440a00d7019eb3d5665" - integrity sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw== +node-source-walk@^5.0.0, node-source-walk@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-5.0.2.tgz#0eb439ce378946ce531e07a6a0073d06288396dd" + integrity sha512-Y4jr/8SRS5hzEdZ7SGuvZGwfORvNsSsNRwDXx5WisiqzsVfeftDvRgfeqWNgZvWSJbgubTRVRYBzK6UO+ErqjA== dependencies: - "@babel/parser" "^7.0.0" + "@babel/parser" "^7.21.4" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -4534,7 +4947,7 @@ object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.2, object-inspect@^1.9.0: +object-inspect@^1.12.3, object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== @@ -4632,14 +5045,14 @@ openapi-types@^12.1.0: resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.0.tgz#bd01acc937b73c9f6db2ac2031bf0231e21ebff0" integrity sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA== -openapi-typescript-codegen@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/openapi-typescript-codegen/-/openapi-typescript-codegen-0.23.0.tgz#702a651eefc536b27e87e4ad54a80a31d36487f0" - integrity sha512-gOJXy5g3H3HlLpVNN+USrNK2i2KYBmDczk9Xk34u6JorwrGiDJZUj+al4S+i9TXdfUQ/ZaLxE59Xf3wqkxGfqA== +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 "^9.3.0" - fs-extra "^10.1.0" + commander "^10.0.0" + fs-extra "^11.1.1" handlebars "^4.7.7" json-schema-ref-parser "^9.0.9" @@ -4687,6 +5100,16 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +overlayscrollbars-react@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/overlayscrollbars-react/-/overlayscrollbars-react-0.5.0.tgz#0272bdc6304c7228a58d30e5b678e97fd5c5d8dd" + integrity sha512-uCNTnkfWW74veoiEv3kSwoLelKt4e8gTNv65D771X3il0x5g5Yo0fUbro7SpQzR9yNgi23cvB2mQHTTdQH96pA== + +overlayscrollbars@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-2.1.1.tgz#a7414fe9c96cf140dbe4975bbe9312861750388d" + integrity sha512-xvs2g8Tcq9+CZDpLEUchN3YUzjJhnTWw9kwqT/qcC53FIkOyP9mqnRMot5sW16tcsPT1KaMyzF0AMXw/7E4a8g== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -4745,17 +5168,17 @@ 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@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621" - integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA== +patch-package@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-7.0.0.tgz#5c646b6b4b4bf37e5184a6950777b21dea6bb66e" + integrity sha512-eYunHbnnB2ghjTNc5iL1Uo7TsGMuXk0vibX3RFcE/CdVdXzmdbMsG/4K4IgoSuIkLTI5oHrMQk4+NkFqSed0BQ== dependencies: "@yarnpkg/lockfile" "^1.1.0" chalk "^4.1.2" - cross-spawn "^6.0.5" + ci-info "^3.7.0" + cross-spawn "^7.0.3" find-yarn-workspace-root "^2.0.0" fs-extra "^9.0.0" - is-ci "^2.0.0" klaw-sync "^6.0.0" minimist "^1.2.6" open "^7.4.2" @@ -4763,7 +5186,12 @@ patch-package@^6.5.1: semver "^5.6.0" slash "^2.0.0" tmp "^0.0.33" - yaml "^1.10.2" + 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" @@ -4775,11 +5203,6 @@ 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@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -4790,7 +5213,7 @@ path-key@^4.0.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== -path-parse@^1.0.7: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -4838,12 +5261,12 @@ postcss-values-parser@^6.0.2: is-url-superb "^4.0.0" quote-unquote "^1.0.0" -postcss@^8.1.7, postcss@^8.4.12, postcss@^8.4.21: - version "8.4.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" - integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== +postcss@^8.1.7, postcss@^8.4.23: + version "8.4.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" + integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== dependencies: - nanoid "^3.3.4" + nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" @@ -4872,22 +5295,22 @@ precinct@^8.1.0: node-source-walk "^4.2.0" precinct@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/precinct/-/precinct-9.0.1.tgz#64e7ea0de4bea1b73572e50531dfe297c7b8a7c7" - integrity sha512-hVNS6JvfvlZ64B3ezKeGAcVhIuOvuAiSVzagHX/+KjVPkYWoCNkfyMgCl1bjDtAFQSlzi95NcS9ykUWrl1L1vA== + version "9.2.1" + resolved "https://registry.yarnpkg.com/precinct/-/precinct-9.2.1.tgz#db0a67abff7b0a9a3b2b1ac33d170e8a5fcac7b2" + integrity sha512-uzKHaTyiVejWW7VJtHInb9KBUq9yl9ojxXGujhjhDmPon2wgZPBKQIKR+6csGqSlUeGXAA4MEFnU6DesxZib+A== dependencies: - commander "^9.1.0" - detective-amd "^4.0.1" - detective-cjs "^4.0.0" - detective-es6 "^3.0.0" - detective-less "^1.0.2" - detective-postcss "^6.0.1" - detective-sass "^4.0.1" - detective-scss "^3.0.0" - detective-stylus "^2.0.0" - detective-typescript "^9.0.0" - module-definition "^4.0.0" - node-source-walk "^5.0.0" + "@dependents/detective-less" "^3.0.1" + commander "^9.5.0" + detective-amd "^4.1.0" + detective-cjs "^4.1.0" + detective-es6 "^3.0.1" + detective-postcss "^6.1.1" + detective-sass "^4.1.1" + detective-scss "^3.0.1" + detective-stylus "^3.0.0" + detective-typescript "^9.1.1" + module-definition "^4.1.0" + node-source-walk "^5.0.1" prelude-ls@^1.2.1: version "1.2.1" @@ -4911,10 +5334,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.0.5, prettier@^2.7.1, prettier@^2.8.4: - version "2.8.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" - integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== +prettier@^2.0.5, prettier@^2.7.1, prettier@^2.8.8: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== pretty-ms@^7.0.1: version "7.0.1" @@ -4967,6 +5390,19 @@ quote-unquote@^1.0.0: resolved "https://registry.yarnpkg.com/quote-unquote/-/quote-unquote-1.0.0.tgz#67a9a77148effeaf81a4d428404a710baaac8a0b" integrity sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg== +railroad-diagrams@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" + integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A== + +randexp@0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" + integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ== + dependencies: + discontinuous-range "1.0.0" + ret "~0.1.10" + rc@1.2.8, rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -4977,6 +5413,13 @@ rc@1.2.8, rc@^1.2.7, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +re-resizable@6.9.6: + version "6.9.6" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.6.tgz#b95d37e3821481b56ddfb1e12862940a791e827d" + integrity sha512-0xYKS5+Z0zk+vICQlcZW+g54CcJTTmHluA7JUUgvERDxnKAnytylcyPsA+BSFi759s5hPlHmBRegFrwXs2FuBQ== + dependencies: + fast-memoize "^2.5.1" + re-resizable@^6.9.9: version "6.9.9" resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" @@ -5002,6 +5445,14 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" +react-draggable@4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.5.tgz#9e37fe7ce1a4cf843030f521a0a4cc41886d7e7c" + integrity sha512-OMHzJdyJbYTZo4uQE393fHcqqPYsEtkjfMgvCHr6rejT+Ezn4OZbNyGH50vv+SunC1RMvwOTSWkEODQLzw1M9g== + dependencies: + clsx "^1.1.1" + prop-types "^15.8.1" + react-dropzone@^14.2.3: version "14.2.3" resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.2.3.tgz#0acab68308fda2d54d1273a1e626264e13d4e84b" @@ -5011,10 +5462,10 @@ react-dropzone@^14.2.3: file-selector "^0.6.0" prop-types "^15.8.1" -react-fast-compare@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== +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" + integrity sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg== react-fast-compare@^2.0.1: version "2.0.4" @@ -5033,15 +5484,15 @@ react-focus-lock@^2.9.2: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-hotkeys-hook@4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.3.5.tgz#d77d62b839f54042d255bc111878967fd4958253" - integrity sha512-tfwTwKP3ga7n4naNS/JOByaEwEkTCoXYCepDuhXpj8mBx+sFszV5JecRWM2dv+PbOowmmBpHAFtTXTnG/p8UkQ== +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-i18next@^12.1.5: - version "12.2.0" - resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-12.2.0.tgz#010e3f6070b8d700442947233352ebe4b252d7a1" - integrity sha512-5XeVgSygaGfyFmDd2WcXvINRw2WEC1XviW1LXY/xLOEMzsCFRwKqfnHN+hUjla8ZipbVJR27GCMSuTr0BhBBBQ== +react-i18next@^12.2.2: + version "12.2.2" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-12.2.2.tgz#38a6fad11acf4f2abfc5611bdb6b1918d0f47578" + integrity sha512-KBB6buBmVKXUWNxXHdnthp+38gPyBT46hJCAIQ8rX19NFL/m2ahte2KARfIDf2tMnSAL7wwck6eDOd/9zn6aFg== dependencies: "@babel/runtime" "^7.20.6" html-parse-stringify "^3.0.1" @@ -5061,18 +5512,18 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-konva-utils@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/react-konva-utils/-/react-konva-utils-0.3.2.tgz#7641f437d9ed97a4dc829dbb47d2de75c07f8f5d" - integrity sha512-BocSYCPd58rCumFAL9sUs5aum+eRD53Amknd78Mm2BQln/XMZZS8zHq35HPbiZkSMcj5Q6fZ4foHa9aMLcPRIQ== +react-konva-utils@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/react-konva-utils/-/react-konva-utils-1.0.4.tgz#bce739a207f02fc5f0246f6ab16a0e295f5544af" + integrity sha512-K1J1K9MoVNGFrUxYt+dn7TUVqpppW3Y0fRcf42Ws1wzTQ2Od4qicCom9jnGxLiwh8zyhYaHAUn3hztgfTyYF7g== dependencies: react-konva "^18.0.0-0" use-image "^1.1.0" -react-konva@^18.0.0-0, react-konva@^18.2.4: - version "18.2.5" - resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-18.2.5.tgz#592692619c5f4a9c14726e146574ddc8bc468a7c" - integrity sha512-lTqJStcHnpGSXB9RlV7p5at3MpRML/TujzbuUDZRIInsLocJ/I4Nhhg3w6yJm9UV05kcwr88OY6LO+2zRyzXog== +react-konva@^18.0.0-0, react-konva@^18.2.7: + version "18.2.7" + resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-18.2.7.tgz#f01735ac9ae35a7cd0f3ca359a898374ce791d04" + integrity sha512-Q52ghaIR+2g3x14V5aIyt7VWNqPnWRotILo0Nj4YWVbNQisozrTJJ3/w68qb5Ar2fsYo7yXb4T6Nt4yZcGd2yg== dependencies: "@types/react-reconciler" "^0.28.2" its-fine "^1.0.6" @@ -5118,6 +5569,15 @@ react-remove-scroll@^2.5.5: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" +react-rnd@^10.4.1: + version "10.4.1" + resolved "https://registry.yarnpkg.com/react-rnd/-/react-rnd-10.4.1.tgz#9e1c3f244895d7862ef03be98b2a620848c3fba1" + integrity sha512-0m887AjQZr6p2ADLNnipquqsDq4XJu/uqVqI3zuoGD19tRm6uB83HmZWydtkilNp5EWsOHbLGF4IjWMdd5du8Q== + dependencies: + re-resizable "6.9.6" + react-draggable "4.4.5" + tslib "2.3.1" + react-style-singleton@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" @@ -5137,10 +5597,40 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react-zoom-pan-pinch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/react-zoom-pan-pinch/-/react-zoom-pan-pinch-2.6.1.tgz#5719fdd9515dc1f379a23350cbf99edd540b1281" - integrity sha512-4Cgdnn6OwN4DomY/E9NpAf0TyCtslEgwdYn96ZV/f5LKuw/FE3gcIBJiaKFmMGThDGV0yKN5mzO8noi34+UE4Q== +react-universal-interface@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" + integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== + +react-use@^17.4.0: + version "17.4.0" + resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.4.0.tgz#cefef258b0a6c534a5c8021c2528ac6e1a4cdc6d" + integrity sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q== + dependencies: + "@types/js-cookie" "^2.2.6" + "@xobotyi/scrollbar-width" "^1.9.5" + copy-to-clipboard "^3.3.1" + fast-deep-equal "^3.1.3" + fast-shallow-equal "^1.0.0" + js-cookie "^2.2.1" + nano-css "^5.3.1" + react-universal-interface "^0.6.2" + resize-observer-polyfill "^1.5.1" + screenfull "^5.1.0" + set-harmonic-interval "^1.0.1" + throttle-debounce "^3.0.1" + ts-easing "^0.2.0" + tslib "^2.1.0" + +react-virtuoso@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.3.5.tgz#1e882d435b2d3d8abf7c4b85235199cbfadd935d" + integrity sha512-MdWzmM9d8Gt5YGPIgGzRoqnYygTsriWlZrq+SqxphJTiiHs9cffnjf2Beo3SA3wRYzQJD8FI2HXtN5ACWzPFbQ== + +react-zoom-pan-pinch@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.0.7.tgz#def52f6886bc11e1b160dedf4250aae95470b94d" + integrity sha512-UJkk1Z7BMPIgfY+Qu4jGTlj+UyZQhrpJeCuK1gg31x57i3p8h4ZXfYWu3dFIiR+uRgfoe/koziwgCjA//T1rKA== react@^18.2.0: version "18.2.0" @@ -5162,9 +5652,9 @@ reactflow@^11.7.0: "@reactflow/node-toolbar" "1.1.11" readable-stream@^3.4.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62" - integrity sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ== + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -5197,7 +5687,7 @@ redux-thunk@^2.4.2: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== -redux@^4.2.0: +redux@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== @@ -5210,18 +5700,13 @@ regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.7: integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + version "1.5.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + define-properties "^1.2.0" + functions-have-names "^1.2.3" registry-auth-token@^4.0.0: version "4.2.2" @@ -5255,10 +5740,15 @@ requirejs@^2.3.5: resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== -reselect@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" - integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== +reselect@^4.1.8: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== + +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== resolve-dependency-path@^2.0.0: version "2.0.0" @@ -5270,12 +5760,12 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.19.0, resolve@^1.21.0, resolve@^1.22.1: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== +resolve@^1.19.0, resolve@^1.21.0, resolve@~1.22.1: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.11.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -5288,6 +5778,14 @@ resolve@^2.0.0-next.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@~1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -5303,12 +5801,17 @@ restore-cursor@^3.1.0: 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" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: +rfdc@^1.2.0, rfdc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== @@ -5327,6 +5830,18 @@ 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== + dependencies: + boolean "^3.1.4" + fast-json-stringify "^2.7.10" + fast-printf "^1.6.9" + globalthis "^1.0.2" + safe-stable-stringify "^2.4.1" + semver-compare "^1.0.0" + rollup-plugin-visualizer@^5.9.0: version "5.9.0" resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.9.0.tgz#013ac54fb6a9d7c9019e7eb77eced673399e5a0b" @@ -5344,13 +5859,20 @@ rollup@^2.77.2: optionalDependencies: fsevents "~2.3.2" -rollup@^3.10.0: - version "3.18.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.18.0.tgz#2354ba63ba66d6a09c652c3ea0dbcd9dad72bbde" - integrity sha512-J8C6VfEBjkvYPESMQYxKHxNOh4A5a3FlP+0BETGo34HEcE4eTlgCrO2+eWzlu2a/sHs2QUkZco+wscH7jhhgWg== +rollup@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.21.0.tgz#0a71517db56e150222670f88e5e7acfa4fede7c8" + integrity sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ== optionalDependencies: fsevents "~2.3.2" +rtl-css-js@^1.14.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.16.1.tgz#4b48b4354b0ff917a30488d95100fbf7219a3e80" + integrity sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg== + dependencies: + "@babel/runtime" "^7.1.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -5358,10 +5880,10 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.0.0, rxjs@^7.8.0: - version "7.8.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" - integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== +rxjs@^7.8.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" @@ -5379,6 +5901,11 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +safe-stable-stringify@^2.4.1: + 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== + sass-lookup@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/sass-lookup/-/sass-lookup-3.0.0.tgz#3b395fa40569738ce857bc258e04df2617c48cac" @@ -5393,6 +5920,16 @@ scheduler@^0.23.0: dependencies: loose-envify "^1.1.0" +screenfull@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" + integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== + +semver-compare@^1.0.0: + version "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-diff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -5400,7 +5937,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver@^5.5.0, semver@^5.6.0: +semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -5411,18 +5948,30 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: + version "7.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== + 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" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== +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== dependencies: - shebang-regex "^1.0.0" + type-fest "^2.12.2" + +set-harmonic-interval@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" + integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== shebang-command@^2.0.0: version "2.0.0" @@ -5431,20 +5980,15 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.7.3: - version "1.8.0" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba" - integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== +shell-quote@^1.8.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== side-channel@^1.0.4: version "1.0.4" @@ -5527,6 +6071,11 @@ source-map-support@~0.5.20: 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" + integrity sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA== + source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -5542,11 +6091,50 @@ source-map@^0.7.4: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -spawn-command@^0.0.2-1: +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +spawn-command@0.0.2-1: version "0.0.2-1" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-generator@^2.0.5: + version "2.0.10" + resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.10.tgz#8ae171e985ed62287d4f1ed55a1633b3fb53bb4d" + integrity sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ== + dependencies: + stackframe "^1.3.4" + +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + +stacktrace-gps@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz#0c40b24a9b119b20da4525c398795338966a2fb0" + integrity sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ== + dependencies: + source-map "0.5.6" + stackframe "^1.3.4" + +stacktrace-js@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" + integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== + dependencies: + error-stack-parser "^2.0.6" + stack-generator "^2.0.5" + stacktrace-gps "^3.0.4" + stream-to-array@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353" @@ -5554,11 +6142,16 @@ stream-to-array@^2.3.0: dependencies: any-promise "^1.1.0" -string-argv@^0.3.1: +string-argv@^0.3.1, string-argv@~0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== +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.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -5591,6 +6184,15 @@ string.prototype.matchall@^4.0.8: regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -5649,7 +6251,7 @@ strip-final-newline@^3.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -5659,10 +6261,10 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -stylis@4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" - integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== +stylis@4.1.4, stylis@^4.0.6: + version "4.1.4" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.4.tgz#9cb60e7153d8ac6d02d773552bf51c7a0344535b" + integrity sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ== stylus-lookup@^3.0.1: version "3.0.2" @@ -5686,7 +6288,7 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.1.0: +supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -5703,10 +6305,10 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser@^5.16.4: - version "5.16.5" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.5.tgz#1c285ca0655f467f92af1bbab46ab72d1cb08e5a" - integrity sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg== +terser@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.1.tgz#948f10830454761e2eeedc6debe45c532c83fd69" + integrity sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -5718,6 +6320,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +throttle-debounce@^3.0.1: + version "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" @@ -5772,10 +6379,28 @@ 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-easing@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" + integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== + +ts-error@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/ts-error/-/ts-error-1.0.6.tgz#277496f2a28de6c184cfce8dfd5cdd03a4e6b0fc" + integrity sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA== + ts-graphviz@^1.5.0: - version "1.5.5" - resolved "https://registry.yarnpkg.com/ts-graphviz/-/ts-graphviz-1.5.5.tgz#b5e9079c18289fb36b6b53f3d81da96445c37514" - integrity sha512-abon0Tlcgvxcqr8x+p8QH1fTbR2R4cEXKGZfT4OJONZWah2YfqkmERb6hrr82omAc1IHwk5PlF8g4BS/ECYvwQ== + version "1.6.1" + resolved "https://registry.yarnpkg.com/ts-graphviz/-/ts-graphviz-1.6.1.tgz#f44525c048cb8c8c188b7324d2a91015fd31ceaf" + integrity sha512-9aZKR7hoQAHXlgb7HvUND3y5VhEI5PMNVv/BfelPXebcsxdwZhBYbM8XpnV4NfiHV9O0/sAI9sQVuce0gogzlA== + +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-node@^10.7.0: version "10.9.1" @@ -5801,10 +6426,10 @@ ts-toolbelt@^9.6.0: resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5" integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w== -tsconfck@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-2.0.3.tgz#47b79fc6be3c5ec6ec9b3862d1c959e85038b117" - integrity sha512-o3DsPZO1+C98KqHMdAbWs30zpxD30kj8r9OLA4ML1yghx4khNDzaaShNalfluh8ZPPhzKe3qyVCP1HiZszSAsw== +tsconfck@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-2.1.1.tgz#9b51603d2712d1f4740fa14748ca886a2e1893e5" + integrity sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww== tsconfig-paths@^3.10.1: version "3.14.2" @@ -5817,14 +6442,19 @@ tsconfig-paths@^3.10.1: strip-bom "^3.0.0" tsconfig-paths@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz#4819f861eef82e6da52fb4af1e8c930a39ed979a" - integrity sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw== + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== dependencies: json5 "^2.2.2" minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tslib@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" @@ -5871,6 +6501,11 @@ type-fest@^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@^2.12.2: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -5887,16 +6522,21 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@4.9.5, typescript@^4.0.0, typescript@^4.5.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - typescript@^3.9.10, typescript@^3.9.5, typescript@^3.9.7: version "3.9.10" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== +typescript@^4.0.0, typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +typescript@~4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + uglify-js@^3.1.4: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" @@ -5924,6 +6564,11 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -6003,6 +6648,27 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +validator@^13.7.0: + version "13.9.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" + integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== + +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== + dependencies: + "@babel/parser" "^7.21.4" + "@microsoft/api-extractor" "^7.34.4" + "@rollup/pluginutils" "^5.0.2" + "@rushstack/node-core-library" "^3.55.2" + 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" + vite-plugin-eslint@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/vite-plugin-eslint/-/vite-plugin-eslint-1.8.1.tgz#0381b8272e7f0fd8b663311b64f7608d55d8b04c" @@ -6012,24 +6678,23 @@ vite-plugin-eslint@^1.8.1: "@types/eslint" "^8.4.5" rollup "^2.77.2" -vite-tsconfig-paths@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.0.5.tgz#c7c54e2cf7ccc5e600db565cecd7b368a1fa8889" - integrity sha512-/L/eHwySFYjwxoYt1WRJniuK/jPv+WGwgRGBYx3leciR5wBeqntQpUE6Js6+TJemChc+ter7fDBKieyEWDx4yQ== +vite-tsconfig-paths@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.0.tgz#bd2647d3eadafb65a10fc98a2ca565211f2eaf63" + integrity sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw== dependencies: debug "^4.1.1" globrex "^0.1.2" - tsconfck "^2.0.1" + tsconfck "^2.1.0" -vite@^4.1.2: - version "4.1.4" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0" - integrity sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg== +vite@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.3.tgz#26adb4aa01439fc4546c480ea547674d87289396" + integrity sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA== dependencies: - esbuild "^0.16.14" - postcss "^8.4.21" - resolve "^1.22.1" - rollup "^3.10.0" + esbuild "^0.17.5" + postcss "^8.4.23" + rollup "^3.21.0" optionalDependencies: fsevents "~2.3.2" @@ -6086,13 +6751,6 @@ which-typed-array@^1.1.9: has-tostringtag "^1.0.0" is-typed-array "^1.1.10" -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -6175,25 +6833,25 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0, yaml@^1.10.2: +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.1.3: - version "2.2.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4" - integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw== +yaml@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.2.tgz#ec551ef37326e6d42872dad1970300f8eb83a073" + integrity sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA== yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.3.1, yargs@^17.5.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== +yargs@^17.5.1, yargs@^17.7.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" escalade "^3.1.1" @@ -6218,6 +6876,17 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +z-schema@~5.0.2: + version "5.0.6" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" + integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== + dependencies: + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + validator "^13.7.0" + optionalDependencies: + commander "^10.0.0" + zustand@^4.3.1: version "4.3.7" resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.7.tgz#501b1f0393a7f1d103332e45ab574be5747fedce" diff --git a/tests/nodes/test_graph_execution_state.py b/tests/nodes/test_graph_execution_state.py index 2476786e41..3c262cf88e 100644 --- a/tests/nodes/test_graph_execution_state.py +++ b/tests/nodes/test_graph_execution_state.py @@ -25,6 +25,7 @@ def mock_services(): return InvocationServices( model_manager = None, # type: ignore events = None, # type: ignore + logger = None, # type: ignore images = None, # type: ignore latents = None, # type: ignore metadata = None, # type: ignore diff --git a/tests/nodes/test_invoker.py b/tests/nodes/test_invoker.py index d187c1b171..66c6b94d6f 100644 --- a/tests/nodes/test_invoker.py +++ b/tests/nodes/test_invoker.py @@ -23,6 +23,7 @@ def mock_services() -> InvocationServices: return InvocationServices( model_manager = None, # type: ignore events = TestEventService(), + logger = None, # type: ignore images = None, # type: ignore latents = None, # type: ignore metadata = None, # type: ignore