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
4 changes: 3 additions & 1 deletion app/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export default function Input({ value, onValueChange, handleSubmit, graph, icon,
}, [open])

useEffect(() => {
if (!graph.Id) return

let isLastRequest = true
const timeout = setTimeout(async () => {

Expand Down Expand Up @@ -75,7 +77,7 @@ export default function Input({ value, onValueChange, handleSubmit, graph, icon,
clearTimeout(timeout)
isLastRequest = false
}
}, [value])
}, [value, graph.Id])

const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
const container = containerRef.current
Expand Down
90 changes: 60 additions & 30 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ interface Message {
type: MessageTypes;
text?: string;
paths?: { nodes: any[], edges: any[] }[];
graphName?: string;
}

interface Props {
Expand All @@ -92,47 +93,52 @@ const SUGGESTIONS = [

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

if (index !== -1) {
messages = [...messages.slice(0, index - 2), ...messages.slice(index + 1)];
messages = RemoveLastPath(messages)
}

return messages
}

export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isPath, setIsPath }: Props) {

// Holds the messages in the chat
const [messages, setMessages] = useState<Message[]>([]);

// Holds the messages in the chat
const [paths, setPaths] = useState<{ nodes: any[], edges: any[] }[]>([]);

const [selectedPath, setSelectedPath] = useState<{ nodes: any[], edges: any[] }>();

// Holds the user input while typing
const [query, setQuery] = useState('');

const [isPathResponse, setIsPathResponse] = useState(false);

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 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(() => {
setSelectedPath(undefined)
setIsPathResponse(false)
}, [graph.Id])

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

if (!p) return

handleSetSelectedPath(p)
}, [selectedPathId])

// Scroll to the bottom of the chat on new message
useEffect(() => {
setTimeout(() => {
Expand Down Expand Up @@ -202,14 +208,28 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
})
chart.elements().filter(el => [...p.nodes, ...p.edges].some(e => e.id == el.id())).layout(LAYOUT).run();
} else {
chart.elements().filter(el => [...p.nodes, ...p.edges].some(e => e.id == el.id())).forEach(el => {
if (el.id() == p.nodes[0].id || el.id() == p.nodes[p.nodes.length - 1].id) {
el.removeStyle().style(SELECTED_PATH_NODE_STYLE);
} else if (el.isNode()) {
el.removeStyle().style(PATH_NODE_STYLE);
const elements: any = { nodes: [], edges: [] };

[...p.nodes, ...p.edges].forEach(e => {
let element = chart.elements(`#${e.id}`)
if (element.length === 0) {
const type = "src_node" in e
e = type ? { ...e, id: e.id.slice(1) } : e
type
? elements.edges.push(e)
: elements.nodes.push(e)
}
if (el.isEdge()) {
el.removeStyle().style(SELECTED_PATH_EDGE_STYLE);
})

chart.add(graph.extend(elements))
chart.elements().filter((e) => [...p.nodes, ...p.edges].some((el) => el.id == e.id())).forEach((e) => {
if (e.id() == p.nodes[0].id || e.id() == p.nodes[p.nodes.length - 1].id) {
e.removeStyle().style(SELECTED_PATH_NODE_STYLE);
} else if (e.isNode()) {
e.removeStyle().style(PATH_NODE_STYLE);
}
if (e.isEdge()) {
e.removeStyle().style(SELECTED_PATH_EDGE_STYLE);
}
}).layout(LAYOUT).run();
}
Expand Down Expand Up @@ -329,7 +349,7 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
});
elements.layout(LAYOUT).run()
setPaths(formattedPaths)
setMessages((prev) => [...RemoveLastPath(prev), { type: MessageTypes.PathResponse, paths: formattedPaths }]);
setMessages((prev) => [...RemoveLastPath(prev), { type: MessageTypes.PathResponse, paths: formattedPaths, graphName: graph.Id }]);
setPath(undefined)
setIsPathResponse(true)
}
Expand All @@ -341,7 +361,6 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
className="Tip"
onClick={() => {
setTipOpen(false)
setPath({})
setMessages(prev => [
...RemoveLastPath(prev),
{ type: MessageTypes.Query, text: "Create a path" },
Expand All @@ -356,7 +375,10 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
type: MessageTypes.Response,
text: "Please select a starting point and the end point. Select or press relevant item on the graph"
}]), 300)
setTimeout(() => setMessages(prev => [...prev, { type: MessageTypes.Path }]), 4000)
setTimeout(() => {
setPath({})
setMessages(prev => [...prev, { type: MessageTypes.Path }])
}, 4000)
}}
>
<Lightbulb />
Expand Down Expand Up @@ -431,14 +453,22 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
message.paths.map((p, i: number) => (
<button
key={i}
className={cn("flex text-wrap border p-2 gap-2 rounded-md", p.nodes.length === selectedPath?.nodes.length && selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id)) && "border-[#FF66B3] bg-[#FFF0F7]")}
className={cn(
"flex text-wrap border p-2 gap-2 rounded-md",
p.nodes.length === selectedPath?.nodes.length &&
selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id)) && selectedPath.nodes.length === p.nodes.length && "border-[#FF66B3] bg-[#FFF0F7]",
message.graphName !== graph.Id && "opacity-50 bg-gray-200"
)}
title={message.graphName !== graph.Id ? `Move to graph ${message.graphName} to use this path` : undefined}
disabled={message.graphName !== graph.Id}
onClick={() => {
if (p.nodes.length === selectedPath?.nodes.length && selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id))) return
handleSetSelectedPath(p)
setIsPath(true)
if (p.nodes.length === selectedPath?.nodes.length &&
selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id))) return;
handleSetSelectedPath(p);
setIsPath(true);
}}
>
<p className="font-bold">#{i}</p>
<p className="font-bold">#{i + 1}</p>
<div className="flex flex-wrap">
{
p.nodes.map((node: any, j: number) => (
Expand Down
Loading