Add webhook endpoint, and other fixes (#1766)

* Update FastAPI app configuration in main.py

* Add webhook endpoint

* Add Observer model and related changes to database models

* Update refresh button text in ParameterComponent

* Update database models and main.py, and add webhook endpoint and utils for flow model

* Add WebhookComponent to langflow data components

* Update webhook component names in flow data and remove unused code in edge/base.py and graph/base.py

* 🐛 (endpoints.py): fix an issue where the user_id was not being correctly assigned based on the api_key_user or flow object

* 📝 (endpoints.py): Update documentation for the webhook_run_flow endpoint to provide clearer information on its purpose, arguments, and return value. Remove outdated request JSON structure and example request sections. Add information on the arguments and exceptions raised for better clarity.

* chore: Remove unnecessary trailing commas in code files

* feat: Add yield statement to get_lifespan function

* feat: Update webhook columns revision ID

* Refactor import statements for OpenAI conversational agent

* refactor(constants.ts): remove unused tabsArray function and update function name to createTabsArray for clarity
feat(constants.ts): add support for including webhook code in tabs array based on flow webhook property
feat(index.tsx): update function calls to use new createTabsArray function and include webhook code in tabs array based on flow webhook property

refactor(utils.ts): remove trailing commas in function parameters to improve code consistency and readability
feat(utils.ts): add support for including webhook cURL code and tweaks code in tabs array creation for better code organization and presentation

* chore: Update folder_id parameter type to str in API endpoints

* feat: Handle invalid JSON payload in WebhookComponent

The code changes in `Webhook.py` modify the `build` method of the `WebhookComponent` class. If an invalid JSON payload is provided, instead of raising a `ValueError`, the code now handles the exception by creating a default payload with the provided data. The commit also includes a message that describes the invalid JSON payload for better error tracking.

Note: This commit message follows the convention used in the recent user commits.

* refactor: Remove unnecessary code in main.py

* refactor: Update Alembic revision IDs for webhook columns

The Alembic revision IDs for adding webhook columns have been updated to reflect the latest changes. This ensures consistency and proper tracking of the database schema modifications.

Note: The commit message has been generated based on the provided code changes and recent commits.

* 🐛 (endpoints.py): Fix handling of flow_id_or_name variable to correctly identify flow ID or endpoint name for running a flow. Improve error handling for invalid UUID strings and flow not found scenarios.

* refactor: Handle invalid JSON payload in WebhookComponent

The code changes in `Webhook.py` modify the `build` method of the `WebhookComponent` class. If an invalid JSON payload is provided, instead of raising a `ValueError`, the code now handles the exception by creating a default payload with the provided data.

* refactor: Update get_flow_by_id function to handle None flow_id parameter

The get_flow_by_id function in utils.py has been updated to handle the case where the flow_id parameter is None. Previously, the function would raise an exception if flow_id was not provided. Now, if flow_id is None, the function returns None instead of querying the database. This change improves the robustness of the function and allows for more flexible usage.

Note: The commit message has been generated based on the provided code changes and recent commits.

* 📝 (endpoints.py): Add import statement for get_flow_by_id_or_endpoint_name function
📝 (flow.py): Add get_flow_by_id_or_endpoint_name function to retrieve a Flow object by ID or endpoint name

* refactor: Update get_flow_by_id_or_endpoint_name function to handle None flow_id parameter

* 🐛 (flow.py): replace ValueError with HTTPException to return a 404 status code when flow identifier is not found

* refactor: Update error message for flow identifier not found

The code changes in `test_endpoints.py` update the error message when a flow identifier is not found. Previously, the error message referenced the flow ID directly, but now it uses the more generic term "Flow identifier" to account for cases where the identifier could be an endpoint name. This change improves the clarity and flexibility of the error message.

Note: This commit message has been generated based on the provided code changes and recent commits.

* 🔧 (endpoints.py): remove unnecessary flow_id_or_name parameter from the simple_run_flow function call to improve code readability and maintainability
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-05-31 11:02:06 -07:00 • committed by GitHub
commit 5e2f4b8f83
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 468 additions and 295 deletions

View file

@ -15,7 +15,7 @@ export default function FolderAccordionComponent({
options,
}: AccordionComponentType): JSX.Element {
const [value, setValue] = useState(
open.length === 0 ? "" : getOpenAccordion(),
open.length === 0 ? "" : getOpenAccordion()
);
function getOpenAccordion(): string {

View file

@ -1,7 +1,6 @@
import { storeComponent } from "../../../../types/store";
import { cn } from "../../../../utils/utils";
import ForwardedIconComponent from "../../../genericIconComponent";
import ShadTooltip from "../../../shadTooltipComponent";
import { Card, CardHeader, CardTitle } from "../../../ui/card";
export default function DragCardComponent({ data }: { data: storeComponent }) {
@ -11,7 +10,7 @@ export default function DragCardComponent({ data }: { data: storeComponent }) {
draggable
//TODO check color schema
className={cn(
"group relative flex flex-col justify-between overflow-hidden transition-all hover:bg-muted/50 hover:shadow-md hover:dark:bg-[#ffffff10]",
"group relative flex flex-col justify-between overflow-hidden transition-all hover:bg-muted/50 hover:shadow-md hover:dark:bg-[#ffffff10]"
)}
>
<div>
@ -23,7 +22,7 @@ export default function DragCardComponent({ data }: { data: storeComponent }) {
"visible flex-shrink-0",
data.is_component
? "mx-0.5 h-6 w-6 text-component-icon"
: "h-7 w-7 flex-shrink-0 text-flow-icon",
: "h-7 w-7 flex-shrink-0 text-flow-icon"
)}
name={data.is_component ? "ToyBrick" : "Group"}
/>

View file

@ -18,7 +18,7 @@ export default function CodeAreaComponent({
setOpen,
}: CodeAreaComponentType) {
const [myValue, setMyValue] = useState(
typeof value == "string" ? value : JSON.stringify(value),
typeof value == "string" ? value : JSON.stringify(value)
);
useEffect(() => {
if (disabled && myValue !== "") {

View file

@ -59,7 +59,7 @@ export default function Dropdown({
? "dropdown-component-outline"
: "dropdown-component-false-outline",
"w-full justify-between font-normal",
editNode ? "input-edit-node" : "py-2",
editNode ? "input-edit-node" : "py-2"
)}
>
<span data-testid={`value-dropdown-` + id}>
@ -107,7 +107,7 @@ export default function Dropdown({
name="Check"
className={cn(
"ml-auto h-4 w-4 text-primary",
value === option ? "opacity-100" : "opacity-0",
value === option ? "opacity-100" : "opacity-0"
)}
/>
</CommandItem>

View file

@ -18,7 +18,7 @@ export const ForwardedIconComponent = memo(
strokeWidth,
id = "",
}: IconComponentProps,
ref,
ref
) => {
const [showFallback, setShowFallback] = useState(false);
@ -65,8 +65,8 @@ export const ForwardedIconComponent = memo(
/>
</Suspense>
);
},
),
}
)
);
export default ForwardedIconComponent;

View file

@ -132,7 +132,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
title: UPLOAD_ERROR_ALERT,
list: [error],
});
},
}
);
}}
>
@ -214,7 +214,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"}
className={cn(
"h-4 w-4",
isBuilding || saveLoading ? "animate-spin" : "animate-wiggle",
isBuilding || saveLoading ? "animate-spin" : "animate-wiggle"
)}
/>
{printByBuildStatus()}

