diff --git a/src/backend/langflow/api/callback.py b/src/backend/langflow/api/callback.py index baab596a4..d63e107c4 100644 --- a/src/backend/langflow/api/callback.py +++ b/src/backend/langflow/api/callback.py @@ -1,12 +1,13 @@ +import asyncio from typing import Any -from langchain.callbacks.base import AsyncCallbackHandler +from langchain.callbacks.base import AsyncCallbackHandler, BaseCallbackHandler from langflow.api.schemas import ChatResponse # https://github.com/hwchase17/chat-langchain/blob/master/callback.py -class StreamingLLMCallbackHandler(AsyncCallbackHandler): +class AsyncStreamingLLMCallbackHandler(AsyncCallbackHandler): """Callback handler for streaming LLM responses.""" def __init__(self, websocket): @@ -15,3 +16,17 @@ class StreamingLLMCallbackHandler(AsyncCallbackHandler): async def on_llm_new_token(self, token: str, **kwargs: Any) -> None: resp = ChatResponse(message=token, type="stream", intermediate_steps="") await self.websocket.send_json(resp.dict()) + + +class StreamingLLMCallbackHandler(BaseCallbackHandler): + """Callback handler for streaming LLM responses.""" + + def __init__(self, websocket): + self.websocket = websocket + + def on_llm_new_token(self, token: str, **kwargs: Any) -> None: + resp = ChatResponse(message=token, type="stream", intermediate_steps="") + + loop = asyncio.get_event_loop() + coroutine = self.websocket.send_json(resp.dict()) + asyncio.run_coroutine_threadsafe(coroutine, loop) diff --git a/src/backend/langflow/api/chat.py b/src/backend/langflow/api/chat.py index e25d0d2f1..4afa6c22f 100644 --- a/src/backend/langflow/api/chat.py +++ b/src/backend/langflow/api/chat.py @@ -1,4 +1,10 @@ -from fastapi import APIRouter, WebSocket +from fastapi import ( + APIRouter, + WebSocket, + WebSocketDisconnect, + WebSocketException, + status, +) from langflow.api.chat_manager import ChatManager from langflow.utils.logger import logger @@ -12,7 +18,9 @@ async def websocket_endpoint(client_id: str, websocket: WebSocket): """Websocket endpoint for chat.""" try: await chat_manager.handle_websocket(client_id, websocket) - except Exception as e: - # Log stack trace - logger.exception(e) - raise e + except WebSocketException as exc: + logger.error(exc) + await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc)) + except WebSocketDisconnect as exc: + logger.error(exc) + await websocket.close(code=status.WS_1000_NORMAL_CLOSURE, reason=str(exc)) diff --git a/src/backend/langflow/api/chat_manager.py b/src/backend/langflow/api/chat_manager.py index 2dab12e34..3636a94f3 100644 --- a/src/backend/langflow/api/chat_manager.py +++ b/src/backend/langflow/api/chat_manager.py @@ -3,7 +3,7 @@ import json from collections import defaultdict from typing import Dict, List -from fastapi import WebSocket +from fastapi import WebSocket, status from langflow.api.schemas import ChatMessage, ChatResponse, FileResponse from langflow.cache import cache_manager @@ -47,7 +47,6 @@ class ChatManager: def __init__(self): self.active_connections: Dict[str, WebSocket] = {} self.chat_history = ChatHistory() - self.chat_history.attach(self.on_chat_history_update) self.cache_manager = cache_manager self.cache_manager.attach(self.update) @@ -91,7 +90,7 @@ class ChatManager: self.active_connections[client_id] = websocket def disconnect(self, client_id: str): - del self.active_connections[client_id] + self.active_connections.pop(client_id, None) async def send_message(self, client_id: str, message: str): websocket = self.active_connections[client_id] @@ -109,7 +108,7 @@ class ChatManager: graph_data = payload start_resp = ChatResponse(message=None, type="start", intermediate_steps="") - self.chat_history.add_message(client_id, start_resp) + await self.send_json(client_id, start_resp) is_first_message = len(self.chat_history.get_history(client_id=client_id)) == 0 # Generate result and thought @@ -143,11 +142,12 @@ class ChatManager: break response = ChatResponse( - message=result or "", + message=result, intermediate_steps=intermediate_steps.strip(), type="end", files=file_responses, ) + await self.send_json(client_id, response) self.chat_history.add_message(client_id, response) async def handle_websocket(self, client_id: str, websocket: WebSocket): @@ -171,17 +171,24 @@ class ChatManager: with self.cache_manager.set_client_id(client_id): await self.process_message(client_id, payload) + except Exception as e: # Handle any exceptions that might occur logger.exception(e) # send a message to the client - await self.send_message(client_id, str(e)) - raise e - finally: await self.active_connections[client_id].close( - code=1000, reason="Client disconnected" + code=status.WS_1011_INTERNAL_ERROR, reason=str(e)[:120] ) self.disconnect(client_id) + finally: + try: + connection = self.active_connections.get(client_id) + if connection: + await connection.close(code=1000, reason="Client disconnected") + self.disconnect(client_id) + except Exception as e: + logger.exception(e) + self.disconnect(client_id) async def process_graph( @@ -203,8 +210,8 @@ async def process_graph( # Generate result and thought try: logger.debug("Generating result and thought") - result, intermediate_steps = get_result_and_steps( - langchain_object, chat_message.message or "" + result, intermediate_steps = await get_result_and_steps( + langchain_object, chat_message.message or "", websocket=websocket ) logger.debug("Generated result and intermediate_steps") return result, intermediate_steps diff --git a/src/backend/langflow/api/endpoints.py b/src/backend/langflow/api/endpoints.py index d4e592901..eae0e9f60 100644 --- a/src/backend/langflow/api/endpoints.py +++ b/src/backend/langflow/api/endpoints.py @@ -1,16 +1,15 @@ import logging -from typing import Any, Dict from fastapi import APIRouter, HTTPException -from langflow.interface.run import process_graph_cached -from langflow.interface.types import build_langchain_types_dict from langflow.api.schemas import ( ExportedFlow, GraphData, PredictRequest, PredictResponse, ) +from langflow.interface.run import process_graph_cached +from langflow.interface.types import build_langchain_types_dict # build router router = APIRouter() diff --git a/src/backend/langflow/api/schemas.py b/src/backend/langflow/api/schemas.py index 2d14bad50..f73b0642d 100644 --- a/src/backend/langflow/api/schemas.py +++ b/src/backend/langflow/api/schemas.py @@ -1,4 +1,4 @@ -from typing import Any, Union, Dict, List +from typing import Any, Dict, List, Union from pydantic import BaseModel, validator diff --git a/src/backend/langflow/interface/agents/custom.py b/src/backend/langflow/interface/agents/custom.py index 6d2efed68..d85ba8a56 100644 --- a/src/backend/langflow/interface/agents/custom.py +++ b/src/backend/langflow/interface/agents/custom.py @@ -1,3 +1,4 @@ +from abc import ABC from typing import Any, List, Optional from langchain import LLMChain @@ -27,14 +28,31 @@ from langchain.agents.agent_toolkits.vectorstore.prompt import ( from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS as SQL_FORMAT_INSTRUCTIONS from langchain.base_language import BaseLanguageModel - from langchain.memory.chat_memory import BaseChatMemory from langchain.sql_database import SQLDatabase from langchain.tools.python.tool import PythonAstREPLTool from langchain.tools.sql_database.prompt import QUERY_CHECKER -class JsonAgent(AgentExecutor): +class CustomAgentExecutor(AgentExecutor, ABC): + """Custom agent executor""" + + @staticmethod + def function_name(): + return "CustomAgentExecutor" + + @classmethod + def initialize(cls, *args, **kwargs): + pass + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def run(self, *args, **kwargs): + return super().run(*args, **kwargs) + + +class JsonAgent(CustomAgentExecutor): """Json agent""" @staticmethod @@ -70,7 +88,7 @@ class JsonAgent(AgentExecutor): return super().run(*args, **kwargs) -class CSVAgent(AgentExecutor): +class CSVAgent(CustomAgentExecutor): """CSV agent""" @staticmethod @@ -118,7 +136,7 @@ class CSVAgent(AgentExecutor): return super().run(*args, **kwargs) -class VectorStoreAgent(AgentExecutor): +class VectorStoreAgent(CustomAgentExecutor): """Vector Store agent""" @staticmethod @@ -156,7 +174,7 @@ class VectorStoreAgent(AgentExecutor): return super().run(*args, **kwargs) -class SQLAgent(AgentExecutor): +class SQLAgent(CustomAgentExecutor): """SQL agent""" @staticmethod @@ -228,7 +246,7 @@ class SQLAgent(AgentExecutor): return super().run(*args, **kwargs) -class VectorStoreRouterAgent(AgentExecutor): +class VectorStoreRouterAgent(CustomAgentExecutor): """Vector Store Router Agent""" @staticmethod @@ -267,7 +285,7 @@ class VectorStoreRouterAgent(AgentExecutor): return super().run(*args, **kwargs) -class InitializeAgent(AgentExecutor): +class InitializeAgent(CustomAgentExecutor): """Implementation of initialize_agent function""" @staticmethod diff --git a/src/backend/langflow/interface/importing/utils.py b/src/backend/langflow/interface/importing/utils.py index 0d14249cb..8c65bf60e 100644 --- a/src/backend/langflow/interface/importing/utils.py +++ b/src/backend/langflow/interface/importing/utils.py @@ -5,9 +5,9 @@ from typing import Any, Type from langchain import PromptTemplate from langchain.agents import Agent +from langchain.base_language import BaseLanguageModel from langchain.chains.base import Chain from langchain.chat_models.base import BaseChatModel -from langchain.base_language import BaseLanguageModel from langchain.tools import BaseTool diff --git a/src/backend/langflow/interface/loading.py b/src/backend/langflow/interface/loading.py index a2d9a799c..0e23c2b45 100644 --- a/src/backend/langflow/interface/loading.py +++ b/src/backend/langflow/interface/loading.py @@ -13,9 +13,9 @@ from langchain.agents.load_tools import ( ) from langchain.agents.loading import load_agent_from_config from langchain.agents.tools import Tool +from langchain.base_language import BaseLanguageModel from langchain.callbacks.base import BaseCallbackManager from langchain.chains.loading import load_chain_from_config -from langchain.base_language import BaseLanguageModel from langchain.llms.loading import load_llm_from_config from pydantic import ValidationError @@ -30,88 +30,19 @@ from langflow.utils import util, validate def instantiate_class(node_type: str, base_type: str, params: Dict) -> Any: """Instantiate class from module type and key, and params""" + params = convert_params_to_sets(params) + if node_type in CUSTOM_AGENTS: - if custom_agent := CUSTOM_AGENTS.get(node_type): - return custom_agent.initialize(**params) # type: ignore - params = process_params(params) + custom_agent = CUSTOM_AGENTS.get(node_type) + if custom_agent: + return custom_agent.initialize(**params) + class_object = import_by_type(_type=base_type, name=node_type) - # check if it is a class before using issubclass - - # if isinstance(class_object, type) and issubclass(class_object, BaseModel): - # # validate params - # fields = class_object.__fields__ - # params = {key: value for key, value in params.items() if key in fields} - - if base_type == "agents": - # We need to initialize it differently - return load_agent_executor(class_object, params) - elif base_type == "prompts": - if node_type == "ZeroShotPrompt": - if "tools" not in params: - params["tools"] = [] - return ZeroShotAgent.create_prompt(**params) - elif base_type == "tools": - if node_type == "JsonSpec": - params["dict_"] = load_file_into_dict(params.pop("path")) - return class_object(**params) - elif node_type == "PythonFunction": - # If the node_type is "PythonFunction" - # we need to get the function from the params - # which will be a str containing a python function - # and then we need to compile it and return the function - # as the instance - function_string = params["code"] - if isinstance(function_string, str): - return validate.eval_function(function_string) - raise ValueError("Function should be a string") - elif node_type.lower() == "tool": - return class_object(**params) - elif base_type == "toolkits": - loaded_toolkit = class_object(**params) - # Check if node_type has a loader - if toolkits_creator.has_create_function(node_type): - return load_toolkits_executor(node_type, loaded_toolkit, params) - return loaded_toolkit - elif base_type == "embeddings": - # ? Why remove model from params? - try: - params.pop("model") - except KeyError: - pass - # remove all params that are not in class_object.__fields__ - try: - return class_object(**params) - except ValidationError: - params = { - key: value - for key, value in params.items() - if key in class_object.__fields__ - } - return class_object(**params) - elif base_type == "vectorstores": - if len(params.get("documents", [])) == 0: - # Error when the pdf or other source was not correctly - # loaded. - raise ValueError( - "The source you provided did not load correctly or was empty." - "This may cause an error in the vectorstore." - ) - return class_object.from_documents(**params) - elif base_type == "documentloaders": - return class_object(**params).load() - elif base_type == "textsplitters": - documents = params.pop("documents") - text_splitter = class_object(**params) - return text_splitter.split_documents(documents) - elif base_type == "utilities": - if node_type == "SQLDatabase": - return class_object.from_uri(params.pop("uri")) - - return class_object(**params) + return instantiate_based_on_type(class_object, base_type, node_type, params) -def process_params(params): - """Process params""" +def convert_params_to_sets(params): + """Convert certain params to sets""" if "allowed_special" in params: params["allowed_special"] = set(params["allowed_special"]) if "disallowed_special" in params: @@ -119,6 +50,100 @@ def process_params(params): return params +def instantiate_based_on_type(class_object, base_type, node_type, params): + if base_type == "agents": + return instantiate_agent(class_object, params) + elif base_type == "prompts": + return instantiate_prompt(node_type, params) + elif base_type == "tools": + return instantiate_tool(node_type, class_object, params) + elif base_type == "toolkits": + return instantiate_toolkit(node_type, class_object, params) + elif base_type == "embeddings": + return instantiate_embedding(class_object, params) + elif base_type == "vectorstores": + return instantiate_vectorstore(class_object, params) + elif base_type == "documentloaders": + return instantiate_documentloader(class_object, params) + elif base_type == "textsplitters": + return instantiate_textsplitter(class_object, params) + elif base_type == "utilities": + return instantiate_utility(node_type, class_object, params) + else: + return class_object(**params) + + +def instantiate_agent(class_object, params): + return load_agent_executor(class_object, params) + + +def instantiate_prompt(node_type, params): + if node_type == "ZeroShotPrompt": + if "tools" not in params: + params["tools"] = [] + return ZeroShotAgent.create_prompt(**params) + return None # Or some other default action + + +def instantiate_tool(node_type, class_object, params): + if node_type == "JsonSpec": + params["dict_"] = load_file_into_dict(params.pop("path")) + return class_object(**params) + elif node_type == "PythonFunction": + function_string = params["code"] + if isinstance(function_string, str): + return validate.eval_function(function_string) + raise ValueError("Function should be a string") + elif node_type.lower() == "tool": + return class_object(**params) + return None # Or some other default action + + +def instantiate_toolkit(node_type, class_object, params): + loaded_toolkit = class_object(**params) + if toolkits_creator.has_create_function(node_type): + return load_toolkits_executor(node_type, loaded_toolkit, params) + return loaded_toolkit + + +def instantiate_embedding(class_object, params): + params.pop("model", None) + try: + return class_object(**params) + except ValidationError: + params = { + key: value + for key, value in params.items() + if key in class_object.__fields__ + } + return class_object(**params) + + +def instantiate_vectorstore(class_object, params): + if len(params.get("documents", [])) == 0: + raise ValueError( + "The source you provided did not load correctly or was empty." + "This may cause an error in the vectorstore." + ) + return class_object.from_documents(**params) + + +def instantiate_documentloader(class_object, params): + return class_object(**params).load() + + +def instantiate_textsplitter(class_object, params): + documents = params.pop("documents") + text_splitter = class_object(**params) + return text_splitter.split_documents(documents) + + +def instantiate_utility(node_type, class_object, params): + if node_type == "SQLDatabase": + return class_object.from_uri(params.pop("uri")) + return class_object(**params) + + def load_flow_from_json(path: str, build=True): # This is done to avoid circular imports from langflow.graph import Graph diff --git a/src/backend/langflow/interface/run.py b/src/backend/langflow/interface/run.py index 4f2143e2e..af80b7acd 100644 --- a/src/backend/langflow/interface/run.py +++ b/src/backend/langflow/interface/run.py @@ -4,9 +4,9 @@ from typing import Any, Dict from chromadb.errors import NotEnoughElementsException # type: ignore +from langflow.api.callback import AsyncStreamingLLMCallbackHandler, StreamingLLMCallbackHandler # type: ignore from langflow.cache.base import compute_dict_hash, load_cache, memoize_dict from langflow.graph.graph import Graph -from langflow.interface import loading from langflow.utils.logger import logger @@ -66,40 +66,6 @@ def build_langchain_object(data_graph): return graph.build() -def process_graph(data_graph: Dict[str, Any]): - """ - Process graph by extracting input variables and replacing ZeroShotPrompt - with PromptTemplate,then run the graph and return the result and thought. - """ - # Load langchain object - logger.debug("Loading langchain object") - message = data_graph.pop("message", "") - is_first_message = len(data_graph.get("chatHistory", [])) == 0 - computed_hash, langchain_object = load_langchain_object( - data_graph, is_first_message - ) - logger.debug("Loaded langchain object") - - if langchain_object is None: - # Raise user facing error - raise ValueError( - "There was an error loading the langchain_object. Please, check all the nodes and try again." - ) - - # Generate result and thought - logger.debug("Generating result and thought") - result, thought = get_result_and_steps(langchain_object, message) - logger.debug("Generated result and thought") - - # Save langchain_object to cache - # We have to save it here because if the - # memory is updated we need to keep the new values - logger.debug("Saving langchain object to cache") - # save_cache(computed_hash, langchain_object, is_first_message) - logger.debug("Saved langchain object to cache") - return {"result": str(result), "thought": thought.strip()} - - def process_graph_cached(data_graph: Dict[str, Any], message: str): """ Process graph by extracting input variables and replacing ZeroShotPrompt @@ -184,8 +150,9 @@ def fix_memory_inputs(langchain_object): update_memory_keys(langchain_object, possible_new_mem_key) -def get_result_and_steps(langchain_object, message: str): +async def get_result_and_steps(langchain_object, message: str, **kwargs): """Get result and thought from extracted json""" + try: if hasattr(langchain_object, "verbose"): langchain_object.verbose = True @@ -205,17 +172,21 @@ def get_result_and_steps(langchain_object, message: str): # https://github.com/hwchase17/langchain/issues/2068 # Deactivating until we have a frontend solution # to display intermediate steps - langchain_object.return_intermediate_steps = False + langchain_object.return_intermediate_steps = True fix_memory_inputs(langchain_object) with io.StringIO() as output_buffer, contextlib.redirect_stdout(output_buffer): try: - output = langchain_object(chat_input) - except ValueError as exc: + async_callbacks = [AsyncStreamingLLMCallbackHandler(**kwargs)] + output = await langchain_object.acall( + chat_input, callbacks=async_callbacks + ) + except Exception as exc: # make the error message more informative logger.debug(f"Error: {str(exc)}") - output = langchain_object.run(chat_input) + sync_callbacks = [StreamingLLMCallbackHandler(**kwargs)] + output = langchain_object(chat_input, callbacks=sync_callbacks) intermediate_steps = ( output.get("intermediate_steps", []) if isinstance(output, dict) else [] diff --git a/src/backend/langflow/interface/utils.py b/src/backend/langflow/interface/utils.py index e8b3e417e..7368fda3e 100644 --- a/src/backend/langflow/interface/utils.py +++ b/src/backend/langflow/interface/utils.py @@ -4,13 +4,9 @@ import os from io import BytesIO import yaml -from langchain.callbacks.manager import AsyncCallbackManager -from langchain.chat_models import AzureChatOpenAI, ChatOpenAI -from langchain.llms import AzureOpenAI, OpenAI +from langchain.base_language import BaseLanguageModel from PIL.Image import Image -from langflow.api.callback import StreamingLLMCallbackHandler - def load_file_into_dict(file_path: str) -> dict: if not os.path.exists(file_path): @@ -48,10 +44,7 @@ def try_setting_streaming_options(langchain_object, websocket): langchain_object.llm_chain, "llm" ): llm = langchain_object.llm_chain.llm - if isinstance(llm, (OpenAI, ChatOpenAI, AzureOpenAI, AzureChatOpenAI)): + if isinstance(llm, BaseLanguageModel): llm.streaming = bool(hasattr(llm, "streaming")) - stream_handler = StreamingLLMCallbackHandler(websocket) - stream_manager = AsyncCallbackManager([stream_handler]) - llm.callback_manager = stream_manager return langchain_object diff --git a/src/backend/langflow/template/nodes.py b/src/backend/langflow/template/nodes.py index 61a41589b..6ce08e57b 100644 --- a/src/backend/langflow/template/nodes.py +++ b/src/backend/langflow/template/nodes.py @@ -123,6 +123,13 @@ class MidJourneyPromptChainNode(FrontendNode): multiline=False, name="llm", ), + TemplateField( + field_type="BaseChatMemory", + required=False, + show=True, + name="memory", + advanced=False, + ), ], ) description: str = "MidJourneyPromptChain is a chain you can use to generate new MidJourney prompts." diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 9b90b435e..a85623dc7 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -13,6 +13,7 @@ "@headlessui/react": "^1.7.10", "@heroicons/react": "^2.0.15", "@mui/material": "^5.11.9", + "@tabler/icons-react": "^2.17.0", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/line-clamp": "^0.4.4", "@testing-library/jest-dom": "^5.16.5", @@ -34,13 +35,21 @@ "react-error-boundary": "^4.0.2", "react-icons": "^4.8.0", "react-laag": "^2.0.5", + "react-markdown": "^8.0.7", "react-router-dom": "^6.8.1", "react-scripts": "5.0.1", + "react-syntax-highlighter": "^15.5.0", "react-tabs": "^6.0.0", "reactflow": "^11.5.5", + "rehype-mathjax": "^4.0.2", + "remark-gfm": "^3.0.1", + "remark-math": "^5.1.1", "tailwindcss": "^3.2.6", "typescript": "^4.9.5", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.9" } }, "node_modules/@adobe/css-tools": { @@ -3921,6 +3930,31 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@tabler/icons": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-2.17.0.tgz", + "integrity": "sha512-UeJaylOGNRhQKyDlgZfrQ3UPSGlfVQuXcmCsTYeXioKKepibW6VZ3H36Lo1jvBTBkQD2e9m+k2NxwkztOTXwrA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-2.17.0.tgz", + "integrity": "sha512-kuEW+qNwRqcK5iMl7qTapzX2NiMOwPg4Az01d+IZ1DIMwaZ7iKPJaIor2ihKFLPYrT9D5BZHXB8R5mSkw0FETg==", + "dependencies": { + "@tabler/icons": "2.17.0", + "prop-types": "^15.7.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@tailwindcss/forms": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", @@ -3940,6 +3974,34 @@ "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.9.tgz", + "integrity": "sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@testing-library/dom": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", @@ -4455,6 +4517,14 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/eslint": { "version": "8.21.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.0.tgz", @@ -4512,6 +4582,14 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", @@ -4574,11 +4652,34 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/katex": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.0.tgz", + "integrity": "sha512-hz+S3nV6Mym5xPbT9fnO8dDhBFQguMYpY0Ipxv06JMi1ORgnEM4M1ymWDUhUNer3ElLmT583opRo4RzxKmh9jw==" + }, + "node_modules/@types/mathjax": { + "version": "0.0.37", + "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.37.tgz", + "integrity": "sha512-y0WSZBtBNQwcYipTU/BhgeFu1EZNlFvUNCmkMXV9kBQZq7/o5z82dNVyH3yy2Xv5zzeNeQoHSL4Xm06+EQiH+g==" + }, + "node_modules/@types/mdast": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz", + "integrity": "sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "node_modules/@types/node": { "version": "16.18.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.12.tgz", @@ -4714,6 +4815,16 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" }, + "node_modules/@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "node_modules/@types/web": { + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.46.tgz", + "integrity": "sha512-ki0OmbjSdAEfvmy5AYWFpMkRsPW+6h4ibQ4tzk8SJsS9dkrrD3B/U1eVvdNNWxAzntjq6o2sjSia6UBCoPH+Yg==" + }, "node_modules/@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -5858,6 +5969,15 @@ "babel-plugin-transform-react-remove-prop-types": "^0.4.24" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6159,6 +6279,15 @@ "node": ">=4" } }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -6180,6 +6309,33 @@ "node": ">=10" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/check-types": { "version": "11.2.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", @@ -6357,6 +6513,15 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -7081,6 +7246,18 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -7184,6 +7361,14 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -7256,6 +7441,14 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-match-patch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", @@ -8346,6 +8539,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -8541,6 +8742,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8590,6 +8796,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -8964,6 +9182,14 @@ "node": ">= 6" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9356,6 +9582,84 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hast-util-from-dom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-4.2.0.tgz", + "integrity": "sha512-t1RJW/OpJbCAJQeKi3Qrj1cAOLA0+av/iPFori112+0X7R3wng+jxLA+kXec8K4szqPRGI8vPxbbpEYvvpwaeQ==", + "dependencies": { + "hastscript": "^7.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz", + "integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-3.1.2.tgz", + "integrity": "sha512-tcllLfp23dJJ+ju5wCCZHVpzsQQ43+moJbqVX3jNWPB7z/KFC4FyZD6R7y94cHL6MQ33YtMZL8Z0aIXXI4XFTw==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0", + "hast-util-is-element": "^2.0.0", + "unist-util-find-after": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", + "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -9364,6 +9668,14 @@ "he": "bin/he" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -9734,6 +10046,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, "node_modules/internal-slot": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", @@ -9755,6 +10072,28 @@ "node": ">= 10" } }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -9825,6 +10164,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -9861,6 +10222,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -9910,6 +10280,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -12350,6 +12729,21 @@ "node": ">=4.0" } }, + "node_modules/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-Xk9C6oGKRwJTfqfIbtr0Kes9OSv6IFsuhFGc7tW4urlpMJtuh+7YhzU6YEG9n8gmWKcMAFzkp7nr+r69kV0zrA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -12460,6 +12854,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -12475,6 +12875,12 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -12495,6 +12901,15 @@ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -12514,6 +12929,19 @@ "tslib": "^2.0.3" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -12568,6 +12996,254 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mathjax-full": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz", + "integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==", + "dependencies": { + "esm": "^3.2.25", + "mhchemparser": "^4.1.0", + "mj-context-menu": "^0.6.1", + "speech-rule-engine": "^4.0.6" + } + }, + "node_modules/mdast-util-definitions": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", + "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", + "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz", + "integrity": "sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", + "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", + "dependencies": { + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", + "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", + "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", + "dependencies": { + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", + "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-2.0.2.tgz", + "integrity": "sha512-8gmkKVp9v6+Tgjtq6SYx9kGPpTf6FVYRa53/DLh479aldR9AyP48qeVOgNZ5X7QUK7nOy4yw7vg6mbiGcs9jWQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz", + "integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==", + "dependencies": { + "@types/mdast": "^3.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", + "integrity": "sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -12618,6 +13294,565 @@ "node": ">= 0.6" } }, + "node_modules/mhchemparser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", + "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" + }, + "node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz", + "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", + "micromark-extension-gfm-strikethrough": "^1.0.0", + "micromark-extension-gfm-table": "^1.0.0", + "micromark-extension-gfm-tagfilter": "^1.0.0", + "micromark-extension-gfm-task-list-item": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.4.tgz", + "integrity": "sha512-WCssN+M9rUyfHN5zPBn3/f0mIA7tqArHL/EKbv3CZK+LT2rG77FEikIQEqBkv46fOqXQK4NEW/Pc7Z27gshpeg==", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.0.tgz", + "integrity": "sha512-RWYce7j8+c0n7Djzv5NzGEGitNNYO3uj+h/XYMdS/JinH1Go+/Qkomg/rfxExFzYTiydaV6GLeffGO5qcJbMPA==", + "dependencies": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.5.tgz", + "integrity": "sha512-X0oI5eYYQVARhiNfbETy7BfLSmSilzN1eOuoRnrf9oUNsPRrWOAe9UqSizgw1vNxQBfOwL+n2610S3bYjVNi7w==", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz", + "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", + "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", + "dependencies": { + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.4.tgz", + "integrity": "sha512-9XlIUUVnYXHsFF2HZ9jby4h3npfX10S1coXTnV035QGPgrtNYQq3J6IfIvcCIUAJrrqBVi5BqA/LmaOMJqPwMQ==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-2.1.0.tgz", + "integrity": "sha512-WH+fJkveMvM3ZN+deb/jT3UW623x8xO9ycfJNDC+UQXX+V72RO6hT9KqxA7c8XFwozAFJ7tufOeG+x/CVSXHUw==", + "dependencies": { + "@types/katex": "^0.16.0", + "katex": "^0.16.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -12775,6 +14010,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mj-context-menu": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", + "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -12786,6 +14026,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -13202,6 +14450,32 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -14665,6 +15939,14 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -14705,6 +15987,15 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/property-information": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.2.0.tgz", + "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -15084,6 +16375,41 @@ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-markdown": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", + "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/react-markdown/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -15194,6 +16520,21 @@ } } }, + "node_modules/react-syntax-highlighter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", + "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/react-tabs": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.0.0.tgz", @@ -15292,6 +16633,83 @@ "node": ">=8" } }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/refractor/node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/refractor/node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -15388,6 +16806,246 @@ "jsesc": "bin/jsesc" } }, + "node_modules/rehype-mathjax": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rehype-mathjax/-/rehype-mathjax-4.0.2.tgz", + "integrity": "sha512-9q4Q4icTIbM5RtvQ4XquvEApGV2oDMaSVa5G3DwXomWU4fAPWYcOOt+iQRNaIH3RBMbFF239QbE5K7hm7rxMPQ==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mathjax": "^0.0.37", + "@types/web": "^0.0.46", + "hast-util-from-dom": "^4.0.0", + "hast-util-to-text": "^3.1.0", + "jsdom": "^18.0.0", + "mathjax-full": "^3.0.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-mathjax/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/rehype-mathjax/node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" + }, + "node_modules/rehype-mathjax/node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/data-urls/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rehype-mathjax/node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rehype-mathjax/node_modules/jsdom": { + "version": "18.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-18.1.1.tgz", + "integrity": "sha512-NmJQbjQ/gpS/1at/ce3nCx89HbXL/f5OcenBe8wU1Eik0ROhyUc3LtmG3567dEHAGXkN8rmILW/qtCOPxPHQJw==", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.5.0", + "acorn-globals": "^6.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.1", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0", + "ws": "^8.2.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/rehype-mathjax/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/w3c-xmlserializer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/whatwg-url": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", + "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/rehype-mathjax/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/rehype-mathjax/node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "engines": { + "node": ">=12" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -15396,6 +17054,65 @@ "node": ">= 0.10" } }, + "node_modules/remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-5.1.1.tgz", + "integrity": "sha512-cE5T2R/xLVtfFI4cCePtiRn+e6jKMtFDR3P8V3qpv8wpKjwvHoBA4eJzvX+nVrnlNy0911bdGmuspCSwetfYHw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-math": "^2.0.0", + "micromark-extension-math": "^2.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/renderkid": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", @@ -15650,6 +17367,17 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -16086,6 +17814,15 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "deprecated": "Please use @jridgewell/sourcemap-codec instead" }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -16114,6 +17851,27 @@ "wbuf": "^1.7.3" } }, + "node_modules/speech-rule-engine": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz", + "integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==", + "dependencies": { + "commander": "9.2.0", + "wicked-good-xpath": "1.3.0", + "xmldom-sre": "0.1.31" + }, + "bin": { + "sre": "bin/sre" + } + }, + "node_modules/speech-rule-engine/node_modules/commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -16340,6 +18098,14 @@ "webpack": "^5.0.0" } }, + "node_modules/style-to-object": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz", + "integrity": "sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -16760,6 +18526,24 @@ "node": ">=8" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", @@ -16944,6 +18728,35 @@ "node": ">=4" } }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -16955,6 +18768,91 @@ "node": ">=8" } }, + "node_modules/unist-util-find-after": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-4.0.1.tgz", + "integrity": "sha512-QO/PuPMm2ERxC6vFXEPtmAutOopy5PknD+Oq64gGwxKtk4xwo9Z97t9Av1obPmGU0IyTa6EKYUfTrK2QJS3Ozw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-generated": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", + "integrity": "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", + "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/universal-cookie": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz", @@ -17092,6 +18990,31 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uvu/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", @@ -17113,6 +19036,34 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -17161,6 +19112,15 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/web-vitals": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", @@ -17607,6 +19567,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wicked-good-xpath": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", + "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==" + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -18001,6 +19966,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xmldom-sre": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", + "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", + "engines": { + "node": ">=0.1" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -18088,6 +20061,15 @@ "optional": true } } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/src/frontend/package.json b/src/frontend/package.json index 7b20bb596..316eb97a1 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -8,6 +8,7 @@ "@headlessui/react": "^1.7.10", "@heroicons/react": "^2.0.15", "@mui/material": "^5.11.9", + "@tabler/icons-react": "^2.17.0", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/line-clamp": "^0.4.4", "@testing-library/jest-dom": "^5.16.5", @@ -29,10 +30,15 @@ "react-error-boundary": "^4.0.2", "react-icons": "^4.8.0", "react-laag": "^2.0.5", + "react-markdown": "^8.0.7", "react-router-dom": "^6.8.1", "react-scripts": "5.0.1", + "react-syntax-highlighter": "^15.5.0", "react-tabs": "^6.0.0", "reactflow": "^11.5.5", + "rehype-mathjax": "^4.0.2", + "remark-gfm": "^3.0.1", + "remark-math": "^5.1.1", "tailwindcss": "^3.2.6", "typescript": "^4.9.5", "web-vitals": "^2.1.4" @@ -61,5 +67,8 @@ "last 1 safari version" ] }, - "proxy": "http://127.0.0.1:7860" -} \ No newline at end of file + "proxy": "http://127.0.0.1:7860", + "devDependencies": { + "@tailwindcss/typography": "^0.5.9" + } +} diff --git a/src/frontend/src/App.css b/src/frontend/src/App.css index 319e2ba39..be7173d7f 100644 --- a/src/frontend/src/App.css +++ b/src/frontend/src/App.css @@ -3,45 +3,45 @@ @tailwind utilities; .App { - text-align: center; + text-align: center; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 20s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } -@font-face{ - font-family: text-security-disc; - src: url("assets/text-security-disc.woff") format("woff"); -} \ No newline at end of file +@font-face { + font-family: text-security-disc; + src: url("assets/text-security-disc.woff") format("woff"); +} diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 1a2eeb9e6..c79904661 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -198,7 +198,9 @@ export default function ParameterComponent({ save(); }} /> - ):(<>)} + ) : ( + <> + )} ); diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index cc6738dcb..8af96387c 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -1,10 +1,5 @@ import { Cog6ToothIcon, TrashIcon } from "@heroicons/react/24/outline"; -import { - classNames, - nodeColors, - nodeIcons, - toNormalCase, -} from "../../utils"; +import { classNames, nodeColors, nodeIcons, toNormalCase } from "../../utils"; import ParameterComponent from "./components/parameterComponent"; import { typesContext } from "../../contexts/typesContext"; import { useContext, useState, useEffect, useRef } from "react"; @@ -16,149 +11,148 @@ import { useCallback } from "react"; import { TabsContext } from "../../contexts/tabsContext"; import { debounce } from "../../utils"; export default function GenericNode({ - data, - selected, + data, + selected, }: { - data: NodeDataType; - selected: boolean; + data: NodeDataType; + selected: boolean; }) { - const { setErrorData } = useContext(alertContext); - const showError = useRef(true); - const { types, deleteNode } = useContext(typesContext); - const { openPopUp } = useContext(PopUpContext); - const Icon = nodeIcons[types[data.type]]; - const [validationStatus, setValidationStatus] = useState("idle"); - // State for outline color - const [isValid, setIsValid] = useState(false); - const { save } = useContext(TabsContext); - const { reactFlowInstance } = useContext(typesContext); - const [params, setParams] = useState([]); + const { setErrorData } = useContext(alertContext); + const showError = useRef(true); + const { types, deleteNode } = useContext(typesContext); + const { openPopUp } = useContext(PopUpContext); + const Icon = nodeIcons[types[data.type]]; + const [validationStatus, setValidationStatus] = useState("idle"); + // State for outline color + const [isValid, setIsValid] = useState(false); + const { save } = useContext(TabsContext); + const { reactFlowInstance } = useContext(typesContext); + const [params, setParams] = useState([]); + useEffect(() => { + if (reactFlowInstance) { + setParams(Object.values(reactFlowInstance.toObject())); + } + }, [save]); - useEffect(() => { - if (reactFlowInstance) { - setParams(Object.values(reactFlowInstance.toObject())); - } - }, [save]); + const validateNode = useCallback( + debounce(async () => { + try { + const response = await fetch(`/validate/node/${data.id}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(reactFlowInstance.toObject()), + }); - const validateNode = useCallback( - debounce(async () => { - try { - const response = await fetch(`/validate/node/${data.id}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(reactFlowInstance.toObject()), - }); + if (response.status === 200) { + setValidationStatus("success"); + } else if (response.status === 500) { + setValidationStatus("error"); + } + } catch (error) { + // console.error("Error validating node:", error); + setValidationStatus("error"); + } + }, 1000), // Adjust the debounce delay (500ms) as needed + [reactFlowInstance, data.id] + ); + useEffect(() => { + if (params.length > 0) { + validateNode(); + } + }, [params, validateNode]); - if (response.status === 200) { - setValidationStatus("success"); - } else if (response.status === 500) { - setValidationStatus("error"); - } - } catch (error) { - // console.error("Error validating node:", error); - setValidationStatus("error"); - } - }, 1000), // Adjust the debounce delay (500ms) as needed - [reactFlowInstance, data.id] - ); - useEffect(() => { - if (params.length > 0) { - validateNode(); - } - }, [params, validateNode]); + useEffect(() => { + if (validationStatus === "success") { + setIsValid(true); + } else { + setIsValid(false); + } + }, [validationStatus]); - useEffect(() => { - if (validationStatus === "success") { - setIsValid(true); - } else { - setIsValid(false); - } - }, [validationStatus]); + if (!Icon) { + if (showError.current) { + setErrorData({ + title: data.type + ? `The ${data.type} node could not be rendered, please review your json file` + : "There was a node that can't be rendered, please review your json file", + }); + showError.current = false; + } + deleteNode(data.id); + return; + } - if (!Icon) { - if (showError.current) { - setErrorData({ - title: data.type - ? `The ${data.type} node could not be rendered, please review your json file` - : "There was a node that can't be rendered, please review your json file", - }); - showError.current = false; - } - deleteNode(data.id); - return; - } + return ( +
+
+
+ +
{data.type}
+
+
+ + +
+
- return ( -
-
-
- -
{data.type}
-
-
- - -
-
+
+
+ {data.node.description} +
-
-
- {data.node.description} -
- - <> - {Object.keys(data.node.template) - .filter((t) => t.charAt(0) !== "_") - .map((t: string, idx) => ( -
- {/* {idx === 0 ? ( + <> + {Object.keys(data.node.template) + .filter((t) => t.charAt(0) !== "_") + .map((t: string, idx) => ( +
+ {/* {idx === 0 ? (
)} */} - {data.node.template[t].show && - !data.node.template[t].advanced ? ( - - ) : ( - <> - )} -
- ))} -
- {" "} -
- {/*
+ {data.node.template[t].show && + !data.node.template[t].advanced ? ( + + ) : ( + <> + )} +
+ ))} +
+ {" "} +
+ {/*
Output
*/} - - -
-
- ); + + +
+
+ ); } diff --git a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx index d9428a34b..6bf9bee57 100644 --- a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx +++ b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx @@ -1,8 +1,8 @@ import { - XCircleIcon, - XMarkIcon, - InformationCircleIcon, - CheckCircleIcon, + XCircleIcon, + XMarkIcon, + InformationCircleIcon, + CheckCircleIcon, } from "@heroicons/react/24/outline"; import { Link } from "react-router-dom"; import { Transition } from "@headlessui/react"; @@ -10,145 +10,145 @@ import { useState } from "react"; import { SingleAlertComponentType } from "../../../../types/alerts"; export default function SingleAlert({ - dropItem, - removeAlert, + dropItem, + removeAlert, }: SingleAlertComponentType) { - const [show, setShow] = useState(true); - const type = dropItem.type; + const [show, setShow] = useState(true); + const type = dropItem.type; - return ( - - {type === "error" ? ( -
-
-
-
-

- {dropItem.title} -

- {dropItem.list ? ( -
-
    - {dropItem.list.map((item, idx) => ( -
  • {item}
  • - ))} -
-
- ) : ( - <> - )} -
-
-
- -
-
-
- ) : type === "notice" ? ( -
-
-
-
-

{dropItem.title}

-

- {dropItem.link ? ( - - Details - - ) : ( - <> - )} -

-
-
-
- -
-
-
- ) : ( -
-
-
-
-

- {dropItem.title} -

-
-
-
- -
-
-
- )} -
- ); + return ( + + {type === "error" ? ( +
+
+
+
+

+ {dropItem.title} +

+ {dropItem.list ? ( +
+
    + {dropItem.list.map((item, idx) => ( +
  • {item}
  • + ))} +
+
+ ) : ( + <> + )} +
+
+
+ +
+
+
+ ) : type === "notice" ? ( +
+
+
+
+

{dropItem.title}

+

+ {dropItem.link ? ( + + Details + + ) : ( + <> + )} +

+
+
+
+ +
+
+
+ ) : ( +
+
+
+
+

+ {dropItem.title} +

+
+
+
+ +
+
+
+ )} +
+ ); } diff --git a/src/frontend/src/alerts/alertDropDown/index.tsx b/src/frontend/src/alerts/alertDropDown/index.tsx index 73ee9413c..84a376aaf 100644 --- a/src/frontend/src/alerts/alertDropDown/index.tsx +++ b/src/frontend/src/alerts/alertDropDown/index.tsx @@ -7,60 +7,60 @@ import { AlertDropdownType } from "../../types/alerts"; import { PopUpContext } from "../../contexts/popUpContext"; import { useOnClickOutside } from "../hooks/useOnClickOutside"; export default function AlertDropdown({}: AlertDropdownType) { - const { closePopUp } = useContext(PopUpContext); - const componentRef = useRef(null); + const { closePopUp } = useContext(PopUpContext); + const componentRef = useRef(null); - // Use the custom hook - useOnClickOutside(componentRef, () => { - closePopUp(); - }); + // Use the custom hook + useOnClickOutside(componentRef, () => { + closePopUp(); + }); - const { - notificationList, - clearNotificationList, - removeFromNotificationList, - } = useContext(alertContext); + const { + notificationList, + clearNotificationList, + removeFromNotificationList, + } = useContext(alertContext); - return ( -
-
- Notifications -
- - -
-
-
- {notificationList.length !== 0 ? ( - notificationList.map((alertItem, index) => ( - - )) - ) : ( -
- No new notifications -
- )} -
-
- ); + return ( +
+
+ Notifications +
+ + +
+
+
+ {notificationList.length !== 0 ? ( + notificationList.map((alertItem, index) => ( + + )) + ) : ( +
+ No new notifications +
+ )} +
+
+ ); } diff --git a/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts b/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts index 249133d96..3046d41a4 100644 --- a/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts +++ b/src/frontend/src/alerts/hooks/useOnClickOutside/index.ts @@ -1,33 +1,33 @@ import { useEffect } from "react"; export function useOnClickOutside(ref, handler) { - useEffect(() => { - const listener = (event) => { - // Do nothing if clicking ref's element or its children - if (!ref.current || ref.current.contains(event.target)) { - return; - } + useEffect(() => { + const listener = (event) => { + // Do nothing if clicking ref's element or its children + if (!ref.current || ref.current.contains(event.target)) { + return; + } - handler(event); - }; + handler(event); + }; - // Attach the listener to the document - document.addEventListener("mousedown", listener, { passive: true }); + // Attach the listener to the document + document.addEventListener("mousedown", listener, { passive: true }); - // Attach the listener to the react-flow instance - const reactFlowContainer = document.querySelector(".react-flow"); - if (reactFlowContainer) { - reactFlowContainer.addEventListener("mousedown", listener, { - passive: true, - }); - } + // Attach the listener to the react-flow instance + const reactFlowContainer = document.querySelector(".react-flow"); + if (reactFlowContainer) { + reactFlowContainer.addEventListener("mousedown", listener, { + passive: true, + }); + } - // Clean up the listener when the component is unmounted - return () => { - document.removeEventListener("mousedown", listener); - if (reactFlowContainer) { - reactFlowContainer.removeEventListener("mousedown", listener); - } - }; - }, [ref, handler]); // Rerun only if ref or handler changes + // Clean up the listener when the component is unmounted + return () => { + document.removeEventListener("mousedown", listener); + if (reactFlowContainer) { + reactFlowContainer.removeEventListener("mousedown", listener); + } + }; + }, [ref, handler]); // Rerun only if ref or handler changes } diff --git a/src/frontend/src/components/CrashErrorComponent/index.tsx b/src/frontend/src/components/CrashErrorComponent/index.tsx index 7864e6d65..de3cea182 100644 --- a/src/frontend/src/components/CrashErrorComponent/index.tsx +++ b/src/frontend/src/components/CrashErrorComponent/index.tsx @@ -2,12 +2,14 @@ export default function CrashErrorComponent({ error, resetErrorBoundary }) { return (
-

Oops! An unknown error has occurred.

+

+ Oops! An unknown error has occurred. +

- Please click the 'Reset Application' button - to restore the application's state. If the error persists, please - create an issue on our GitHub page. We apologize for any inconvenience - this may have caused. + Please click the 'Reset Application' button to restore the + application's state. If the error persists, please create an issue on + our GitHub page. We apologize for any inconvenience this may have + caused.

)} {chat.thought && chat.thought !== "" && !hidden &&

} -
- {chat.message} +
+ {chat.message}
diff --git a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx index 9d5f67e0c..2759b13a5 100644 --- a/src/frontend/src/components/chatComponent/chatTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/chatTrigger/index.tsx @@ -1,37 +1,45 @@ import { Transition } from "@headlessui/react"; -import { Bars3CenterLeftIcon, ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline"; +import { + Bars3CenterLeftIcon, + ChatBubbleBottomCenterTextIcon, +} from "@heroicons/react/24/outline"; import { nodeColors } from "../../../utils"; import { PopUpContext } from "../../../contexts/popUpContext"; import { useContext } from "react"; import ChatModal from "../../../modals/chatModal"; -export default function ChatTrigger({open, setOpen,flow}){ - const {openPopUp} = useContext(PopUpContext) - return( -
-
- -
-
-
) -} \ No newline at end of file +export default function ChatTrigger({ open, setOpen }) { + const { openPopUp } = useContext(PopUpContext); + return ( + +
+
+ +
+
+
+ ); +} diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 1eeddb191..940a9341b 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -7,26 +7,26 @@ import ChatModal from "../../modals/chatModal"; const _ = require("lodash"); export default function Chat({ flow }: ChatType) { - const [open, setOpen] = useState(false); - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - (event.key === "K" || event.key === "k") && - (event.metaKey || event.ctrlKey) - ) { - event.preventDefault(); - setOpen((oldState) => !oldState); - } - }; - document.addEventListener("keydown", handleKeyDown); - return () => { - document.removeEventListener("keydown", handleKeyDown); - }; - }, []); - return ( - <> - - - - ); + const [open, setOpen] = useState(false); + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ( + (event.key === "K" || event.key === "k") && + (event.metaKey || event.ctrlKey) + ) { + event.preventDefault(); + setOpen((oldState) => !oldState); + } + }; + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); + return ( + <> + + + + ); } diff --git a/src/frontend/src/components/dropdownComponent/index.tsx b/src/frontend/src/components/dropdownComponent/index.tsx index bb4cd621c..92085d8b8 100644 --- a/src/frontend/src/components/dropdownComponent/index.tsx +++ b/src/frontend/src/components/dropdownComponent/index.tsx @@ -5,90 +5,90 @@ import { DropDownComponentType } from "../../types/components"; import { classNames } from "../../utils"; export default function Dropdown({ - value, - options, - onSelect, + value, + options, + onSelect, }: DropDownComponentType) { - let [internalValue, setInternalValue] = useState( - value === "" || !value ? "Choose an option" : value - ); - return ( - <> - { - setInternalValue(value); - onSelect(value); - }} - > - {({ open }) => ( - <> -
- - {internalValue} - - - + let [internalValue, setInternalValue] = useState( + value === "" || !value ? "Choose an option" : value + ); + return ( + <> + { + setInternalValue(value); + onSelect(value); + }} + > + {({ open }) => ( + <> +
+ + {internalValue} + + + - - - {options.map((option, id) => ( - - classNames( - active - ? "text-white bg-indigo-600 dark:bg-indigo-500" - : "text-gray-900", - "relative cursor-default select-none py-2 pl-3 pr-9 dark:text-gray-300 dark:bg-gray-800" - ) - } - value={option} - > - {({ selected, active }) => ( - <> - - {option} - + + + {options.map((option, id) => ( + + classNames( + active + ? "text-white bg-indigo-600 dark:bg-indigo-500" + : "text-gray-900", + "relative cursor-default select-none py-2 pl-3 pr-9 dark:text-gray-300 dark:bg-gray-800" + ) + } + value={option} + > + {({ selected, active }) => ( + <> + + {option} + - {selected ? ( - - - ) : null} - - )} - - ))} - - -
- - )} -
- - ); + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+ + )} +
+ + ); } diff --git a/src/frontend/src/components/floatComponent/index.tsx b/src/frontend/src/components/floatComponent/index.tsx index adce64ba5..3a09527da 100644 --- a/src/frontend/src/components/floatComponent/index.tsx +++ b/src/frontend/src/components/floatComponent/index.tsx @@ -1,26 +1,33 @@ import { useEffect, useState } from "react"; import { FloatComponentType } from "../../types/components"; -export default function FloatComponent({value, onChange, disabled}: FloatComponentType){ - const [myValue, setMyValue] = useState(value ?? ""); - useEffect(()=> { - if(disabled){ - setMyValue(""); - onChange(""); - } - }, [disabled, onChange]) - return ( -
- { - setMyValue(e.target.value); - onChange(e.target.value); - }} - /> -
- ); -} \ No newline at end of file +export default function FloatComponent({ + value, + onChange, + disabled, +}: FloatComponentType) { + const [myValue, setMyValue] = useState(value ?? ""); + useEffect(() => { + if (disabled) { + setMyValue(""); + onChange(""); + } + }, [disabled, onChange]); + return ( +
+ { + setMyValue(e.target.value); + onChange(e.target.value); + }} + /> +
+ ); +} diff --git a/src/frontend/src/components/inputComponent/index.tsx b/src/frontend/src/components/inputComponent/index.tsx index f28d82307..05be68532 100644 --- a/src/frontend/src/components/inputComponent/index.tsx +++ b/src/frontend/src/components/inputComponent/index.tsx @@ -3,84 +3,84 @@ import { InputComponentType } from "../../types/components"; import { classNames } from "../../utils"; export default function InputComponent({ - value, - onChange, - disabled, - password, + value, + onChange, + disabled, + password, }: InputComponentType) { - const [myValue, setMyValue] = useState(value ?? ""); - const [pwdVisible, setPwdVisible] = useState(false); - useEffect(() => { - if (disabled) { - setMyValue(""); - onChange(""); - } - }, [disabled, onChange]); - return ( -
- { - setMyValue(e.target.value); - onChange(e.target.value); - }} - /> - -
- ); + const [myValue, setMyValue] = useState(value ?? ""); + const [pwdVisible, setPwdVisible] = useState(false); + useEffect(() => { + if (disabled) { + setMyValue(""); + onChange(""); + } + }, [disabled, onChange]); + return ( +
+ { + setMyValue(e.target.value); + onChange(e.target.value); + }} + /> + +
+ ); } diff --git a/src/frontend/src/components/inputFileComponent/index.tsx b/src/frontend/src/components/inputFileComponent/index.tsx index cb915bce5..d20044571 100644 --- a/src/frontend/src/components/inputFileComponent/index.tsx +++ b/src/frontend/src/components/inputFileComponent/index.tsx @@ -9,7 +9,7 @@ export default function InputFileComponent({ disabled, suffixes, fileTypes, - onFileChange + onFileChange, }: FileComponentType) { const [myValue, setMyValue] = useState(value); const { setErrorData } = useContext(alertContext); @@ -17,23 +17,23 @@ export default function InputFileComponent({ if (disabled) { setMyValue(""); onChange(""); - onFileChange("") + onFileChange(""); } }, [disabled, onChange]); function attachFile(fileReadEvent: ProgressEvent) { fileReadEvent.preventDefault(); const file = fileReadEvent.target.result; - onFileChange(file as string) + onFileChange(file as string); } - function checkFileType(fileName:string):boolean{ + function checkFileType(fileName: string): boolean { for (let index = 0; index < suffixes.length; index++) { - if(fileName.endsWith(suffixes[index])){ - return true + if (fileName.endsWith(suffixes[index])) { + return true; } } - return false + return false; } const handleButtonClick = () => { @@ -69,7 +69,7 @@ export default function InputFileComponent({ >
{ - if(disabled){ - setInputList([""]); - onChange([""]); - } -}, [disabled, onChange]) - return ( -
- {inputList.map((i, idx) => ( -
- { - setInputList((old) => { - let newInputList = _.cloneDeep(old); - newInputList[idx] = e.target.value; - return newInputList; - }); - onChange(inputList); - }} - /> - {idx === inputList.length - 1 ? - - : } -
- ))} -
- ); +export default function InputListComponent({ + value, + onChange, + disabled, +}: InputListComponentType) { + const [inputList, setInputList] = useState(value ?? [""]); + useEffect(() => { + if (disabled) { + setInputList([""]); + onChange([""]); + } + }, [disabled, onChange]); + return ( +
+ {inputList.map((i, idx) => ( +
+ { + setInputList((old) => { + let newInputList = _.cloneDeep(old); + newInputList[idx] = e.target.value; + return newInputList; + }); + onChange(inputList); + }} + /> + {idx === inputList.length - 1 ? ( + + ) : ( + + )} +
+ ))} +
+ ); } diff --git a/src/frontend/src/components/intComponent/index.tsx b/src/frontend/src/components/intComponent/index.tsx index 520a78c0d..cc435c897 100644 --- a/src/frontend/src/components/intComponent/index.tsx +++ b/src/frontend/src/components/intComponent/index.tsx @@ -14,12 +14,23 @@ export default function IntComponent({ } }, [disabled, onChange]); return ( -
+
{ - if (event.key !== 'Backspace' && event.key !== 'Enter' && event.key !== 'Delete' && event.key !== 'ArrowLeft' && event.key !== 'ArrowRight' && !/^[-]?\d*$/.test(event.key)) { - event.preventDefault(); - } + if ( + event.key !== "Backspace" && + event.key !== "Enter" && + event.key !== "Delete" && + event.key !== "ArrowLeft" && + event.key !== "ArrowRight" && + !/^[-]?\d*$/.test(event.key) + ) { + event.preventDefault(); + } }} type="number" value={myValue} diff --git a/src/frontend/src/components/loadingComponent/index.tsx b/src/frontend/src/components/loadingComponent/index.tsx index 6181fd7cc..43d6d9d75 100644 --- a/src/frontend/src/components/loadingComponent/index.tsx +++ b/src/frontend/src/components/loadingComponent/index.tsx @@ -1,17 +1,28 @@ -type LoadingComponentProps={ - remSize:number +type LoadingComponentProps = { + remSize: number; +}; + +export default function LoadingComponent({ remSize }: LoadingComponentProps) { + return ( +
+ +

+ Loading... +
+ ); } - - -export default function LoadingComponent({remSize}:LoadingComponentProps){ - return( -
- -

- Loading... -
- ) -} \ No newline at end of file diff --git a/src/frontend/src/components/textAreaComponent/index.tsx b/src/frontend/src/components/textAreaComponent/index.tsx index 153de4ffa..93b0ddb62 100644 --- a/src/frontend/src/components/textAreaComponent/index.tsx +++ b/src/frontend/src/components/textAreaComponent/index.tsx @@ -4,30 +4,57 @@ import { PopUpContext } from "../../contexts/popUpContext"; import TextAreaModal from "../../modals/textAreaModal"; import { TextAreaComponentType } from "../../types/components"; -export default function TextAreaComponent({ value, onChange, disabled }:TextAreaComponentType) { - const [myValue, setMyValue] = useState(value); - const { openPopUp } = useContext(PopUpContext); - useEffect(() => { - if (disabled) { - setMyValue(""); - onChange(""); - } - }, [disabled, onChange]); - return ( -
-
- {openPopUp( {setMyValue(t); onChange(t);}}/>)}} - className={ - "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + - (disabled ? " bg-gray-200" : "") - } - > - {myValue !== "" ? myValue : 'Text empty'} - - -
-
- ); +export default function TextAreaComponent({ + value, + onChange, + disabled, +}: TextAreaComponentType) { + const [myValue, setMyValue] = useState(value); + const { openPopUp } = useContext(PopUpContext); + useEffect(() => { + if (disabled) { + setMyValue(""); + onChange(""); + } + }, [disabled, onChange]); + return ( +
+
+ { + openPopUp( + { + setMyValue(t); + onChange(t); + }} + /> + ); + }} + className={ + "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + + (disabled ? " bg-gray-200" : "") + } + > + {myValue !== "" ? myValue : "Text empty"} + + +
+
+ ); } diff --git a/src/frontend/src/components/toggleComponent/index.tsx b/src/frontend/src/components/toggleComponent/index.tsx index 4cd6ee615..102512ab3 100644 --- a/src/frontend/src/components/toggleComponent/index.tsx +++ b/src/frontend/src/components/toggleComponent/index.tsx @@ -3,73 +3,80 @@ import { classNames } from "../../utils"; import { useEffect } from "react"; import { ToggleComponentType } from "../../types/components"; -export default function ToggleComponent({ enabled, setEnabled, disabled }:ToggleComponentType) { - useEffect(()=> { - if(disabled){ - setEnabled(false); - } -}, [disabled, setEnabled]) - return ( -
- { - setEnabled(x); - }} - className={classNames( - enabled ? "bg-indigo-600" : "bg-gray-200 dark:bg-gray-600", - "relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out " - )} - > - Use setting - - - - - -
- ); +export default function ToggleComponent({ + enabled, + setEnabled, + disabled, +}: ToggleComponentType) { + useEffect(() => { + if (disabled) { + setEnabled(false); + } + }, [disabled, setEnabled]); + return ( +
+ { + setEnabled(x); + }} + className={classNames( + enabled ? "bg-indigo-600" : "bg-gray-200 dark:bg-gray-600", + "relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out " + )} + > + Use setting + + + + + +
+ ); } diff --git a/src/frontend/src/contexts/alertContext.tsx b/src/frontend/src/contexts/alertContext.tsx index 0fba6f65e..ad2110217 100644 --- a/src/frontend/src/contexts/alertContext.tsx +++ b/src/frontend/src/contexts/alertContext.tsx @@ -20,13 +20,13 @@ type alertContextType = { notificationCenter: boolean; setNotificationCenter: (newState: boolean) => void; notificationList: Array; - pushNotificationList: (Object:AlertItemType) => void; + pushNotificationList: (Object: AlertItemType) => void; clearNotificationList: () => void; removeFromNotificationList: (index: string) => void; }; //initial values to alertContextType -const initialValue:alertContextType = { +const initialValue: alertContextType = { errorData: { title: "", list: [] }, setErrorData: () => {}, errorOpen: false, @@ -49,7 +49,7 @@ const initialValue:alertContextType = { export const alertContext = createContext(initialValue); -export function AlertProvider({ children }:{children:ReactNode}) { +export function AlertProvider({ children }: { children: ReactNode }) { const [errorData, setErrorDataState] = useState<{ title: string; list?: Array; @@ -73,68 +73,69 @@ export function AlertProvider({ children }:{children:ReactNode}) { return newNotificationList; }); }; -/** - * Sets the error data state, opens the error dialog and pushes the new error notification to the notification list - * @param newState An object containing the new error data, including title and optional list of error messages - */ -function setErrorData(newState: { title: string; list?: Array }) { - setErrorDataState(newState); - setErrorOpen(true); - if (newState.title) { - setNotificationCenter(true); - pushNotificationList({ - type: "error", - title: newState.title, - list: newState.list, - id: _.uniqueId(), - }); + /** + * Sets the error data state, opens the error dialog and pushes the new error notification to the notification list + * @param newState An object containing the new error data, including title and optional list of error messages + */ + function setErrorData(newState: { title: string; list?: Array }) { + setErrorDataState(newState); + setErrorOpen(true); + if (newState.title) { + setNotificationCenter(true); + pushNotificationList({ + type: "error", + title: newState.title, + list: newState.list, + id: _.uniqueId(), + }); + } } -} -/** - * Sets the state of the notice data and opens the notice modal, also adds a new notice to the notification center if the title is defined. - * @param newState An object containing the title of the notice and optionally a link. - */ -function setNoticeData(newState: { title: string; link?: string }) { - setNoticeDataState(newState); - setNoticeOpen(true); - if (newState.title) { - // Add new notice to notification center - setNotificationCenter(true); - pushNotificationList({ - type: "notice", - title: newState.title, - link: newState.link, - id: _.uniqueId(), - }); + /** + * Sets the state of the notice data and opens the notice modal, also adds a new notice to the notification center if the title is defined. + * @param newState An object containing the title of the notice and optionally a link. + */ + function setNoticeData(newState: { title: string; link?: string }) { + setNoticeDataState(newState); + setNoticeOpen(true); + if (newState.title) { + // Add new notice to notification center + setNotificationCenter(true); + pushNotificationList({ + type: "notice", + title: newState.title, + link: newState.link, + id: _.uniqueId(), + }); + } } -} -/** - * Update the success data state and show a success alert notification. - * @param newState - A state object with a "title" property to set in the success data state. - */ -function setSuccessData(newState: { title: string }) { - setSuccessDataState(newState); // update the success data state with the provided new state - setSuccessOpen(true); // open the success alert + /** + * Update the success data state and show a success alert notification. + * @param newState - A state object with a "title" property to set in the success data state. + */ + function setSuccessData(newState: { title: string }) { + setSuccessDataState(newState); // update the success data state with the provided new state + setSuccessOpen(true); // open the success alert - // If the new state has a "title" property, add a new success notification to the list - if (newState.title) { - setNotificationCenter(true); // show the notification center - pushNotificationList({ // add the new notification to the list - type: "success", - title: newState.title, - id: _.uniqueId(), - }); + // If the new state has a "title" property, add a new success notification to the list + if (newState.title) { + setNotificationCenter(true); // show the notification center + pushNotificationList({ + // add the new notification to the list + type: "success", + title: newState.title, + id: _.uniqueId(), + }); + } } -} function clearNotificationList() { setNotificationList([]); } function removeFromNotificationList(index: string) { // set the notification list to a new array that filters out the alert with the matching id setNotificationList((prevAlertsList) => - prevAlertsList.filter((alert) => alert.id !== index) + prevAlertsList.filter((alert) => alert.id !== index) ); - } + } return ( (initialValue); export function DarkProvider({ children }) { const [dark, setDark] = useState(false); - useEffect(()=>{ - if(dark){ + useEffect(() => { + if (dark) { document.getElementById("body").classList.add("dark"); } else { document.getElementById("body").classList.remove("dark"); } - }, [dark]) + }, [dark]); return ( ); -} \ No newline at end of file +} diff --git a/src/frontend/src/contexts/locationContext.tsx b/src/frontend/src/contexts/locationContext.tsx index dbefaa7c9..a73db24fe 100644 --- a/src/frontend/src/contexts/locationContext.tsx +++ b/src/frontend/src/contexts/locationContext.tsx @@ -32,7 +32,7 @@ type locationContextType = { //initial value for location context const initialValue = { - //actual + //actual current: window.location.pathname.replace(/\/$/g, "").split("/"), isStackedOpen: window.innerWidth > 1024 && window.location.pathname.split("/")[1] @@ -50,7 +50,7 @@ const initialValue = { export const locationContext = createContext(initialValue); -export function LocationProvider({ children }:{children:ReactNode}) { +export function LocationProvider({ children }: { children: ReactNode }) { const [current, setCurrent] = useState(initialValue.current); const [isStackedOpen, setIsStackedOpen] = useState( initialValue.isStackedOpen diff --git a/src/frontend/src/contexts/popUpContext.tsx b/src/frontend/src/contexts/popUpContext.tsx index efa263146..b8c47dea2 100644 --- a/src/frontend/src/contexts/popUpContext.tsx +++ b/src/frontend/src/contexts/popUpContext.tsx @@ -3,31 +3,31 @@ import React, { useState } from "react"; // context to set JSX element on the DOM export const PopUpContext = createContext({ - openPopUp: (popUpElement: JSX.Element) => {}, - closePopUp: () => {}, + openPopUp: (popUpElement: JSX.Element) => {}, + closePopUp: () => {}, }); interface PopUpProviderProps { - children: React.ReactNode; + children: React.ReactNode; } const PopUpProvider = ({ children }: PopUpProviderProps) => { - const [popUpElements, setPopUpElements] = useState([]); + const [popUpElements, setPopUpElements] = useState([]); - const openPopUp = (element: JSX.Element) => { - setPopUpElements(prevPopUps => [element, ...prevPopUps]); - }; + const openPopUp = (element: JSX.Element) => { + setPopUpElements((prevPopUps) => [element, ...prevPopUps]); + }; - const closePopUp = () => { - setPopUpElements(prevPopUps => prevPopUps.slice(1)); - }; + const closePopUp = () => { + setPopUpElements((prevPopUps) => prevPopUps.slice(1)); + }; - return ( - - {children} - {popUpElements[0]} - - ); + return ( + + {children} + {popUpElements[0]} + + ); }; export default PopUpProvider; diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 3384ab479..9905051b2 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -1,10 +1,10 @@ import { - createContext, - useEffect, - useState, - useRef, - ReactNode, - useContext, + createContext, + useEffect, + useState, + useRef, + ReactNode, + useContext, } from "react"; import { FlowType } from "../types/flow"; import { LangFlowState, TabsContextType } from "../types/tabs"; @@ -15,221 +15,221 @@ import { APITemplateType, TemplateVariableType } from "../types/api"; const { v4: uuidv4 } = require("uuid"); const TabsContextInitialValue: TabsContextType = { - save: () => {}, - tabIndex: 0, - setTabIndex: (index: number) => {}, - flows: [], - removeFlow: (id: string) => {}, - addFlow: (flowData?: any) => {}, - updateFlow: (newFlow: FlowType) => {}, - incrementNodeId: () => 0, - downloadFlow: (flow: FlowType) => {}, - uploadFlow: () => {}, - hardReset: () => {}, + save: () => {}, + tabIndex: 0, + setTabIndex: (index: number) => {}, + flows: [], + removeFlow: (id: string) => {}, + addFlow: (flowData?: any) => {}, + updateFlow: (newFlow: FlowType) => {}, + incrementNodeId: () => 0, + downloadFlow: (flow: FlowType) => {}, + uploadFlow: () => {}, + hardReset: () => {}, }; export const TabsContext = createContext( - TabsContextInitialValue + TabsContextInitialValue ); export function TabsProvider({ children }: { children: ReactNode }) { - const { setNoticeData } = useContext(alertContext); - const [tabIndex, setTabIndex] = useState(0); - const [flows, setFlows] = useState>([]); - const [id, setId] = useState(""); - const { templates } = useContext(typesContext); + const { setNoticeData } = useContext(alertContext); + const [tabIndex, setTabIndex] = useState(0); + const [flows, setFlows] = useState>([]); + const [id, setId] = useState(""); + const { templates } = useContext(typesContext); - const newNodeId = useRef(0); - function incrementNodeId() { - newNodeId.current = newNodeId.current + 1; - return newNodeId.current; - } - function save() { - if (flows.length !== 0) - window.localStorage.setItem( - "tabsData", - JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) - ); - } - useEffect(() => { - //save tabs locally - save(); - }, [flows, id, tabIndex, newNodeId]); + const newNodeId = useRef(0); + function incrementNodeId() { + newNodeId.current = newNodeId.current + 1; + return newNodeId.current; + } + function save() { + if (flows.length !== 0) + window.localStorage.setItem( + "tabsData", + JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) + ); + } + useEffect(() => { + //save tabs locally + save(); + }, [flows, id, tabIndex, newNodeId]); - useEffect(() => { - //get tabs locally saved - let cookie = window.localStorage.getItem("tabsData"); - if (cookie && Object.keys(templates).length > 0) { - let cookieObject: LangFlowState = JSON.parse(cookie); - cookieObject.flows.forEach((flow) => { - flow.data.nodes.forEach((node) => { - if (Object.keys(templates[node.data.type]["template"]).length > 0) { - node.data.node.template = updateTemplate( - templates[node.data.type][ - "template" - ] as unknown as APITemplateType, + useEffect(() => { + //get tabs locally saved + let cookie = window.localStorage.getItem("tabsData"); + if (cookie && Object.keys(templates).length > 0) { + let cookieObject: LangFlowState = JSON.parse(cookie); + cookieObject.flows.forEach((flow) => { + flow.data.nodes.forEach((node) => { + if (Object.keys(templates[node.data.type]["template"]).length > 0) { + node.data.node.template = updateTemplate( + templates[node.data.type][ + "template" + ] as unknown as APITemplateType, - node.data.node.template as APITemplateType - ); - } - }); - }); - setTabIndex(cookieObject.tabIndex); - setFlows(cookieObject.flows); - setId(cookieObject.id); - newNodeId.current = cookieObject.nodeId; - } - }, [templates]); - function hardReset() { - newNodeId.current = 0; - setTabIndex(0); - setFlows([]); - setId(""); - } + node.data.node.template as APITemplateType + ); + } + }); + }); + setTabIndex(cookieObject.tabIndex); + setFlows(cookieObject.flows); + setId(cookieObject.id); + newNodeId.current = cookieObject.nodeId; + } + }, [templates]); + function hardReset() { + newNodeId.current = 0; + setTabIndex(0); + setFlows([]); + setId(""); + } - /** - * Downloads the current flow as a JSON file - */ - function downloadFlow(flow: FlowType) { - // create a data URI with the current flow data - const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( - JSON.stringify(flow) - )}`; + /** + * Downloads the current flow as a JSON file + */ + function downloadFlow(flow: FlowType) { + // create a data URI with the current flow data + const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( + JSON.stringify(flow) + )}`; - // create a link element and set its properties - const link = document.createElement("a"); - link.href = jsonString; - link.download = `${flows[tabIndex].name}.json`; + // create a link element and set its properties + const link = document.createElement("a"); + link.href = jsonString; + link.download = `${flows[tabIndex].name}.json`; - // simulate a click on the link element to trigger the download - link.click(); - setNoticeData({ - title: "Warning: Critical data,JSON file may including API keys.", - }); - } + // simulate a click on the link element to trigger the download + link.click(); + setNoticeData({ + title: "Warning: Critical data,JSON file may including API keys.", + }); + } - /** - * Creates a file input and listens to a change event to upload a JSON flow file. - * If the file type is application/json, the file is read and parsed into a JSON object. - * The resulting JSON object is passed to the addFlow function. - */ - function uploadFlow() { - // create a file input - const input = document.createElement("input"); - input.type = "file"; - // add a change event listener to the file input - input.onchange = (e: Event) => { - // check if the file type is application/json - if ((e.target as HTMLInputElement).files[0].type === "application/json") { - // get the file from the file input - const file = (e.target as HTMLInputElement).files[0]; - // read the file as text - file.text().then((text) => { - // parse the text into a JSON object - let flow: FlowType = JSON.parse(text); + /** + * Creates a file input and listens to a change event to upload a JSON flow file. + * If the file type is application/json, the file is read and parsed into a JSON object. + * The resulting JSON object is passed to the addFlow function. + */ + function uploadFlow() { + // create a file input + const input = document.createElement("input"); + input.type = "file"; + // add a change event listener to the file input + input.onchange = (e: Event) => { + // check if the file type is application/json + if ((e.target as HTMLInputElement).files[0].type === "application/json") { + // get the file from the file input + const file = (e.target as HTMLInputElement).files[0]; + // read the file as text + file.text().then((text) => { + // parse the text into a JSON object + let flow: FlowType = JSON.parse(text); - addFlow(flow); - }); - } - }; - // trigger the file input click event to open the file dialog - input.click(); - } - /** - * Removes a flow from an array of flows based on its id. - * Updates the state of flows and tabIndex using setFlows and setTabIndex hooks. - * @param {string} id - The id of the flow to remove. - */ - function removeFlow(id: string) { - setFlows((prevState) => { - const newFlows = [...prevState]; - const index = newFlows.findIndex((flow) => flow.id === id); - if (index >= 0) { - if (index === tabIndex) { - setTabIndex(flows.length - 2); - newFlows.splice(index, 1); - } else { - let flowId = flows[tabIndex].id; - newFlows.splice(index, 1); - setTabIndex(newFlows.findIndex((flow) => flow.id === flowId)); - } - } - return newFlows; - }); - } - /** - * Add a new flow to the list of flows. - * @param flow Optional flow to add. - */ - function addFlow(flow?: FlowType) { - // Get data from the flow or set it to null if there's no flow provided. - const data = flow?.data ? flow.data : null; - const description = flow?.description ? flow.description : ""; + addFlow(flow); + }); + } + }; + // trigger the file input click event to open the file dialog + input.click(); + } + /** + * Removes a flow from an array of flows based on its id. + * Updates the state of flows and tabIndex using setFlows and setTabIndex hooks. + * @param {string} id - The id of the flow to remove. + */ + function removeFlow(id: string) { + setFlows((prevState) => { + const newFlows = [...prevState]; + const index = newFlows.findIndex((flow) => flow.id === id); + if (index >= 0) { + if (index === tabIndex) { + setTabIndex(flows.length - 2); + newFlows.splice(index, 1); + } else { + let flowId = flows[tabIndex].id; + newFlows.splice(index, 1); + setTabIndex(newFlows.findIndex((flow) => flow.id === flowId)); + } + } + return newFlows; + }); + } + /** + * Add a new flow to the list of flows. + * @param flow Optional flow to add. + */ + function addFlow(flow?: FlowType) { + // Get data from the flow or set it to null if there's no flow provided. + const data = flow?.data ? flow.data : null; + const description = flow?.description ? flow.description : ""; - if (data) { - data.nodes.forEach((node) => { - if (Object.keys(templates[node.data.type]["template"]).length > 0) { - node.data.node.template = updateTemplate( - templates[node.data.type]["template"] as unknown as APITemplateType, - node.data.node.template as APITemplateType - ); - } - }); - } - // Create a new flow with a default name if no flow is provided. - let newFlow: FlowType = { - description, - name: flow?.name ?? "New Flow", - id: id.toString(), - data, - }; + if (data) { + data.nodes.forEach((node) => { + if (Object.keys(templates[node.data.type]["template"]).length > 0) { + node.data.node.template = updateTemplate( + templates[node.data.type]["template"] as unknown as APITemplateType, + node.data.node.template as APITemplateType + ); + } + }); + } + // Create a new flow with a default name if no flow is provided. + let newFlow: FlowType = { + description, + name: flow?.name ?? "New Flow", + id: id.toString(), + data, + }; - // Increment the ID counter. - setId(uuidv4()); + // Increment the ID counter. + setId(uuidv4()); - // Add the new flow to the list of flows. - setFlows((prevState) => { - const newFlows = [...prevState, newFlow]; - return newFlows; - }); + // Add the new flow to the list of flows. + setFlows((prevState) => { + const newFlows = [...prevState, newFlow]; + return newFlows; + }); - // Set the tab index to the new flow. - setTabIndex(flows.length); - } - /** - * Updates an existing flow with new data - * @param newFlow - The new flow object containing the updated data - */ - function updateFlow(newFlow: FlowType) { - setFlows((prevState) => { - const newFlows = [...prevState]; - const index = newFlows.findIndex((flow) => flow.id === newFlow.id); - if (index !== -1) { - newFlows[index].description = newFlow.description ?? ""; - newFlows[index].data = newFlow.data; - newFlows[index].name = newFlow.name; - } - return newFlows; - }); - } + // Set the tab index to the new flow. + setTabIndex(flows.length); + } + /** + * Updates an existing flow with new data + * @param newFlow - The new flow object containing the updated data + */ + function updateFlow(newFlow: FlowType) { + setFlows((prevState) => { + const newFlows = [...prevState]; + const index = newFlows.findIndex((flow) => flow.id === newFlow.id); + if (index !== -1) { + newFlows[index].description = newFlow.description ?? ""; + newFlows[index].data = newFlow.data; + newFlows[index].name = newFlow.name; + } + return newFlows; + }); + } - return ( - - {children} - - ); + return ( + + {children} + + ); } diff --git a/src/frontend/src/contexts/typesContext.tsx b/src/frontend/src/contexts/typesContext.tsx index ad86d4699..2ab1eb057 100644 --- a/src/frontend/src/contexts/typesContext.tsx +++ b/src/frontend/src/contexts/typesContext.tsx @@ -1,12 +1,12 @@ import { createContext, ReactNode, useEffect, useState } from "react"; -import { Node} from "reactflow"; +import { Node } from "reactflow"; import { typesContextType } from "../types/typesContext"; import { getAll } from "../controllers/API"; import { APIKindType } from "../types/api"; //context to share types adn functions from nodes to flow -const initialValue:typesContextType = { +const initialValue: typesContextType = { reactFlowInstance: null, setReactFlowInstance: () => {}, deleteNode: () => {}, @@ -14,13 +14,13 @@ const initialValue:typesContextType = { setTypes: () => {}, templates: {}, setTemplates: () => {}, - data:{}, - setData:()=>{} + data: {}, + setData: () => {}, }; export const typesContext = createContext(initialValue); -export function TypesProvider({ children }:{children:ReactNode}) { +export function TypesProvider({ children }: { children: ReactNode }) { const [types, setTypes] = useState({}); const [reactFlowInstance, setReactFlowInstance] = useState(null); const [templates, setTemplates] = useState({}); @@ -35,11 +35,11 @@ export function TypesProvider({ children }:{children:ReactNode}) { setData(result.data); setTemplates( Object.keys(result.data).reduce((acc, curr) => { - Object.keys(result.data[curr]).forEach((c: keyof APIKindType)=>{ - acc[c] = result.data[curr][c] - }) + Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { + acc[c] = result.data[curr][c]; + }); return acc; - },{}) + }, {}) ); // Set the types by reducing over the keys of the result data and updating the accumulator. setTypes( @@ -59,11 +59,15 @@ export function TypesProvider({ children }:{children:ReactNode}) { getTypes(); }, [setTypes]); - function deleteNode(idx:string) { + function deleteNode(idx: string) { reactFlowInstance.setNodes( - reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx) + reactFlowInstance.getNodes().filter((n: Node) => n.id !== idx) + ); + reactFlowInstance.setEdges( + reactFlowInstance + .getEdges() + .filter((ns) => ns.source !== idx && ns.target !== idx) ); - reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter((ns) => ns.source !== idx && ns.target !== idx)); } return ( {children} diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index f6f46404b..9a93a9b36 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -4,40 +4,40 @@ import axios, { AxiosResponse } from "axios"; import { FlowType } from "../../types/flow"; export async function getAll(): Promise> { - return await axios.get(`/all`); + return await axios.get(`/all`); } export async function sendAll(data: sendAllProps) { - return await axios.post(`/predict`, data); + return await axios.post(`/predict`, data); } export async function checkCode( - code: string + code: string ): Promise> { - return await axios.post("/validate/code", { code }); + return await axios.post("/validate/code", { code }); } export async function checkPrompt( - template: string + template: string ): Promise> { - return await axios.post("/validate/prompt", { template }); + return await axios.post("/validate/prompt", { template }); } export async function getExamples(): Promise { - const url = - "https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples"; - const response = await axios.get(url); + const url = + "https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples"; + const response = await axios.get(url); - const jsonFiles = response.data.filter((file: any) => { - return file.name.endsWith(".json"); - }); + const jsonFiles = response.data.filter((file: any) => { + return file.name.endsWith(".json"); + }); - const contentsPromises = jsonFiles.map(async (file: any) => { - const contentResponse = await axios.get(file.download_url); - return contentResponse.data; - }); + const contentsPromises = jsonFiles.map(async (file: any) => { + const contentResponse = await axios.get(file.download_url); + return contentResponse.data; + }); - const contents = await Promise.all(contentsPromises); + const contents = await Promise.all(contentsPromises); - return contents; + return contents; } diff --git a/src/frontend/src/index.css b/src/frontend/src/index.css index 95681f059..e0684378d 100644 --- a/src/frontend/src/index.css +++ b/src/frontend/src/index.css @@ -1,15 +1,13 @@ - - body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; } diff --git a/src/frontend/src/index.tsx b/src/frontend/src/index.tsx index c71219a94..c98d24378 100644 --- a/src/frontend/src/index.tsx +++ b/src/frontend/src/index.tsx @@ -11,8 +11,7 @@ const root = ReactDOM.createRoot( root.render( - - + ); diff --git a/src/frontend/src/modals/NodeModal/index.tsx b/src/frontend/src/modals/NodeModal/index.tsx index aad549a83..68e1ed2d2 100644 --- a/src/frontend/src/modals/NodeModal/index.tsx +++ b/src/frontend/src/modals/NodeModal/index.tsx @@ -87,37 +87,38 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
- { - Object.keys(data.node.template) - .filter((t) => t.charAt(0) !== "_"&& data.node.template[t].advanced && data.node.template[t].show) - .map((t: string, idx) => { - return ( - + t.charAt(0) !== "_" && + data.node.template[t].advanced && + data.node.template[t].show + ) + .map((t: string, idx) => { + return ( + - ); - }) - } + data={data} + title={ + data.node.template[t].display_name + ? data.node.template[t].display_name + : data.node.template[t].name + ? toNormalCase(data.node.template[t].name) + : toNormalCase(t) + } + required={data.node.template[t].required} + id={ + data.node.template[t].type + + "|" + + t + + "|" + + data.id + } + name={t} + type={data.node.template[t].type} + /> + ); + })}
diff --git a/src/frontend/src/modals/chatModal/chatInput/index.tsx b/src/frontend/src/modals/chatModal/chatInput/index.tsx index a05ef1ef3..9e59709fd 100644 --- a/src/frontend/src/modals/chatModal/chatInput/index.tsx +++ b/src/frontend/src/modals/chatModal/chatInput/index.tsx @@ -24,9 +24,9 @@ export default function ChatInput({ }} ref={inputRef} disabled={lockChat} - style={{resize: "none" }} + style={{ resize: "none" }} value={lockChat ? "Thinking..." : chatValue} - onChange={(e) => { + onChange={(e) => { setChatValue(e.target.value); }} className={classNames( diff --git a/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx new file mode 100644 index 000000000..d9a20579a --- /dev/null +++ b/src/frontend/src/modals/chatModal/chatMessage/codeBlock/index.tsx @@ -0,0 +1,81 @@ +import { IconCheck, IconClipboard, IconDownload } from "@tabler/icons-react"; +import { FC, memo, useState } from "react"; +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism"; +import { programmingLanguages } from "../../../../utils"; + +interface Props { + language: string; + value: string; +} + +export const CodeBlock: FC = memo(({ language, value }) => { + const [isCopied, setIsCopied] = useState(false); + + const copyToClipboard = () => { + if (!navigator.clipboard || !navigator.clipboard.writeText) { + return; + } + + navigator.clipboard.writeText(value).then(() => { + setIsCopied(true); + + setTimeout(() => { + setIsCopied(false); + }, 2000); + }); + }; + const downloadAsFile = () => { + const fileExtension = programmingLanguages[language] || ".file"; + const suggestedFileName = `${"generated-code"}${fileExtension}`; + const fileName = window.prompt("enter file name", suggestedFileName); + + if (!fileName) { + // user pressed cancel on prompt + return; + } + + const blob = new Blob([value], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = fileName; + link.href = url; + link.style.display = "none"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + return ( +
+
+ {language} + +
+ + +
+
+ + + {value} + +
+ ); +}); +CodeBlock.displayName = "CodeBlock"; diff --git a/src/frontend/src/modals/chatModal/chatMessage/index.tsx b/src/frontend/src/modals/chatModal/chatMessage/index.tsx index 70f224f88..e836fd887 100644 --- a/src/frontend/src/modals/chatModal/chatMessage/index.tsx +++ b/src/frontend/src/modals/chatModal/chatMessage/index.tsx @@ -1,82 +1,140 @@ import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { ChatMessageType } from "../../../types/chat"; import { classNames } from "../../../utils"; import AiIcon from "../../../assets/Gooey Ring-5s-271px.svg"; import { UserIcon } from "@heroicons/react/24/solid"; import FileCard from "../fileComponent"; +import ReactMarkdown from "react-markdown"; +import rehypeMathjax from "rehype-mathjax"; +import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; +import { CodeBlock } from "./codeBlock"; var Convert = require("ansi-to-html"); var convert = new Convert({ newline: true }); export default function ChatMessage({ chat }: { chat: ChatMessageType }) { - const [hidden, setHidden] = useState(true); - return ( -
-
- {!chat.isSend && } - {chat.isSend && } -
- {!chat.isSend ? ( -
-
- {hidden && chat.thought && chat.thought !== "" && ( -
setHidden((prev) => !prev)} - className="absolute -top-1 -left-2 cursor-pointer" - > - -
- )} - {chat.thought && chat.thought !== "" && !hidden && ( -
setHidden((prev) => !prev)} - className=" text-start inline-block rounded-md h-full border border-gray-300 + const [message, setMessage] = useState(""); + useEffect(() => { + setMessage(chat.message); + }, [chat.message]); + const [hidden, setHidden] = useState(true); + return ( +
+
+ {!chat.isSend && } + {chat.isSend && } +
+ {!chat.isSend ? ( +
+
+ {hidden && chat.thought && chat.thought !== "" && ( +
setHidden((prev) => !prev)} + className="absolute -top-1 -left-2 cursor-pointer" + > + +
+ )} + {chat.thought && chat.thought !== "" && !hidden && ( +
setHidden((prev) => !prev)} + className=" text-start inline-block rounded-md h-full border border-gray-300 bg-gray-100 w-[95%] pb-3 pt-3 px-2 ml-3 cursor-pointer scrollbar-hide overflow-scroll" - dangerouslySetInnerHTML={{ - __html: convert.toHtml(chat.thought), - }} - >
- )} - {chat.thought && chat.thought !== "" && !hidden &&

} -
- - {chat.message} - {chat.files && ( -
- {chat.files.map((file, index) => { - return ( -
- -
- ); - })} -
- )} -
-
-
-
- ) : ( -
-
- {chat.message} -
-
- )} -
- ); + dangerouslySetInnerHTML={{ + __html: convert.toHtml(chat.thought), + }} + >
+ )} + {chat.thought && chat.thought !== "" && !hidden &&

} +
+
+
+ + ▍ + + ); + } + + children[0] = (children[0] as string).replace( + "`▍`", + "▍" + ); + } + + const match = /language-(\w+)/.exec(className || ""); + + return !inline ? ( + + ) : ( + + {children} + + ); + }, + }} + > + {message} + +
+ {chat.files && ( +
+ {chat.files.map((file, index) => { + return ( +
+ +
+ ); + })} +
+ )} +
+
+
+
+ ) : ( +
+
+ + {message} + +
+
+ )} +
+ ); } diff --git a/src/frontend/src/modals/chatModal/fileComponent/index.tsx b/src/frontend/src/modals/chatModal/fileComponent/index.tsx index a7b492c95..1ffb1da01 100644 --- a/src/frontend/src/modals/chatModal/fileComponent/index.tsx +++ b/src/frontend/src/modals/chatModal/fileComponent/index.tsx @@ -1,19 +1,55 @@ -import { CloudArrowDownIcon, DocumentIcon } from "@heroicons/react/24/outline"; -import * as base64js from 'base64-js'; +import { CloudArrowDownIcon, DocumentIcon } from "@heroicons/react/24/outline"; +import * as base64js from "base64-js"; +import { useState } from "react"; export default function FileCard({ fileName, content, fileType }) { - const handleDownload = () => { - const byteArray = new Uint8Array(base64js.toByteArray(content)); - const blob = new Blob([byteArray], { type: 'application/octet-stream' }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName+".png"; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); - }; + const handleDownload = () => { + const byteArray = new Uint8Array(base64js.toByteArray(content)); + const blob = new Blob([byteArray], { type: "application/octet-stream" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = fileName + ".png"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; + const [isHovered, setIsHovered] = useState(false); + function handleMouseEnter() { + setIsHovered(true); + } + function handleMouseLeave() { + setIsHovered(false); + } + + if (fileType === "image") { + return ( +
+ generated image + {isHovered && ( +
+ +
+ )} +
+ ); + } return ( @@ -334,7 +362,7 @@ export default function ChatModal({ {chatHistory.length > 0 ? ( chatHistory.map((c, i) => ) ) : ( -
+
👋{" "} diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index db4de60f4..d2c539b28 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -134,7 +134,7 @@ export default function CodeAreaModal({ title: "Code is ready to run", }); setModalOpen(false); - setValue(code) + setValue(code); } else { if (funcErrors.length !== 0) { setErrorData({ @@ -142,7 +142,7 @@ export default function CodeAreaModal({ list: funcErrors, }); } - if(importsErrors.length!==0){ + if (importsErrors.length !== 0) { setErrorData({ title: "There is an error in your imports", list: importsErrors, diff --git a/src/frontend/src/modals/exportModal/index.tsx b/src/frontend/src/modals/exportModal/index.tsx index 10494bc58..e2761e0fd 100644 --- a/src/frontend/src/modals/exportModal/index.tsx +++ b/src/frontend/src/modals/exportModal/index.tsx @@ -1,9 +1,9 @@ import { Dialog, Transition } from "@headlessui/react"; import { - XMarkIcon, - ArrowDownTrayIcon, - DocumentDuplicateIcon, - ComputerDesktopIcon, + XMarkIcon, + ArrowDownTrayIcon, + DocumentDuplicateIcon, + ComputerDesktopIcon, } from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { alertContext } from "../../contexts/alertContext"; @@ -12,169 +12,169 @@ import { TabsContext } from "../../contexts/tabsContext"; import { removeApiKeys } from "../../utils"; export default function ExportModal() { - const [open, setOpen] = useState(true); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - const { setErrorData } = useContext(alertContext); - const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext); - function setModalOpen(x: boolean) { - setOpen(x); - if (x === false) { - setTimeout(() => { - closePopUp(); - }, 300); - } - } - const [checked, setChecked] = useState(true); - const [name, setName] = useState(flows[tabIndex].name); - return ( - - - -
- + const [open, setOpen] = useState(true); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + const { setErrorData } = useContext(alertContext); + const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } + const [checked, setChecked] = useState(true); + const [name, setName] = useState(flows[tabIndex].name); + return ( + + + +
+ -
-
- - -
- -
-
-
-
-
-
- - Export as - -
-
-
-
- - { - if (event.target.value != "") { - let newFlow = flows[tabIndex]; - newFlow.name = event.target.value; - setName(event.target.value); - updateFlow(newFlow); - } else { - setName(event.target.value); - } - }} - type="text" - name="name" - value={name ?? null} - placeholder="File name" - id="name" - className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100" - /> -
-
- - -
+
+
+ + +
+ +
+
+
+
+
+
+ + Export as + +
+
+
+
+ + { + if (event.target.value != "") { + let newFlow = flows[tabIndex]; + newFlow.name = event.target.value; + setName(event.target.value); + updateFlow(newFlow); + } else { + setName(event.target.value); + } + }} + type="text" + name="name" + value={name ?? null} + placeholder="File name" + id="name" + className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500 text-gray-900 dark:text-gray-100" + /> +
+
+ + +
-
- -
-
- -
-
-
-
-
-
-
-
-
- ); +
+ +
+
+ +
+
+
+ + +
+
+ + + ); } diff --git a/src/frontend/src/modals/importModal/index.tsx b/src/frontend/src/modals/importModal/index.tsx index 0ad655bf1..d351b847a 100644 --- a/src/frontend/src/modals/importModal/index.tsx +++ b/src/frontend/src/modals/importModal/index.tsx @@ -1,11 +1,11 @@ import { Dialog, Transition } from "@headlessui/react"; import { - XMarkIcon, - ArrowDownTrayIcon, - DocumentDuplicateIcon, - ComputerDesktopIcon, - ArrowUpTrayIcon, - ArrowLeftIcon, + XMarkIcon, + ArrowDownTrayIcon, + DocumentDuplicateIcon, + ComputerDesktopIcon, + ArrowUpTrayIcon, + ArrowLeftIcon, } from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; @@ -19,214 +19,214 @@ import { FlowType } from "../../types/flow"; import { classNames, toNormalCase } from "../../utils"; export default function ImportModal() { - const [open, setOpen] = useState(true); - const { setErrorData } = useContext(alertContext); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - const [showExamples, setShowExamples] = useState(false); - const [loadingExamples, setLoadingExamples] = useState(false); - const [examples, setExamples] = useState([]); - const { uploadFlow, addFlow } = useContext(TabsContext); - function setModalOpen(x: boolean) { - setOpen(x); - if (x === false) { - setTimeout(() => { - closePopUp(); - }, 300); - } - } + const [open, setOpen] = useState(true); + const { setErrorData } = useContext(alertContext); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + const [showExamples, setShowExamples] = useState(false); + const [loadingExamples, setLoadingExamples] = useState(false); + const [examples, setExamples] = useState([]); + const { uploadFlow, addFlow } = useContext(TabsContext); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } - function handleExamples() { - setLoadingExamples(true); - getExamples() - .then((result) => { - setLoadingExamples(false); - setExamples(result); - }) - .catch((error) => - setErrorData({ - title: "there was an error loading examples, please try again", - list: [error.message], - }) - ); - } + function handleExamples() { + setLoadingExamples(true); + getExamples() + .then((result) => { + setLoadingExamples(false); + setExamples(result); + }) + .catch((error) => + setErrorData({ + title: "there was an error loading examples, please try again", + list: [error.message], + }) + ); + } - return ( - - - -
- + return ( + + + +
+ -
-
- - -
- -
- {showExamples && ( - <> -
- -
- - - )} -
-
-
-
-
- - {showExamples ? "Select an example" : "Import from"} - -
-
-
- {!showExamples && ( -
- - } - onClick={() => { - setShowExamples(true); - handleExamples(); - }} - textColor="text-emerald-400" - title="Examples" - > - - } - onClick={() => { - uploadFlow(); - setModalOpen(false); - }} - textColor="text-blue-500" - title="Local file" - > -
- )} - {showExamples && loadingExamples && ( -
- -
- )} - {showExamples && - !loadingExamples && - examples.map((example, index) => { - return ( -
- {" "} - - } - onClick={() => { - addFlow(example); - setModalOpen(false); - }} - textColor="text-emerald-400" - title={toNormalCase(example.name)} - > -
- ); - })} -
-
-
-
-
-
-
-
- ); +
+
+ + +
+ +
+ {showExamples && ( + <> +
+ +
+ + + )} +
+
+
+
+
+ + {showExamples ? "Select an example" : "Import from"} + +
+
+
+ {!showExamples && ( +
+ + } + onClick={() => { + setShowExamples(true); + handleExamples(); + }} + textColor="text-emerald-400" + title="Examples" + > + + } + onClick={() => { + uploadFlow(); + setModalOpen(false); + }} + textColor="text-blue-500" + title="Local file" + > +
+ )} + {showExamples && loadingExamples && ( +
+ +
+ )} + {showExamples && + !loadingExamples && + examples.map((example, index) => { + return ( +
+ {" "} + + } + onClick={() => { + addFlow(example); + setModalOpen(false); + }} + textColor="text-emerald-400" + title={toNormalCase(example.name)} + > +
+ ); + })} +
+
+
+
+
+
+
+
+ ); } diff --git a/src/frontend/src/modals/promptModal/index.tsx b/src/frontend/src/modals/promptModal/index.tsx index 10dab2c2c..63edfeb94 100644 --- a/src/frontend/src/modals/promptModal/index.tsx +++ b/src/frontend/src/modals/promptModal/index.tsx @@ -135,7 +135,8 @@ export default function PromptAreaModal({ return setErrorData({ title: "There is something wrong with this prompt, please review it", - list:[error.response.data.detail]}); + list: [error.response.data.detail], + }); }); }} > diff --git a/src/frontend/src/modals/textAreaModal/index.tsx b/src/frontend/src/modals/textAreaModal/index.tsx index 8cfcebcd1..10e4555a4 100644 --- a/src/frontend/src/modals/textAreaModal/index.tsx +++ b/src/frontend/src/modals/textAreaModal/index.tsx @@ -1,104 +1,123 @@ import { Dialog, Transition } from "@headlessui/react"; -import { XMarkIcon, ClipboardDocumentListIcon } from "@heroicons/react/24/outline"; +import { + XMarkIcon, + ClipboardDocumentListIcon, +} from "@heroicons/react/24/outline"; import { Fragment, useContext, useRef, useState } from "react"; import { PopUpContext } from "../../contexts/popUpContext"; -export default function TextAreaModal({value, setValue}:{setValue:(value:string)=>void,value:string|string[]}){ - const [open, setOpen] = useState(true); - const [myValue, setMyValue] = useState(value); - const { closePopUp } = useContext(PopUpContext); - const ref = useRef(); - function setModalOpen(x:boolean){ - setOpen(x); - if(x === false){ - setTimeout(() => {closePopUp()}, 300); - } - } - return ( - - - -
- +export default function TextAreaModal({ + value, + setValue, +}: { + setValue: (value: string) => void; + value: string | string[]; +}) { + const [open, setOpen] = useState(true); + const [myValue, setMyValue] = useState(value); + const { closePopUp } = useContext(PopUpContext); + const ref = useRef(); + function setModalOpen(x: boolean) { + setOpen(x); + if (x === false) { + setTimeout(() => { + closePopUp(); + }, 300); + } + } + return ( + + + +
+ -
-
- - -
- -
-
-
-
-
-
- - Edit text - -
-
-
-
-
-