-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #150 from softflow24/feat/request-block-config-panel
Feat(editor): Request block
- Loading branch information
Showing
47 changed files
with
3,800 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
import { IBlockConfig, IBlock } from "@data-river/shared/interfaces"; | ||
import { ILogger } from "@data-river/shared/interfaces/ILogger"; | ||
|
||
import { StartBlock } from "../startBlock"; | ||
import { EndBlock } from "../endBlock"; | ||
import { InputBlock } from "../inputBlock"; | ||
import { OutputBlock } from "../outputBlock"; | ||
import { LogicBlock } from ".."; | ||
import { | ||
RequestBlock, | ||
StartBlock, | ||
EndBlock, | ||
InputBlock, | ||
OutputBlock, | ||
LogicBlock, | ||
} from ".."; | ||
|
||
type BlockConstructor = new (config: IBlockConfig, logger: ILogger) => IBlock; | ||
Check warning on line 13 in packages/blocks/src/blockFactory/index.ts GitHub Actions / build
|
||
|
||
|
@@ -15,6 +18,7 @@ const blockRegistry: Record<string, BlockConstructor> = { | |
"blocks/[email protected]": InputBlock, | ||
"blocks/[email protected]": OutputBlock, | ||
"blocks/[email protected]": LogicBlock, | ||
"blocks/[email protected]": RequestBlock, | ||
}; | ||
|
||
export function createBlock(config: IBlockConfig, logger: ILogger): IBlock { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { | ||
RequestFormData, | ||
RequestFormSchema, | ||
} from "@data-river/shared/contracts/blocks/request"; | ||
import axios, { AxiosRequestConfig, Method } from "axios"; | ||
import { Block } from ".."; | ||
import { IBlockConfig } from "@data-river/shared/interfaces"; | ||
import { ILogger } from "@data-river/shared/interfaces/ILogger"; | ||
|
||
export class RequestBlock extends Block { | ||
private config: RequestFormData; | ||
|
||
constructor(config: IBlockConfig, logger: ILogger) { | ||
super(config, logger); | ||
const result = RequestFormSchema.safeParse(config.config); | ||
if (!result.success) { | ||
throw new Error(`Invalid request configuration: ${result.error}`); | ||
} | ||
this.config = result.data; | ||
} | ||
|
||
async execute(): Promise<any> { | ||
const { httpMethod, url, headers, queryParams, bodyType, body } = | ||
this.config; | ||
|
||
const axiosConfig: AxiosRequestConfig = { | ||
method: httpMethod as Method, | ||
url, | ||
headers: headers?.reduce( | ||
(acc, { key, value }) => ({ ...acc, [key]: value }), | ||
{}, | ||
), | ||
params: queryParams, | ||
}; | ||
|
||
if (body) { | ||
let contentType: string | undefined = undefined; | ||
|
||
switch (bodyType) { | ||
case "json": | ||
contentType = "application/json"; | ||
axiosConfig.data = JSON.parse(body); | ||
break; | ||
case "form-data": | ||
contentType = "multipart/form-data"; | ||
axiosConfig.data = body; | ||
break; | ||
case "x-www-form-urlencoded": | ||
contentType = "application/x-www-form-urlencoded"; | ||
axiosConfig.data = new URLSearchParams(body); | ||
break; | ||
} | ||
|
||
if (contentType) { | ||
axiosConfig.headers = { | ||
...axiosConfig.headers, | ||
"Content-Type": contentType, | ||
}; | ||
} | ||
} | ||
|
||
try { | ||
const response = await axios(axiosConfig); | ||
return { | ||
data: response.data, | ||
status: response.status, | ||
statusText: response.statusText, | ||
}; | ||
} catch (error) { | ||
// TODO: Add option in config to accept error and handle it manually if needed. | ||
if (axios.isAxiosError(error)) { | ||
throw new Error(`Request failed: ${error.message}`); | ||
} | ||
throw error; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Node } from "reactflow"; | ||
import { RequestNodeData } from "@/types/NodeTypes"; | ||
|
||
export const requestNode: Omit<Node<RequestNodeData>, "position"> = { | ||
id: "0", | ||
type: "custom", | ||
data: { | ||
block: "[email protected]", | ||
label: "Request", | ||
color: "rgb(234 179 8)", | ||
sourceHandle: true, | ||
targetHandle: true, | ||
icon: "Network", | ||
config: { | ||
httpMethod: "GET", | ||
url: "https://pokeapi.co/api/v2/pokemon/ditto", | ||
headers: [ | ||
{ | ||
key: "Content-Type", | ||
value: "application/json", | ||
}, | ||
], | ||
bodyType: "none", | ||
}, | ||
controls: [ | ||
{ | ||
type: "request-info", | ||
label: "Request Info", | ||
name: "request-info", | ||
}, | ||
], | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Editor, EditorProps, OnMount } from "@monaco-editor/react"; | ||
import { MemoExoticComponent, useCallback, useEffect, useState } from "react"; | ||
import { editor } from "monaco-editor"; | ||
import darkTheme from "../themes/dark.json"; | ||
import useTheme from "@data-river/shared/ui/hooks/useTheme"; | ||
import { Skeleton } from "@data-river/shared/ui"; | ||
|
||
const EditorSkeleton = () => { | ||
return ( | ||
<div className="flex flex-col space-y-3"> | ||
<Skeleton className="h-4 w-full" /> | ||
<Skeleton className="h-4 w-full" /> | ||
<Skeleton className="h-4 w-full" /> | ||
<Skeleton className="h-4 w-full" /> | ||
</div> | ||
); | ||
}; | ||
|
||
const MonacoEditorWrapper = (props: EditorProps) => { | ||
const [MonacoEditor, setMonacoEditor] = useState< | ||
MemoExoticComponent<typeof Editor> | ||
>(null as unknown as MemoExoticComponent<typeof Editor>); | ||
|
||
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor | null>( | ||
null, | ||
); | ||
|
||
const theme = useTheme(); | ||
useEffect(() => { | ||
import("@monaco-editor/react").then((module) => { | ||
setMonacoEditor( | ||
() => module.default as unknown as MemoExoticComponent<typeof Editor>, | ||
); | ||
}); | ||
}, []); | ||
|
||
const handleEditorDidMount: OnMount = useCallback( | ||
(_editor, monaco) => { | ||
const customTheme: editor.IStandaloneThemeData = { | ||
base: "vs-dark", | ||
inherit: true, | ||
colors: darkTheme.colors, | ||
rules: [], | ||
}; | ||
|
||
monaco.editor.defineTheme("customTheme", customTheme); | ||
theme === "dark" | ||
? monaco.editor.setTheme("customTheme") | ||
: monaco.editor.setTheme("vs-light"); | ||
setEditor(_editor); | ||
}, | ||
[theme, setEditor], | ||
); | ||
|
||
useEffect(() => { | ||
editor?.updateOptions({ | ||
theme: theme === "dark" ? "customTheme" : "vs-light", | ||
}); | ||
}, [theme, editor]); | ||
|
||
if (!MonacoEditor) return <EditorSkeleton />; | ||
|
||
return ( | ||
<MonacoEditor | ||
{...props} | ||
options={{ ...props.options }} | ||
onMount={handleEditorDidMount} | ||
loading={<EditorSkeleton />} | ||
/> | ||
); | ||
}; | ||
|
||
export default MonacoEditorWrapper; |
Oops, something went wrong.