mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-06 22:03:59 -05:00
fix(frontend/library): Fix trigger UX flows in v3 library (#11589)
- Resolves #11586 - Follow-up to #11580 ### Changes 🏗️ - Fix logic to include manual triggers as a possibility - Fix input render logic to use trigger setup schema if applicable - Fix rendering payload input for externally triggered runs - Amend `RunAgentModal` to load preset inputs+credentials if selected - Amend `SelectedTemplateView` to use modified input for run (if applicable) - Hide non-applicable buttons in `SelectedRunView` for externally triggered runs - Implement auto-navigation to `SelectedTriggerView` on trigger setup ### 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: - [x] Can set up manual triggers - [x] Navigates to trigger view after setup - [x] Can set up automatic triggers - [x] Can create templates from runs - [x] Can run templates - [x] Can run templates with modified input
This commit is contained in:
committed by
GitHub
parent
979d7c3b74
commit
117bb05438
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { Breadcrumbs } from "@/components/molecules/Breadcrumbs/Breadcrumbs";
|
||||
import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard";
|
||||
@@ -24,11 +25,13 @@ import { useNewAgentLibraryView } from "./useNewAgentLibraryView";
|
||||
|
||||
export function NewAgentLibraryView() {
|
||||
const {
|
||||
agent,
|
||||
hasAnyItems,
|
||||
ready,
|
||||
error,
|
||||
agentId,
|
||||
agent,
|
||||
ready,
|
||||
activeTemplate,
|
||||
isTemplateLoading,
|
||||
error,
|
||||
hasAnyItems,
|
||||
activeItem,
|
||||
sidebarLoading,
|
||||
activeTab,
|
||||
@@ -38,6 +41,12 @@ export function NewAgentLibraryView() {
|
||||
handleClearSelectedRun,
|
||||
} = useNewAgentLibraryView();
|
||||
|
||||
function onTriggerSetup(newTrigger: LibraryAgentPreset) {
|
||||
if (!agent) return;
|
||||
|
||||
handleSelectRun(newTrigger.id, "triggers");
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorCard
|
||||
@@ -65,7 +74,7 @@ export function NewAgentLibraryView() {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex min-h-0 flex-1">
|
||||
<EmptyTasks agent={agent} />
|
||||
<EmptyTasks agent={agent} onTriggerSetup={onTriggerSetup} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -82,16 +91,23 @@ export function NewAgentLibraryView() {
|
||||
>
|
||||
<RunAgentModal
|
||||
triggerSlot={
|
||||
<Button variant="primary" size="large" className="w-full">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="large"
|
||||
className="w-full"
|
||||
disabled={isTemplateLoading && activeTab === "templates"}
|
||||
>
|
||||
<PlusIcon size={20} /> New task
|
||||
</Button>
|
||||
}
|
||||
agent={agent}
|
||||
agentId={agent.id.toString()}
|
||||
onRunCreated={(execution) => handleSelectRun(execution.id, "runs")}
|
||||
onScheduleCreated={(schedule) =>
|
||||
handleSelectRun(schedule.id, "scheduled")
|
||||
}
|
||||
onTriggerSetup={onTriggerSetup}
|
||||
initialInputValues={activeTemplate?.inputs}
|
||||
initialInputCredentials={activeTemplate?.credentials}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -151,7 +167,7 @@ export function NewAgentLibraryView() {
|
||||
</SelectedViewLayout>
|
||||
) : (
|
||||
<SelectedViewLayout agentName={agent.name} agentId={agent.id}>
|
||||
<EmptyTasks agent={agent} />
|
||||
<EmptyTasks agent={agent} onTriggerSetup={onTriggerSetup} />
|
||||
</SelectedViewLayout>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import type { CredentialsMetaInput } from "@/lib/autogpt-server-api/types";
|
||||
import type {
|
||||
BlockIOSubSchema,
|
||||
CredentialsMetaInput,
|
||||
} from "@/lib/autogpt-server-api/types";
|
||||
import { CredentialsInput } from "../CredentialsInputs/CredentialsInputs";
|
||||
import {
|
||||
getAgentCredentialsFields,
|
||||
@@ -20,13 +23,21 @@ export function AgentInputsReadOnly({
|
||||
inputs,
|
||||
credentialInputs,
|
||||
}: Props) {
|
||||
const fields = getAgentInputFields(agent);
|
||||
const credentialFields = getAgentCredentialsFields(agent);
|
||||
const inputEntries = Object.entries(fields);
|
||||
const credentialEntries = Object.entries(credentialFields);
|
||||
const inputFields = getAgentInputFields(agent);
|
||||
const credentialFieldEntries = Object.entries(
|
||||
getAgentCredentialsFields(agent),
|
||||
);
|
||||
|
||||
const hasInputs = inputs && inputEntries.length > 0;
|
||||
const hasCredentials = credentialInputs && credentialEntries.length > 0;
|
||||
// Take actual input entries as leading; augment with schema from input fields.
|
||||
// TODO: ensure consistent ordering.
|
||||
const inputEntries =
|
||||
inputs &&
|
||||
Object.entries(inputs).map<[string, [BlockIOSubSchema | undefined, any]]>(
|
||||
([k, v]) => [k, [inputFields[k], v]],
|
||||
);
|
||||
|
||||
const hasInputs = inputEntries && inputEntries.length > 0;
|
||||
const hasCredentials = credentialInputs && credentialFieldEntries.length > 0;
|
||||
|
||||
if (!hasInputs && !hasCredentials) {
|
||||
return <div className="text-neutral-600">No input for this run.</div>;
|
||||
@@ -37,11 +48,13 @@ export function AgentInputsReadOnly({
|
||||
{/* Regular inputs */}
|
||||
{hasInputs && (
|
||||
<div className="flex flex-col gap-4">
|
||||
{inputEntries.map(([key, sub]) => (
|
||||
{inputEntries.map(([key, [schema, value]]) => (
|
||||
<div key={key} className="flex flex-col gap-1.5">
|
||||
<label className="text-sm font-medium">{sub?.title || key}</label>
|
||||
<label className="text-sm font-medium">
|
||||
{schema?.title || key}
|
||||
</label>
|
||||
<p className="whitespace-pre-wrap break-words text-sm text-neutral-700">
|
||||
{renderValue((inputs as Record<string, any>)[key])}
|
||||
{renderValue(value)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
@@ -52,7 +65,7 @@ export function AgentInputsReadOnly({
|
||||
{hasCredentials && (
|
||||
<div className="flex flex-col gap-6">
|
||||
{hasInputs && <div className="border-t border-neutral-200 pt-4" />}
|
||||
{credentialEntries.map(([key, inputSubSchema]) => {
|
||||
{credentialFieldEntries.map(([key, inputSubSchema]) => {
|
||||
const credential = credentialInputs![key];
|
||||
if (!credential) return null;
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ export function getCredentialTypeDisplayName(type: string): string {
|
||||
}
|
||||
|
||||
export function getAgentInputFields(agent: LibraryAgent): Record<string, any> {
|
||||
const schema = agent.input_schema as unknown as {
|
||||
const schema = (agent.trigger_setup_info?.config_schema ??
|
||||
agent.input_schema) as unknown as {
|
||||
properties?: Record<string, any>;
|
||||
} | null;
|
||||
if (!schema || !schema.properties) return {};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo";
|
||||
import { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta";
|
||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import {
|
||||
Tooltip,
|
||||
@@ -22,16 +23,20 @@ import { useAgentRunModal } from "./useAgentRunModal";
|
||||
interface Props {
|
||||
triggerSlot: React.ReactNode;
|
||||
agent: LibraryAgent;
|
||||
agentId: string;
|
||||
agentVersion?: number;
|
||||
initialInputValues?: Record<string, any>;
|
||||
initialInputCredentials?: Record<string, any>;
|
||||
onRunCreated?: (execution: GraphExecutionMeta) => void;
|
||||
onTriggerSetup?: (preset: LibraryAgentPreset) => void;
|
||||
onScheduleCreated?: (schedule: GraphExecutionJobInfo) => void;
|
||||
}
|
||||
|
||||
export function RunAgentModal({
|
||||
triggerSlot,
|
||||
agent,
|
||||
initialInputValues,
|
||||
initialInputCredentials,
|
||||
onRunCreated,
|
||||
onTriggerSetup,
|
||||
onScheduleCreated,
|
||||
}: Props) {
|
||||
const {
|
||||
@@ -71,6 +76,9 @@ export function RunAgentModal({
|
||||
handleRun,
|
||||
} = useAgentRunModal(agent, {
|
||||
onRun: onRunCreated,
|
||||
onSetupTrigger: onTriggerSetup,
|
||||
initialInputValues,
|
||||
initialInputCredentials,
|
||||
});
|
||||
|
||||
const [isScheduleModalOpen, setIsScheduleModalOpen] = useState(false);
|
||||
|
||||
@@ -26,7 +26,8 @@ export function ModalRunSection() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{defaultRunType === "automatic-trigger" ? (
|
||||
{defaultRunType === "automatic-trigger" ||
|
||||
defaultRunType === "manual-trigger" ? (
|
||||
<ModalSection
|
||||
title="Task Trigger"
|
||||
subtitle="Set up a trigger for the agent to run this task automatically"
|
||||
|
||||
@@ -24,7 +24,8 @@ export function RunActions({
|
||||
disabled={!isRunReady || isExecuting || isSettingUpTrigger}
|
||||
loading={isExecuting || isSettingUpTrigger}
|
||||
>
|
||||
{defaultRunType === "automatic-trigger"
|
||||
{defaultRunType === "automatic-trigger" ||
|
||||
defaultRunType === "manual-trigger"
|
||||
? "Set up Trigger"
|
||||
: "Start Task"}
|
||||
</Button>
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
getGetV2ListPresetsQueryKey,
|
||||
usePostV2SetupTrigger,
|
||||
} from "@/app/api/__generated__/endpoints/presets/presets";
|
||||
import { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo";
|
||||
import { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta";
|
||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
||||
@@ -14,7 +13,7 @@ import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { isEmpty } from "@/lib/utils";
|
||||
import { analytics } from "@/services/analytics";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { showExecutionErrorToast } from "./errorHelpers";
|
||||
|
||||
export type RunVariant =
|
||||
@@ -25,8 +24,9 @@ export type RunVariant =
|
||||
|
||||
interface UseAgentRunModalCallbacks {
|
||||
onRun?: (execution: GraphExecutionMeta) => void;
|
||||
onCreateSchedule?: (schedule: GraphExecutionJobInfo) => void;
|
||||
onSetupTrigger?: (preset: LibraryAgentPreset) => void;
|
||||
initialInputValues?: Record<string, any>;
|
||||
initialInputCredentials?: Record<string, any>;
|
||||
}
|
||||
|
||||
export function useAgentRunModal(
|
||||
@@ -36,18 +36,28 @@ export function useAgentRunModal(
|
||||
const { toast } = useToast();
|
||||
const queryClient = useQueryClient();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [inputValues, setInputValues] = useState<Record<string, any>>({});
|
||||
const [inputValues, setInputValues] = useState<Record<string, any>>(
|
||||
callbacks?.initialInputValues || {},
|
||||
);
|
||||
const [inputCredentials, setInputCredentials] = useState<Record<string, any>>(
|
||||
{},
|
||||
callbacks?.initialInputCredentials || {},
|
||||
);
|
||||
const [presetName, setPresetName] = useState<string>("");
|
||||
const [presetDescription, setPresetDescription] = useState<string>("");
|
||||
|
||||
// Determine the default run type based on agent capabilities
|
||||
const defaultRunType: RunVariant = agent.has_external_trigger
|
||||
? "automatic-trigger"
|
||||
const defaultRunType: RunVariant = agent.trigger_setup_info
|
||||
? agent.trigger_setup_info.credentials_input_name
|
||||
? "automatic-trigger"
|
||||
: "manual-trigger"
|
||||
: "manual";
|
||||
|
||||
// Update input values/credentials if template is selected/unselected
|
||||
useEffect(() => {
|
||||
setInputValues(callbacks?.initialInputValues || {});
|
||||
setInputCredentials(callbacks?.initialInputCredentials || {});
|
||||
}, [callbacks?.initialInputValues, callbacks?.initialInputCredentials]);
|
||||
|
||||
// API mutations
|
||||
const executeGraphMutation = usePostV1ExecuteGraphAgent({
|
||||
mutation: {
|
||||
@@ -105,11 +115,13 @@ export function useAgentRunModal(
|
||||
},
|
||||
});
|
||||
|
||||
// Input schema validation
|
||||
const agentInputSchema = useMemo(
|
||||
() => agent.input_schema || { properties: {}, required: [] },
|
||||
[agent.input_schema],
|
||||
);
|
||||
// Input schema validation (use trigger schema for triggered agents)
|
||||
const agentInputSchema = useMemo(() => {
|
||||
if (agent.trigger_setup_info?.config_schema) {
|
||||
return agent.trigger_setup_info.config_schema;
|
||||
}
|
||||
return agent.input_schema || { properties: {}, required: [] };
|
||||
}, [agent.input_schema, agent.trigger_setup_info]);
|
||||
|
||||
const agentInputFields = useMemo(() => {
|
||||
if (
|
||||
@@ -205,7 +217,10 @@ export function useAgentRunModal(
|
||||
return;
|
||||
}
|
||||
|
||||
if (defaultRunType === "automatic-trigger") {
|
||||
if (
|
||||
defaultRunType === "automatic-trigger" ||
|
||||
defaultRunType === "manual-trigger"
|
||||
) {
|
||||
// Setup trigger
|
||||
if (!presetName.trim()) {
|
||||
toast({
|
||||
@@ -262,7 +277,7 @@ export function useAgentRunModal(
|
||||
setIsOpen,
|
||||
|
||||
// Run mode
|
||||
defaultRunType,
|
||||
defaultRunType: defaultRunType as RunVariant,
|
||||
|
||||
// Form: regular inputs
|
||||
inputValues,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { getV1GetGraphVersion } from "@/app/api/__generated__/endpoints/graphs/graphs";
|
||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import { ShowMoreText } from "@/components/molecules/ShowMoreText/ShowMoreText";
|
||||
@@ -15,9 +16,10 @@ import { EmptyTasksIllustration } from "./EmptyTasksIllustration";
|
||||
|
||||
type Props = {
|
||||
agent: LibraryAgent;
|
||||
onTriggerSetup?: (preset: LibraryAgentPreset) => void;
|
||||
};
|
||||
|
||||
export function EmptyTasks({ agent }: Props) {
|
||||
export function EmptyTasks({ agent, onTriggerSetup }: Props) {
|
||||
const { toast } = useToast();
|
||||
|
||||
async function handleExport() {
|
||||
@@ -75,7 +77,7 @@ export function EmptyTasks({ agent }: Props) {
|
||||
</Button>
|
||||
}
|
||||
agent={agent}
|
||||
agentId={agent.id.toString()}
|
||||
onTriggerSetup={onTriggerSetup}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -198,8 +198,8 @@ export function SelectedRunView({
|
||||
<RunDetailCard title="Your input">
|
||||
<AgentInputsReadOnly
|
||||
agent={agent}
|
||||
inputs={(run as any)?.inputs}
|
||||
credentialInputs={(run as any)?.credential_inputs}
|
||||
inputs={run?.inputs}
|
||||
credentialInputs={run?.credential_inputs}
|
||||
/>
|
||||
</RunDetailCard>
|
||||
</div>
|
||||
|
||||
@@ -20,13 +20,18 @@ import { useSelectedRunActions } from "./useSelectedRunActions";
|
||||
type Props = {
|
||||
agent: LibraryAgent;
|
||||
run: GraphExecution | undefined;
|
||||
scheduleRecurrence?: string;
|
||||
onSelectRun?: (id: string) => void;
|
||||
onClearSelectedRun?: () => void;
|
||||
};
|
||||
|
||||
export function SelectedRunActions(props: Props) {
|
||||
export function SelectedRunActions({
|
||||
agent,
|
||||
run,
|
||||
onSelectRun,
|
||||
onClearSelectedRun,
|
||||
}: Props) {
|
||||
const {
|
||||
canRunManually,
|
||||
handleRunAgain,
|
||||
handleStopRun,
|
||||
isRunningAgain,
|
||||
@@ -37,21 +42,20 @@ export function SelectedRunActions(props: Props) {
|
||||
isCreateTemplateModalOpen,
|
||||
setIsCreateTemplateModalOpen,
|
||||
} = useSelectedRunActions({
|
||||
agentGraphId: props.agent.graph_id,
|
||||
run: props.run,
|
||||
agent: props.agent,
|
||||
onSelectRun: props.onSelectRun,
|
||||
onClearSelectedRun: props.onClearSelectedRun,
|
||||
agentGraphId: agent.graph_id,
|
||||
run: run,
|
||||
agent: agent,
|
||||
onSelectRun: onSelectRun,
|
||||
});
|
||||
|
||||
const shareExecutionResultsEnabled = useGetFlag(Flag.SHARE_EXECUTION_RESULTS);
|
||||
const isRunning = props.run?.status === "RUNNING";
|
||||
const isRunning = run?.status === "RUNNING";
|
||||
|
||||
if (!props.run || !props.agent) return null;
|
||||
if (!run || !agent) return null;
|
||||
|
||||
return (
|
||||
<SelectedActionsWrap>
|
||||
{!isRunning ? (
|
||||
{canRunManually && !isRunning ? (
|
||||
<Button
|
||||
variant="icon"
|
||||
size="icon"
|
||||
@@ -103,37 +107,37 @@ export function SelectedRunActions(props: Props) {
|
||||
) : null}
|
||||
{shareExecutionResultsEnabled && (
|
||||
<ShareRunButton
|
||||
graphId={props.agent.graph_id}
|
||||
executionId={props.run.id}
|
||||
isShared={props.run.is_shared}
|
||||
shareToken={props.run.share_token}
|
||||
graphId={agent.graph_id}
|
||||
executionId={run.id}
|
||||
isShared={run.is_shared}
|
||||
shareToken={run.share_token}
|
||||
/>
|
||||
)}
|
||||
<FloatingSafeModeToggle
|
||||
graph={props.agent}
|
||||
variant="white"
|
||||
fullWidth={false}
|
||||
/>
|
||||
<Button
|
||||
variant="icon"
|
||||
size="icon"
|
||||
aria-label="Save task as template"
|
||||
onClick={() => setIsCreateTemplateModalOpen(true)}
|
||||
title="Create template"
|
||||
>
|
||||
<CardsThreeIcon weight="bold" size={18} className="text-zinc-700" />
|
||||
</Button>
|
||||
<FloatingSafeModeToggle graph={agent} variant="white" fullWidth={false} />
|
||||
{canRunManually && (
|
||||
<>
|
||||
<Button
|
||||
variant="icon"
|
||||
size="icon"
|
||||
aria-label="Save task as template"
|
||||
onClick={() => setIsCreateTemplateModalOpen(true)}
|
||||
title="Create template"
|
||||
>
|
||||
<CardsThreeIcon weight="bold" size={18} className="text-zinc-700" />
|
||||
</Button>
|
||||
<CreateTemplateModal
|
||||
isOpen={isCreateTemplateModalOpen}
|
||||
onClose={() => setIsCreateTemplateModalOpen(false)}
|
||||
onCreate={handleCreateTemplate}
|
||||
run={run}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<AgentActionsDropdown
|
||||
agent={props.agent}
|
||||
run={props.run}
|
||||
agentGraphId={props.agent.graph_id}
|
||||
onClearSelectedRun={props.onClearSelectedRun}
|
||||
/>
|
||||
<CreateTemplateModal
|
||||
isOpen={isCreateTemplateModalOpen}
|
||||
onClose={() => setIsCreateTemplateModalOpen(false)}
|
||||
onCreate={handleCreateTemplate}
|
||||
run={props.run}
|
||||
agent={agent}
|
||||
run={run}
|
||||
agentGraphId={agent.graph_id}
|
||||
onClearSelectedRun={onClearSelectedRun}
|
||||
/>
|
||||
</SelectedActionsWrap>
|
||||
);
|
||||
|
||||
@@ -15,15 +15,19 @@ import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
|
||||
interface Args {
|
||||
interface Params {
|
||||
agentGraphId: string;
|
||||
run?: GraphExecution;
|
||||
agent?: LibraryAgent;
|
||||
onSelectRun?: (id: string) => void;
|
||||
onClearSelectedRun?: () => void;
|
||||
}
|
||||
|
||||
export function useSelectedRunActions(args: Args) {
|
||||
export function useSelectedRunActions({
|
||||
agentGraphId,
|
||||
run,
|
||||
agent,
|
||||
onSelectRun,
|
||||
}: Params) {
|
||||
const queryClient = useQueryClient();
|
||||
const { toast } = useToast();
|
||||
|
||||
@@ -31,8 +35,9 @@ export function useSelectedRunActions(args: Args) {
|
||||
const [isCreateTemplateModalOpen, setIsCreateTemplateModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const canStop =
|
||||
args.run?.status === "RUNNING" || args.run?.status === "QUEUED";
|
||||
const canStop = run?.status === "RUNNING" || run?.status === "QUEUED";
|
||||
|
||||
const canRunManually = !agent?.trigger_setup_info;
|
||||
|
||||
const { mutateAsync: stopRun, isPending: isStopping } =
|
||||
usePostV1StopGraphExecution();
|
||||
@@ -46,16 +51,16 @@ export function useSelectedRunActions(args: Args) {
|
||||
async function handleStopRun() {
|
||||
try {
|
||||
await stopRun({
|
||||
graphId: args.run?.graph_id ?? "",
|
||||
graphExecId: args.run?.id ?? "",
|
||||
graphId: run?.graph_id ?? "",
|
||||
graphExecId: run?.id ?? "",
|
||||
});
|
||||
|
||||
toast({ title: "Run stopped" });
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getGetV1ListGraphExecutionsInfiniteQueryOptions(
|
||||
args.agentGraphId,
|
||||
).queryKey,
|
||||
queryKey:
|
||||
getGetV1ListGraphExecutionsInfiniteQueryOptions(agentGraphId)
|
||||
.queryKey,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
toast({
|
||||
@@ -70,7 +75,7 @@ export function useSelectedRunActions(args: Args) {
|
||||
}
|
||||
|
||||
async function handleRunAgain() {
|
||||
if (!args.run) {
|
||||
if (!run) {
|
||||
toast({
|
||||
title: "Run not found",
|
||||
description: "Run not found",
|
||||
@@ -83,11 +88,11 @@ export function useSelectedRunActions(args: Args) {
|
||||
toast({ title: "Run started" });
|
||||
|
||||
const res = await executeRun({
|
||||
graphId: args.run.graph_id,
|
||||
graphVersion: args.run.graph_version,
|
||||
graphId: run.graph_id,
|
||||
graphVersion: run.graph_version,
|
||||
data: {
|
||||
inputs: args.run.inputs || {},
|
||||
credentials_inputs: args.run.credential_inputs || {},
|
||||
inputs: run.inputs || {},
|
||||
credentials_inputs: run.credential_inputs || {},
|
||||
source: "library",
|
||||
},
|
||||
});
|
||||
@@ -95,12 +100,12 @@ export function useSelectedRunActions(args: Args) {
|
||||
const newRunId = res?.status === 200 ? (res?.data?.id ?? "") : "";
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: getGetV1ListGraphExecutionsInfiniteQueryOptions(
|
||||
args.agentGraphId,
|
||||
).queryKey,
|
||||
queryKey:
|
||||
getGetV1ListGraphExecutionsInfiniteQueryOptions(agentGraphId)
|
||||
.queryKey,
|
||||
});
|
||||
|
||||
if (newRunId && args.onSelectRun) args.onSelectRun(newRunId);
|
||||
if (newRunId && onSelectRun) onSelectRun(newRunId);
|
||||
} catch (error: unknown) {
|
||||
toast({
|
||||
title: "Failed to start run",
|
||||
@@ -118,7 +123,7 @@ export function useSelectedRunActions(args: Args) {
|
||||
}
|
||||
|
||||
async function handleCreateTemplate(name: string, description: string) {
|
||||
if (!args.run) {
|
||||
if (!run) {
|
||||
toast({
|
||||
title: "Run not found",
|
||||
description: "Cannot create template from missing run",
|
||||
@@ -132,7 +137,7 @@ export function useSelectedRunActions(args: Args) {
|
||||
data: {
|
||||
name,
|
||||
description,
|
||||
graph_execution_id: args.run.id,
|
||||
graph_execution_id: run.id,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -141,10 +146,10 @@ export function useSelectedRunActions(args: Args) {
|
||||
title: "Template created",
|
||||
});
|
||||
|
||||
if (args.agent) {
|
||||
if (agent) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getGetV2ListPresetsQueryKey({
|
||||
graph_id: args.agent.graph_id,
|
||||
graph_id: agent.graph_id,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -164,8 +169,8 @@ export function useSelectedRunActions(args: Args) {
|
||||
}
|
||||
|
||||
// Open in builder URL helper
|
||||
const openInBuilderHref = args.run
|
||||
? `/build?flowID=${args.run.graph_id}&flowVersion=${args.run.graph_version}&flowExecutionID=${args.run.id}`
|
||||
const openInBuilderHref = run
|
||||
? `/build?flowID=${run.graph_id}&flowVersion=${run.graph_version}&flowExecutionID=${run.id}`
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
@@ -173,6 +178,7 @@ export function useSelectedRunActions(args: Args) {
|
||||
showDeleteDialog,
|
||||
canStop,
|
||||
isStopping,
|
||||
canRunManually,
|
||||
isRunningAgain,
|
||||
handleShowDeleteDialog,
|
||||
handleStopRun,
|
||||
|
||||
@@ -95,6 +95,7 @@ export function SelectedTemplateView({
|
||||
return null;
|
||||
}
|
||||
|
||||
const templateOrTrigger = agent.trigger_setup_info ? "Trigger" : "Template";
|
||||
const hasWebhook = !!template.webhook_id && template.webhook;
|
||||
|
||||
return (
|
||||
@@ -111,14 +112,14 @@ export function SelectedTemplateView({
|
||||
/>
|
||||
)}
|
||||
|
||||
<RunDetailCard title="Template Details">
|
||||
<RunDetailCard title={`${templateOrTrigger} Details`}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Input
|
||||
id="template-name"
|
||||
label="Name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="Enter template name"
|
||||
placeholder={`Enter ${templateOrTrigger.toLowerCase()} name`}
|
||||
/>
|
||||
|
||||
<Input
|
||||
@@ -128,7 +129,7 @@ export function SelectedTemplateView({
|
||||
rows={3}
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="Enter template description"
|
||||
placeholder={`Enter ${templateOrTrigger.toLowerCase()} description`}
|
||||
/>
|
||||
</div>
|
||||
</RunDetailCard>
|
||||
|
||||
@@ -138,11 +138,21 @@ export function useSelectedTemplateView({
|
||||
}
|
||||
|
||||
function handleStartTask() {
|
||||
if (!query.data) return;
|
||||
|
||||
const inputsChanged =
|
||||
JSON.stringify(inputs) !== JSON.stringify(query.data.inputs || {});
|
||||
|
||||
const credentialsChanged =
|
||||
JSON.stringify(credentials) !==
|
||||
JSON.stringify(query.data.credentials || {});
|
||||
|
||||
// Use changed unpersisted inputs if applicable
|
||||
executeMutation.mutate({
|
||||
presetId: templateId,
|
||||
data: {
|
||||
inputs: {},
|
||||
credential_inputs: {},
|
||||
inputs: inputsChanged ? inputs : undefined,
|
||||
credential_inputs: credentialsChanged ? credentials : undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { useGetV2GetLibraryAgent } from "@/app/api/__generated__/endpoints/library/library";
|
||||
import { useGetV2GetASpecificPreset } from "@/app/api/__generated__/endpoints/presets/presets";
|
||||
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
|
||||
import { okData } from "@/app/api/helpers";
|
||||
import { useParams } from "next/navigation";
|
||||
import { parseAsString, useQueryStates } from "nuqs";
|
||||
@@ -24,7 +26,7 @@ export function useNewAgentLibraryView() {
|
||||
const agentId = id as string;
|
||||
|
||||
const {
|
||||
data: response,
|
||||
data: agent,
|
||||
isSuccess,
|
||||
error,
|
||||
} = useGetV2GetLibraryAgent(agentId, {
|
||||
@@ -41,6 +43,24 @@ export function useNewAgentLibraryView() {
|
||||
|
||||
const activeTab = useMemo(() => parseTab(activeTabRaw), [activeTabRaw]);
|
||||
|
||||
const {
|
||||
data: _template,
|
||||
isSuccess: isTemplateLoaded,
|
||||
isLoading: isTemplateLoading,
|
||||
error: templateError,
|
||||
} = useGetV2GetASpecificPreset(activeItem ?? "", {
|
||||
query: {
|
||||
enabled: Boolean(activeTab === "templates" && activeItem),
|
||||
select: okData<LibraryAgentPreset>,
|
||||
},
|
||||
});
|
||||
const activeTemplate =
|
||||
isTemplateLoaded &&
|
||||
activeTab === "templates" &&
|
||||
_template?.id === activeItem
|
||||
? _template
|
||||
: null;
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeTabRaw && !activeItem) {
|
||||
setQueryStates({
|
||||
@@ -71,10 +91,10 @@ export function useNewAgentLibraryView() {
|
||||
const showSidebarLayout = sidebarLoading || hasAnyItems;
|
||||
|
||||
useEffect(() => {
|
||||
if (response) {
|
||||
document.title = `${response.name} - Library - AutoGPT Platform`;
|
||||
if (agent) {
|
||||
document.title = `${agent.name} - Library - AutoGPT Platform`;
|
||||
}
|
||||
}, [response]);
|
||||
}, [agent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -135,9 +155,11 @@ export function useNewAgentLibraryView() {
|
||||
|
||||
return {
|
||||
agentId: id,
|
||||
agent,
|
||||
ready: isSuccess,
|
||||
error,
|
||||
agent: response,
|
||||
activeTemplate,
|
||||
isTemplateLoading,
|
||||
error: error || templateError,
|
||||
hasAnyItems,
|
||||
showSidebarLayout,
|
||||
activeItem,
|
||||
|
||||
Reference in New Issue
Block a user