From e9dae4240e896693e59df06474e24e1e5f55730d Mon Sep 17 00:00:00 2001 From: sabaimran Date: Sat, 21 Dec 2024 08:45:43 -0800 Subject: [PATCH] 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 0ec76839..079006f7 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 f7fbb906..a4becd1b 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 91a7c12b..1162379f 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 08a12658..ed77425e 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 aa129469..29c43e48 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 3023f28c..811eb799 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 cb55386a..73dfce36 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 3d1a3752..923a16fe 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 28d1ce4d..00000000 --- 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 2efdd904..00000000 --- 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 b90fa951..e2d63d84 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 4571fb87..b22bf231 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 3178824b..0fe35b97 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 c64d8d3a..ed7d2672 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}