-
Notifications
You must be signed in to change notification settings - Fork 44.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(builder, server): Add Builds to Frontend and Packaged assets #7406
Changes from 14 commits
48740d9
7337e2f
76cfeef
5969d44
741e4db
2f4fe33
b376e84
bded791
aedb8d8
50d92d1
01cc25b
a57d27a
42ee23d
d06d8a2
fad8e30
d3c8cf0
2c56b85
2e3e8ac
9fe1efa
97581a7
2e6d094
ab830b5
483cd07
2a43462
9be9dbe
66384c1
75a5ee8
0716b59
8c212e5
db14af2
be14969
5243c9d
f673f8a
01e6fdd
20152cf
5617a64
a30b3f7
94e2d0e
c25f32e
e46cfb1
95ccc05
6b89941
dc3a9b4
e7c5696
a15ad5c
2359a7d
03df00c
e676124
72c6332
68f46c0
bfb3a45
7479d18
4565635
cbb81a3
189eccb
1ffa261
f2849b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
frontend/ | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,10 @@ | ||
{ | ||
"extends": "next/core-web-vitals" | ||
"extends": [ | ||
"next/core-web-vitals", | ||
"plugin:@typescript-eslint/recommended" | ||
], | ||
"rules": { | ||
"@typescript-eslint/no-explicit-any": "off", | ||
"@typescript-eslint/ban-ts-comment": "off" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,17 @@ | ||
const dotenv = require('dotenv'); | ||
ntindle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dotenv.config(); | ||
|
||
module.exports = { | ||
const nextConfig = { | ||
output: 'export', | ||
ntindle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
env: { | ||
AGPT_SERVER_URL: process.env.AGPT_SERVER_URL, | ||
}, | ||
eslint: { | ||
ignoreDuringBuilds: true, | ||
}, | ||
typescript: { | ||
ignoreBuildErrors: true, | ||
}, | ||
}; | ||
|
||
module.exports = nextConfig |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,53 @@ | ||
"use client"; | ||
import React, { Suspense } from "react"; | ||
import Image from "next/image"; | ||
import { useSearchParams } from "next/navigation"; | ||
import FlowEditor from '@/components/Flow'; | ||
|
||
function FlowEditorWrapper() { | ||
const searchParams = useSearchParams(); | ||
const flowID = searchParams.get("flowID") ?? undefined; | ||
|
||
return ( | ||
<FlowEditor | ||
className="flow-container w-full min-h-[75vh] border border-gray-300 dark:border-gray-700 rounded-lg" | ||
flowID={flowID} | ||
/> | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unnecessary abstraction imo |
||
|
||
export default function Home() { | ||
return ( | ||
<div className="flex flex-col items-center px-12"> | ||
<div className="z-10 w-full items-center justify-between font-mono text-sm lg:flex"> | ||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-600 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-900 dark:bg-zinc-900 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> | ||
Get started by adding a | ||
<code className="font-mono font-bold">node</code> | ||
</p> | ||
<div | ||
className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:size-auto lg:bg-none" | ||
> | ||
<a | ||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0" | ||
href="https://news.agpt.co/" | ||
target="_blank" | ||
rel="noopener noreferrer" | ||
> | ||
By{" "} | ||
<Image | ||
src="/autogpt_logo_dark.svg" | ||
alt="AutoGPT Logo" | ||
width={100} | ||
height={24} | ||
priority | ||
/> | ||
</a> | ||
</div> | ||
</div> | ||
<div className="flex flex-col items-center px-12"> | ||
<div className="z-10 w-full items-center justify-between font-mono text-sm lg:flex"> | ||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-600 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-900 dark:bg-zinc-900 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> | ||
Get started by adding a | ||
<code className="font-mono font-bold">node</code> | ||
</p> | ||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:size-auto lg:bg-none"> | ||
<a | ||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0" | ||
href="https://news.agpt.co/" | ||
target="_blank" | ||
rel="noopener noreferrer" | ||
> | ||
By{" "} | ||
<Image | ||
src="/autogpt_logo_dark.svg" | ||
alt="AutoGPT Logo" | ||
width={100} | ||
height={24} | ||
priority | ||
/> | ||
</a> | ||
</div> | ||
</div> | ||
|
||
<div className="w-full flex justify-center mt-10"> | ||
<FlowEditor | ||
className="flow-container w-full min-h-[75vh] border border-gray-300 dark:border-gray-700 rounded-lg" | ||
flowID={useSearchParams().get("flowID") ?? undefined} | ||
/> | ||
</div> | ||
<div className="w-full flex justify-center mt-10"> | ||
<Suspense fallback={<div>Loading...</div>}> | ||
<FlowEditorWrapper /> | ||
</Suspense> | ||
</div> | ||
</div> | ||
Comment on lines
+47
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changed indentation? |
||
); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing newline |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import { Calendar } from "@/components/ui/calendar"; | |
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | ||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; | ||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; | ||
import type { Payload } from "recharts/types/component/DefaultLegendContent"; | ||
|
||
const Monitor = () => { | ||
const [flows, setFlows] = useState<Flow[]>([]); | ||
|
@@ -177,7 +178,8 @@ const AgentFlowList = ( | |
</TableHeader> | ||
<TableBody> | ||
{flows.map((flow) => { | ||
let runCount, lastRun: FlowRun | null; | ||
let runCount = 0; | ||
let lastRun: FlowRun | null = null; | ||
if (flowRuns) { | ||
const _flowRuns = flowRuns.filter(r => r.flowID == flow.id); | ||
runCount = _flowRuns.length; | ||
|
@@ -210,20 +212,6 @@ const AgentFlowList = ( | |
</CardContent> | ||
</Card> | ||
); | ||
|
||
const FlowStatusBadge = ({ status }: { status: "active" | "disabled" | "failing" }) => ( | ||
<Badge | ||
variant="default" | ||
className={ | ||
status === 'active' ? 'bg-green-500 dark:bg-green-600' : | ||
status === 'failing' ? 'bg-red-500 dark:bg-red-700' : | ||
'bg-gray-500 dark:bg-gray-600' | ||
} | ||
> | ||
{status} | ||
</Badge> | ||
); | ||
|
||
const FlowRunsList = ({ flows, runs }: { flows: Flow[], runs: FlowRun[] }) => ( | ||
<Card> | ||
<CardHeader> | ||
|
@@ -268,7 +256,7 @@ const FlowRunStatusBadge = ({ status }: { status: FlowRun['status'] }) => ( | |
</Badge> | ||
); | ||
|
||
const ScrollableLegend = ({ payload }) => { | ||
const ScrollableLegend = ({ payload }: { payload: Payload[] }) => { | ||
return ( | ||
<div style={{ | ||
overflowX: 'auto', | ||
|
@@ -396,7 +384,7 @@ const FlowRunsTimeline = ( | |
tickFormatter={s => s > 90 ? `${Math.round(s / 60)}m` : `${s}s`} | ||
/> | ||
<Tooltip | ||
content={({ payload, label }) => { | ||
content={({ payload}) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inconsistent spacing: |
||
if (payload && payload.length) { | ||
const data: FlowRun & { time: number, _duration: number } = payload[0].payload; | ||
const flow = flows.find(f => f.id === data.flowID); | ||
|
@@ -442,7 +430,7 @@ const FlowRunsTimeline = ( | |
/> | ||
))} | ||
<Legend | ||
content={<ScrollableLegend />} | ||
content={(props) => <ScrollableLegend payload={props.payload || []} />} | ||
wrapperStyle={{ bottom: 0, left: 0, right: 0 }} | ||
/> | ||
</ComposedChart> | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -102,6 +102,16 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
setErrors((prevErrors) => ({ ...prevErrors, [key]: null })); | ||||||
}; | ||||||
|
||||||
const getSelectValue = (value: any): string => { | ||||||
if (typeof value === 'string') return value; | ||||||
if (typeof value === 'number') return value.toString(); | ||||||
if (Array.isArray(value)) return value.join(','); | ||||||
if (typeof value === 'object' && value !== null) { | ||||||
return JSON.stringify(value); | ||||||
} | ||||||
return ''; | ||||||
}; | ||||||
|
||||||
const getValue = (key: string) => { | ||||||
const keys = key.split('.'); | ||||||
return keys.reduce((acc, k) => (acc && acc[k] !== undefined) ? acc[k] : '', data.hardcodedValues); | ||||||
|
@@ -110,7 +120,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
const isHandleConnected = (key: string) => { | ||||||
return data.connections && data.connections.some((conn: any) => { | ||||||
if (typeof conn === 'string') { | ||||||
const [source, target] = conn.split(' -> '); | ||||||
const [ target] = conn.split(' -> '); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inconsistent spacing: |
||||||
return target.includes(key) && target.includes(data.title); | ||||||
} | ||||||
return conn.target === id && conn.targetHandle === key; | ||||||
|
@@ -157,11 +167,13 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
return <div className="connected-input">Connected</div>; | ||||||
} | ||||||
|
||||||
const renderClickableInput = (displayValue: string) => ( | ||||||
<div className="clickable-input" onClick={() => handleInputClick(fullKey)}> | ||||||
{displayValue} | ||||||
</div> | ||||||
); | ||||||
const renderClickableInput = (displayValue: unknown): JSX.Element => ( | ||||||
<div className="clickable-input" onClick={() => handleInputClick(fullKey)}> | ||||||
{typeof displayValue === 'string' || typeof displayValue === 'number' || typeof displayValue === 'boolean' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
? String(displayValue) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for the three selected types, I think so then this whole thing can just be |
||||||
: JSON.stringify(displayValue)} | ||||||
</div> | ||||||
); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bad indentation |
||||||
|
||||||
if (schema.type === 'object' && schema.properties) { | ||||||
return ( | ||||||
|
@@ -286,7 +298,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
return schema.enum ? ( | ||||||
<div key={fullKey} className="input-container"> | ||||||
<select | ||||||
value={value || ''} | ||||||
value={getSelectValue(value)} | ||||||
Comment on lines
-303
to
+313
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are there currently any cases where this is necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's nothing in our nodes yet with different data types - but this fixes some of the TS check issues I was having - if there's a better solution lmk There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What was TypeScript's complaint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
onChange={(e) => handleInputChange(fullKey, e.target.value)} | ||||||
className="select-input" | ||||||
> | ||||||
|
@@ -326,7 +338,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
<div key={fullKey} className="input-container"> | ||||||
<input | ||||||
type="number" | ||||||
value={value || ''} | ||||||
value={typeof value === 'number' ? value : typeof value === 'string' ? value : ''} | ||||||
aarushik93 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
onChange={(e) => handleInputChange(fullKey, parseFloat(e.target.value))} | ||||||
className="number-input" | ||||||
/> | ||||||
|
@@ -335,7 +347,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
); | ||||||
case 'array': | ||||||
if (schema.items && schema.items.type === 'string') { | ||||||
const arrayValues = value || []; | ||||||
const arrayValues = Array.isArray(value) ? value : []; | ||||||
return ( | ||||||
<div key={fullKey} className="input-container"> | ||||||
{arrayValues.map((item: string, index: number) => ( | ||||||
|
@@ -346,7 +358,11 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
onChange={(e) => handleInputChange(`${fullKey}.${index}`, e.target.value)} | ||||||
className="array-item-input" | ||||||
/> | ||||||
<Button onClick={() => handleInputChange(`${fullKey}.${index}`, '')} className="array-item-remove"> | ||||||
<Button onClick={() => { | ||||||
const newArray = [...arrayValues]; | ||||||
newArray.splice(index, 1); | ||||||
handleInputChange(fullKey, newArray); | ||||||
}} className="array-item-remove"> | ||||||
× | ||||||
</Button> | ||||||
</div> | ||||||
|
@@ -358,7 +374,7 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
</div> | ||||||
); | ||||||
} | ||||||
return null; | ||||||
return <div key={fullKey}></div>; | ||||||
default: | ||||||
return ( | ||||||
<div key={fullKey} className="input-container"> | ||||||
|
@@ -369,28 +385,6 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => { | |||||
} | ||||||
}; | ||||||
|
||||||
const validateInputs = () => { | ||||||
const newErrors: { [key: string]: string | null } = {}; | ||||||
const validateRecursive = (schema: any, parentKey: string = '') => { | ||||||
Object.entries(schema.properties).forEach(([key, propSchema]: [string, any]) => { | ||||||
const fullKey = parentKey ? `${parentKey}.${key}` : key; | ||||||
const value = getValue(fullKey); | ||||||
|
||||||
if (propSchema.type === 'object' && propSchema.properties) { | ||||||
validateRecursive(propSchema, fullKey); | ||||||
} else { | ||||||
if (propSchema.required && !value) { | ||||||
newErrors[fullKey] = `${fullKey} is required`; | ||||||
} | ||||||
} | ||||||
}); | ||||||
}; | ||||||
|
||||||
validateRecursive(data.inputSchema); | ||||||
setErrors(newErrors); | ||||||
return Object.values(newErrors).every((error) => error === null); | ||||||
}; | ||||||
|
||||||
return ( | ||||||
<div className={`custom-node dark-theme ${data.status === 'RUNNING' ? 'running' : data.status === 'COMPLETED' ? 'completed' : data.status === 'FAILED' ? 'failed' :''}`}> | ||||||
<div className="node-header"> | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
// @ts-nocheck | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bad There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just put this in for now til i do a proper linting and formatting PR to get the build working |
||
"use client"; | ||
import React, { useState, useCallback, useEffect, useMemo } from 'react'; | ||
import ReactFlow, { | ||
|
@@ -111,6 +112,7 @@ const FlowEditor: React.FC<{ flowID?: string; className?: string }> = ({ | |
const onConnect: OnConnect = useCallback( | ||
(connection: Connection) => { | ||
setEdges((eds) => addEdge(connection, eds)); | ||
|
||
setNodes((nds) => | ||
nds.map((node) => { | ||
if (node.id === connection.target) { | ||
|
@@ -241,7 +243,7 @@ const FlowEditor: React.FC<{ flowID?: string; className?: string }> = ({ | |
return inputData; | ||
}; | ||
|
||
let inputData = getNestedData(blockSchema, node.data.hardcodedValues); | ||
const inputData = getNestedData(blockSchema, node.data.hardcodedValues); | ||
|
||
// Get data from connected nodes | ||
const incomingEdges = allEdges.filter(edge => edge.target === node.id); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Staging area for cx-freeze to pull the built files from