Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions app/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ export default function Input({ value, onValueChange, handelSubmit, graph, icon,
case "ArrowUp": {
e.preventDefault()
setSelectedOption(prev => {
containerRef.current?.scrollTo({ behavior: 'smooth', top: (prev <= 0 ? options.length - 1 : prev - 1) * 64 })
containerRef.current?.scrollTo({ behavior: 'smooth', top: (prev <= 0 ? options.length - 1 : prev - 1) * containerRef.current.children[0].clientHeight })
return prev <= 0 ? options.length - 1 : prev - 1
})
return
}
case "ArrowDown": {
e.preventDefault()
setSelectedOption(prev => {
containerRef.current?.scrollTo({ behavior: 'smooth', top: ((prev + 1) % options.length) * 64 })
containerRef.current?.scrollTo({ behavior: 'smooth', top: ((prev + 1) % options.length) * containerRef.current.children[0].clientHeight })
return (prev + 1) % options.length
})
return
Expand Down Expand Up @@ -163,7 +163,6 @@ export default function Input({ value, onValueChange, handelSubmit, graph, icon,
selectedOption === index && "bg-gray-100"
)}
onMouseEnter={() => setSelectedOption(index)}
onMouseLeave={() => setSelectedOption(-1)}
onClick={() => {
onValueChange({ name: option.properties.name, id: option.id })
handelSubmit && handelSubmit(option)
Expand Down
86 changes: 58 additions & 28 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { toast } from "@/components/ui/use-toast";
import { Dispatch, FormEvent, MutableRefObject, SetStateAction, useEffect, useRef, useState } from "react";
import Image from "next/image";
import { AlignLeft, ArrowRight, ChevronDown, Lightbulb, Undo2 } from "lucide-react";
import { AlignLeft, ArrowDown, ArrowRight, ChevronDown, Lightbulb, Undo2 } from "lucide-react";
import { Path } from "../page";
import Input from "./Input";
import { Graph } from "./model";
import { cn } from "@/lib/utils";
import { LAYOUT } from "./code-graph";
import { TypeAnimation } from "react-type-animation";
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";

enum MessageTypes {
Query,
Expand Down Expand Up @@ -35,6 +36,14 @@ interface Props {
setIsPath: (isPathResponse: boolean) => void
}

const SUGGESTIONS = [
"List a few recursive functions",
"What is the name of the most used method?",
"Who is calling the most used method?",
"Which function has the largest number of arguments? List a few arguments",
"Show a calling path between the drop_edge_range_index function and _query, only return function(s) names",
]

const RemoveLastPath = (messages: Message[]) => {
const index = messages.findIndex((m) => m.type === MessageTypes.Path)

Expand Down Expand Up @@ -63,19 +72,13 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP

const [tipOpen, setTipOpen] = useState(false);

const [sugOpen, setSugOpen] = useState(false);

// A reference to the chat container to allow scrolling to the bottom
const containerRef: React.RefObject<HTMLDivElement> = useRef(null);

const tipRef: React.RefObject<HTMLDivElement> = useRef(null);

const isSendMessage = messages.some(m => m.type === MessageTypes.Pending) || (messages.some(m => m.text === "Please select a starting point and the end point. Select or press relevant item on the graph") && !messages.some(m => m.type === MessageTypes.Path))

useEffect(() => {
if (tipOpen) {
tipRef.current?.focus()
}
}, [tipOpen])

useEffect(() => {
const p = paths.find((path) => [...path.edges, ...path.nodes].some((e: any) => e.id === selectedPathId))

Expand Down Expand Up @@ -202,11 +205,13 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
}

// Send the user query to the server
async function sendQuery(event: FormEvent) {
async function sendQuery(event?: FormEvent, sugQuery?: string) {

event.preventDefault();
event?.preventDefault();

const q = query.trim()
if (isSendMessage) return

const q = query?.trim() || sugQuery!

if (!q) {
toast({
Expand Down Expand Up @@ -486,27 +491,52 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
}
{
tipOpen &&
<div ref={tipRef} className="bg-white fixed bottom-[85px] border rounded-md flex flex-col gap-3 p-2 overflow-y-auto" onBlur={() => setTipOpen(false)}>
<div ref={ref => ref?.focus()} className="bg-white absolute bottom-0 border rounded-md flex flex-col gap-3 p-2 overflow-y-auto" tabIndex={-1} onMouseDown={(e) => e.preventDefault()} onBlur={() => setTipOpen(false)}>
{getTip()}
</div>
}
</main>
<footer>
{
repo &&
<div className="flex gap-4 px-4">
<button data-name="lightbulb" disabled={isSendMessage} className="p-4 border rounded-md hover:border-[#FF66B3] hover:bg-[#FFF0F7]" onClick={() => setTipOpen(prev => !prev)}>
<Lightbulb />
</button>
<form className="grow flex items-center border rounded-md pr-2" onSubmit={sendQuery}>
<input disabled={isSendMessage} className="grow p-4 rounded-md focus-visible:outline-none" placeholder="Ask your question" onChange={handleQueryInputChange} value={query} />
<button disabled={isSendMessage} className={`bg-gray-200 p-2 rounded-md ${!isSendMessage && 'hover:bg-gray-300'}`}>
<ArrowRight color="white" />
<DropdownMenu open={sugOpen} onOpenChange={setSugOpen}>
<footer>
{
repo &&
<div className="flex gap-4 px-4">
<button data-name="lightbulb" onClick={() => setTipOpen(prev => !prev)} disabled={isSendMessage} className="p-4 border rounded-md hover:border-[#FF66B3] hover:bg-[#FFF0F7]">
<Lightbulb />
</button>
</form>
</div>
}
</footer>
<form className="grow flex items-center border rounded-md px-2" onSubmit={sendQuery}>
<DropdownMenuTrigger asChild>
<button className="bg-gray-200 p-2 rounded-md hover:bg-gray-300">
<ArrowDown color="white" />
</button>
</DropdownMenuTrigger>
<input className="grow p-4 rounded-md focus-visible:outline-none" placeholder="Ask your question" onChange={handleQueryInputChange} value={query} />
<button disabled={isSendMessage} className={`bg-gray-200 p-2 rounded-md ${!isSendMessage && 'hover:bg-gray-300'}`}>
<ArrowRight color="white" />
</button>
</form>
</div>
}
</footer>
<DropdownMenuContent className="flex flex-col mb-4 w-[20dvw]" side="top">
{
SUGGESTIONS.map((s, i) => (
<button
disabled={isSendMessage}
type="submit"
key={i}
className="p-2 text-left hover:bg-gray-200"
onClick={() => {
sendQuery(undefined, s)
setSugOpen(false)
}}
>
{s}
</button>
))
}
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}
2 changes: 1 addition & 1 deletion app/components/dataPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function DataPanel({ obj, setObj, url }: Props) {
const object = Object.entries(obj).filter(([k]) => !excludedProperties.includes(k))

return (
<div className="z-20 absolute -top-10 left-20 text-white shadow-lg rounded-lg flex flex-col min-h-[65%] max-h-[88%] max-w-[56%] overflow-hidden" >
<div className="z-20 absolute -top-10 left-20 bg-[#343434] text-white shadow-lg rounded-lg flex flex-col max-h-[88%] max-w-[56%] overflow-hidden" >
<header className="bg-[#191919] flex items-center gap-8 justify-between p-8">
<p title={label} className="truncate font-bold">{label.toUpperCase()}</p>
<button onClick={() => setObj(undefined)}>
Expand Down
Loading