diff --git a/skyvern-frontend/src/hooks/useFirstParam.ts b/skyvern-frontend/src/hooks/useFirstParam.ts
index d57206f5..1f9f39a6 100644
--- a/skyvern-frontend/src/hooks/useFirstParam.ts
+++ b/skyvern-frontend/src/hooks/useFirstParam.ts
@@ -11,7 +11,7 @@ const useFirstParam = (...paramNames: string[]) => {
return value;
}
}
- return null;
+ return undefined;
};
export { useFirstParam };
diff --git a/skyvern-frontend/src/routes/history/RunHistory.tsx b/skyvern-frontend/src/routes/history/RunHistory.tsx
index 5eb1e860..0b434621 100644
--- a/skyvern-frontend/src/routes/history/RunHistory.tsx
+++ b/skyvern-frontend/src/routes/history/RunHistory.tsx
@@ -29,6 +29,7 @@ import { useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { getClient } from "@/api/AxiosClient";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
+import * as env from "@/util/env";
function isTask(run: Task | WorkflowRunApiResponse): run is Task {
return "task_id" in run;
@@ -185,7 +186,9 @@ function RunHistory() {
onClick={(event) => {
handleNavigate(
event,
- `/workflows/${run.workflow_permanent_id}/${run.workflow_run_id}/overview`,
+ env.useNewRunsUrl
+ ? `/runs/${run.workflow_run_id}`
+ : `/workflows/${run.workflow_permanent_id}/${run.workflow_run_id}/overview`,
);
}}
>
diff --git a/skyvern-frontend/src/routes/runs/RunRouter.tsx b/skyvern-frontend/src/routes/runs/RunRouter.tsx
index 275934c0..061ca095 100644
--- a/skyvern-frontend/src/routes/runs/RunRouter.tsx
+++ b/skyvern-frontend/src/routes/runs/RunRouter.tsx
@@ -4,6 +4,7 @@
*/
import { Navigate, Route, Routes, useParams } from "react-router-dom";
+import { useMemo } from "react";
import { PageLayout } from "@/components/PageLayout";
import { Status404 } from "@/components/Status404";
@@ -22,12 +23,67 @@ import { WorkflowsPageLayout } from "@/routes/workflows/WorkflowsPageLayout";
import { useTaskV2Query } from "@/routes/runs/useTaskV2Query";
function RunRouter() {
- let { runId } = useParams();
+ const { runId } = useParams();
const { data: task_v2, isLoading } = useTaskV2Query({
id: runId?.startsWith("tsk_v2") ? runId : undefined,
});
+ const runType = runId?.startsWith("tsk_v2")
+ ? "redirect"
+ : runId?.startsWith("wr_")
+ ? "workflow"
+ : runId?.startsWith("tsk_")
+ ? "task"
+ : null;
+
+ const routes = useMemo(() => {
+ if (runType === "workflow") {
+ return (
+
+ }>
+ }>
+ } />
+ }
+ />
+ } />
+ } />
+ }
+ />
+ } />
+ }
+ />
+
+
+
+ );
+ }
+
+ if (runType === "task") {
+ return (
+
+ }>
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+ );
+ }
+
+ return ;
+ }, [runType]);
+
if (runId?.startsWith("tsk_v2")) {
if (isLoading) {
return
Fetching task details...
;
@@ -45,50 +101,10 @@ function RunRouter() {
return ;
}
- runId = workflowRunId;
-
return ;
}
- if (runId?.startsWith("wr_")) {
- return (
-
- }>
- }>
- } />
- } />
- } />
- } />
- } />
- } />
- }
- />
-
-
-
- );
- }
-
- if (runId?.startsWith("tsk_")) {
- return (
-
- }>
- }>
- } />
- } />
- } />
- } />
- } />
-
-
-
- );
- }
-
- // Fallback (should not reach here due to earlier check)
- return ;
+ return routes;
}
export { RunRouter };
diff --git a/skyvern-frontend/src/routes/tasks/create/retry/RetryTask.tsx b/skyvern-frontend/src/routes/tasks/create/retry/RetryTask.tsx
index 123ef149..774a1feb 100644
--- a/skyvern-frontend/src/routes/tasks/create/retry/RetryTask.tsx
+++ b/skyvern-frontend/src/routes/tasks/create/retry/RetryTask.tsx
@@ -1,9 +1,9 @@
-import { useParams } from "react-router-dom";
import { useTaskQuery } from "../../detail/hooks/useTaskQuery";
import { CreateNewTaskForm } from "../CreateNewTaskForm";
+import { useFirstParam } from "@/hooks/useFirstParam";
function RetryTask() {
- const { taskId } = useParams();
+ const taskId = useFirstParam("taskId", "runId");
const { data: task, isLoading } = useTaskQuery({ id: taskId });
if (isLoading) {
diff --git a/skyvern-frontend/src/routes/tasks/detail/TaskDetails.tsx b/skyvern-frontend/src/routes/tasks/detail/TaskDetails.tsx
index f628a519..25db0eaf 100644
--- a/skyvern-frontend/src/routes/tasks/detail/TaskDetails.tsx
+++ b/skyvern-frontend/src/routes/tasks/detail/TaskDetails.tsx
@@ -40,6 +40,7 @@ import { statusIsFinalized } from "../types";
import { MAX_STEPS_DEFAULT } from "../constants";
import { useTaskQuery } from "./hooks/useTaskQuery";
import { useFirstParam } from "@/hooks/useFirstParam";
+import * as env from "@/util/env";
function createTaskRequestObject(values: TaskApiResponse) {
return {
@@ -303,7 +304,11 @@ function TaskDetails() {
workflow &&
workflowRun && (
{workflow.title}
diff --git a/skyvern-frontend/src/routes/workflows/RunWorkflowForm.tsx b/skyvern-frontend/src/routes/workflows/RunWorkflowForm.tsx
index 0ee81d5f..a378f925 100644
--- a/skyvern-frontend/src/routes/workflows/RunWorkflowForm.tsx
+++ b/skyvern-frontend/src/routes/workflows/RunWorkflowForm.tsx
@@ -49,6 +49,7 @@ import { getLabelForWorkflowParameterType } from "./editor/workflowEditorUtils";
import { WorkflowParameter } from "./types/workflowTypes";
import { WorkflowParameterInput } from "./WorkflowParameterInput";
import { TestWebhookDialog } from "@/components/TestWebhookDialog";
+import * as env from "@/util/env";
// Utility function to omit specified keys from an object
function omit, K extends keyof T>(
@@ -247,7 +248,9 @@ function RunWorkflowForm({
queryKey: ["runs"],
});
navigate(
- `/workflows/${workflowPermanentId}/${response.data.workflow_run_id}/overview`,
+ env.useNewRunsUrl
+ ? `/runs/${response.data.workflow_run_id}`
+ : `/workflows/${workflowPermanentId}/${response.data.workflow_run_id}/overview`,
);
},
onError: (error: AxiosError) => {
diff --git a/skyvern-frontend/src/routes/workflows/WorkflowPage.tsx b/skyvern-frontend/src/routes/workflows/WorkflowPage.tsx
index c493e123..2da9c8e1 100644
--- a/skyvern-frontend/src/routes/workflows/WorkflowPage.tsx
+++ b/skyvern-frontend/src/routes/workflows/WorkflowPage.tsx
@@ -49,6 +49,7 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";
import { RunParametersDialog } from "./workflowRun/RunParametersDialog";
+import * as env from "@/util/env";
function WorkflowPage() {
const { workflowPermanentId } = useParams();
@@ -186,18 +187,19 @@ function WorkflowPage() {
{
+ const url = env.useNewRunsUrl
+ ? `/runs/${workflowRun.workflow_run_id}`
+ : `/workflows/${workflowPermanentId}/${workflowRun.workflow_run_id}/overview`;
+
if (event.ctrlKey || event.metaKey) {
window.open(
- window.location.origin +
- `/workflows/${workflowPermanentId}/${workflowRun.workflow_run_id}/overview`,
+ window.location.origin + url,
"_blank",
"noopener,noreferrer",
);
return;
}
- navigate(
- `/workflows/${workflowPermanentId}/${workflowRun.workflow_run_id}/overview`,
- );
+ navigate(url);
}}
className="cursor-pointer"
>
diff --git a/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx b/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
index c1e1a2f6..1902b255 100644
--- a/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
+++ b/skyvern-frontend/src/routes/workflows/WorkflowRun.tsx
@@ -32,7 +32,7 @@ import {
ReloadIcon,
} from "@radix-ui/react-icons";
import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { Link, Outlet, useParams, useSearchParams } from "react-router-dom";
+import { Link, Outlet, useSearchParams } from "react-router-dom";
import { statusIsFinalized, statusIsRunningOrQueued } from "../tasks/types";
import { useWorkflowRunWithWorkflowQuery } from "./hooks/useWorkflowRunWithWorkflowQuery";
import { WorkflowRunTimeline } from "./workflowRun/WorkflowRunTimeline";
@@ -44,6 +44,7 @@ import { cn } from "@/util/utils";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import { ApiWebhookActionsMenu } from "@/components/ApiWebhookActionsMenu";
import { WebhookReplayDialog } from "@/components/WebhookReplayDialog";
+import { useFirstParam } from "@/hooks/useFirstParam";
import { type ApiCommandOptions } from "@/util/apiCommands";
import { useBlockScriptsQuery } from "@/routes/workflows/hooks/useBlockScriptsQuery";
import { constructCacheKeyValue } from "@/routes/workflows/editor/utils";
@@ -55,7 +56,7 @@ function WorkflowRun() {
const embed = searchParams.get("embed");
const isEmbedded = embed === "true";
const active = searchParams.get("active");
- const { workflowRunId } = useParams();
+ const workflowRunId = useFirstParam("workflowRunId", "runId");
const credentialGetter = useCredentialGetter();
const apiCredential = useApiCredential();
const queryClient = useQueryClient();
diff --git a/skyvern-frontend/src/routes/workflows/hooks/useWorkflowRunTimelineQuery.ts b/skyvern-frontend/src/routes/workflows/hooks/useWorkflowRunTimelineQuery.ts
index acca3655..26cc6129 100644
--- a/skyvern-frontend/src/routes/workflows/hooks/useWorkflowRunTimelineQuery.ts
+++ b/skyvern-frontend/src/routes/workflows/hooks/useWorkflowRunTimelineQuery.ts
@@ -2,7 +2,6 @@ import { getClient } from "@/api/AxiosClient";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { statusIsNotFinalized } from "@/routes/tasks/types";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
-import { useParams } from "react-router-dom";
import { WorkflowRunTimelineItem } from "../types/workflowRunTypes";
import { useWorkflowRunWithWorkflowQuery } from "./useWorkflowRunWithWorkflowQuery";
import { useGlobalWorkflowsQuery } from "./useGlobalWorkflowsQuery";
@@ -10,13 +9,11 @@ import { useFirstParam } from "@/hooks/useFirstParam";
function useWorkflowRunTimelineQuery() {
const workflowRunId = useFirstParam("workflowRunId", "runId");
- const { workflowPermanentId: workflowPermanentIdParam } = useParams();
const credentialGetter = useCredentialGetter();
const { data: globalWorkflows } = useGlobalWorkflowsQuery();
const { data: workflowRun } = useWorkflowRunWithWorkflowQuery();
-
- const workflowPermanentId =
- workflowPermanentIdParam ?? workflowRun?.workflow?.workflow_permanent_id;
+ const workflow = workflowRun?.workflow;
+ const workflowPermanentId = workflow?.workflow_permanent_id;
return useQuery>({
queryKey: ["workflowRunTimeline", workflowPermanentId, workflowRunId],
diff --git a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunStream.tsx b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunStream.tsx
index c67e3f8c..00b4f5e3 100644
--- a/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunStream.tsx
+++ b/skyvern-frontend/src/routes/workflows/workflowRun/WorkflowRunStream.tsx
@@ -1,5 +1,5 @@
import { Status } from "@/api/types";
-import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
+import { useWorkflowRunWithWorkflowQuery } from "../hooks/useWorkflowRunWithWorkflowQuery";
import { ZoomableImage } from "@/components/ZoomableImage";
import { useEffect, useState } from "react";
import { statusIsNotFinalized } from "@/routes/tasks/types";
@@ -25,12 +25,14 @@ const wssBaseUrl = import.meta.env.VITE_WSS_BASE_URL;
function WorkflowRunStream(props?: Props) {
const alwaysShowStream = props?.alwaysShowStream ?? false;
- const { data: workflowRun } = useWorkflowRunQuery();
+ const { data: workflowRun } = useWorkflowRunWithWorkflowQuery();
const [streamImgSrc, setStreamImgSrc] = useState("");
const showStream =
alwaysShowStream || (workflowRun && statusIsNotFinalized(workflowRun));
const credentialGetter = useCredentialGetter();
- const { workflowRunId, workflowPermanentId } = useParams();
+ const { workflowRunId } = useParams();
+ const workflow = workflowRun?.workflow;
+ const workflowPermanentId = workflow?.workflow_permanent_id;
const queryClient = useQueryClient();
useEffect(() => {
@@ -73,6 +75,9 @@ function WorkflowRunStream(props?: Props) {
queryClient.invalidateQueries({
queryKey: ["workflowRun", workflowPermanentId, workflowRunId],
});
+ queryClient.invalidateQueries({
+ queryKey: ["workflowRun", workflowRunId],
+ });
queryClient.invalidateQueries({
queryKey: ["workflowTasks", workflowRunId],
});
diff --git a/skyvern-frontend/src/util/env.ts b/skyvern-frontend/src/util/env.ts
index a18b21ca..6170b31e 100644
--- a/skyvern-frontend/src/util/env.ts
+++ b/skyvern-frontend/src/util/env.ts
@@ -94,6 +94,8 @@ function clearRuntimeApiKey(): void {
}
}
+const useNewRunsUrl = true as const;
+
export {
apiBaseUrl,
runsApiBaseUrl,
@@ -106,4 +108,5 @@ export {
getRuntimeApiKey,
persistRuntimeApiKey,
clearRuntimeApiKey,
+ useNewRunsUrl,
};