summaryrefslogtreecommitdiff
path: root/extension/react-app/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'extension/react-app/src/components')
-rw-r--r--extension/react-app/src/components/CodeBlock.tsx1
-rw-r--r--extension/react-app/src/components/ComboBox.tsx146
-rw-r--r--extension/react-app/src/components/StepContainer.tsx67
-rw-r--r--extension/react-app/src/components/index.ts18
4 files changed, 209 insertions, 23 deletions
diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx
index e0336554..eedae3fb 100644
--- a/extension/react-app/src/components/CodeBlock.tsx
+++ b/extension/react-app/src/components/CodeBlock.tsx
@@ -11,6 +11,7 @@ const StyledPre = styled.pre`
border: 1px solid gray;
border-radius: ${defaultBorderRadius};
background-color: ${vscBackground};
+ padding: 8px;
`;
const StyledCode = styled.code`
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
new file mode 100644
index 00000000..1b7c60e6
--- /dev/null
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -0,0 +1,146 @@
+import React, { useCallback } from "react";
+import { useCombobox } from "downshift";
+import styled from "styled-components";
+import {
+ buttonColor,
+ defaultBorderRadius,
+ secondaryDark,
+ vscBackground,
+} from ".";
+
+const mainInputFontSize = 16;
+const MainTextInput = styled.input`
+ padding: 8px;
+ font-size: ${mainInputFontSize}px;
+ border-radius: ${defaultBorderRadius};
+ border: 1px solid #ccc;
+ margin: 8px auto;
+ width: 100%;
+ background-color: ${vscBackground};
+ color: white;
+ outline: 1px solid orange;
+`;
+
+const UlMaxHeight = 200;
+const Ul = styled.ul<{
+ hidden: boolean;
+ showAbove: boolean;
+ ulHeightPixels: number;
+}>`
+ ${(props) =>
+ props.showAbove
+ ? `transform: translateY(-${props.ulHeightPixels + 8}px);`
+ : `transform: translateY(${2 * mainInputFontSize}px);`}
+ position: absolute;
+ background: ${vscBackground};
+ background-color: ${secondaryDark};
+ color: white;
+ font-family: "Fira Code", monospace;
+ max-height: ${UlMaxHeight}px;
+ overflow: scroll;
+ padding: 0;
+ ${({ hidden }) => hidden && "display: none;"}
+ border-radius: ${defaultBorderRadius};
+ overflow: hidden;
+ border: 0.5px solid gray;
+`;
+
+const Li = styled.li<{
+ highlighted: boolean;
+ selected: boolean;
+ isLastItem: boolean;
+}>`
+ ${({ highlighted }) => highlighted && "background: #aa0000;"}
+ ${({ selected }) => selected && "font-weight: bold;"}
+ padding: 0.5rem 0.75rem;
+ display: flex;
+ flex-direction: column;
+ ${({ isLastItem }) => isLastItem && "border-bottom: 1px solid gray;"}
+ border-top: 1px solid gray;
+ cursor: pointer;
+`;
+
+interface ComboBoxProps {
+ items: { name: string; description: string }[];
+ onInputValueChange: (inputValue: string) => void;
+ disabled?: boolean;
+ onEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
+}
+
+const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
+ const [items, setItems] = React.useState(props.items);
+ const {
+ isOpen,
+ getToggleButtonProps,
+ getLabelProps,
+ getMenuProps,
+ getInputProps,
+ highlightedIndex,
+ getItemProps,
+ selectedItem,
+ setInputValue,
+ } = useCombobox({
+ onInputValueChange({ inputValue }) {
+ if (!inputValue) return;
+ props.onInputValueChange(inputValue);
+ setItems(
+ props.items.filter((item) =>
+ item.name.toLowerCase().startsWith(inputValue.toLowerCase())
+ )
+ );
+ },
+ items,
+ itemToString(item) {
+ return item ? item.name : "";
+ },
+ });
+
+ const divRef = React.useRef<HTMLDivElement>(null);
+ const ulRef = React.useRef<HTMLUListElement>(null);
+ const showAbove = () => {
+ return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
+ };
+
+ return (
+ <div className="flex px-2" ref={divRef} hidden={!isOpen}>
+ <MainTextInput
+ disabled={props.disabled}
+ placeholder="Ask anything:"
+ {...getInputProps({
+ onKeyDown: (event) => {
+ if (event.key === "Enter" && (!isOpen || items.length === 0)) {
+ // Prevent Downshift's default 'Enter' behavior.
+ (event.nativeEvent as any).preventDownshiftDefault = true;
+ if (props.onEnter) props.onEnter(event);
+ setInputValue("");
+ }
+ },
+ ref: ref as any,
+ })}
+ />
+ <Ul
+ {...getMenuProps({
+ ref: ulRef,
+ })}
+ showAbove={showAbove()}
+ ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
+ >
+ {isOpen &&
+ items.map((item, index) => (
+ <Li
+ key={`${item.name}${index}`}
+ {...getItemProps({ item, index })}
+ highlighted={highlightedIndex === index}
+ selected={selectedItem === item}
+ >
+ <span>
+ {item.name}: {item.description}
+ </span>
+ </Li>
+ ))}
+ </Ul>
+ </div>
+ );
+});
+
+export default ComboBox;
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 3408053b..ca142b06 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -7,6 +7,7 @@ import {
vscBackground,
GradientBorder,
vscBackgroundTransparent,
+ HeaderButton,
} from ".";
import { RangeInFile, FileEdit } from "../../../src/client";
import CodeBlock from "./CodeBlock";
@@ -15,7 +16,7 @@ import SubContainer from "./SubContainer";
import {
ChevronDown,
ChevronRight,
- Backward,
+ XMark,
ArrowPath,
} from "@styled-icons/heroicons-outline";
import { HistoryNode } from "../../../schema/HistoryNode";
@@ -31,6 +32,7 @@ interface StepContainerProps {
onRefinement: (input: string) => void;
onUserInput: (input: string) => void;
onRetry: () => void;
+ onDelete: () => void;
open?: boolean;
}
@@ -54,8 +56,10 @@ const HeaderDiv = styled.div<{ error: boolean }>`
background-color: ${(props) =>
props.error ? "#522" : vscBackgroundTransparent};
display: grid;
- grid-template-columns: 1fr auto;
+ grid-template-columns: 1fr auto auto;
+ grid-gap: 8px;
align-items: center;
+ padding-right: 8px;
`;
const ContentDiv = styled.div`
@@ -64,26 +68,21 @@ const ContentDiv = styled.div`
background-color: ${vscBackground};
`;
-const HeaderButton = styled.button`
- background-color: transparent;
- border: 1px solid white;
- border-radius: ${defaultBorderRadius};
- padding: 2px;
- cursor: pointer;
- color: white;
-
- &:hover {
- background-color: white;
- color: black;
- }
-`;
-
const OnHoverDiv = styled.div`
text-align: center;
padding: 10px;
animation: ${appear} 0.3s ease-in-out;
`;
+const MarkdownPre = styled.pre`
+ background-color: ${secondaryDark};
+ padding: 10px;
+ border-radius: ${defaultBorderRadius};
+ border: 0.5px solid white;
+`;
+
+const MarkdownCode = styled.code``;
+
function StepContainer(props: StepContainerProps) {
const [open, setOpen] = useState(
typeof props.open === "undefined" ? true : props.open
@@ -152,18 +151,28 @@ function StepContainer(props: StepContainerProps) {
<Backward size="1.6em" onClick={props.onReverse}></Backward>
</HeaderButton> */}
- {props.historyNode.observation?.error ? (
+ <>
<HeaderButton
onClick={(e) => {
e.stopPropagation();
- props.onRetry();
+ props.onDelete();
}}
>
- <ArrowPath size="1.6em" onClick={props.onRetry}></ArrowPath>
+ <XMark size="1.6em" onClick={props.onDelete} />
</HeaderButton>
- ) : (
- <></>
- )}
+ {props.historyNode.observation?.error ? (
+ <HeaderButton
+ onClick={(e) => {
+ e.stopPropagation();
+ props.onRetry();
+ }}
+ >
+ <ArrowPath size="1.6em" onClick={props.onRetry} />
+ </HeaderButton>
+ ) : (
+ <></>
+ )}
+ </>
</HeaderDiv>
</GradientBorder>
<ContentDiv hidden={!open}>
@@ -182,7 +191,19 @@ function StepContainer(props: StepContainerProps) {
{props.historyNode.observation.error as string}
</pre>
) : (
- <ReactMarkdown key={1} className="overflow-scroll">
+ <ReactMarkdown
+ key={1}
+ className="overflow-scroll"
+ components={{
+ pre: ({ node, ...props }) => {
+ return (
+ <CodeBlock
+ children={props.children[0] as string}
+ ></CodeBlock>
+ );
+ },
+ }}
+ >
{props.historyNode.step.description as any}
</ReactMarkdown>
)}
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index 4966f3e8..525989af 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -143,3 +143,21 @@ export const appear = keyframes`
transform: translateY(0px);
}
`;
+
+export const HeaderButton = styled.button`
+ background-color: transparent;
+ border: 1px solid white;
+ border-radius: ${defaultBorderRadius};
+ cursor: pointer;
+ color: white;
+
+ &:hover {
+ background-color: white;
+ color: black;
+ }
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 4px;
+ padding: 1px;
+`;