From 122b63daeec6cb35d401eccd660759e1745f6778 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 13 Jun 2023 22:56:29 -0700
Subject: feedback dialog

---
 extension/react-app/src/components/TextDialog.tsx |  56 +++++++
 extension/react-app/src/tabs/gui.tsx              | 194 +++++++++++++---------
 2 files changed, 168 insertions(+), 82 deletions(-)
 create mode 100644 extension/react-app/src/components/TextDialog.tsx

(limited to 'extension/react-app/src')

diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx
new file mode 100644
index 00000000..6b335e00
--- /dev/null
+++ b/extension/react-app/src/components/TextDialog.tsx
@@ -0,0 +1,56 @@
+// Write a component that displays a dialog box with a text field and a button.
+import React, { useState } from "react";
+import styled from "styled-components";
+import { Button, buttonColor, secondaryDark, vscBackground } from ".";
+
+const DialogContainer = styled.div`
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+`;
+
+const Dialog = styled.div`
+  background-color: white;
+  border-radius: 8px;
+  padding: 8px;
+  display: flex;
+  flex-direction: column;
+  /* box-shadow: 0 0 10px 0 rgba(255, 255, 255, 0.5); */
+  border: 2px solid ${buttonColor};
+  width: fit-content;
+  margin: auto;
+`;
+
+const TextArea = styled.textarea`
+  border: 1px solid #ccc;
+  border-radius: 8px;
+  padding: 8px;
+  outline: 1px solid black;
+  font-family: Arial, Helvetica, sans-serif;
+`;
+
+const P = styled.p`
+  color: black;
+  margin: 8px auto;
+`;
+
+const TextDialog = (props: {
+  showDialog: boolean;
+  onEnter: (text: string) => void;
+}) => {
+  const [text, setText] = useState("");
+  const textAreaRef = React.createRef<HTMLTextAreaElement>();
+
+  return (
+    <DialogContainer hidden={!props.showDialog}>
+      <Dialog>
+        <P>Thanks for your feedback. We'll get back to you soon!</P>
+        <TextArea cols={50} rows={10} ref={textAreaRef}></TextArea>
+        <Button onClick={() => props.onEnter(text)}>Enter</Button>
+      </Dialog>
+    </DialogContainer>
+  );
+};
+
+export default TextDialog;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index bf6a9401..55c2b763 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -12,8 +12,15 @@ import { History } from "../../../schema/History";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import StepContainer from "../components/StepContainer";
 import useContinueGUIProtocol from "../hooks/useWebsocket";
-import { BookOpen, Trash } from "@styled-icons/heroicons-outline";
+import {
+  BookOpen,
+  ChatBubbleOvalLeft,
+  ChatBubbleOvalLeftEllipsis,
+  Trash,
+} from "@styled-icons/heroicons-outline";
 import ComboBox from "../components/ComboBox";
