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 (
+
+
+
+
+
{
+ event.preventDefault();
+ openPopUp( );
+ }}
+ >
+
+ {Object.keys(data.node.template).some(
+ (t) =>
+ data.node.template[t].advanced &&
+ data.node.template[t].required
+ )
+ ? " *"
+ : ""}
+
+
+ data.node.template[t].advanced && data.node.template[t].show
+ )
+ ? ""
+ : "hidden",
+ "w-6 h-6 dark:text-gray-500 hover:animate-spin"
+ )}
+ >
+
+
{
+ deleteNode(data.id);
+ }}
+ >
+
+
+
+
- return (
-
-
-
-
-
{
- event.preventDefault();
- openPopUp( );
- }}
- >
-
- {Object.keys(data.node.template).some(
- (t) =>
- data.node.template[t].advanced &&
- data.node.template[t].required
- )
- ? " *"
- : ""}
-
-
- data.node.template[t].advanced && data.node.template[t].show
- )
- ? ""
- : "hidden",
- "w-6 h-6 dark:text-gray-500 hover:animate-spin"
- )}
- >
-
-
{
- deleteNode(data.id);
- }}
- >
-
-
-
-
+
+
+ {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}
- ))}
-
-
- ) : (
- <>>
- )}
-
-
-
- {
- setShow(false);
- setTimeout(() => {
- removeAlert(dropItem.id);
- }, 500);
- }}
- className="inline-flex rounded-md bg-red-50 p-1.5 text-red-500"
- >
- Dismiss
-
-
-
-
-
- ) : type === "notice" ? (
-
-
-
-
-
-
{dropItem.title}
-
- {dropItem.link ? (
-
- Details
-
- ) : (
- <>>
- )}
-
-
-
-
- {
- setShow(false);
- setTimeout(() => {
- removeAlert(dropItem.id);
- }, 500);
- }}
- className="inline-flex rounded-md bg-blue-50 p-1.5 text-blue-500"
- >
- Dismiss
-
-
-
-
-
- ) : (
-
-
-
-
-
-
-
- {
- setShow(false);
- setTimeout(() => {
- removeAlert(dropItem.id);
- }, 500);
- }}
- className="inline-flex rounded-md bg-green-50 p-1.5 text-green-500"
- >
- Dismiss
-
-
-
-
-
- )}
-
- );
+ return (
+
+ {type === "error" ? (
+
+
+
+
+
+
+ {dropItem.title}
+
+ {dropItem.list ? (
+
+
+ {dropItem.list.map((item, idx) => (
+ {item}
+ ))}
+
+
+ ) : (
+ <>>
+ )}
+
+
+
+ {
+ setShow(false);
+ setTimeout(() => {
+ removeAlert(dropItem.id);
+ }, 500);
+ }}
+ className="inline-flex rounded-md bg-red-50 p-1.5 text-red-500"
+ >
+ Dismiss
+
+
+
+
+
+ ) : type === "notice" ? (
+
+
+
+
+
+
{dropItem.title}
+
+ {dropItem.link ? (
+
+ Details
+
+ ) : (
+ <>>
+ )}
+
+
+
+
+ {
+ setShow(false);
+ setTimeout(() => {
+ removeAlert(dropItem.id);
+ }, 500);
+ }}
+ className="inline-flex rounded-md bg-blue-50 p-1.5 text-blue-500"
+ >
+ Dismiss
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+ {
+ setShow(false);
+ setTimeout(() => {
+ removeAlert(dropItem.id);
+ }, 500);
+ }}
+ className="inline-flex rounded-md bg-green-50 p-1.5 text-green-500"
+ >
+ Dismiss
+
+
+
+
+
+ )}
+
+ );
}
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
-
- {
- closePopUp();
- setTimeout(clearNotificationList, 100);
- }}
- >
-
-
-
-
-
-
-
-
- {notificationList.length !== 0 ? (
- notificationList.map((alertItem, index) => (
-
- ))
- ) : (
-
- No new notifications
-
- )}
-
-
- );
+ return (
+
+
+ Notifications
+
+ {
+ closePopUp();
+ setTimeout(clearNotificationList, 100);
+ }}
+ >
+
+
+
+
+
+
+
+
+ {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.
-
- >
- );
+ const {
+ current,
+ isStackedOpen,
+ setIsStackedOpen,
+ extraNavigation,
+ extraComponent,
+ } = useContext(locationContext);
+ return (
+ <>
+
+ >
+ );
}
diff --git a/src/frontend/src/components/LightTooltipComponent/index.tsx b/src/frontend/src/components/LightTooltipComponent/index.tsx
index ae4a2ffd4..334fc0e71 100644
--- a/src/frontend/src/components/LightTooltipComponent/index.tsx
+++ b/src/frontend/src/components/LightTooltipComponent/index.tsx
@@ -1,17 +1,17 @@
-import { styled } from '@mui/material/styles';
-import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
+import { styled } from "@mui/material/styles";
+import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip";
export const LightTooltip = styled(({ className, ...props }: TooltipProps) => (
-
+
))(({ theme }) => ({
- [`& .${tooltipClasses.tooltip}`]: {
- backgroundColor: theme.palette.common.white,
- color: 'rgba(0, 0, 0, 0.87)',
- boxShadow: theme.shadows[2],
- fontSize: 14,
- },
- [`& .${tooltipClasses.arrow}:before`]: {
- color: theme.palette.common.white,
- boxShadow: theme.shadows[1],
- },
-}));
\ No newline at end of file
+ [`& .${tooltipClasses.tooltip}`]: {
+ backgroundColor: theme.palette.common.white,
+ color: "rgba(0, 0, 0, 0.87)",
+ boxShadow: theme.shadows[2],
+ fontSize: 14,
+ },
+ [`& .${tooltipClasses.arrow}:before`]: {
+ color: theme.palette.common.white,
+ boxShadow: theme.shadows[1],
+ },
+}));
diff --git a/src/frontend/src/components/TooltipComponent/index.tsx b/src/frontend/src/components/TooltipComponent/index.tsx
index 65c8d0e5f..f0a4eb8e6 100644
--- a/src/frontend/src/components/TooltipComponent/index.tsx
+++ b/src/frontend/src/components/TooltipComponent/index.tsx
@@ -2,6 +2,14 @@ import { ReactElement } from "react";
import { LightTooltip } from "../LightTooltipComponent";
import { TooltipComponentType } from "../../types/components";
-export default function Tooltip({ children, title,placement }:TooltipComponentType) {
- return {children} ;
+export default function Tooltip({
+ children,
+ title,
+ placement,
+}: TooltipComponentType) {
+ return (
+
+ {children}
+
+ );
}
diff --git a/src/frontend/src/components/chatComponent/chatMessage/index.tsx b/src/frontend/src/components/chatComponent/chatMessage/index.tsx
index aa2a0d080..d155ed8ab 100644
--- a/src/frontend/src/components/chatComponent/chatMessage/index.tsx
+++ b/src/frontend/src/components/chatComponent/chatMessage/index.tsx
@@ -1,9 +1,13 @@
-import { ChatBubbleLeftEllipsisIcon, ChatBubbleOvalLeftEllipsisIcon, PlusSmallIcon } from "@heroicons/react/24/outline";
+import {
+ ChatBubbleLeftEllipsisIcon,
+ ChatBubbleOvalLeftEllipsisIcon,
+ PlusSmallIcon,
+} from "@heroicons/react/24/outline";
import { useState } from "react";
import { ChatMessageType } from "../../../types/chat";
import { nodeColors } from "../../../utils";
-var Convert = require('ansi-to-html');
-var convert = new Convert({newline:true});
+var Convert = require("ansi-to-html");
+var convert = new Convert({ newline: true });
export default function ChatMessage({ chat }: { chat: ChatMessageType }) {
const [hidden, setHidden] = useState(true);
@@ -29,13 +33,16 @@ export default function ChatMessage({ chat }: { chat: ChatMessageType }) {
style={{ backgroundColor: nodeColors["thought"] }}
className=" text-start inline-block w-full pb-3 pt-3 px-5 cursor-pointer"
dangerouslySetInnerHTML={{
- __html: convert.toHtml(chat.thought)
+ __html: convert.toHtml(chat.thought),
}}
>
)}
{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(
-
-
-
{
- setOpen(true);
- }}
- >
-
-
-
-
-
-
- )
-}
\ No newline at end of file
+export default function ChatTrigger({ open, setOpen }) {
+ const { openPopUp } = useContext(PopUpContext);
+ return (
+
+
+
+
{
+ setOpen(true);
+ }}
+ >
+
+
+
+
+
+
+
+ );
+}
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);
- }}
- />
-
{
- setPwdVisible(!pwdVisible);
- }}
- >
- {password &&
- (pwdVisible ? (
-
-
-
- ) : (
-
-
-
-
- ))}
-
-
- );
+ 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);
+ }}
+ />
+
{
+ setPwdVisible(!pwdVisible);
+ }}
+ >
+ {password &&
+ (pwdVisible ? (
+
+
+
+ ) : (
+
+
+
+
+ ))}
+
+
+ );
}
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 ?
-
{setInputList((old) => {
- let newInputList = _.cloneDeep(old);
- newInputList.push('');
- return newInputList;
- });
- onChange(inputList);}}>
-
-
- :
{setInputList((old) => {
- let newInputList = _.cloneDeep(old);
- newInputList.splice(idx, 1);
- return newInputList;
- });
- onChange(inputList);}}>
-
- }
-
- ))}
-
- );
+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 ? (
+
{
+ setInputList((old) => {
+ let newInputList = _.cloneDeep(old);
+ newInputList.push("");
+ return newInputList;
+ });
+ onChange(inputList);
+ }}
+ >
+
+
+ ) : (
+
{
+ setInputList((old) => {
+ let newInputList = _.cloneDeep(old);
+ newInputList.splice(idx, 1);
+ return newInputList;
+ });
+ onChange(inputList);
+ }}
+ >
+
+
+ )}
+
+ ))}
+
+ );
}
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 (
+
+ );
}
-
-
-export default function LoadingComponent({remSize}:LoadingComponentProps){
- return(
-
- )
-}
\ 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'}
-
-
{openPopUp( {setMyValue(t); onChange(t);}}/>)}}>
-
-
-
-
- );
+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"}
+
+
{
+ openPopUp(
+ {
+ setMyValue(t);
+ onChange(t);
+ }}
+ />
+ );
+ }}
+ >
+
+
+
+
+ );
}
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}
+
+
+
+ {isCopied ? : }
+ {isCopied ? "Copied!" : "Copy code"}
+
+
+
+
+
+
+
+
+ {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 (
-
-
-
- );
- })}
-
- )}
-
-
-
-
- ) : (
-
- )}
-
- );
+ 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 (
+
+
+
+ );
+ })}
+
+ )}
+
+
+
+
+ ) : (
+
+ )}
+
+ );
}
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 (
+
+
+ {isHovered && (
+
+
+
+
+
+ )}
+
+ );
+ }
return (
{" "}
-
+ {fileType === "image" ? (
+
+ ) : (
+
+ )}
{" "}
{fileName}
-
{fileType}
-
+
{fileType}
diff --git a/src/frontend/src/modals/chatModal/index.tsx b/src/frontend/src/modals/chatModal/index.tsx
index dd82ae313..50ad42b23 100644
--- a/src/frontend/src/modals/chatModal/index.tsx
+++ b/src/frontend/src/modals/chatModal/index.tsx
@@ -1,13 +1,7 @@
import { Dialog, Transition } from "@headlessui/react";
-import {
- ChatBubbleOvalLeftEllipsisIcon,
- LockClosedIcon,
- PaperAirplaneIcon,
-} from "@heroicons/react/24/outline";
+import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline";
import { Fragment, useContext, useEffect, useRef, useState } from "react";
-import { PopUpContext } from "../../contexts/popUpContext";
import { FlowType, NodeType } from "../../types/flow";
-import { TabsContext } from "../../contexts/tabsContext";
import { alertContext } from "../../contexts/alertContext";
import { toNormalCase } from "../../utils";
import { typesContext } from "../../contexts/typesContext";
@@ -32,8 +26,15 @@ export default function ChatModal({
const [chatHistory, setChatHistory] = useState([]);
const { reactFlowInstance } = useContext(typesContext);
const { setErrorData, setNoticeData } = useContext(alertContext);
- const [ws, setWs] = useState(null);
+ const ws = useRef(null);
const [lockChat, setLockChat] = useState(false);
+ const isOpen = useRef(open);
+
+ useEffect(() => {
+ isOpen.current = open;
+ }, [open]);
+ var isStream = false;
+
const addChatHistory = (
message: string,
isSend: boolean,
@@ -53,135 +54,176 @@ export default function ChatModal({
});
};
+ //add proper type signature for function
+
+ function updateLastMessage({
+ str,
+ thought,
+ end = false,
+ files,
+ }: {
+ str?: string;
+ thought?: string;
+ // end param default is false
+ end?: boolean;
+ files?: Array;
+ }) {
+ setChatHistory((old) => {
+ let newChat = [...old];
+ if (str) {
+ if (end) {
+ newChat[newChat.length - 1].message = str;
+ } else {
+ newChat[newChat.length - 1].message =
+ newChat[newChat.length - 1].message + str;
+ }
+ }
+ if (thought) {
+ newChat[newChat.length - 1].thought = thought;
+ }
+ if (files) {
+ newChat[newChat.length - 1].files = files;
+ }
+ return newChat;
+ });
+ }
+
+ function handleOnClose(event: CloseEvent) {
+ if (isOpen.current) {
+ setErrorData({ title: event.reason });
+ setLockChat(false);
+ setTimeout(() => {
+ connectWS();
+ }, 1000);
+ }
+ }
+
+ function handleWsMessage(data: any) {
+ if (Array.isArray(data)) {
+ //set chat history
+ setChatHistory((_) => {
+ let newChatHistory: ChatMessageType[] = [];
+ data.forEach(
+ (chatItem: {
+ intermediate_steps?: "string";
+ is_bot: boolean;
+ message: string;
+ type: string;
+ files?: Array;
+ }) => {
+ if (chatItem.message) {
+ newChatHistory.push(
+ chatItem.files
+ ? {
+ isSend: !chatItem.is_bot,
+ message: chatItem.message,
+ thought: chatItem.intermediate_steps,
+ files: chatItem.files,
+ }
+ : {
+ isSend: !chatItem.is_bot,
+ message: chatItem.message,
+ thought: chatItem.intermediate_steps,
+ }
+ );
+ }
+ }
+ );
+ return newChatHistory;
+ });
+ }
+ if (data.type === "start") {
+ addChatHistory("", false);
+ isStream = true;
+ }
+ if (data.type === "end") {
+ if (data.intermediate_steps) {
+ updateLastMessage({
+ str: data.message,
+ thought: data.intermediate_steps,
+ end: true,
+ });
+ }
+ if (data.files) {
+ updateLastMessage({
+ end: true,
+ files: data.files,
+ });
+ }
+
+ setLockChat(false);
+ isStream = false;
+ }
+ if (data.type === "stream" && isStream) {
+ updateLastMessage({ str: data.message });
+ }
+ }
+
function connectWS() {
- console.log("conectou");
try {
const urlWs =
process.env.NODE_ENV === "development"
? `ws://localhost:7860/chat/${flow.id}`
- : `${window.location.protocol === "https:" ? "wss" : "ws"}://${
- window.location.host
- }/chat/${flow.id}`;
+ : `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host
+ }/chat/${flow.id}`;
const newWs = new WebSocket(urlWs);
newWs.onopen = () => {
console.log("WebSocket connection established!");
};
+ console.log(flow.id);
newWs.onmessage = (event) => {
- try {
- setLockChat(false);
- const data = JSON.parse(event.data);
- console.log("Received data:", data);
- //get chat history
- if (Array.isArray(data)) {
- console.log(data);
-
- setChatHistory((_) => {
- let newChatHistory: ChatMessageType[] = [];
- data.forEach(
- (chatItem: {
- intermediate_steps?: "string";
- is_bot: boolean;
- message: string;
- type: string;
- files?: Array;
- }) => {
- if (chatItem.message) {
- newChatHistory.push(
- chatItem.files
- ? {
- isSend: !chatItem.is_bot,
- message: chatItem.message,
- thought: chatItem.intermediate_steps,
- files: chatItem.files,
- }
- : {
- isSend: !chatItem.is_bot,
- message: chatItem.message,
- thought: chatItem.intermediate_steps,
- }
- );
- }
- }
- );
- return newChatHistory;
- });
- }
- if (data.type === "end") {
- if (data.files) {
- addChatHistory(
- data.message,
- false,
- data.intermediate_steps,
- data.files
- );
- } else {
- addChatHistory(data.message, false, data.intermediate_steps);
- }
- }
- if (data.type == "file") {
- console.log(data);
- }
- } catch (error) {
- if (event.data !== "Error: 1005") {
- setErrorData({ title: event.data });
- newWs.close();
- connectWS();
- }
- }
+ const data = JSON.parse(event.data);
+ console.log("Received data:", data);
+ handleWsMessage(data);
+ //get chat history
};
- newWs.onclose = (_) => {
- if (open) {
- setLockChat(false);
- setTimeout(() => {
- connectWS();
- }, 1000);
- }
+ newWs.onclose = (event) => {
+ handleOnClose(event);
};
newWs.onerror = (ev) => {
console.log(ev, "error");
+ setErrorData({
+ title: "There was an error on web connection, please: ",
+ list: [
+ "Refresh the page",
+ "Use a new flow tab",
+ "Check if the backend is up",
+ ],
+ });
};
- setWs(newWs);
-
- return newWs;
+ ws.current = newWs;
} catch {
setErrorData({
title: "There was an error on web connection, please: ",
list: [
- "refresh the page",
- "use a new flow tab",
- "check if the backend is up",
+ "Refresh the page",
+ "Use a new flow tab",
+ "Check if the backend is up",
],
});
}
}
useEffect(() => {
- if (ws && (ws.readyState === ws.CLOSED || ws.readyState === ws.CLOSING)) {
- let newWs = connectWS();
- return () => {
- console.log("trigger");
- newWs.close();
- };
- }
- }, [lockChat]);
-
- useEffect(() => {
- let newWs = connectWS();
+ connectWS();
return () => {
- console.log("trigger");
- newWs.close();
+ console.log("unmount");
+ console.log(ws);
+ if (ws) {
+ ws.current.close();
+ }
};
}, []);
async function sendAll(data: sendAllProps) {
try {
if (ws) {
- ws.send(JSON.stringify(data));
+ ws.current.send(JSON.stringify(data));
}
} catch (error) {
setErrorData({
- title: "There was an erro sending the message",
+ title: "There was an error sending the message",
list: [error.message],
});
setChatValue(data.message);
@@ -193,12 +235,6 @@ export default function ChatModal({
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
}, [chatHistory]);
- useEffect(() => {
- if (ws && ws.readyState === ws.CLOSED) {
- setLockChat(false);
- }
- }, [lockChat]);
-
function validateNode(n: NodeType): Array {
if (!n.data?.node?.template || !Object.keys(n.data.node.template)) {
setNoticeData({
@@ -227,12 +263,11 @@ export default function ChatModal({
e.targetHandle.split("|")[2] === n.id
)
? [
- `${type} is missing ${
- template.display_name
- ? template.display_name
- : toNormalCase(template[t].name)
- }.`,
- ]
+ `${type} is missing ${template.display_name
+ ? template.display_name
+ : toNormalCase(template[t].name)
+ }.`,
+ ]
: []
),
[] as string[]
@@ -255,7 +290,6 @@ export default function ChatModal({
let message = chatValue;
setChatValue("");
addChatHistory(message, true);
-
sendAll({
...reactFlowInstance.toObject(),
message,
@@ -278,20 +312,14 @@ export default function ChatModal({
}
function clearChat() {
setChatHistory([]);
- ws.send(JSON.stringify({ clear_history: true }));
+ ws.current.send(JSON.stringify({ clear_history: true }));
}
- const { closePopUp } = useContext(PopUpContext);
function setModalOpen(x: boolean) {
setOpen(x);
- if (x === false) {
- setTimeout(() => {
- closePopUp();
- }, 300);
- }
}
return (
-
+
-
-
+
+
clearChat()}
- className="absolute top-2 right-2 hover:text-red-500"
+ className="absolute top-2 right-3 hover:text-red-500 z-30"
>
@@ -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 (
+
+
+
+
+
-
-
-
-
-
- {
- setModalOpen(false);
- }}
- >
- Close
-
-
-
-
-
-
-
-
- Name
-
- {
- 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"
- />
-
-
-
- Description{" "}
-
- {" "}
- (optional)
-
-
-
-
+
+
+
+
+
+ {
+ setModalOpen(false);
+ }}
+ >
+ Close
+
+
+
+
+
+
+
+
+ Name
+
+ {
+ 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"
+ />
+
+
+
+ Description{" "}
+
+ {" "}
+ (optional)
+
+
+
+
-
-
- {
- setChecked(event.target.checked);
- }}
- checked={checked}
- id="checkbox"
- type="checkbox"
- className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
- />
-
- Save with my API keys
-
-
-
-
- {
- if (checked) downloadFlow(flows[tabIndex]);
- else downloadFlow(removeApiKeys(flows[tabIndex]));
- }}
- className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
- >
- Download Flow
-
-
-
-
-
-
-
-
-
-
- );
+
+
+ {
+ setChecked(event.target.checked);
+ }}
+ checked={checked}
+ id="checkbox"
+ type="checkbox"
+ className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
+ />
+
+ Save with my API keys
+
+
+
+
+ {
+ if (checked) downloadFlow(flows[tabIndex]);
+ else downloadFlow(removeApiKeys(flows[tabIndex]));
+ }}
+ className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
+ >
+ Download Flow
+
+
+
+
+
+
+
+
+
+
+ );
}
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 (
+
+
+
+
+
-
-
-
-
-
- {
- setModalOpen(false);
- }}
- >
- Close
-
-
-
- {showExamples && (
- <>
-
-
{
- setShowExamples(false);
- }}
- >
- Close
-
-
-
-
- >
- )}
-
-
-
-
-
- {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)}
- >
-
- );
- })}
-
-
-
-
-
-
-
-
- );
+
+
+
+
+
+ {
+ setModalOpen(false);
+ }}
+ >
+ Close
+
+
+
+ {showExamples && (
+ <>
+
+
{
+ setShowExamples(false);
+ }}
+ >
+ Close
+
+
+
+
+ >
+ )}
+
+
+
+
+
+ {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 (
+
+
+
+
+
-
-
-
-
-
- {
- setModalOpen(false);
- }}
- >
- Close
-
-
-
-
-
-
-
-
-
-
- Edit text
-
-
-
-
-
- {
- setModalOpen(false);
- }}
- >
- Finish editing
-
-
-
-
-
-
-
-
-
- )
-}
\ No newline at end of file
+
+
+
+
+
+ {
+ setModalOpen(false);
+ }}
+ >
+ Close
+
+
+
+
+
+
+
+
+
+
+ Edit text
+
+
+
+
+
+ {
+ setModalOpen(false);
+ }}
+ >
+ Finish editing
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/frontend/src/pages/FlowPage/components/ConnectionLineComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/ConnectionLineComponent/index.tsx
index 102cd4d38..9eae07286 100644
--- a/src/frontend/src/pages/FlowPage/components/ConnectionLineComponent/index.tsx
+++ b/src/frontend/src/pages/FlowPage/components/ConnectionLineComponent/index.tsx
@@ -1,14 +1,12 @@
-import { ConnectionLineComponentProps } from 'reactflow';
-
-
+import { ConnectionLineComponentProps } from "reactflow";
const ConnectionLineComponent = ({
fromX,
fromY,
toX,
toY,
- connectionLineStyle = {} // provide a default value for connectionLineStyle
-}:ConnectionLineComponentProps) => {
+ connectionLineStyle = {}, // provide a default value for connectionLineStyle
+}: ConnectionLineComponentProps) => {
return (
{({ open }) => (
diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx
index fc02e31d5..37bf096dd 100644
--- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx
+++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx
@@ -3,13 +3,10 @@ import DisclosureComponent from "../DisclosureComponent";
import { nodeColors, nodeIcons, nodeNames } from "../../../../utils";
import { useContext, useEffect, useState } from "react";
import { typesContext } from "../../../../contexts/typesContext";
-import {
- APIClassType,
- APIObjectType,
-} from "../../../../types/api";
+import { APIClassType, APIObjectType } from "../../../../types/api";
export default function ExtraSidebar() {
- const {data} = useContext(typesContext)
+ const { data } = useContext(typesContext);
function onDragStart(
event: React.DragEvent,
@@ -22,45 +19,49 @@ export default function ExtraSidebar() {
return (
- {Object.keys(data).sort().map((d: keyof APIObjectType, i) => (
-
-
- {Object.keys(data[d]).sort().map((t: string, k) => (
-
-
- onDragStart(event, {
- type: t,
- node: data[d][t],
- })
- }
- >
-
-
- {t}
-
-
+ {Object.keys(data)
+ .sort()
+ .map((d: keyof APIObjectType, i) => (
+
+
+ {Object.keys(data[d])
+ .sort()
+ .map((t: string, k) => (
+
+
+ onDragStart(event, {
+ type: t,
+ node: data[d][t],
+ })
+ }
+ >
+
+
+ {t}
+
+
+
+
-
-
- ))}
- {Object.keys(data[d]).length === 0 && (
-
Coming soon
- )}
-
-
- ))}
+ ))}
+ {Object.keys(data[d]).length === 0 && (
+
Coming soon
+ )}
+
+
+ ))}
);
}
diff --git a/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx
index a8d098c32..964ab440c 100644
--- a/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx
+++ b/src/frontend/src/pages/FlowPage/components/tabComponent/index.tsx
@@ -5,9 +5,16 @@ import { FlowType } from "../../../../types/flow";
var _ = require("lodash");
-export default function TabComponent({ selected, flow, onClick }:{flow:FlowType,selected:boolean,onClick:()=>void}) {
- const { removeFlow, updateFlow, flows } =
- useContext(TabsContext);
+export default function TabComponent({
+ selected,
+ flow,
+ onClick,
+}: {
+ flow: FlowType;
+ selected: boolean;
+ onClick: () => void;
+}) {
+ const { removeFlow, updateFlow, flows } = useContext(TabsContext);
const [isRename, setIsRename] = useState(false);
const [value, setValue] = useState("");
return (
@@ -19,7 +26,7 @@ export default function TabComponent({ selected, flow, onClick }:{flow:FlowType,
onClick={onClick}
>
{flow.name}
-
+
{
e.stopPropagation();
@@ -85,4 +92,3 @@ export default function TabComponent({ selected, flow, onClick }:{flow:FlowType,
>
);
}
-
diff --git a/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx
index 7a7526906..4873c9a6d 100644
--- a/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx
+++ b/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx
@@ -94,9 +94,7 @@ export default function TabsManagerComponent() {
>
-
-
-
+
>
);
}}
diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx
index fdb226629..ce28e0305 100644
--- a/src/frontend/src/pages/FlowPage/index.tsx
+++ b/src/frontend/src/pages/FlowPage/index.tsx
@@ -1,21 +1,21 @@
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import ReactFlow, {
- Background,
- Controls,
- addEdge,
- useEdgesState,
- useNodesState,
- useReactFlow,
- updateEdge,
- EdgeChange,
- Connection,
- Edge,
- useKeyPress,
- useOnSelectionChange,
- NodeDragHandler,
- OnEdgesDelete,
- OnNodesDelete,
- SelectionDragHandler,
+ Background,
+ Controls,
+ addEdge,
+ useEdgesState,
+ useNodesState,
+ useReactFlow,
+ updateEdge,
+ EdgeChange,
+ Connection,
+ Edge,
+ useKeyPress,
+ useOnSelectionChange,
+ NodeDragHandler,
+ OnEdgesDelete,
+ OnNodesDelete,
+ SelectionDragHandler,
} from "reactflow";
import { locationContext } from "../../contexts/locationContext";
import ExtraSidebar from "./components/extraSidebarComponent";
@@ -31,270 +31,270 @@ import { isValidConnection } from "../../utils";
import useUndoRedo from "./hooks/useUndoRedo";
const nodeTypes = {
- genericNode: GenericNode,
+ genericNode: GenericNode,
};
var _ = require("lodash");
-export default function FlowPage({ flow }:{flow:FlowType}) {
- let { updateFlow, incrementNodeId} =
+export default function FlowPage({ flow }: { flow: FlowType }) {
+ let { updateFlow, incrementNodeId } =
useContext(TabsContext);
const { types, reactFlowInstance, setReactFlowInstance, templates } =
useContext(typesContext);
const reactFlowWrapper = useRef(null);
- const { undo, redo, canUndo, canRedo, takeSnapshot } = useUndoRedo();
+ const { undo, redo, canUndo, canRedo, takeSnapshot } = useUndoRedo();
- const onKeyDown = (event : React.KeyboardEvent) => {
- if ((event.ctrlKey || event.metaKey) && (event.key === 'c') && lastSelection){
- event.preventDefault();
- setLastCopiedSelection(lastSelection);
- }
- if ((event.ctrlKey || event.metaKey) && (event.key === 'v') && lastCopiedSelection){
- event.preventDefault();
- paste();
- }
- }
+ const onKeyDown = (event: React.KeyboardEvent) => {
+ if ((event.ctrlKey || event.metaKey) && (event.key === 'c') && lastSelection) {
+ event.preventDefault();
+ setLastCopiedSelection(lastSelection);
+ }
+ if ((event.ctrlKey || event.metaKey) && (event.key === 'v') && lastCopiedSelection) {
+ event.preventDefault();
+ paste();
+ }
+ }
- const [lastSelection, setLastSelection] = useState(null);
- const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
+ const [lastSelection, setLastSelection] = useState(null);
+ const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
- const [position, setPosition] = useState({ x: 0, y: 0 });
+ const [position, setPosition] = useState({ x: 0, y: 0 });
- const handleMouseMove = (event) => {
- setPosition({ x: event.clientX, y: event.clientY });
- };
+ const handleMouseMove = (event) => {
+ setPosition({ x: event.clientX, y: event.clientY });
+ };
- useOnSelectionChange({
- onChange: (flow) => {setLastSelection(flow);},
- })
+ useOnSelectionChange({
+ onChange: (flow) => { setLastSelection(flow); },
+ })
- let paste = () => {
- let minimumX = Infinity;
- let minimumY = Infinity;
- let idsMap = {};
- lastCopiedSelection.nodes.forEach((n) => {
- if(n.position.y < minimumY){
- minimumY = n.position.y
- }
- if(n.position.x < minimumX){
- minimumX = n.position.x;
- }
- });
+ let paste = () => {
+ let minimumX = Infinity;
+ let minimumY = Infinity;
+ let idsMap = {};
+ lastCopiedSelection.nodes.forEach((n) => {
+ if (n.position.y < minimumY) {
+ minimumY = n.position.y
+ }
+ if (n.position.x < minimumX) {
+ minimumX = n.position.x;
+ }
+ });
- const bounds = reactFlowWrapper.current.getBoundingClientRect();
- const insidePosition = reactFlowInstance.project({
- x: position.x - bounds.left,
- y: position.y - bounds.top
- });
+ const bounds = reactFlowWrapper.current.getBoundingClientRect();
+ const insidePosition = reactFlowInstance.project({
+ x: position.x - bounds.left,
+ y: position.y - bounds.top
+ });
- lastCopiedSelection.nodes.forEach((n) => {
+ lastCopiedSelection.nodes.forEach((n) => {
- // Generate a unique node ID
- let newId = getId();
- idsMap[n.id] = newId;
+ // Generate a unique node ID
+ let newId = getId();
+ idsMap[n.id] = newId;
- // Create a new node object
- const newNode: NodeType = {
- id: newId,
- type: "genericNode",
- position: {
- x: insidePosition.x + n.position.x - minimumX,
- y: insidePosition.y + n.position.y - minimumY,
- },
- data: {
- ...n.data,
- id: newId,
- },
- };
+ // Create a new node object
+ const newNode: NodeType = {
+ id: newId,
+ type: "genericNode",
+ position: {
+ x: insidePosition.x + n.position.x - minimumX,
+ y: insidePosition.y + n.position.y - minimumY,
+ },
+ data: {
+ ...n.data,
+ id: newId,
+ },
+ };
- // Add the new node to the list of nodes in state
- setNodes((nds) => nds.map((e) => ({...e, selected: false})).concat({...newNode, selected: false}));
- })
+ // Add the new node to the list of nodes in state
+ setNodes((nds) => nds.map((e) => ({ ...e, selected: false })).concat({ ...newNode, selected: false }));
+ })
- lastCopiedSelection.edges.forEach((e) => {
- let source = idsMap[e.source];
- let target = idsMap[e.target];
- let sourceHandleSplitted = e.sourceHandle.split('|');
- let sourceHandle = sourceHandleSplitted[0] + '|' + source + '|' + sourceHandleSplitted.slice(2).join('|');
- let targetHandleSplitted = e.targetHandle.split('|');
- let targetHandle = targetHandleSplitted.slice(0, -1).join('|') + '|' + target;
- let id = "reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle;
- setEdges((eds) =>
- addEdge({ source, target, sourceHandle, targetHandle, id, className: "animate-pulse", selected: false }, eds.map((e) => ({...e, selected: false})))
- );
- })
- }
+ lastCopiedSelection.edges.forEach((e) => {
+ let source = idsMap[e.source];
+ let target = idsMap[e.target];
+ let sourceHandleSplitted = e.sourceHandle.split('|');
+ let sourceHandle = sourceHandleSplitted[0] + '|' + source + '|' + sourceHandleSplitted.slice(2).join('|');
+ let targetHandleSplitted = e.targetHandle.split('|');
+ let targetHandle = targetHandleSplitted.slice(0, -1).join('|') + '|' + target;
+ let id = "reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle;
+ setEdges((eds) =>
+ addEdge({ source, target, sourceHandle, targetHandle, id, className: "animate-pulse", selected: false }, eds.map((e) => ({ ...e, selected: false })))
+ );
+ })
+ }
- const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
- const { setErrorData } = useContext(alertContext);
- const [nodes, setNodes, onNodesChange] = useNodesState(
- flow.data?.nodes ?? []
- );
- const [edges, setEdges, onEdgesChange] = useEdgesState(
- flow.data?.edges ?? []
- );
- const { setViewport } = useReactFlow();
- const edgeUpdateSuccessful = useRef(true);
+ const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
+ const { setErrorData } = useContext(alertContext);
+ const [nodes, setNodes, onNodesChange] = useNodesState(
+ flow.data?.nodes ?? []
+ );
+ const [edges, setEdges, onEdgesChange] = useEdgesState(
+ flow.data?.edges ?? []
+ );
+ const { setViewport } = useReactFlow();
+ const edgeUpdateSuccessful = useRef(true);
- function getId() {
- return `dndnode_` + incrementNodeId();
- }
+ function getId() {
+ return `dndnode_` + incrementNodeId();
+ }
- useEffect(() => {
- if (reactFlowInstance && flow) {
- flow.data = reactFlowInstance.toObject();
- updateFlow(flow);
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [nodes, edges]);
- //update flow when tabs change
- useEffect(() => {
- setNodes(flow?.data?.nodes ?? []);
- setEdges(flow?.data?.edges ?? []);
- if (reactFlowInstance) {
- setViewport(flow?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 });
- }
- }, [flow, reactFlowInstance, setEdges, setNodes, setViewport]);
- //set extra sidebar
- useEffect(() => {
- setExtraComponent( );
- setExtraNavigation({ title: "Components" });
- }, [setExtraComponent, setExtraNavigation]);
+ useEffect(() => {
+ if (reactFlowInstance && flow) {
+ flow.data = reactFlowInstance.toObject();
+ updateFlow(flow);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [nodes, edges]);
+ //update flow when tabs change
+ useEffect(() => {
+ setNodes(flow?.data?.nodes ?? []);
+ setEdges(flow?.data?.edges ?? []);
+ if (reactFlowInstance) {
+ setViewport(flow?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 });
+ }
+ }, [flow, reactFlowInstance, setEdges, setNodes, setViewport]);
+ //set extra sidebar
+ useEffect(() => {
+ setExtraComponent( );
+ setExtraNavigation({ title: "Components" });
+ }, [setExtraComponent, setExtraNavigation]);
- const onEdgesChangeMod = useCallback(
- (s: EdgeChange[]) => {
- onEdgesChange(s);
- setNodes((x) => {
- let newX = _.cloneDeep(x);
- return newX;
- });
- },
- [onEdgesChange, setNodes]
- );
+ const onEdgesChangeMod = useCallback(
+ (s: EdgeChange[]) => {
+ onEdgesChange(s);
+ setNodes((x) => {
+ let newX = _.cloneDeep(x);
+ return newX;
+ });
+ },
+ [onEdgesChange, setNodes]
+ );
- const onConnect = useCallback(
- (params: Connection) => {
- takeSnapshot();
- setEdges((eds) =>
- addEdge({ ...params, className: "animate-pulse" }, eds)
- );
- setNodes((x) => {
- let newX = _.cloneDeep(x);
- return newX;
- });
- },
- [setEdges, setNodes, takeSnapshot]
- );
+ const onConnect = useCallback(
+ (params: Connection) => {
+ takeSnapshot();
+ setEdges((eds) =>
+ addEdge({ ...params, className: "animate-pulse" }, eds)
+ );
+ setNodes((x) => {
+ let newX = _.cloneDeep(x);
+ return newX;
+ });
+ },
+ [setEdges, setNodes, takeSnapshot]
+ );
- const onNodeDragStart: NodeDragHandler = useCallback(() => {
- // 👇 make dragging a node undoable
- takeSnapshot();
- // 👉 you can place your event handlers here
- }, [takeSnapshot]);
+ const onNodeDragStart: NodeDragHandler = useCallback(() => {
+ // 👇 make dragging a node undoable
+ takeSnapshot();
+ // 👉 you can place your event handlers here
+ }, [takeSnapshot]);
- const onSelectionDragStart: SelectionDragHandler = useCallback(() => {
- // 👇 make dragging a selection undoable
- takeSnapshot();
- }, [takeSnapshot]);
+ const onSelectionDragStart: SelectionDragHandler = useCallback(() => {
+ // 👇 make dragging a selection undoable
+ takeSnapshot();
+ }, [takeSnapshot]);
- const onEdgesDelete: OnEdgesDelete = useCallback(() => {
- // 👇 make deleting edges undoable
- takeSnapshot();
- }, [takeSnapshot]);
+ const onEdgesDelete: OnEdgesDelete = useCallback(() => {
+ // 👇 make deleting edges undoable
+ takeSnapshot();
+ }, [takeSnapshot]);
- const onDragOver = useCallback((event: React.DragEvent) => {
- event.preventDefault();
- event.dataTransfer.dropEffect = "move";
- }, []);
+ const onDragOver = useCallback((event: React.DragEvent) => {
+ event.preventDefault();
+ event.dataTransfer.dropEffect = "move";
+ }, []);
- const onDrop = useCallback(
- (event: React.DragEvent) => {
- event.preventDefault();
- takeSnapshot();
+ const onDrop = useCallback(
+ (event: React.DragEvent) => {
+ event.preventDefault();
+ takeSnapshot();
- // Get the current bounds of the ReactFlow wrapper element
- const reactflowBounds = reactFlowWrapper.current.getBoundingClientRect();
+ // Get the current bounds of the ReactFlow wrapper element
+ const reactflowBounds = reactFlowWrapper.current.getBoundingClientRect();
- // Extract the data from the drag event and parse it as a JSON object
- let data: { type: string; node?: APIClassType } = JSON.parse(
- event.dataTransfer.getData("json")
- );
+ // Extract the data from the drag event and parse it as a JSON object
+ let data: { type: string; node?: APIClassType } = JSON.parse(
+ event.dataTransfer.getData("json")
+ );
- // If data type is not "chatInput" or if there are no "chatInputNode" nodes present in the ReactFlow instance, create a new node
- if (
- data.type !== "chatInput" ||
- (data.type === "chatInput" &&
- !reactFlowInstance.getNodes().some((n) => n.type === "chatInputNode"))
- ) {
- // Calculate the position where the node should be created
- const position = reactFlowInstance.project({
- x: event.clientX - reactflowBounds.left,
- y: event.clientY - reactflowBounds.top,
- });
+ // If data type is not "chatInput" or if there are no "chatInputNode" nodes present in the ReactFlow instance, create a new node
+ if (
+ data.type !== "chatInput" ||
+ (data.type === "chatInput" &&
+ !reactFlowInstance.getNodes().some((n) => n.type === "chatInputNode"))
+ ) {
+ // Calculate the position where the node should be created
+ const position = reactFlowInstance.project({
+ x: event.clientX - reactflowBounds.left,
+ y: event.clientY - reactflowBounds.top,
+ });
- // Generate a unique node ID
- let newId = getId();
+ // Generate a unique node ID
+ let newId = getId();
- // Create a new node object
- const newNode: NodeType = {
- id: newId,
- type: "genericNode",
- position,
- data: {
- ...data,
- id: newId,
- value: null,
- },
- };
+ // Create a new node object
+ const newNode: NodeType = {
+ id: newId,
+ type: "genericNode",
+ position,
+ data: {
+ ...data,
+ id: newId,
+ value: null,
+ },
+ };
- // Add the new node to the list of nodes in state
- setNodes((nds) => nds.concat(newNode));
- } else {
- // If a chat input node already exists, set an error message
- setErrorData({
- title: "Error creating node",
- list: ["There can't be more than one chat input."],
- });
- }
- },
- // Specify dependencies for useCallback
- [incrementNodeId, reactFlowInstance, setErrorData, setNodes, takeSnapshot]
- );
+ // Add the new node to the list of nodes in state
+ setNodes((nds) => nds.concat(newNode));
+ } else {
+ // If a chat input node already exists, set an error message
+ setErrorData({
+ title: "Error creating node",
+ list: ["There can't be more than one chat input."],
+ });
+ }
+ },
+ // Specify dependencies for useCallback
+ [incrementNodeId, reactFlowInstance, setErrorData, setNodes, takeSnapshot]
+ );
- const onDelete = useCallback((mynodes) => {
- takeSnapshot();
- setEdges(
- edges.filter(
- (ns) => !mynodes.some((n) => ns.source === n.id || ns.target === n.id)
- )
- );
- }, [takeSnapshot, edges, setEdges]);
+ const onDelete = useCallback((mynodes) => {
+ takeSnapshot();
+ setEdges(
+ edges.filter(
+ (ns) => !mynodes.some((n) => ns.source === n.id || ns.target === n.id)
+ )
+ );
+ }, [takeSnapshot, edges, setEdges]);
- const onEdgeUpdateStart = useCallback(() => {
- edgeUpdateSuccessful.current = false;
- }, []);
+ const onEdgeUpdateStart = useCallback(() => {
+ edgeUpdateSuccessful.current = false;
+ }, []);
- const onEdgeUpdate = useCallback(
- (oldEdge: Edge, newConnection: Connection) => {
- if (isValidConnection(newConnection, reactFlowInstance)) {
- edgeUpdateSuccessful.current = true;
- setEdges((els) => updateEdge(oldEdge, newConnection, els));
- }
- },
- []
- );
+ const onEdgeUpdate = useCallback(
+ (oldEdge: Edge, newConnection: Connection) => {
+ if (isValidConnection(newConnection, reactFlowInstance)) {
+ edgeUpdateSuccessful.current = true;
+ setEdges((els) => updateEdge(oldEdge, newConnection, els));
+ }
+ },
+ []
+ );
const onEdgeUpdateEnd = useCallback((_, edge) => {
if (!edgeUpdateSuccessful.current) {
- setEdges((eds) => eds.filter((e) => e.id !== edge.id));
+ setEdges((eds) => eds.filter((e) => e.id !== edge.id));
}
-
+
edgeUpdateSuccessful.current = true;
- }, []);
-
+ }, []);
+
return (
{Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
@@ -307,7 +307,7 @@ export default function FlowPage({ flow }:{flow:FlowType}) {
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChangeMod}
- onKeyDown={(e) => onKeyDown(e)}
+ onKeyDown={(e) => onKeyDown(e)}
onConnect={onConnect}
onLoad={setReactFlowInstance}
onInit={setReactFlowInstance}
@@ -315,16 +315,16 @@ export default function FlowPage({ flow }:{flow:FlowType}) {
onEdgeUpdate={onEdgeUpdate}
onEdgeUpdateStart={onEdgeUpdateStart}
onEdgeUpdateEnd={onEdgeUpdateEnd}
- onNodeDragStart={onNodeDragStart}
- onSelectionDragStart={onSelectionDragStart}
- onEdgesDelete={onEdgesDelete}
+ onNodeDragStart={onNodeDragStart}
+ onSelectionDragStart={onSelectionDragStart}
+ onEdgesDelete={onEdgesDelete}
connectionLineComponent={ConnectionLineComponent}
onDragOver={onDragOver}
onDrop={onDrop}
onNodesDelete={onDelete}
- selectNodesOnDrag={false}
+ selectNodesOnDrag={false}
>
-
+
diff --git a/src/frontend/src/reportWebVitals.ts b/src/frontend/src/reportWebVitals.ts
index 5fa3583b7..e48d8f3ca 100644
--- a/src/frontend/src/reportWebVitals.ts
+++ b/src/frontend/src/reportWebVitals.ts
@@ -1,15 +1,15 @@
import { ReportHandler } from "web-vitals";
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
- if (onPerfEntry && onPerfEntry instanceof Function) {
- import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
- getCLS(onPerfEntry);
- getFID(onPerfEntry);
- getFCP(onPerfEntry);
- getLCP(onPerfEntry);
- getTTFB(onPerfEntry);
- });
- }
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
};
export default reportWebVitals;
diff --git a/src/frontend/src/svg.d.ts b/src/frontend/src/svg.d.ts
index 1a3dd3c2a..d071d8e9e 100644
--- a/src/frontend/src/svg.d.ts
+++ b/src/frontend/src/svg.d.ts
@@ -1,4 +1,4 @@
declare module "*.svg" {
- const content: any;
- export default content;
+ const content: any;
+ export default content;
}
diff --git a/src/frontend/src/types/alerts/index.ts b/src/frontend/src/types/alerts/index.ts
index 7033d99eb..91b6444b2 100644
--- a/src/frontend/src/types/alerts/index.ts
+++ b/src/frontend/src/types/alerts/index.ts
@@ -1,29 +1,29 @@
export type ErrorAlertType = {
- title: string;
- list: Array;
- id: string;
- removeAlert: (id: string) => void;
+ title: string;
+ list: Array;
+ id: string;
+ removeAlert: (id: string) => void;
};
export type NoticeAlertType = {
- title: string;
- link: string;
- id: string;
- removeAlert: (id: string) => void;
+ title: string;
+ link: string;
+ id: string;
+ removeAlert: (id: string) => void;
};
export type SuccessAlertType = {
- title: string;
- id: string;
- removeAlert: (id: string) => void;
+ title: string;
+ id: string;
+ removeAlert: (id: string) => void;
};
export type SingleAlertComponentType = {
- dropItem: AlertItemType;
- removeAlert: (index: string) => void;
+ dropItem: AlertItemType;
+ removeAlert: (index: string) => void;
};
export type AlertDropdownType = {};
export type AlertItemType = {
- type: "notice" | "error" | "success";
- title: string;
- link?: string;
- list?: Array;
- id: string;
+ type: "notice" | "error" | "success";
+ title: string;
+ link?: string;
+ list?: Array;
+ id: string;
};
diff --git a/src/frontend/src/types/api/index.ts b/src/frontend/src/types/api/index.ts
index 8d26c4e15..333e3d39a 100644
--- a/src/frontend/src/types/api/index.ts
+++ b/src/frontend/src/types/api/index.ts
@@ -4,37 +4,37 @@ import { Node, Edge, Viewport } from "reactflow";
export type APIObjectType = { kind: APIKindType; [key: string]: APIKindType };
export type APIKindType = { class: APIClassType; [key: string]: APIClassType };
export type APITemplateType = {
- variable: TemplateVariableType;
- [key: string]: TemplateVariableType;
+ variable: TemplateVariableType;
+ [key: string]: TemplateVariableType;
};
export type APIClassType = {
- base_classes: Array;
- description: string;
- template: APITemplateType;
- [key: string]: Array | string | APITemplateType;
+ base_classes: Array;
+ description: string;
+ template: APITemplateType;
+ [key: string]: Array | string | APITemplateType;
};
export type TemplateVariableType = {
- type: string;
- required: boolean;
- placeholder?: string;
- list: boolean;
- show: boolean;
- multiline?: boolean;
- value?: any;
- [key: string]: any;
+ type: string;
+ required: boolean;
+ placeholder?: string;
+ list: boolean;
+ show: boolean;
+ multiline?: boolean;
+ value?: any;
+ [key: string]: any;
};
export type sendAllProps = {
- nodes: Node[];
- edges: Edge[];
- name: string;
- description: string;
- viewport: Viewport;
- message: string;
+ nodes: Node[];
+ edges: Edge[];
+ name: string;
+ description: string;
+ viewport: Viewport;
+ message: string;
- chatHistory: { message: string; isSend: boolean }[];
+ chatHistory: { message: string; isSend: boolean }[];
};
export type errorsTypeAPI = {
- function: { errors: Array };
- imports: { errors: Array };
+ function: { errors: Array };
+ imports: { errors: Array };
};
export type PromptTypeAPI = { input_variables: Array };
diff --git a/src/frontend/src/types/chat/index.ts b/src/frontend/src/types/chat/index.ts
index e4e0c1627..13ca1db67 100644
--- a/src/frontend/src/types/chat/index.ts
+++ b/src/frontend/src/types/chat/index.ts
@@ -3,8 +3,8 @@ import { FlowType } from "../flow";
export type ChatType = { flow: FlowType; reactFlowInstance: ReactFlowInstance };
export type ChatMessageType = {
- message: string;
- isSend: boolean;
- thought?: string;
- files?: Array<{ data: string; type: string; data_type: string }>;
+ message: string;
+ isSend: boolean;
+ thought?: string;
+ files?: Array<{ data: string; type: string; data_type: string }>;
};
diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts
index e8c682724..564ba31d2 100644
--- a/src/frontend/src/types/components/index.ts
+++ b/src/frontend/src/types/components/index.ts
@@ -1,85 +1,85 @@
import { ForwardRefExoticComponent, ReactElement, ReactNode } from "react";
import { NodeDataType } from "../flow/index";
export type InputComponentType = {
- value: string;
- disabled?: boolean;
- onChange: (value: string) => void;
- password: boolean;
+ value: string;
+ disabled?: boolean;
+ onChange: (value: string) => void;
+ password: boolean;
};
export type ToggleComponentType = {
- enabled: boolean;
- setEnabled: (state: boolean) => void;
- disabled: boolean;
+ enabled: boolean;
+ setEnabled: (state: boolean) => void;
+ disabled: boolean;
};
export type DropDownComponentType = {
- value: string;
- options: string[];
- onSelect: (value: string) => void;
+ value: string;
+ options: string[];
+ onSelect: (value: string) => void;
};
export type ParameterComponentType = {
- data: NodeDataType;
- title: string;
- id: string;
- color: string;
- left: boolean;
- type: string;
- required?: boolean;
- name?: string;
- tooltipTitle: string;
+ data: NodeDataType;
+ title: string;
+ id: string;
+ color: string;
+ left: boolean;
+ type: string;
+ required?: boolean;
+ name?: string;
+ tooltipTitle: string;
};
export type InputListComponentType = {
- value: string[];
- onChange: (value: string[]) => void;
- disabled: boolean;
+ value: string[];
+ onChange: (value: string[]) => void;
+ disabled: boolean;
};
export type TextAreaComponentType = {
- disabled: boolean;
- onChange: (value: string[] | string) => void;
- value: string;
+ disabled: boolean;
+ onChange: (value: string[] | string) => void;
+ value: string;
};
export type FileComponentType = {
- disabled: boolean;
- onChange: (value: string[] | string) => void;
- value: string;
- suffixes: Array;
- fileTypes: Array;
- onFileChange: (value: string) => void;
+ disabled: boolean;
+ onChange: (value: string[] | string) => void;
+ value: string;
+ suffixes: Array;
+ fileTypes: Array;
+ onFileChange: (value: string) => void;
};
export type DisclosureComponentType = {
- children: ReactNode;
- button: {
- title: string;
- Icon: ForwardRefExoticComponent>;
- buttons?: {
- Icon: ReactElement;
- title: string;
- onClick: (event?: React.MouseEvent) => void;
- }[];
- };
+ children: ReactNode;
+ button: {
+ title: string;
+ Icon: ForwardRefExoticComponent>;
+ buttons?: {
+ Icon: ReactElement;
+ title: string;
+ onClick: (event?: React.MouseEvent) => void;
+ }[];
+ };
};
export type FloatComponentType = {
- value: string;
- disabled?: boolean;
- onChange: (value: string) => void;
+ value: string;
+ disabled?: boolean;
+ onChange: (value: string) => void;
};
export type TooltipComponentType = {
- children: ReactElement;
- title: string;
- placement?:
- | "bottom-end"
- | "bottom-start"
- | "bottom"
- | "left-end"
- | "left-start"
- | "left"
- | "right-end"
- | "right-start"
- | "right"
- | "top-end"
- | "top-start"
- | "top";
+ children: ReactElement;
+ title: string;
+ placement?:
+ | "bottom-end"
+ | "bottom-start"
+ | "bottom"
+ | "left-end"
+ | "left-start"
+ | "left"
+ | "right-end"
+ | "right-start"
+ | "right"
+ | "top-end"
+ | "top-start"
+ | "top";
};
diff --git a/src/frontend/src/types/entities/index.ts b/src/frontend/src/types/entities/index.ts
index 3c0877579..0a395f64e 100644
--- a/src/frontend/src/types/entities/index.ts
+++ b/src/frontend/src/types/entities/index.ts
@@ -1,8 +1,8 @@
import { HomeIcon } from "@heroicons/react/24/outline";
export type sidebarNavigationItemType = {
- name: string;
- href: string;
- icon: React.ForwardRefExoticComponent>;
- current: boolean;
+ name: string;
+ href: string;
+ icon: React.ForwardRefExoticComponent>;
+ current: boolean;
};
diff --git a/src/frontend/src/types/flow/index.ts b/src/frontend/src/types/flow/index.ts
index 6c118aa49..e4c43a2aa 100644
--- a/src/frontend/src/types/flow/index.ts
+++ b/src/frontend/src/types/flow/index.ts
@@ -3,20 +3,20 @@ import { APIClassType } from "../api/index";
import { ReactFlowJsonObject, XYPosition } from "reactflow";
export type FlowType = {
- name: string;
- id: string;
- data: ReactFlowJsonObject;
- description: string;
+ name: string;
+ id: string;
+ data: ReactFlowJsonObject;
+ description: string;
};
export type NodeType = {
- id: string;
- type?: string;
- position: XYPosition;
- data: NodeDataType;
+ id: string;
+ type?: string;
+ position: XYPosition;
+ data: NodeDataType;
};
export type NodeDataType = {
- type: string;
- node?: APIClassType;
- id: string;
- value: any;
+ type: string;
+ node?: APIClassType;
+ id: string;
+ value: any;
};
diff --git a/src/frontend/src/types/tabs/index.ts b/src/frontend/src/types/tabs/index.ts
index 7297b06ec..6cf3d2cd1 100644
--- a/src/frontend/src/types/tabs/index.ts
+++ b/src/frontend/src/types/tabs/index.ts
@@ -1,17 +1,22 @@
import { FlowType } from "../flow";
export type TabsContextType = {
- save: () => void;
- tabIndex: number;
- setTabIndex: (index: number) => void;
- flows: Array;
- removeFlow: (id: string) => void;
- addFlow: (flowData?: FlowType) => void;
- updateFlow: (newFlow: FlowType) => void;
- incrementNodeId: () => number;
- downloadFlow: (flow: FlowType) => void;
- uploadFlow: () => void;
- hardReset: () => void;
+ save: () => void;
+ tabIndex: number;
+ setTabIndex: (index: number) => void;
+ flows: Array;
+ removeFlow: (id: string) => void;
+ addFlow: (flowData?: FlowType) => void;
+ updateFlow: (newFlow: FlowType) => void;
+ incrementNodeId: () => number;
+ downloadFlow: (flow: FlowType) => void;
+ uploadFlow: () => void;
+ hardReset: () => void;
};
-export type LangFlowState={ tabIndex:number, flows:FlowType[], id:string, nodeId:number }
\ No newline at end of file
+export type LangFlowState = {
+ tabIndex: number;
+ flows: FlowType[];
+ id: string;
+ nodeId: number;
+};
diff --git a/src/frontend/src/types/templatesContext/index.ts b/src/frontend/src/types/templatesContext/index.ts
index 88e2dd07c..7e2f82890 100644
--- a/src/frontend/src/types/templatesContext/index.ts
+++ b/src/frontend/src/types/templatesContext/index.ts
@@ -1,7 +1,6 @@
-
-const template:{[char: string]: string}={}
+const template: { [char: string]: string } = {};
export type TemplateContextType = {
templates: typeof template;
setTemplates: (newState: {}) => void;
-};
\ No newline at end of file
+};
diff --git a/src/frontend/src/types/typesContext/index.ts b/src/frontend/src/types/typesContext/index.ts
index 0868bfa59..6754e605c 100644
--- a/src/frontend/src/types/typesContext/index.ts
+++ b/src/frontend/src/types/typesContext/index.ts
@@ -1,12 +1,11 @@
import { ReactFlowInstance } from "reactflow";
-const types:{[char: string]: string}={};
-const template:{[char: string]: string}={}
-const data:{[char: string]: string}={}
-
+const types: { [char: string]: string } = {};
+const template: { [char: string]: string } = {};
+const data: { [char: string]: string } = {};
export type typesContextType = {
- reactFlowInstance: ReactFlowInstance|null;
+ reactFlowInstance: ReactFlowInstance | null;
setReactFlowInstance: any;
deleteNode: (idx: string) => void;
types: typeof types;
diff --git a/src/frontend/src/utils.ts b/src/frontend/src/utils.ts
index 4ac16ce07..65579cdfe 100644
--- a/src/frontend/src/utils.ts
+++ b/src/frontend/src/utils.ts
@@ -317,24 +317,25 @@ export function toFirstUpperCase(str: string) {
}
export function toNormalCase(str: string) {
- let result = str
- .split("_")
- .map((word, index) => {
- if (index === 0) {
- return word[0].toUpperCase() + word.slice(1).toLowerCase();
- }
- return word.toLowerCase();
- })
- .join(" ");
+ let result = str
+ .split("_")
+ .map((word, index) => {
+ if (index === 0) {
+ return word[0].toUpperCase() + word.slice(1).toLowerCase();
+ }
+ return word.toLowerCase();
+ })
+ .join(" ");
- return result.split("-")
- .map((word, index) => {
- if (index === 0) {
- return word[0].toUpperCase() + word.slice(1).toLowerCase();
- }
- return word.toLowerCase();
- })
- .join(" ");
+ return result
+ .split("-")
+ .map((word, index) => {
+ if (index === 0) {
+ return word[0].toUpperCase() + word.slice(1).toLowerCase();
+ }
+ return word.toLowerCase();
+ })
+ .join(" ");
}
export function normalCaseToSnakeCase(str: string) {
@@ -397,15 +398,15 @@ export function isValidConnection(
}
export function removeApiKeys(flow: FlowType): FlowType {
- let cleanFLow = _.cloneDeep(flow);
- cleanFLow.data.nodes.forEach((node) => {
- for (const key in node.data.node.template) {
- if (key.includes("api")) {
- node.data.node.template[key].value = "";
- }
- }
- });
- return cleanFLow;
+ let cleanFLow = _.cloneDeep(flow);
+ cleanFLow.data.nodes.forEach((node) => {
+ for (const key in node.data.node.template) {
+ if (key.includes("api")) {
+ node.data.node.template[key].value = "";
+ }
+ }
+ });
+ return cleanFLow;
}
export function updateObject>(
@@ -443,7 +444,7 @@ export function updateTemplate(
reference: APITemplateType,
objectToUpdate: APITemplateType
): APITemplateType {
- let clonedObject:APITemplateType = _.cloneDeep(reference);
+ let clonedObject: APITemplateType = _.cloneDeep(reference);
// Loop through each key in the reference object
for (const key in clonedObject) {
@@ -454,3 +455,34 @@ export function updateTemplate(
}
return clonedObject;
}
+
+interface languageMap {
+ [key: string]: string | undefined;
+}
+
+export const programmingLanguages: languageMap = {
+ javascript: ".js",
+ python: ".py",
+ java: ".java",
+ c: ".c",
+ cpp: ".cpp",
+ "c++": ".cpp",
+ "c#": ".cs",
+ ruby: ".rb",
+ php: ".php",
+ swift: ".swift",
+ "objective-c": ".m",
+ kotlin: ".kt",
+ typescript: ".ts",
+ go: ".go",
+ perl: ".pl",
+ rust: ".rs",
+ scala: ".scala",
+ haskell: ".hs",
+ lua: ".lua",
+ shell: ".sh",
+ sql: ".sql",
+ html: ".html",
+ css: ".css",
+ // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
+};
diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js
index c679a87bc..84571cb5f 100644
--- a/src/frontend/tailwind.config.js
+++ b/src/frontend/tailwind.config.js
@@ -73,6 +73,6 @@ module.exports = {
}
}
})
- }),require('@tailwindcss/line-clamp')
+ }),require('@tailwindcss/line-clamp'),require('@tailwindcss/typography'),
],
};
diff --git a/tests/test_graph.py b/tests/test_graph.py
index 73c05099f..a0f5945fc 100644
--- a/tests/test_graph.py
+++ b/tests/test_graph.py
@@ -14,7 +14,7 @@ from langflow.graph.nodes import (
ToolNode,
WrapperNode,
)
-from langflow.interface.run import get_result_and_steps
+from langflow.interface.run import get_result_and_thought
from langflow.utils.payload import get_root_node
# Test cases for the graph module
@@ -335,7 +335,7 @@ def test_get_result_and_thought(basic_graph):
# now build again and check if FakeListLLM was used
# Get the result and thought
- result, thought = get_result_and_steps(langchain_object, message)
+ result, thought = get_result_and_thought(langchain_object, message)
# The result should be a str
assert isinstance(result, str)
# The thought should be a Thought