From 9228005a7e3de5ae188b5cf2b8764cdf7ba2684f Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 12 Feb 2023 16:25:01 +0000 Subject: [PATCH 01/16] chunked embedding --- scripts/parser/open_ai_func.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/scripts/parser/open_ai_func.py b/scripts/parser/open_ai_func.py index 500e4888..00c57be9 100644 --- a/scripts/parser/open_ai_func.py +++ b/scripts/parser/open_ai_func.py @@ -14,12 +14,30 @@ def num_tokens_from_string(string: str, encoding_name: str) -> int: def call_openai_api(docs): # Function to create a vector store from the documents and save it to disk. - store = FAISS.from_documents(docs, OpenAIEmbeddings()) - faiss.write_index(store.index, "docs.index") - store.index = None + from tqdm import tqdm + docs_test = [docs[0]] + # remove the first element from docs + docs.pop(0) + # cut first n docs if you want to restart + #docs = docs[:n] + c1 = 0 + store = FAISS.from_documents(docs_test, OpenAIEmbeddings()) + for i in tqdm(docs, desc="Embedding ๐Ÿฆ–", unit="docs", total=len(docs), bar_format='{l_bar}{bar}| Time Left: {remaining}'): + try: + import time + store.add_texts([i.page_content], metadatas=[i.metadata]) + except Exception as e: + print(e) + print("Error on ", i) + print("Saving progress") + print(f"stopped at {c1} out of {len(docs)}") + store.save_local("outputs") + print("Sleeping for 10 seconds and trying again") + time.sleep(10) + store.add_texts([i.page_content], metadatas=[i.metadata]) + c1 += 1 - with open("faiss_store.pkl", "wb") as f: - pickle.dump(store, f) + store.save_local("outputs") def get_user_permission(docs): # Function to ask user permission to call the OpenAI api and spend their OpenAI funds. From 205be538a33cc43fcf101a969743cd12ec190d99 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 12 Feb 2023 17:58:54 +0000 Subject: [PATCH 02/16] fix dbqa, with new chain type, also fix for doc export --- application/app.py | 19 +++++++++++++++---- scripts/parser/open_ai_func.py | 11 +++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/application/app.py b/application/app.py index aa9089ed..c114c63b 100644 --- a/application/app.py +++ b/application/app.py @@ -5,8 +5,8 @@ import datetime from flask import Flask, request, render_template # os.environ["LANGCHAIN_HANDLER"] = "langchain" import faiss -from langchain import OpenAI -from langchain.chains import VectorDBQAWithSourcesChain +from langchain import OpenAI, VectorDBQA +from langchain.chains.question_answering import load_qa_chain from langchain.prompts import PromptTemplate import requests @@ -69,11 +69,22 @@ def api_answer(): c_prompt = PromptTemplate(input_variables=["summaries", "question"], template=template) # create a chain with the prompt template and the store - chain = VectorDBQAWithSourcesChain.from_llm(llm=OpenAI(openai_api_key=api_key, temperature=0), vectorstore=store, combine_prompt=c_prompt) + #chain = VectorDBQA.from_llm(llm=OpenAI(openai_api_key=api_key, temperature=0), vectorstore=store, combine_prompt=c_prompt) + # chain = VectorDBQA.from_chain_type(llm=OpenAI(openai_api_key=api_key, temperature=0), chain_type='map_reduce', + # vectorstore=store) + + qa_chain = load_qa_chain(OpenAI(openai_api_key=api_key, temperature=0), chain_type="map_reduce", + combine_prompt=c_prompt) + chain = VectorDBQA(combine_documents_chain=qa_chain, vectorstore=store) + + + # fetch the answer - result = chain({"question": question}) + result = chain({"query": question}) + print(result) # some formatting for the frontend + result['answer'] = result['result'] result['answer'] = result['answer'].replace("\\n", "
") result['answer'] = result['answer'].replace("SOURCES:", "") # mock result diff --git a/scripts/parser/open_ai_func.py b/scripts/parser/open_ai_func.py index 00c57be9..cbd947ee 100644 --- a/scripts/parser/open_ai_func.py +++ b/scripts/parser/open_ai_func.py @@ -31,13 +31,20 @@ def call_openai_api(docs): print("Error on ", i) print("Saving progress") print(f"stopped at {c1} out of {len(docs)}") - store.save_local("outputs") + faiss.write_index(store.index, "docs.index") + store.index = None + with open("faiss_store.pkl", "wb") as f: + pickle.dump(store, f) print("Sleeping for 10 seconds and trying again") time.sleep(10) store.add_texts([i.page_content], metadatas=[i.metadata]) c1 += 1 - store.save_local("outputs") + + faiss.write_index(store.index, "docs.index") + store.index = None + with open("faiss_store.pkl", "wb") as f: + pickle.dump(store, f) def get_user_permission(docs): # Function to ask user permission to call the OpenAI api and spend their OpenAI funds. From b1a6ebffba593ae772344381b87ca173fe11e83a Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 12 Feb 2023 22:29:40 +0400 Subject: [PATCH 03/16] Directives + Interpreted Some additional filters for rst parsing --- scripts/parser/file/rst_parser.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/parser/file/rst_parser.py b/scripts/parser/file/rst_parser.py index 0b887d4e..7c97b326 100644 --- a/scripts/parser/file/rst_parser.py +++ b/scripts/parser/file/rst_parser.py @@ -24,6 +24,8 @@ class RstParser(BaseParser): remove_hyperlinks: bool = True, remove_images: bool = True, remove_table_excess: bool = True, + remove_interpreters: bool = True, + remove_directives: bool = True, remove_whitespaces_excess: bool = True, #Be carefull with remove_characters_excess, might cause data loss remove_characters_excess: bool = True, @@ -34,6 +36,8 @@ class RstParser(BaseParser): self._remove_hyperlinks = remove_hyperlinks self._remove_images = remove_images self._remove_table_excess = remove_table_excess + self._remove_interpreters = remove_interpreters + self._remove_directives = remove_directives self._remove_whitespaces_excess = remove_whitespaces_excess self._remove_characters_excess = remove_characters_excess @@ -95,6 +99,18 @@ class RstParser(BaseParser): content = re.sub(pattern, r"\1", content) return content + def remove_directives(self, content: str) -> str: + """Removes reStructuredText Directives""" + pattern = r"`\.\.([^:]+)::" + content = re.sub(pattern, "", content) + return content + + def remove_interpreters(self, content: str) -> str: + """Removes reStructuredText Interpreted Text Roles""" + pattern = r":(\w+):" + content = re.sub(pattern, "", content) + return content + def remove_table_excess(self, content: str) -> str: """Pattern to remove grid table separators""" pattern = r"^\+[-]+\+[-]+\+$" @@ -129,6 +145,10 @@ class RstParser(BaseParser): content = self.remove_images(content) if self._remove_table_excess: content = self.remove_table_excess(content) + if self._remove_directives: + content = self.remove_directives(content) + if self._remove_interpreters: + content = self.remove_interpreters(content) rst_tups = self.rst_to_tups(content) if self._remove_whitespaces_excess: rst_tups = self.remove_whitespaces_excess(rst_tups) From 3ab02ca9596111cc72bd440529b8150c5f811774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E4=B8=8D=E6=B8=B8?= <71683364+mefengl@users.noreply.github.com> Date: Mon, 13 Feb 2023 11:00:34 +0800 Subject: [PATCH 04/16] feat: compatible with markdown --- .gitignore | 1 + scripts/ingest_rst_sphinx.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/.gitignore b/.gitignore index 8b394e9b..0003c21c 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,4 @@ frontend/*.sw? application/vectors/ +**/inputs diff --git a/scripts/ingest_rst_sphinx.py b/scripts/ingest_rst_sphinx.py index 9d6c8ece..ecc71570 100644 --- a/scripts/ingest_rst_sphinx.py +++ b/scripts/ingest_rst_sphinx.py @@ -29,6 +29,18 @@ def convert_rst_to_txt(src_dir, dst_dir): f"-D source_suffix=.rst " \ f"-C {dst_dir} " sphinx_main(args.split()) + elif file.endswith(".md"): + # Rename the .md file to .rst file + src_file = os.path.join(root, file) + dst_file = os.path.join(root, file.replace(".md", ".rst")) + os.rename(src_file, dst_file) + # Convert the .rst file to .txt file using sphinx-build + args = f". -b text -D extensions=sphinx.ext.autodoc " \ + f"-D master_doc={dst_file} " \ + f"-D source_suffix=.rst " \ + f"-C {dst_dir} " + sphinx_main(args.split()) + def num_tokens_from_string(string: str, encoding_name: str) -> int: # Function to convert string to tokens and estimate user cost. From d5e5a5f59bbcd54b52fc582a4492e569f8b2a7ec Mon Sep 17 00:00:00 2001 From: Carson Yang Date: Mon, 13 Feb 2023 19:20:15 +0800 Subject: [PATCH 05/16] Add Docker Image CI support Signed-off-by: Carson Yang --- .github/workflows/ci.yml | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..325e0f64 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: Build and push DocsGPT Docker image + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + branches: [ main ] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to ghcr.io + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GHCR_TOKEN }} + + # Runs a single command using the runners shell + - name: Build and push Docker images to docker.io and ghcr.io + uses: docker/build-push-action@v2 + with: + file: './application/Dockerfile' + platforms: linux/amd64 + context: ./application + push: true + tags: | + ${{ secrets.DOCKER_USERNAME }}/docsgpt:latest + ghcr.io/${{ github.repository_owner }}/docsgpt:latest From 458f2a3ff3a9edaa78290f2e1ed0f5237f787fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E4=B8=8D=E6=B8=B8?= <71683364+mefengl@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:05:16 +0800 Subject: [PATCH 06/16] fix: restore index back when continue process --- scripts/parser/open_ai_func.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/parser/open_ai_func.py b/scripts/parser/open_ai_func.py index cbd947ee..433e5bcd 100644 --- a/scripts/parser/open_ai_func.py +++ b/scripts/parser/open_ai_func.py @@ -32,11 +32,14 @@ def call_openai_api(docs): print("Saving progress") print(f"stopped at {c1} out of {len(docs)}") faiss.write_index(store.index, "docs.index") + store_index_bak = store.index store.index = None with open("faiss_store.pkl", "wb") as f: pickle.dump(store, f) print("Sleeping for 10 seconds and trying again") time.sleep(10) + faiss.write_index(store_index_bak, "docs.index") + store.index = store_index_bak store.add_texts([i.page_content], metadatas=[i.metadata]) c1 += 1 @@ -66,4 +69,4 @@ def get_user_permission(docs): elif user_input == "": call_openai_api(docs) else: - print("The API was not called. No money was spent.") \ No newline at end of file + print("The API was not called. No money was spent.") From 636783ca8a5843b3dfb3e399e14ff3634efb4962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E4=B8=8D=E6=B8=B8?= <71683364+mefengl@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:29:17 +0800 Subject: [PATCH 07/16] fix: avoid second error issue --- scripts/parser/open_ai_func.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/parser/open_ai_func.py b/scripts/parser/open_ai_func.py index 433e5bcd..70091324 100644 --- a/scripts/parser/open_ai_func.py +++ b/scripts/parser/open_ai_func.py @@ -36,8 +36,8 @@ def call_openai_api(docs): store.index = None with open("faiss_store.pkl", "wb") as f: pickle.dump(store, f) - print("Sleeping for 10 seconds and trying again") - time.sleep(10) + print("Sleeping for 60 seconds and trying again") + time.sleep(60) faiss.write_index(store_index_bak, "docs.index") store.index = store_index_bak store.add_texts([i.page_content], metadatas=[i.metadata]) From 0b42279709a67101ce58bcf782b41fbc61c7278b Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 14 Feb 2023 14:32:32 +0000 Subject: [PATCH 08/16] Update ci.yml --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 325e0f64..92cc718b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,8 +5,6 @@ on: push: branches: - main - pull_request: - branches: [ main ] jobs: deploy: From c67956da3794e527d6f997a525c959de298850fd Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 14 Feb 2023 14:55:41 +0000 Subject: [PATCH 09/16] Create CONTRIBUTING.md --- CONTRIBUTING.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0c10d0b4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# Welcome to DocsGPT Contributing guideline + +Thank you for choosing this project to contribute to, we are all very grateful! + +# We accept different types of contributions + +๐Ÿ“ฃ Discussions - where you can start a new topic or answer some questions + +๐Ÿž Issues - Is how we track tasks, sometimes its bugs that need fixing, sometimes its new features + +๐Ÿ› ๏ธ Pull requests - Is how you can suggest changes to our repository, to work on existing issue or to add new features + +๐Ÿ“š Wiki - where we have our documentation + + +## ๐Ÿž Issues and Pull requests + +We value contributions to our issues in form of discussion or suggestion, we recommend that you check out existing issues and our [Roadmap](https://github.com/orgs/arc53/projects/2) + +If you want to contribute by writing code there are few things that you should know before doing it: +We have frontend (React, Vite) and Backend (python) + +### If you are looking to contribute to Frontend (โš›๏ธReact, Vite): +Current frontend is being migrated from /application to /frontend with a new design, so please contribute to the new on. Check out this [Milestone](https://github.com/arc53/DocsGPT/milestone/1) and its issues also [Figma](https://www.figma.com/file/OXLtrl1EAy885to6S69554/DocsGPT?node-id=0%3A1&t=hjWVuxRg9yi5YkJ9-1) +Please try to follow guidelines + + +### If you are looking to contribute to Backend (๐ŸPython): +Check out our issues, and contribute to /application or /scripts (ignore old ingest_rst.py ingest_rst_sphinx.py files, they will be deprecated soon) +Currently we don't have any tests(which would be useful๐Ÿ˜‰) but before submitting you PR make sure that after you ingested some test data its queryable + +### Workflow: +Create a fork, make changes on your forked repository, submit changes in a form of pull request + +## Questions / collaboration +Please join our [Discord](https://discord.gg/n5BX8dh8rU) don't hesitate, we are very friendly and welcoming to new contributors. + +# Thank you so much for considering to contribute to DocsGPT!๐Ÿ™ From 484764eac1695ada8cbf754ce1ba406cc9b2b815 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 14 Feb 2023 14:56:25 +0000 Subject: [PATCH 10/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b81171e..ccd14305 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Copy .env_sample and create .env with your openai api token ## [Guides](https://github.com/arc53/docsgpt/wiki) - +## [Interested in contributing?](https://github.com/arc53/DocsGPT/blob/main/CONTRIBUTING.md) ## [How to use any other documentation](https://github.com/arc53/docsgpt/wiki/How-to-train-on-other-documentation) From af20c7298aa04a6b64e70347884795abb20a5ad6 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 14 Feb 2023 19:37:07 +0400 Subject: [PATCH 11/16] new-ingest Ingest with a CLI --- scripts/ingest.py | 65 ++++++++++++++++++-------- scripts/{ => old}/ingest_rst.py | 0 scripts/{ => old}/ingest_rst_sphinx.py | 0 3 files changed, 46 insertions(+), 19 deletions(-) rename scripts/{ => old}/ingest_rst.py (100%) rename scripts/{ => old}/ingest_rst_sphinx.py (100%) diff --git a/scripts/ingest.py b/scripts/ingest.py index cebb6c33..3082cf4e 100644 --- a/scripts/ingest.py +++ b/scripts/ingest.py @@ -1,6 +1,9 @@ import sys import nltk import dotenv +import typer + +from typing import List, Optional from langchain.text_splitter import RecursiveCharacterTextSplitter @@ -10,28 +13,52 @@ from parser.open_ai_func import call_openai_api, get_user_permission dotenv.load_dotenv() -#Specify your folder HERE -directory_to_ingest = 'inputs' +app = typer.Typer(add_completion=False) -nltk.download('punkt') -nltk.download('averaged_perceptron_tagger') +nltk.download('punkt', quiet=True) +nltk.download('averaged_perceptron_tagger', quiet=True) #Splits all files in specified folder to documents -raw_docs = SimpleDirectoryReader(input_dir=directory_to_ingest).load_data() -raw_docs = [Document.to_langchain_format(raw_doc) for raw_doc in raw_docs] -# Here we split the documents, as needed, into smaller chunks. -# We do this due to the context limits of the LLMs. -text_splitter = RecursiveCharacterTextSplitter() -docs = text_splitter.split_documents(raw_docs) +@app.command() +def ingest(directory: Optional[str] = typer.Option("inputs", + help="Path to the directory for index creation."), + files: Optional[List[str]] = typer.Option(None, + help="""File paths to use (Optional; overrides directory). + E.g. --files inputs/1.md --files inputs/2.md"""), + recursive: Optional[bool] = typer.Option(True, + help="Whether to recursively search in subdirectories."), + limit: Optional[int] = typer.Option(None, + help="Maximum number of files to read."), + formats: Optional[List[str]] = typer.Option([".rst", ".md"], + help="""List of required extensions (list with .) + Currently supported: .rst, .md, .pdf, .docx, .csv, .epub"""), + exclude: Optional[bool] = typer.Option(True, help="Whether to exclude hidden files (dotfiles).")): -# Here we check for command line arguments for bot calls. -# If no argument exists or the permission_bypass_flag argument is not '-y', -# user permission is requested to call the API. -if len(sys.argv) > 1: - permission_bypass_flag = sys.argv[1] - if permission_bypass_flag == '-y': - call_openai_api(docs) + """ + Creates index from specified location or files. + By default /inputs folder is used, .rst and .md are parsed. + """ + raw_docs = SimpleDirectoryReader(input_dir=directory, input_files=files, recursive=recursive, + required_exts=formats, num_files_limit=limit, + exclude_hidden=exclude).load_data() + raw_docs = [Document.to_langchain_format(raw_doc) for raw_doc in raw_docs] + print(raw_docs) + # Here we split the documents, as needed, into smaller chunks. + # We do this due to the context limits of the LLMs. + text_splitter = RecursiveCharacterTextSplitter() + docs = text_splitter.split_documents(raw_docs) + + # Here we check for command line arguments for bot calls. + # If no argument exists or the permission_bypass_flag argument is not '-y', + # user permission is requested to call the API. + if len(sys.argv) > 1: + permission_bypass_flag = sys.argv[1] + if permission_bypass_flag == '-y': + call_openai_api(docs) + else: + get_user_permission(docs) else: get_user_permission(docs) -else: - get_user_permission(docs) \ No newline at end of file + +if __name__ == "__main__": + app() diff --git a/scripts/ingest_rst.py b/scripts/old/ingest_rst.py similarity index 100% rename from scripts/ingest_rst.py rename to scripts/old/ingest_rst.py diff --git a/scripts/ingest_rst_sphinx.py b/scripts/old/ingest_rst_sphinx.py similarity index 100% rename from scripts/ingest_rst_sphinx.py rename to scripts/old/ingest_rst_sphinx.py From 7af703451918234623c30d7bf62df5957397b49e Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 14 Feb 2023 19:41:37 +0400 Subject: [PATCH 12/16] requirements --- application/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/application/requirements.txt b/application/requirements.txt index 9e8f73b1..7972f8c3 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -60,6 +60,7 @@ tiktoken==0.1.2 tokenizers==0.13.2 tqdm==4.64.1 transformers==4.26.0 +typer==0.7.0 typing-inspect==0.8.0 typing_extensions==4.4.0 urllib3==1.26.14 From cbe924235593dcabb573458d223da652c237eee5 Mon Sep 17 00:00:00 2001 From: TaylorS15 Date: Tue, 14 Feb 2023 21:39:53 -0500 Subject: [PATCH 13/16] installed redux --- frontend/package-lock.json | 270 ++++++++++++++++++++++++++++++++++--- frontend/package.json | 2 + 2 files changed, 252 insertions(+), 20 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c86fdb06..f63a726f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,8 +8,10 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "@reduxjs/toolkit": "^1.9.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^8.0.5", "react-router-dom": "^6.8.1" }, "devDependencies": { @@ -343,6 +345,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", @@ -897,6 +910,29 @@ "node": ">= 8" } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.2.tgz", + "integrity": "sha512-5ZAZ7hwAKWSii5T6NTPmgIBUqyVdlDs+6JjThz6J6dmHLDm6zCzv2OjHIFAi3Vvs1qjmXU0bm6eBojukYXjVMQ==", + "dependencies": { + "immer": "^9.0.16", + "redux": "^4.2.0", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.7" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", @@ -905,6 +941,15 @@ "node": ">=14" } }, + "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", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -920,14 +965,12 @@ "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/react": { "version": "18.0.27", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -938,7 +981,7 @@ "version": "18.0.10", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } @@ -946,8 +989,7 @@ "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "node_modules/@types/semver": { "version": "7.3.13", @@ -955,6 +997,11 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.51.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", @@ -1856,8 +1903,7 @@ "node_modules/csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/debug": { "version": "4.3.4", @@ -3224,6 +3270,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/human-signals": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", @@ -3257,6 +3311,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", + "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4754,8 +4817,50 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-redux/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.14.0", @@ -4817,6 +4922,27 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -4846,6 +4972,11 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/reselect": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -5501,6 +5632,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5956,6 +6095,14 @@ "@babel/helper-plugin-utils": "^7.19.0" } }, + "@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, "@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", @@ -6265,11 +6412,31 @@ "fastq": "^1.6.0" } }, + "@reduxjs/toolkit": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.2.tgz", + "integrity": "sha512-5ZAZ7hwAKWSii5T6NTPmgIBUqyVdlDs+6JjThz6J6dmHLDm6zCzv2OjHIFAi3Vvs1qjmXU0bm6eBojukYXjVMQ==", + "requires": { + "immer": "^9.0.16", + "redux": "^4.2.0", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.7" + } + }, "@remix-run/router": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==" }, + "@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", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -6285,14 +6452,12 @@ "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/react": { "version": "18.0.27", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -6303,7 +6468,7 @@ "version": "18.0.10", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "dev": true, + "devOptional": true, "requires": { "@types/react": "*" } @@ -6311,8 +6476,7 @@ "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "@types/semver": { "version": "7.3.13", @@ -6320,6 +6484,11 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "@typescript-eslint/eslint-plugin": { "version": "5.51.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", @@ -6934,8 +7103,7 @@ "csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "debug": { "version": "4.3.4", @@ -7928,6 +8096,14 @@ "has-symbols": "^1.0.2" } }, + "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", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "human-signals": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", @@ -7946,6 +8122,11 @@ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, + "immer": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", + "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -8920,8 +9101,27 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } }, "react-refresh": { "version": "0.14.0", @@ -8964,6 +9164,25 @@ "picomatch": "^2.2.1" } }, + "redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "requires": {} + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -8981,6 +9200,11 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "reselect": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==" + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -9441,6 +9665,12 @@ "punycode": "^2.1.0" } }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index b00008ff..c63a305d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,8 +19,10 @@ ] }, "dependencies": { + "@reduxjs/toolkit": "^1.9.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^8.0.5", "react-router-dom": "^6.8.1" }, "devDependencies": { From c44e1804bfd6d75342e1d6d4a9ed27714471630d Mon Sep 17 00:00:00 2001 From: TaylorS15 Date: Tue, 14 Feb 2023 21:40:49 -0500 Subject: [PATCH 14/16] changed image folder location --- frontend/src/{components/Navigation => }/imgs/arrow.svg | 0 frontend/src/{components/Navigation => }/imgs/exit.svg | 0 frontend/src/{components/Navigation => }/imgs/hamburger.svg | 0 frontend/src/{components/Navigation => }/imgs/info.svg | 0 frontend/src/{components/Navigation => }/imgs/key.svg | 0 frontend/src/{components/Navigation => }/imgs/link.svg | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename frontend/src/{components/Navigation => }/imgs/arrow.svg (100%) rename frontend/src/{components/Navigation => }/imgs/exit.svg (100%) rename frontend/src/{components/Navigation => }/imgs/hamburger.svg (100%) rename frontend/src/{components/Navigation => }/imgs/info.svg (100%) rename frontend/src/{components/Navigation => }/imgs/key.svg (100%) rename frontend/src/{components/Navigation => }/imgs/link.svg (100%) diff --git a/frontend/src/components/Navigation/imgs/arrow.svg b/frontend/src/imgs/arrow.svg similarity index 100% rename from frontend/src/components/Navigation/imgs/arrow.svg rename to frontend/src/imgs/arrow.svg diff --git a/frontend/src/components/Navigation/imgs/exit.svg b/frontend/src/imgs/exit.svg similarity index 100% rename from frontend/src/components/Navigation/imgs/exit.svg rename to frontend/src/imgs/exit.svg diff --git a/frontend/src/components/Navigation/imgs/hamburger.svg b/frontend/src/imgs/hamburger.svg similarity index 100% rename from frontend/src/components/Navigation/imgs/hamburger.svg rename to frontend/src/imgs/hamburger.svg diff --git a/frontend/src/components/Navigation/imgs/info.svg b/frontend/src/imgs/info.svg similarity index 100% rename from frontend/src/components/Navigation/imgs/info.svg rename to frontend/src/imgs/info.svg diff --git a/frontend/src/components/Navigation/imgs/key.svg b/frontend/src/imgs/key.svg similarity index 100% rename from frontend/src/components/Navigation/imgs/key.svg rename to frontend/src/imgs/key.svg diff --git a/frontend/src/components/Navigation/imgs/link.svg b/frontend/src/imgs/link.svg similarity index 100% rename from frontend/src/components/Navigation/imgs/link.svg rename to frontend/src/imgs/link.svg From 5e5f13b6648435ef33fa4bda985fc61a14b59a7d Mon Sep 17 00:00:00 2001 From: TaylorS15 Date: Tue, 14 Feb 2023 21:43:14 -0500 Subject: [PATCH 15/16] major changes state management now handled with redux responsiveness uses custom hook (hooks.ts) --- frontend/src/App.tsx | 59 ++---------- frontend/src/components/APIKeyModal.tsx | 41 ++++----- frontend/src/components/About.tsx | 19 ++-- .../Conversation.tsx} | 17 ++-- .../{Navigation => }/Navigation.tsx | 91 +++++++------------ .../src/components/Navigation/PastChat.tsx | 1 - frontend/src/hooks.ts | 22 +++++ frontend/src/index.css | 1 + frontend/src/main.tsx | 6 +- frontend/src/store.ts | 48 ++++++++++ 10 files changed, 156 insertions(+), 149 deletions(-) rename frontend/src/components/{DocsGPT/DocsGPT.tsx => Conversation/Conversation.tsx} (51%) rename frontend/src/components/{Navigation => }/Navigation.tsx (68%) delete mode 100644 frontend/src/components/Navigation/PastChat.tsx create mode 100644 frontend/src/hooks.ts create mode 100644 frontend/src/store.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c0a3a9c0..d6467e2f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,62 +1,17 @@ -import { useEffect, useState } from 'react'; import { Routes, Route } from 'react-router-dom'; -import Navigation from './components/Navigation/Navigation'; -import DocsGPT from './components/DocsGPT/DocsGPT'; +import Navigation from './components/Navigation'; +import Conversation from './components/Conversation/Conversation'; import APIKeyModal from './components/APIKeyModal'; import About from './components/About'; export default function App() { - //Currently using primitive state management. Will most likely be replaced with Redux. - const [isMobile, setIsMobile] = useState(true); - const [isMenuOpen, setIsMenuOpen] = useState(true); - const [isApiModalOpen, setIsApiModalOpen] = useState(false); - const [apiKey, setApiKey] = useState(''); - - const handleResize = () => { - if (window.innerWidth > 768 && isMobile) { - setIsMobile(false); - } else { - setIsMobile(true); - setIsMenuOpen(false); - } - }; - - useEffect(() => { - window.addEventListener('resize', handleResize); - handleResize(); - - return () => { - window.removeEventListener('resize', handleResize); - }; - }, []); - return ( -
- - +
+ + - } - /> - } - /> + } /> + } />
); diff --git a/frontend/src/components/APIKeyModal.tsx b/frontend/src/components/APIKeyModal.tsx index 505f2494..07a8f061 100644 --- a/frontend/src/components/APIKeyModal.tsx +++ b/frontend/src/components/APIKeyModal.tsx @@ -1,30 +1,29 @@ import { useState } from 'react'; - -export default function APIKeyModal({ - isApiModalOpen, - setIsApiModalOpen, - apiKey, +import { useDispatch, useSelector } from 'react-redux'; +import { setApiKey, -}: { - isApiModalOpen: boolean; - setIsApiModalOpen: React.Dispatch>; - apiKey: string; - setApiKey: React.Dispatch>; -}) { - //TODO - Add form validation + toggleApiKeyModal, + selectIsApiKeyModalOpen, +} from '../store'; + +export default function APIKeyModal({}) { + //TODO - Add form validation? //TODO - Connect to backend //TODO - Add link to OpenAI API Key page + const dispatch = useDispatch(); + const isApiModalOpen = useSelector(selectIsApiKeyModalOpen); + const [key, setKey] = useState(''); const [formError, setFormError] = useState(false); - const handleResetKey = () => { - if (!apiKey) { + function handleSubmit() { + if (key.length < 1) { setFormError(true); - } else { - setFormError(false); - setIsApiModalOpen(false); + return; } - }; + dispatch(setApiKey(key)); + dispatch(toggleApiKeyModal()); + } return (
setApiKey(e.target.value)} + onChange={(e) => setKey(e.target.value)} />
{formError && (

Please enter a valid API key

)} @@ -38,7 +40,7 @@ function MobileNavigation({ <> @@ -71,7 +73,7 @@ function MobileNavigation({
setIsApiModalOpen(true)} + onClick={() => dispatch(toggleApiKeyModal())} > info

Reset Key

@@ -82,15 +84,10 @@ function MobileNavigation({ ); } -function DesktopNavigation({ - isMenuOpen, - setIsMenuOpen, - setIsApiModalOpen, -}: { - isMenuOpen: boolean; - setIsMenuOpen: React.Dispatch>; - setIsApiModalOpen: React.Dispatch>; -}) { +function DesktopNavigation() { + const dispatch = useDispatch(); + const isMenuOpen = useSelector(selectIsMenuOpen); + return (