From a2ef45e13f57976f84887f7825afbd49dc0b6440 Mon Sep 17 00:00:00 2001 From: jayantp2003 Date: Fri, 11 Oct 2024 17:08:04 +0530 Subject: [PATCH 001/101] Fix #859: Resolve issue with large zip breaking stream endpoint --- application/parser/file/rst_parser.py | 53 ++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/application/parser/file/rst_parser.py b/application/parser/file/rst_parser.py index 633ec844..eb9043b2 100644 --- a/application/parser/file/rst_parser.py +++ b/application/parser/file/rst_parser.py @@ -91,6 +91,48 @@ class RstParser(BaseParser): ] return rst_tups + def chunk_by_token_count(self, text: str, max_tokens: int = 100) -> List[str]: + """Chunk text by token count.""" + # words = text.split() + # chunks = [] + # current_chunk = [] + # current_token_count = 0 + + # for word in words: + # word_token_len = len(word.split()) # Token count + # if current_token_count + word_token_len > max_tokens: + # chunks.append(" ".join(current_chunk)) + # current_chunk = [] + # current_token_count = 0 + # current_chunk.append(word) + # current_token_count += word_token_len + + # if current_chunk: + # chunks.append(" ".join(current_chunk)) + + # return chunks + + + avg_token_length = 5 + + # Calculate approximate chunk size in characters + chunk_size = max_tokens * avg_token_length + + # Split text into chunks + chunks = [] + for i in range(0, len(text), chunk_size): + chunk = text[i:i+chunk_size] + + # Adjust chunk to end at a word boundary + if i + chunk_size < len(text): + last_space = chunk.rfind(' ') + if last_space != -1: + chunk = chunk[:last_space] + + chunks.append(chunk.strip()) + + return chunks + def remove_images(self, content: str) -> str: pattern = r"\.\. image:: (.*)" content = re.sub(pattern, "", content) @@ -136,7 +178,7 @@ class RstParser(BaseParser): return {} def parse_tups( - self, filepath: Path, errors: str = "ignore" + self, filepath: Path, errors: str = "ignore",max_tokens: Optional[int] = 1000 ) -> List[Tuple[Optional[str], str]]: """Parse file into tuples.""" with open(filepath, "r") as f: @@ -156,6 +198,15 @@ class RstParser(BaseParser): rst_tups = self.remove_whitespaces_excess(rst_tups) if self._remove_characters_excess: rst_tups = self.remove_characters_excess(rst_tups) + + # Apply chunking if max_tokens is provided + if max_tokens is not None: + chunked_tups = [] + for header, text in rst_tups: + chunks = self.chunk_by_token_count(text, max_tokens) + for idx, chunk in enumerate(chunks): + chunked_tups.append((f"{header} - Chunk {idx + 1}", chunk)) + return chunked_tups return rst_tups def parse_file( From 3db07f3a26c56d29e6d5a7d99c097206ac64cdce Mon Sep 17 00:00:00 2001 From: jayantp2003 Date: Fri, 11 Oct 2024 17:10:12 +0530 Subject: [PATCH 002/101] Fix #859: Resolve issue with large zip breaking stream endpoint --- application/parser/file/rst_parser.py | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/application/parser/file/rst_parser.py b/application/parser/file/rst_parser.py index eb9043b2..d39a0837 100644 --- a/application/parser/file/rst_parser.py +++ b/application/parser/file/rst_parser.py @@ -93,37 +93,14 @@ class RstParser(BaseParser): def chunk_by_token_count(self, text: str, max_tokens: int = 100) -> List[str]: """Chunk text by token count.""" - # words = text.split() - # chunks = [] - # current_chunk = [] - # current_token_count = 0 - - # for word in words: - # word_token_len = len(word.split()) # Token count - # if current_token_count + word_token_len > max_tokens: - # chunks.append(" ".join(current_chunk)) - # current_chunk = [] - # current_token_count = 0 - # current_chunk.append(word) - # current_token_count += word_token_len - - # if current_chunk: - # chunks.append(" ".join(current_chunk)) - - # return chunks - avg_token_length = 5 - # Calculate approximate chunk size in characters chunk_size = max_tokens * avg_token_length - - # Split text into chunks + chunks = [] for i in range(0, len(text), chunk_size): chunk = text[i:i+chunk_size] - - # Adjust chunk to end at a word boundary if i + chunk_size < len(text): last_space = chunk.rfind(' ') if last_space != -1: From fe18d6e638a255499b41ed70e8d82a15293007b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:41:57 +0000 Subject: [PATCH 003/101] build(deps): bump react-dropzone from 14.2.3 to 14.3.5 in /frontend Bumps [react-dropzone](https://github.com/react-dropzone/react-dropzone) from 14.2.3 to 14.3.5. - [Release notes](https://github.com/react-dropzone/react-dropzone/releases) - [Commits](https://github.com/react-dropzone/react-dropzone/compare/v14.2.3...v14.3.5) --- updated-dependencies: - dependency-name: react-dropzone dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 50 ++++++++++++-------------------------- frontend/package.json | 2 +- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9973bb9e..9f25e198 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,7 @@ "react-chartjs-2": "^5.2.0", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", - "react-dropzone": "^14.2.3", + "react-dropzone": "^14.3.5", "react-i18next": "^15.0.2", "react-markdown": "^9.0.1", "react-redux": "^8.0.5", @@ -2371,9 +2371,9 @@ } }, "node_modules/attr-accept": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", - "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.4.tgz", + "integrity": "sha512-2pA6xFIbdTUDCAwjN8nQwI+842VwzbDUXO2IYlpPXQIORgKnavorcr4Ce3rwh+zsNg9zK7QPsdvDj3Lum4WX4w==", "engines": { "node": ">=4" } @@ -3075,24 +3075,6 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "node_modules/easy-speech": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/easy-speech/-/easy-speech-2.4.0.tgz", - "integrity": "sha512-wpMv29DEoeP/eyXr4aXpDqd9DvlXl7aQs7BgfKbjGVxqkmQPgNmpbF5YULaTH5bc/5qrteg5MDfCD2Zd0qr4rQ==", - "funding": [ - { - "type": "GitHub", - "url": "https://github.com/sponsors/jankapunkt" - }, - { - "type": "PayPal", - "url": "https://paypal.me/kuesterjan" - } - ], - "engines": { - "node": ">= 14.x" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.11", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.11.tgz", @@ -4172,20 +4154,20 @@ } }, "node_modules/file-selector": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", - "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.0.tgz", + "integrity": "sha512-ZuXAqGePcSPz4JuerOY06Dzzq0hrmQ6VGoXVzGyFI1npeOfBgqGIKKpznfYWRkSLJlXutkqVC5WvGZtkFVhu9Q==", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.7.0" }, "engines": { "node": ">= 12" } }, "node_modules/file-selector/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/fill-range": { "version": "7.1.1", @@ -7847,12 +7829,12 @@ } }, "node_modules/react-dropzone": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", - "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "version": "14.3.5", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.5.tgz", + "integrity": "sha512-9nDUaEEpqZLOz5v5SUcFA0CjM4vq8YbqO0WRls+EYT7+DvxUdzDPKNCPLqGfj3YL9MsniCLCD4RFA6M95V6KMQ==", "dependencies": { - "attr-accept": "^2.2.2", - "file-selector": "^0.6.0", + "attr-accept": "^2.2.4", + "file-selector": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { diff --git a/frontend/package.json b/frontend/package.json index 83d531d6..a9afb3c1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,7 +28,7 @@ "react-chartjs-2": "^5.2.0", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", - "react-dropzone": "^14.2.3", + "react-dropzone": "^14.3.5", "react-i18next": "^15.0.2", "react-markdown": "^9.0.1", "react-redux": "^8.0.5", From 0ef232f7317b96f7046505290deb8938d93bbc5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:01:52 +0000 Subject: [PATCH 004/101] build(deps): bump werkzeug from 3.0.4 to 3.1.3 in /application Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.4 to 3.1.3. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/3.0.4...3.1.3) --- updated-dependencies: - dependency-name: werkzeug dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 2f28c2ea..36a008a7 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -85,5 +85,5 @@ tzdata==2024.2 urllib3==2.2.3 vine==5.1.0 wcwidth==0.2.13 -werkzeug==3.0.4 +werkzeug==3.1.3 yarl==1.11.1 \ No newline at end of file From 58af393968a8bd5f6c74832838927fafc69fbfe1 Mon Sep 17 00:00:00 2001 From: rohittcodes Date: Wed, 13 Nov 2024 02:15:05 +0530 Subject: [PATCH 005/101] feat: wrapper modal --- frontend/src/Navigation.tsx | 17 +- frontend/src/modals/ConfirmationModal.tsx | 76 ++++---- frontend/src/modals/CreateAPIKeyModal.tsx | 163 +++++++++--------- .../src/modals/ShareConversationModal.tsx | 145 ++++++++-------- frontend/src/modals/WrapperModal.tsx | 48 ++++++ frontend/src/modals/types/index.ts | 4 + frontend/src/settings/Documents.tsx | 2 +- frontend/src/upload/Upload.tsx | 37 ++-- 8 files changed, 254 insertions(+), 238 deletions(-) create mode 100644 frontend/src/modals/WrapperModal.tsx create mode 100644 frontend/src/modals/types/index.ts diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index 324d5aa0..f5eee00e 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -32,7 +32,6 @@ import { selectConversations, selectModalStateDeleteConv, selectSelectedDocs, - selectSelectedDocsStatus, selectSourceDocs, selectPaginatedDocuments, setConversations, @@ -85,10 +84,6 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { const [apiKeyModalState, setApiKeyModalState] = useState('INACTIVE'); - const isSelectedDocsSet = useSelector(selectSelectedDocsStatus); - const [selectedDocsModalState, setSelectedDocsModalState] = - useState(isSelectedDocsSet ? 'INACTIVE' : 'ACTIVE'); - const [uploadModalState, setUploadModalState] = useState('INACTIVE'); @@ -491,11 +486,13 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { setModalState={setModalStateDeleteConv} handleDeleteAllConv={handleDeleteAllConversations} /> - + {uploadModalState === 'ACTIVE' && ( + setUploadModalState('INACTIVE')} + > + )} ); } diff --git a/frontend/src/modals/ConfirmationModal.tsx b/frontend/src/modals/ConfirmationModal.tsx index 0b39440b..c69dcedd 100644 --- a/frontend/src/modals/ConfirmationModal.tsx +++ b/frontend/src/modals/ConfirmationModal.tsx @@ -1,6 +1,6 @@ -import Exit from '../assets/exit.svg'; import { ActiveState } from '../models/misc'; import { useTranslation } from 'react-i18next'; +import WrapperModal from './WrapperModal'; function ConfirmationModal({ message, modalState, @@ -20,49 +20,43 @@ function ConfirmationModal({ }) { const { t } = useTranslation(); return ( -
-
-
- -
-

- {message} -

-
-
- - + <> + {modalState === 'ACTIVE' && ( + { + setModalState('INACTIVE'); + handleCancel && handleCancel(); + }} + > +
+
+

+ {message} +

+
+
+ + +
-
-
-
+ + )} + ); } diff --git a/frontend/src/modals/CreateAPIKeyModal.tsx b/frontend/src/modals/CreateAPIKeyModal.tsx index eb085a28..5c8c75b8 100644 --- a/frontend/src/modals/CreateAPIKeyModal.tsx +++ b/frontend/src/modals/CreateAPIKeyModal.tsx @@ -3,11 +3,11 @@ import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import userService from '../api/services/userService'; -import Exit from '../assets/exit.svg'; import Dropdown from '../components/Dropdown'; import Input from '../components/Input'; import { CreateAPIKeyModalProps, Doc } from '../models/misc'; import { selectSourceDocs } from '../preferences/preferenceSlice'; +import WrapperModal from './WrapperModal'; const embeddingsName = import.meta.env.VITE_EMBEDDINGS_NAME || @@ -73,91 +73,82 @@ export default function CreateAPIKeyModal({ handleFetchPrompts(); }, []); return ( -
-
- -
- - {t('modals.createAPIKey.label')} - -
-
- - {t('modals.createAPIKey.apiKeyName')} - - setAPIKeyName(e.target.value)} - > -
-
- { - setSourcePath(selection); - }} - options={extractDocPaths()} - size="w-full" - rounded="xl" - border="border" - /> -
-
- - setPrompt(value) - } - size="w-full" - border="border" - /> -
-
-

- {t('modals.createAPIKey.chunks')} -

- setChunk(value)} - size="w-full" - border="border" - /> -
- + +
+ + {t('modals.createAPIKey.label')} +
-
+
+ + {t('modals.createAPIKey.apiKeyName')} + + setAPIKeyName(e.target.value)} + > +
+
+ { + setSourcePath(selection); + }} + options={extractDocPaths()} + size="w-full" + rounded="xl" + border="border" + /> +
+
+ + setPrompt(value) + } + size="w-full" + border="border" + /> +
+
+

+ {t('modals.createAPIKey.chunks')} +

