diff --git a/README.md b/README.md index 05a5feb..03a3fe8 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Say goodbye to time-consuming manual searches, and let -
+

About DocsGPT

🦖

diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ad9d72a..4454094 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -18,9 +18,7 @@ export default function App() {
diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index e065d65..7a55cd0 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -32,6 +32,7 @@ import { useMediaQuery, useOutsideAlerter } from './hooks'; import Upload from './upload/Upload'; import { Doc, getConversations } from './preferences/preferenceApi'; import SelectDocsModal from './preferences/SelectDocsModal'; +import ConversationTile from './conversation/ConversationTile'; interface NavigationProps { navOpen: boolean; @@ -68,16 +69,20 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { useEffect(() => { if (!conversations) { - getConversations() - .then((fetchedConversations) => { - dispatch(setConversations(fetchedConversations)); - }) - .catch((error) => { - console.error('Failed to fetch conversations: ', error); - }); + fetchConversations(); } }, [conversations, dispatch]); + async function fetchConversations() { + return await getConversations() + .then((fetchedConversations) => { + dispatch(setConversations(fetchedConversations)); + }) + .catch((error) => { + console.error('Failed to fetch conversations: ', error); + }); + } + const handleDeleteConversation = (id: string) => { fetch(`${apiHost}/api/delete_conversation?id=${id}`, { method: 'POST', @@ -89,6 +94,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { ) as HTMLElement; const parentElement = imageElement.parentNode as HTMLElement; parentElement.parentNode?.removeChild(parentElement); + fetchConversations(); }) .catch((error) => console.error(error)); }; @@ -126,6 +132,29 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { ); }); }; + + async function updateConversationName(updatedConversation: { + name: string; + id: string; + }) { + await fetch(`${apiHost}/api/update_conversation_name`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(updatedConversation), + }) + .then((response) => response.json()) + .then((data) => { + if (data) { + navigate('/'); + fetchConversations(); + } + }) + .catch((err) => { + console.error(err); + }); + } useOutsideAlerter( navRef, () => { @@ -210,41 +239,17 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
{conversations - ? conversations.map((conversation) => { - return ( -
{ - handleConversationClick(conversation.id); - }} - className={`my-auto mx-4 mt-4 flex h-12 cursor-pointer items-center justify-between gap-4 rounded-3xl hover:bg-gray-100 ${ - conversationId === conversation.id ? 'bg-gray-100' : '' - }`} - > -
- -

- {conversation.name.length > 45 - ? conversation.name.substring(0, 45) + '...' - : conversation.name} -

-
- - {conversationId === conversation.id ? ( - Exit { - event.stopPropagation(); - handleDeleteConversation(conversation.id); - }} - /> - ) : null} -
- ); - }) + ? conversations.map((conversation, index) => ( + handleConversationClick(id)} + onDeleteConversation={(id) => handleDeleteConversation(id)} + onSave={(conversation) => + updateConversationName(conversation) + } + /> + )) : null}
diff --git a/frontend/src/assets/checkMark.svg b/frontend/src/assets/checkMark.svg new file mode 100644 index 0000000..9ed02cb --- /dev/null +++ b/frontend/src/assets/checkMark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/assets/checkmark.svg b/frontend/src/assets/checkmark.svg index 682c29d..9ed02cb 100644 --- a/frontend/src/assets/checkmark.svg +++ b/frontend/src/assets/checkmark.svg @@ -1,3 +1,3 @@ - - - + + + \ No newline at end of file diff --git a/frontend/src/assets/edit.svg b/frontend/src/assets/edit.svg new file mode 100644 index 0000000..2565377 --- /dev/null +++ b/frontend/src/assets/edit.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/assets/trash.svg b/frontend/src/assets/trash.svg new file mode 100644 index 0000000..d0e4546 --- /dev/null +++ b/frontend/src/assets/trash.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index aa9514c..84d86ae 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -74,7 +74,7 @@ const ConversationBubble = forwardRef<
)} void; + onDeleteConversation: (arg1: string) => void; + onSave: ({ name, id }: ConversationProps) => void; +} + +export default function ConversationTile({ + conversation, + selectConversation, + onDeleteConversation, + onSave, +}: ConversationTileProps) { + const conversationId = useSelector(selectConversationId); + const tileRef = useRef(null); + + const [isEdit, setIsEdit] = useState(false); + const [conversationName, setConversationsName] = useState(''); + useOutsideAlerter( + tileRef, + () => + handleSaveConversation({ + id: conversationId || conversation.id, + name: conversationName, + }), + [conversationName], + ); + + useEffect(() => { + setConversationsName(conversation.name); + }, [conversation.name]); + + function handleEditConversation() { + setIsEdit(true); + } + + function handleSaveConversation(changedConversation: ConversationProps) { + if (changedConversation.name.trim().length) { + onSave(changedConversation); + setIsEdit(false); + } else { + onClear(); + } + } + + function onClear() { + setConversationsName(conversation.name); + setIsEdit(false); + } + return ( +
{ + selectConversation(conversation.id); + }} + className={`my-auto mx-4 mt-4 flex h-12 cursor-pointer items-center justify-between gap-4 rounded-3xl hover:bg-gray-100 ${ + conversationId === conversation.id ? 'bg-gray-100' : '' + }`} + > +
+ + {isEdit ? ( + setConversationsName(e.target.value)} + /> + ) : ( +

+ {conversationName} +

+ )} +
+ {conversationId === conversation.id ? ( +
+ Edit { + event.stopPropagation(); + isEdit + ? handleSaveConversation({ + id: conversationId, + name: conversationName, + }) + : handleEditConversation(); + }} + /> + Exit { + event.stopPropagation(); + isEdit ? onClear() : onDeleteConversation(conversation.id); + }} + /> +
+ ) : null} +
+ ); +} diff --git a/scripts/ingest.py b/scripts/ingest.py index 6ab9cce..8c74fd0 100644 --- a/scripts/ingest.py +++ b/scripts/ingest.py @@ -78,14 +78,12 @@ def ingest(yes: bool = typer.Option(False, "-y", "--yes", prompt=False, # Here we check for command line arguments for bot calls. # If no argument exists or the yes is not True, then the # user permission is requested to call the API. - if len(sys.argv) > 1: - if yes: - call_openai_api(docs, folder_name) - else: - get_user_permission(docs, folder_name) + if len(sys.argv) > 1 and yes: + call_openai_api(docs, folder_name) else: get_user_permission(docs, folder_name) + folder_counts = defaultdict(int) folder_names = [] for dir_path in dir: @@ -110,14 +108,19 @@ def convert(dir: Optional[str] = typer.Option("inputs", Creates documentation linked to original functions from specified location. By default /inputs folder is used, .py is parsed. """ - if formats == 'py': - functions_dict, classes_dict = extract_py(dir) - elif formats == 'js': - functions_dict, classes_dict = extract_js(dir) - elif formats == 'java': - functions_dict, classes_dict = extract_java(dir) + # Using a dictionary to map between the formats and their respective extraction functions + # makes the code more scalable. When adding more formats in the future, + # you only need to update the extraction_functions dictionary. + extraction_functions = { + 'py': extract_py, + 'js': extract_js, + 'java': extract_java + } + + if formats in extraction_functions: + functions_dict, classes_dict = extraction_functions[formats](dir) else: - raise Exception("Sorry, language not supported yet") + raise Exception("Sorry, language not supported yet") transform_to_docs(functions_dict, classes_dict, formats, dir)