add duration to workflow block timeline (#3107)
This commit is contained in:
@@ -50,6 +50,7 @@ export type WorkflowRunBlock = {
|
|||||||
wait_sec?: number | null;
|
wait_sec?: number | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
modified_at: string;
|
modified_at: string;
|
||||||
|
duration: number | null;
|
||||||
|
|
||||||
// for loop block itself
|
// for loop block itself
|
||||||
loop_values: Array<unknown> | null;
|
loop_values: Array<unknown> | null;
|
||||||
|
|||||||
@@ -47,3 +47,33 @@ export const getInitialValues = (
|
|||||||
|
|
||||||
return iv as Record<string, unknown>;
|
return iv as Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface Duration {
|
||||||
|
hour: number;
|
||||||
|
minute: number;
|
||||||
|
second: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toDuration = (seconds: number): Duration => {
|
||||||
|
let minutes = Math.floor(seconds / 60);
|
||||||
|
let hours = Math.floor(minutes / 60);
|
||||||
|
seconds = seconds % 60;
|
||||||
|
minutes = minutes % 60;
|
||||||
|
hours = hours % 24;
|
||||||
|
|
||||||
|
return {
|
||||||
|
hour: Math.floor(hours),
|
||||||
|
minute: Math.floor(minutes),
|
||||||
|
second: Math.floor(seconds),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formatDuration = (duration: Duration): string => {
|
||||||
|
if (duration.hour) {
|
||||||
|
return `${duration.hour}h ${duration.minute}m ${duration.second}s`;
|
||||||
|
} else if (duration.minute) {
|
||||||
|
return `${duration.minute}m ${duration.second}s`;
|
||||||
|
} else {
|
||||||
|
return `${duration.second}s`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { isTaskVariantBlock } from "../types/workflowTypes";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { Status } from "@/api/types";
|
import { Status } from "@/api/types";
|
||||||
|
import { formatDuration, toDuration } from "@/routes/workflows/utils";
|
||||||
import { ThoughtCard } from "./ThoughtCard";
|
import { ThoughtCard } from "./ThoughtCard";
|
||||||
import { ObserverThought } from "../types/workflowRunTypes";
|
import { ObserverThought } from "../types/workflowRunTypes";
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -85,6 +86,9 @@ function WorkflowRunTimelineBlockItem({
|
|||||||
block.status === Status.TimedOut ||
|
block.status === Status.TimedOut ||
|
||||||
block.status === Status.Canceled);
|
block.status === Status.Canceled);
|
||||||
|
|
||||||
|
const duration =
|
||||||
|
block.duration !== null ? formatDuration(toDuration(block.duration)) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -115,7 +119,9 @@ function WorkflowRunTimelineBlockItem({
|
|||||||
<span className="text-sm">
|
<span className="text-sm">
|
||||||
{workflowBlockTitle[block.block_type]}
|
{workflowBlockTitle[block.block_type]}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-slate-400">{block.label}</span>
|
<span className="flex gap-2 text-xs text-slate-400">
|
||||||
|
{block.label}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -129,19 +135,26 @@ function WorkflowRunTimelineBlockItem({
|
|||||||
<CheckCircledIcon className="size-4 text-success" />
|
<CheckCircledIcon className="size-4 text-success" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex gap-1 self-start rounded bg-slate-elevation5 px-2 py-1">
|
<div className="flex flex-col items-end gap-[1px]">
|
||||||
{showDiagnosticLink ? (
|
<div className="flex gap-1 self-start rounded bg-slate-elevation5 px-2 py-1">
|
||||||
<Link to={`/tasks/${block.task_id}/diagnostics`}>
|
{showDiagnosticLink ? (
|
||||||
<div className="flex gap-1">
|
<Link to={`/tasks/${block.task_id}/diagnostics`}>
|
||||||
<ExternalLinkIcon className="size-4" />
|
<div className="flex gap-1">
|
||||||
<span className="text-xs">Diagnostics</span>
|
<ExternalLinkIcon className="size-4" />
|
||||||
</div>
|
<span className="text-xs">Diagnostics</span>
|
||||||
</Link>
|
</div>
|
||||||
) : (
|
</Link>
|
||||||
<>
|
) : (
|
||||||
<CubeIcon className="size-4" />
|
<>
|
||||||
<span className="text-xs">Block</span>
|
<CubeIcon className="size-4" />
|
||||||
</>
|
<span className="text-xs">Block</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{duration && (
|
||||||
|
<div className="pr-[5px] text-xs text-[#00ecff]">
|
||||||
|
{duration}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user