diff --git a/packages/client/editor/src/components/workspaces/composer/composer.tsx b/packages/client/editor/src/components/workspaces/composer/composer.tsx index 88129dbc97..581a46f3b0 100644 --- a/packages/client/editor/src/components/workspaces/composer/composer.tsx +++ b/packages/client/editor/src/components/workspaces/composer/composer.tsx @@ -220,10 +220,8 @@ export const Composer = ({ tab, theme, spellId }) => { setApi(event.api) } - useEffect(() => { - if (!api) return - - const unsubscribe = subscribe(events.$CREATE_TEXT_EDITOR(tab.id), () => { + const windowBarMap = { + [events.$CREATE_TEXT_EDITOR(tab.id)]: () => { api.addPanel({ id: 'Text Editor', component: 'TextEditor', @@ -232,18 +230,63 @@ export const Composer = ({ tab, theme, spellId }) => { tab, spellId }, + position: { referencePanel: 'Composer', direction: 'left' }, + }) + }, + [events.$CREATE_INSPECTOR(tab.id)]: () => { + api.addPanel({ + id: 'Inspector', + component: 'Inspector', + params: { + title: 'Inspector', + tab, + spellId + }, + position: { referencePanel: 'Composer', direction: 'left' }, + }) + }, + [events.$CREATE_PLAYTEST(tab.id)]: () => { + api.addPanel({ + id: 'Playtest', + component: 'Playtest', + params: { + title: 'Playtest', + tab, + spellId + }, + position: { referencePanel: 'Composer', direction: 'below' }, }) + }, + [events.$CREATE_CONSOLE(tab.id)]: () => { + api.addPanel({ + id: 'Console', + component: 'Console', + params: { + title: 'Console', + tab, + spellId + }, + position: { referencePanel: 'Composer', direction: 'below' }, + }) + }, + } + + useEffect(() => { + if (!api) return + + const windowBarSubscriptions = Object.entries(windowBarMap).map(([event, handler]) => { + return subscribe(event, handler) }) - console.log('Setting up layout change listener') api.onDidLayoutChange(() => { const layout = api.toJSON() - saveLayoutToLocalStorage(spellId, layout) }) return () => { - unsubscribe() + windowBarSubscriptions.forEach(unsubscribe => { + unsubscribe() + }) } }, [api]) diff --git a/packages/client/editor/src/components/workspaces/composer/index.tsx b/packages/client/editor/src/components/workspaces/composer/index.tsx index 24fb7d7db9..4da347bd7f 100644 --- a/packages/client/editor/src/components/workspaces/composer/index.tsx +++ b/packages/client/editor/src/components/workspaces/composer/index.tsx @@ -4,37 +4,61 @@ import { Tab, useDockviewTheme } from 'client/state'; import { usePubSub } from '@magickml/providers'; import { Composer } from './composer'; -const DraggableElement = (props) => ( -

{ - if (event.dataTransfer) { - event.dataTransfer.effectAllowed = 'move'; +const DraggableElement = (props) => { + const { tab } = props.params + const { publish, events } = usePubSub() + const windows = { + 'Console': () => { + publish(events.$CREATE_CONSOLE(tab.id)) + }, + 'TextEditor': () => { + publish(events.$CREATE_TEXT_EDITOR(tab.id)) + }, + 'Inspector': () => { + publish(events.$CREATE_INSPECTOR(tab.id)) + }, + 'Playtest': () => { + publish(events.$CREATE_PLAYTEST(tab.id)) + } + } - event.dataTransfer.setData('text/plain', 'nothing'); - event.dataTransfer.setData('component', props.window) - event.dataTransfer.setData('title', props.title) - } - }} - style={{ - padding: '8px', - color: 'white', - cursor: 'pointer', - }} - draggable={true} - > - {props.window} -

-); + const handleClick = () => { + windows[props.window]() + } + + return ( +

{ + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move'; + + event.dataTransfer.setData('text/plain', 'nothing'); + event.dataTransfer.setData('component', props.window) + event.dataTransfer.setData('title', props.title) + } + }} + style={{ + padding: '8px', + color: 'white', + cursor: 'pointer', + }} + draggable={true} + onClick={handleClick} + > + {props.window} +

+ ) +}; const composerLayoutComponents = { WindowBar: (props: IGridviewPanelProps<{ title: string }>) => { return (
- - - - + + + +
) }, @@ -53,6 +77,9 @@ const ComposerContainer = (props: IGridviewPanelProps<{ tab: Tab; theme: string, component: 'WindowBar', maximumHeight: 30, minimumHeight: 30, + params: { + ...props.params + } }) event.api.addPanel({ diff --git a/packages/client/editor/src/components/workspaces/composerv2/composer.tsx b/packages/client/editor/src/components/workspaces/composerv2/composer.tsx index 4be879294d..017d763ce1 100644 --- a/packages/client/editor/src/components/workspaces/composerv2/composer.tsx +++ b/packages/client/editor/src/components/workspaces/composerv2/composer.tsx @@ -157,10 +157,8 @@ export const Composer = ({ tab, theme, spellId }) => { setApi(event.api) } - useEffect(() => { - if (!api) return - - const unsubscribe = subscribe(events.$CREATE_TEXT_EDITOR(tab.id), () => { + const windowBarMap = { + [events.$CREATE_TEXT_EDITOR(tab.id)]: () => { api.addPanel({ id: 'Text Editor', component: 'TextEditor', @@ -169,7 +167,52 @@ export const Composer = ({ tab, theme, spellId }) => { tab, spellId }, + position: { referencePanel: 'Graph', direction: 'left' }, + }) + }, + [events.$CREATE_INSPECTOR(tab.id)]: () => { + api.addPanel({ + id: 'Inspector', + component: 'Inspector', + params: { + title: 'Inspector', + tab, + spellId + }, + position: { referencePanel: 'Graph', direction: 'left' }, }) + }, + [events.$CREATE_PLAYTEST(tab.id)]: () => { + api.addPanel({ + id: 'Chat', + component: 'Chat', + params: { + title: 'Chat', + tab, + spellId + }, + position: { referencePanel: 'Graph', direction: 'below' }, + }) + }, + [events.$CREATE_CONSOLE(tab.id)]: () => { + api.addPanel({ + id: 'Console', + component: 'Console', + params: { + title: 'Console', + tab, + spellId + }, + position: { referencePanel: 'Graph', direction: 'below' }, + }) + }, + } + + useEffect(() => { + if (!api) return + + const windowBarSubscriptions = Object.entries(windowBarMap).map(([event, handler]) => { + return subscribe(event, handler) }) api.onDidLayoutChange(() => { @@ -179,7 +222,9 @@ export const Composer = ({ tab, theme, spellId }) => { }) return () => { - unsubscribe() + windowBarSubscriptions.forEach(unsubscribe => { + unsubscribe() + }) } }, [api]) diff --git a/packages/client/editor/src/components/workspaces/composerv2/index.tsx b/packages/client/editor/src/components/workspaces/composerv2/index.tsx index 74df0199fe..b27585475f 100644 --- a/packages/client/editor/src/components/workspaces/composerv2/index.tsx +++ b/packages/client/editor/src/components/workspaces/composerv2/index.tsx @@ -1,32 +1,56 @@ import { GridviewReact, IGridviewPanelProps, Orientation } from 'dockview'; import WorkspaceProvider from '../../../contexts/WorkspaceProvider' -import { Tab, createStore, injectReducer, tabReducer, useDockviewTheme } from 'client/state'; +import { Tab, useDockviewTheme } from 'client/state'; import { usePubSub } from '@magickml/providers'; import { Composer } from './composer'; -import { useEffect } from 'react'; -const DraggableElement = (props) => ( -

{ - if (event.dataTransfer) { - event.dataTransfer.effectAllowed = 'move'; - event.dataTransfer.setData('text/plain', 'nothing'); - event.dataTransfer.setData('component', props.window) - event.dataTransfer.setData('title', props.title) - } - }} - style={{ - padding: '8px', - color: 'white', - cursor: 'pointer', - }} - draggable={true} - > - {props.window} -

-); +const DraggableElement = (props) => { + const { tab } = props.params + const { publish, events } = usePubSub() + const windows = { + 'Console': () => { + publish(events.$CREATE_CONSOLE(tab.id)) + }, + 'TextEditor': () => { + publish(events.$CREATE_TEXT_EDITOR(tab.id)) + }, + 'Inspector': () => { + publish(events.$CREATE_INSPECTOR(tab.id)) + }, + 'Playtest': () => { + publish(events.$CREATE_PLAYTEST(tab.id)) + } + } + + const handleClick = () => { + windows[props.window]() + } + + return ( +

{ + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move'; + + event.dataTransfer.setData('text/plain', 'nothing'); + event.dataTransfer.setData('component', props.window) + event.dataTransfer.setData('title', props.title) + } + }} + onClick={handleClick} + style={{ + padding: '8px', + color: 'white', + cursor: 'pointer', + }} + draggable={true} + > + {props.window} +

+ ) +}; const composerLayoutComponents = { WindowBar: (props: IGridviewPanelProps<{ title: string }>) => { @@ -34,10 +58,10 @@ const composerLayoutComponents = {

Composer V2

- - - - + + + +
) @@ -48,7 +72,6 @@ const composerLayoutComponents = { } const ComposerContainer = (props: IGridviewPanelProps<{ tab: Tab; theme: string, spellId: string }>) => { - const { tab } = props.params const { theme } = useDockviewTheme() const pubSub = usePubSub() @@ -58,6 +81,9 @@ const ComposerContainer = (props: IGridviewPanelProps<{ tab: Tab; theme: string, component: 'WindowBar', maximumHeight: 30, minimumHeight: 30, + params: { + ...props.params + } }) event.api.addPanel({ diff --git a/packages/shared/nodeSpec/src/nodeSpec.json b/packages/shared/nodeSpec/src/nodeSpec.json index 6578bbd999..5a51ae7414 100644 --- a/packages/shared/nodeSpec/src/nodeSpec.json +++ b/packages/shared/nodeSpec/src/nodeSpec.json @@ -49,6 +49,48 @@ ], "configuration": [] }, + { + "type": "magick/fetch", + "category": "Action", + "label": "Fetch", + "inputs": [ + { + "name": "flow", + "valueType": "flow" + }, + { + "name": "method", + "valueType": "string", + "defaultValue": "" + }, + { + "name": "headers", + "valueType": "string", + "defaultValue": "" + }, + { + "name": "url", + "valueType": "string", + "defaultValue": "" + }, + { + "name": "params", + "valueType": "string", + "defaultValue": "" + } + ], + "outputs": [ + { + "name": "flow", + "valueType": "flow" + }, + { + "name": "output", + "valueType": "string" + } + ], + "configuration": [] + }, { "type": "logic/string", "category": "None", diff --git a/plugins/core/src/lib/corePlugin.ts b/plugins/core/src/lib/corePlugin.ts index f585f31ed7..b769896f00 100644 --- a/plugins/core/src/lib/corePlugin.ts +++ b/plugins/core/src/lib/corePlugin.ts @@ -12,6 +12,7 @@ import CoreEventClient from './services/coreEventClient' import { RedisPubSub } from 'server/redis-pubsub' import { CoreActionService } from './services/coreActionService' import { sendMessage } from './nodes/actions/sendMessage' +import { FetchNode } from './nodes/actions/Fetch' import { Job } from 'bullmq' import { SpellCaster } from 'server/grimoire' @@ -23,7 +24,7 @@ const pluginName = 'Core' export class CorePlugin extends CoreEventsPlugin { override enabled = true client: CoreEventClient - nodes = [messageEvent, sendMessage] + nodes = [messageEvent, sendMessage, FetchNode.Description] values = [] constructor(connection: Redis, agentId: string, pubSub: RedisPubSub) { diff --git a/plugins/core/src/lib/nodes/actions/Fetch.ts b/plugins/core/src/lib/nodes/actions/Fetch.ts new file mode 100644 index 0000000000..33f69da046 --- /dev/null +++ b/plugins/core/src/lib/nodes/actions/Fetch.ts @@ -0,0 +1,67 @@ +import { + Engine, + Socket, + NodeDescription, + NodeDescription2, + AsyncNode, + IGraph, + NodeCategory, +} from '@magickml/behave-graph' +import axios, { AxiosResponse } from 'axios' + +export class FetchNode extends AsyncNode { + public static Description = new NodeDescription2({ + typeName: 'magick/fetch', + category: NodeCategory.Action, + label: 'Fetch', + factory: (description, graph) => new FetchNode(description, graph), + }) + + constructor(description: NodeDescription, graph: IGraph) { + super( + description, + graph, + [ + new Socket('flow', 'flow'), + new Socket('string', 'method'), + new Socket('string', 'headers'), + new Socket('string', 'url'), + new Socket('string', 'params'), + ], + [new Socket('flow', 'flow'), new Socket('string', 'output')], + {}, + 'FetchNode' + ) + } + + override async triggered( + engine: Engine, + triggeringSocketName: string, + finished: () => void + ): Promise { + const method = ((this.readInput('method') as string) || '') + .toLowerCase() + .trim() + const headers = (this.readInput('headers') as string) || {} + const url = (this.readInput('url') as string) || '' + const params = this.readInput('params') || {} + + try { + const response: AxiosResponse = await axios({ + url, + method, + data: params, + headers: headers, + }) + + const responseData = JSON.stringify(response.data) + + this.writeOutput('output', responseData) + engine.commitToNewFiber(this, 'flow') + finished() + } catch (error) { + console.error('Request failed::::::::::::', error) + throw new Error(`Request failed with (${error})!`) + } + } +}