- {/* sub panels */}
- {workflowPanelState.active && (
+ {/* sub panels in design mode */}
+ {!showBrowser && workflowPanelState.active && (
{
- promote("dropdown");
}}
+ onMouseDownCapture={() => {}}
>
{workflowPanelState.content === "cacheKeyValues" && (
{
- promote("dropdown");
- }}
onPaginate={(page) => {
setPage(page);
}}
@@ -709,17 +705,10 @@ function Workspace({
/>
)}
{workflowPanelState.content === "parameters" && (
- {
- promote("dropdown");
- }}
- />
+
)}
{workflowPanelState.content === "nodeLibrary" && (
{
- promote("dropdown");
- }}
onNodeClick={(props) => {
addNode(props);
}}
@@ -728,110 +717,189 @@ function Workspace({
+ {/* infinite canvas */}
{
- closeWorkflowPanel();
- promote("history");
- }}
+ className={cn("skyvern-split-left h-full w-[33rem]", {
+ "w-full": !showBrowser,
+ })}
>
-
-
- {workflowRunId && (
-
setContent(value)}
- value={content}
- options={[
- {
- label: "Actions",
- value: "actions",
- },
- {
- label: "Inputs",
- value: "inputs",
- },
- {
- label: "Outputs",
- value: "outputs",
- },
- ]}
- />
- )}
-
- {(!workflowRunId || content === "actions") && }
- {workflowRunId && content === "inputs" && (
-
+
+
+
+ {/* divider if browser is in play */}
+ {showBrowser && (
+
+ )}
+
+ {/* browser & timeline & sub-panels in debug mode */}
+ {showBrowser && (
+
+ {/* sub panels */}
+ {workflowPanelState.active && (
+
+ {workflowPanelState.content === "cacheKeyValues" && (
+ {
+ setToDeleteCacheKeyValue(cacheKeyValue);
+ setOpenConfirmCacheKeyValueDeleteDialogue(true);
+ }}
+ onPaginate={(page) => {
+ setPage(page);
+ }}
+ onSelect={(cacheKeyValue) => {
+ setCacheKeyValue(cacheKeyValue);
+ setCacheKeyValueFilter("");
+ closeWorkflowPanel();
+ }}
+ />
)}
- {workflowRunId && content === "outputs" && (
-
+ {workflowPanelState.content === "parameters" && (
+
)}
+ {workflowPanelState.content === "nodeLibrary" && (
+ {
+ addNode(props);
+ }}
+ />
+ )}
+
+ )}
+
+ {/* browser & timeline */}
+
+ {/* browser */}
+
+
+ {activeDebugSession &&
+ activeDebugSession.browser_session_id &&
+ !cycleBrowser.isPending ? (
+
+ ) : (
+
+ Connecting to your browser...
+
+
+ )}
+
+
+
+
+ {/* timeline */}
+
+
{
+ if (timelineMode === "narrow") {
+ setTimelineMode("wide");
+ }
+ }}
+ >
+ {/* timeline wide */}
+
+
+ {/* divider */}
+
+
+ {/* slide indicator */}
+
{
+ e.stopPropagation();
+ setTimelineMode(
+ timelineMode === "wide" ? "narrow" : "wide",
+ );
+ }}
+ >
+ {timelineMode === "narrow" && }
+ {timelineMode === "wide" && }
+
+
+ {/* timeline narrow */}
+
+
+
+
-
- )}
-
- {/* infinite canvas */}
-
promote("infiniteCanvas")}
- zIndex={rankedItems.infiniteCanvas}
- />
-
- {/* browser */}
- {showBrowser && (
- promote("browserWindow")}
- onMinimize={() => {
- setHideControlButtons(true);
- }}
- onMaximize={() => {
- setHideControlButtons(false);
- }}
- onRestore={() => {
- setHideControlButtons(false);
- }}
- >
- {activeDebugSession &&
- activeDebugSession.browser_session_id &&
- !cycleBrowser.isPending ? (
-
- ) : (
-
- Connecting to your browser...
-
-
- )}
-
- )}
+ )}
+
);
}
diff --git a/skyvern-frontend/src/routes/workflows/editor/workspace-styles.css b/skyvern-frontend/src/routes/workflows/editor/workspace-styles.css
new file mode 100644
index 00000000..89af84ba
--- /dev/null
+++ b/skyvern-frontend/src/routes/workflows/editor/workspace-styles.css
@@ -0,0 +1,32 @@
+.vertical-line-gradient {
+ background: linear-gradient(
+ to bottom,
+ transparent 0%,
+ rgba(51, 65, 85, 0.3) 20%,
+ rgba(51, 65, 85, 1) 50%,
+ rgba(51, 65, 85, 0.3) 80%,
+ transparent 100%
+ );
+}
+
+.vertical-gradient-error {
+ background: linear-gradient(
+ to bottom,
+ transparent 0%,
+ rgba(51, 0, 0, 0.3) 5%,
+ rgba(51, 0, 0, 0.4) 50%,
+ rgba(51, 0, 0, 0.3) 95%,
+ transparent 100%
+ );
+}
+
+.vertical-gradient-success {
+ background: linear-gradient(
+ to bottom,
+ transparent 0%,
+ rgba(0, 51, 0, 0.3) 5%,
+ rgba(0, 51, 0, 0.4) 50%,
+ rgba(0, 51, 0, 0.3) 95%,
+ transparent 100%
+ );
+}
diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/ActionCardMinimal.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/ActionCardMinimal.tsx
new file mode 100644
index 00000000..25e1cf59
--- /dev/null
+++ b/skyvern-frontend/src/routes/workflows/workflowRun/ActionCardMinimal.tsx
@@ -0,0 +1,43 @@
+import { LightningBoltIcon } from "@radix-ui/react-icons";
+import { ActionsApiResponse, Status } from "@/api/types";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@/components/ui/tooltip";
+import { ActionTypePillMinimal } from "@/routes/tasks/detail/ActionTypePillMinimal";
+import { ItemStatusIndicator } from "./ItemStatusIndicator";
+
+type Props = {
+ action: ActionsApiResponse;
+};
+
+function ActionCardMinimal({ action }: Props) {
+ const success =
+ action.status === Status.Completed || action.status === Status.Skipped;
+
+ return (
+
+
+
+ {action.created_by === "script" && (
+
+
+
+
+
+
+
+
+ Code Execution
+
+
+
+ )}
+
+
+ );
+}
+
+export { ActionCardMinimal };
diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/ItemStatusIndicator.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/ItemStatusIndicator.tsx
new file mode 100644
index 00000000..bfbdd7db
--- /dev/null
+++ b/skyvern-frontend/src/routes/workflows/workflowRun/ItemStatusIndicator.tsx
@@ -0,0 +1,35 @@
+import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons";
+
+interface Props {
+ children: React.ReactNode;
+ offset?: string;
+ failure?: boolean;
+ success?: boolean;
+}
+
+function ItemStatusIndicator({
+ children,
+ offset = "-0.6rem",
+ failure,
+ success,
+}: Props) {
+ return (
+
+ {children}
+ {success && (
+
+ )}
+ {failure && (
+
+ )}
+
+ );
+}
+
+export { ItemStatusIndicator };
diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/ThoughtCardMinimal.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/ThoughtCardMinimal.tsx
new file mode 100644
index 00000000..c9f91ee9
--- /dev/null
+++ b/skyvern-frontend/src/routes/workflows/workflowRun/ThoughtCardMinimal.tsx
@@ -0,0 +1,17 @@
+import { ObserverThought } from "../types/workflowRunTypes";
+import { Tip } from "@/components/Tip";
+import { BrainIcon } from "@/components/icons/BrainIcon";
+
+type Props = {
+ thought: ObserverThought;
+};
+
+function ThoughtCardMinimal({ thought }: Props) {
+ return (
+
+
+
+ );
+}
+
+export { ThoughtCardMinimal };
diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunTimelineBlockItemMinimal.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunTimelineBlockItemMinimal.tsx
new file mode 100644
index 00000000..8d3b3dce
--- /dev/null
+++ b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunTimelineBlockItemMinimal.tsx
@@ -0,0 +1,76 @@
+import { Tip } from "@/components/Tip";
+import { workflowBlockTitle } from "../editor/nodes/types";
+import { WorkflowBlockIcon } from "../editor/nodes/WorkflowBlockIcon";
+import {
+ isBlockItem,
+ isThoughtItem,
+ WorkflowRunBlock,
+ WorkflowRunTimelineItem,
+} from "../types/workflowRunTypes";
+import { ActionCardMinimal } from "./ActionCardMinimal";
+import { Status } from "@/api/types";
+import { ThoughtCardMinimal } from "./ThoughtCardMinimal";
+import { ItemStatusIndicator } from "./ItemStatusIndicator";
+
+type Props = {
+ block: WorkflowRunBlock;
+ subItems: Array
;
+};
+
+function WorkflowRunTimelineBlockItemMinimal({ block, subItems }: Props) {
+ const actions = block.actions ?? [];
+ const showStatusIndicator = block.status !== null;
+ const showSuccessIndicator =
+ showStatusIndicator && block.status === Status.Completed;
+ const showFailureIndicator =
+ showStatusIndicator &&
+ (block.status === Status.Failed ||
+ block.status === Status.Terminated ||
+ block.status === Status.TimedOut ||
+ block.status === Status.Canceled);
+
+ return (
+
+
+
+
+
+
+
+ {actions.length > 0 && (
+
+ {actions.map((action) => {
+ return
;
+ })}
+
+ )}
+ {subItems.map((item) => {
+ if (isBlockItem(item)) {
+ return (
+
+ );
+ }
+ if (isThoughtItem(item)) {
+ return (
+
+ );
+ }
+ })}
+
+ );
+}
+
+export { WorkflowRunTimelineBlockItemMinimal };