From 0da3647105a8098f9218e0d6c8105b9d60c1cb28 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 15 Jun 2023 18:15:11 -0700
Subject: footer sticks to bottom

---
 extension/react-app/src/tabs/gui.tsx | 201 +++++++++++++++++------------------
 1 file changed, 96 insertions(+), 105 deletions(-)

(limited to 'extension/react-app/src/tabs/gui.tsx')

diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 5316f42b..05795cdf 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -21,18 +21,11 @@ import {
 import ComboBox from "../components/ComboBox";
 import TextDialog from "../components/TextDialog";
 
-const MainDiv = styled.div`
-  display: grid;
-  grid-template-rows: 1fr auto;
+const TopGUIDiv = styled.div`
+  overflow: hidden;
 `;
 
-let TopGUIDiv = styled.div`
-  display: grid;
-  grid-template-columns: 1fr;
-  background-color: ${vscBackground};
-`;
-
-let UserInputQueueItem = styled.div`
+const UserInputQueueItem = styled.div`
   border-radius: ${defaultBorderRadius};
   color: gray;
   padding: 8px;
@@ -40,7 +33,7 @@ let UserInputQueueItem = styled.div`
   text-align: center;
 `;
 
-const TopBar = styled.div`
+const Footer = styled.footer`
   display: flex;
   flex-direction: row;
   gap: 8px;
@@ -303,103 +296,101 @@ function GUI(props: GUIProps) {
           setShowFeedbackDialog(false);
         }}
       ></TextDialog>
-      <MainDiv>
-        <TopGUIDiv
-          ref={topGuiDivRef}
-          onKeyDown={(e) => {
-            if (e.key === "Enter" && e.ctrlKey) {
-              onMainTextInput();
-            }
-          }}
-        >
-          {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);
-                }}
-              />
-            );
-          })}
-          {waitingForSteps && <Loader></Loader>}
 
-          <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} />
-
-          <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);
+      <TopGUIDiv
+        ref={topGuiDivRef}
+        onKeyDown={(e) => {
+          if (e.key === "Enter" && e.ctrlKey) {
+            onMainTextInput();
+          }
+        }}
+      >
+        {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);
               }}
-            >
-              Feedback
-              <ChatBubbleOvalLeftEllipsis size="1.6em" />
-            </HeaderButton>
-            <HeaderButton
-              onClick={() => {
-                client?.sendClear();
+              onRetry={() => {
+                client?.retryAtIndex(index);
+                setWaitingForSteps(true);
               }}
-              style={{ padding: "3px" }}
-            >
-              Clear History
-              <Trash size="1.6em" />
-            </HeaderButton>
-          </TopBar>
-        </TopGUIDiv>
-      </MainDiv>
+              onDelete={() => {
+                client?.deleteAtIndex(index);
+              }}
+            />
+          );
+        })}
+        {waitingForSteps && <Loader></Loader>}
+
+        <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>
+      <Footer>
+        <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);
+          }}
+        >
+          Feedback
+          <ChatBubbleOvalLeftEllipsis size="1.6em" />
+        </HeaderButton>
+        <HeaderButton
+          onClick={() => {
+            client?.sendClear();
+          }}
+          style={{ padding: "3px" }}
+        >
+          Clear History
+          <Trash size="1.6em" />
+        </HeaderButton>
+      </Footer>
     </>
   );
 }
-- 
cgit v1.2.3-70-g09d2


From a328d3671529935929ade8c0ca28ccb465699f8e Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 15 Jun 2023 18:22:35 -0700
Subject: hover icons for description

---
 .../src/components/HeaderButtonWithText.tsx        | 26 ++++++++++++++++++++++
 .../react-app/src/components/StepContainer.tsx     | 14 ++++++------
 extension/react-app/src/tabs/gui.tsx               | 21 ++++++++---------
 3 files changed, 42 insertions(+), 19 deletions(-)
 create mode 100644 extension/react-app/src/components/HeaderButtonWithText.tsx

(limited to 'extension/react-app/src/tabs/gui.tsx')

diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx
new file mode 100644
index 00000000..d70a3d70
--- /dev/null
+++ b/extension/react-app/src/components/HeaderButtonWithText.tsx
@@ -0,0 +1,26 @@
+import React, { useState } from "react";
+
+import { HeaderButton } from ".";
+
+interface HeaderButtonWithTextProps {
+  text: string;
+  onClick?: (e: any) => void;
+  children: React.ReactNode;
+}
+
+const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => {
+  const [hover, setHover] = useState(false);
+  return (
+    <HeaderButton
+      style={{ padding: "3px" }}
+      onMouseEnter={() => setHover(true)}
+      onMouseLeave={() => setHover(false)}
+      onClick={props.onClick}
+    >
+      <span hidden={!hover}>{props.text}</span>
+      {props.children}
+    </HeaderButton>
+  );
+};
+
+export default HeaderButtonWithText;
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index b0116e92..480f517f 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -21,9 +21,7 @@ import {
 } from "@styled-icons/heroicons-outline";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import ReactMarkdown from "react-markdown";
-import ContinueButton from "./ContinueButton";
-import InputAndButton from "./InputAndButton";
-import ToggleErrorDiv from "./ToggleErrorDiv";
+import HeaderButtonWithText from "./HeaderButtonWithText";
 
 interface StepContainerProps {
   historyNode: HistoryNode;
@@ -152,23 +150,25 @@ function StepContainer(props: StepContainerProps) {
             </HeaderButton> */}
 
             <>
-              <HeaderButton
+              <HeaderButtonWithText
                 onClick={(e) => {
                   e.stopPropagation();
                   props.onDelete();
                 }}
+                text="Delete"
               >
                 <XMark size="1.6em" onClick={props.onDelete} />
-              </HeaderButton>
+              </HeaderButtonWithText>
               {props.historyNode.observation?.error ? (
-                <HeaderButton
+                <HeaderButtonWithText
+                  text="Retry"
                   onClick={(e) => {
                     e.stopPropagation();
                     props.onRetry();
                   }}
                 >
                   <ArrowPath size="1.6em" onClick={props.onRetry} />
-                </HeaderButton>
+                </HeaderButtonWithText>
               ) : (
                 <></>
               )}
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 05795cdf..279d052b 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -14,12 +14,12 @@ import StepContainer from "../components/StepContainer";
 import useContinueGUIProtocol from "../hooks/useWebsocket";
 import {
   BookOpen,
-  ChatBubbleOvalLeft,
   ChatBubbleOvalLeftEllipsis,
   Trash,
 } from "@styled-icons/heroicons-outline";
 import ComboBox from "../components/ComboBox";
 import TextDialog from "../components/TextDialog";
+import HeaderButtonWithText from "../components/HeaderButtonWithText";
 
 const TopGUIDiv = styled.div`
   overflow: hidden;
@@ -366,30 +366,27 @@ function GUI(props: GUIProps) {
       </TopGUIDiv>
       <Footer>
         <a href="https://continue.dev/docs" className="no-underline">
-          <HeaderButton style={{ padding: "3px" }}>
-            Continue Docs
+          <HeaderButtonWithText text="Continue Docs">
             <BookOpen size="1.6em" />
-          </HeaderButton>
+          </HeaderButtonWithText>
         </a>
-        <HeaderButton
-          style={{ padding: "3px" }}
+        <HeaderButtonWithText
           onClick={() => {
             // Set dialog open
             setShowFeedbackDialog(true);
           }}
+          text="Feedback"
         >
-          Feedback
           <ChatBubbleOvalLeftEllipsis size="1.6em" />
-        </HeaderButton>
-        <HeaderButton
+        </HeaderButtonWithText>
+        <HeaderButtonWithText
           onClick={() => {
             client?.sendClear();
           }}
-          style={{ padding: "3px" }}
+          text="Clear History"
         >
-          Clear History
           <Trash size="1.6em" />
-        </HeaderButton>
+        </HeaderButtonWithText>
       </Footer>
     </>
   );
-- 
cgit v1.2.3-70-g09d2


From 149db209603c5de16d4135f1fdc4f19104974861 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Fri, 16 Jun 2023 11:40:36 -0700
Subject: dlt demo work

---
 continuedev/src/continuedev/core/autopilot.py      |  4 +++
 continuedev/src/continuedev/core/config.py         |  1 +
 .../src/continuedev/libs/util/traceback_parsers.py | 13 ++++++---
 .../recipes/CreatePipelineRecipe/main.py           |  4 ++-
 .../recipes/CreatePipelineRecipe/steps.py          |  4 +--
 extension/react-app/src/index.css                  |  1 +
 extension/react-app/src/tabs/gui.tsx               | 34 ++++++++++++----------
 extension/src/activation/activate.ts               |  6 ++++
 extension/src/continueIdeClient.ts                 |  2 +-
 extension/src/terminal/terminalEmulator.ts         |  7 +++--
 10 files changed, 49 insertions(+), 27 deletions(-)

(limited to 'extension/react-app/src/tabs/gui.tsx')

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 782d6270..73f46a37 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -113,6 +113,10 @@ class Autopilot(ContinueBaseModel):
         await self.update_subscribers()
 
     async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]:
