From e9dae4240e896693e59df06474e24e1e5f55730d Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sat, 21 Dec 2024 08:45:43 -0800 Subject: [PATCH 01/10] Clean up all references to authenticatedData - De facto, was being assumed everywhere if authenticatedData is null, that it's not logged in. This isn't true because the data can still be loading. Update the hook to send additional states. - Bonus: Delete model picker code and a slew of unused imports. --- src/interface/web/app/agents/page.tsx | 154 ++++++++-------- src/interface/web/app/automations/page.tsx | 39 ++-- src/interface/web/app/chat/page.tsx | 8 +- src/interface/web/app/common/auth.ts | 6 +- .../app/components/agentCard/agentCard.tsx | 1 - .../allConversations/allConversations.tsx | 12 +- .../app/components/appSidebar/appSidebar.tsx | 20 +-- .../chatInputArea/chatInputArea.tsx | 1 - .../components/loginPrompt/loginPrompt.tsx | 1 - .../modelPicker/modelPicker.module.css | 23 --- .../components/modelPicker/modelPicker.tsx | 166 ------------------ .../web/app/components/navMenu/navMenu.tsx | 26 ++- src/interface/web/app/page.tsx | 27 +-- src/interface/web/app/settings/page.tsx | 4 +- src/interface/web/app/share/chat/page.tsx | 8 +- 15 files changed, 155 insertions(+), 341 deletions(-) delete mode 100644 src/interface/web/app/components/modelPicker/modelPicker.module.css delete mode 100644 src/interface/web/app/components/modelPicker/modelPicker.tsx diff --git a/src/interface/web/app/agents/page.tsx b/src/interface/web/app/agents/page.tsx index 0ec768394..079006f7b 100644 --- a/src/interface/web/app/agents/page.tsx +++ b/src/interface/web/app/agents/page.tsx @@ -144,7 +144,6 @@ function CreateAgentCard(props: CreateAgentCardProps) { Create Agent {!props.userProfile && showLoginPrompt && ( @@ -174,7 +173,11 @@ export default function Agents() { const { data, error, mutate } = useSWR("agents", agentsFetcher, { revalidateOnFocus: false, }); - const authenticatedData = useAuthenticatedData(); + const { + data: authenticatedData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const { userConfig } = useUserConfig(true); const [showLoginPrompt, setShowLoginPrompt] = useState(false); const isMobileWidth = useIsMobileWidth(); @@ -297,38 +300,39 @@ export default function Agents() {

Agents

- + {authenticatedData && ( + + )}
{showLoginPrompt && ( @@ -345,53 +349,59 @@ export default function Agents() {
- {personalAgents.map((agent) => ( - - ))} + {authenticatedData && + personalAgents.map((agent) => ( + + ))}

Explore

- {publicAgents.map((agent) => ( - - ))} + {!authenticationLoading && + publicAgents.map((agent) => ( + + ))}
diff --git a/src/interface/web/app/automations/page.tsx b/src/interface/web/app/automations/page.tsx index f7fbb906f..a4becd1b9 100644 --- a/src/interface/web/app/automations/page.tsx +++ b/src/interface/web/app/automations/page.tsx @@ -980,7 +980,11 @@ function AutomationComponentWrapper(props: AutomationComponentWrapperProps) { } export default function Automations() { - const authenticatedData = useAuthenticatedData(); + const { + data: authenticatedData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const { data: personalAutomations, error, @@ -1068,9 +1072,6 @@ export default function Automations() { {showLoginPrompt && ( @@ -1114,7 +1115,7 @@ export default function Automations() { {isLoading && }
- {personalAutomations && + {authenticatedData && + personalAutomations && personalAutomations.map((automation) => ( ))} - {allNewAutomations.map((automation) => ( - - ))} + {authenticatedData && + allNewAutomations.map((automation) => ( + + ))}

Explore

@@ -1154,7 +1157,7 @@ export default function Automations() { isMobileWidth={isMobileWidth} setNewAutomationData={setNewAutomationData} key={automation.id} - authenticatedData={authenticatedData} + authenticatedData={authenticatedData || null} automation={automation} locationData={locationData} isLoggedIn={authenticatedData ? true : false} diff --git a/src/interface/web/app/chat/page.tsx b/src/interface/web/app/chat/page.tsx index 91a7c12b5..1162379fb 100644 --- a/src/interface/web/app/chat/page.tsx +++ b/src/interface/web/app/chat/page.tsx @@ -193,7 +193,11 @@ export default function Chat() { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, }, }; - const authenticatedData = useAuthenticatedData(); + const { + data: authenticatedData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const isMobileWidth = useIsMobileWidth(); useEffect(() => { @@ -425,7 +429,7 @@ export default function Chat() {
}> .catch((err) => console.warn(err)); export function useAuthenticatedData() { - const { data, error } = useSWR("/api/v1/user", fetcher, { + const { data, error, isLoading } = useSWR("/api/v1/user", fetcher, { revalidateOnFocus: false, }); - if (error || !data || data.detail === "Forbidden") return null; - - return data; + return { data, error, isLoading }; } export interface ModelOptions { diff --git a/src/interface/web/app/components/agentCard/agentCard.tsx b/src/interface/web/app/components/agentCard/agentCard.tsx index 08a126589..ed77425e9 100644 --- a/src/interface/web/app/components/agentCard/agentCard.tsx +++ b/src/interface/web/app/components/agentCard/agentCard.tsx @@ -326,7 +326,6 @@ export function AgentCard(props: AgentCardProps) { {showLoginPrompt && ( diff --git a/src/interface/web/app/components/allConversations/allConversations.tsx b/src/interface/web/app/components/allConversations/allConversations.tsx index aa1294695..29c43e48d 100644 --- a/src/interface/web/app/components/allConversations/allConversations.tsx +++ b/src/interface/web/app/components/allConversations/allConversations.tsx @@ -3,7 +3,6 @@ import styles from "./sidePanel.module.css"; import { useEffect, useMemo, useState } from "react"; -import { useRef } from "react"; import { mutate } from "swr"; @@ -102,14 +101,10 @@ import { } from "@/components/ui/alert-dialog"; import { modifyFileFilterForConversation } from "@/app/common/chatFunctions"; import { ScrollAreaScrollbar } from "@radix-ui/react-scroll-area"; -import { KhojLogoType } from "@/app/components/logo/khojLogo"; -import NavMenu from "@/app/components/navMenu/navMenu"; import { getIconFromIconName } from "@/app/common/iconUtils"; -import LoginPrompt from "../loginPrompt/loginPrompt"; import { SidebarGroup, SidebarGroupLabel, - SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, @@ -908,9 +903,12 @@ export default function AllConversations(props: SidePanelProps) { const [data, setData] = useState(null); const [organizedData, setOrganizedData] = useState(null); const [subsetOrganizedData, setSubsetOrganizedData] = useState(null); - const [showLoginPrompt, setShowLoginPrompt] = useState(false); - const authenticatedData = useAuthenticatedData(); + const { + data: authenticatedData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const { data: chatSessions, isLoading } = useChatSessionsFetchRequest( authenticatedData ? `/api/chat/sessions` : "", ); diff --git a/src/interface/web/app/components/appSidebar/appSidebar.tsx b/src/interface/web/app/components/appSidebar/appSidebar.tsx index 3023f28c0..811eb7994 100644 --- a/src/interface/web/app/components/appSidebar/appSidebar.tsx +++ b/src/interface/web/app/components/appSidebar/appSidebar.tsx @@ -1,18 +1,14 @@ -import { Calendar, Home, Inbox, Search, Settings } from "lucide-react"; - import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, - SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, } from "@/components/ui/sidebar"; -import Link from "next/link"; import { KhojAgentLogo, KhojAutomationLogo, @@ -21,12 +17,12 @@ import { KhojSearchLogo, } from "../logo/khojLogo"; import { Gear } from "@phosphor-icons/react/dist/ssr"; -import { House, Plus } from "@phosphor-icons/react"; +import { Plus } from "@phosphor-icons/react"; import { useEffect, useState } from "react"; -import { useAuthenticatedData } from "@/app/common/auth"; import AllConversations from "../allConversations/allConversations"; import NavMenu from "../navMenu/navMenu"; import { useSidebar } from "@/components/ui/sidebar"; +import { useIsMobileWidth } from "@/app/common/utils"; // Menu items. const items = [ @@ -66,21 +62,11 @@ interface AppSidebarProps { } export function AppSidebar(props: AppSidebarProps) { - const [isMobileWidth, setIsMobileWidth] = useState(false); + const isMobileWidth = useIsMobileWidth(); const { state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar } = useSidebar(); - useEffect(() => { - const handleResize = () => { - setIsMobileWidth(window.innerWidth < 768); - }; - - handleResize(); - window.addEventListener("resize", handleResize); - return () => window.removeEventListener("resize", handleResize); - }, []); - return ( diff --git a/src/interface/web/app/components/chatInputArea/chatInputArea.tsx b/src/interface/web/app/components/chatInputArea/chatInputArea.tsx index cb55386a1..73dfce365 100644 --- a/src/interface/web/app/components/chatInputArea/chatInputArea.tsx +++ b/src/interface/web/app/components/chatInputArea/chatInputArea.tsx @@ -409,7 +409,6 @@ export const ChatInputArea = forwardRef((pr )} {uploading && ( diff --git a/src/interface/web/app/components/loginPrompt/loginPrompt.tsx b/src/interface/web/app/components/loginPrompt/loginPrompt.tsx index 3d1a3752b..923a16fe7 100644 --- a/src/interface/web/app/components/loginPrompt/loginPrompt.tsx +++ b/src/interface/web/app/components/loginPrompt/loginPrompt.tsx @@ -29,7 +29,6 @@ import { Card, CardContent } from "@/components/ui/card"; import { InputOTP, InputOTPGroup, InputOTPSlot } from "@/components/ui/input-otp"; export interface LoginPromptProps { - loginRedirectMessage: string; onOpenChange: (open: boolean) => void; isMobileWidth?: boolean; } diff --git a/src/interface/web/app/components/modelPicker/modelPicker.module.css b/src/interface/web/app/components/modelPicker/modelPicker.module.css deleted file mode 100644 index 28d1ce4d8..000000000 --- a/src/interface/web/app/components/modelPicker/modelPicker.module.css +++ /dev/null @@ -1,23 +0,0 @@ -select.modelPicker { - font-size: small; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - padding-left: 0.75rem; - padding-right: 0.75rem; - border: none; - border-width: 1px; - display: flex; - align-items: center; - height: 2.5rem; - justify-content: space-between; - border-radius: calc(0.5rem - 2px); -} - -select.modelPicker:after { - grid-area: select; - justify-self: end; -} - -div.modelPicker { - margin-top: 8px; -} diff --git a/src/interface/web/app/components/modelPicker/modelPicker.tsx b/src/interface/web/app/components/modelPicker/modelPicker.tsx deleted file mode 100644 index 2efdd9040..000000000 --- a/src/interface/web/app/components/modelPicker/modelPicker.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { useAuthenticatedData } from "@/app/common/auth"; -import React, { useEffect } from "react"; -import useSWR from "swr"; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog"; - -import styles from "./modelPicker.module.css"; - -export interface Model { - id: number; - chat_model: string; -} - -// Custom fetcher function to fetch options -const fetchOptionsRequest = async (url: string) => { - const response = await fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); - return response.json(); -}; - -export const useOptionsRequest = (url: string) => { - const { data, error } = useSWR(url, fetchOptionsRequest); - - return { - data, - isLoading: !error && !data, - isError: error, - }; -}; - -const fetchSelectedModel = async (url: string) => { - const response = await fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); - return response.json(); -}; - -export const useSelectedModel = (url: string) => { - const { data, error } = useSWR(url, fetchSelectedModel); - - return { - data, - isLoading: !error && !data, - isError: error, - }; -}; - -interface ModelPickerProps { - disabled?: boolean; - setModelUsed?: (model: Model) => void; - initialModel?: Model; -} - -export const ModelPicker: React.FC = (props: ModelPickerProps) => { - const { data: models } = useOptionsRequest("/api/model/chat/options"); - const { data: selectedModel } = useSelectedModel("/api/model/chat"); - const [openLoginDialog, setOpenLoginDialog] = React.useState(false); - - let userData = useAuthenticatedData(); - - const setModelUsed = props.setModelUsed; - - useEffect(() => { - if (setModelUsed && selectedModel) { - setModelUsed(selectedModel); - } - }, [selectedModel, setModelUsed]); - - if (!models) { - return
Loading...
; - } - - function onSelect(model: Model) { - if (!userData) { - setOpenLoginDialog(true); - return; - } - - if (props.setModelUsed) { - props.setModelUsed(model); - } - - fetch("/api/model/chat" + "?id=" + String(model.id), { - method: "POST", - body: JSON.stringify(model), - }) - .then((response) => { - if (!response.ok) { - throw new Error("Failed to select model"); - } - }) - .catch((error) => { - console.error("Failed to select model", error); - }); - } - - function isSelected(model: Model) { - if (props.initialModel) { - return model.id === props.initialModel.id; - } - return selectedModel?.id === model.id; - } - - return ( -
- - - - - - You must be logged in to configure your model. - - - Once you create an account with Khoj, you can configure your model and - use a whole suite of other features. Check out our{" "} - documentation to learn more. - - - - Cancel - { - window.location.href = window.location.origin + "/login"; - }} - > - Sign in - - - - -
- ); -}; diff --git a/src/interface/web/app/components/navMenu/navMenu.tsx b/src/interface/web/app/components/navMenu/navMenu.tsx index b90fa9514..e2d63d849 100644 --- a/src/interface/web/app/components/navMenu/navMenu.tsx +++ b/src/interface/web/app/components/navMenu/navMenu.tsx @@ -1,20 +1,10 @@ "use client"; -import styles from "./navMenu.module.css"; import Link from "next/link"; import { useAuthenticatedData } from "@/app/common/auth"; import { useState, useEffect } from "react"; import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; -import { - Menubar, - MenubarContent, - MenubarItem, - MenubarMenu, - MenubarSeparator, - MenubarTrigger, -} from "@/components/ui/menubar"; - import { DropdownMenu, DropdownMenuContent, @@ -22,8 +12,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { Moon, Sun, UserCircle, Question, GearFine, ArrowRight, Code } from "@phosphor-icons/react"; -import { KhojAgentLogo, KhojAutomationLogo, KhojSearchLogo } from "../logo/khojLogo"; +import { Moon, Sun, UserCircle, Question, ArrowRight, Code } from "@phosphor-icons/react"; import { useIsMobileWidth } from "@/app/common/utils"; import LoginPrompt from "../loginPrompt/loginPrompt"; import { Button } from "@/components/ui/button"; @@ -55,10 +44,13 @@ interface NavMenuProps { } export default function NavMenu({ sideBarIsOpen }: NavMenuProps) { - const userData = useAuthenticatedData(); + const { + data: userData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const [darkMode, setDarkMode] = useState(false); const [initialLoadDone, setInitialLoadDone] = useState(false); - const isMobileWidth = useIsMobileWidth(); const [showLoginPrompt, setShowLoginPrompt] = useState(false); useEffect(() => { @@ -97,6 +89,12 @@ export default function NavMenu({ sideBarIsOpen }: NavMenuProps) { return ( + {showLoginPrompt && ( + setShowLoginPrompt(isOpen)} + isMobileWidth={useIsMobileWidth()} + /> + )} diff --git a/src/interface/web/app/page.tsx b/src/interface/web/app/page.tsx index 4571fb87d..b22bf231b 100644 --- a/src/interface/web/app/page.tsx +++ b/src/interface/web/app/page.tsx @@ -222,7 +222,6 @@ function ChatBodyData(props: ChatBodyDataProps) { )} {!props.isLoggedIn && ( @@ -425,7 +424,11 @@ export default function Home() { const { userConfig: initialUserConfig, isLoadingUserConfig } = useUserConfig(true); const [userConfig, setUserConfig] = useState(null); - const authenticatedData = useAuthenticatedData(); + const { + data: authenticatedData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const handleConversationIdChange = (newConversationId: string) => { setConversationID(newConversationId); @@ -477,15 +480,17 @@ export default function Home() { Khoj AI - Your Second Brain
- + {!authenticationLoading && ( + + )}
diff --git a/src/interface/web/app/settings/page.tsx b/src/interface/web/app/settings/page.tsx index 3178824b1..0fe35b97c 100644 --- a/src/interface/web/app/settings/page.tsx +++ b/src/interface/web/app/settings/page.tsx @@ -38,7 +38,6 @@ import { Key, Palette, UserCircle, - FileMagnifyingGlass, Trash, Copy, CreditCard, @@ -499,7 +498,6 @@ enum PhoneNumberValidationState { } export default function SettingsView() { - const [title, setTitle] = useState("Settings"); const { apiKeys, generateAPIKey, copyAPIKey, deleteAPIKey } = useApiKeys(); const { userConfig: initialUserConfig } = useUserConfig(true); const [userConfig, setUserConfig] = useState(null); @@ -514,6 +512,8 @@ export default function SettingsView() { const { toast } = useToast(); const isMobileWidth = useIsMobileWidth(); + const title = "Settings"; + const cardClassName = "w-full lg:w-1/3 grid grid-flow-column border border-gray-300 shadow-md rounded-lg border dark:border-none dark:bg-muted border-opacity-50"; diff --git a/src/interface/web/app/share/chat/page.tsx b/src/interface/web/app/share/chat/page.tsx index c64d8d3a6..ed7d2672c 100644 --- a/src/interface/web/app/share/chat/page.tsx +++ b/src/interface/web/app/share/chat/page.tsx @@ -123,7 +123,11 @@ export default function SharedChat() { const [paramSlug, setParamSlug] = useState(undefined); const [images, setImages] = useState([]); - const authenticatedData = useAuthenticatedData(); + const { + data: authenticatedData, + error: authenticationError, + isLoading: authenticationLoading, + } = useAuthenticatedData(); const isMobileWidth = useIsMobileWidth(); useEffect(() => { @@ -222,7 +226,7 @@ export default function SharedChat() { conversationId={conversationId} streamedMessages={messages} setQueryToProcess={setQueryToProcess} - isLoggedIn={authenticatedData !== null} + isLoggedIn={authenticatedData ? true : false} publicConversationSlug={paramSlug} chatOptionsData={chatOptionsData} setTitle={setTitle} From 2c7c16d93e2b02856d95469ea2e494f0aeef2e2b Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sat, 21 Dec 2024 12:48:29 -0800 Subject: [PATCH 02/10] Fix conditional reference to is mobile width hook --- src/interface/web/app/components/navMenu/navMenu.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/interface/web/app/components/navMenu/navMenu.tsx b/src/interface/web/app/components/navMenu/navMenu.tsx index e2d63d849..7e7801469 100644 --- a/src/interface/web/app/components/navMenu/navMenu.tsx +++ b/src/interface/web/app/components/navMenu/navMenu.tsx @@ -52,6 +52,7 @@ export default function NavMenu({ sideBarIsOpen }: NavMenuProps) { const [darkMode, setDarkMode] = useState(false); const [initialLoadDone, setInitialLoadDone] = useState(false); const [showLoginPrompt, setShowLoginPrompt] = useState(false); + const isMobileWidth = useIsMobileWidth(); useEffect(() => { if (localStorage.getItem("theme") === "dark") { @@ -92,7 +93,7 @@ export default function NavMenu({ sideBarIsOpen }: NavMenuProps) { {showLoginPrompt && ( setShowLoginPrompt(isOpen)} - isMobileWidth={useIsMobileWidth()} + isMobileWidth={isMobileWidth} /> )} From a17cc9db381037913343b648fcbd501b8c4fbde1 Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sat, 21 Dec 2024 19:19:35 -0800 Subject: [PATCH 03/10] Fix handling 403 forbidden error from auth response --- src/interface/web/app/common/auth.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/interface/web/app/common/auth.ts b/src/interface/web/app/common/auth.ts index 1dca49156..738d273f4 100644 --- a/src/interface/web/app/common/auth.ts +++ b/src/interface/web/app/common/auth.ts @@ -23,6 +23,10 @@ export function useAuthenticatedData() { revalidateOnFocus: false, }); + if (data?.detail === "Forbidden") { + return { data: null, error: "Forbidden", isLoading: false }; + } + return { data, error, isLoading }; } From 8c6b4217ae7cee020bbed97d67f1360f8074eb7f Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sat, 21 Dec 2024 19:29:37 -0800 Subject: [PATCH 04/10] Set width of chat layout to 100% --- src/interface/web/app/chat/chat.module.css | 3 ++- src/interface/web/app/share/chat/sharedChat.module.css | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/interface/web/app/chat/chat.module.css b/src/interface/web/app/chat/chat.module.css index 9bd954347..c98684296 100644 --- a/src/interface/web/app/chat/chat.module.css +++ b/src/interface/web/app/chat/chat.module.css @@ -64,9 +64,10 @@ div.chatBody { div.chatLayout { display: grid; - grid-template-columns: auto 1fr; + grid-template-columns: 1fr; gap: 1rem; padding-top: 1rem; + width: 100%; } div.chatBox { diff --git a/src/interface/web/app/share/chat/sharedChat.module.css b/src/interface/web/app/share/chat/sharedChat.module.css index 81c422c7e..286e5ba45 100644 --- a/src/interface/web/app/share/chat/sharedChat.module.css +++ b/src/interface/web/app/share/chat/sharedChat.module.css @@ -62,6 +62,7 @@ div.chatLayout { display: grid; grid-template-columns: auto 1fr; gap: 1rem; + width: 100%; } div.chatBox { From dc17272f7098e7fc7369e4c3b58b91ee9e04021a Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sun, 22 Dec 2024 09:01:09 -0800 Subject: [PATCH 05/10] Fix some spacing in the nav menu --- src/interface/web/app/components/navMenu/navMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interface/web/app/components/navMenu/navMenu.tsx b/src/interface/web/app/components/navMenu/navMenu.tsx index 7e7801469..d6bfd85ce 100644 --- a/src/interface/web/app/components/navMenu/navMenu.tsx +++ b/src/interface/web/app/components/navMenu/navMenu.tsx @@ -106,13 +106,13 @@ export default function NavMenu({ sideBarIsOpen }: NavMenuProps) { > - {userData?.username[0].toUpperCase()} + {userData.username[0].toUpperCase()} {sideBarIsOpen && ( <>

{userData?.username}

- + )} From 9f84f5dcc713ce35032f213e6dcbb561dadb7f40 Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sun, 22 Dec 2024 09:18:05 -0800 Subject: [PATCH 06/10] Give more breathing space to the sidebar footer --- src/interface/web/app/components/appSidebar/appSidebar.tsx | 2 +- src/interface/web/app/layout.tsx | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/interface/web/app/components/appSidebar/appSidebar.tsx b/src/interface/web/app/components/appSidebar/appSidebar.tsx index 811eb7994..45aba3cf6 100644 --- a/src/interface/web/app/components/appSidebar/appSidebar.tsx +++ b/src/interface/web/app/components/appSidebar/appSidebar.tsx @@ -68,7 +68,7 @@ export function AppSidebar(props: AppSidebarProps) { useSidebar(); return ( - + diff --git a/src/interface/web/app/layout.tsx b/src/interface/web/app/layout.tsx index 8fb49fc11..3d2cd4f74 100644 --- a/src/interface/web/app/layout.tsx +++ b/src/interface/web/app/layout.tsx @@ -3,9 +3,6 @@ import { noto_sans, noto_sans_arabic } from "@/app/fonts"; import "./globals.css"; import { ContentSecurityPolicy } from "./common/layoutHelper"; -import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; -import { AppSidebar } from "@/app/components/appSidebar/appSidebar"; - export const metadata: Metadata = { title: "Khoj AI - Ask Anything", description: From 60f80548a47bc66a999a16cfc4728c3e8e3e331c Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sun, 22 Dec 2024 09:21:40 -0800 Subject: [PATCH 07/10] Remove unused span text --- src/interface/web/app/components/appSidebar/appSidebar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/interface/web/app/components/appSidebar/appSidebar.tsx b/src/interface/web/app/components/appSidebar/appSidebar.tsx index 45aba3cf6..590fb8420 100644 --- a/src/interface/web/app/components/appSidebar/appSidebar.tsx +++ b/src/interface/web/app/components/appSidebar/appSidebar.tsx @@ -82,7 +82,6 @@ export function AppSidebar(props: AppSidebarProps) { - Khoj )} From 0fefbac89f9fba954e22305661571318e48a6a50 Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sun, 22 Dec 2024 09:58:21 -0800 Subject: [PATCH 08/10] Improve sidebar experience for not logged in state --- .../allConversations/allConversations.tsx | 12 +++---- .../app/components/appSidebar/appSidebar.tsx | 36 +++++++++++++++++-- .../web/app/components/navMenu/navMenu.tsx | 2 +- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/interface/web/app/components/allConversations/allConversations.tsx b/src/interface/web/app/components/allConversations/allConversations.tsx index 29c43e48d..52c6806eb 100644 --- a/src/interface/web/app/components/allConversations/allConversations.tsx +++ b/src/interface/web/app/components/allConversations/allConversations.tsx @@ -883,13 +883,9 @@ const fetchChatHistory = async (url: string) => { }; export const useChatSessionsFetchRequest = (url: string) => { - const { data, error } = useSWR(url, fetchChatHistory); + const { data, isLoading, error } = useSWR(url, fetchChatHistory); - return { - data, - isLoading: !error && !data, - isError: error, - }; + return { data, isLoading, error }; }; interface SidePanelProps { @@ -965,10 +961,12 @@ export default function AllConversations(props: SidePanelProps) { return ( - Conversations
{authenticatedData && ( <> + + Conversations +
diff --git a/src/interface/web/app/components/appSidebar/appSidebar.tsx b/src/interface/web/app/components/appSidebar/appSidebar.tsx index 590fb8420..d80314b9b 100644 --- a/src/interface/web/app/components/appSidebar/appSidebar.tsx +++ b/src/interface/web/app/components/appSidebar/appSidebar.tsx @@ -20,9 +20,12 @@ import { Gear } from "@phosphor-icons/react/dist/ssr"; import { Plus } from "@phosphor-icons/react"; import { useEffect, useState } from "react"; import AllConversations from "../allConversations/allConversations"; -import NavMenu from "../navMenu/navMenu"; +import FooterMenu from "../navMenu/navMenu"; import { useSidebar } from "@/components/ui/sidebar"; import { useIsMobileWidth } from "@/app/common/utils"; +import { UserPlusIcon } from "lucide-react"; +import { useAuthenticatedData } from "@/app/common/auth"; +import LoginPrompt from "../loginPrompt/loginPrompt"; // Menu items. const items = [ @@ -63,10 +66,19 @@ interface AppSidebarProps { export function AppSidebar(props: AppSidebarProps) { const isMobileWidth = useIsMobileWidth(); + const { data, isLoading, error } = useAuthenticatedData(); const { state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar } = useSidebar(); + const [showLoginPrompt, setShowLoginPrompt] = useState(false); + + useEffect(() => { + if (!isLoading && !data) { + setShowLoginPrompt(true); + } + }, [isLoading, data]); + return ( @@ -89,9 +101,29 @@ export function AppSidebar(props: AppSidebarProps) { + {showLoginPrompt && ( + setShowLoginPrompt(isOpen)} + isMobileWidth={isMobileWidth} + /> + )} + {!isLoading && !data && ( + + setShowLoginPrompt(true)} + > +
+ + Sign up to get started +
+
+
+ )} {items.map((item) => ( @@ -116,7 +148,7 @@ export function AppSidebar(props: AppSidebarProps) {
- +
); diff --git a/src/interface/web/app/components/navMenu/navMenu.tsx b/src/interface/web/app/components/navMenu/navMenu.tsx index d6bfd85ce..434a9e2ed 100644 --- a/src/interface/web/app/components/navMenu/navMenu.tsx +++ b/src/interface/web/app/components/navMenu/navMenu.tsx @@ -43,7 +43,7 @@ interface NavMenuProps { sideBarIsOpen: boolean; } -export default function NavMenu({ sideBarIsOpen }: NavMenuProps) { +export default function FooterMenu({ sideBarIsOpen }: NavMenuProps) { const { data: userData, error: authenticationError, From 7032ccf130e824e55e8b608745a42ba341a4ba61 Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sun, 22 Dec 2024 10:01:15 -0800 Subject: [PATCH 09/10] Show create agent button when not logged in agents page --- src/interface/web/app/agents/page.tsx | 60 ++++++++++++++------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/interface/web/app/agents/page.tsx b/src/interface/web/app/agents/page.tsx index 079006f7b..a31c2901c 100644 --- a/src/interface/web/app/agents/page.tsx +++ b/src/interface/web/app/agents/page.tsx @@ -300,35 +300,37 @@ export default function Agents() {

Agents

- {authenticatedData && ( - - )} +
{showLoginPrompt && ( From 798837378f48783e65e7405603004d7024efa21f Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sun, 22 Dec 2024 11:02:50 -0800 Subject: [PATCH 10/10] Improve mobile friendliness and highlight missing necessary data --- src/interface/web/app/agents/page.tsx | 6 ++- .../app/components/agentCard/agentCard.tsx | 38 ++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/interface/web/app/agents/page.tsx b/src/interface/web/app/agents/page.tsx index a31c2901c..89deb663f 100644 --- a/src/interface/web/app/agents/page.tsx +++ b/src/interface/web/app/agents/page.tsx @@ -140,7 +140,11 @@ function CreateAgentCard(props: CreateAgentCardProps) { Create Agent
- + Create Agent {!props.userProfile && showLoginPrompt && ( @@ -535,6 +535,8 @@ export function AgentModificationForm(props: AgentModificationFormProps) { const basicFields = [ { name: "name", label: "Name" }, { name: "persona", label: "Personality" }, + { name: "color", label: "Color" }, + { name: "icon", label: "Icon" }, ]; const toolsFields = [ @@ -545,17 +547,15 @@ export function AgentModificationForm(props: AgentModificationFormProps) { const knowledgeBaseFields = [{ name: "files", label: "Knowledge Base" }]; const customizationFields = [ - { name: "color", label: "Color" }, - { name: "icon", label: "Icon" }, { name: "chat_model", label: "Chat Model" }, { name: "privacy_level", label: "Privacy Level" }, ]; const formGroups = [ - { fields: basicFields, label: "Basic Settings", tabName: "basic" }, - { fields: customizationFields, label: "Customization & Access", tabName: "customize" }, - { fields: knowledgeBaseFields, label: "Knowledge Base", tabName: "knowledge" }, - { fields: toolsFields, label: "Tools Settings", tabName: "tools" }, + { fields: basicFields, label: "1. Basic Settings", tabName: "basic" }, + { fields: customizationFields, label: "2. Model & Privacy", tabName: "customize" }, + { fields: knowledgeBaseFields, label: "3. Knowledge Base", tabName: "knowledge" }, + { fields: toolsFields, label: "4. Tools", tabName: "tools" }, ]; const fileInputRef = useRef(null); @@ -754,7 +754,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) { control={props.form.control} name="chat_model" render={({ field }) => ( - + Chat Model {!props.isSubscribed ? ( @@ -801,7 +801,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) { control={props.form.control} name="privacy_level" render={({ field }) => ( - +
Privacy Level
@@ -858,7 +858,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) { control={props.form.control} name="color" render={({ field }) => ( - + Color @@ -928,12 +928,12 @@ export function AgentModificationForm(props: AgentModificationFormProps) { control={props.form.control} name="persona" render={({ field }) => ( - + Personality What is the personality, thought process, or tuning of this - agent? Get creative; this is how you can influence the agent - constitution. + agent? This is where you can provide any instructions to the + agent.