-
Notifications
You must be signed in to change notification settings - Fork 264
Expand file tree
/
Copy pathsearchCodeToolComponent.tsx
More file actions
96 lines (89 loc) · 4.12 KB
/
searchCodeToolComponent.tsx
File metadata and controls
96 lines (89 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
'use client';
import { SearchCodeToolUIPart } from "@/features/chat/tools";
import { useDomain } from "@/hooks/useDomain";
import { createPathWithQueryParams, isServiceError } from "@/lib/utils";
import { useMemo, useState } from "react";
import { FileListItem, ToolHeader, TreeList } from "./shared";
import { CodeSnippet } from "@/app/components/codeSnippet";
import { Separator } from "@/components/ui/separator";
import { SearchIcon } from "lucide-react";
import Link from "next/link";
import { SearchQueryParams } from "@/lib/types";
import { PlayIcon } from "@radix-ui/react-icons";
import { buildSearchQuery } from "@/features/chat/utils";
export const SearchCodeToolComponent = ({ part }: { part: SearchCodeToolUIPart }) => {
const [isExpanded, setIsExpanded] = useState(false);
const domain = useDomain();
const displayQuery = useMemo(() => {
if (part.state !== 'input-available' && part.state !== 'output-available') {
return '';
}
const query = buildSearchQuery({
query: part.input.queryRegexp,
repoNamesFilterRegexp: part.input.repoNamesFilterRegexp,
languageNamesFilter: part.input.languageNamesFilter,
fileNamesFilterRegexp: part.input.fileNamesFilterRegexp,
});
return query;
}, [part]);
const label = useMemo(() => {
switch (part.state) {
case 'input-streaming':
return 'Searching...';
case 'output-error':
return '"Search code" tool call failed';
case 'input-available':
case 'output-available':
return <span>Searched for <CodeSnippet>{displayQuery}</CodeSnippet></span>;
}
}, [part, displayQuery]);
return (
<div className="my-4">
<ToolHeader
isLoading={part.state !== 'output-available' && part.state !== 'output-error'}
isError={part.state === 'output-error' || (part.state === 'output-available' && isServiceError(part.output))}
isExpanded={isExpanded}
label={label}
Icon={SearchIcon}
onExpand={setIsExpanded}
/>
{part.state === 'output-available' && isExpanded && (
<>
{isServiceError(part.output) ? (
<TreeList>
<span>Failed with the following error: <CodeSnippet className="text-sm text-destructive">{part.output.message}</CodeSnippet></span>
</TreeList>
) : (
<>
{part.output.files.length === 0 ? (
<span className="text-sm text-muted-foreground ml-[25px]">No matches found</span>
) : (
<TreeList>
{part.output.files.map((file) => {
return (
<FileListItem
key={file.fileName}
path={file.fileName}
repoName={file.repository}
/>
)
})}
</TreeList>
)}
<Link
href={createPathWithQueryParams(`/${domain}/search`,
[SearchQueryParams.query, part.output.query],
)}
className='flex flex-row items-center gap-2 text-sm text-muted-foreground mt-2 ml-auto w-fit hover:text-foreground'
>
<PlayIcon className='h-4 w-4' />
Manually run query
</Link>
</>
)}
<Separator className='ml-[7px] my-2' />
</>
)}
</div>
)
}