Skip to content

Commit 0097bd4

Browse files
authored
Merge branch 'staging' into fix-data-view
2 parents 56b7b91 + 4581d56 commit 0097bd4

File tree

5 files changed

+111
-56
lines changed

5 files changed

+111
-56
lines changed

app/components/Input.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export default function Input({ value, onValueChange, handleSubmit, graph, icon,
3333
}, [open])
3434

3535
useEffect(() => {
36+
if (!graph.Id) return
37+
3638
let isLastRequest = true
3739
const timeout = setTimeout(async () => {
3840

@@ -75,7 +77,7 @@ export default function Input({ value, onValueChange, handleSubmit, graph, icon,
7577
clearTimeout(timeout)
7678
isLastRequest = false
7779
}
78-
}, [value])
80+
}, [value, graph.Id])
7981

8082
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
8183
const container = containerRef.current

app/components/chat.tsx

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ interface Message {
6969
type: MessageTypes;
7070
text?: string;
7171
paths?: { nodes: any[], edges: any[] }[];
72+
graphName?: string;
7273
}
7374

7475
interface Props {
@@ -92,47 +93,52 @@ const SUGGESTIONS = [
9293

9394
const RemoveLastPath = (messages: Message[]) => {
9495
const index = messages.findIndex((m) => m.type === MessageTypes.Path)
95-
96+
9697
if (index !== -1) {
9798
messages = [...messages.slice(0, index - 2), ...messages.slice(index + 1)];
9899
messages = RemoveLastPath(messages)
99100
}
100-
101+
101102
return messages
102103
}
103104

104105
export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isPath, setIsPath }: Props) {
105-
106+
106107
// Holds the messages in the chat
107108
const [messages, setMessages] = useState<Message[]>([]);
108-
109+
109110
// Holds the messages in the chat
110111
const [paths, setPaths] = useState<{ nodes: any[], edges: any[] }[]>([]);
111-
112+
112113
const [selectedPath, setSelectedPath] = useState<{ nodes: any[], edges: any[] }>();
113-
114+
114115
// Holds the user input while typing
115116
const [query, setQuery] = useState('');
116-
117+
117118
const [isPathResponse, setIsPathResponse] = useState(false);
118-
119+
119120
const [tipOpen, setTipOpen] = useState(false);
120-
121+
121122
const [sugOpen, setSugOpen] = useState(false);
122-
123+
123124
// A reference to the chat container to allow scrolling to the bottom
124125
const containerRef: React.RefObject<HTMLDivElement> = useRef(null);
125-
126+
126127
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))
127-
128+
129+
useEffect(() => {
130+
setSelectedPath(undefined)
131+
setIsPathResponse(false)
132+
}, [graph.Id])
133+
128134
useEffect(() => {
129135
const p = paths.find((path) => [...path.edges, ...path.nodes].some((e: any) => e.id === selectedPathId))
130-
136+
131137
if (!p) return
132-
138+
133139
handleSetSelectedPath(p)
134140
}, [selectedPathId])
135-
141+
136142
// Scroll to the bottom of the chat on new message
137143
useEffect(() => {
138144
setTimeout(() => {
@@ -202,14 +208,28 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
202208
})
203209
chart.elements().filter(el => [...p.nodes, ...p.edges].some(e => e.id == el.id())).layout(LAYOUT).run();
204210
} else {
205-
chart.elements().filter(el => [...p.nodes, ...p.edges].some(e => e.id == el.id())).forEach(el => {
206-
if (el.id() == p.nodes[0].id || el.id() == p.nodes[p.nodes.length - 1].id) {
207-
el.removeStyle().style(SELECTED_PATH_NODE_STYLE);
208-
} else if (el.isNode()) {
209-
el.removeStyle().style(PATH_NODE_STYLE);
211+
const elements: any = { nodes: [], edges: [] };
212+
213+
[...p.nodes, ...p.edges].forEach(e => {
214+
let element = chart.elements(`#${e.id}`)
215+
if (element.length === 0) {
216+
const type = "src_node" in e
217+
e = type ? { ...e, id: e.id.slice(1) } : e
218+
type
219+
? elements.edges.push(e)
220+
: elements.nodes.push(e)
210221
}
211-
if (el.isEdge()) {
212-
el.removeStyle().style(SELECTED_PATH_EDGE_STYLE);
222+
})
223+
224+
chart.add(graph.extend(elements))
225+
chart.elements().filter((e) => [...p.nodes, ...p.edges].some((el) => el.id == e.id())).forEach((e) => {
226+
if (e.id() == p.nodes[0].id || e.id() == p.nodes[p.nodes.length - 1].id) {
227+
e.removeStyle().style(SELECTED_PATH_NODE_STYLE);
228+
} else if (e.isNode()) {
229+
e.removeStyle().style(PATH_NODE_STYLE);
230+
}
231+
if (e.isEdge()) {
232+
e.removeStyle().style(SELECTED_PATH_EDGE_STYLE);
213233
}
214234
}).layout(LAYOUT).run();
215235
}
@@ -329,7 +349,7 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
329349
});
330350
elements.layout(LAYOUT).run()
331351
setPaths(formattedPaths)
332-
setMessages((prev) => [...RemoveLastPath(prev), { type: MessageTypes.PathResponse, paths: formattedPaths }]);
352+
setMessages((prev) => [...RemoveLastPath(prev), { type: MessageTypes.PathResponse, paths: formattedPaths, graphName: graph.Id }]);
333353
setPath(undefined)
334354
setIsPathResponse(true)
335355
}
@@ -341,7 +361,6 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
341361
className="Tip"
342362
onClick={() => {
343363
setTipOpen(false)
344-
setPath({})
345364
setMessages(prev => [
346365
...RemoveLastPath(prev),
347366
{ type: MessageTypes.Query, text: "Create a path" },
@@ -356,7 +375,10 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
356375
type: MessageTypes.Response,
357376
text: "Please select a starting point and the end point. Select or press relevant item on the graph"
358377
}]), 300)
359-
setTimeout(() => setMessages(prev => [...prev, { type: MessageTypes.Path }]), 4000)
378+
setTimeout(() => {
379+
setPath({})
380+
setMessages(prev => [...prev, { type: MessageTypes.Path }])
381+
}, 4000)
360382
}}
361383
>
362384
<Lightbulb />
@@ -431,14 +453,22 @@ export function Chat({ repo, path, setPath, graph, chartRef, selectedPathId, isP
431453
message.paths.map((p, i: number) => (
432454
<button
433455
key={i}
434-
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]")}
456+
className={cn(
457+
"flex text-wrap border p-2 gap-2 rounded-md",
458+
p.nodes.length === selectedPath?.nodes.length &&
459+
selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id)) && selectedPath.nodes.length === p.nodes.length && "border-[#FF66B3] bg-[#FFF0F7]",
460+
message.graphName !== graph.Id && "opacity-50 bg-gray-200"
461+
)}
462+
title={message.graphName !== graph.Id ? `Move to graph ${message.graphName} to use this path` : undefined}
463+
disabled={message.graphName !== graph.Id}
435464
onClick={() => {
436-
if (p.nodes.length === selectedPath?.nodes.length && selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id))) return
437-
handleSetSelectedPath(p)
438-
setIsPath(true)
465+
if (p.nodes.length === selectedPath?.nodes.length &&
466+
selectedPath?.nodes.every(node => p?.nodes.some((n) => n.id === node.id))) return;
467+
handleSetSelectedPath(p);
468+
setIsPath(true);
439469
}}
440470
>
441-
<p className="font-bold">#{i}</p>
471+
<p className="font-bold">#{i + 1}</p>
442472
<div className="flex flex-wrap">
443473
{
444474
p.nodes.map((node: any, j: number) => (

app/components/code-graph.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface Props {
2121
onFetchGraph: (graphName: string) => void,
2222
onFetchNode: (nodeIds: string[]) => Promise<any[]>,
2323
options: string[]
24+
setOptions: Dispatch<SetStateAction<string[]>>
2425
isShowPath: boolean
2526
setPath: Dispatch<SetStateAction<Path | undefined>>
2627
chartRef: MutableRefObject<cytoscape.Core | null>
@@ -119,6 +120,7 @@ export function CodeGraph({
119120
onFetchGraph,
120121
onFetchNode,
121122
options,
123+
setOptions,
122124
isShowPath,
123125
setPath,
124126
chartRef,
@@ -380,7 +382,7 @@ export function CodeGraph({
380382
chartNode.select()
381383
chartNode.style({ display: "element" })
382384
setIsSelectedObj(String(n.id))
383-
const layout = { ...LAYOUT, padding: 250 }
385+
const layout = { ...LAYOUT, padding: chart.width() / 5 }
384386
chartNode.layout(layout).run()
385387
setSearchNode(n)
386388
}
@@ -397,6 +399,7 @@ export function CodeGraph({
397399
<header className="flex flex-col gap-4">
398400
<Combobox
399401
options={options}
402+
setOptions={setOptions}
400403
selectedValue={graphName}
401404
onSelectedValue={handleSelectedValue}
402405
/>

app/components/combobox.tsx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,56 @@
11
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
2+
import { toast } from "@/components/ui/use-toast";
3+
import { useEffect, useState } from "react";
24

35
interface Props {
46
options: string[]
7+
setOptions: (options: string[]) => void
58
selectedValue: string
69
onSelectedValue: (value: string) => void
710

811
}
912

10-
export default function Combobox({ options, selectedValue, onSelectedValue }: Props) {
13+
export default function Combobox({ options, setOptions, selectedValue, onSelectedValue }: Props) {
14+
15+
const [open, setOpen] = useState(false)
16+
const [lastOpened, setLastOpened] = useState<number>();
17+
18+
const fetchOptions = async () => {
19+
const result = await fetch(`/api/repo`, {
20+
method: 'GET',
21+
})
22+
23+
if (!result.ok) {
24+
toast({
25+
variant: "destructive",
26+
title: "Uh oh! Something went wrong.",
27+
description: await result.text(),
28+
})
29+
return
30+
}
31+
32+
const json = await result.json()
33+
setOptions(json.result)
34+
}
35+
36+
useEffect(() => {
37+
fetchOptions()
38+
}, [])
39+
40+
useEffect(() => {
41+
if (!open) return
42+
43+
const now = Date.now();
44+
45+
if (lastOpened && now - lastOpened < 30000) return;
46+
47+
setLastOpened(now);
48+
49+
fetchOptions()
50+
}, [open])
51+
1152
return (
12-
<Select value={selectedValue} onValueChange={onSelectedValue}>
53+
<Select open={open} onOpenChange={setOpen} value={selectedValue} onValueChange={onSelectedValue}>
1354
<SelectTrigger className="rounded-md border focus:ring-0 focus:ring-offset-0">
1455
<SelectValue placeholder="Select a repo" />
1556
</SelectTrigger>

app/page.tsx

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,28 +65,6 @@ export default function Home() {
6565
const [isSubmit, setIsSubmit] = useState<boolean>(false);
6666
const chartRef = useRef<cytoscape.Core | null>(null)
6767

68-
useEffect(() => {
69-
const run = async () => {
70-
const result = await fetch(`/api/repo`, {
71-
method: 'GET',
72-
})
73-
74-
if (!result.ok) {
75-
toast({
76-
variant: "destructive",
77-
title: "Uh oh! Something went wrong.",
78-
description: await result.text(),
79-
})
80-
return
81-
}
82-
83-
const json = await result.json()
84-
setOptions(json.result)
85-
}
86-
87-
run()
88-
}, [])
89-
9068
async function onCreateRepo(e: React.FormEvent<HTMLFormElement>) {
9169
e.preventDefault()
9270

@@ -279,6 +257,7 @@ export default function Home() {
279257
<CodeGraph
280258
chartRef={chartRef}
281259
options={options}
260+
setOptions={setOptions}
282261
onFetchGraph={onFetchGraph}
283262
onFetchNode={onFetchNode}
284263
setPath={setPath}

0 commit comments

Comments
 (0)