mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-03 11:24:57 -05:00
Compare commits
2 Commits
test/verif
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
696c3bbbce | ||
|
|
0861e4a759 |
@@ -18,6 +18,7 @@ import {
|
|||||||
BlockIOSubSchema,
|
BlockIOSubSchema,
|
||||||
BlockUIType,
|
BlockUIType,
|
||||||
Category,
|
Category,
|
||||||
|
Node,
|
||||||
NodeExecutionResult,
|
NodeExecutionResult,
|
||||||
} from "@/lib/autogpt-server-api";
|
} from "@/lib/autogpt-server-api";
|
||||||
import {
|
import {
|
||||||
@@ -81,6 +82,7 @@ export type CustomNodeData = {
|
|||||||
outputSchema: BlockIORootSchema;
|
outputSchema: BlockIORootSchema;
|
||||||
hardcodedValues: { [key: string]: any };
|
hardcodedValues: { [key: string]: any };
|
||||||
connections: ConnectionData;
|
connections: ConnectionData;
|
||||||
|
webhook?: Node["webhook"];
|
||||||
isOutputOpen: boolean;
|
isOutputOpen: boolean;
|
||||||
status?: NodeExecutionResult["status"];
|
status?: NodeExecutionResult["status"];
|
||||||
/** executionResults contains outputs across multiple executions
|
/** executionResults contains outputs across multiple executions
|
||||||
@@ -910,6 +912,39 @@ export const CustomNode = React.memo(
|
|||||||
</span>
|
</span>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
{data.uiType === BlockUIType.WEBHOOK_MANUAL && (
|
||||||
|
<>
|
||||||
|
{data.webhook ? (
|
||||||
|
<div className="nodrag mr-5 flex flex-col gap-1">
|
||||||
|
Webhook URL:
|
||||||
|
<div className="flex gap-2 rounded-md bg-gray-50 p-2">
|
||||||
|
<code className="select-all break-all text-sm">
|
||||||
|
{data.webhook.url}
|
||||||
|
</code>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="size-7 flex-none"
|
||||||
|
onClick={() =>
|
||||||
|
data.webhook &&
|
||||||
|
navigator.clipboard.writeText(
|
||||||
|
data.webhook.url,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
title="Copy webhook URL"
|
||||||
|
>
|
||||||
|
<CopyIcon className="size-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="italic text-gray-500">
|
||||||
|
(A Webhook URL will be generated when you save the
|
||||||
|
agent)
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="pointer-events-none opacity-50">
|
<div className="pointer-events-none opacity-50">
|
||||||
{generateInputHandles(data.inputSchema, data.uiType)}
|
{generateInputHandles(data.inputSchema, data.uiType)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ReactFlow, ReactFlowProvider } from "@xyflow/react";
|
||||||
|
import {
|
||||||
|
CustomNode,
|
||||||
|
type CustomNode as FlowNode,
|
||||||
|
type CustomNodeData,
|
||||||
|
} from "@/app/(platform)/build/components/legacy-builder/CustomNode/CustomNode";
|
||||||
|
import { BuilderContext } from "@/app/(platform)/build/components/legacy-builder/Flow/Flow";
|
||||||
|
import {
|
||||||
|
BlockUIType,
|
||||||
|
type Category,
|
||||||
|
type Node as GraphNode,
|
||||||
|
} from "@/lib/autogpt-server-api";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
const mockCategories: Category[] = [
|
||||||
|
{
|
||||||
|
category: "triggers",
|
||||||
|
description: "Trigger block",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockWebhook: NonNullable<GraphNode["webhook"]> = {
|
||||||
|
id: "webhook-manual-123",
|
||||||
|
url: "https://hooks.autogpt.io/very/long/path/that/should/wrap/properly/when/rendered/in/the/manual/webhook/block/and-demonstrate-that-break-all-is-working/callback?id=1234567890abcdefghijklmnopqrstuvwxyz",
|
||||||
|
provider: "http",
|
||||||
|
credentials_id: "",
|
||||||
|
webhook_type: "manual",
|
||||||
|
resource: "generic",
|
||||||
|
events: ["POST"],
|
||||||
|
secret: "****",
|
||||||
|
config: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockNodeData: CustomNodeData = {
|
||||||
|
blockType: "WebhookManualBlock",
|
||||||
|
blockCosts: [],
|
||||||
|
title: "Generic Webhook (Manual)",
|
||||||
|
description: "Trigger flows manually via incoming POST requests.",
|
||||||
|
categories: mockCategories,
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {},
|
||||||
|
required: [],
|
||||||
|
},
|
||||||
|
outputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {},
|
||||||
|
required: [],
|
||||||
|
},
|
||||||
|
hardcodedValues: {},
|
||||||
|
connections: [],
|
||||||
|
webhook: mockWebhook,
|
||||||
|
isOutputOpen: false,
|
||||||
|
uiType: BlockUIType.WEBHOOK_MANUAL,
|
||||||
|
block_id: "manual-webhook-block",
|
||||||
|
executionResults: [],
|
||||||
|
errors: {},
|
||||||
|
metadata: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockBuilderContext = {
|
||||||
|
libraryAgent: null,
|
||||||
|
visualizeBeads: "no" as const,
|
||||||
|
setIsAnyModalOpen: () => undefined,
|
||||||
|
getNextNodeId: () => "mock-node-id",
|
||||||
|
getNodeTitle: () => mockNodeData.title,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function WebhookTriggerPreviewPage() {
|
||||||
|
const nodeData = useMemo(
|
||||||
|
() => ({
|
||||||
|
...mockNodeData,
|
||||||
|
inputSchema: { ...mockNodeData.inputSchema },
|
||||||
|
outputSchema: { ...mockNodeData.outputSchema },
|
||||||
|
hardcodedValues: { ...mockNodeData.hardcodedValues },
|
||||||
|
connections: [...mockNodeData.connections],
|
||||||
|
categories: mockNodeData.categories.map((category) => ({ ...category })),
|
||||||
|
executionResults: mockNodeData.executionResults
|
||||||
|
? [...mockNodeData.executionResults]
|
||||||
|
: mockNodeData.executionResults,
|
||||||
|
webhook: mockNodeData.webhook
|
||||||
|
? { ...mockNodeData.webhook }
|
||||||
|
: mockNodeData.webhook,
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const nodes = useMemo<FlowNode[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: "manual-webhook-node",
|
||||||
|
type: "custom",
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
data: nodeData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[nodeData],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen items-center justify-center bg-gray-100 p-8">
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<BuilderContext.Provider value={mockBuilderContext}>
|
||||||
|
<div className="h-[600px] w-[640px] rounded-2xl bg-white p-6 shadow-lg">
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
edges={[]}
|
||||||
|
nodeTypes={{ custom: CustomNode }}
|
||||||
|
panOnScroll={false}
|
||||||
|
zoomOnScroll={false}
|
||||||
|
nodesDraggable={false}
|
||||||
|
nodesConnectable={false}
|
||||||
|
elementsSelectable={false}
|
||||||
|
fitView
|
||||||
|
fitViewOptions={{ padding: 0.2 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</BuilderContext.Provider>
|
||||||
|
</ReactFlowProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
autogpt_platform/frontend/src/tests/webhook-trigger.spec.ts
Normal file
17
autogpt_platform/frontend/src/tests/webhook-trigger.spec.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
const ROUTE = "/playwright/webhook-trigger";
|
||||||
|
|
||||||
|
test.describe("Webhook manual block", () => {
|
||||||
|
test("wraps long webhook URLs without overflow", async ({ page }) => {
|
||||||
|
await page.goto(ROUTE);
|
||||||
|
|
||||||
|
const block = page.locator('[data-blockid="manual-webhook-block"]');
|
||||||
|
await expect(block).toBeVisible();
|
||||||
|
|
||||||
|
const webhookUrl = block.locator("code");
|
||||||
|
await expect(webhookUrl).toContainText("https://hooks.autogpt.io/");
|
||||||
|
|
||||||
|
await expect(block).toHaveScreenshot("webhook-manual-block.png");
|
||||||
|
});
|
||||||
|
});
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Reference in New Issue
Block a user