+        # Allow config to set disallowed steps
+        if step.__class__.__name__ in self.continue_sdk.config.disallowed_steps:
+            return None
+
         # If a parent step is deleted/cancelled, don't run this step
         last_depth = self._step_depth
         i = self.history.current_index
diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index d8b29f5b..8f703758 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -22,6 +22,7 @@ class ContinueConfig(BaseModel):
     A pydantic class for the continue config file.
     """
     steps_on_startup: Optional[Dict[str, Dict]] = {}
+    disallowed_steps: Optional[List[str]] = []
     server_url: Optional[str] = None
     allow_anonymous_telemetry: Optional[bool] = True
     default_model: Literal["gpt-3.5-turbo",
diff --git a/continuedev/src/continuedev/libs/util/traceback_parsers.py b/continuedev/src/continuedev/libs/util/traceback_parsers.py
index 1885cc79..a2e94c26 100644
--- a/continuedev/src/continuedev/libs/util/traceback_parsers.py
+++ b/continuedev/src/continuedev/libs/util/traceback_parsers.py
@@ -12,9 +12,14 @@ def get_python_traceback(output: str) -> str:
 
 def get_javascript_traceback(output: str) -> str:
     lines = output.splitlines()
-    if len(lines) > 0:
-        first_line = lines[0].split(": ")
-        if len(lines) > 1 and len(first_line) > 0 and len(first_line[0]) > 0 and "at" in lines[1].lstrip():
-            return output
+    first_line = None
+    for i in range(len(lines) - 1):
+        segs = lines[i].split(":")
+        if len(segs) > 1 and segs[0] != "" and segs[1].startswith(" ") and lines[i + 1].strip().startswith("at"):
+            first_line = lines[i]
+            break
+
+    if first_line is not None:
+        return "\n".join(lines[lines.index(first_line):])
     else:
         return None
diff --git a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py
index 92bddc98..55ef107b 100644
--- a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py
+++ b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/main.py
@@ -27,5 +27,7 @@ class CreatePipelineRecipe(Step):
         await sdk.run_step(
             SetupPipelineStep(api_description=text_observation.text) >>
             ValidatePipelineStep() >>
-            RunQueryStep()
+            RunQueryStep() >>
+            MessageStep(
+                name="Congrats!", message="You've successfully created your first dlt pipeline! 🎉")
         )
diff --git a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py
index 1a756a76..91515dc2 100644
--- a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py
@@ -64,7 +64,7 @@ class SetupPipelineStep(Step):
 
         # wait for user to put API key in secrets.toml
         await sdk.ide.setFileOpen(await sdk.ide.getWorkspaceDirectory() + "/.dlt/secrets.toml")
-        await sdk.wait_for_user_confirmation("If this service requires an API key, please add it to the `secrets.toml` file and then press `Continue`. Otherwise, type '/edit this API does not require an API key'")
+        await sdk.wait_for_user_confirmation("If this service requires an API key, please add it to the `secrets.toml` file and then press `Continue`.")
 
         sdk.context.set("source_name", source_name)
 
@@ -172,5 +172,5 @@ class RunQueryStep(Step):
                 This is a brief summary of the error followed by a suggestion on how it can be fixed:"""))
 
             sdk.raise_exception(
-                title="Error while running query", message=output, with_step=MessageStep(name=f"Suggestion to solve error {AI_ASSISTED_STRING}", message=suggestion)
+                title="Error while running query", message=output, with_step=MessageStep(name=f"Suggestion to solve error {AI_ASSISTED_STRING}", message=suggestion + "\n\nIt is also very likely that no duckdb table was created, which can happen if the resource function did not yield any data. Please make sure that it is yielding data and then rerun this step.")
             )
diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css
index 32a92d0e..db8afab9 100644
--- a/extension/react-app/src/index.css
+++ b/extension/react-app/src/index.css
@@ -22,6 +22,7 @@ html,
 body,
 #root {
   height: 100%;
+  background-color: var(--vsc-background);
 }
 
 body {
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 279d052b..994cb896 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -194,7 +194,7 @@ function GUI(props: GUIProps) {
     if (topGuiDivRef.current) {
       const timeout = setTimeout(() => {
         window.scrollTo({
-          top: window.outerHeight,
+          top: topGuiDivRef.current!.offsetHeight,
           behavior: "smooth",
         });
       }, 200);
@@ -206,7 +206,9 @@ function GUI(props: GUIProps) {
     console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate);
     client?.onStateUpdate((state) => {
       // Scroll only if user is at very bottom of the window.
-      const shouldScrollToBottom = window.outerHeight - window.scrollY < 200;
+      const shouldScrollToBottom =
+        topGuiDivRef.current &&
+        topGuiDivRef.current?.offsetHeight - window.scrollY < 100;
       setWaitingForSteps(state.active);
       setHistory(state.history);
       setUserInputQueue(state.user_input_queue);
@@ -347,12 +349,12 @@ function GUI(props: GUIProps) {
         </div>
 
         <ComboBox
-          disabled={
-            history?.timeline.length
-              ? history.timeline[history.current_index].step.name ===
-                "Waiting for user confirmation"
-              : false
-          }
+          // disabled={
+          //   history?.timeline.length
+          //     ? history.timeline[history.current_index].step.name ===
+          //       "Waiting for user confirmation"
+          //     : false
+          // }
           ref={mainTextInputRef}
           onEnter={(e) => {
             onMainTextInput();
@@ -365,6 +367,14 @@ function GUI(props: GUIProps) {
         <ContinueButton onClick={onMainTextInput} />
       </TopGUIDiv>
       <Footer>
+        <HeaderButtonWithText
+          onClick={() => {
+            client?.sendClear();
+          }}
+          text="Clear History"
+        >
+          <Trash size="1.6em" />
+        </HeaderButtonWithText>
         <a href="https://continue.dev/docs" className="no-underline">
           <HeaderButtonWithText text="Continue Docs">
             <BookOpen size="1.6em" />
@@ -379,14 +389,6 @@ function GUI(props: GUIProps) {
         >
           <ChatBubbleOvalLeftEllipsis size="1.6em" />
         </HeaderButtonWithText>
-        <HeaderButtonWithText
-          onClick={() => {
-            client?.sendClear();
-          }}
-          text="Clear History"
-        >
-          <Trash size="1.6em" />
-        </HeaderButtonWithText>
       </Footer>
     </>
   );
diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts
index 77010241..32726c86 100644
--- a/extension/src/activation/activate.ts
+++ b/extension/src/activation/activate.ts
@@ -59,6 +59,9 @@ export function activateExtension(
       name: "Continue",
     });
     terminal.dispose();
+    if (!ideProtocolClient.continueTerminal) {
+      ideProtocolClient.continueTerminal = capturedTerminal;
+    }
   });
 
   // If any terminals are open to start, replace them
@@ -77,6 +80,9 @@ export function activateExtension(
       }
     );
     terminal.dispose();
+    if (!ideProtocolClient.continueTerminal) {
+      ideProtocolClient.continueTerminal = capturedTerminal;
+    }
   });
 
   extensionContext = context;
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index a889d3dc..9a93a4ef 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -323,7 +323,7 @@ class IdeProtocolClient {
     return rangeInFiles;
   }
 
-  private continueTerminal: CapturedTerminal | undefined;
+  public continueTerminal: CapturedTerminal | undefined;
 
   async runCommand(command: string) {
     if (!this.continueTerminal || this.continueTerminal.isClosed()) {
diff --git a/extension/src/terminal/terminalEmulator.ts b/extension/src/terminal/terminalEmulator.ts
index 9d90b331..ff2060f8 100644
--- a/extension/src/terminal/terminalEmulator.ts
+++ b/extension/src/terminal/terminalEmulator.ts
@@ -76,7 +76,8 @@ export class CapturedTerminal {
       (lines.length > 0 &&
         (last_line.includes("bash-") || last_line.includes(") $ ")) &&
         last_line.includes("$")) ||
-      (last_line.includes("]> ") && last_line.includes(") ["))
+      (last_line.includes("]> ") && last_line.includes(") [")) ||
+      (last_line.includes(" (") && last_line.includes(")>"))
     );
   }
 
@@ -98,7 +99,7 @@ export class CapturedTerminal {
     if (!this.hasRunCommand) {
       this.hasRunCommand = true;
       // Let the first bash- prompt appear and let python env be opened
-      await this.waitForCommandToFinish();
+      // await this.waitForCommandToFinish();
     }
 
     if (this.commandQueue.length === 0) {
@@ -154,7 +155,7 @@ export class CapturedTerminal {
     // Create the pseudo terminal
     this.ptyProcess = pty.spawn(this.shellCmd, [], {
       name: "xterm-256color",
-      cols: 160, // TODO: Get size of vscode terminal, and change with resize
+      cols: 250, // No way to get the size of VS Code terminal, or listen to resize, so make it just bigger than most conceivable VS Code widths
       rows: 26,
       cwd: getRootDir(),
       env,
-- 
cgit v1.2.3-70-g09d2

