Add "Execute on Any Outcome" (Finally) option to blocks - Pair Team request (#4443)

This commit is contained in:
Marc Kelechava
2026-01-13 16:56:06 -08:00
committed by GitHub
parent b321402ba9
commit 40a743e5ca
26 changed files with 373 additions and 49 deletions

View File

@@ -77,10 +77,13 @@ function WorkflowRunOverview() {
}
const workflowRunIsFinalized = statusIsFinalized(workflowRun);
const finallyBlockLabel =
workflowRun.workflow?.workflow_definition?.finally_block_label ?? null;
const selection = findActiveItem(
workflowRunTimeline,
active,
workflowRunIsFinalized,
finallyBlockLabel,
);
const browserSessionId = workflowRun.browser_session_id;

View File

@@ -53,6 +53,9 @@ function WorkflowRunTimeline({
const workflowRunIsNotFinalized = statusIsNotFinalized(workflowRun);
const workflowRunIsFinalized = statusIsFinalized(workflowRun);
const finallyBlockLabel =
workflowRun.workflow?.workflow_definition?.finally_block_label ?? null;
const numberOfActions = workflowRunTimeline.reduce((total, current) => {
if (isTaskVariantBlockItem(current)) {
return total + current.block!.actions!.length;
@@ -104,6 +107,7 @@ function WorkflowRunTimeline({
onActionClick={onActionItemSelected}
onBlockItemClick={onBlockItemSelected}
onThoughtCardClick={onObserverThoughtCardSelected}
finallyBlockLabel={finallyBlockLabel}
/>
);
}

View File

@@ -38,6 +38,7 @@ type Props = {
onBlockItemClick: (block: WorkflowRunBlock) => void;
onActionClick: (action: ActionItem) => void;
onThoughtCardClick: (thought: ObserverThought) => void;
finallyBlockLabel?: string | null;
};
function WorkflowRunTimelineBlockItem({
@@ -47,8 +48,10 @@ function WorkflowRunTimelineBlockItem({
onBlockItemClick,
onActionClick,
onThoughtCardClick,
finallyBlockLabel,
}: Props) {
const actions = block.actions ?? [];
const isFinallyBlock = finallyBlockLabel && block.label === finallyBlockLabel;
const hasActiveAction =
isAction(activeItem) &&
@@ -128,6 +131,11 @@ function WorkflowRunTimelineBlockItem({
<span className="flex gap-2 text-xs text-slate-400">
{block.label}
</span>
{isFinallyBlock && (
<span className="w-fit rounded bg-amber-500 px-1.5 py-0.5 text-[10px] font-medium text-black">
Execute on any outcome
</span>
)}
</div>
</div>
<div className="flex gap-2">
@@ -235,6 +243,7 @@ function WorkflowRunTimelineBlockItem({
onActionClick={onActionClick}
onBlockItemClick={onBlockItemClick}
onThoughtCardClick={onThoughtCardClick}
finallyBlockLabel={finallyBlockLabel}
/>
);
}

View File

@@ -1,6 +1,7 @@
import { useSearchParams } from "react-router-dom";
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
import { useWorkflowRunTimelineQuery } from "../hooks/useWorkflowRunTimelineQuery";
import { useWorkflowRunWithWorkflowQuery } from "../hooks/useWorkflowRunWithWorkflowQuery";
import { statusIsFinalized } from "@/routes/tasks/types";
import { findActiveItem } from "./workflowTimelineUtils";
import { WorkflowRunOverviewActiveElement } from "./WorkflowRunOverview";
@@ -13,14 +14,19 @@ function useActiveWorkflowRunItem(): [
const active = searchParams.get("active");
const { data: workflowRun } = useWorkflowRunQuery();
const { data: workflowRunWithWorkflow } = useWorkflowRunWithWorkflowQuery();
const { data: workflowRunTimeline } = useWorkflowRunTimelineQuery();
const workflowRunIsFinalized = workflowRun && statusIsFinalized(workflowRun);
const finallyBlockLabel =
workflowRunWithWorkflow?.workflow?.workflow_definition
?.finally_block_label ?? null;
const activeItem = findActiveItem(
workflowRunTimeline ?? [],
active,
!!workflowRunIsFinalized,
finallyBlockLabel,
);
function handleSetActiveItem(id: string) {

View File

@@ -31,11 +31,27 @@ function findActiveItem(
timeline: Array<WorkflowRunTimelineItem>,
target: string | null,
workflowRunIsFinalized: boolean,
finallyBlockLabel?: string | null,
): WorkflowRunOverviewActiveElement {
if (target === null) {
if (!workflowRunIsFinalized) {
return "stream";
}
// If there's a finally block, try to show it first when workflow is finalized
if (finallyBlockLabel && timeline?.length > 0) {
const finallyBlock = timeline.find(
(item) => isBlockItem(item) && item.block.label === finallyBlockLabel,
);
if (finallyBlock && isBlockItem(finallyBlock)) {
if (
finallyBlock.block.actions &&
finallyBlock.block.actions.length > 0
) {
return finallyBlock.block.actions[0]!;
}
return finallyBlock.block;
}
}
if (timeline?.length > 0) {
const timelineItem = timeline![0];
if (isBlockItem(timelineItem)) {