|
1 | | -import { HTMLAttributes, forwardRef, useMemo, useState } from "react" |
2 | | -import { Virtuoso } from "react-virtuoso" |
3 | | -import { ChevronDown } from "lucide-react" |
| 1 | +import { forwardRef, useState } from "react" |
| 2 | +import { useTranslation } from "react-i18next" |
4 | 3 |
|
5 | 4 | import { useExtensionState } from "@src/context/ExtensionStateContext" |
6 | | -import { cn } from "@src/lib/utils" |
| 5 | +import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock" |
7 | 6 |
|
8 | 7 | interface CommandExecutionProps { |
9 | 8 | command: string |
10 | 9 | output: string |
11 | 10 | } |
12 | 11 |
|
13 | 12 | export const CommandExecution = forwardRef<HTMLDivElement, CommandExecutionProps>(({ command, output }, ref) => { |
| 13 | + const { t } = useTranslation() |
14 | 14 | const { terminalShellIntegrationDisabled = false } = useExtensionState() |
15 | | - |
16 | | - // If we aren't opening the VSCode terminal for this command then we default |
17 | | - // to expanding the command execution output. |
18 | 15 | const [isExpanded, setIsExpanded] = useState(terminalShellIntegrationDisabled) |
19 | 16 |
|
20 | | - const lines = useMemo(() => output.split("\n"), [output]) |
| 17 | + const onToggleExpand = () => { |
| 18 | + setIsExpanded(!isExpanded) |
| 19 | + } |
21 | 20 |
|
22 | 21 | return ( |
23 | | - <div ref={ref} className="w-full p-2 rounded-xs bg-vscode-editor-background"> |
| 22 | + <> |
24 | 23 | <div |
25 | | - className={cn("flex flex-row justify-between cursor-pointer active:opacity-75", { |
26 | | - "opacity-50": isExpanded, |
27 | | - })} |
28 | | - onClick={() => setIsExpanded(!isExpanded)}> |
29 | | - <Line>{command}</Line> |
30 | | - <ChevronDown className={cn("size-4 transition-transform duration-300", { "rotate-180": isExpanded })} /> |
31 | | - </div> |
32 | | - <div className={cn("h-[200px]", { hidden: !isExpanded })}> |
33 | | - <Virtuoso |
34 | | - className="h-full mt-2" |
35 | | - totalCount={lines.length} |
36 | | - itemContent={(i) => <Line>{lines[i]}</Line>} |
37 | | - followOutput="auto" |
38 | | - /> |
| 24 | + ref={ref} |
| 25 | + style={{ |
| 26 | + borderRadius: 3, |
| 27 | + border: "1px solid var(--vscode-editorGroup-border)", |
| 28 | + overflow: "hidden", |
| 29 | + backgroundColor: CODE_BLOCK_BG_COLOR, |
| 30 | + }}> |
| 31 | + <CodeBlock source={command} language="shell" /> |
| 32 | + {output.length > 0 && ( |
| 33 | + <div style={{ width: "100%" }}> |
| 34 | + <div |
| 35 | + onClick={onToggleExpand} |
| 36 | + style={{ |
| 37 | + display: "flex", |
| 38 | + alignItems: "center", |
| 39 | + gap: "4px", |
| 40 | + width: "100%", |
| 41 | + justifyContent: "flex-start", |
| 42 | + cursor: "pointer", |
| 43 | + padding: `2px 8px ${isExpanded ? 0 : 8}px 8px`, |
| 44 | + }}> |
| 45 | + <span className={`codicon codicon-chevron-${isExpanded ? "down" : "right"}`}></span> |
| 46 | + <span style={{ fontSize: "0.8em" }}>{t("chat:commandOutput")}</span> |
| 47 | + </div> |
| 48 | + {isExpanded && <CodeBlock source={output} language="log" />} |
| 49 | + </div> |
| 50 | + )} |
39 | 51 | </div> |
40 | | - </div> |
| 52 | + </> |
41 | 53 | ) |
42 | 54 | }) |
43 | 55 |
|
44 | | -type LineProps = HTMLAttributes<HTMLDivElement> |
45 | | - |
46 | | -const Line = ({ className, ...props }: LineProps) => { |
47 | | - return ( |
48 | | - <div |
49 | | - className={cn("font-mono text-vscode-editor-foreground whitespace-pre-wrap break-words", className)} |
50 | | - {...props} |
51 | | - /> |
52 | | - ) |
53 | | -} |
54 | | - |
55 | 56 | CommandExecution.displayName = "CommandExecution" |
0 commit comments