From 8ceb03ce1a555da99bdb2a6a639811801228cbcf Mon Sep 17 00:00:00 2001 From: Reinier van der Leer Date: Thu, 3 Apr 2025 23:34:33 +0200 Subject: [PATCH] feat(frontend/library): Add "Open in builder" run action (#9755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Resolves #9730 ### Changes 🏗️ - feat: Add "Open in builder" run action - refactor: Add `ActionButtonGroup` to replace boilerplate code in `AgentRunDetailsView`, `AgentRunDraftView`, `AgentScheduleDetailsView` - feat: Add link support to `ActionButtonGroup`, `ButtonAction` ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - Go to `/library/agents/[id]` - [x] "Run again" button works - [x] "Open in builder" button-link works --- .../src/app/library/agents/[id]/page.tsx | 11 ++-- .../agents/agent-run-details-view.tsx | 51 +++++++++---------- .../agents/agent-run-draft-view.tsx | 28 ++-------- .../agents/agent-schedule-details-view.tsx | 26 ++-------- .../components/agptui/action-button-group.tsx | 41 +++++++++++++++ .../frontend/src/components/agptui/types.ts | 3 +- 6 files changed, 78 insertions(+), 82 deletions(-) create mode 100644 autogpt_platform/frontend/src/components/agptui/action-button-group.tsx diff --git a/autogpt_platform/frontend/src/app/library/agents/[id]/page.tsx b/autogpt_platform/frontend/src/app/library/agents/[id]/page.tsx index 6cb36ff03d..29d5fc43e2 100644 --- a/autogpt_platform/frontend/src/app/library/agents/[id]/page.tsx +++ b/autogpt_platform/frontend/src/app/library/agents/[id]/page.tsx @@ -226,12 +226,8 @@ export default function AgentRunsPage(): React.ReactElement { ...(agent?.can_access_graph ? [ { - label: "Open in builder", - callback: () => - agent && - router.push( - `/build?flowID=${agent.agent_id}&flowVersion=${agent.agent_version}`, - ), + label: "Open graph in builder", + href: `/build?flowID=${agent.agent_id}&flowVersion=${agent.agent_version}`, }, { label: "Export agent to file", callback: downloadGraph }, ] @@ -242,7 +238,7 @@ export default function AgentRunsPage(): React.ReactElement { callback: () => setAgentDeleteDialogOpen(true), }, ], - [agent, router, downloadGraph], + [agent, downloadGraph], ); if (!agent || !graph) { @@ -282,6 +278,7 @@ export default function AgentRunsPage(): React.ReactElement { {(selectedView.type == "run" && selectedView.id ? ( selectedRun && (
-
-

Run actions

- {runActions.map((action, i) => ( - - ))} -
+ -
-

Agent actions

- {agentActions.map((action, i) => ( - - ))} -
+
diff --git a/autogpt_platform/frontend/src/components/agents/agent-run-draft-view.tsx b/autogpt_platform/frontend/src/components/agents/agent-run-draft-view.tsx index f59e2a6c7b..f73fa4978f 100644 --- a/autogpt_platform/frontend/src/components/agents/agent-run-draft-view.tsx +++ b/autogpt_platform/frontend/src/components/agents/agent-run-draft-view.tsx @@ -8,9 +8,9 @@ import type { ButtonAction } from "@/components/agptui/types"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { TypeBasedInput } from "@/components/type-based-input"; import { useToastOnFail } from "@/components/ui/use-toast"; +import ActionButtonGroup from "@/components/agptui/action-button-group"; import SchemaTooltip from "@/components/SchemaTooltip"; import { IconPlay } from "@/components/ui/icons"; -import { Button } from "@/components/agptui/Button"; export default function AgentRunDraftView({ graph, @@ -87,31 +87,9 @@ export default function AgentRunDraftView({ {/* Actions */} diff --git a/autogpt_platform/frontend/src/components/agents/agent-schedule-details-view.tsx b/autogpt_platform/frontend/src/components/agents/agent-schedule-details-view.tsx index 5cc783d9ed..4ee4a23cf5 100644 --- a/autogpt_platform/frontend/src/components/agents/agent-schedule-details-view.tsx +++ b/autogpt_platform/frontend/src/components/agents/agent-schedule-details-view.tsx @@ -12,7 +12,7 @@ import type { ButtonAction } from "@/components/agptui/types"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { AgentRunStatus } from "@/components/agents/agent-run-status-chip"; import { useToastOnFail } from "@/components/ui/use-toast"; -import { Button } from "@/components/agptui/Button"; +import ActionButtonGroup from "@/components/agptui/action-button-group"; import { Input } from "@/components/ui/input"; export default function AgentScheduleDetailsView({ @@ -75,7 +75,7 @@ export default function AgentScheduleDetailsView({ [api, graph, schedule, onForcedRun, toastOnFail], ); - const runActions: { label: string; callback: () => void }[] = useMemo( + const runActions: ButtonAction[] = useMemo( () => [{ label: "Run now", callback: () => runNow() }], [runNow], ); @@ -126,27 +126,9 @@ export default function AgentScheduleDetailsView({ {/* Run / Agent Actions */} diff --git a/autogpt_platform/frontend/src/components/agptui/action-button-group.tsx b/autogpt_platform/frontend/src/components/agptui/action-button-group.tsx new file mode 100644 index 0000000000..a9d565ae7c --- /dev/null +++ b/autogpt_platform/frontend/src/components/agptui/action-button-group.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { cn } from "@/lib/utils"; + +import type { ButtonAction } from "@/components/agptui/types"; +import { Button, buttonVariants } from "@/components/agptui/Button"; +import Link from "next/link"; + +export default function ActionButtonGroup({ + title, + actions, + className, +}: { + title: React.ReactNode; + actions: ButtonAction[]; + className?: string; +}): React.ReactElement { + return ( +
+

{title}

+ {actions.map((action, i) => + "callback" in action ? ( + + ) : ( + + {action.label} + + ), + )} +
+ ); +} diff --git a/autogpt_platform/frontend/src/components/agptui/types.ts b/autogpt_platform/frontend/src/components/agptui/types.ts index 7b07afc8cc..2cdcb1912e 100644 --- a/autogpt_platform/frontend/src/components/agptui/types.ts +++ b/autogpt_platform/frontend/src/components/agptui/types.ts @@ -4,5 +4,4 @@ import React from "react"; export type ButtonAction = { label: React.ReactNode; variant?: ButtonProps["variant"]; - callback: () => void; -}; +} & ({ callback: () => void } | { href: string });