View file

@ -32,11 +32,11 @@ export default function HorizontalScrollFadeComponent({
fadeContainerRef.current.classList.toggle(
"fade-left",
isScrollable && !atStart,
isScrollable && !atStart
);
fadeContainerRef.current.classList.toggle(
"fade-right",
isScrollable && !atEnd,
isScrollable && !atEnd
);
};

View file

@ -104,8 +104,8 @@ export default function InputFileComponent({
editNode
? "input-edit-node input-dialog text-muted-foreground"
: disabled
? "input-disable input-dialog primary-input"
: "input-dialog primary-input text-muted-foreground"
? "input-disable input-dialog primary-input"
: "input-dialog primary-input text-muted-foreground"
}
>
{myValue !== "" ? myValue : "No file"}

View file

@ -19,15 +19,15 @@ export default function InputGlobalComponent({
editNode = false,
}: InputGlobalComponentType): JSX.Element {
const globalVariablesEntries = useGlobalVariablesStore(
(state) => state.globalVariablesEntries,
(state) => state.globalVariablesEntries
);
const getVariableId = useGlobalVariablesStore((state) => state.getVariableId);
const unavaliableFields = useGlobalVariablesStore(
(state) => state.unavaliableFields,
(state) => state.unavaliableFields
);
const removeGlobalVariable = useGlobalVariablesStore(
(state) => state.removeGlobalVariable,
(state) => state.removeGlobalVariable
);
const setErrorData = useAlertStore((state) => state.setErrorData);
@ -130,7 +130,7 @@ export default function InputGlobalComponent({
<ForwardedIconComponent
name="Trash2"
className={cn(
"h-4 w-4 text-primary opacity-0 hover:text-status-red group-hover:opacity-100",
"h-4 w-4 text-primary opacity-0 hover:text-status-red group-hover:opacity-100"
)}
aria-hidden="true"
/>

View file

@ -2,8 +2,8 @@ import { ColDef, ColGroupDef } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
import "ag-grid-community/styles/ag-theme-balham.css"; // Optional Theme applied to the grid
import { FlowPoolObjectType } from "../../types/chat";
import TableComponent from "../tableComponent";
import { extractColumnsFromRows } from "../../utils/utils";
import TableComponent from "../tableComponent";
function RecordsOutputComponent({
flowPool,

View file

@ -21,7 +21,7 @@ const SideBarButtonsComponent = ({ items }: SideBarButtonsComponentProps) => {
data-testid={`sidebar-nav-${item.title}`}
className={cn(
buttonVariants({ variant: "ghost" }),
"!w-[200px] cursor-pointer justify-start gap-2 border border-transparent hover:border-border hover:bg-transparent",
"!w-[200px] cursor-pointer justify-start gap-2 border border-transparent hover:border-border hover:bg-transparent"
)}
>
{item.title}

View file

@ -5,7 +5,6 @@ import DateReader from "../dateReaderComponent";
import NumberReader from "../numberReader";
import ObjectRender from "../objectRender";
import StringReader from "../stringReaderComponent";
import { Label } from "../ui/label";
import { Badge } from "../ui/badge";
export default function TableAutoCellRender({
@ -35,7 +34,7 @@ export default function TableAutoCellRender({
variant="outline"
size="sq"
className={cn(
"min-w-min bg-success-background text-success-foreground hover:bg-success-background",
"min-w-min bg-success-background text-success-foreground hover:bg-success-background"
)}
>
{value}

View file

@ -48,7 +48,7 @@ export function TagsSelector({
className={cn(
selectedTags.some((category) => category === tag.name)
? "min-w-min bg-beta-foreground text-background hover:bg-beta-foreground"
: "",
: ""
)}
>
{tag.name}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "../../utils/utils";
const alertVariants = cva(
@ -15,7 +15,7 @@ const alertVariants = cva(
defaultVariants: {
variant: "default",
},
},
}
);
const Alert = React.forwardRef<
@ -55,4 +55,4 @@ const AlertDescription = React.forwardRef<
));
AlertDescription.displayName = "AlertDescription";
export { Alert, AlertTitle, AlertDescription };
export { Alert, AlertDescription, AlertTitle };

View file

@ -13,7 +13,7 @@ const Checkbox = React.forwardRef<
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className,
className
)}
{...props}
>
@ -37,7 +37,7 @@ const CheckBoxDiv = ({
className={cn(
className,
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
checked ? "bg-primary text-primary-foreground" : "",
checked ? "bg-primary text-primary-foreground" : ""
)}
>
{checked && (

View file

@ -24,7 +24,7 @@ const AccordionTrigger = React.forwardRef<
<div
className={cn(
" flex flex-1 cursor-pointer items-center justify-between border-[1px] py-2 text-sm font-medium data-[state=closed]:rounded-md data-[state=open]:rounded-t-md data-[state=open]:border-b-0 data-[state=open]:bg-muted [&[data-state=open]>svg]:rotate-180",
className,
className
)}
>
{children}
@ -43,7 +43,7 @@ const AccordionContent = React.forwardRef<
ref={ref}
className={cn(
"data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden border-[1px] text-sm data-[state=open]:rounded-b-md data-[state=open]:border-t-0 data-[state=open]:bg-muted",
className,
className
)}
{...props}
>

View file

@ -16,18 +16,18 @@ const Form = FormProvider;
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = {
name: TName;
};
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue,
{} as FormFieldContextValue
);
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
@ -66,7 +66,7 @@ type FormItemContextValue = {
};
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue,
{} as FormItemContextValue
);
const FormItem = React.forwardRef<

View file

@ -606,84 +606,6 @@ export const CONTROL_NEW_USER = {
export const tabsCode = [];
export function tabsArray(codes: string[], method: number) {
if (!method) return;
if (method === 0) {
return [
{
name: "cURL",
mode: "bash",
image: "https://curl.se/logo/curl-symbol-transparent.png",
language: "sh",
code: codes[0],
},
{
name: "Python API",
mode: "python",
image:
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
language: "py",
code: codes[1],
},
{
name: "Python Code",
mode: "python",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[2],
},
{
name: "Chat Widget HTML",
description:
"Insert this code anywhere in your &lt;body&gt; tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
mode: "html",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[3],
},
];
}
return [
{
name: "cURL",
mode: "bash",
image: "https://curl.se/logo/curl-symbol-transparent.png",
language: "sh",
code: codes[0],
},
{
name: "Python API",
mode: "python",
image:
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
language: "py",
code: codes[1],
},
{
name: "Python Code",
mode: "python",
language: "py",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
code: codes[2],
},
{
name: "Chat Widget HTML",
description:
"Insert this code anywhere in your &lt;body&gt; tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
mode: "html",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[3],
},
{
name: "Tweaks",
mode: "python",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[4],
},
];
}
export const FETCH_ERROR_MESSAGE = "Couldn't establish a connection.";
export const FETCH_ERROR_DESCRIPION =
"Check if everything is working properly and try again.";

View file

@ -355,8 +355,7 @@ export default function ParameterComponent({
name={name}
data={data}
button_text={
data.node?.template[name]?.refresh_button_text ??
"Refresh"
data.node?.template[name].refresh_button_text
}
className="extra-side-bar-buttons mt-1"
handleUpdateValues={handleRefreshButtonPress}
@ -404,8 +403,7 @@ export default function ParameterComponent({
name={name}
data={data}
button_text={
data.node?.template[name]?.refresh_button_text ??
"Refresh"
data.node?.template[name].refresh_button_text
}
className="extra-side-bar-buttons ml-2 mt-1"
handleUpdateValues={handleRefreshButtonPress}

View file

@ -24,7 +24,7 @@ const TooltipRenderComponent = ({ item, index, left }) => {
<span
key={index}
className={classNames(
index > 0 ? "mt-2 flex items-center" : "mt-3 flex items-center",
index > 0 ? "mt-2 flex items-center" : "mt-3 flex items-center"
)}
>
<div

View file

@ -9,7 +9,7 @@ const useFetchDataOnMount = (
handleUpdateValues,
setNode,
renderTooltips,
setIsLoading,
setIsLoading
) => {
const setErrorData = useAlertStore((state) => state.setErrorData);

View file

@ -6,7 +6,7 @@ const useHandleNodeClass = (
takeSnapshot,
setNode,
updateNodeInternals,
renderTooltips,
renderTooltips
) => {
const handleNodeClass = (newNodeClass, code) => {
if (!data.node) return;

View file

@ -4,7 +4,7 @@
* @param {boolean} isAuth - If the API is authenticated
* @returns {string} - The curl code
*/
export default function getCurlCode(
export default function getCurlRunCode(
flowId: string,
isAuth: boolean,
tweaksBuildedObject,
@ -25,3 +25,24 @@ export default function getCurlCode(
"tweaks": ${JSON.stringify(tweaksObject, null, 2)}}'
`;
}
/**
* Generates a cURL command for making a POST request to a webhook endpoint.
*
* @param {Object} options - The options for generating the cURL command.
* @param {string} options.flowId - The ID of the flow.
* @param {boolean} options.isAuth - Indicates whether authentication is required.
* @param {string} options.endpointName - The name of the webhook endpoint.
* @returns {string} The cURL command.
*/
export function getCurlWebhookCode(flowId, isAuth, endpointName?: string) {
return `curl -X POST \\
"${window.location.protocol}//${window.location.host}/api/v1/webhook/${
endpointName || flowId
}" \\
-H 'Content-Type: application/json'\\${
!isAuth ? `\n -H 'x-api-key: <your api key>'\\` : ""
}
-d '{"any": "data"}'
`;
}

View file

@ -1,43 +1,11 @@
export default function tabsArray(codes: string[], method: number) {
if (!method) return;
if (method === 0) {
return [
{
name: "cURL",
mode: "bash",
image: "https://curl.se/logo/curl-symbol-transparent.png",
language: "sh",
code: codes[0],
},
{
name: "Python API",
mode: "python",
image:
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
language: "py",
code: codes[1],
},
{
name: "Python Code",
mode: "python",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[2],
},
{
name: "Chat Widget HTML",
description:
"Insert this code anywhere in your &lt;body&gt; tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
mode: "html",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[3],
},
];
}
return [
export function createTabsArray(
codes,
includeWebhookCurl = false,
includeTweaks = false
) {
const tabs = [
{
name: "cURL",
name: "Run cURL",
mode: "bash",
image: "https://curl.se/logo/curl-symbol-transparent.png",
language: "sh",
@ -49,14 +17,14 @@ export default function tabsArray(codes: string[], method: number) {
image:
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
language: "py",
code: codes[1],
code: codes[2],
},
{
name: "Python Code",
mode: "python",
language: "py",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
code: codes[2],
language: "py",
code: codes[3],
},
{
name: "Chat Widget HTML",
@ -64,15 +32,30 @@ export default function tabsArray(codes: string[], method: number) {
"Insert this code anywhere in your &lt;body&gt; tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
mode: "html",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[3],
language: "html",
code: codes[4],
},
{
];
if (includeWebhookCurl) {
tabs.splice(1, 0, {
name: "Webhook cURL",
mode: "bash",
image: "https://curl.se/logo/curl-symbol-transparent.png",
language: "sh",
code: codes[1],
});
}
if (includeTweaks) {
tabs.push({
name: "Tweaks",
mode: "python",
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
language: "py",
code: codes[4],
},
];
code: codes[5],
});
}
return tabs;
}

View file

@ -18,13 +18,13 @@ import { buildContent } from "../utils/build-content";
import { buildTweaks } from "../utils/build-tweaks";
import { checkCanBuildTweakObject } from "../utils/check-can-build-tweak-object";
import { getChangesType } from "../utils/get-changes-types";
import getCurlCode from "../utils/get-curl-code";
import { getCurlRunCode, getCurlWebhookCode } from "../utils/get-curl-code";
import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value";
import getPythonApiCode from "../utils/get-python-api-code";
import getPythonCode from "../utils/get-python-code";
import { getValue } from "../utils/get-value";
import getWidgetCode from "../utils/get-widget-code";
import tabsArray from "../utils/tabs-array";
import { createTabsArray } from "../utils/tabs-array";
const ApiModal = forwardRef(
(
@ -47,23 +47,33 @@ const ApiModal = forwardRef(
const [open, setOpen] = useState(false);
const [activeTab, setActiveTab] = useState("0");
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, tweak);
const curl_code = getCurlCode(
const curl_run_code = getCurlRunCode(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name
);
const curl_webhook_code = getCurlWebhookCode(
flow?.id,
autoLogin,
flow?.endpoint_name
);
const pythonCode = getPythonCode(flow?.name, tweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
console.log("flow", flow);
const includeWebhook = flow.webhook;
const tweaksCode = buildTweaks(flow);
const codesArray = [
curl_code,
curl_run_code,
curl_webhook_code,
pythonApiCode,
pythonCode,
widgetCode,
pythonCode,
];
const [tabs, setTabs] = useState(tabsArray(codesArray, 0));
const [tabs, setTabs] = useState(
createTabsArray(codesArray, includeWebhook)
);
const canShowTweaks =
flow &&
@ -93,9 +103,9 @@ const ApiModal = forwardRef(
if (Object.keys(tweaksCode).length > 0) {
setActiveTab("0");
setTabs(tabsArray(codesArray, 1));
setTabs(createTabsArray(codesArray, includeWebhook, true));
} else {
setTabs(tabsArray(codesArray, 1));
setTabs(createTabsArray(codesArray, includeWebhook, true));
}
}, [flow["data"]!["nodes"], open]);
@ -166,7 +176,7 @@ const ApiModal = forwardRef(
const addCodes = (cloneTweak) => {
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, cloneTweak);
const curl_code = getCurlCode(
const curl_code = getCurlRunCode(
flow?.id,
autoLogin,
cloneTweak,

View file

@ -19,6 +19,7 @@ export type FlowType = {
icon?: string;
icon_bg_color?: string;
folder_id?: string;
webhook?: boolean;
};
export type NodeType = {

View file

@ -2,8 +2,6 @@ import { ColDef, ColGroupDef } from "ag-grid-community";
import clsx, { ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
import TableAutoCellRender from "../components/tableAutoCellRender";
import { priorityFields } from "../constants/constants";
import { ADJECTIVES, DESCRIPTIONS, NOUNS } from "../flow_constants";
import { APIDataType, TemplateVariableType } from "../types/api";
import {
groupedObjType,
@ -57,7 +55,7 @@ export function normalCaseToSnakeCase(str: string): string {
export function toTitleCase(
str: string | undefined,
isNodeField?: boolean,
isNodeField?: boolean
): string {
if (!str) return "";
let result = str
@ -66,7 +64,7 @@ export function toTitleCase(
if (isNodeField) return word;
if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase(),
word[0].toUpperCase() + word.slice(1).toLowerCase()
);
}
return checkUpperWords(word.toLowerCase());
@ -79,7 +77,7 @@ export function toTitleCase(
if (isNodeField) return word;
if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase(),
word[0].toUpperCase() + word.slice(1).toLowerCase()
);
}
return checkUpperWords(word.toLowerCase());
@ -183,7 +181,7 @@ export function checkLocalStorageKey(key: string): boolean {
export function IncrementObjectKey(
object: object,
key: string,
key: string
): { newKey: string; increment: number } {
let count = 1;
const type = removeCountFromString(key);
@ -218,7 +216,7 @@ export function groupByFamily(
data: APIDataType,
baseClasses: string,
left: boolean,
flow?: NodeType[],
flow?: NodeType[]
): groupedObjType[] {
const baseClassesSet = new Set(baseClasses.split("\n"));
let arrOfPossibleInputs: Array<{
@ -244,7 +242,7 @@ export function groupByFamily(
baseClassesSet.has(template.type)) ||
(template.input_types &&
template.input_types.some((inputType) =>
baseClassesSet.has(inputType),
baseClassesSet.has(inputType)
)))
);
};
@ -264,7 +262,7 @@ export function groupByFamily(
hasBaseClassInBaseClasses:
foundNode?.hasBaseClassInBaseClasses ||
nodeData.node!.base_classes.some((baseClass) =>
baseClassesSet.has(baseClass),
baseClassesSet.has(baseClass)
), //seta como anterior ou verifica se o node tem base class
displayName: nodeData.node?.display_name,
});
@ -281,10 +279,10 @@ export function groupByFamily(
if (!foundNode) {
foundNode = {
hasBaseClassInTemplate: Object.values(node!.template).some(
checkBaseClass,
checkBaseClass
),
hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) =>
baseClassesSet.has(baseClass),
baseClassesSet.has(baseClass)
),
displayName: node?.display_name,
};
@ -353,7 +351,7 @@ export function isTimeStampString(str: string): boolean {
export function extractColumnsFromRows(
rows: object[],
mode: "intersection" | "union",
mode: "intersection" | "union"
): (ColDef<any> | ColGroupDef<any>)[] {
const columnsKeys: { [key: string]: ColDef<any> | ColGroupDef<any> } = {};
if (rows.length === 0) {