- {personalAutomations &&
+ {authenticatedData &&
+ personalAutomations &&
personalAutomations.map((automation) => (
))}
- {allNewAutomations.map((automation) => (
-
- ))}
+ {authenticatedData &&
+ allNewAutomations.map((automation) => (
+
+ ))}
@@ -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 (
-
-
{
- const selectedModelId = Number(e.target.value);
- const selectedModel = models.find((model) => model.id === selectedModelId);
- if (selectedModel) {
- onSelect(selectedModel);
- } else {
- console.error("Selected model not found", e.target.value);
- }
- }}
- disabled={props.disabled}
- >
- {models?.map((model) => (
-
- {model.chat_model}
-
- ))}
-
-
-
-
-
- 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}