+import TextDialog from "../components/TextDialog";
+
 let TopGUIDiv = styled.div`
   display: grid;
   grid-template-columns: 1fr;
@@ -31,9 +38,11 @@ let UserInputQueueItem = styled.div`
 const TopBar = styled.div`
   display: flex;
   flex-direction: row;
-  justify-content: space-between;
+  gap: 8px;
+  justify-content: center;
   padding: 8px;
   align-items: center;
+  border-bottom: 0.1px solid gray;
 `;
 
 interface GUIProps {
@@ -170,6 +179,8 @@ function GUI(props: GUIProps) {
   //   current_index: 3,
   // } as any);
 
+  const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
+
   const topGuiDivRef = useRef<HTMLDivElement>(null);
   const client = useContinueGUIProtocol();
 
@@ -275,91 +286,110 @@ function GUI(props: GUIProps) {
 
   // const iterations = useSelector(selectIterations);
   return (
-    <TopGUIDiv
-      ref={topGuiDivRef}
-      onKeyDown={(e) => {
-        if (e.key === "Enter" && e.ctrlKey) {
-          onMainTextInput();
-        }
-      }}
-    >
-      <TopBar>
-        <a href="https://continue.dev/docs" className="no-underline">
-          <HeaderButton style={{ padding: "3px" }}>
-            Continue Docs
-            <BookOpen size="1.6em" />
-          </HeaderButton>
-        </a>
-        <HeaderButton
-          onClick={() => {
-            client?.sendClear();
-          }}
-          style={{ padding: "3px" }}
-        >
-          Clear History
-          <Trash size="1.6em" />
-        </HeaderButton>
-      </TopBar>
-
-      {typeof client === "undefined" && (
-        <>
-          <Loader></Loader>
-          <p style={{ textAlign: "center" }}>
-            Trying to reconnect with server...
-          </p>
-        </>
-      )}
-      {history?.timeline.map((node: HistoryNode, index: number) => {
-        return (
-          <StepContainer
-            key={index}
-            onUserInput={(input: string) => {
-              onStepUserInput(input, index);
-            }}
-            inFuture={index > history?.current_index}
-            historyNode={node}
-            onRefinement={(input: string) => {
-              client?.sendRefinementInput(input, index);
-            }}
-            onReverse={() => {
-              client?.reverseToIndex(index);
-            }}
-            onRetry={() => {
-              client?.retryAtIndex(index);
-              setWaitingForSteps(true);
+    <>
+      <TextDialog
+        showDialog={showFeedbackDialog}
+        onEnter={(text) => {
+          client?.sendMainInput(`/feedback ${text}`);
+          setShowFeedbackDialog(false);
+        }}
+      ></TextDialog>
+      <TopGUIDiv
+        ref={topGuiDivRef}
+        onKeyDown={(e) => {
+          if (e.key === "Enter" && e.ctrlKey) {
+            onMainTextInput();
+          }
+        }}
+      >
+        <TopBar>
+          <a href="https://continue.dev/docs" className="no-underline">
+            <HeaderButton style={{ padding: "3px" }}>
+              Continue Docs
+              <BookOpen size="1.6em" />
+            </HeaderButton>
+          </a>
+          <HeaderButton
+            style={{ padding: "3px" }}
+            onClick={() => {
+              // Set dialog open
+              setShowFeedbackDialog(true);
             }}
-            onDelete={() => {
-              client?.deleteAtIndex(index);
+          >
+            Feedback
+            <ChatBubbleOvalLeftEllipsis size="1.6em" />
+          </HeaderButton>
+          <HeaderButton
+            onClick={() => {
+              client?.sendClear();
             }}
-          />
-        );
-      })}
-      {waitingForSteps && <Loader></Loader>}
+            style={{ padding: "3px" }}
+          >
+            Clear History
+            <Trash size="1.6em" />
+          </HeaderButton>
+        </TopBar>
 
-      <div>
-        {userInputQueue.map((input) => {
-          return <UserInputQueueItem>{input}</UserInputQueueItem>;
+        {typeof client === "undefined" && (
+          <>
+            <Loader></Loader>
+            <p style={{ textAlign: "center" }}>
+              Trying to reconnect with server...
+            </p>
+          </>
+        )}
+        {history?.timeline.map((node: HistoryNode, index: number) => {
+          return (
+            <StepContainer
+              key={index}
+              onUserInput={(input: string) => {
+                onStepUserInput(input, index);
+              }}
+              inFuture={index > history?.current_index}
+              historyNode={node}
+              onRefinement={(input: string) => {
+                client?.sendRefinementInput(input, index);
+              }}
+              onReverse={() => {
+                client?.reverseToIndex(index);
+              }}
+              onRetry={() => {
+                client?.retryAtIndex(index);
+                setWaitingForSteps(true);
+              }}
+              onDelete={() => {
+                client?.deleteAtIndex(index);
+              }}
+            />
+          );
         })}
-      </div>
+        {waitingForSteps && <Loader></Loader>}
 
-      <ComboBox
-        disabled={
-          history?.timeline.length
-            ? history.timeline[history.current_index].step.name ===
-              "Waiting for user confirmation"
-            : false
-        }
-        ref={mainTextInputRef}
-        onEnter={(e) => {
-          onMainTextInput();
-          e.stopPropagation();
-          e.preventDefault();
-        }}
-        onInputValueChange={() => {}}
-        items={availableSlashCommands}
-      />
-      <ContinueButton onClick={onMainTextInput} />
-    </TopGUIDiv>
+        <div>
+          {userInputQueue.map((input) => {
+            return <UserInputQueueItem>{input}</UserInputQueueItem>;
+          })}
+        </div>
+
+        <ComboBox
+          disabled={
+            history?.timeline.length
+              ? history.timeline[history.current_index].step.name ===
+                "Waiting for user confirmation"
+              : false
+          }
+          ref={mainTextInputRef}
+          onEnter={(e) => {
+            onMainTextInput();
+            e.stopPropagation();
+            e.preventDefault();
+          }}
+          onInputValueChange={() => {}}
+          items={availableSlashCommands}
+        />
+        <ContinueButton onClick={onMainTextInput} />
+      </TopGUIDiv>
+    </>
   );
 }
 
-- 
cgit v1.2.3-70-g09d2