Skip to content

Commit

Permalink
Merge pull request #1017 from khoj-ai/features/update-home-page
Browse files Browse the repository at this point in the history
- Rather than chunky generic cards, make the suggested actions more action oriented, around the problem a user might want to solve. Give them follow-up options. Design still in progress.
  • Loading branch information
sabaimran authored Dec 24, 2024
2 parents d27d291 + 5985ef4 commit 03b4667
Show file tree
Hide file tree
Showing 16 changed files with 717 additions and 989 deletions.
5 changes: 4 additions & 1 deletion src/interface/web/app/agents/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/s
import { AppSidebar } from "../components/appSidebar/appSidebar";
import { Separator } from "@/components/ui/separator";
import { KhojLogoType } from "../components/logo/khojLogo";
import { DialogTitle } from "@radix-ui/react-dialog";

export interface AgentData {
slug: string;
Expand Down Expand Up @@ -145,7 +146,9 @@ function CreateAgentCard(props: CreateAgentCardProps) {
"lg:max-w-screen-lg py-4 overflow-y-scroll h-full md:h-4/6 rounded-lg flex flex-col"
}
>
<DialogHeader>Create Agent</DialogHeader>
<DialogHeader>
<DialogTitle>Create Agent</DialogTitle>
</DialogHeader>
{!props.userProfile && showLoginPrompt && (
<LoginPrompt
onOpenChange={setShowLoginPrompt}
Expand Down
6 changes: 6 additions & 0 deletions src/interface/web/app/common/iconUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ const iconMap: IconMap = {
Broadcast: (color: string, width: string, height: string) => (
<Broadcast className={`${width} ${height} ${color} mr-2`} />
),
Image: (color: string, width: string, height: string) => (
<Image className={`${width} ${height} ${color} mr-2`} />
),
File: (color: string, width: string, height: string) => (
<File className={`${width} ${height} ${color} mr-2`} />
),
};

export function getIconForSlashCommand(command: string, customClassName: string | null = null) {
Expand Down
152 changes: 81 additions & 71 deletions src/interface/web/app/components/agentCard/agentCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import ShareLink from "@/app/components/shareLink/shareLink";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ScrollArea } from "@/components/ui/scroll-area";

export interface AgentData {
slug: string;
Expand Down Expand Up @@ -453,7 +454,9 @@ export function AgentCard(props: AgentCardProps) {
<DialogHeader>
<div className="flex items-center">
{getIconFromIconName(props.data.icon, props.data.color)}
<p className="font-bold text-lg">{props.data.name}</p>
<p className="font-bold text-lg">
<DialogTitle>{props.data.name}</DialogTitle>
</p>
</div>
</DialogHeader>
<div className="max-h-[60vh] overflow-y-scroll text-neutral-500 dark:text-white">
Expand Down Expand Up @@ -649,6 +652,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) {
};

const handleSubmit = (values: any) => {
console.log("Submitting", values);
props.onSubmit(values);
setIsSaving(true);
};
Expand Down Expand Up @@ -937,7 +941,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) {
</FormDescription>
<FormControl>
<Textarea
className="dark:bg-muted"
className="dark:bg-muted focus:outline-none focus-visible:border-orange-500 focus-visible:border-2"
placeholder="You are an excellent biologist, at the top of your field in marine biology."
{...field}
/>
Expand Down Expand Up @@ -967,7 +971,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) {
? `${field.value.length} files selected`
: "Select files"}
</CollapsibleTrigger>
<CollapsibleContent>
<CollapsibleContent className="m-1">
<Command>
<AlertDialog open={warning !== null || error != null}>
<AlertDialogContent>
Expand Down Expand Up @@ -1040,6 +1044,7 @@ export function AgentModificationForm(props: AgentModificationFormProps) {
<CommandItem
value={file}
key={file}
className="break-all"
onSelect={() => {
const currentFiles =
props.form.getValues("files") ||
Expand Down Expand Up @@ -1257,83 +1262,88 @@ export function AgentModificationForm(props: AgentModificationFormProps) {

return (
<Form {...props.form}>
<form
onSubmit={props.form.handleSubmit(handleSubmit)}
className="space-y-6 pb-4 h-full flex flex-col justify-between"
>
<Tabs defaultValue="basic" value={formGroups[currentStep].tabName}>
<TabsList className="grid grid-cols-2 md:grid-cols-4 gap-2 h-fit">
<ScrollArea className="h-full">
<form
onSubmit={props.form.handleSubmit(handleSubmit)}
className="space-y-6 pb-4 px-4 h-full flex flex-col justify-between"
>
<Tabs defaultValue="basic" value={formGroups[currentStep].tabName}>
<TabsList className="grid grid-cols-2 md:grid-cols-4 gap-2 h-fit">
{formGroups.map((group) => (
<TabsTrigger
key={group.tabName}
value={group.tabName}
className={`text-center ${areRequiredFieldsCompletedForCurrentStep(group) ? "" : "text-red-500"}`}
onClick={() =>
setCurrentStep(
formGroups.findIndex(
(g) => g.tabName === group.tabName,
),
)
}
>
{group.label}{" "}
{!areRequiredFieldsCompletedForCurrentStep(group) && "*"}
</TabsTrigger>
))}
</TabsList>
{formGroups.map((group) => (
<TabsTrigger
key={group.tabName}
value={group.tabName}
className={`text-center ${areRequiredFieldsCompletedForCurrentStep(group) ? "" : "text-red-500"}`}
onClick={() =>
setCurrentStep(
formGroups.findIndex((g) => g.tabName === group.tabName),
)
}
>
{group.label}{" "}
{!areRequiredFieldsCompletedForCurrentStep(group) && "*"}
</TabsTrigger>
<TabsContent key={group.tabName} value={group.tabName}>
{group.fields.map((field) => renderFormField(field.name))}
</TabsContent>
))}
</TabsList>
{formGroups.map((group) => (
<TabsContent key={group.tabName} value={group.tabName}>
{group.fields.map((field) => renderFormField(field.name))}
</TabsContent>
))}
</Tabs>
<div className="flex justify-between mt-4">
</Tabs>

{props.errors && (
<Alert className="bg-secondary border-none my-4">
<AlertDescription className="flex items-center gap-1">
<ShieldWarning
weight="fill"
className="h-4 w-4 text-yellow-400 inline"
/>
<span>{props.errors}</span>
</AlertDescription>
</Alert>
)}
</form>
</ScrollArea>
<div className="flex justify-between mt-1 left-0 right-0 bg-background p-1">
<Button
type="button"
variant={"outline"}
onClick={handlePrevious}
disabled={currentStep === 0}
className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
>
<ArrowLeft className="mr-2 h-4 w-4" />
Previous
</Button>
{currentStep < formGroups.length - 1 ? (
<Button
type="button"
variant={"outline"}
onClick={handlePrevious}
disabled={currentStep === 0}
onClick={handleNext}
disabled={
!areRequiredFieldsCompletedForCurrentStep(formGroups[currentStep])
}
className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
>
<ArrowLeft className="mr-2 h-4 w-4" />
Previous
Continue
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
) : (
<Button
type="submit"
variant={"outline"}
disabled={isSaving}
onClick={props.form.handleSubmit(handleSubmit)}
className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
>
<FloppyDisk className="h-4 w-4 mr-2" />
{isSaving ? "Booting..." : "Save"}
</Button>
{currentStep < formGroups.length - 1 ? (
<Button
type="button"
variant={"outline"}
onClick={handleNext}
disabled={
!areRequiredFieldsCompletedForCurrentStep(formGroups[currentStep])
}
className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
>
Continue
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
) : (
<Button
type="submit"
variant={"outline"}
disabled={isSaving}
className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
>
<FloppyDisk className="h-4 w-4 mr-2" />
{isSaving ? "Booting..." : "Save"}
</Button>
)}
</div>

{props.errors && (
<Alert className="bg-secondary border-none my-4">
<AlertDescription className="flex items-center gap-1">
<ShieldWarning
weight="fill"
className="h-4 w-4 text-yellow-400 inline"
/>
<span>{props.errors}</span>
</AlertDescription>
</Alert>
)}
</form>
</div>
</Form>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,6 @@ interface SessionsAndFilesProps {
function SessionsAndFiles(props: SessionsAndFilesProps) {
return (
<div>
{props.data && props.data.length > 5 && (
<ChatSessionsModal data={props.organizedData} sideBarOpen={props.sideBarOpen} />
)}
{props.sideBarOpen && (
<ScrollArea>
<ScrollAreaScrollbar
Expand Down Expand Up @@ -461,6 +458,9 @@ function SessionsAndFiles(props: SessionsAndFilesProps) {
</div>
</ScrollArea>
)}
{props.data && props.data.length > 5 && (
<ChatSessionsModal data={props.organizedData} sideBarOpen={props.sideBarOpen} />
)}
</div>
);
}
Expand Down Expand Up @@ -786,7 +786,7 @@ function ChatSessionsModal({ data, sideBarOpen }: ChatSessionsModalProps) {
>
<span className="flex items-center gap-1">
<ChatsCircle className="inline h-4 w-4 mr-1" />
{sideBarOpen ? "Find Conversation" : ""}
{sideBarOpen ? "All Conversations" : ""}
</span>
</DialogTrigger>
<DialogContent>
Expand Down
53 changes: 45 additions & 8 deletions src/interface/web/app/components/chatInputArea/chatInputArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export interface AttachedFileText {
size: number;
}

export enum ChatInputFocus {
MESSAGE = "message",
FILE = "file",
RESEARCH = "research",
}

interface ChatInputProps {
sendMessage: (message: string) => void;
sendImage: (image: string) => void;
Expand All @@ -77,11 +83,15 @@ interface ChatInputProps {
agentColor?: string;
isResearchModeEnabled?: boolean;
setTriggeredAbort: (value: boolean) => void;
prefillMessage?: string;
focus?: ChatInputFocus;
}

export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((props, ref) => {
const [message, setMessage] = useState("");
const fileInputRef = useRef<HTMLInputElement>(null);
const fileInputButtonRef = useRef<HTMLButtonElement>(null);
const researchModeRef = useRef<HTMLButtonElement>(null);

const [warning, setWarning] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
Expand Down Expand Up @@ -125,6 +135,22 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
}
}, [uploading]);

useEffect(() => {
if (props.prefillMessage === undefined) return;
setMessage(props.prefillMessage);
chatInputRef?.current?.focus();
}, [props.prefillMessage]);

useEffect(() => {
if (props.focus === ChatInputFocus.MESSAGE) {
chatInputRef?.current?.focus();
} else if (props.focus === ChatInputFocus.FILE) {
fileInputButtonRef.current?.focus();
} else if (props.focus === ChatInputFocus.RESEARCH) {
researchModeRef.current?.focus();
}
}, [props.focus]);

useEffect(() => {
async function fetchImageData() {
if (imagePaths.length > 0) {
Expand Down Expand Up @@ -625,14 +651,24 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
/>

<div className="flex items-center">
<Button
variant={"ghost"}
className="!bg-none p-0 m-2 h-auto text-3xl rounded-full text-gray-300 hover:text-gray-500"
disabled={props.sendDisabled || !props.isLoggedIn}
onClick={handleFileButtonClick}
>
<Paperclip className="w-8 h-8" />
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={"ghost"}
className="!bg-none p-0 m-2 h-auto text-3xl rounded-full text-gray-300 hover:text-gray-500"
disabled={props.sendDisabled || !props.isLoggedIn}
onClick={handleFileButtonClick}
ref={fileInputButtonRef}
>
<Paperclip className="w-8 h-8" />
</Button>
</TooltipTrigger>
<TooltipContent>
Attach a PDF, plain text file, or image
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div className="flex-grow flex flex-col w-full gap-1.5 relative">
<Textarea
Expand Down Expand Up @@ -732,6 +768,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
variant="ghost"
className="float-right justify-center gap-1 flex items-center p-1.5 mr-2 h-fit"
disabled={props.sendDisabled || !props.isLoggedIn}
ref={researchModeRef}
onClick={() => {
setUseResearchMode(!useResearchMode);
chatInputRef?.current?.focus();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ function EmailSignInContext({
className="p-6 w-[300px] mx-auto rounded-lg"
disabled={checkEmail}
value={email}
autoFocus={true}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleMagicLinkSignIn();
Expand Down
2 changes: 1 addition & 1 deletion src/interface/web/app/components/navMenu/navMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export default function FooterMenu({ sideBarIsOpen }: NavMenuProps) {
<Avatar
className={`${sideBarIsOpen ? "h-8 w-8" : "h-6 w-6"} border-2 ${userData.is_active ? "border-yellow-500" : "border-stone-700 dark:border-stone-300"}`}
>
<AvatarImage src={userData?.photo} alt="user profile" />
<AvatarImage src={userData.photo} alt="user profile" />
<AvatarFallback className="bg-transparent hover:bg-muted">
{userData.username[0].toUpperCase()}
</AvatarFallback>
Expand Down
Loading

0 comments on commit 03b4667

Please sign in to comment.