+ setChunk(value)} + size="w-full" + border="border" + /> +
+ + ); } diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx index fbb49468..3f87839e 100644 --- a/frontend/src/modals/ShareConversationModal.tsx +++ b/frontend/src/modals/ShareConversationModal.tsx @@ -10,7 +10,6 @@ import { import Dropdown from '../components/Dropdown'; import { Doc } from '../models/misc'; import Spinner from '../assets/spinner.svg'; -import Exit from '../assets/exit.svg'; const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; const embeddingsName = import.meta.env.VITE_EMBEDDINGS_NAME || @@ -19,6 +18,7 @@ const embeddingsName = type StatusType = 'loading' | 'idle' | 'fetched' | 'failed'; import conversationService from '../api/services/conversationService'; +import WrapperModal from './WrapperModal'; export const ShareConversationModal = ({ close, @@ -99,85 +99,78 @@ export const ShareConversationModal = ({ }; return ( -
-
- -
-

{t('modals.shareConv.label')}

-

{t('modals.shareConv.note')}

-
- {t('modals.shareConv.option')} - -
- {allowPrompt && ( -
- - setSourcePath(selection) - } - options={extractDocPaths(sourceDocs ?? [])} - size="w-full" - rounded="xl" + +
+

{t('modals.shareConv.label')}

+

{t('modals.shareConv.note')}

+
+ {t('modals.shareConv.option')} +
-
+
); }; diff --git a/frontend/src/modals/WrapperModal.tsx b/frontend/src/modals/WrapperModal.tsx new file mode 100644 index 00000000..1a012871 --- /dev/null +++ b/frontend/src/modals/WrapperModal.tsx @@ -0,0 +1,48 @@ +import React, { useEffect, useRef } from 'react'; +import { WrapperModalProps } from './types'; +import Exit from '../assets/exit.svg'; + +const WrapperModal: React.FC = ({ children, close }) => { + const modalRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + modalRef.current && + !modalRef.current.contains(event.target as Node) + ) { + close(); + } + }; + + const handleEscapePress = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + close(); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('keydown', handleEscapePress); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('keydown', handleEscapePress); + }; + }, [close]); + + return ( +
+
+ + {children} +
+
+ ); +}; + +export default WrapperModal; diff --git a/frontend/src/modals/types/index.ts b/frontend/src/modals/types/index.ts new file mode 100644 index 00000000..2010bbb9 --- /dev/null +++ b/frontend/src/modals/types/index.ts @@ -0,0 +1,4 @@ +export type WrapperModalProps = { + children?: React.ReactNode; + close: () => void; +}; diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index f91a3355..db2e5855 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -255,9 +255,9 @@ const Documents: React.FC = ({
{/* Your Upload component */} setModalState('INACTIVE')} />
diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 4fee88f6..612456d5 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import userService from '../api/services/userService'; -import Exit from '../assets/exit.svg'; import ArrowLeft from '../assets/arrow-left.svg'; import FileUpload from '../assets/file_upload.svg'; import WebsiteCollect from '../assets/website_collect.svg'; @@ -17,15 +16,16 @@ import { setSourceDocs, selectSourceDocs, } from '../preferences/preferenceSlice'; +import WrapperModal from '../modals/WrapperModal'; function Upload({ - modalState, setModalState, isOnboarding, + close, }: { - modalState: ActiveState; setModalState: (state: ActiveState) => void; isOnboarding: boolean; + close: () => void; }) { const [docName, setDocName] = useState(''); const [urlName, setUrlName] = useState(''); @@ -626,28 +626,17 @@ function Upload({ } return ( -
{ + close(); + setDocName(''); + setfiles([]); + setModalState('INACTIVE'); + setActiveTab(null); + }} > -
- {!isOnboarding && !progress && ( - - )} - {view} -
-
+ {view} + ); } From 541a6417b707f6a19527f7b0330a9e95c864323a Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 14 Nov 2024 04:51:26 +0530 Subject: [PATCH 006/101] (refactor): separate widget core --- .../src/components/DocsGPTWidget.tsx | 110 +++++++++++------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 1baa4c62..355056ac 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -1,9 +1,9 @@ "use client"; import React, { useRef } from 'react' import DOMPurify from 'dompurify'; -import styled, { keyframes, createGlobalStyle } from 'styled-components'; +import styled, { keyframes } from 'styled-components'; import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon } from '@radix-ui/react-icons'; -import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetProps } from '../types/index'; +import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetCoreProps, WidgetProps } from '../types/index'; import { fetchAnswerStreaming, sendFeedback } from '../requests/streamingApi'; import { ThemeProvider } from 'styled-components'; import Like from "../assets/like.svg" @@ -66,13 +66,14 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>` right: ${props => props.modal ? '50%' : '10px'}; bottom: ${props => props.modal ? '50%' : '10px'}; z-index: 1000; - display: none; transform-origin:100% 100%; &.open { animation: createBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards; + display: block; } &.close { animation: closeBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards; + display: none; } ${props => props.modal && "transform : translate(50%,50%);" @@ -119,11 +120,11 @@ const StyledContainer = styled.div<{ isOpen: boolean }>` box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); padding: 26px 26px 0px 26px; animation: ${({ isOpen, theme }) => - theme.dimensions.size === 'large' - ? isOpen - ? 'fadeIn 150ms ease-in forwards' - : 'fadeOut 150ms ease-in forwards' - : isOpen + theme.dimensions.size === 'large' + ? isOpen + ? 'fadeIn 150ms ease-in forwards' + : 'fadeOut 150ms ease-in forwards' + : isOpen ? 'openContainer 150ms ease-in forwards' : 'closeContainer 250ms ease-in forwards'}; @keyframes openContainer { @@ -478,7 +479,49 @@ const Hero = ({ title, description, theme }: { title: string, description: strin ); }; -export const DocsGPTWidget = ({ +export const DocsGPTWidget = (props: WidgetProps) => { + + const { + buttonIcon = 'https://d3dg1063dc54p9.cloudfront.net/widget/chat.svg', + buttonText = 'Ask a question', + buttonBg = 'linear-gradient(to bottom right, #5AF0EC, #E80D9D)', + defaultOpen = false, + ...coreProps + } = props + + const [open, setOpen] = React.useState(defaultOpen); + const [isAnimatingButton, setIsAnimatingButton] = React.useState(false); + const [isFloatingButtonVisible, setIsFloatingButtonVisible] = React.useState(true); + const widgetRef = useRef(null) + + + const handleClose = () => { + setOpen(false); + setTimeout(() => { + if (widgetRef.current) + widgetRef.current.style.display = "none"; + setIsFloatingButtonVisible(true); + setIsAnimatingButton(true); + setTimeout(() => setIsAnimatingButton(false), 200); + }, 250) + }; + const handleOpen = () => { + setOpen(true); + setIsFloatingButtonVisible(false); + if (widgetRef.current) + widgetRef.current.style.display = 'block' + } + return ( + <> + + + + ) +} +export const WidgetCore = ({ apiHost = 'https://gptcloud.arc53.com', apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a', avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png', @@ -488,22 +531,19 @@ export const DocsGPTWidget = ({ heroDescription = 'This chatbot is built with DocsGPT and utilises GenAI, please review important information using sources.', size = 'small', theme = 'dark', - buttonIcon = 'https://d3dg1063dc54p9.cloudfront.net/widget/chat.svg', - buttonText = 'Ask a question', - buttonBg = 'linear-gradient(to bottom right, #5AF0EC, #E80D9D)', collectFeedback = true, - deafultOpen = false -}: WidgetProps) => { - const [prompt, setPrompt] = React.useState(''); + widgetRef = null, + isOpen = false, + prefilledQuery = "", + handleClose +}: WidgetCoreProps) => { + const [prompt, setPrompt] = React.useState(prefilledQuery); const [status, setStatus] = React.useState('idle'); - const [queries, setQueries] = React.useState([]) - const [conversationId, setConversationId] = React.useState(null) - const [open, setOpen] = React.useState(deafultOpen) + const [queries, setQueries] = React.useState([]); + const [conversationId, setConversationId] = React.useState(null); const [eventInterrupt, setEventInterrupt] = React.useState(false); //click or scroll by user while autoScrolling - const [isAnimatingButton, setIsAnimatingButton] = React.useState(false); - const [isFloatingButtonVisible, setIsFloatingButtonVisible] = React.useState(true); - const isBubbleHovered = useRef(false) - const widgetRef = useRef(null) + + const isBubbleHovered = useRef(false); const endMessageRef = React.useRef(null); const md = new MarkdownIt(); @@ -615,37 +655,17 @@ export const DocsGPTWidget = ({ const handleImageError = (event: React.SyntheticEvent) => { event.currentTarget.src = "https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png"; }; - const handleClose = () => { - setOpen(false); - setTimeout(() => { - if (widgetRef.current) widgetRef.current.style.display = "none"; - setIsFloatingButtonVisible(true); - setIsAnimatingButton(true); - setTimeout(() => setIsAnimatingButton(false), 200); - }, 250) - }; - const handleOpen = () => { - setOpen(true); - setIsFloatingButtonVisible(false); - if (widgetRef.current) - widgetRef.current.style.display = 'block' - } const dimensions = typeof size === 'object' && 'custom' in size ? sizesConfig.getCustom(size.custom) : sizesConfig[size]; - return ( - {open && size === 'large' && + {isOpen && size === 'large' && } - - - { + + {
From 9409e4498f7f4579d25f5ab8d4a0e5a7ef903180 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 14 Nov 2024 04:52:15 +0530 Subject: [PATCH 007/101] (feat:search bar) initiating seach bar --- extensions/react-widget/package.json | 2 +- extensions/react-widget/src/App.tsx | 8 +- .../react-widget/src/components/SearchBar.tsx | 177 ++++++++++++++++++ extensions/react-widget/src/index.html | 6 +- extensions/react-widget/src/index.ts | 3 +- extensions/react-widget/src/main.tsx | 21 ++- .../react-widget/src/requests/searchAPI.ts | 34 ++++ extensions/react-widget/src/types/index.ts | 21 ++- 8 files changed, 257 insertions(+), 15 deletions(-) create mode 100644 extensions/react-widget/src/components/SearchBar.tsx create mode 100644 extensions/react-widget/src/requests/searchAPI.ts diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json index a1097403..554b2438 100644 --- a/extensions/react-widget/package.json +++ b/extensions/react-widget/package.json @@ -32,7 +32,7 @@ "scripts": { "build": "parcel build src/main.tsx --public-url ./", "build:react": "parcel build src/index.ts", - "dev": "parcel src/index.html -p 3000", + "dev": "parcel -p 3000", "test": "jest", "lint": "eslint", "check": "tsc --noEmit", diff --git a/extensions/react-widget/src/App.tsx b/extensions/react-widget/src/App.tsx index ec9de47b..4bb24bae 100644 --- a/extensions/react-widget/src/App.tsx +++ b/extensions/react-widget/src/App.tsx @@ -1,11 +1,11 @@ import React from "react" import {DocsGPTWidget} from "./components/DocsGPTWidget" -const App = () => { +import {SearchBar} from "./components/SearchBar" +export const App = () => { return (
+
) -} - -export default App \ No newline at end of file +} \ No newline at end of file diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx new file mode 100644 index 00000000..f16271a3 --- /dev/null +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -0,0 +1,177 @@ +import React from 'react' +import styled, { keyframes, createGlobalStyle } from 'styled-components'; +import { WidgetCore } from './DocsGPTWidget'; +import { SearchBarProps } from '@/types'; +import { getSearchResults } from '../requests/searchAPI' +import { Result } from '@/types'; +import MarkdownIt from 'markdown-it'; +import DOMPurify from 'dompurify'; +const Main = styled.div` + font-family: sans-serif; +` +const TextField = styled.input` + padding: 8px; + border-radius: 8px; + display: inline; + color: rgb(107 114 128); + outline: none; + border: 2px solid transparent; + background-color: rgba(0, 0, 0, .05);; + &:focus { + outline: #467f95; /* remove default outline */ + border:2px solid skyblue; /* change border color on focus */ + box-shadow: 0px 0px 2px skyblue; /* add a red box shadow on focus */ + } +` + +const Container = styled.div` + position: relative; + display: inline-block; +` +const SearchResults = styled.div` + position: absolute; + background-color: white; + opacity: 90%; + border: 1px solid rgba(0, 0, 0, .1); + border-radius: 12px; + padding: 20px; + width: 576px; + z-index: 100; + height: 25vh; + overflow-y: auto; + top: 45px; + scrollbar-color: lab(48.438 0 0 / 0.4) rgba(0, 0, 0, 0); + scrollbar-gutter: stable; + scrollbar-width: thin; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(16px); +` +const Title = styled.h3` + font-size: 12px; + color: rgb(107, 114, 128); + padding-bottom: 4px; + font-weight: 600; + text-transform: uppercase; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + +` + +const Content = styled.div` + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; +` +const Markdown = styled.div` + +font-size: 12px; + pre { + padding: 8px; + width: 90%; + font-size: 12px; + border-radius: 6px; + overflow-x: auto; + background-color: #1B1C1F; + color: #fff ; + } + + h1,h2 { + font-size: 16px; + font-weight: 600; + color: rgb(31, 41, 55); + } + + + h3 { + font-size: 14px; + } + + p { + margin: 0px; + line-height: 1.35rem; + } + + code:not(pre code) { + border-radius: 6px; + padding: 4px 4px; + font-size: 12px; + display: inline-block; + background-color: #646464; + color: #fff ; + } + + code { + white-space: pre-wrap ; + overflow-wrap: break-word; + word-break: break-all; + } + + ul{ + padding:0px; + list-style-position: inside; + } +` +export const SearchBar = ({ + apiKey = "79bcbf0e-3dd1-4ac3-b893-e41b3d40ec8d", + apiHost = "http://127.0.0.1:7091", + theme = "dark" +}: SearchBarProps) => { + const [input, setInput] = React.useState("") + const [isWidgetOpen, setIsWidgetOpen] = React.useState(false); + const inputRef = React.useRef(null) + const [results, setResults] = React.useState([]) + React.useEffect(() => { + input.length > 0 ? + getSearchResults(input, apiKey, apiHost) + .then((data) => setResults(data)) + .catch((err) => console.log(err)) + : + setResults([]) + }, [input]) + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + setIsWidgetOpen(true); + } + }; + const handleClose = () => { + setIsWidgetOpen(false); + } + const md = new MarkdownIt(); + return ( +
+ + handleKeyDown(e)} + placeholder='Search here or Ask DocsGPT' + value={input} + onChange={(e) => setInput(e.target.value)} + /> + { + results.length > 0 && ( + + {results.map((res) => ( +
+ {res.title} + + + +
+ )) + } +
+ + ) + } +
+ + +
+ ) +} \ No newline at end of file diff --git a/extensions/react-widget/src/index.html b/extensions/react-widget/src/index.html index 0f0710d5..40eaad15 100644 --- a/extensions/react-widget/src/index.html +++ b/extensions/react-widget/src/index.html @@ -9,11 +9,11 @@
- - --> diff --git a/extensions/react-widget/src/index.ts b/extensions/react-widget/src/index.ts index 1efa89a6..e29b85a5 100644 --- a/extensions/react-widget/src/index.ts +++ b/extensions/react-widget/src/index.ts @@ -1 +1,2 @@ -export { DocsGPTWidget } from "./components/DocsGPTWidget"; \ No newline at end of file +export {SearchBar} from "./components/SearchBar" +export { DocsGPTWidget } from "./components/DocsGPTWidget"; diff --git a/extensions/react-widget/src/main.tsx b/extensions/react-widget/src/main.tsx index 4fb3bbb4..a8542e26 100644 --- a/extensions/react-widget/src/main.tsx +++ b/extensions/react-widget/src/main.tsx @@ -1,12 +1,25 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; -import { DocsGPTWidget } from './components/DocsGPTWidget'; +import { createRoot } from "react-dom/client"; +import { App } from "./App"; +import { DocsGPTWidget } from './components/DocsGPTWidget'; +import { SearchBar } from './components/SearchBar'; +import React from "react"; if (typeof window !== 'undefined') { const renderWidget = (elementId: string, props = {}) => { const root = createRoot(document.getElementById(elementId) as HTMLElement); root.render(); }; + const renderSearchBar = (elementId: string, props = {}) => { + const root = createRoot(document.getElementById(elementId) as HTMLElement); + root.render(); + }; (window as any).renderDocsGPTWidget = renderWidget; + + (window as any).renderSearchBar = renderSearchBar; } -export { DocsGPTWidget }; \ No newline at end of file +const container = document.getElementById("app") as HTMLElement; +const root = createRoot(container) +root.render(); + +export { DocsGPTWidget }; +export { SearchBar } diff --git a/extensions/react-widget/src/requests/searchAPI.ts b/extensions/react-widget/src/requests/searchAPI.ts new file mode 100644 index 00000000..18df3691 --- /dev/null +++ b/extensions/react-widget/src/requests/searchAPI.ts @@ -0,0 +1,34 @@ +import { Result } from "@/types"; + + async function getSearchResults(question: string, apiKey:string, apiHost:string): Promise { + + const payload = { + question, + api_key:apiKey + }; + + try { + const response = await fetch(`${apiHost}/api/search`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + }); + + if (!response.ok) { + throw new Error(`Error: ${response.status}`); + } + + const data: Result[] = await response.json(); + return data; + + } catch (error) { + console.error("Failed to fetch documents:", error); + throw error; + } + } + + export { + getSearchResults + } \ No newline at end of file diff --git a/extensions/react-widget/src/types/index.ts b/extensions/react-widget/src/types/index.ts index 717efd92..445260dc 100644 --- a/extensions/react-widget/src/types/index.ts +++ b/extensions/react-widget/src/types/index.ts @@ -32,5 +32,22 @@ export interface WidgetProps { buttonText?:string; buttonBg?:string; collectFeedback?:boolean; - deafultOpen?: boolean; -} \ No newline at end of file + defaultOpen?: boolean; +} +export interface WidgetCoreProps extends WidgetProps { + widgetRef?:React.RefObject | null; + handleClose?:React.MouseEventHandler | undefined; + isOpen:boolean; + prefilledQuery?: string; +} + +export interface SearchBarProps { + apiHost?: string; + apiKey?: string; + theme?:THEME +} + +export interface Result { + text:string; + title:string +} From 811a20f080151fd781ac6710b005227d4397bc78 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 15 Nov 2024 05:52:46 +0530 Subject: [PATCH 008/101] search: add themes, fix css override --- .../src/components/DocsGPTWidget.tsx | 6 +- .../react-widget/src/components/SearchBar.tsx | 150 +++++++++++------- extensions/react-widget/src/types/index.ts | 3 +- 3 files changed, 99 insertions(+), 60 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 355056ac..6fff4f46 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -106,8 +106,10 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>` `; const StyledContainer = styled.div<{ isOpen: boolean }>` all: initial; - max-height: ${(props) => props.theme.dimensions.maxHeight}; - max-width: ${(props) => props.theme.dimensions.maxWidth}; + max-height: ${(props) => props.theme.dimensions.maxHeight} !important; + max-width: ${(props) => props.theme.dimensions.maxWidth} !important; + width: ${(props) => props.theme.dimensions.width} !important; + height: ${(props) => props.theme.dimensions.height} !important; position: relative; flex-direction: column; justify-content: space-between; diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index f16271a3..a6a48173 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -1,26 +1,56 @@ import React from 'react' -import styled, { keyframes, createGlobalStyle } from 'styled-components'; +import styled, { keyframes, createGlobalStyle, ThemeProvider } from 'styled-components'; import { WidgetCore } from './DocsGPTWidget'; import { SearchBarProps } from '@/types'; import { getSearchResults } from '../requests/searchAPI' import { Result } from '@/types'; import MarkdownIt from 'markdown-it'; import DOMPurify from 'dompurify'; + +const themes = { + dark: { + bg: '#222327', + text: '#fff', + primary: { + text: "#FAFAFA", + bg: '#111111' + }, + secondary: { + text: "#A1A1AA", + bg: "#38383b" + } + }, + light: { + bg: '#fff', + text: '#000', + primary: { + text: "#222327", + bg: "#fff" + }, + secondary: { + text: "#A1A1AA", + bg: "#F6F6F6" + } + } + } + const Main = styled.div` + all:initial; + font-family: sans-serif; ` const TextField = styled.input` - padding: 8px; + padding: 6px 6px; border-radius: 8px; display: inline; - color: rgb(107 114 128); + color: ${props => props.theme.primary.text}; outline: none; border: 2px solid transparent; - background-color: rgba(0, 0, 0, .05);; + background-color: ${props => props.theme.secondary.bg}; &:focus { - outline: #467f95; /* remove default outline */ - border:2px solid skyblue; /* change border color on focus */ - box-shadow: 0px 0px 2px skyblue; /* add a red box shadow on focus */ + border:2px solid #007ee6; + box-shadow: 0px 0px 2px skyblue; + background-color: ${props => props.theme.primary.bg}; } ` @@ -30,29 +60,30 @@ const Container = styled.div` ` const SearchResults = styled.div` position: absolute; - background-color: white; + background-color: ${props => props.theme.primary.bg}; opacity: 90%; border: 1px solid rgba(0, 0, 0, .1); border-radius: 12px; - padding: 20px; + padding: 15px; width: 576px; z-index: 100; height: 25vh; overflow-y: auto; top: 45px; - scrollbar-color: lab(48.438 0 0 / 0.4) rgba(0, 0, 0, 0); - scrollbar-gutter: stable; - scrollbar-width: thin; + color: ${props => props.theme.primary.text}; + scrollbar-color: lab(48.438 0 0 / 0.4) rgba(0, 0, 0, 0); + scrollbar-gutter: stable; + scrollbar-width: thin; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); backdrop-filter: blur(16px); ` const Title = styled.h3` - font-size: 12px; + font-size: 14px; color: rgb(107, 114, 128); - padding-bottom: 4px; + padding-bottom: 6px; font-weight: 600; text-transform: uppercase; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); + border-bottom: 1px solid ${(props) => props.theme.secondary.text}; ` @@ -60,7 +91,7 @@ const Content = styled.div` font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; ` const Markdown = styled.div` - +line-height:20px; font-size: 12px; pre { padding: 8px; @@ -86,6 +117,7 @@ font-size: 12px; p { margin: 0px; line-height: 1.35rem; + font-size: 12px; } code:not(pre code) { @@ -102,20 +134,20 @@ font-size: 12px; overflow-wrap: break-word; word-break: break-all; } - - ul{ - padding:0px; - list-style-position: inside; + a{ + color: #007ee6; } ` export const SearchBar = ({ apiKey = "79bcbf0e-3dd1-4ac3-b893-e41b3d40ec8d", apiHost = "http://127.0.0.1:7091", - theme = "dark" + theme = "dark", + placeholder = "Search or Ask AI" }: SearchBarProps) => { const [input, setInput] = React.useState("") const [isWidgetOpen, setIsWidgetOpen] = React.useState(false); const inputRef = React.useRef(null) + const widgetRef = React.useRef(null) const [results, setResults] = React.useState([]) React.useEffect(() => { input.length > 0 ? @@ -125,6 +157,9 @@ export const SearchBar = ({ : setResults([]) }, [input]) + React.useEffect(()=>{ + console.log(isWidgetOpen, input); + },[isWidgetOpen]) const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { setIsWidgetOpen(true); @@ -135,43 +170,44 @@ export const SearchBar = ({ } const md = new MarkdownIt(); return ( -
- - handleKeyDown(e)} - placeholder='Search here or Ask DocsGPT' - value={input} - onChange={(e) => setInput(e.target.value)} + +
+ + handleKeyDown(e)} + placeholder={placeholder} + value={input} + onChange={(e) => setInput(e.target.value)} + /> + { + input.length>0 && results.length > 0 && ( + + {results.map((res) => ( +
+ {res.title} + + + +
+ )) + } +
+ ) + } +
+ - { - results.length > 0 && ( - - {results.map((res) => ( -
- {res.title} - - - -
- )) - } -
- ) - } - - - -
+
+ ) } \ No newline at end of file diff --git a/extensions/react-widget/src/types/index.ts b/extensions/react-widget/src/types/index.ts index 445260dc..f8fc3753 100644 --- a/extensions/react-widget/src/types/index.ts +++ b/extensions/react-widget/src/types/index.ts @@ -44,7 +44,8 @@ export interface WidgetCoreProps extends WidgetProps { export interface SearchBarProps { apiHost?: string; apiKey?: string; - theme?:THEME + theme?:THEME; + placeholder?:string; } export interface Result { From 7bd0351ee9ff12a4082726b2fb9be03a17094f65 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 15 Nov 2024 06:25:24 +0530 Subject: [PATCH 009/101] (fix): mount only when open --- extensions/react-widget/package-lock.json | 9 +- .../src/components/DocsGPTWidget.tsx | 212 +++++++++--------- .../react-widget/src/components/SearchBar.tsx | 52 +++-- 3 files changed, 139 insertions(+), 134 deletions(-) diff --git a/extensions/react-widget/package-lock.json b/extensions/react-widget/package-lock.json index de4c228d..6d736c6f 100644 --- a/extensions/react-widget/package-lock.json +++ b/extensions/react-widget/package-lock.json @@ -4860,9 +4860,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001625", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz", - "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==", + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", "funding": [ { "type": "opencollective", @@ -4876,7 +4876,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "2.4.2", diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 6fff4f46..7a43cb7b 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -65,8 +65,11 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>` position: fixed; right: ${props => props.modal ? '50%' : '10px'}; bottom: ${props => props.modal ? '50%' : '10px'}; - z-index: 1000; + z-index: 1001; transform-origin:100% 100%; + &.modal{ + transform : translate(50%,50%); + } &.open { animation: createBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards; display: block; @@ -75,9 +78,6 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>` animation: closeBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards; display: none; } - ${props => props.modal && - "transform : translate(50%,50%);" - } align-items: center; text-align: left; @keyframes createBox { @@ -539,7 +539,9 @@ export const WidgetCore = ({ prefilledQuery = "", handleClose }: WidgetCoreProps) => { - const [prompt, setPrompt] = React.useState(prefilledQuery); + const [prompt, setPrompt] = React.useState(prefilledQuery); + console.log("propmpt",prompt); + const [status, setStatus] = React.useState('idle'); const [queries, setQueries] = React.useState([]); const [conversationId, setConversationId] = React.useState(null); @@ -666,106 +668,110 @@ export const WidgetCore = ({ {isOpen && size === 'large' && } - - { -
- - - -
- docs-gpt - - {title} - {description} - -
-
- - { - queries.length > 0 ? queries?.map((query, index) => { - return ( - - { - query.prompt && - - {query.prompt} - - - } - { - query.response ? { isBubbleHovered.current = true }} type='ANSWER'> - - - + { + isOpen && ( + + +
+ + + +
+ docs-gpt + + {title} + {description} + +
+
+ + { + queries.length > 0 ? queries?.map((query, index) => { + return ( + + { + query.prompt && + + {query.prompt} + + + } + { + query.response ? { isBubbleHovered.current = true }} type='ANSWER'> + + + - {collectFeedback && - - handleFeedback("LIKE", index)} /> - handleFeedback("DISLIKE", index)} /> - } - - :
- { - query.error ? + {collectFeedback && + + handleFeedback("LIKE", index)} /> + handleFeedback("DISLIKE", index)} /> + } + + :
+ { + query.error ? - -
-
Network Error
- {query.error} -
-
- : - - . - . - . - - - } -
- } - ) - }) - : - } - -
- - setPrompt(event.target.value)} - type='text' placeholder="Ask your question" /> - - - - - - Powered by  - DocsGPT - -
- } - + +
+
Network Error
+ {query.error} +
+
+ : + + . + . + . + + + } +
+ } +
) + }) + : + } +
+
+ + setPrompt(event.target.value)} + type='text' placeholder="Ask your question" /> + + + + + + Powered by  + DocsGPT + +
+
+
+ ) + } ) } \ No newline at end of file diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index a6a48173..2589cb2f 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -9,30 +9,30 @@ import DOMPurify from 'dompurify'; const themes = { dark: { - bg: '#222327', - text: '#fff', - primary: { - text: "#FAFAFA", - bg: '#111111' - }, - secondary: { - text: "#A1A1AA", - bg: "#38383b" - } + bg: '#222327', + text: '#fff', + primary: { + text: "#FAFAFA", + bg: '#111111' + }, + secondary: { + text: "#A1A1AA", + bg: "#38383b" + } }, light: { - bg: '#fff', - text: '#000', - primary: { - text: "#222327", - bg: "#fff" - }, - secondary: { - text: "#A1A1AA", - bg: "#F6F6F6" - } + bg: '#fff', + text: '#000', + primary: { + text: "#222327", + bg: "#fff" + }, + secondary: { + text: "#A1A1AA", + bg: "#F6F6F6" + } } - } +} const Main = styled.div` all:initial; @@ -157,9 +157,7 @@ export const SearchBar = ({ : setResults([]) }, [input]) - React.useEffect(()=>{ - console.log(isWidgetOpen, input); - },[isWidgetOpen]) + const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { setIsWidgetOpen(true); @@ -181,7 +179,7 @@ export const SearchBar = ({ onChange={(e) => setInput(e.target.value)} /> { - input.length>0 && results.length > 0 && ( + input.length > 0 && results.length > 0 && ( {results.map((res) => (
@@ -198,14 +196,14 @@ export const SearchBar = ({ ) } - + />} From d33246612dcc926f1a64a956ef1810feef1cab56 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 15 Nov 2024 18:16:45 +0530 Subject: [PATCH 010/101] (widget) unmount with timeout --- .../src/components/DocsGPTWidget.tsx | 246 +++++++++--------- .../react-widget/src/components/SearchBar.tsx | 18 +- frontend/.env.development | 2 +- 3 files changed, 137 insertions(+), 129 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 7a43cb7b..557aa9a0 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -67,16 +67,15 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>` bottom: ${props => props.modal ? '50%' : '10px'}; z-index: 1001; transform-origin:100% 100%; + display: block; &.modal{ transform : translate(50%,50%); } &.open { animation: createBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards; - display: block; } &.close { animation: closeBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards; - display: none; } align-items: center; text-align: left; @@ -494,24 +493,20 @@ export const DocsGPTWidget = (props: WidgetProps) => { const [open, setOpen] = React.useState(defaultOpen); const [isAnimatingButton, setIsAnimatingButton] = React.useState(false); const [isFloatingButtonVisible, setIsFloatingButtonVisible] = React.useState(true); - const widgetRef = useRef(null) + React.useEffect(() => { + if(isFloatingButtonVisible) + setTimeout(() => setIsAnimatingButton(false), 400); + }, [isFloatingButtonVisible]) const handleClose = () => { + setIsFloatingButtonVisible(true); + setIsAnimatingButton(true); setOpen(false); - setTimeout(() => { - if (widgetRef.current) - widgetRef.current.style.display = "none"; - setIsFloatingButtonVisible(true); - setIsAnimatingButton(true); - setTimeout(() => setIsAnimatingButton(false), 200); - }, 250) }; const handleOpen = () => { setOpen(true); setIsFloatingButtonVisible(false); - if (widgetRef.current) - widgetRef.current.style.display = 'block' } return ( <> @@ -519,7 +514,7 @@ export const DocsGPTWidget = (props: WidgetProps) => { {buttonText} - + ) } @@ -534,14 +529,13 @@ export const WidgetCore = ({ size = 'small', theme = 'dark', collectFeedback = true, - widgetRef = null, isOpen = false, prefilledQuery = "", handleClose }: WidgetCoreProps) => { - const [prompt, setPrompt] = React.useState(prefilledQuery); - console.log("propmpt",prompt); - + const [prompt, setPrompt] = React.useState(""); + console.log("propmpt", prompt); + const [mounted, setMounted] = React.useState(false); const [status, setStatus] = React.useState('idle'); const [queries, setQueries] = React.useState([]); const [conversationId, setConversationId] = React.useState(null); @@ -551,6 +545,22 @@ export const WidgetCore = ({ const endMessageRef = React.useRef(null); const md = new MarkdownIt(); + React.useEffect(() => { + if (isOpen) { + setMounted(true); // Mount the component + setPrompt(prefilledQuery) + } else { + // Wait for animations before unmounting + const timeout = setTimeout(() => { + setMounted(false) + console.log("Unmounted syccess") + }, 250); + return () => clearTimeout(timeout); + } + }, [isOpen]); + + + const handleUserInterrupt = () => { (status === 'loading') && setEventInterrupt(true); } @@ -663,114 +673,114 @@ export const WidgetCore = ({ typeof size === 'object' && 'custom' in size ? sizesConfig.getCustom(size.custom) : sizesConfig[size]; + if (!mounted) return null; return ( {isOpen && size === 'large' && } - { - isOpen && ( - - -
- - - -
- docs-gpt - - {title} - {description} - -
-
- - { - queries.length > 0 ? queries?.map((query, index) => { - return ( - - { - query.prompt && - - {query.prompt} - - - } - { - query.response ? { isBubbleHovered.current = true }} type='ANSWER'> - - - + {( + + +
+ + + +
+ docs-gpt + + {title} + {description} + +
+
+ + { + queries.length > 0 ? queries?.map((query, index) => { + return ( + + { + query.prompt && + + {query.prompt} + + + } + { + query.response ? { isBubbleHovered.current = true }} type='ANSWER'> + + + - {collectFeedback && - - handleFeedback("LIKE", index)} /> - handleFeedback("DISLIKE", index)} /> - } - - :
- { - query.error ? + {collectFeedback && + + handleFeedback("LIKE", index)} /> + handleFeedback("DISLIKE", index)} /> + } + + :
+ { + query.error ? - -
-
Network Error
- {query.error} -
-
- : - - . - . - . - - - } -
- } - ) - }) - : - } - -
- - setPrompt(event.target.value)} - type='text' placeholder="Ask your question" /> - - - - - - Powered by  - DocsGPT - -
- - - ) + +
+
Network Error
+ {query.error} +
+
+ : + + . + . + . + + + } +
+ } +
) + }) + : + } +
+
+ + setPrompt(event.target.value)} + type='text' placeholder="Ask your question" /> + + + + + + Powered by  + DocsGPT + +
+
+
+ ) }
) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 2589cb2f..5486871b 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -45,11 +45,12 @@ const TextField = styled.input` display: inline; color: ${props => props.theme.primary.text}; outline: none; - border: 2px solid transparent; + border: none; background-color: ${props => props.theme.secondary.bg}; + width: 240px; &:focus { - border:2px solid #007ee6; - box-shadow: 0px 0px 2px skyblue; + outline: none; + box-shadow: 0px 0px 0px 2px rgba(0, 109, 199); background-color: ${props => props.theme.primary.bg}; } ` @@ -84,9 +85,7 @@ const Title = styled.h3` font-weight: 600; text-transform: uppercase; border-bottom: 1px solid ${(props) => props.theme.secondary.text}; - ` - const Content = styled.div` font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; ` @@ -141,7 +140,7 @@ font-size: 12px; export const SearchBar = ({ apiKey = "79bcbf0e-3dd1-4ac3-b893-e41b3d40ec8d", apiHost = "http://127.0.0.1:7091", - theme = "dark", + theme = "light", placeholder = "Search or Ask AI" }: SearchBarProps) => { const [input, setInput] = React.useState("") @@ -157,7 +156,7 @@ export const SearchBar = ({ : setResults([]) }, [input]) - + const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { setIsWidgetOpen(true); @@ -196,15 +195,14 @@ export const SearchBar = ({ ) } - {isWidgetOpen && } - + /> ) diff --git a/frontend/.env.development b/frontend/.env.development index 7a87f762..9569966a 100644 --- a/frontend/.env.development +++ b/frontend/.env.development @@ -1,3 +1,3 @@ # Please put appropriate value -VITE_API_HOST=http://0.0.0.0:7091 +VITE_API_HOST=http://127.0.0.1:7091 VITE_API_STREAMING=true \ No newline at end of file From 94617c5ef72f126802f82de4a04402dd412440c9 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sat, 16 Nov 2024 02:13:40 +0530 Subject: [PATCH 011/101] (fix:animations) minor fix --- .../src/components/DocsGPTWidget.tsx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 557aa9a0..725e829a 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -105,10 +105,10 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>` `; const StyledContainer = styled.div<{ isOpen: boolean }>` all: initial; - max-height: ${(props) => props.theme.dimensions.maxHeight} !important; - max-width: ${(props) => props.theme.dimensions.maxWidth} !important; - width: ${(props) => props.theme.dimensions.width} !important; - height: ${(props) => props.theme.dimensions.height} !important; + max-height: ${(props) => props.theme.dimensions.maxHeight}; + max-width: ${(props) => props.theme.dimensions.maxWidth}; + width: ${(props) => props.theme.dimensions.width}; + height: ${(props) => props.theme.dimensions.height} ; position: relative; flex-direction: column; justify-content: space-between; @@ -134,15 +134,15 @@ const StyledContainer = styled.div<{ isOpen: boolean }>` height: 100px; } 100% { - width: ${(props) => props.theme.dimensions.width}; - height: ${(props) => props.theme.dimensions.height}; + width: ${(props) => props.theme.dimensions.width} !important; + height: ${(props) => props.theme.dimensions.height} !important; border-radius: 12px; } } @keyframes closeContainer { 0% { - width: ${(props) => props.theme.dimensions.width}; - height: ${(props) => props.theme.dimensions.height}; + width: ${(props) => props.theme.dimensions.width} !important; + height: ${(props) => props.theme.dimensions.height} !important; border-radius: 12px; } 100% { @@ -495,13 +495,15 @@ export const DocsGPTWidget = (props: WidgetProps) => { const [isFloatingButtonVisible, setIsFloatingButtonVisible] = React.useState(true); React.useEffect(() => { - if(isFloatingButtonVisible) - setTimeout(() => setIsAnimatingButton(false), 400); + if (isFloatingButtonVisible) + setTimeout(() => setIsAnimatingButton(true), 250); + return () => { + setIsAnimatingButton(false) + } }, [isFloatingButtonVisible]) const handleClose = () => { setIsFloatingButtonVisible(true); - setIsAnimatingButton(true); setOpen(false); }; const handleOpen = () => { @@ -534,7 +536,6 @@ export const WidgetCore = ({ handleClose }: WidgetCoreProps) => { const [prompt, setPrompt] = React.useState(""); - console.log("propmpt", prompt); const [mounted, setMounted] = React.useState(false); const [status, setStatus] = React.useState('idle'); const [queries, setQueries] = React.useState([]); @@ -553,7 +554,6 @@ export const WidgetCore = ({ // Wait for animations before unmounting const timeout = setTimeout(() => { setMounted(false) - console.log("Unmounted syccess") }, 250); return () => clearTimeout(timeout); } From 2ad6b4fa4ea3c257af0b9cd05804f7e7e9f613e0 Mon Sep 17 00:00:00 2001 From: fadingNA Date: Fri, 15 Nov 2024 23:16:58 -0500 Subject: [PATCH 012/101] update table styling --- .../src/components/DocumentPagination.tsx | 2 +- frontend/src/index.css | 12 +- frontend/src/settings/Documents.tsx | 224 ++++++++++-------- 3 files changed, 128 insertions(+), 110 deletions(-) diff --git a/frontend/src/components/DocumentPagination.tsx b/frontend/src/components/DocumentPagination.tsx index b0532362..4000f83d 100644 --- a/frontend/src/components/DocumentPagination.tsx +++ b/frontend/src/components/DocumentPagination.tsx @@ -42,7 +42,7 @@ const Pagination: React.FC = ({ }; return ( -
+
Rows per page: setEditInputBox(e.target.value)} + value={editInputBox} + className="ml-2 mr-2 rounded-[28px] py-[14px] px-[19px] border-[1.5px] border-black" + /> + )} +
+ Edit { + setIsEditClicked(true); + setEditInputBox(message); + }} + /> +
+ {isEditClicked && ( +
+ + +
+ )}
); } else { From 63b547ea138aa9748eb6dd862461ca9b44dee9f4 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 17 Nov 2024 12:59:34 +0000 Subject: [PATCH 017/101] fix: delete old files --- Assets/DocsGPT tee-back.jpeg | Bin 90358 -> 0 bytes Assets/DocsGPT tee-front.jpeg | Bin 21921 -> 0 bytes application/parser/java2doc.py | 66 ------------------ application/parser/js2doc.py | 70 ------------------- application/parser/py2doc.py | 121 --------------------------------- 5 files changed, 257 deletions(-) delete mode 100644 Assets/DocsGPT tee-back.jpeg delete mode 100644 Assets/DocsGPT tee-front.jpeg delete mode 100644 application/parser/java2doc.py delete mode 100644 application/parser/js2doc.py delete mode 100644 application/parser/py2doc.py diff --git a/Assets/DocsGPT tee-back.jpeg b/Assets/DocsGPT tee-back.jpeg deleted file mode 100644 index 8c0e22aa2fcb706f8b64bce6145d721eceb05315..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90358 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' - functions[func_name] = escodegen.generate(node) - elif node.type == 'VariableDeclaration': - for declaration in node.declarations: - if declaration.init and declaration.init.type == 'FunctionExpression': - func_name = declaration.id.name if declaration.id else '' - functions[func_name] = escodegen.generate(declaration.init) - elif node.type == 'ClassDeclaration': - for subnode in node.body.body: - if subnode.type == 'MethodDefinition': - func_name = subnode.key.name - functions[func_name] = escodegen.generate(subnode.value) - elif subnode.type == 'VariableDeclaration': - for declaration in subnode.declarations: - if declaration.init and declaration.init.type == 'FunctionExpression': - func_name = declaration.id.name if declaration.id else '' - functions[func_name] = escodegen.generate(declaration.init) - return functions - - -def extract_classes(file_path): - with open(file_path, 'r') as file: - source_code = file.read() - classes = {} - tree = esprima.parseScript(source_code) - for node in tree.body: - if node.type == 'ClassDeclaration': - class_name = node.id.name - function_names = [] - for subnode in node.body.body: - if subnode.type == 'MethodDefinition': - function_names.append(subnode.key.name) - classes[class_name] = ", ".join(function_names) - return classes - - -def extract_functions_and_classes(directory): - files = find_files(directory) - functions_dict = {} - classes_dict = {} - for file in files: - functions = extract_functions(file) - if functions: - functions_dict[file] = functions - classes = extract_classes(file) - if classes: - classes_dict[file] = classes - return functions_dict, classes_dict diff --git a/application/parser/py2doc.py b/application/parser/py2doc.py deleted file mode 100644 index 3a8175d4..00000000 --- a/application/parser/py2doc.py +++ /dev/null @@ -1,121 +0,0 @@ -import ast -import os -from pathlib import Path - -import tiktoken -from langchain.llms import OpenAI -from langchain.prompts import PromptTemplate - - -def find_files(directory): - files_list = [] - for root, dirs, files in os.walk(directory): - for file in files: - if file.endswith('.py'): - files_list.append(os.path.join(root, file)) - return files_list - - -def extract_functions(file_path): - with open(file_path, 'r') as file: - source_code = file.read() - functions = {} - tree = ast.parse(source_code) - for node in ast.walk(tree): - if isinstance(node, ast.FunctionDef): - func_name = node.name - func_def = ast.get_source_segment(source_code, node) - functions[func_name] = func_def - return functions - - -def extract_classes(file_path): - with open(file_path, 'r') as file: - source_code = file.read() - classes = {} - tree = ast.parse(source_code) - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - class_name = node.name - function_names = [] - for subnode in ast.walk(node): - if isinstance(subnode, ast.FunctionDef): - function_names.append(subnode.name) - classes[class_name] = ", ".join(function_names) - return classes - - -def extract_functions_and_classes(directory): - files = find_files(directory) - functions_dict = {} - classes_dict = {} - for file in files: - functions = extract_functions(file) - if functions: - functions_dict[file] = functions - classes = extract_classes(file) - if classes: - classes_dict[file] = classes - return functions_dict, classes_dict - - -def parse_functions(functions_dict, formats, dir): - c1 = len(functions_dict) - for i, (source, functions) in enumerate(functions_dict.items(), start=1): - print(f"Processing file {i}/{c1}") - source_w = source.replace(dir + "/", "").replace("." + formats, ".md") - subfolders = "/".join(source_w.split("/")[:-1]) - Path(f"outputs/{subfolders}").mkdir(parents=True, exist_ok=True) - for j, (name, function) in enumerate(functions.items(), start=1): - print(f"Processing function {j}/{len(functions)}") - prompt = PromptTemplate( - input_variables=["code"], - template="Code: \n{code}, \nDocumentation: ", - ) - llm = OpenAI(temperature=0) - response = llm(prompt.format(code=function)) - mode = "a" if Path(f"outputs/{source_w}").exists() else "w" - with open(f"outputs/{source_w}", mode) as f: - f.write( - f"\n\n# Function name: {name} \n\nFunction: \n```\n{function}\n```, \nDocumentation: \n{response}") - - -def parse_classes(classes_dict, formats, dir): - c1 = len(classes_dict) - for i, (source, classes) in enumerate(classes_dict.items()): - print(f"Processing file {i + 1}/{c1}") - source_w = source.replace(dir + "/", "").replace("." + formats, ".md") - subfolders = "/".join(source_w.split("/")[:-1]) - Path(f"outputs/{subfolders}").mkdir(parents=True, exist_ok=True) - for name, function_names in classes.items(): - print(f"Processing Class {i + 1}/{c1}") - prompt = PromptTemplate( - input_variables=["class_name", "functions_names"], - template="Class name: {class_name} \nFunctions: {functions_names}, \nDocumentation: ", - ) - llm = OpenAI(temperature=0) - response = llm(prompt.format(class_name=name, functions_names=function_names)) - - with open(f"outputs/{source_w}", "a" if Path(f"outputs/{source_w}").exists() else "w") as f: - f.write(f"\n\n# Class name: {name} \n\nFunctions: \n{function_names}, \nDocumentation: \n{response}") - - -def transform_to_docs(functions_dict, classes_dict, formats, dir): - docs_content = ''.join([str(key) + str(value) for key, value in functions_dict.items()]) - docs_content += ''.join([str(key) + str(value) for key, value in classes_dict.items()]) - - num_tokens = len(tiktoken.get_encoding("cl100k_base").encode(docs_content)) - total_price = ((num_tokens / 1000) * 0.02) - - print(f"Number of Tokens = {num_tokens:,d}") - print(f"Approx Cost = ${total_price:,.2f}") - - user_input = input("Price Okay? (Y/N)\n").lower() - if user_input == "y" or user_input == "": - if not Path("outputs").exists(): - Path("outputs").mkdir() - parse_functions(functions_dict, formats, dir) - parse_classes(classes_dict, formats, dir) - print("All done!") - else: - print("The API was not called. No money was spent.") From 7a0137682858fb631eae9ca75562faccadb56cba Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 17 Nov 2024 13:02:45 +0000 Subject: [PATCH 018/101] fix: remove more old files --- Readme Logo.png | Bin 23575 -> 0 bytes package-lock.json | 1716 --------------------------------------------- package.json | 7 - 3 files changed, 1723 deletions(-) delete mode 100644 Readme Logo.png delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/Readme Logo.png b/Readme Logo.png deleted file mode 100644 index aad92a7524ff2e31de6ab21a1d10a58d42652219..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23575 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.10.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", - "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", - "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", - "dev": true, - "dependencies": { - "type-fest": "^1.0.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "dev": true, - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", - "dev": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", - "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.53.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lint-staged": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.1.0.tgz", - "integrity": "sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==", - "dev": true, - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "2.1.0", - "listr2": "7.0.2", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/listr2": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", - "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", - "dev": true, - "dependencies": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^5.0.1", - "rfdc": "^1.3.0", - "wrap-ansi": "^8.1.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-update": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", - "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", - "dev": true, - "dependencies": { - "ansi-escapes": "^5.0.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 78820bd8..00000000 --- a/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "devDependencies": { - "eslint": "^8.53.0", - "lint-staged": "^15.1.0", - "prettier": "^3.1.0" - } -} From 250edf26a55ea3c37d75608329e59fc5e11e9c0e Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 17 Nov 2024 15:01:39 +0000 Subject: [PATCH 019/101] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 99baf811..83a5bab7 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,7 @@ Say goodbye to time-consuming manual searches, and let - Let's chat - +[Book a Meeting :wave:](https://cal.com/arc53/docsgpt-demo-b2b)⁠ [Send Email :email:](mailto:contact@arc53.com?subject=DocsGPT%20support%2Fsolutions) From 5ee0f15d946ea04de0433d0a9322f3c10343e96b Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Mon, 18 Nov 2024 03:18:39 +0530 Subject: [PATCH 020/101] (feat: search): close on click outside --- .../src/components/DocsGPTWidget.tsx | 9 +-- .../react-widget/src/components/SearchBar.tsx | 58 +++++++++++++++---- extensions/react-widget/src/types/index.ts | 1 + frontend/.env.development | 2 +- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index d471aa57..b9ee8acc 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -78,14 +78,14 @@ const openContainer = keyframes` height: 100px; } 100% { - width: ${(props) => props.theme.dimensions.width} !important; - height: ${(props) => props.theme.dimensions.height} !important; + width: ${(props) => props.theme.dimensions.width}; + height: ${(props) => props.theme.dimensions.height}; border-radius: 12px; }` const closeContainer = keyframes` 0% { - width: ${(props) => props.theme.dimensions.width} !important; - height: ${(props) => props.theme.dimensions.height} !important; + width: ${(props) => props.theme.dimensions.width}; + height: ${(props) => props.theme.dimensions.height}; border-radius: 12px; } 100% { @@ -671,6 +671,7 @@ export const WidgetCore = ({ const handleImageError = (event: React.SyntheticEvent) => { event.currentTarget.src = "https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png"; }; + const dimensions = typeof size === 'object' && 'custom' in size ? sizesConfig.getCustom(size.custom) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 5486871b..a417b955 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -39,15 +39,16 @@ const Main = styled.div` font-family: sans-serif; ` -const TextField = styled.input` +const TextField = styled.input<{inputWidth:string}>` padding: 6px 6px; + width: ${({inputWidth}) => inputWidth}; border-radius: 8px; display: inline; color: ${props => props.theme.primary.text}; outline: none; border: none; background-color: ${props => props.theme.secondary.bg}; - width: 240px; + &:focus { outline: none; box-shadow: 0px 0px 0px 2px rgba(0, 109, 199); @@ -61,6 +62,7 @@ const Container = styled.div` ` const SearchResults = styled.div` position: absolute; + display: block; background-color: ${props => props.theme.primary.bg}; opacity: 90%; border: 1px solid rgba(0, 0, 0, .1); @@ -77,6 +79,11 @@ const SearchResults = styled.div` scrollbar-width: thin; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); backdrop-filter: blur(16px); + @media only screen and (max-width: 768px) { + max-height: 100vh; + max-width: 80vw; + overflow: auto; + } ` const Title = styled.h3` font-size: 14px; @@ -137,17 +144,45 @@ font-size: 12px; color: #007ee6; } ` +const Toolkit = styled.kbd` + position: absolute; + right: 12px; + top: 4px; + background-color: ${(props) => props.theme.primary.bg}; + color: ${(props) => props.theme.secondary.text}; + font-size: 9px; + padding: 2px; + border: 1px solid ${(props) => props.theme.secondary.text}; + border-radius: 4px; +` export const SearchBar = ({ apiKey = "79bcbf0e-3dd1-4ac3-b893-e41b3d40ec8d", apiHost = "http://127.0.0.1:7091", - theme = "light", - placeholder = "Search or Ask AI" + theme = "dark", + placeholder = "Search or Ask AI...", + width="240px" }: SearchBarProps) => { - const [input, setInput] = React.useState("") + const [input, setInput] = React.useState(""); const [isWidgetOpen, setIsWidgetOpen] = React.useState(false); - const inputRef = React.useRef(null) - const widgetRef = React.useRef(null) - const [results, setResults] = React.useState([]) + const inputRef = React.useRef(null); + const resultsRef = React.useRef(null); + const [isResultVisible, setIsResultVisible] = React.useState(true); + const [results, setResults] = React.useState([]); + React.useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + resultsRef.current && + !resultsRef.current.contains(event.target as Node) + ) { + setIsResultVisible(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => { + resultsRef.current && (resultsRef.current.style.display = 'block') + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []) React.useEffect(() => { input.length > 0 ? getSearchResults(input, apiKey, apiHost) @@ -171,6 +206,8 @@ export const SearchBar = ({

setIsResultVisible(true)} ref={inputRef} onKeyDown={(e) => handleKeyDown(e)} placeholder={placeholder} @@ -178,8 +215,8 @@ export const SearchBar = ({ onChange={(e) => setInput(e.target.value)} /> { - input.length > 0 && results.length > 0 && ( - + input.length > 0 && results.length > 0 && isResultVisible && ( + {results.map((res) => (
{res.title} @@ -194,6 +231,7 @@ export const SearchBar = ({ ) } + Enter Date: Mon, 18 Nov 2024 00:05:48 -0500 Subject: [PATCH 021/101] backend : update sources/paginated to search document by query 'name' --- application/api/user/routes.py | 13 ++++++++++++- application/celery_init.py | 10 +++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 6a2f3bea..5ebd54c8 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -473,11 +473,22 @@ class PaginatedSources(Resource): sort_order = request.args.get("order", "desc") # Default to 'desc' page = int(request.args.get("page", 1)) # Default to 1 rows_per_page = int(request.args.get("rows", 10)) # Default to 10 + # add .strip() to remove leading and trailing whitespaces + search_term = request.args.get( + "search", "" + ).strip() # add search for filter documents - # Prepare + # Prepare query for filtering query = {"user": user} + if search_term: + query["name"] = { + "$regex": search_term, + "$options": "i", # using case-insensitive search + } + total_documents = sources_collection.count_documents(query) total_pages = max(1, math.ceil(total_documents / rows_per_page)) + page = min(max(1, page), total_pages) # add this to make sure page inbound is within the range sort_order = 1 if sort_order == "asc" else -1 skip = (page - 1) * rows_per_page diff --git a/application/celery_init.py b/application/celery_init.py index c5838083..185cc87f 100644 --- a/application/celery_init.py +++ b/application/celery_init.py @@ -2,14 +2,22 @@ from celery import Celery from application.core.settings import settings from celery.signals import setup_logging + def make_celery(app_name=__name__): - celery = Celery(app_name, broker=settings.CELERY_BROKER_URL, backend=settings.CELERY_RESULT_BACKEND) + celery = Celery( + app_name, + broker=settings.CELERY_BROKER_URL, + backend=settings.CELERY_RESULT_BACKEND, + ) celery.conf.update(settings) return celery + @setup_logging.connect def config_loggers(*args, **kwargs): from application.core.logging_config import setup_logging + setup_logging() + celery = make_celery() From 0493352292b3d89317709c8bb79e77cdd978ac99 Mon Sep 17 00:00:00 2001 From: fadingNA Date: Mon, 18 Nov 2024 00:06:18 -0500 Subject: [PATCH 022/101] frontend: remove search on localstate, change to backend search use mongo passing searchTerm --- frontend/src/preferences/preferenceApi.ts | 3 ++- frontend/src/settings/Documents.tsx | 29 +++++++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/frontend/src/preferences/preferenceApi.ts b/frontend/src/preferences/preferenceApi.ts index 32cf8b17..8d21bdcd 100644 --- a/frontend/src/preferences/preferenceApi.ts +++ b/frontend/src/preferences/preferenceApi.ts @@ -25,9 +25,10 @@ export async function getDocsWithPagination( order = 'desc', pageNumber = 1, rowsPerPage = 10, + searchTerm = '', ): Promise { try { - const query = `sort=${sort}&order=${order}&page=${pageNumber}&rows=${rowsPerPage}`; + const query = `sort=${sort}&order=${order}&page=${pageNumber}&rows=${rowsPerPage}&search=${searchTerm}`; const response = await userService.getDocsWithPagination(query); const data = await response.json(); const docs: Doc[] = []; diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 1e5a610e..bb45b9ff 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -40,25 +40,18 @@ const Documents: React.FC = ({ const { t } = useTranslation(); const dispatch = useDispatch(); // State for search input - const [searchTerm, setSearchTerm] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); // State for modal: active/inactive const [modalState, setModalState] = useState('INACTIVE'); // Initialize with inactive state - const [isOnboarding, setIsOnboarding] = useState(false); // State for onboarding flag - const [loading, setLoading] = useState(false); + const [isOnboarding, setIsOnboarding] = useState(false); // State for onboarding flag + const [loading, setLoading] = useState(false); const [sortField, setSortField] = useState<'date' | 'tokens'>('date'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); // Pagination const [currentPage, setCurrentPage] = useState(1); const [rowsPerPage, setRowsPerPage] = useState(10); const [totalPages, setTotalPages] = useState(1); - // const [totalDocuments, setTotalDocuments] = useState(0); - // Filter documents based on the search term - const filteredDocuments = paginatedDocuments?.filter((document) => - document.name.toLowerCase().includes(searchTerm.toLowerCase()), - ); - // State for documents - const currentDocuments = filteredDocuments ?? []; - console.log('currentDocuments', currentDocuments); + const currentDocuments = paginatedDocuments ?? []; const syncOptions = [ { label: 'Never', value: 'never' }, { label: 'Daily', value: 'daily' }, @@ -84,7 +77,7 @@ const Documents: React.FC = ({ setSortOrder('desc'); } } - getDocsWithPagination(sortField, sortOrder, page, rowsPerPg) + getDocsWithPagination(sortField, sortOrder, page, rowsPerPg, searchTerm) .then((data) => { dispatch(setPaginatedDocuments(data ? data.docs : [])); setTotalPages(data ? data.totalPages : 0); @@ -130,6 +123,10 @@ const Documents: React.FC = ({ } }, [modalState, sortField, currentPage, rowsPerPage]); + useEffect(() => { + refreshDocs(sortField, 1, rowsPerPage); + }, [searchTerm]); + return (
@@ -143,7 +140,13 @@ const Documents: React.FC = ({ type="text" id="document-search-input" value={searchTerm} - onChange={(e) => setSearchTerm(e.target.value)} // Handle search input change + onChange={(e) => { + setSearchTerm(e.target.value); + setCurrentPage(1); + // refreshDocs(sortField, 1, rowsPerPage); + // do not call refreshDocs here the state is async + // so it will not have the updated value + }} // Handle search input change />
+ {/*}
{t('settings.documents.type')}
+ */} = ({ ? formatTokens(+document.tokens) : ''} + {/*} {document.type === 'remote' ? 'Pre-loaded' : 'Private'} + */}
{document.type !== 'remote' && ( From dae0942d03ea24da04df1f37a5a4ca3b45861c85 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sat, 23 Nov 2024 02:29:27 +0530 Subject: [PATCH 043/101] (refactor): separate browser ready builds --- extensions/react-widget/package-lock.json | 4 ++-- extensions/react-widget/package.json | 20 ++++------------- extensions/react-widget/src/browser.tsx | 22 +++++++++++++++++++ .../react-widget/src/components/SearchBar.tsx | 6 ++--- extensions/react-widget/src/index.ts | 1 + extensions/react-widget/src/main.tsx | 22 ++----------------- 6 files changed, 34 insertions(+), 41 deletions(-) create mode 100644 extensions/react-widget/src/browser.tsx diff --git a/extensions/react-widget/package-lock.json b/extensions/react-widget/package-lock.json index 6d736c6f..6e43997a 100644 --- a/extensions/react-widget/package-lock.json +++ b/extensions/react-widget/package-lock.json @@ -1,12 +1,12 @@ { "name": "docsgpt", - "version": "0.4.7", + "version": "0.4.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "docsgpt", - "version": "0.4.7", + "version": "0.4.8", "license": "Apache-2.0", "dependencies": { "@babel/plugin-transform-flow-strip-types": "^7.23.3", diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json index 12a66939..35676fc1 100644 --- a/extensions/react-widget/package.json +++ b/extensions/react-widget/package.json @@ -1,6 +1,6 @@ { - "name": "docsgpt", - "version": "0.4.7", + "name": "docsgpt-react", + "version": "0.4.8", "private": false, "description": "DocsGPT 🦖 is an innovative open-source tool designed to simplify the retrieval of information from project documentation using advanced GPT models 🤖.", "source": "./src/index.html", @@ -11,18 +11,6 @@ "dist", "package.json" ], - "targets": { - "modern": { - "engines": { - "browsers": "Chrome 80" - } - }, - "legacy": { - "engines": { - "browsers": "> 0.5%, last 2 versions, not dead" - } - } - }, "@parcel/resolver-default": { "packageExports": true }, @@ -30,9 +18,9 @@ "styled-components": "^5" }, "scripts": { - "build": "parcel build src/main.tsx --public-url ./", + "build": "parcel build src/browser.tsx --public-url ./", "build:react": "parcel build src/index.ts", - "serve": "parcel serve -p 3000", + "serve": "parcel serve -p 3000", "dev": "parcel -p 3000", "test": "jest", "lint": "eslint", diff --git a/extensions/react-widget/src/browser.tsx b/extensions/react-widget/src/browser.tsx new file mode 100644 index 00000000..8bee7748 --- /dev/null +++ b/extensions/react-widget/src/browser.tsx @@ -0,0 +1,22 @@ +//exports browser ready methods + +import { createRoot } from "react-dom/client"; + +import { DocsGPTWidget } from './components/DocsGPTWidget'; +import { SearchBar } from './components/SearchBar'; +import React from "react"; +if (typeof window !== 'undefined') { + const renderWidget = (elementId: string, props = {}) => { + const root = createRoot(document.getElementById(elementId) as HTMLElement); + root.render(); + }; + const renderSearchBar = (elementId: string, props = {}) => { + const root = createRoot(document.getElementById(elementId) as HTMLElement); + root.render(); + }; + (window as any).renderDocsGPTWidget = renderWidget; + + (window as any).renderSearchBar = renderSearchBar; +} + +export { DocsGPTWidget, SearchBar }; diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index aff036d0..e88bdafd 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -69,7 +69,6 @@ const SearchResults = styled.div` position: absolute; display: block; background-color: ${props => props.theme.primary.bg}; - opacity: 90%; border: 1px solid rgba(0, 0, 0, .1); border-radius: 12px; padding: 8px; @@ -287,7 +286,7 @@ export const SearchBar = ({ debounceTimeout.current = setTimeout(() => { getSearchResults(input, apiKey, apiHost, abortController.signal) .then((data) => setResults(data)) - .catch((err) => console.log(err)) + .catch((err) => !abortController.signal.aborted && console.log(err)) .finally(() => setLoading(false)); }, 500); @@ -340,10 +339,11 @@ export const SearchBar = ({ {!loading ? (results.length > 0 ? - results.map((res) => { + results.map((res, key) => { const containsSource = res.source !== 'local'; return ( { if (!containsSource) return; window.open(res.source, '_blank', 'noopener, noreferrer') diff --git a/extensions/react-widget/src/index.ts b/extensions/react-widget/src/index.ts index e29b85a5..5f2e30e8 100644 --- a/extensions/react-widget/src/index.ts +++ b/extensions/react-widget/src/index.ts @@ -1,2 +1,3 @@ +//exports methods for React export {SearchBar} from "./components/SearchBar" export { DocsGPTWidget } from "./components/DocsGPTWidget"; diff --git a/extensions/react-widget/src/main.tsx b/extensions/react-widget/src/main.tsx index a8542e26..a1a47065 100644 --- a/extensions/react-widget/src/main.tsx +++ b/extensions/react-widget/src/main.tsx @@ -1,25 +1,7 @@ - +//development import { createRoot } from "react-dom/client"; import { App } from "./App"; -import { DocsGPTWidget } from './components/DocsGPTWidget'; -import { SearchBar } from './components/SearchBar'; import React from "react"; -if (typeof window !== 'undefined') { - const renderWidget = (elementId: string, props = {}) => { - const root = createRoot(document.getElementById(elementId) as HTMLElement); - root.render(); - }; - const renderSearchBar = (elementId: string, props = {}) => { - const root = createRoot(document.getElementById(elementId) as HTMLElement); - root.render(); - }; - (window as any).renderDocsGPTWidget = renderWidget; - - (window as any).renderSearchBar = renderSearchBar; -} const container = document.getElementById("app") as HTMLElement; const root = createRoot(container) -root.render(); - -export { DocsGPTWidget }; -export { SearchBar } +root.render(); \ No newline at end of file From fb4bb54aca71dfb58cc28a82503de1efd6f46360 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sat, 23 Nov 2024 02:44:06 +0530 Subject: [PATCH 044/101] (upgrade) v0.4.8 --- docs/package-lock.json | 237 +++++++++++++++++++++++++-- docs/package.json | 2 +- docs/pages/_app.mdx | 2 +- extensions/react-widget/package.json | 12 ++ 4 files changed, 240 insertions(+), 13 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 10418138..eb26e8ed 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -7,7 +7,7 @@ "license": "MIT", "dependencies": { "@vercel/analytics": "^1.1.1", - "docsgpt": "^0.4.7", + "docsgpt-react": "^0.4.8", "next": "^14.2.12", "nextra": "^2.13.2", "nextra-theme-docs": "^2.13.2", @@ -3575,10 +3575,10 @@ "node": ">=0.3.1" } }, - "node_modules/docsgpt": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/docsgpt/-/docsgpt-0.4.7.tgz", - "integrity": "sha512-4YZzLZo6ybudFrJVUQflDFeWzFiTATRWB9myrGSpLigyuMMzax1ZAY2xFallZLuEG9VVm0mOgkx3ssWHLrXWkQ==", + "node_modules/docsgpt-react": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/docsgpt-react/-/docsgpt-react-0.4.8.tgz", + "integrity": "sha512-A4+wZVDDtX6J84SHBl2VZpDAydy1kwKUOeGcIiq0uY+JmP+ZKst879vsfgEN1WY3ZNo8F+AC1w+3g/jOZ3Ma8g==", "license": "Apache-2.0", "dependencies": { "@babel/plugin-transform-flow-strip-types": "^7.23.3", @@ -6634,15 +6634,16 @@ }, "node_modules/npm/node_modules/@colors/colors": { "version": "1.5.0", + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.1.90" } }, "node_modules/npm/node_modules/@isaacs/cliui": { "version": "8.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6659,6 +6660,7 @@ }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -6670,11 +6672,13 @@ }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -6691,6 +6695,7 @@ }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -6705,11 +6710,13 @@ }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/agent": { "version": "2.2.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6725,6 +6732,7 @@ }, "node_modules/npm/node_modules/@npmcli/arborist": { "version": "7.4.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6771,6 +6779,7 @@ }, "node_modules/npm/node_modules/@npmcli/config": { "version": "8.2.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6789,6 +6798,7 @@ }, "node_modules/npm/node_modules/@npmcli/disparity-colors": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6800,6 +6810,7 @@ }, "node_modules/npm/node_modules/@npmcli/disparity-colors/node_modules/ansi-styles": { "version": "4.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -6814,6 +6825,7 @@ }, "node_modules/npm/node_modules/@npmcli/fs": { "version": "3.1.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6825,6 +6837,7 @@ }, "node_modules/npm/node_modules/@npmcli/git": { "version": "5.0.4", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6843,6 +6856,7 @@ }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { "version": "2.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6858,6 +6872,7 @@ }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { "version": "3.0.4", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6872,6 +6887,7 @@ }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { "version": "7.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6886,6 +6902,7 @@ }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -6894,6 +6911,7 @@ }, "node_modules/npm/node_modules/@npmcli/node-gyp": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -6902,6 +6920,7 @@ }, "node_modules/npm/node_modules/@npmcli/package-json": { "version": "5.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6919,6 +6938,7 @@ }, "node_modules/npm/node_modules/@npmcli/promise-spawn": { "version": "7.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6930,6 +6950,7 @@ }, "node_modules/npm/node_modules/@npmcli/query": { "version": "3.1.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6941,6 +6962,7 @@ }, "node_modules/npm/node_modules/@npmcli/redact": { "version": "1.1.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -6949,6 +6971,7 @@ }, "node_modules/npm/node_modules/@npmcli/run-script": { "version": "7.0.4", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -6964,15 +6987,16 @@ }, "node_modules/npm/node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=14" } }, "node_modules/npm/node_modules/@sigstore/bundle": { "version": "2.2.0", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -6984,6 +7008,7 @@ }, "node_modules/npm/node_modules/@sigstore/core": { "version": "1.0.0", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "engines": { @@ -6992,6 +7017,7 @@ }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { "version": "0.3.0", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "engines": { @@ -7000,6 +7026,7 @@ }, "node_modules/npm/node_modules/@sigstore/sign": { "version": "2.2.3", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -7014,6 +7041,7 @@ }, "node_modules/npm/node_modules/@sigstore/tuf": { "version": "2.3.2", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -7026,6 +7054,7 @@ }, "node_modules/npm/node_modules/@sigstore/verify": { "version": "1.1.0", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -7039,6 +7068,7 @@ }, "node_modules/npm/node_modules/@tufjs/canonical-json": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7047,6 +7077,7 @@ }, "node_modules/npm/node_modules/@tufjs/models": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7059,6 +7090,7 @@ }, "node_modules/npm/node_modules/abbrev": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7067,6 +7099,7 @@ }, "node_modules/npm/node_modules/agent-base": { "version": "7.1.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7078,6 +7111,7 @@ }, "node_modules/npm/node_modules/aggregate-error": { "version": "3.1.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7090,6 +7124,7 @@ }, "node_modules/npm/node_modules/ansi-regex": { "version": "5.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7098,6 +7133,7 @@ }, "node_modules/npm/node_modules/ansi-styles": { "version": "6.2.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7109,16 +7145,19 @@ }, "node_modules/npm/node_modules/aproba": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/archy": { "version": "1.0.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/are-we-there-yet": { "version": "4.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7127,11 +7166,13 @@ }, "node_modules/npm/node_modules/balanced-match": { "version": "1.0.2", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/bin-links": { "version": "4.0.3", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7146,6 +7187,7 @@ }, "node_modules/npm/node_modules/binary-extensions": { "version": "2.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7157,6 +7199,7 @@ }, "node_modules/npm/node_modules/brace-expansion": { "version": "2.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7165,6 +7208,7 @@ }, "node_modules/npm/node_modules/builtins": { "version": "5.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7173,6 +7217,7 @@ }, "node_modules/npm/node_modules/cacache": { "version": "18.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7195,6 +7240,7 @@ }, "node_modules/npm/node_modules/chalk": { "version": "5.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7206,6 +7252,7 @@ }, "node_modules/npm/node_modules/chownr": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7214,6 +7261,7 @@ }, "node_modules/npm/node_modules/ci-info": { "version": "4.0.0", + "extraneous": true, "funding": [ { "type": "github", @@ -7228,6 +7276,7 @@ }, "node_modules/npm/node_modules/cidr-regex": { "version": "4.0.3", + "extraneous": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -7239,6 +7288,7 @@ }, "node_modules/npm/node_modules/clean-stack": { "version": "2.2.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7247,6 +7297,7 @@ }, "node_modules/npm/node_modules/cli-columns": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7259,6 +7310,7 @@ }, "node_modules/npm/node_modules/cli-table3": { "version": "0.6.4", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7273,6 +7325,7 @@ }, "node_modules/npm/node_modules/clone": { "version": "1.0.4", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7281,6 +7334,7 @@ }, "node_modules/npm/node_modules/cmd-shim": { "version": "6.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7289,6 +7343,7 @@ }, "node_modules/npm/node_modules/color-convert": { "version": "2.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7300,11 +7355,13 @@ }, "node_modules/npm/node_modules/color-name": { "version": "1.1.4", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/color-support": { "version": "1.1.3", + "extraneous": true, "inBundle": true, "license": "ISC", "bin": { @@ -7313,6 +7370,7 @@ }, "node_modules/npm/node_modules/columnify": { "version": "1.6.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7325,16 +7383,19 @@ }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/console-control-strings": { "version": "1.1.0", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/cross-spawn": { "version": "7.0.3", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7348,6 +7409,7 @@ }, "node_modules/npm/node_modules/cross-spawn/node_modules/which": { "version": "2.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7362,6 +7424,7 @@ }, "node_modules/npm/node_modules/cssesc": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "bin": { @@ -7373,6 +7436,7 @@ }, "node_modules/npm/node_modules/debug": { "version": "4.3.4", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7389,11 +7453,13 @@ }, "node_modules/npm/node_modules/debug/node_modules/ms": { "version": "2.1.2", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/defaults": { "version": "1.0.4", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7405,6 +7471,7 @@ }, "node_modules/npm/node_modules/diff": { "version": "5.2.0", + "extraneous": true, "inBundle": true, "license": "BSD-3-Clause", "engines": { @@ -7413,25 +7480,28 @@ }, "node_modules/npm/node_modules/eastasianwidth": { "version": "0.2.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/encoding": { "version": "0.1.13", + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "iconv-lite": "^0.6.2" } }, "node_modules/npm/node_modules/env-paths": { "version": "2.2.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7440,16 +7510,19 @@ }, "node_modules/npm/node_modules/err-code": { "version": "2.0.3", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/exponential-backoff": { "version": "3.1.1", + "extraneous": true, "inBundle": true, "license": "Apache-2.0" }, "node_modules/npm/node_modules/fastest-levenshtein": { "version": "1.0.16", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7458,6 +7531,7 @@ }, "node_modules/npm/node_modules/foreground-child": { "version": "3.1.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7473,6 +7547,7 @@ }, "node_modules/npm/node_modules/fs-minipass": { "version": "3.0.3", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7484,6 +7559,7 @@ }, "node_modules/npm/node_modules/function-bind": { "version": "1.1.2", + "extraneous": true, "inBundle": true, "license": "MIT", "funding": { @@ -7492,6 +7568,7 @@ }, "node_modules/npm/node_modules/gauge": { "version": "5.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7510,6 +7587,7 @@ }, "node_modules/npm/node_modules/glob": { "version": "10.3.12", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7531,16 +7609,19 @@ }, "node_modules/npm/node_modules/graceful-fs": { "version": "4.2.11", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/has-unicode": { "version": "2.0.1", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/hasown": { "version": "2.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7552,6 +7633,7 @@ }, "node_modules/npm/node_modules/hosted-git-info": { "version": "7.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7563,11 +7645,13 @@ }, "node_modules/npm/node_modules/http-cache-semantics": { "version": "4.1.1", + "extraneous": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/http-proxy-agent": { "version": "7.0.2", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7580,6 +7664,7 @@ }, "node_modules/npm/node_modules/https-proxy-agent": { "version": "7.0.4", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7592,9 +7677,9 @@ }, "node_modules/npm/node_modules/iconv-lite": { "version": "0.6.3", + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -7604,6 +7689,7 @@ }, "node_modules/npm/node_modules/ignore-walk": { "version": "6.0.4", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7615,6 +7701,7 @@ }, "node_modules/npm/node_modules/imurmurhash": { "version": "0.1.4", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7623,6 +7710,7 @@ }, "node_modules/npm/node_modules/indent-string": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7631,6 +7719,7 @@ }, "node_modules/npm/node_modules/ini": { "version": "4.1.2", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7639,6 +7728,7 @@ }, "node_modules/npm/node_modules/init-package-json": { "version": "6.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7656,6 +7746,7 @@ }, "node_modules/npm/node_modules/ip-address": { "version": "9.0.5", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7668,11 +7759,13 @@ }, "node_modules/npm/node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", + "extraneous": true, "inBundle": true, "license": "BSD-3-Clause" }, "node_modules/npm/node_modules/ip-regex": { "version": "5.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7684,6 +7777,7 @@ }, "node_modules/npm/node_modules/is-cidr": { "version": "5.0.3", + "extraneous": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -7695,6 +7789,7 @@ }, "node_modules/npm/node_modules/is-core-module": { "version": "2.13.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -7706,6 +7801,7 @@ }, "node_modules/npm/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7714,16 +7810,19 @@ }, "node_modules/npm/node_modules/is-lambda": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/isexe": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/jackspeak": { "version": "2.3.6", + "extraneous": true, "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -7741,11 +7840,13 @@ }, "node_modules/npm/node_modules/jsbn": { "version": "1.1.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/json-parse-even-better-errors": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -7754,6 +7855,7 @@ }, "node_modules/npm/node_modules/json-stringify-nice": { "version": "1.1.4", + "extraneous": true, "inBundle": true, "license": "ISC", "funding": { @@ -7765,21 +7867,25 @@ "engines": [ "node >= 0.2.0" ], + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/just-diff": { "version": "6.0.2", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/just-diff-apply": { "version": "5.5.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { "version": "8.0.3", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7792,6 +7898,7 @@ }, "node_modules/npm/node_modules/libnpmdiff": { "version": "6.0.8", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7811,6 +7918,7 @@ }, "node_modules/npm/node_modules/libnpmexec": { "version": "7.0.9", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7832,6 +7940,7 @@ }, "node_modules/npm/node_modules/libnpmfund": { "version": "5.0.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7843,6 +7952,7 @@ }, "node_modules/npm/node_modules/libnpmhook": { "version": "10.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7855,6 +7965,7 @@ }, "node_modules/npm/node_modules/libnpmorg": { "version": "6.0.3", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7867,6 +7978,7 @@ }, "node_modules/npm/node_modules/libnpmpack": { "version": "6.0.8", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7881,6 +7993,7 @@ }, "node_modules/npm/node_modules/libnpmpublish": { "version": "9.0.5", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7899,6 +8012,7 @@ }, "node_modules/npm/node_modules/libnpmsearch": { "version": "7.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7910,6 +8024,7 @@ }, "node_modules/npm/node_modules/libnpmteam": { "version": "6.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7922,6 +8037,7 @@ }, "node_modules/npm/node_modules/libnpmversion": { "version": "5.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7937,6 +8053,7 @@ }, "node_modules/npm/node_modules/lru-cache": { "version": "10.2.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7945,6 +8062,7 @@ }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "13.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7966,6 +8084,7 @@ }, "node_modules/npm/node_modules/minimatch": { "version": "9.0.4", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7980,6 +8099,7 @@ }, "node_modules/npm/node_modules/minipass": { "version": "7.0.4", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -7988,6 +8108,7 @@ }, "node_modules/npm/node_modules/minipass-collect": { "version": "2.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -7999,6 +8120,7 @@ }, "node_modules/npm/node_modules/minipass-fetch": { "version": "3.0.4", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8015,6 +8137,7 @@ }, "node_modules/npm/node_modules/minipass-flush": { "version": "1.0.5", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8026,6 +8149,7 @@ }, "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8037,6 +8161,7 @@ }, "node_modules/npm/node_modules/minipass-json-stream": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8046,6 +8171,7 @@ }, "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { "version": "3.3.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8057,6 +8183,7 @@ }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8068,6 +8195,7 @@ }, "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8079,6 +8207,7 @@ }, "node_modules/npm/node_modules/minipass-sized": { "version": "1.0.3", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8090,6 +8219,7 @@ }, "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8101,6 +8231,7 @@ }, "node_modules/npm/node_modules/minizlib": { "version": "2.1.2", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8113,6 +8244,7 @@ }, "node_modules/npm/node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8124,6 +8256,7 @@ }, "node_modules/npm/node_modules/mkdirp": { "version": "1.0.4", + "extraneous": true, "inBundle": true, "license": "MIT", "bin": { @@ -8135,11 +8268,13 @@ }, "node_modules/npm/node_modules/ms": { "version": "2.1.3", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/mute-stream": { "version": "1.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8148,6 +8283,7 @@ }, "node_modules/npm/node_modules/negotiator": { "version": "0.6.3", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8156,6 +8292,7 @@ }, "node_modules/npm/node_modules/node-gyp": { "version": "10.1.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8179,6 +8316,7 @@ }, "node_modules/npm/node_modules/nopt": { "version": "7.2.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8193,6 +8331,7 @@ }, "node_modules/npm/node_modules/normalize-package-data": { "version": "6.0.0", + "extraneous": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -8207,6 +8346,7 @@ }, "node_modules/npm/node_modules/npm-audit-report": { "version": "5.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8215,6 +8355,7 @@ }, "node_modules/npm/node_modules/npm-bundled": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8226,6 +8367,7 @@ }, "node_modules/npm/node_modules/npm-install-checks": { "version": "6.3.0", + "extraneous": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -8237,6 +8379,7 @@ }, "node_modules/npm/node_modules/npm-normalize-package-bin": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8245,6 +8388,7 @@ }, "node_modules/npm/node_modules/npm-package-arg": { "version": "11.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8259,6 +8403,7 @@ }, "node_modules/npm/node_modules/npm-packlist": { "version": "8.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8270,6 +8415,7 @@ }, "node_modules/npm/node_modules/npm-pick-manifest": { "version": "9.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8284,6 +8430,7 @@ }, "node_modules/npm/node_modules/npm-profile": { "version": "9.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8296,6 +8443,7 @@ }, "node_modules/npm/node_modules/npm-registry-fetch": { "version": "16.2.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8314,6 +8462,7 @@ }, "node_modules/npm/node_modules/npm-user-validate": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "BSD-2-Clause", "engines": { @@ -8322,6 +8471,7 @@ }, "node_modules/npm/node_modules/npmlog": { "version": "7.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8336,6 +8486,7 @@ }, "node_modules/npm/node_modules/p-map": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8350,6 +8501,7 @@ }, "node_modules/npm/node_modules/pacote": { "version": "17.0.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8381,6 +8533,7 @@ }, "node_modules/npm/node_modules/parse-conflict-json": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8394,6 +8547,7 @@ }, "node_modules/npm/node_modules/path-key": { "version": "3.1.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8402,6 +8556,7 @@ }, "node_modules/npm/node_modules/path-scurry": { "version": "1.10.2", + "extraneous": true, "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -8417,6 +8572,7 @@ }, "node_modules/npm/node_modules/postcss-selector-parser": { "version": "6.0.15", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8429,6 +8585,7 @@ }, "node_modules/npm/node_modules/proc-log": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8437,6 +8594,7 @@ }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "funding": { @@ -8445,6 +8603,7 @@ }, "node_modules/npm/node_modules/promise-call-limit": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "funding": { @@ -8453,11 +8612,13 @@ }, "node_modules/npm/node_modules/promise-inflight": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8470,6 +8631,7 @@ }, "node_modules/npm/node_modules/promzard": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8481,6 +8643,7 @@ }, "node_modules/npm/node_modules/qrcode-terminal": { "version": "0.12.0", + "extraneous": true, "inBundle": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" @@ -8488,6 +8651,7 @@ }, "node_modules/npm/node_modules/read": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8499,6 +8663,7 @@ }, "node_modules/npm/node_modules/read-cmd-shim": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8507,6 +8672,7 @@ }, "node_modules/npm/node_modules/read-package-json": { "version": "7.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8521,6 +8687,7 @@ }, "node_modules/npm/node_modules/read-package-json-fast": { "version": "3.0.2", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8533,6 +8700,7 @@ }, "node_modules/npm/node_modules/retry": { "version": "0.12.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8541,12 +8709,13 @@ }, "node_modules/npm/node_modules/safer-buffer": { "version": "2.1.2", + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/npm/node_modules/semver": { "version": "7.6.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8561,6 +8730,7 @@ }, "node_modules/npm/node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8572,11 +8742,13 @@ }, "node_modules/npm/node_modules/set-blocking": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/shebang-command": { "version": "2.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8588,6 +8760,7 @@ }, "node_modules/npm/node_modules/shebang-regex": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8596,6 +8769,7 @@ }, "node_modules/npm/node_modules/signal-exit": { "version": "4.1.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8607,6 +8781,7 @@ }, "node_modules/npm/node_modules/sigstore": { "version": "2.2.2", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -8623,6 +8798,7 @@ }, "node_modules/npm/node_modules/smart-buffer": { "version": "4.2.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8632,6 +8808,7 @@ }, "node_modules/npm/node_modules/socks": { "version": "2.8.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8645,6 +8822,7 @@ }, "node_modules/npm/node_modules/socks-proxy-agent": { "version": "8.0.2", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8658,6 +8836,7 @@ }, "node_modules/npm/node_modules/spdx-correct": { "version": "3.2.0", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -8667,11 +8846,13 @@ }, "node_modules/npm/node_modules/spdx-exceptions": { "version": "2.5.0", + "extraneous": true, "inBundle": true, "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8681,11 +8862,13 @@ }, "node_modules/npm/node_modules/spdx-license-ids": { "version": "3.0.17", + "extraneous": true, "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { "version": "10.0.5", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8697,6 +8880,7 @@ }, "node_modules/npm/node_modules/string-width": { "version": "4.2.3", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8711,6 +8895,7 @@ "node_modules/npm/node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8724,6 +8909,7 @@ }, "node_modules/npm/node_modules/strip-ansi": { "version": "6.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8736,6 +8922,7 @@ "node_modules/npm/node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8747,6 +8934,7 @@ }, "node_modules/npm/node_modules/supports-color": { "version": "9.4.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8758,6 +8946,7 @@ }, "node_modules/npm/node_modules/tar": { "version": "6.2.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8774,6 +8963,7 @@ }, "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8785,6 +8975,7 @@ }, "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { "version": "3.3.6", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8796,6 +8987,7 @@ }, "node_modules/npm/node_modules/tar/node_modules/minipass": { "version": "5.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8804,16 +8996,19 @@ }, "node_modules/npm/node_modules/text-table": { "version": "0.2.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/tiny-relative-date": { "version": "1.3.0", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/treeverse": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8822,6 +9017,7 @@ }, "node_modules/npm/node_modules/tuf-js": { "version": "2.2.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8835,6 +9031,7 @@ }, "node_modules/npm/node_modules/unique-filename": { "version": "3.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8846,6 +9043,7 @@ }, "node_modules/npm/node_modules/unique-slug": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8857,11 +9055,13 @@ }, "node_modules/npm/node_modules/util-deprecate": { "version": "1.0.2", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/validate-npm-package-license": { "version": "3.0.4", + "extraneous": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -8871,6 +9071,7 @@ }, "node_modules/npm/node_modules/validate-npm-package-name": { "version": "5.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8882,11 +9083,13 @@ }, "node_modules/npm/node_modules/walk-up-path": { "version": "3.0.1", + "extraneous": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/wcwidth": { "version": "1.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8895,6 +9098,7 @@ }, "node_modules/npm/node_modules/which": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8909,6 +9113,7 @@ }, "node_modules/npm/node_modules/which/node_modules/isexe": { "version": "3.1.1", + "extraneous": true, "inBundle": true, "license": "ISC", "engines": { @@ -8917,6 +9122,7 @@ }, "node_modules/npm/node_modules/wide-align": { "version": "1.1.5", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -8925,6 +9131,7 @@ }, "node_modules/npm/node_modules/wrap-ansi": { "version": "8.1.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8942,6 +9149,7 @@ "node_modules/npm/node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8958,6 +9166,7 @@ }, "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -8972,6 +9181,7 @@ }, "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -8983,11 +9193,13 @@ }, "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { "version": "9.2.2", + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { "version": "5.1.2", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -9004,6 +9216,7 @@ }, "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "7.1.0", + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -9018,6 +9231,7 @@ }, "node_modules/npm/node_modules/write-file-atomic": { "version": "5.0.1", + "extraneous": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -9030,6 +9244,7 @@ }, "node_modules/npm/node_modules/yallist": { "version": "4.0.0", + "extraneous": true, "inBundle": true, "license": "ISC" }, diff --git a/docs/package.json b/docs/package.json index cc3e786d..96de9ea8 100644 --- a/docs/package.json +++ b/docs/package.json @@ -7,7 +7,7 @@ "license": "MIT", "dependencies": { "@vercel/analytics": "^1.1.1", - "docsgpt": "^0.4.7", + "docsgpt-react": "^0.4.8", "next": "^14.2.12", "nextra": "^2.13.2", "nextra-theme-docs": "^2.13.2", diff --git a/docs/pages/_app.mdx b/docs/pages/_app.mdx index 1cb8cadd..0111cd96 100644 --- a/docs/pages/_app.mdx +++ b/docs/pages/_app.mdx @@ -1,4 +1,4 @@ -import { DocsGPTWidget } from "docsgpt"; +import { DocsGPTWidget } from "docsgpt-react"; export default function MyApp({ Component, pageProps }) { return ( diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json index 35676fc1..c6401d30 100644 --- a/extensions/react-widget/package.json +++ b/extensions/react-widget/package.json @@ -11,6 +11,18 @@ "dist", "package.json" ], + "targets": { + "modern": { + "engines": { + "browsers": "Chrome 80" + } + }, + "legacy": { + "engines": { + "browsers": "> 0.5%, last 2 versions, not dead" + } + } + }, "@parcel/resolver-default": { "packageExports": true }, From ce975c5d93036cfdf63d96a3ccece213a6cc65ff Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sat, 23 Nov 2024 03:09:03 +0530 Subject: [PATCH 045/101] (documentation): udpate with search bar --- docs/pages/Extensions/react-widget.md | 111 +++++++++++++++++++++++--- extensions/react-widget/README.md | 75 ++++++++++++++++- 2 files changed, 171 insertions(+), 15 deletions(-) diff --git a/docs/pages/Extensions/react-widget.md b/docs/pages/Extensions/react-widget.md index 1859b558..8429e377 100644 --- a/docs/pages/Extensions/react-widget.md +++ b/docs/pages/Extensions/react-widget.md @@ -29,18 +29,30 @@ Now, you can use the widget in your component like this : buttonBg = "#222327" /> ``` -To tailor the widget to your needs, you can configure the following props in your component: -1. `apiHost` — The URL of your DocsGPT API. -2. `theme` — Allows to select your specific theme (dark or light). -3. `apiKey` — Usually, it's empty. -4. `avatar`: Specifies the URL of the avatar or image representing the chatbot. -5. `title`: Sets the title text displayed in the chatbot interface. -6. `description`: Provides a brief description of the chatbot's purpose or functionality. -7. `heroTitle`: Displays a welcome title when users interact with the chatbot. -8. `heroDescription`: Provide additional introductory text or information about the chatbot's capabilities. -9. `buttonIcon`: Specifies the url of the icon image for the widget. -10. `buttonBg`: Allows to specify the Background color of the widget. -11. `size`: Sets the size of the widget ( small, medium). +### Props Table for DocsGPT Widget + +| **Prop** | **Type** | **Default Value** | **Description** | +|--------------------|------------------|-------------------------------------------------------------|-----------------------------------------------------------------------------------------------------| +| **`apiHost`** | `string` | `"https://gptcloud.arc53.com"` | The URL of your DocsGPT API for vector search and chatbot queries. | +| **`apiKey`** | `string` | `""` | Your API key for authentication. Can be left empty if authentication is not required. | +| **`avatar`** | `string` | `"https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png"` | Specifies the URL of the avatar or image representing the chatbot. | +| **`title`** | `string` | `"Get AI assistance"` | Sets the title text displayed in the chatbot interface. | +| **`description`** | `string` | `"DocsGPT's AI Chatbot is here to help"` | Provides a brief description of the chatbot's purpose or functionality. | +| **`heroTitle`** | `string` | `"Welcome to DocsGPT !"` | Displays a welcome title when users interact with the chatbot. | +| **`heroDescription`** | `string` | `"This chatbot is built with DocsGPT and utilises GenAI, please review important information using sources."` | Provides additional introductory text or information about the chatbot's capabilities. | +| **`theme`** | `"dark" \| "light"` | `"dark"` | Allows you to select the theme for the chatbot interface. Accepts `"dark"` or `"light"`. | +| **`buttonIcon`** | `string` | `"https://your-icon"` | Specifies the URL of the icon image for the widget's launch button. | +| **`buttonBg`** | `string` | `"#222327"` | Sets the background color of the widget's launch button. | +| **`size`** | `"small" \| "medium"` | `"medium"` | Sets the size of the widget. Options are `"small"` or `"medium"`. | + +--- + +### Notes +- **Customizing Props:** All properties can be overridden when embedding the widget. For example, you can provide a unique avatar, title, or color scheme to better align with your brand. +- **Default Theme:** The widget defaults to the dark theme unless explicitly set to `"light"`. +- **API Key:** If the `apiKey` is not required for your application, leave it empty. + +This table provides a clear overview of the customization options available for tailoring the DocsGPT widget to fit your application. ### How to use DocsGPTWidget with [Nextra](https://nextra.site/) (Next.js + MDX) @@ -121,5 +133,80 @@ To link the widget to your api and your documents you can pass parameters to the ``` +# SearchBar + +The `SearchBar` component is an interactive search bar designed to provide search results based on **vector similarity search**. It also includes the capability to open the AI Chatbot, enabling users to query. + +--- + +### Importing the Component +```tsx +import { SearchBar } from "docsgpt-react"; +``` + +--- + +### Usage Example +```tsx + +``` + +--- + +## HTML embedding for Search bar + +```html + + + + + + SearchBar Embedding + + + + +
+ + + + + +``` + +### Props + +| **Prop** | **Type** | **Default Value** | **Description** | +|-----------------|-----------|-------------------------------------|--------------------------------------------------------------------------------------------------| +| **`apiKey`** | `string` | `"74039c6d-bff7-44ce-ae55-2973cbf13837"` | Your API key generated from the app. Used for authenticating requests. | +| **`apiHost`** | `string` | `"https://gptcloud.arc53.com"` | The base URL of the server hosting the vector similarity search and chatbot services. | +| **`theme`** | `"dark" \| "light"` | `"dark"` | The theme of the search bar. Accepts `"dark"` or `"light"`. | +| **`placeholder`** | `string` | `"Search or Ask AI..."` | Placeholder text displayed in the search input field. | +| **`width`** | `string` | `"256px"` | Width of the search bar. Accepts any valid CSS width value (e.g., `"300px"`, `"100%"`, `"20rem"`). | + + +Feel free to reach out if you need help customizing or extending the `SearchBar`! + +## Our github + +[DocsGPT](https://github.com/arc53/DocsGPT) + +You can find the source code in the extensions/react-widget folder. + For more information about React, refer to this [link here](https://react.dev/learn) diff --git a/extensions/react-widget/README.md b/extensions/react-widget/README.md index b4159578..5b6222d2 100644 --- a/extensions/react-widget/README.md +++ b/extensions/react-widget/README.md @@ -13,7 +13,7 @@ npm install docsgpt ### React ```javascript - import { DocsGPTWidget } from "docsgpt"; + import { DocsGPTWidget } from "docsgpt-react"; const App = () => { return ; @@ -23,11 +23,11 @@ npm install docsgpt To link the widget to your api and your documents you can pass parameters to the component. ```javascript - import { DocsGPTWidget } from "docsgpt"; + import { DocsGPTWidget } from "docsgpt-react"; const App = () => { return ``` +# SearchBar + +The `SearchBar` component is an interactive search bar designed to provide search results based on **vector similarity search**. It also includes the capability to open the AI Chatbot, enabling users to query. + +--- + +### Importing the Component +```tsx +import { SearchBar } from "docsgpt-react"; +``` + +--- + +### Usage Example +```tsx + +``` + +--- + +## HTML embedding for Search bar + +```html + + + + + + SearchBar Embedding + + + + +
+ + + + + +``` + +### Props + +| **Prop** | **Type** | **Default Value** | **Description** | +|-----------------|-----------|-------------------------------------|--------------------------------------------------------------------------------------------------| +| **`apiKey`** | `string` | `"74039c6d-bff7-44ce-ae55-2973cbf13837"` | Your API key generated from the app. Used for authenticating requests. | +| **`apiHost`** | `string` | `"https://gptcloud.arc53.com"` | The base URL of the server hosting the vector similarity search and chatbot services. | +| **`theme`** | `"dark" \| "light"` | `"dark"` | The theme of the search bar. Accepts `"dark"` or `"light"`. | +| **`placeholder`** | `string` | `"Search or Ask AI..."` | Placeholder text displayed in the search input field. | +| **`width`** | `string` | `"256px"` | Width of the search bar. Accepts any valid CSS width value (e.g., `"300px"`, `"100%"`, `"20rem"`). | + + +Feel free to reach out if you need help customizing or extending the `SearchBar`! + ## Our github [DocsGPT](https://github.com/arc53/DocsGPT) From 8a67f18cd9bd9541934759a30f8f8bbb06e6688c Mon Sep 17 00:00:00 2001 From: Niharika Goulikar Date: Sat, 23 Nov 2024 06:13:07 +0000 Subject: [PATCH 046/101] Fixed minor ui issues --- frontend/src/conversation/ConversationBubble.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index bc131376..567b09e9 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -104,7 +104,7 @@ const ConversationBubble = forwardRef< setEditInputBox(e.target.value)} value={editInputBox} - className="ml-2 mr-2 rounded-[28px] py-[14px] px-[19px] border-[1.5px] border-black" + className="w-[85%] ml-2 mr-2 rounded-[28px] py-[12px] dark:border-[0.5px] dark:border-white dark:bg-raisin-black dark:text-white px-[18px] border-[1.5px] border-black" /> )}
{isEditClicked && ( -
+
+
+ {rowsPerPageOptions.map((option) => ( +
handleSelectRowsPerPage(option)} + className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ + rowsPerPage === option + ? 'bg-gray-100 dark:bg-neutral-700 dark:text-light-gray' + : 'bg-white dark:bg-dark-charcoal dark:text-light-gray' + }`} + > + {option} +
+ ))} +
+
+ {/* Pagination controls */}
Page {currentPage} of {totalPages}
-
@@ -85,7 +108,7 @@ const Pagination: React.FC = ({ > arrow @@ -96,7 +119,7 @@ const Pagination: React.FC = ({ > arrow @@ -107,7 +130,7 @@ const Pagination: React.FC = ({ > arrow diff --git a/frontend/src/components/DropdownMenu.tsx b/frontend/src/components/DropdownMenu.tsx index 787d3b84..2e6c922c 100644 --- a/frontend/src/components/DropdownMenu.tsx +++ b/frontend/src/components/DropdownMenu.tsx @@ -48,7 +48,7 @@ export default function DropdownMenu({
+ {/* outside scrollable area */} + { + setCurrentPage(page); + refreshDocs(undefined, page, rowsPerPage); + }} + onRowsPerPageChange={(rows) => { + setRowsPerPage(rows); + setCurrentPage(1); + refreshDocs(undefined, 1, rows); + }} + /> + {/* Conditionally render the Upload modal based on modalState */} {modalState === 'ACTIVE' && (
From e5bd194b6c7a29bd62e89f00e4a485de45d0f5a6 Mon Sep 17 00:00:00 2001 From: fadingNA Date: Sat, 23 Nov 2024 20:04:53 -0500 Subject: [PATCH 049/101] Remove dangling console log --- frontend/src/settings/Documents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 074d5516..7efd9016 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -134,7 +134,7 @@ const Documents: React.FC = ({ }; useEffect(() => { - console.log('modalState', modalState); + // console.log('modalState', modalState); if (modalState === 'INACTIVE') { refreshDocs(sortField, currentPage, rowsPerPage); } From 2709994ede7d644afb1973b2d1b0734552bba735 Mon Sep 17 00:00:00 2001 From: fadingNA Date: Sun, 24 Nov 2024 11:18:42 -0500 Subject: [PATCH 050/101] update APIKey Table and dark styling --- frontend/src/settings/APIKeys.tsx | 85 +++++++++++++++++------------ frontend/src/settings/Documents.tsx | 7 ++- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/frontend/src/settings/APIKeys.tsx b/frontend/src/settings/APIKeys.tsx index b039477c..6775ba87 100644 --- a/frontend/src/settings/APIKeys.tsx +++ b/frontend/src/settings/APIKeys.tsx @@ -109,41 +109,56 @@ export default function APIKeys() { {loading ? ( ) : ( - - - - - - - - - - - {!apiKeys?.length && ( - - - - )} - {apiKeys?.map((element, index) => ( - - - - - - - ))} - -
{t('settings.apiKeys.name')}{t('settings.apiKeys.sourceDoc')}{t('settings.apiKeys.key')}
- {t('settings.apiKeys.noData')} -
{element.name}{element.source}{element.key} - Delete handleDeleteKey(element.id)} - /> -
+
+
+
+ + + + + + + + + + + {!apiKeys?.length && ( + + + + )} + {Array.isArray(apiKeys) && + apiKeys?.map((element, index) => ( + + + + + + + ))} + +
{t('settings.apiKeys.name')} + {t('settings.apiKeys.sourceDoc')} + {t('settings.apiKeys.key')}
+ {t('settings.apiKeys.noData')} +
{element.name}{element.source}{element.key} + Delete handleDeleteKey(element.id)} + /> +
+
+
+
)}
diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 7efd9016..4003f655 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -183,7 +183,7 @@ const Documents: React.FC = ({ ) : (
-
+
@@ -228,7 +228,10 @@ const Documents: React.FC = ({ {!currentDocuments?.length && ( - From b5e5fb7f10337ea2c774a9b6a5f32e3c7cb080b1 Mon Sep 17 00:00:00 2001 From: fadingNA Date: Sun, 24 Nov 2024 17:02:57 -0500 Subject: [PATCH 051/101] fix table header text wrap --- frontend/src/settings/Documents.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 4003f655..0fd82aa8 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -186,7 +186,7 @@ const Documents: React.FC = ({
+ {t('settings.documents.noData')}
- + @@ -201,7 +201,7 @@ const Documents: React.FC = ({ /> - From d89bd0941d7cda6dc0287955ab9cf1829efb2916 Mon Sep 17 00:00:00 2001 From: fadingNA Date: Mon, 25 Nov 2024 08:35:24 -0500 Subject: [PATCH 053/101] change visible to block --- frontend/src/components/DocumentPagination.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/DocumentPagination.tsx b/frontend/src/components/DocumentPagination.tsx index af849ed4..f02ef1c0 100644 --- a/frontend/src/components/DocumentPagination.tsx +++ b/frontend/src/components/DocumentPagination.tsx @@ -62,17 +62,17 @@ const Pagination: React.FC = ({ {rowsPerPage}
{rowsPerPageOptions.map((option) => (
handleSelectRowsPerPage(option)} - className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ + className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ rowsPerPage === option ? 'bg-gray-100 dark:bg-neutral-700 dark:text-light-gray' : 'bg-white dark:bg-dark-charcoal dark:text-light-gray' From e9a2b8f03a3b8e7f732abf50107934edb248641c Mon Sep 17 00:00:00 2001 From: Niharika Goulikar Date: Tue, 26 Nov 2024 12:16:21 +0000 Subject: [PATCH 054/101] Fixed the feedback issue --- application/api/user/routes.py | 24 +++++++++++-------- frontend/src/conversation/Conversation.tsx | 2 +- .../src/conversation/ConversationBubble.tsx | 20 +++++++++++++--- .../src/conversation/conversationHandlers.ts | 4 ++++ 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index e305845d..0e4a9f4d 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -176,10 +176,12 @@ class SubmitFeedback(Resource): "FeedbackModel", { "question": fields.String( - required=True, description="The user question" + required=False, description="The user question" ), - "answer": fields.String(required=True, description="The AI answer"), + "answer": fields.String(required=False, description="The AI answer"), "feedback": fields.String(required=True, description="User feedback"), + "question_index":fields.Integer(required=True, description="The question number in that particular conversation"), + "conversation_id":fields.String(required=True, description="id of the particular conversation"), "api_key": fields.String(description="Optional API key"), }, ) @@ -189,23 +191,25 @@ class SubmitFeedback(Resource): ) def post(self): data = request.get_json() - required_fields = ["question", "answer", "feedback"] + required_fields = [ "feedback","conversation_id","question_index"] missing_fields = check_required_fields(data, required_fields) if missing_fields: return missing_fields - new_doc = { - "question": data["question"], - "answer": data["answer"], - "feedback": data["feedback"], - "timestamp": datetime.datetime.now(datetime.timezone.utc), - } if "api_key" in data: new_doc["api_key"] = data["api_key"] try: - feedback_collection.insert_one(new_doc) + conversations_collection.update_one( + {"_id": ObjectId(data["conversation_id"]), f"queries.{data["question_index"]}": {"$exists": True}}, + { + "$set": { + f"queries.{data["question_index"]}.feedback": data["feedback"] + } + } + ) + except Exception as err: return make_response(jsonify({"success": False, "error": str(err)}), 400) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index ed69064a..41bc8d2f 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -111,7 +111,7 @@ export default function Conversation() { const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => { const prevFeedback = query.feedback; dispatch(updateQuery({ index, query: { feedback } })); - handleSendFeedback(query.prompt, query.response!, feedback).catch(() => + handleSendFeedback(query.prompt, query.response!, feedback,conversationId as string,index).catch(() => dispatch(updateQuery({ index, query: { feedback: prevFeedback } })), ); }; diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 567b09e9..7fe1b003 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -429,6 +429,11 @@ const ConversationBubble = forwardRef< feedback === 'LIKE' || type !== 'ERROR' ? 'group-hover:lg:visible' : '' + } + ${ + feedback === 'DISLIKE' && type !== 'ERROR' + ? ' hidden' + : '' }`} >
@@ -445,11 +450,14 @@ const ConversationBubble = forwardRef< isLikeClicked || feedback === 'LIKE' ? 'fill-white-3000 stroke-purple-30 dark:fill-transparent' : 'fill-none stroke-gray-4000' - }`} + } `} onClick={() => { + if(feedback===undefined){ + console.log("liked") handleFeedback?.('LIKE'); setIsLikeClicked(true); setIsDislikeClicked(false); + } }} onMouseEnter={() => setIsLikeHovered(true)} onMouseLeave={() => setIsLikeHovered(false)} @@ -462,9 +470,13 @@ const ConversationBubble = forwardRef< !isDislikeClicked ? 'lg:invisible' : '' } ${ feedback === 'DISLIKE' || type !== 'ERROR' - ? 'group-hover:lg:visible' + ? ' group-hover:lg:visible' : '' - }`} + } ${ + feedback === 'LIKE' && type !== 'ERROR' + ? ' hidden' + : '' + } `} >
{ + if(feedback===undefined){ handleFeedback?.('DISLIKE'); setIsDislikeClicked(true); setIsLikeClicked(false); + } }} onMouseEnter={() => setIsDislikeHovered(true)} onMouseLeave={() => setIsDislikeHovered(false)} diff --git a/frontend/src/conversation/conversationHandlers.ts b/frontend/src/conversation/conversationHandlers.ts index be046bca..ea8ad6ea 100644 --- a/frontend/src/conversation/conversationHandlers.ts +++ b/frontend/src/conversation/conversationHandlers.ts @@ -202,12 +202,16 @@ export function handleSendFeedback( prompt: string, response: string, feedback: FEEDBACK, + conversation_id:string, + prompt_index:number ) { return conversationService .feedback({ question: prompt, answer: response, feedback: feedback, + conversation_id:conversation_id, + question_index:prompt_index }) .then((response) => { if (response.ok) { From faf031ce8037aac6abbbb35ad66447df98c5ff3b Mon Sep 17 00:00:00 2001 From: Niharika Goulikar Date: Tue, 26 Nov 2024 12:28:16 +0000 Subject: [PATCH 055/101] fixed linting issues --- application/api/user/routes.py | 4 --- .../src/conversation/ConversationBubble.tsx | 33 +++++++------------ 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 0e4a9f4d..96fc0e0f 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -196,10 +196,6 @@ class SubmitFeedback(Resource): if missing_fields: return missing_fields - - if "api_key" in data: - new_doc["api_key"] = data["api_key"] - try: conversations_collection.update_one( {"_id": ObjectId(data["conversation_id"]), f"queries.{data["question_index"]}": {"$exists": True}}, diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 7fe1b003..03a3ab08 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -430,11 +430,7 @@ const ConversationBubble = forwardRef< ? 'group-hover:lg:visible' : '' } - ${ - feedback === 'DISLIKE' && type !== 'ERROR' - ? ' hidden' - : '' - }`} + ${feedback === 'DISLIKE' && type !== 'ERROR' ? 'hidden' : ''}`} >
{ - if(feedback===undefined){ - console.log("liked") - handleFeedback?.('LIKE'); - setIsLikeClicked(true); - setIsDislikeClicked(false); + if (feedback === undefined) { + handleFeedback?.('LIKE'); + setIsLikeClicked(true); + setIsDislikeClicked(false); } }} onMouseEnter={() => setIsLikeHovered(true)} @@ -470,13 +465,9 @@ const ConversationBubble = forwardRef< !isDislikeClicked ? 'lg:invisible' : '' } ${ feedback === 'DISLIKE' || type !== 'ERROR' - ? ' group-hover:lg:visible' + ? 'group-hover:lg:visible' : '' - } ${ - feedback === 'LIKE' && type !== 'ERROR' - ? ' hidden' - : '' - } `} + } ${feedback === 'LIKE' && type !== 'ERROR' ? ' hidden' : ''} `} >
{ - if(feedback===undefined){ - handleFeedback?.('DISLIKE'); - setIsDislikeClicked(true); - setIsLikeClicked(false); + if (feedback === undefined) { + handleFeedback?.('DISLIKE'); + setIsDislikeClicked(true); + setIsLikeClicked(false); } }} onMouseEnter={() => setIsDislikeHovered(true)} From 9d4aee5de2a9bbefc33b61f55da5d2a5cc6e11a0 Mon Sep 17 00:00:00 2001 From: Niharika Goulikar Date: Tue, 26 Nov 2024 13:05:50 +0000 Subject: [PATCH 056/101] fixed the python error --- application/api/user/routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 96fc0e0f..6eb57cc0 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -198,10 +198,10 @@ class SubmitFeedback(Resource): try: conversations_collection.update_one( - {"_id": ObjectId(data["conversation_id"]), f"queries.{data["question_index"]}": {"$exists": True}}, + {"_id": ObjectId(data["conversation_id"]), f"queries.{data['question_index']}": {"$exists": True}}, { "$set": { - f"queries.{data["question_index"]}.feedback": data["feedback"] + f"queries.{data['question_index']}.feedback": data["feedback"] } } ) From 0a7a313e5dd33e092b5dece90b66788491e9d52d Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 26 Nov 2024 18:57:11 +0530 Subject: [PATCH 057/101] (fix:conv) input touches viewport bottom in mobile --- frontend/src/conversation/Conversation.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index ed69064a..7f06d6b1 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -15,7 +15,6 @@ import { useDarkTheme, useMediaQuery } from '../hooks'; import { ShareConversationModal } from '../modals/ShareConversationModal'; import { selectConversationId } from '../preferences/preferenceSlice'; import { AppDispatch } from '../store'; -import conversationService from '../api/services/conversationService'; import ConversationBubble from './ConversationBubble'; import { handleSendFeedback } from './conversationHandlers'; import { FEEDBACK, Query } from './conversationModels'; @@ -323,8 +322,8 @@ export default function Conversation() { )}
-
-
+
+
{t('settings.documents.name')} +
{t('settings.documents.tokenUsage')} Date: Sun, 24 Nov 2024 17:05:36 -0500 Subject: [PATCH 052/101] add text center when no data --- frontend/src/settings/Documents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 0fd82aa8..0987b5d7 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -230,7 +230,7 @@ const Documents: React.FC = ({
{t('settings.documents.noData')}