add more types

This commit is contained in:
Igor Carvalho 2023-08-04 19:35:39 -03:00
commit cc26bb0c8f
23 changed files with 127 additions and 277 deletions

View file

@ -42,7 +42,7 @@ export default function GenericNode({
nodes: flow.data.nodes, nodes: flow.data.nodes,
}, },
updateEdge: (edge) => { updateEdge: (edge) => {
flow.data.edges = edge; flow.data!.edges = edge;
reactFlowInstance.setEdges(edge); reactFlowInstance.setEdges(edge);
updateNodeInternals(data.id); updateNodeInternals(data.id);
}, },

View file

@ -2,7 +2,7 @@ import { useEffect } from "react";
export function useOnClickOutside(ref, handler) { export function useOnClickOutside(ref, handler) {
useEffect(() => { useEffect(() => {
const listener = (event) => { const listener = (event: Event) => {
// Do nothing if clicking ref's element or its children // Do nothing if clicking ref's element or its children
if (!ref.current || ref.current.contains(event.target)) { if (!ref.current || ref.current.contains(event.target)) {
return; return;

View file

@ -4,6 +4,7 @@ import { Label } from "../../components/ui/label";
import { Textarea } from "../../components/ui/textarea"; import { Textarea } from "../../components/ui/textarea";
import { InputProps } from "../../types/components"; import { InputProps } from "../../types/components";
import { readFlowsFromDatabase } from "../../controllers/API"; import { readFlowsFromDatabase } from "../../controllers/API";
import { FlowType } from "../../types/flow";
export const EditFlowSettings: React.FC<InputProps> = ({ export const EditFlowSettings: React.FC<InputProps> = ({
name, name,
@ -15,13 +16,12 @@ export const EditFlowSettings: React.FC<InputProps> = ({
tabId, tabId,
setName, setName,
setDescription, setDescription,
updateFlow,
}: InputProps): JSX.Element => { }: InputProps): JSX.Element => {
const [isMaxLength, setIsMaxLength] = useState(false); const [isMaxLength, setIsMaxLength] = useState(false);
const nameLists = useRef<string[]>([]); const nameLists = useRef<string[]>([]);
useEffect(() => { useEffect(() => {
readFlowsFromDatabase().then((flows) => { readFlowsFromDatabase().then((flows) => {
flows.forEach((flow) => { flows.forEach((flow: FlowType) => {
nameLists.current.push(flow.name); nameLists.current.push(flow.name);
}); });
}); });
@ -35,9 +35,9 @@ export const EditFlowSettings: React.FC<InputProps> = ({
setIsMaxLength(false); setIsMaxLength(false);
} }
if (!nameLists.current.includes(value)) { if (!nameLists.current.includes(value)) {
setInvalidName(false); setInvalidName!(false);
} else { } else {
setInvalidName(true); setInvalidName!(true);
} }
setName(value); setName(value);
}; };

View file

@ -42,13 +42,13 @@ export default function CodeTabsComponent({
tweaks, tweaks,
}: codeTabsPropsType) { }: codeTabsPropsType) {
const [isCopied, setIsCopied] = useState<Boolean>(false); const [isCopied, setIsCopied] = useState<Boolean>(false);
const [data, setData] = useState(flow ? flow["data"]["nodes"] : null); const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
const [openAccordion, setOpenAccordion] = useState<string[]>([]); const [openAccordion, setOpenAccordion] = useState<string[]>([]);
const { dark } = useContext(darkContext); const { dark } = useContext(darkContext);
useEffect(() => { useEffect(() => {
if (flow && flow["data"]["nodes"]) { if (flow && flow["data"]!["nodes"]) {
setData(flow["data"]["nodes"]); setData(flow["data"]!["nodes"]);
} }
}, [flow]); }, [flow]);

View file

@ -1,4 +1,4 @@
import { createContext, useCallback, useContext, useState } from "react"; import { ReactNode, createContext, useCallback, useContext, useState } from "react";
const initialValue = { const initialValue = {
updateSSEData: ({}) => {}, updateSSEData: ({}) => {},

View file

@ -7,7 +7,7 @@ import {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import { Node, addEdge } from "reactflow"; import { Edge, Node, ReactFlowJsonObject, addEdge } from "reactflow";
import ShortUniqueId from "short-unique-id"; import ShortUniqueId from "short-unique-id";
import { import {
deleteFlowFromDatabase, deleteFlowFromDatabase,
@ -18,8 +18,8 @@ import {
uploadFlowsToDatabase, uploadFlowsToDatabase,
} from "../controllers/API"; } from "../controllers/API";
import { APIClassType, APITemplateType } from "../types/api"; import { APIClassType, APITemplateType } from "../types/api";
import { FlowType, NodeDataType, NodeType } from "../types/flow"; import { FlowType, NodeDataType, NodeType, TweaksType } from "../types/flow";
import { TabsContextType, TabsState } from "../types/tabs"; import { TabsContextType, TabsState, errorsVarType } from "../types/tabs";
import { import {
addVersionToDuplicates, addVersionToDuplicates,
updateIds, updateIds,
@ -78,7 +78,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
edges: any; edges: any;
} | null>(null); } | null>(null);
const [tabsState, setTabsState] = useState<TabsState>({}); const [tabsState, setTabsState] = useState<TabsState>({});
const [getTweak, setTweak] = useState([]); const [getTweak, setTweak] = useState<TweaksType[]>([]);
const newNodeId = useRef(uid()); const newNodeId = useRef(uid());
function incrementNodeId() { function incrementNodeId() {
@ -133,8 +133,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
//get tabs from db //get tabs from db
return readFlowsFromDatabase(); return readFlowsFromDatabase();
} }
function processDBData(DbData) { function processDBData(DbData: FlowType[]) {
DbData.forEach((flow) => { DbData.forEach((flow: FlowType) => {
try { try {
if (!flow.data) { if (!flow.data) {
return; return;
@ -147,7 +147,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}); });
} }
function processFlowEdges(flow) { function processFlowEdges(flow: FlowType) {
if (!flow.data || !flow.data.edges) return; if (!flow.data || !flow.data.edges) return;
flow.data.edges.forEach((edge) => { flow.data.edges.forEach((edge) => {
edge.className = ""; edge.className = "";
@ -163,7 +163,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
node.data.node!.documentation = template["documentation"]; node.data.node!.documentation = template["documentation"];
} }
function processFlowNodes(flow) { function processFlowNodes(flow: FlowType) {
if (!flow.data || !flow.data.nodes) return; if (!flow.data || !flow.data.nodes) return;
flow.data.nodes.forEach((node: NodeType) => { flow.data.nodes.forEach((node: NodeType) => {
const template = templates[node.data.type]; const template = templates[node.data.type];
@ -191,7 +191,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
node: NodeType, node: NodeType,
template: APIClassType template: APIClassType
) { ) {
flow.data.edges.forEach((edge) => { flow.data!.edges.forEach((edge) => {
if (edge.source === node.id) { if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle edge.sourceHandle = edge.sourceHandle
?.split("|") ?.split("|")
@ -213,7 +213,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
); );
} }
function updateStateWithDbData(tabsData) { function updateStateWithDbData(tabsData: FlowType[]) {
setFlows(tabsData); setFlows(tabsData);
} }
@ -356,7 +356,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
*/ */
function paste( function paste(
selectionInstance, selectionInstance: {nodes: Node[], edges: Edge[]},
position: { x: number; y: number; paneX?: number; paneY?: number } position: { x: number; y: number; paneX?: number; paneY?: number }
) { ) {
let minimumX = Infinity; let minimumX = Infinity;
@ -364,7 +364,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
let idsMap = {}; let idsMap = {};
let nodes: Node<NodeDataType>[] = reactFlowInstance!.getNodes(); let nodes: Node<NodeDataType>[] = reactFlowInstance!.getNodes();
let edges = reactFlowInstance!.getEdges(); let edges = reactFlowInstance!.getEdges();
selectionInstance.nodes.forEach((n) => { selectionInstance.nodes.forEach((n: Node) => {
if (n.position.y < minimumY) { if (n.position.y < minimumY) {
minimumY = n.position.y; minimumY = n.position.y;
} }
@ -406,14 +406,14 @@ export function TabsProvider({ children }: { children: ReactNode }) {
selectionInstance.edges.forEach((e) => { selectionInstance.edges.forEach((e) => {
let source = idsMap[e.source]; let source = idsMap[e.source];
let target = idsMap[e.target]; let target = idsMap[e.target];
let sourceHandleSplitted = e.sourceHandle.split("|"); let sourceHandleSplitted = e.sourceHandle!.split("|");
let sourceHandle = let sourceHandle =
sourceHandleSplitted[0] + sourceHandleSplitted[0] +
"|" + "|" +
source + source +
"|" + "|" +
sourceHandleSplitted.slice(2).join("|"); sourceHandleSplitted.slice(2).join("|");
let targetHandleSplitted = e.targetHandle.split("|"); let targetHandleSplitted = e.targetHandle!.split("|");
let targetHandle = let targetHandle =
targetHandleSplitted.slice(0, -1).join("|") + "|" + target; targetHandleSplitted.slice(0, -1).join("|") + "|" + target;
let id = let id =
@ -449,13 +449,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
newProject?: Boolean newProject?: Boolean
): Promise<String | undefined> => { ): Promise<String | undefined> => {
if (newProject) { if (newProject) {
let flowData = extractDataFromFlow(flow); let flowData = extractDataFromFlow(flow!);
if (flowData.description == "") { if (flowData.description == "") {
flowData.description = getRandomDescription(); flowData.description = getRandomDescription();
} }
// Create a new flow with a default name if no flow is provided. // Create a new flow with a default name if no flow is provided.
const newFlow = createNewFlow(flowData, flow); const newFlow = createNewFlow(flowData, flow!);
processFlowEdges(newFlow); processFlowEdges(newFlow);
processFlowNodes(newFlow); processFlowNodes(newFlow);
@ -480,13 +480,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
} }
} else { } else {
paste( paste(
{ nodes: flow!.data.nodes, edges: flow!.data.edges }, { nodes: flow!.data!.nodes, edges: flow!.data!.edges },
{ x: 10, y: 10 } { x: 10, y: 10 }
); );
} }
}; };
const extractDataFromFlow = (flow) => { const extractDataFromFlow = (flow: FlowType) => {
let data = flow?.data ? flow.data : null; let data = flow?.data ? flow.data : null;
const description = flow?.description ? flow.description : ""; const description = flow?.description ? flow.description : "";
@ -499,17 +499,17 @@ export function TabsProvider({ children }: { children: ReactNode }) {
return { data, description }; return { data, description };
}; };
const updateEdges = (edges) => { const updateEdges = (edges: Edge[]) => {
edges.forEach((edge) => { edges.forEach((edge) => {
edge.className = edge.className =
(edge.targetHandle.split("|")[0] === "Text" (edge.targetHandle!.split("|")[0] === "Text"
? "stroke-gray-800 " ? "stroke-gray-800 "
: "stroke-gray-900 ") + " stroke-connection"; : "stroke-gray-900 ") + " stroke-connection";
edge.animated = edge.targetHandle.split("|")[0] === "Text"; edge.animated = edge.targetHandle!.split("|")[0] === "Text";
}); });
}; };
const updateNodes = (nodes, edges) => { const updateNodes = (nodes: Node[], edges: Edge[]) => {
nodes.forEach((node) => { nodes.forEach((node) => {
const template = templates[node.data.type]; const template = templates[node.data.type];
if (!template) { if (!template) {
@ -520,7 +520,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
node.data.node.base_classes = template["base_classes"]; node.data.node.base_classes = template["base_classes"];
edges.forEach((edge) => { edges.forEach((edge) => {
if (edge.source === node.id) { if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle edge.sourceHandle = edge.sourceHandle!
.split("|") .split("|")
.slice(0, 2) .slice(0, 2)
.concat(template["base_classes"]) .concat(template["base_classes"])
@ -536,14 +536,14 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}); });
}; };
const createNewFlow = (flowData, flow) => ({ const createNewFlow = (flowData: { data: ReactFlowJsonObject | null; description: string; }, flow: FlowType) => ({
description: flowData.description, description: flowData.description,
name: flow?.name ?? getRandomName(), name: flow?.name ?? getRandomName(),
data: flowData.data, data: flowData.data,
id: "", id: "",
}); });
const addFlowToLocalState = (newFlow) => { const addFlowToLocalState = (newFlow: FlowType) => {
setFlows((prevState) => { setFlows((prevState) => {
return [...prevState, newFlow]; return [...prevState, newFlow];
}); });
@ -594,7 +594,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}); });
} }
} catch (err) { } catch (err) {
setErrorData(err); setErrorData(err as errorsVarType);
} }
} }

View file

@ -29,7 +29,7 @@ export function TypesProvider({ children }: { children: ReactNode }) {
useEffect(() => { useEffect(() => {
let delay = 1000; // Start delay of 1 second let delay = 1000; // Start delay of 1 second
let intervalId; let intervalId: NodeJS.Timer;
let retryCount = 0; // Count of retry attempts let retryCount = 0; // Count of retry attempts
const maxRetryCount = 5; // Max retry attempts const maxRetryCount = 5; // Max retry attempts
@ -78,7 +78,7 @@ export function TypesProvider({ children }: { children: ReactNode }) {
// Start the initial interval. // Start the initial interval.
intervalId = setInterval(getTypes, delay); intervalId = setInterval(getTypes, delay);
console.log(intervalId)
return () => { return () => {
// This will clear the interval when the component unmounts, or when the dependencies of the useEffect hook change. // This will clear the interval when the component unmounts, or when the dependencies of the useEffect hook change.
clearInterval(intervalId!); clearInterval(intervalId!);

View file

@ -8,7 +8,7 @@ const api: AxiosInstance = axios.create({
baseURL: "", baseURL: "",
}); });
function ApiInterceptor() { function ApiInterceptor(): null {
const retryCounts = useRef([]); const retryCounts = useRef([]);
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
@ -55,7 +55,7 @@ function ApiInterceptor() {
} }
// Function to sleep for a given duration in milliseconds // Function to sleep for a given duration in milliseconds
function sleep(ms) { function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }

View file

@ -23,7 +23,7 @@ export async function getAll(): Promise<AxiosResponse<APIObjectType>> {
const GITHUB_API_URL = "https://api.github.com"; const GITHUB_API_URL = "https://api.github.com";
export async function getRepoStars(owner, repo) { export async function getRepoStars(owner: string, repo: string) {
try { try {
const response = await api.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`); const response = await api.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`);
return response.data.stargazers_count; return response.data.stargazers_count;
@ -100,7 +100,7 @@ export async function getExamples(): Promise<FlowType[]> {
export async function saveFlowToDatabase(newFlow: { export async function saveFlowToDatabase(newFlow: {
name: string; name: string;
id: string; id: string;
data: ReactFlowJsonObject; data: ReactFlowJsonObject | null;
description: string; description: string;
style?: FlowStyleType; style?: FlowStyleType;
}): Promise<FlowType> { }): Promise<FlowType> {
@ -179,7 +179,7 @@ export async function downloadFlowsFromDatabase() {
} }
} }
export async function uploadFlowsToDatabase(flows) { export async function uploadFlowsToDatabase(flows: FlowType[]) {
try { try {
const response = await api.post(`/api/v1/flows/upload/`, flows); const response = await api.post(`/api/v1/flows/upload/`, flows);

View file

@ -3,6 +3,7 @@ import "ace-builds/src-noconflict/mode-python";
import "ace-builds/src-noconflict/theme-github"; import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/theme-twilight"; import "ace-builds/src-noconflict/theme-twilight";
import { import {
MutableRefObject,
ReactNode, ReactNode,
forwardRef, forwardRef,
useContext, useContext,
@ -15,7 +16,7 @@ import CodeTabsComponent from "../../components/codeTabsComponent";
import IconComponent from "../../components/genericIconComponent"; import IconComponent from "../../components/genericIconComponent";
import { EXPORT_CODE_DIALOG } from "../../constants/constants"; import { EXPORT_CODE_DIALOG } from "../../constants/constants";
import { TabsContext } from "../../contexts/tabsContext"; import { TabsContext } from "../../contexts/tabsContext";
import { FlowType } from "../../types/flow/index"; import { FlowType, NodeType } from "../../types/flow/index";
import { buildTweaks } from "../../utils/reactflowUtils"; import { buildTweaks } from "../../utils/reactflowUtils";
import { import {
getCurlCode, getCurlCode,
@ -25,6 +26,7 @@ import {
} from "../../utils/utils"; } from "../../utils/utils";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
import { tweakType } from "../../types/components"; import { tweakType } from "../../types/components";
import { APITemplateType } from "../../types/api";
const ApiModal = forwardRef( const ApiModal = forwardRef(
( (
@ -42,7 +44,7 @@ const ApiModal = forwardRef(
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [activeTab, setActiveTab] = useState("0"); const [activeTab, setActiveTab] = useState("0");
const tweak = useRef<tweakType[]>([]); const tweak = useRef<tweakType[]>([]);
const tweaksList = useRef([]); const tweaksList = useRef<string[]>([]);
const { setTweak, getTweak, tabsState } = useContext(TabsContext); const { setTweak, getTweak, tabsState } = useContext(TabsContext);
const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState); const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState);
const curl_code = getCurlCode(flow, tweak.current, tabsState); const curl_code = getCurlCode(flow, tweak.current, tabsState);
@ -180,7 +182,7 @@ const ApiModal = forwardRef(
}, [flow["data"]["nodes"], open]); }, [flow["data"]["nodes"], open]);
function filterNodes() { function filterNodes() {
let arrNodesWithValues = []; let arrNodesWithValues: string[] = [];
flow["data"]["nodes"].forEach((t) => { flow["data"]["nodes"].forEach((t) => {
Object.keys(t["data"]["node"]["template"]) Object.keys(t["data"]["node"]["template"])
@ -205,7 +207,7 @@ const ApiModal = forwardRef(
return self.indexOf(value) === index; return self.indexOf(value) === index;
}); });
} }
function buildTweakObject(tw, changes, template) { function buildTweakObject(tw: string, changes: string | string[], template: APITemplateType) {
if (template.type === "float") { if (template.type === "float") {
changes = parseFloat(changes); changes = parseFloat(changes);
} }
@ -255,7 +257,7 @@ const ApiModal = forwardRef(
setTweak(tweak.current); setTweak(tweak.current);
} }
function buildContent(value) { function buildContent(value: string) {
const htmlContent = ( const htmlContent = (
<div className="w-[200px]"> <div className="w-[200px]">
<span>{value != null && value != "" ? value : "None"}</span> <span>{value != null && value != "" ? value : "None"}</span>
@ -264,7 +266,7 @@ const ApiModal = forwardRef(
return htmlContent; return htmlContent;
} }
function getValue(value, node, template) { function getValue(value: string, node: NodeType, template: APITemplateType) {
let returnValue = value ?? ""; let returnValue = value ?? "";
if (getTweak.length > 0) { if (getTweak.length > 0) {

View file

@ -27,6 +27,7 @@ import { typesContext } from "../../contexts/typesContext";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import { classNames } from "../../utils/utils"; import { classNames } from "../../utils/utils";
import BaseModal from "../baseModal"; import BaseModal from "../baseModal";
import { TabsState } from "../../types/tabs";
const EditNodeModal = forwardRef( const EditNodeModal = forwardRef(
( (
@ -310,7 +311,8 @@ const EditNodeModal = forwardRef(
className="mt-3" className="mt-3"
onClick={() => { onClick={() => {
setData(cloneDeep(myData)); //saves data with actual state of modal setData(cloneDeep(myData)); //saves data with actual state of modal
setTabsState((prev) => { //@ts-ignore
setTabsState((prev: TabsState) => {
return { return {
...prev, ...prev,
[tabId]: { [tabId]: {

View file

@ -1,180 +0,0 @@
import { useState } from "react";
import CodeAreaComponent from "../../../../components/codeAreaComponent";
import Dropdown from "../../../../components/dropdownComponent";
import FloatComponent from "../../../../components/floatComponent";
import InputComponent from "../../../../components/inputComponent";
import InputFileComponent from "../../../../components/inputFileComponent";
import InputListComponent from "../../../../components/inputListComponent";
import IntComponent from "../../../../components/intComponent";
import PromptAreaComponent from "../../../../components/promptComponent";
import TextAreaComponent from "../../../../components/textAreaComponent";
import ToggleComponent from "../../../../components/toggleComponent";
import { classNames } from "../../../../utils/utils";
export default function ModalField({
data,
title,
required,
id,
name,
type,
index,
}) {
const [enabled, setEnabled] = useState(
data.node.template[name]?.value ?? false
);
const display =
type === "str" ||
type === "int" ||
type === "prompt" ||
type === "bool" ||
type === "float" ||
type === "file" ||
type === "code";
return (
<div
className={classNames(
"flex w-full flex-row items-center justify-between",
display ? "" : "hidden",
Object.keys(data.node.template).filter(
(t) =>
t.charAt(0) !== "_" &&
data.node.template[t].advanced &&
data.node.template[t].show
).length -
1 ===
index
? "pb-4"
: ""
)}
>
{display && (
<div>
<span className="mx-2">{title}</span>
<span className="text-status-red">{required ? " *" : ""}</span>
</div>
)}
{type === "str" && !data.node.template[name].options ? (
<div className="w-1/2">
{data.node.template[name].list ? (
<InputListComponent
disabled={false}
value={
!data.node.template[name].value ||
data.node.template[name].value === ""
? [""]
: data.node.template[name].value
}
onChange={(t: string[]) => {
data.node.template[name].value = t;
}}
/>
) : data.node.template[name].multiline ? (
<TextAreaComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
/>
) : (
<InputComponent
disabled={false}
password={data.node.template[name].password ?? false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
}}
/>
)}
</div>
) : type === "bool" ? (
<div className="ml-auto">
{" "}
<ToggleComponent
disabled={false}
enabled={enabled}
setEnabled={(t) => {
data.node.template[name].value = t;
setEnabled(t);
}}
size="small"
/>
</div>
) : type === "float" ? (
<div className="w-1/2">
<FloatComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
}}
/>
</div>
) : type === "str" && data.node.template[name].options ? (
<div className="w-1/2">
<Dropdown
options={data.node.template[name].options}
onSelect={(newValue) => (data.node.template[name].value = newValue)}
value={data.node.template[name].value ?? "Choose an option"}
></Dropdown>
</div>
) : type === "int" ? (
<div className="w-1/2">
<IntComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
}}
/>
</div>
) : type === "file" ? (
<div className="w-1/2">
<InputFileComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
fileTypes={data.node.template[name].fileTypes}
suffixes={data.node.template[name].suffixes}
onFileChange={(t: string) => {
data.node.template[name].file_path = t;
}}
></InputFileComponent>
</div>
) : type === "prompt" ? (
<div className="w-1/2">
<PromptAreaComponent
field_name={name}
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
/>
</div>
) : type === "code" ? (
<div className="w-1/2">
<CodeAreaComponent
dynamic={data.node.template[name].dynamic ?? false}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
}}
nodeClass={data.node}
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
/>
</div>
) : (
<div className="hidden"></div>
)}
</div>
);
}

View file

@ -47,7 +47,6 @@ export default function FlowSettingsModal({
tabId={tabId} tabId={tabId}
setName={setName} setName={setName}
setDescription={setDescription} setDescription={setDescription}
updateFlow={updateFlow}
/> />
</BaseModal.Content> </BaseModal.Content>

View file

@ -25,6 +25,7 @@ import { Textarea } from "../../components/ui/textarea";
import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants"; import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants";
import { TabsContext } from "../../contexts/tabsContext"; import { TabsContext } from "../../contexts/tabsContext";
import { validateNodes } from "../../utils/reactflowUtils"; import { validateNodes } from "../../utils/reactflowUtils";
import { TabsState, errorsVarType } from "../../types/tabs";
export default function FormModal({ export default function FormModal({
flow, flow,
@ -354,7 +355,8 @@ export default function FormModal({
name: flow.name, name: flow.name,
description: flow.description, description: flow.description,
}); });
setTabsState((old) => { //@ts-ignore
setTabsState((old: TabsState) => {
if (!chatKey) return old; if (!chatKey) return old;
let newTabsState = _.cloneDeep(old); let newTabsState = _.cloneDeep(old);
newTabsState[id.current].formKeysData.input_keys![chatKey] = ""; newTabsState[id.current].formKeysData.input_keys![chatKey] = "";
@ -468,7 +470,8 @@ export default function FormModal({
tabsState[id.current].formKeysData.input_keys![i] tabsState[id.current].formKeysData.input_keys![i]
} }
onChange={(e) => { onChange={(e) => {
setTabsState((old) => { //@ts-ignore
setTabsState((old: TabsState) => {
let newTabsState = _.cloneDeep(old); let newTabsState = _.cloneDeep(old);
newTabsState[id.current].formKeysData.input_keys![ newTabsState[id.current].formKeysData.input_keys![
i i
@ -576,7 +579,8 @@ export default function FormModal({
sendMessage={sendMessage} sendMessage={sendMessage}
setChatValue={(value) => { setChatValue={(value) => {
setChatValue(value); setChatValue(value);
setTabsState((old) => { //@ts-ignore
setTabsState((old: TabsState) => {
let newTabsState = _.cloneDeep(old); let newTabsState = _.cloneDeep(old);
newTabsState[id.current].formKeysData.input_keys![ newTabsState[id.current].formKeysData.input_keys![
chatKey! chatKey!

View file

@ -42,7 +42,7 @@ export default function GenericModal({
const [wordsHighlight, setWordsHighlight] = useState<string[]>([]); const [wordsHighlight, setWordsHighlight] = useState<string[]>([]);
const { setErrorData, setSuccessData, setNoticeData } = const { setErrorData, setSuccessData, setNoticeData } =
useContext(alertContext); useContext(alertContext);
const ref = useRef<HTMLDivElement>(); const ref = useRef<HTMLTextAreaElement | undefined>();
const divRef = useRef(null); const divRef = useRef(null);
const divRefPrompt = useRef(null); const divRefPrompt = useRef(null);
@ -208,7 +208,7 @@ export default function GenericModal({
<TextAreaContentView /> <TextAreaContentView />
) : type !== TypeModal.PROMPT ? ( ) : type !== TypeModal.PROMPT ? (
<Textarea <Textarea
ref={ref} ref={ref!}
className="form-input h-full w-full rounded-lg focus-visible:ring-1" className="form-input h-full w-full rounded-lg focus-visible:ring-1"
value={inputValue} value={inputValue}
onChange={(e) => { onChange={(e) => {

View file

@ -1,11 +1,12 @@
import _ from "lodash"; import _ from "lodash";
import { useCallback, useContext, useEffect, useRef, useState } from "react"; import { MouseEvent, useCallback, useContext, useEffect, useRef, useState } from "react";
import ReactFlow, { import ReactFlow, {
Background, Background,
Connection, Connection,
Controls, Controls,
Edge, Edge,
EdgeChange, EdgeChange,
Node,
NodeChange, NodeChange,
NodeDragHandler, NodeDragHandler,
OnEdgesDelete, OnEdgesDelete,
@ -30,6 +31,7 @@ import { isValidConnection } from "../../../../utils/reactflowUtils";
import { isWrappedWithClass } from "../../../../utils/utils"; import { isWrappedWithClass } from "../../../../utils/utils";
import ConnectionLineComponent from "../ConnectionLineComponent"; import ConnectionLineComponent from "../ConnectionLineComponent";
import ExtraSidebar from "../extraSidebarComponent"; import ExtraSidebar from "../extraSidebarComponent";
import { TabsState } from "../../../../types/tabs";
const nodeTypes = { const nodeTypes = {
genericNode: GenericNode, genericNode: GenericNode,
@ -51,7 +53,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
} = useContext(TabsContext); } = useContext(TabsContext);
const { types, reactFlowInstance, setReactFlowInstance, templates } = const { types, reactFlowInstance, setReactFlowInstance, templates } =
useContext(typesContext); useContext(typesContext);
const reactFlowWrapper = useRef(null); const reactFlowWrapper = useRef<HTMLDivElement>(null);
const { takeSnapshot } = useContext(undoRedoContext); const { takeSnapshot } = useContext(undoRedoContext);
@ -80,8 +82,8 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
event.preventDefault(); event.preventDefault();
let bounds = reactFlowWrapper.current?.getBoundingClientRect(); let bounds = reactFlowWrapper.current?.getBoundingClientRect();
paste(lastCopiedSelection, { paste(lastCopiedSelection, {
x: position.x - bounds.left, x: position.x - bounds!.left,
y: position.y - bounds.top, y: position.y - bounds!.top,
}); });
} }
if ( if (
@ -93,7 +95,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
} }
} }
}; };
const handleMouseMove = (event: MouseEvent) => { const handleMouseMove = (event) => {
setPosition({ x: event.clientX, y: event.clientY }); setPosition({ x: event.clientX, y: event.clientY });
}; };
@ -147,7 +149,8 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
let newX = _.cloneDeep(x); let newX = _.cloneDeep(x);
return newX; return newX;
}); });
setTabsState((prev) => { //@ts-ignore
setTabsState((prev: TabsState) => {
return { return {
...prev, ...prev,
[tabId]: { [tabId]: {
@ -163,7 +166,8 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
const onNodesChangeMod = useCallback( const onNodesChangeMod = useCallback(
(s: NodeChange[]) => { (s: NodeChange[]) => {
onNodesChange(s); onNodesChange(s);
setTabsState((prev) => { //@ts-ignore
setTabsState((prev: TabsState) => {
return { return {
...prev, ...prev,
[tabId]: { [tabId]: {
@ -243,9 +247,9 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
// If data type is not "chatInput" or if there are no "chatInputNode" nodes present in the ReactFlow instance, create a new node // If data type is not "chatInput" or if there are no "chatInputNode" nodes present in the ReactFlow instance, create a new node
// Calculate the position where the node should be created // Calculate the position where the node should be created
const position = reactFlowInstance?.project({ const position = reactFlowInstance!.project({
x: event.clientX - reactflowBounds.left, x: event.clientX - reactflowBounds!.left,
y: event.clientY - reactflowBounds.top, y: event.clientY - reactflowBounds!.top,
}); });
// Generate a unique node ID // Generate a unique node ID
@ -297,7 +301,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
}, []); }, []);
const onDelete = useCallback( const onDelete = useCallback(
(mynodes) => { (mynodes: Node[]) => {
takeSnapshot(); takeSnapshot();
setEdges( setEdges(
edges.filter( edges.filter(
@ -322,7 +326,6 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
[reactFlowInstance, setEdges] [reactFlowInstance, setEdges]
); );
// IS THIS RIGHT?
const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => { const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => {
if (!edgeUpdateSuccessful.current) { if (!edgeUpdateSuccessful.current) {
setEdges((eds) => eds.filter((e) => e.id !== edge.id)); setEdges((eds) => eds.filter((e) => e.id !== edge.id));
@ -335,7 +338,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
const onSelectionEnd = useCallback(() => { const onSelectionEnd = useCallback(() => {
setSelectionEnded(true); setSelectionEnded(true);
}, []); }, []);
const onSelectionStart = useCallback((event) => { const onSelectionStart = useCallback((event: MouseEvent) => {
event.preventDefault(); event.preventDefault();
setSelectionEnded(false); setSelectionEnded(false);
}, []); }, []);
@ -349,7 +352,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
} }
}, [selectionEnded, lastSelection]); }, [selectionEnded, lastSelection]);
const onSelectionChange = useCallback((flow): void => { const onSelectionChange = useCallback((flow: OnSelectionChangeParams): void => {
setLastSelection(flow); setLastSelection(flow);
}, []); }, []);
@ -378,7 +381,6 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
onEdgesChange={onEdgesChangeMod} onEdgesChange={onEdgesChangeMod}
onConnect={onConnect} onConnect={onConnect}
disableKeyboardA11y={true} disableKeyboardA11y={true}
onLoad={setReactFlowInstance}
onInit={setReactFlowInstance} onInit={setReactFlowInstance}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
onEdgeUpdate={onEdgeUpdate} onEdgeUpdate={onEdgeUpdate}

View file

@ -1,10 +1,10 @@
import { Edge, Node, Viewport } from "reactflow"; import { Edge, Node, Viewport } from "reactflow";
//kind and class are just representative names to represent the actual structure of the object received by the API //kind and class are just representative names to represent the actual structure of the object received by the API
export type APIObjectType = { kind: APIKindType; [key: string]: APIKindType }; export type APIObjectType = { kind?: APIKindType; [key: string]: APIKindType };
export type APIKindType = { class: APIClassType; [key: string]: APIClassType }; export type APIKindType = { class: APIClassType; [key: string]: APIClassType };
export type APITemplateType = { export type APITemplateType = {
variable: TemplateVariableType; variable?: TemplateVariableType;
[key: string]: TemplateVariableType; [key: string]: TemplateVariableType;
}; };
export type APIClassType = { export type APIClassType = {

View file

@ -177,10 +177,10 @@ export type InputProps = {
maxLength?: number; maxLength?: number;
flows: Array<{ id: string; name: string; description: string }>; flows: Array<{ id: string; name: string; description: string }>;
tabId: string; tabId: string;
invalidName: boolean; invalidName?: boolean;
setName: (name: string) => void; setName: (name: string) => void;
setDescription: (description: string) => void; setDescription: (description: string) => void;
setInvalidName: (invalidName: boolean) => void; setInvalidName?: (invalidName: boolean) => void;
}; };
export type TooltipProps = { export type TooltipProps = {
@ -211,8 +211,24 @@ export type groupedObjType = {
type: string; type: string;
}; };
type test = {
[char: string]: string;
}
export type tweakType = { export type tweakType = {
[key: string]: object; [key: string]: {
[char: string]: string;
};
};
export type apiModalTweakType = {
current: Array<{
[key: string]: {
[char: string]: string | number;
}
}>;
}; };
export type nodeToolbarType = { export type nodeToolbarType = {
@ -240,7 +256,7 @@ export type chatTriggerPropType = {
}; };
export type headerFlowsType = { export type headerFlowsType = {
data: ReactFlowJsonObject; data: ReactFlowJsonObject | null;
description: string; description: string;
id: string; id: string;
name: string; name: string;
@ -408,14 +424,14 @@ export type codeTabsPropsType = {
buildContent?: (value: string) => ReactNode; buildContent?: (value: string) => ReactNode;
getValue?: ( getValue?: (
value: string, value: string,
node: getValueNodeType, node: NodeType,
template: codeTabsFuncTempType template: APITemplateType
) => string; ) => string;
buildTweakObject?: ( buildTweakObject?: (
tw: string, tw: string,
changes: string | string[] | boolean, changes: string | string[] | boolean | number,
template: codeTabsFuncTempType template: APITemplateType
) => string; ) => string | void;
}; };
}; };

View file

@ -4,7 +4,7 @@ import { APIClassType } from "../api/index";
export type FlowType = { export type FlowType = {
name: string; name: string;
id: string; id: string;
data: ReactFlowJsonObject; data: ReactFlowJsonObject | null;
description: string; description: string;
style?: FlowStyleType; style?: FlowStyleType;
}; };

View file

@ -1,3 +1,4 @@
import { Dispatch, SetStateAction } from "react";
import { FlowType, TweaksType } from "../flow"; import { FlowType, TweaksType } from "../flow";
export type TabsContextType = { export type TabsContextType = {
@ -33,7 +34,7 @@ export type TabsContextType = {
) => void; ) => void;
lastCopiedSelection: { nodes: any; edges: any } | null; lastCopiedSelection: { nodes: any; edges: any } | null;
setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void; setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void;
setTweak: (tweak: TweaksType) => void; setTweak: Dispatch<SetStateAction<TweaksType[]>>;
getTweak: TweaksType[]; getTweak: TweaksType[];
}; };
@ -48,3 +49,8 @@ export type TabsState = {
}; };
}; };
}; };
export type errorsVarType = {
title: string;
list?: Array<string>;
};

View file

@ -1,6 +1,6 @@
import { Edge, Node, ReactFlowInstance } from "reactflow"; import { Edge, Node, ReactFlowInstance } from "reactflow";
import { AlertItemType } from "../alerts"; import { AlertItemType } from "../alerts";
import { APIClassType } from "../api"; import { APIClassType, APIObjectType } from "../api";
const types: { [char: string]: string } = {}; const types: { [char: string]: string } = {};
const template: { [char: string]: APIClassType } = {}; const template: { [char: string]: APIClassType } = {};
@ -14,7 +14,7 @@ export type typesContextType = {
setTypes: (newState: {}) => void; setTypes: (newState: {}) => void;
templates: typeof template; templates: typeof template;
setTemplates: (newState: {}) => void; setTemplates: (newState: {}) => void;
data: typeof data; data: APIObjectType;
setData: (newState: {}) => void; setData: (newState: {}) => void;
}; };

View file

@ -1,5 +1,5 @@
import _ from "lodash"; import _ from "lodash";
import { Connection, ReactFlowInstance } from "reactflow"; import { Connection, ReactFlowInstance, ReactFlowJsonObject } from "reactflow";
import { APITemplateType } from "../types/api"; import { APITemplateType } from "../types/api";
import { FlowType, NodeType } from "../types/flow"; import { FlowType, NodeType } from "../types/flow";
import { cleanEdgesType } from "../types/utils/reactflowUtils"; import { cleanEdgesType } from "../types/utils/reactflowUtils";
@ -93,7 +93,7 @@ export function isValidConnection(
export function removeApiKeys(flow: FlowType): FlowType { export function removeApiKeys(flow: FlowType): FlowType {
let cleanFLow = _.cloneDeep(flow); let cleanFLow = _.cloneDeep(flow);
cleanFLow.data.nodes.forEach((node) => { cleanFLow.data!.nodes.forEach((node) => {
for (const key in node.data.node.template) { for (const key in node.data.node.template) {
if (node.data.node.template[key].password) { if (node.data.node.template[key].password) {
node.data.node.template[key].value = ""; node.data.node.template[key].value = "";
@ -126,7 +126,7 @@ export function updateTemplate(
return clonedObject; return clonedObject;
} }
export function updateIds(newFlow, getNodeId) { export function updateIds(newFlow: ReactFlowJsonObject, getNodeId: (type: string) => string) {
let idsMap = {}; let idsMap = {};
newFlow.nodes.forEach((n: NodeType) => { newFlow.nodes.forEach((n: NodeType) => {
@ -141,14 +141,14 @@ export function updateIds(newFlow, getNodeId) {
newFlow.edges.forEach((e) => { newFlow.edges.forEach((e) => {
e.source = idsMap[e.source]; e.source = idsMap[e.source];
e.target = idsMap[e.target]; e.target = idsMap[e.target];
let sourceHandleSplitted = e.sourceHandle.split("|"); let sourceHandleSplitted = e.sourceHandle!.split("|");
e.sourceHandle = e.sourceHandle =
sourceHandleSplitted[0] + sourceHandleSplitted[0] +
"|" + "|" +
e.source + e.source +
"|" + "|" +
sourceHandleSplitted.slice(2).join("|"); sourceHandleSplitted.slice(2).join("|");
let targetHandleSplitted = e.targetHandle.split("|"); let targetHandleSplitted = e.targetHandle!.split("|");
e.targetHandle = e.targetHandle =
targetHandleSplitted.slice(0, -1).join("|") + "|" + e.target; targetHandleSplitted.slice(0, -1).join("|") + "|" + e.target;
e.id = e.id =
@ -161,8 +161,8 @@ export function updateIds(newFlow, getNodeId) {
}); });
} }
export function buildTweaks(flow) { export function buildTweaks(flow: FlowType) {
return flow.data.nodes.reduce((acc, node) => { return flow.data!.nodes.reduce((acc, node) => {
acc[node.data.id] = {}; acc[node.data.id] = {};
return acc; return acc;
}, {}); }, {});

View file

@ -89,7 +89,7 @@ export function checkUpperWords(str: string): string {
export const isWrappedWithClass = (event: any, className: string | undefined) => export const isWrappedWithClass = (event: any, className: string | undefined) =>
event.target.closest(`.${className}`); event.target.closest(`.${className}`);
export function groupByFamily(data, baseClasses: string, left: boolean, flow?: NodeType[]): groupedObjType[] { export function groupByFamily(data: APIObjectType, baseClasses: string, left: boolean, flow?: NodeType[]): groupedObjType[] {
const baseClassesSet = new Set(baseClasses.split("\n")); const baseClassesSet = new Set(baseClasses.split("\n"));
let arrOfPossibleInputs: Array<{ category: string; nodes: string[]; full: boolean; }> = []; let arrOfPossibleInputs: Array<{ category: string; nodes: string[]; full: boolean; }> = [];
let arrOfPossibleOutputs: Array<{ category: string; nodes: string[]; full: boolean; }> = []; let arrOfPossibleOutputs: Array<{ category: string; nodes: string[]; full: boolean; }> = [];
@ -104,7 +104,7 @@ export function groupByFamily(data, baseClasses: string, left: boolean, flow?: N
"int", "int",
]); ]);
const checkBaseClass = (t: any) => const checkBaseClass = (t) =>
t.type && t.type &&
t.show && t.show &&
((!excludeTypes.has(t.type) && baseClassesSet.has(t.type)) || ((!excludeTypes.has(t.type) && baseClassesSet.has(t.type)) ||
@ -234,7 +234,7 @@ export function varHighlightHTML({ name }: IVarHighlightType): string {
return html; return html;
} }
export function buildTweakObject(tweak: tweakType[]): string { export function buildTweakObject(tweak: tweakType[]) {
tweak.forEach((el) => { tweak.forEach((el) => {
Object.keys(el).forEach((key) => { Object.keys(el).forEach((key) => {
for (let kp in el[key]) { for (let kp in el[key]) {
@ -244,7 +244,6 @@ export function buildTweakObject(tweak: tweakType[]): string {
} }
}); });
}); });
const tweakString = JSON.stringify(tweak.at(-1), null, 2); const tweakString = JSON.stringify(tweak.at(-1), null, 2);
return tweakString; return tweakString;
} }