Jon/use new runs urls (#3930)
This commit is contained in:
@@ -11,7 +11,7 @@ const useFirstParam = (...paramNames: string[]) => {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useFirstParam };
|
export { useFirstParam };
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { useState } from "react";
|
|||||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||||
import { getClient } from "@/api/AxiosClient";
|
import { getClient } from "@/api/AxiosClient";
|
||||||
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
||||||
|
import * as env from "@/util/env";
|
||||||
|
|
||||||
function isTask(run: Task | WorkflowRunApiResponse): run is Task {
|
function isTask(run: Task | WorkflowRunApiResponse): run is Task {
|
||||||
return "task_id" in run;
|
return "task_id" in run;
|
||||||
@@ -185,7 +186,9 @@ function RunHistory() {
|
|||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
handleNavigate(
|
handleNavigate(
|
||||||
event,
|
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`,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Navigate, Route, Routes, useParams } from "react-router-dom";
|
import { Navigate, Route, Routes, useParams } from "react-router-dom";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { PageLayout } from "@/components/PageLayout";
|
import { PageLayout } from "@/components/PageLayout";
|
||||||
import { Status404 } from "@/components/Status404";
|
import { Status404 } from "@/components/Status404";
|
||||||
@@ -22,12 +23,67 @@ import { WorkflowsPageLayout } from "@/routes/workflows/WorkflowsPageLayout";
|
|||||||
import { useTaskV2Query } from "@/routes/runs/useTaskV2Query";
|
import { useTaskV2Query } from "@/routes/runs/useTaskV2Query";
|
||||||
|
|
||||||
function RunRouter() {
|
function RunRouter() {
|
||||||
let { runId } = useParams();
|
const { runId } = useParams();
|
||||||
|
|
||||||
const { data: task_v2, isLoading } = useTaskV2Query({
|
const { data: task_v2, isLoading } = useTaskV2Query({
|
||||||
id: runId?.startsWith("tsk_v2") ? runId : undefined,
|
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 (
|
||||||
|
<Routes>
|
||||||
|
<Route element={<WorkflowsPageLayout />}>
|
||||||
|
<Route element={<WorkflowRun />}>
|
||||||
|
<Route index element={<Navigate to="overview" replace />} />
|
||||||
|
<Route
|
||||||
|
path="blocks"
|
||||||
|
element={<Navigate to="overview" replace />}
|
||||||
|
/>
|
||||||
|
<Route path="overview" element={<WorkflowRunOverview />} />
|
||||||
|
<Route path="output" element={<WorkflowRunOutput />} />
|
||||||
|
<Route
|
||||||
|
path="parameters"
|
||||||
|
element={<WorkflowPostRunParameters />}
|
||||||
|
/>
|
||||||
|
<Route path="recording" element={<WorkflowRunRecording />} />
|
||||||
|
<Route
|
||||||
|
path="code"
|
||||||
|
element={<WorkflowRunCode showCacheKeyValueSelector={true} />}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runType === "task") {
|
||||||
|
return (
|
||||||
|
<Routes>
|
||||||
|
<Route element={<PageLayout />}>
|
||||||
|
<Route element={<TaskDetails />}>
|
||||||
|
<Route index element={<Navigate to="actions" replace />} />
|
||||||
|
<Route path="actions" element={<TaskActions />} />
|
||||||
|
<Route path="recording" element={<TaskRecording />} />
|
||||||
|
<Route path="parameters" element={<TaskParameters />} />
|
||||||
|
<Route path="diagnostics" element={<StepArtifactsLayout />} />
|
||||||
|
</Route>
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Status404 />;
|
||||||
|
}, [runType]);
|
||||||
|
|
||||||
if (runId?.startsWith("tsk_v2")) {
|
if (runId?.startsWith("tsk_v2")) {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <div>Fetching task details...</div>;
|
return <div>Fetching task details...</div>;
|
||||||
@@ -45,50 +101,10 @@ function RunRouter() {
|
|||||||
return <Status404 />;
|
return <Status404 />;
|
||||||
}
|
}
|
||||||
|
|
||||||
runId = workflowRunId;
|
|
||||||
|
|
||||||
return <Navigate to={`/runs/${workflowRunId}`} replace />;
|
return <Navigate to={`/runs/${workflowRunId}`} replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runId?.startsWith("wr_")) {
|
return routes;
|
||||||
return (
|
|
||||||
<Routes>
|
|
||||||
<Route element={<WorkflowsPageLayout />}>
|
|
||||||
<Route element={<WorkflowRun />}>
|
|
||||||
<Route index element={<Navigate to="overview" replace />} />
|
|
||||||
<Route path="blocks" element={<Navigate to="overview" replace />} />
|
|
||||||
<Route path="overview" element={<WorkflowRunOverview />} />
|
|
||||||
<Route path="output" element={<WorkflowRunOutput />} />
|
|
||||||
<Route path="parameters" element={<WorkflowPostRunParameters />} />
|
|
||||||
<Route path="recording" element={<WorkflowRunRecording />} />
|
|
||||||
<Route
|
|
||||||
path="code"
|
|
||||||
element={<WorkflowRunCode showCacheKeyValueSelector={true} />}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
</Route>
|
|
||||||
</Routes>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runId?.startsWith("tsk_")) {
|
|
||||||
return (
|
|
||||||
<Routes>
|
|
||||||
<Route element={<PageLayout />}>
|
|
||||||
<Route element={<TaskDetails />}>
|
|
||||||
<Route index element={<Navigate to="actions" replace />} />
|
|
||||||
<Route path="actions" element={<TaskActions />} />
|
|
||||||
<Route path="recording" element={<TaskRecording />} />
|
|
||||||
<Route path="parameters" element={<TaskParameters />} />
|
|
||||||
<Route path="diagnostics" element={<StepArtifactsLayout />} />
|
|
||||||
</Route>
|
|
||||||
</Route>
|
|
||||||
</Routes>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback (should not reach here due to earlier check)
|
|
||||||
return <Status404 />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { RunRouter };
|
export { RunRouter };
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { useTaskQuery } from "../../detail/hooks/useTaskQuery";
|
import { useTaskQuery } from "../../detail/hooks/useTaskQuery";
|
||||||
import { CreateNewTaskForm } from "../CreateNewTaskForm";
|
import { CreateNewTaskForm } from "../CreateNewTaskForm";
|
||||||
|
import { useFirstParam } from "@/hooks/useFirstParam";
|
||||||
|
|
||||||
function RetryTask() {
|
function RetryTask() {
|
||||||
const { taskId } = useParams();
|
const taskId = useFirstParam("taskId", "runId");
|
||||||
const { data: task, isLoading } = useTaskQuery({ id: taskId });
|
const { data: task, isLoading } = useTaskQuery({ id: taskId });
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import { statusIsFinalized } from "../types";
|
|||||||
import { MAX_STEPS_DEFAULT } from "../constants";
|
import { MAX_STEPS_DEFAULT } from "../constants";
|
||||||
import { useTaskQuery } from "./hooks/useTaskQuery";
|
import { useTaskQuery } from "./hooks/useTaskQuery";
|
||||||
import { useFirstParam } from "@/hooks/useFirstParam";
|
import { useFirstParam } from "@/hooks/useFirstParam";
|
||||||
|
import * as env from "@/util/env";
|
||||||
|
|
||||||
function createTaskRequestObject(values: TaskApiResponse) {
|
function createTaskRequestObject(values: TaskApiResponse) {
|
||||||
return {
|
return {
|
||||||
@@ -303,7 +304,11 @@ function TaskDetails() {
|
|||||||
workflow &&
|
workflow &&
|
||||||
workflowRun && (
|
workflowRun && (
|
||||||
<Link
|
<Link
|
||||||
to={`/workflows/${workflow.workflow_permanent_id}/${workflowRun.workflow_run_id}/overview`}
|
to={
|
||||||
|
env.useNewRunsUrl
|
||||||
|
? `/runs/${workflowRun.workflow_run_id}`
|
||||||
|
: `/workflows/${workflow.workflow_permanent_id}/${workflowRun.workflow_run_id}/overview`
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{workflow.title}
|
{workflow.title}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import { getLabelForWorkflowParameterType } from "./editor/workflowEditorUtils";
|
|||||||
import { WorkflowParameter } from "./types/workflowTypes";
|
import { WorkflowParameter } from "./types/workflowTypes";
|
||||||
import { WorkflowParameterInput } from "./WorkflowParameterInput";
|
import { WorkflowParameterInput } from "./WorkflowParameterInput";
|
||||||
import { TestWebhookDialog } from "@/components/TestWebhookDialog";
|
import { TestWebhookDialog } from "@/components/TestWebhookDialog";
|
||||||
|
import * as env from "@/util/env";
|
||||||
|
|
||||||
// Utility function to omit specified keys from an object
|
// Utility function to omit specified keys from an object
|
||||||
function omit<T extends Record<string, unknown>, K extends keyof T>(
|
function omit<T extends Record<string, unknown>, K extends keyof T>(
|
||||||
@@ -247,7 +248,9 @@ function RunWorkflowForm({
|
|||||||
queryKey: ["runs"],
|
queryKey: ["runs"],
|
||||||
});
|
});
|
||||||
navigate(
|
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) => {
|
onError: (error: AxiosError) => {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { RunParametersDialog } from "./workflowRun/RunParametersDialog";
|
import { RunParametersDialog } from "./workflowRun/RunParametersDialog";
|
||||||
|
import * as env from "@/util/env";
|
||||||
|
|
||||||
function WorkflowPage() {
|
function WorkflowPage() {
|
||||||
const { workflowPermanentId } = useParams();
|
const { workflowPermanentId } = useParams();
|
||||||
@@ -186,18 +187,19 @@ function WorkflowPage() {
|
|||||||
<TableRow
|
<TableRow
|
||||||
key={workflowRun.workflow_run_id}
|
key={workflowRun.workflow_run_id}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
|
const url = env.useNewRunsUrl
|
||||||
|
? `/runs/${workflowRun.workflow_run_id}`
|
||||||
|
: `/workflows/${workflowPermanentId}/${workflowRun.workflow_run_id}/overview`;
|
||||||
|
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
window.open(
|
window.open(
|
||||||
window.location.origin +
|
window.location.origin + url,
|
||||||
`/workflows/${workflowPermanentId}/${workflowRun.workflow_run_id}/overview`,
|
|
||||||
"_blank",
|
"_blank",
|
||||||
"noopener,noreferrer",
|
"noopener,noreferrer",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigate(
|
navigate(url);
|
||||||
`/workflows/${workflowPermanentId}/${workflowRun.workflow_run_id}/overview`,
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
ReloadIcon,
|
ReloadIcon,
|
||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
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 { statusIsFinalized, statusIsRunningOrQueued } from "../tasks/types";
|
||||||
import { useWorkflowRunWithWorkflowQuery } from "./hooks/useWorkflowRunWithWorkflowQuery";
|
import { useWorkflowRunWithWorkflowQuery } from "./hooks/useWorkflowRunWithWorkflowQuery";
|
||||||
import { WorkflowRunTimeline } from "./workflowRun/WorkflowRunTimeline";
|
import { WorkflowRunTimeline } from "./workflowRun/WorkflowRunTimeline";
|
||||||
@@ -44,6 +44,7 @@ import { cn } from "@/util/utils";
|
|||||||
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
||||||
import { ApiWebhookActionsMenu } from "@/components/ApiWebhookActionsMenu";
|
import { ApiWebhookActionsMenu } from "@/components/ApiWebhookActionsMenu";
|
||||||
import { WebhookReplayDialog } from "@/components/WebhookReplayDialog";
|
import { WebhookReplayDialog } from "@/components/WebhookReplayDialog";
|
||||||
|
import { useFirstParam } from "@/hooks/useFirstParam";
|
||||||
import { type ApiCommandOptions } from "@/util/apiCommands";
|
import { type ApiCommandOptions } from "@/util/apiCommands";
|
||||||
import { useBlockScriptsQuery } from "@/routes/workflows/hooks/useBlockScriptsQuery";
|
import { useBlockScriptsQuery } from "@/routes/workflows/hooks/useBlockScriptsQuery";
|
||||||
import { constructCacheKeyValue } from "@/routes/workflows/editor/utils";
|
import { constructCacheKeyValue } from "@/routes/workflows/editor/utils";
|
||||||
@@ -55,7 +56,7 @@ function WorkflowRun() {
|
|||||||
const embed = searchParams.get("embed");
|
const embed = searchParams.get("embed");
|
||||||
const isEmbedded = embed === "true";
|
const isEmbedded = embed === "true";
|
||||||
const active = searchParams.get("active");
|
const active = searchParams.get("active");
|
||||||
const { workflowRunId } = useParams();
|
const workflowRunId = useFirstParam("workflowRunId", "runId");
|
||||||
const credentialGetter = useCredentialGetter();
|
const credentialGetter = useCredentialGetter();
|
||||||
const apiCredential = useApiCredential();
|
const apiCredential = useApiCredential();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { getClient } from "@/api/AxiosClient";
|
|||||||
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
||||||
import { statusIsNotFinalized } from "@/routes/tasks/types";
|
import { statusIsNotFinalized } from "@/routes/tasks/types";
|
||||||
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { WorkflowRunTimelineItem } from "../types/workflowRunTypes";
|
import { WorkflowRunTimelineItem } from "../types/workflowRunTypes";
|
||||||
import { useWorkflowRunWithWorkflowQuery } from "./useWorkflowRunWithWorkflowQuery";
|
import { useWorkflowRunWithWorkflowQuery } from "./useWorkflowRunWithWorkflowQuery";
|
||||||
import { useGlobalWorkflowsQuery } from "./useGlobalWorkflowsQuery";
|
import { useGlobalWorkflowsQuery } from "./useGlobalWorkflowsQuery";
|
||||||
@@ -10,13 +9,11 @@ import { useFirstParam } from "@/hooks/useFirstParam";
|
|||||||
|
|
||||||
function useWorkflowRunTimelineQuery() {
|
function useWorkflowRunTimelineQuery() {
|
||||||
const workflowRunId = useFirstParam("workflowRunId", "runId");
|
const workflowRunId = useFirstParam("workflowRunId", "runId");
|
||||||
const { workflowPermanentId: workflowPermanentIdParam } = useParams();
|
|
||||||
const credentialGetter = useCredentialGetter();
|
const credentialGetter = useCredentialGetter();
|
||||||
const { data: globalWorkflows } = useGlobalWorkflowsQuery();
|
const { data: globalWorkflows } = useGlobalWorkflowsQuery();
|
||||||
const { data: workflowRun } = useWorkflowRunWithWorkflowQuery();
|
const { data: workflowRun } = useWorkflowRunWithWorkflowQuery();
|
||||||
|
const workflow = workflowRun?.workflow;
|
||||||
const workflowPermanentId =
|
const workflowPermanentId = workflow?.workflow_permanent_id;
|
||||||
workflowPermanentIdParam ?? workflowRun?.workflow?.workflow_permanent_id;
|
|
||||||
|
|
||||||
return useQuery<Array<WorkflowRunTimelineItem>>({
|
return useQuery<Array<WorkflowRunTimelineItem>>({
|
||||||
queryKey: ["workflowRunTimeline", workflowPermanentId, workflowRunId],
|
queryKey: ["workflowRunTimeline", workflowPermanentId, workflowRunId],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Status } from "@/api/types";
|
import { Status } from "@/api/types";
|
||||||
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
|
import { useWorkflowRunWithWorkflowQuery } from "../hooks/useWorkflowRunWithWorkflowQuery";
|
||||||
import { ZoomableImage } from "@/components/ZoomableImage";
|
import { ZoomableImage } from "@/components/ZoomableImage";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { statusIsNotFinalized } from "@/routes/tasks/types";
|
import { statusIsNotFinalized } from "@/routes/tasks/types";
|
||||||
@@ -25,12 +25,14 @@ const wssBaseUrl = import.meta.env.VITE_WSS_BASE_URL;
|
|||||||
|
|
||||||
function WorkflowRunStream(props?: Props) {
|
function WorkflowRunStream(props?: Props) {
|
||||||
const alwaysShowStream = props?.alwaysShowStream ?? false;
|
const alwaysShowStream = props?.alwaysShowStream ?? false;
|
||||||
const { data: workflowRun } = useWorkflowRunQuery();
|
const { data: workflowRun } = useWorkflowRunWithWorkflowQuery();
|
||||||
const [streamImgSrc, setStreamImgSrc] = useState<string>("");
|
const [streamImgSrc, setStreamImgSrc] = useState<string>("");
|
||||||
const showStream =
|
const showStream =
|
||||||
alwaysShowStream || (workflowRun && statusIsNotFinalized(workflowRun));
|
alwaysShowStream || (workflowRun && statusIsNotFinalized(workflowRun));
|
||||||
const credentialGetter = useCredentialGetter();
|
const credentialGetter = useCredentialGetter();
|
||||||
const { workflowRunId, workflowPermanentId } = useParams();
|
const { workflowRunId } = useParams();
|
||||||
|
const workflow = workflowRun?.workflow;
|
||||||
|
const workflowPermanentId = workflow?.workflow_permanent_id;
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -73,6 +75,9 @@ function WorkflowRunStream(props?: Props) {
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: ["workflowRun", workflowPermanentId, workflowRunId],
|
queryKey: ["workflowRun", workflowPermanentId, workflowRunId],
|
||||||
});
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["workflowRun", workflowRunId],
|
||||||
|
});
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: ["workflowTasks", workflowRunId],
|
queryKey: ["workflowTasks", workflowRunId],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ function clearRuntimeApiKey(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useNewRunsUrl = true as const;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
apiBaseUrl,
|
apiBaseUrl,
|
||||||
runsApiBaseUrl,
|
runsApiBaseUrl,
|
||||||
@@ -106,4 +108,5 @@ export {
|
|||||||
getRuntimeApiKey,
|
getRuntimeApiKey,
|
||||||
persistRuntimeApiKey,
|
persistRuntimeApiKey,
|
||||||
clearRuntimeApiKey,
|
clearRuntimeApiKey,
|
||||||
|
useNewRunsUrl,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user