From 409d0e4084d7ffd74a2f9b9d7f8fc3caf32beb03 Mon Sep 17 00:00:00 2001 From: ayaan-qadri Date: Tue, 29 Oct 2024 01:19:47 +0530 Subject: [PATCH 1/5] Added custom size N Default widget open in --- .../src/components/DocsGPTWidget.tsx | 71 +++++++++++++------ extensions/react-widget/src/types/index.ts | 12 +++- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 01861274..0b4d9665 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -183,23 +183,53 @@ const Description = styled.p` margin-top: 0; `; -const Conversation = styled.div<{ size: string }>` - min-height: 250px; - max-width: 968px; - height: ${props => props.size === 'large' ? '75vh' : props.size === 'medium' ? '70vh' : '320px'}; - width: ${props => props.size === 'large' ? '60vw' : props.size === 'medium' ? '28vw' : '400px'}; - padding-inline: 0.5rem; - border-radius: 0.375rem; - text-align: left; - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: #4a4a4a transparent; /* thumb color track color */ - @media only screen and (max-width: 768px) { +const Conversation = styled.div<{ size: WidgetProps["size"] }>` + min-height: 250px; + max-height: ${(props) => + typeof props.size === "object" && + "custom" in props.size + && (props.size as { custom: { maxHeight: string } }).custom + .maxHeight || "" + }; + max-width: ${(props) => + (typeof props.size === "object" && + "custom" in props.size ? + (props.size as { custom: { maxWidth: string } }).custom + .maxWidth || "" : "968px") + }; + height: ${(props) => + props.size === "large" + ? "75vh" + : props.size === "medium" + ? "70vh" + : typeof props.size === "object" && "custom" in props.size + ? (props.size as { custom: { height: string } }).custom.height + : "320px"}; + width: ${(props) => + props.size === "large" + ? "60vw" + : props.size === "medium" + ? "28vw" + : typeof props.size === "object" && "custom" in props.size + ? (props.size as { custom: { width: string } }).custom.width + : "400px"}; + padding-inline: 0.5rem; + border-radius: 0.375rem; + text-align: left; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: #4a4a4a transparent; /* thumb color track color */ + @media only screen and (max-width: 768px) { width: 90vw !important; - } - @media only screen and (min-width:768px ) and (max-width: 1280px) { - width:${props => props.size === 'large' ? '90vw' : props.size === 'medium' ? '60vw' : '400px'} !important; - } + } + @media only screen and (min-width: 768px) and (max-width: 1280px) { + width: ${(props) => + props.size === "large" + ? "90vw" + : props.size === "medium" + ? "60vw" + : "400px"} !important; + } `; const Feedback = styled.div` background-color: transparent; @@ -265,7 +295,7 @@ const DotAnimation = styled.div` const Delay = styled(DotAnimation) <{ delay: number }>` animation-delay: ${props => props.delay + 'ms'}; `; -const PromptContainer = styled.form<{ size: string }>` +const PromptContainer = styled.form<{ size: WidgetProps['size'] }>` background-color: transparent; height: ${props => props.size == 'large' ? '60px' : '40px'}; margin: 16px; @@ -282,7 +312,7 @@ const StyledInput = styled.input` color: ${props => props.theme.text}; outline: none; `; -const StyledButton = styled.button<{ size: string }>` +const StyledButton = styled.button<{ size: WidgetProps['size'] }>` display: flex; justify-content: center; align-items: center; @@ -366,13 +396,14 @@ export const DocsGPTWidget = ({ theme = 'dark', buttonIcon = 'https://d3dg1063dc54p9.cloudfront.net/widget/message.svg', buttonBg = 'linear-gradient(to bottom right, #5AF0EC, #E80D9D)', - collectFeedback = true + collectFeedback = true, + deafultOpen = false }: WidgetProps) => { const [prompt, setPrompt] = React.useState(''); const [status, setStatus] = React.useState('idle'); const [queries, setQueries] = React.useState([]) const [conversationId, setConversationId] = React.useState(null) - const [open, setOpen] = React.useState(false) + const [open, setOpen] = React.useState(deafultOpen) const [eventInterrupt, setEventInterrupt] = React.useState(false); //click or scroll by user while autoScrolling const isBubbleHovered = useRef(false) const endMessageRef = React.useRef(null); diff --git a/extensions/react-widget/src/types/index.ts b/extensions/react-widget/src/types/index.ts index a55b6342..0a57a960 100644 --- a/extensions/react-widget/src/types/index.ts +++ b/extensions/react-widget/src/types/index.ts @@ -19,9 +19,17 @@ export interface WidgetProps { description?: string; heroTitle?: string; heroDescription?: string; - size?: 'small' | 'medium' | 'large'; + size?: 'small' | 'medium' | 'large' | { + custom: { + width: string; + height: string; + maxWidth?: string; + maxHeight?: string; + }; + }; theme?:THEME, buttonIcon?:string; buttonBg?:string; - collectFeedback?:boolean + collectFeedback?:boolean; + deafultOpen?: boolean; } \ No newline at end of file From 64f72ada283278b86cdd8ce839e3b837942cf441 Mon Sep 17 00:00:00 2001 From: ayaan-qadri Date: Mon, 4 Nov 2024 16:55:49 +0530 Subject: [PATCH 2/5] Added sizesConfig for controlling sizes(large, medium, small and custom) from one point --- .../src/components/DocsGPTWidget.tsx | 76 +++++++++---------- 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx index 0b4d9665..3edaaaf2 100644 --- a/extensions/react-widget/src/components/DocsGPTWidget.tsx +++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx @@ -9,6 +9,7 @@ import { ThemeProvider } from 'styled-components'; import Like from "../assets/like.svg" import Dislike from "../assets/dislike.svg" import MarkdownIt from 'markdown-it'; + const themes = { dark: { bg: '#222327', @@ -35,6 +36,20 @@ const themes = { } } } + +const sizesConfig = { + small: { size:'small', width: '400px', height: '320px' }, + medium: { size:'medium', width: '28vw', height: '70vh'}, + large: { size:'large', width: '60vw', height: '75vh'}, + getCustom: (custom: { width: string; height: string; maxWidth?: string; maxHeight?: string }) => ({ + size:'custom', + width: custom.width, + height: custom.height, + maxWidth: custom.maxWidth || '968px', + maxHeight: custom.maxHeight || '70vh', + }), +}; + const GlobalStyles = createGlobalStyle` .response pre { padding: 8px; @@ -80,7 +95,7 @@ const Overlay = styled.div` z-index: 999; transition: opacity 0.5s; ` -const WidgetContainer = styled.div<{ modal: boolean }>` +const WidgetContainer = styled.div<{ modal?: boolean }>` display: block; position: fixed; right: ${props => props.modal ? '50%' : '10px'}; @@ -183,36 +198,12 @@ const Description = styled.p` margin-top: 0; `; -const Conversation = styled.div<{ size: WidgetProps["size"] }>` +const Conversation = styled.div` min-height: 250px; - max-height: ${(props) => - typeof props.size === "object" && - "custom" in props.size - && (props.size as { custom: { maxHeight: string } }).custom - .maxHeight || "" - }; - max-width: ${(props) => - (typeof props.size === "object" && - "custom" in props.size ? - (props.size as { custom: { maxWidth: string } }).custom - .maxWidth || "" : "968px") - }; - height: ${(props) => - props.size === "large" - ? "75vh" - : props.size === "medium" - ? "70vh" - : typeof props.size === "object" && "custom" in props.size - ? (props.size as { custom: { height: string } }).custom.height - : "320px"}; - width: ${(props) => - props.size === "large" - ? "60vw" - : props.size === "medium" - ? "28vw" - : typeof props.size === "object" && "custom" in props.size - ? (props.size as { custom: { width: string } }).custom.width - : "400px"}; + max-height: ${(props) => props.theme.dimensions.maxHeight}; + max-width: ${(props) => props.theme.dimensions.maxWidth}; + height: ${(props) => props.theme.dimensions.height}; + width: ${(props) => props.theme.dimensions.width}; padding-inline: 0.5rem; border-radius: 0.375rem; text-align: left; @@ -224,9 +215,9 @@ const Conversation = styled.div<{ size: WidgetProps["size"] }>` } @media only screen and (min-width: 768px) and (max-width: 1280px) { width: ${(props) => - props.size === "large" + props.theme.dimensions.size === "large" ? "90vw" - : props.size === "medium" + : props.theme.dimensions.size === "medium" ? "60vw" : "400px"} !important; } @@ -295,9 +286,9 @@ const DotAnimation = styled.div` const Delay = styled(DotAnimation) <{ delay: number }>` animation-delay: ${props => props.delay + 'ms'}; `; -const PromptContainer = styled.form<{ size: WidgetProps['size'] }>` +const PromptContainer = styled.form` background-color: transparent; - height: ${props => props.size == 'large' ? '60px' : '40px'}; + height: ${props => props.theme.dimensions.size == 'large' ? '60px' : '40px'}; margin: 16px; display: flex; justify-content: space-evenly; @@ -312,14 +303,14 @@ const StyledInput = styled.input` color: ${props => props.theme.text}; outline: none; `; -const StyledButton = styled.button<{ size: WidgetProps['size'] }>` +const StyledButton = styled.button` display: flex; justify-content: center; align-items: center; background-image: linear-gradient(to bottom right, #5AF0EC, #E80D9D); border-radius: 6px; - min-width: ${props => props.size === 'large' ? '60px' : '36px'}; - height: ${props => props.size === 'large' ? '60px' : '36px'}; + min-width: ${props => props.theme.dimensions.size === 'large' ? '60px' : '36px'}; + height: ${props => props.theme.dimensions.size === 'large' ? '60px' : '36px'}; margin-left:8px; padding: 0px; border: none; @@ -517,8 +508,13 @@ export const DocsGPTWidget = ({ 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) + : sizesConfig[size]; return ( - + {open && size === 'large' && { setOpen(false) @@ -544,7 +540,7 @@ export const DocsGPTWidget = ({ - + { queries.length > 0 ? queries?.map((query, index) => { return ( @@ -615,13 +611,11 @@ export const DocsGPTWidget = ({ } setPrompt(event.target.value)} type='text' placeholder="What do you want to do?" /> From 877b165a9ae54c3a77ee10d965c5218e3dd5f21b Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 5 Nov 2024 00:44:02 +0530 Subject: [PATCH 3/5] (feat:docs) sort --- application/api/user/routes.py | 4 ++- frontend/src/api/services/userService.ts | 3 +- frontend/src/preferences/preferenceApi.ts | 7 +++-- frontend/src/settings/Documents.tsx | 35 +++++++++++++++++++---- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index c33a6c84..8e62683e 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -433,6 +433,8 @@ class CombinedJson(Resource): @api.doc(description="Provide JSON file with combined available indexes") def get(self): user = "local" + sort_field = request.args.get('sort', 'date') # Default to 'date' + sort_order = request.args.get('order', "desc") # Default to 'desc' data = [ { "name": "default", @@ -445,7 +447,7 @@ class CombinedJson(Resource): ] try: - for index in sources_collection.find({"user": user}).sort("date", -1): + for index in sources_collection.find({"user": user}).sort(sort_field, 1 if sort_order=="asc" else -1): data.append( { "id": str(index["_id"]), diff --git a/frontend/src/api/services/userService.ts b/frontend/src/api/services/userService.ts index c5bbba7d..53b38f50 100644 --- a/frontend/src/api/services/userService.ts +++ b/frontend/src/api/services/userService.ts @@ -2,7 +2,8 @@ import apiClient from '../client'; import endpoints from '../endpoints'; const userService = { - getDocs: (): Promise => apiClient.get(endpoints.USER.DOCS), + getDocs: (sort = 'date', order = 'desc'): Promise => + apiClient.get(`${endpoints.USER.DOCS}?sort=${sort}&order=${order}`), checkDocs: (data: any): Promise => apiClient.post(endpoints.USER.DOCS_CHECK, data), getAPIKeys: (): Promise => apiClient.get(endpoints.USER.API_KEYS), diff --git a/frontend/src/preferences/preferenceApi.ts b/frontend/src/preferences/preferenceApi.ts index ed730f7c..af1060b8 100644 --- a/frontend/src/preferences/preferenceApi.ts +++ b/frontend/src/preferences/preferenceApi.ts @@ -3,9 +3,12 @@ import userService from '../api/services/userService'; import { Doc } from '../models/misc'; //Fetches all JSON objects from the source. We only use the objects with the "model" property in SelectDocsModal.tsx. Hopefully can clean up the source file later. -export async function getDocs(): Promise { +export async function getDocs( + sort = 'date', + order = 'desc', +): Promise { try { - const response = await userService.getDocs(); + const response = await userService.getDocs(sort, order); const data = await response.json(); const docs: Doc[] = []; diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 004b6f48..f94d1a87 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -45,14 +45,30 @@ const Documents: React.FC = ({ const [modalState, setModalState] = useState('INACTIVE'); // Initialize with inactive state 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'); const syncOptions = [ { label: 'Never', value: 'never' }, { label: 'Daily', value: 'daily' }, { label: 'Weekly', value: 'weekly' }, { label: 'Monthly', value: 'monthly' }, ]; - + const refreshDocs = (field: 'date' | 'tokens') => { + if (field === sortField) { + setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setSortOrder('desc'); + setSortField(field); + } + getDocs(sortField, sortOrder) + .then((data) => { + dispatch(setSourceDocs(data)); + }) + .catch((error) => console.error(error)) + .finally(() => { + setLoading(false); + }); + }; const handleManageSync = (doc: Doc, sync_frequency: string) => { setLoading(true); userService @@ -110,19 +126,28 @@ const Documents: React.FC = ({
{t('settings.documents.date')} - + refreshDocs('date')} + src={caretSort} + alt="sort" + />
{t('settings.documents.tokenUsage')} - + refreshDocs('tokens')} + src={caretSort} + alt="sort" + />
{t('settings.documents.type')} -
From 7e24995afe15ff08a31af5ea97a12a90ebdafd93 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 5 Nov 2024 00:48:12 +0530 Subject: [PATCH 4/5] fix(nav): minor ui --- frontend/src/Navigation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index ce23e90e..3591469b 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -254,7 +254,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { ref={navRef} className={`${ !navOpen && '-ml-96 md:-ml-[18rem]' - } duration-20 fixed top-0 z-40 flex h-full w-72 flex-col border-r-[1px] border-b-0 bg-white transition-all dark:border-r-purple-taupe dark:bg-chinese-black dark:text-white`} + } duration-20 fixed top-0 z-20 flex h-full w-72 flex-col border-r-[1px] border-b-0 bg-white transition-all dark:border-r-purple-taupe dark:bg-chinese-black dark:text-white`} >
Date: Tue, 5 Nov 2024 01:36:54 +0530 Subject: [PATCH 5/5] fix(all sources): text overflows --- frontend/src/conversation/ConversationBubble.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index a9a05168..284c2b56 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -474,7 +474,7 @@ function AllSources(sources: AllSourcesProps) { > ) : null} -

+

{source.text}