This commit is contained in:
cristhianzl 2024-06-03 15:49:51 -03:00
commit 9d033c9e34
157 changed files with 6860 additions and 5525 deletions

View file

@ -120,7 +120,6 @@ export default function App() {
await getFoldersApi();
await getTypes();
await refreshFlows();
console.log(axios.defaults);
const res = await getGlobalVariables();
setGlobalVariables(res);
checkHasStore();

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

@ -841,9 +841,7 @@ export default function CodeTabsComponent({
node.data.node!.template[
templateField
].value?.toString() === "{}"
? {
// yourkey: "value",
}
? {}
: node.data.node!
.template[
templateField

View file

@ -12,6 +12,9 @@ export default function DictComponent({
editNode = false,
id = "",
}: DictComponentType): JSX.Element {
// Create a reference to the value
const ref = useRef(value);
useEffect(() => {
if (disabled) {
onChange({});
@ -19,10 +22,9 @@ export default function DictComponent({
}, [disabled]);
useEffect(() => {
if (value) onChange(value);
// Update the reference value
ref.current = value;
}, [value]);
const ref = useRef(value);
return (
<div
className={classNames(

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

@ -9,11 +9,14 @@ export const EditFlowSettings: React.FC<InputProps> = ({
name,
invalidNameList,
description,
endpointName,
maxLength = 50,
setName,
setDescription,
setEndpointName,
}: InputProps): JSX.Element => {
const [isMaxLength, setIsMaxLength] = useState(false);
const [isEndpointNameValid, setIsEndpointNameValid] = useState(true);
const handleNameChange = (event: ChangeEvent<HTMLInputElement>) => {
const { value } = event.target;
@ -29,6 +32,18 @@ export const EditFlowSettings: React.FC<InputProps> = ({
setDescription!(event.target.value);
};
const handleEndpointNameChange = (event: ChangeEvent<HTMLInputElement>) => {
// Validate the endpoint name
// use this regex r'^[a-zA-Z0-9_-]+$'
const isValid =
(/^[a-zA-Z0-9_-]+$/.test(event.target.value) &&
event.target.value.length <= maxLength) ||
// empty is also valid
event.target.value.length === 0;
setIsEndpointNameValid(isValid);
setEndpointName!(event.target.value);
};
//this function is necessary to select the text when double clicking, this was not working with the onFocus event
const handleFocus = (event) => event.target.select();
@ -91,6 +106,32 @@ export const EditFlowSettings: React.FC<InputProps> = ({
</span>
)}
</Label>
{setEndpointName && (
<Label>
<div className="edit-flow-arrangement mt-3">
<span className="font-medium">Endpoint name:</span>
{!isEndpointNameValid && (
<span className="edit-flow-span">
Invalid endpoint name. Use only letters, numbers, hyphens, and
underscores ({maxLength} characters max).
</span>
)}
</div>
<Input
className="nopan nodelete nodrag noundo nocopy mt-2 font-normal"
onChange={handleEndpointNameChange}
type="text"
name="endpoint_name"
value={endpointName ?? ""}
placeholder="An alternative name for the run endpoint"
maxLength={maxLength}
id="endpoint_name"
onDoubleClickCapture={(event) => {
handleFocus(event);
}}
/>
</Label>
)}
</>
);
};

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

@ -56,7 +56,7 @@ export default function Header(): JSX.Element {
const lastFlowVisitedIndex = routeHistory
.reverse()
.findIndex(
(path) => path.includes("/flow/") && path !== location.pathname,
(path) => path.includes("/flow/") && path !== location.pathname
);
const lastFlowVisited = routeHistory[lastFlowVisitedIndex];
@ -181,7 +181,7 @@ export default function Header(): JSX.Element {
/>
</div>
</AlertDropdown>
{!autoLogin && (
{autoLogin && (
<button
onClick={() => {
navigate("/account/api-keys");

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

@ -66,10 +66,8 @@ export default function InputFileComponent({
uploadFile(file, currentFlowId)
.then((res) => res.data)
.then((data) => {
console.log(CONSOLE_SUCCESS_MSG);
// Get the file name from the response
const { file_path } = data;
console.log("File name:", file_path);
// sets the value that goes to the backend
onFileChange(file_path);
@ -106,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

@ -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

@ -33,7 +33,7 @@ const SideBarFoldersButtonsComponent = ({
const [foldersNames, setFoldersNames] = useState({});
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
const [editFolders, setEditFolderName] = useState(
folders.map((obj) => ({ name: obj.name, edit: false })),
folders.map((obj) => ({ name: obj.name, edit: false }))
);
const uploadFolder = useFolderStore((state) => state.uploadFolder);
const currentFolder = pathname.split("/");
@ -58,7 +58,7 @@ const SideBarFoldersButtonsComponent = ({
const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop(
folderId,
handleFolderChange,
handleFolderChange
);
const handleUploadFlowsToFolder = () => {
@ -73,7 +73,7 @@ const SideBarFoldersButtonsComponent = ({
addFolder({ name: "New Folder", parent_id: null, description: "" }).then(
(res) => {
getFoldersApi(true);
},
}
);
}
@ -91,8 +91,6 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({ name: obj.name, edit: false }));
}, [folders]);
console.log(folderId, folderIdDragging);
return (
<>
<div className="flex shrink-0 items-center justify-between">
@ -120,7 +118,7 @@ const SideBarFoldersButtonsComponent = ({
<>
{folders.map((item, index) => {
const editFolderName = editFolders?.filter(
(folder) => folder.name === item.name,
(folder) => folder.name === item.name
)[0];
return (
<div
@ -136,7 +134,7 @@ const SideBarFoldersButtonsComponent = ({
? "border border-border bg-muted hover:bg-muted"
: "border hover:bg-transparent lg:border-transparent lg:hover:border-border",
"group flex w-full shrink-0 cursor-pointer gap-2 opacity-100 lg:min-w-full",
folderIdDragging === item.id! ? "bg-border" : "",
folderIdDragging === item.id! ? "bg-border" : ""
)}
onClick={() => handleChangeFolder!(item.id!)}
>
@ -206,7 +204,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({
name: obj.name,
edit: false,
})),
}))
);
}
if (e.key === "Enter") {
@ -239,10 +237,10 @@ const SideBarFoldersButtonsComponent = ({
};
const updatedFolder = await updateFolder(
body,
item.id!,
item.id!
);
const updateFolders = folders.filter(
(f) => f.name !== item.name,
(f) => f.name !== item.name
);
setFolders([...updateFolders, updatedFolder]);
setFoldersNames({});
@ -250,7 +248,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({
name: obj.name,
edit: false,
})),
}))
);
} else {
setFoldersNames((old) => ({

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

@ -61,7 +61,7 @@ export async function sendAll(data: sendAllProps) {
}
export async function postValidateCode(
code: string,
code: string
): Promise<AxiosResponse<errorsTypeAPI>> {
return await api.post(`${BASE_URL_API}validate/code`, { code });
}
@ -76,7 +76,7 @@ export async function postValidateCode(
export async function postValidatePrompt(
name: string,
template: string,
frontend_node: APIClassType,
frontend_node: APIClassType
): Promise<AxiosResponse<PromptTypeAPI>> {
return api.post(`${BASE_URL_API}validate/prompt`, {
name,
@ -149,7 +149,7 @@ export async function saveFlowToDatabase(newFlow: {
* @throws Will throw an error if the update fails.
*/
export async function updateFlowInDatabase(
updatedFlow: FlowType,
updatedFlow: FlowType
): Promise<FlowType> {
try {
const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, {
@ -157,6 +157,7 @@ export async function updateFlowInDatabase(
data: updatedFlow.data,
description: updatedFlow.description,
folder_id: updatedFlow.folder_id === "" ? null : updatedFlow.folder_id,
endpoint_name: updatedFlow.endpoint_name,
});
if (response?.status !== 200) {
@ -326,7 +327,7 @@ export async function getHealth() {
*
*/
export async function getBuildStatus(
flowId: string,
flowId: string
): Promise<AxiosResponse<BuildStatusTypeAPI>> {
return await api.get(`${BASE_URL_API}build/${flowId}/status`);
}
@ -339,7 +340,7 @@ export async function getBuildStatus(
*
*/
export async function postBuildInit(
flow: FlowType,
flow: FlowType
): Promise<AxiosResponse<InitTypeAPI>> {
return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow);
}
@ -355,7 +356,7 @@ export async function postBuildInit(
*/
export async function uploadFile(
file: File,
id: string,
id: string
): Promise<AxiosResponse<UploadFileTypeAPI>> {
const formData = new FormData();
formData.append("file", file);
@ -364,7 +365,7 @@ export async function uploadFile(
export async function postCustomComponent(
code: string,
apiClass: APIClassType,
apiClass: APIClassType
): Promise<AxiosResponse<APIClassType>> {
// let template = apiClass.template;
return await api.post(`${BASE_URL_API}custom_component`, {
@ -377,7 +378,7 @@ export async function postCustomComponentUpdate(
code: string,
template: APITemplateType,
field: string,
field_value: any,
field_value: any
): Promise<AxiosResponse<APIClassType>> {
return await api.post(`${BASE_URL_API}custom_component/update`, {
code,
@ -399,7 +400,7 @@ export async function onLogin(user: LoginType) {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
}
);
if (response.status === 200) {
@ -461,11 +462,11 @@ export async function addUser(user: UserInputType): Promise<Array<Users>> {
export async function getUsersPage(
skip: number,
limit: number,
limit: number
): Promise<Array<Users>> {
try {
const res = await api.get(
`${BASE_URL_API}users/?skip=${skip}&limit=${limit}`,
`${BASE_URL_API}users/?skip=${skip}&limit=${limit}`
);
if (res.status === 200) {
return res.data;
@ -502,7 +503,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) {
try {
const res = await api.patch(
`${BASE_URL_API}users/${user_id}/reset-password`,
user,
user
);
if (res.status === 200) {
return res.data;
@ -576,7 +577,7 @@ export async function saveFlowStore(
last_tested_version?: string;
},
tags: string[],
publicFlow = false,
publicFlow = false
): Promise<FlowType> {
try {
const response = await api.post(`${BASE_URL_API}store/components/`, {
@ -705,7 +706,7 @@ export async function postStoreComponents(component: Component) {
export async function getComponent(component_id: string) {
try {
const res = await api.get(
`${BASE_URL_API}store/components/${component_id}`,
`${BASE_URL_API}store/components/${component_id}`
);
if (res.status === 200) {
return res.data;
@ -720,7 +721,7 @@ export async function searchComponent(
page?: number | null,
limit?: number | null,
status?: string | null,
tags?: string[],
tags?: string[]
): Promise<StoreComponentResponse | undefined> {
try {
let url = `${BASE_URL_API}store/components/`;
@ -832,7 +833,7 @@ export async function updateFlowStore(
},
tags: string[],
publicFlow = false,
id: string,
id: string
): Promise<FlowType> {
try {
const response = await api.patch(`${BASE_URL_API}store/components/${id}`, {
@ -916,7 +917,7 @@ export async function deleteGlobalVariable(id: string) {
export async function updateGlobalVariable(
name: string,
value: string,
id: string,
id: string
) {
try {
const response = api.patch(`${BASE_URL_API}variables/${id}`, {
@ -935,7 +936,7 @@ export async function getVerticesOrder(
startNodeId?: string | null,
stopNodeId?: string | null,
nodes?: Node[],
Edges?: Edge[],
Edges?: Edge[]
): Promise<AxiosResponse<VerticesOrderTypeAPI>> {
// nodeId is optional and is a query parameter
// if nodeId is not provided, the API will return all vertices
@ -955,7 +956,7 @@ export async function getVerticesOrder(
return await api.post(
`${BASE_URL_API}build/${flowId}/vertices`,
data,
config,
config
);
}
@ -966,12 +967,15 @@ export async function postBuildVertex(
files?: string[]
): Promise<AxiosResponse<VertexBuildTypeAPI>> {
// input_value is optional and is a query parameter
const data = input_value ? { inputs: { input_value: input_value } } : undefined
const data = input_value
? { inputs: { input_value: input_value } }
: undefined;
if (data && files) {
data["files"] = files;
}
return await api.post(
`${BASE_URL_API}build/${flowId}/vertices/${vertexId}`, data
`${BASE_URL_API}build/${flowId}/vertices/${vertexId}`,
data
);
}
@ -995,7 +999,7 @@ export async function getFlowPool({
}
export async function deleteFlowPool(
flowId: string,
flowId: string
): Promise<AxiosResponse<any>> {
const config = {};
config["params"] = { flow_id: flowId };
@ -1003,7 +1007,7 @@ export async function deleteFlowPool(
}
export async function multipleDeleteFlowsComponents(
flowIds: string[],
flowIds: string[]
): Promise<AxiosResponse<any>> {
return await api.post(`${BASE_URL_API}flows/multiple_delete/`, {
flow_ids: flowIds,
@ -1013,7 +1017,7 @@ export async function multipleDeleteFlowsComponents(
export async function getTransactionTable(
id: string,
mode: "intersection" | "union",
params = {},
params = {}
): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> {
const config = {};
config["params"] = { flow_id: id };
@ -1028,7 +1032,7 @@ export async function getTransactionTable(
export async function getMessagesTable(
id: string,
mode: "intersection" | "union",
params = {},
params = {}
): Promise<{ rows: Array<object>; columns: Array<ColDef | ColGroupDef> }> {
const config = {};
config["params"] = { flow_id: id };

View file

@ -0,0 +1 @@
export const TEXT_FIELD_TYPES: string[] = ["str", "SecretStr"];

View file

@ -46,6 +46,7 @@ import useHandleNodeClass from "../../../hooks/use-handle-node-class";
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
import OutputModal from "../outputModal";
import TooltipRenderComponent from "../tooltipRenderComponent";
import { TEXT_FIELD_TYPES } from "./constants";
export default function ParameterComponent({
left,
@ -95,8 +96,7 @@ export default function ParameterComponent({
debouncedHandleUpdateValues,
setNode,
renderTooltips,
isLoading,
setIsLoading,
setIsLoading
);
const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass(
@ -105,7 +105,7 @@ export default function ParameterComponent({
takeSnapshot,
setNode,
updateNodeInternals,
renderTooltips,
renderTooltips
);
const { handleRefreshButtonPress: handleRefreshButtonPressHook } =
@ -114,7 +114,7 @@ export default function ParameterComponent({
let disabled =
edges.some(
(edge) =>
edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id),
edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id)
) ?? false;
const handleRefreshButtonPress = async (name, data) => {
@ -127,12 +127,12 @@ export default function ParameterComponent({
handleUpdateValues,
setNode,
renderTooltips,
setIsLoading,
setIsLoading
);
const handleOnNewValue = async (
newValue: string | string[] | boolean | Object[],
skipSnapshot: boolean | undefined = false,
skipSnapshot: boolean | undefined = false
): Promise<void> => {
handleOnNewValueHook(newValue, skipSnapshot);
};
@ -214,7 +214,7 @@ export default function ParameterComponent({
className={classNames(
left ? "my-12 -ml-0.5 " : " my-12 -mr-0.5 ",
"h-3 w-3 rounded-full border-2 bg-background",
!showNode ? "mt-0" : "",
!showNode ? "mt-0" : ""
)}
style={{
borderColor: color ?? nodeColors.unknown,
@ -245,7 +245,7 @@ export default function ParameterComponent({
(left ? "" : " justify-end")
}
>
<Case condition={left && data.node?.frozen}>
<Case condition={!left && data.node?.frozen}>
<div className="pr-1">
<IconComponent className="h-5 w-5 text-ice" name={"Snowflake"} />
</div>
@ -330,7 +330,7 @@ export default function ParameterComponent({
}
className={classNames(
left ? "-ml-0.5" : "-mr-0.5",
"h-3 w-3 rounded-full border-2 bg-background",
"h-3 w-3 rounded-full border-2 bg-background"
)}
style={{ borderColor: color ?? nodeColors.unknown }}
onClick={() => setFilterEdge(groupedEdge.current)}
@ -343,7 +343,7 @@ export default function ParameterComponent({
<Case
condition={
left === true &&
type === "str" &&
TEXT_FIELD_TYPES.includes(type ?? "") &&
!data.node?.template[name]?.options
}
>
@ -389,8 +389,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}
@ -438,8 +437,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}
@ -581,9 +579,7 @@ export default function ParameterComponent({
value={
!data.node!.template[name]?.value ||
data.node!.template[name]?.value?.toString() === "{}"
? {
// yourkey: "value",
}
? {}
: data.node!.template[name]?.value
}
onChange={handleOnNewValue}

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

@ -32,7 +32,6 @@ import useUpdateValidationStatus from "../hooks/use-update-validation-status";
import useValidationStatusString from "../hooks/use-validation-status-string";
import getFieldTitle from "../utils/get-field-title";
import sortFields from "../utils/sort-fields";
import OutputModal from "./components/outputModal";
import ParameterComponent from "./components/parameterComponent";
export default function GenericNode({
@ -55,10 +54,10 @@ export default function GenericNode({
const setErrorData = useAlertStore((state) => state.setErrorData);
const isDark = useDarkStore((state) => state.dark);
const buildStatus = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.status,
(state) => state.flowBuildStatus[data.id]?.status
);
const lastRunTime = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.timestamp,
(state) => state.flowBuildStatus[data.id]?.timestamp
);
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
@ -66,7 +65,7 @@ export default function GenericNode({
const [nodeName, setNodeName] = useState(data.node!.display_name);
const [inputDescription, setInputDescription] = useState(false);
const [nodeDescription, setNodeDescription] = useState(
data.node?.description!,
data.node?.description!
);
const [isOutdated, setIsOutdated] = useState(false);
const [validationStatus, setValidationStatus] =
@ -84,7 +83,7 @@ export default function GenericNode({
data.node!,
setNode,
setIsOutdated,
updateNodeInternals,
updateNodeInternals
);
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
@ -115,26 +114,30 @@ export default function GenericNode({
selected: boolean,
showNode: boolean,
buildStatus: BuildStatus | undefined,
validationStatus: VertexBuildTypeAPI | null,
validationStatus: VertexBuildTypeAPI | null
) => {
const specificClassFromBuildStatus = getSpecificClassFromBuildStatus(
buildStatus,
validationStatus,
isDark,
isDark
);
const baseBorderClass = getBaseBorderClass(selected);
const nodeSizeClass = getNodeSizeClass(showNode);
return classNames(
const names = classNames(
baseBorderClass,
nodeSizeClass,
"generic-node-div",
specificClassFromBuildStatus,
specificClassFromBuildStatus
);
return names;
};
const getBaseBorderClass = (selected) =>
selected ? "border border-ring" : "border";
const getBaseBorderClass = (selected) => {
let className = selected ? "border border-ring" : "border";
let frozenClass = selected ? "border-ring-frozen" : "border-frozen";
return data.node?.frozen ? frozenClass : className;
};
const getNodeSizeClass = (showNode) =>
showNode ? "w-96 rounded-lg" : "w-26 h-26 rounded-full";
@ -167,7 +170,7 @@ export default function GenericNode({
showNode,
isEmoji,
nodeIconFragment,
checkNodeIconFragment,
checkNodeIconFragment
);
function countHandles(): void {
@ -244,7 +247,7 @@ export default function GenericNode({
selected,
showNode,
buildStatus,
validationStatus,
validationStatus
)}
>
{data.node?.beta && showNode && (
@ -389,7 +392,7 @@ export default function GenericNode({
}
title={getFieldTitle(
data.node?.template!,
templateField,
templateField
)}
info={data.node?.template[templateField].info}
name={templateField}
@ -417,7 +420,7 @@ export default function GenericNode({
proxy={data.node?.template[templateField].proxy}
showNode={showNode}
/>
),
)
)}
<ParameterComponent
key={scapedJSONStringfy({
@ -563,7 +566,7 @@ export default function GenericNode({
!data.node?.description) &&
nameEditable
? "font-light italic"
: "",
: ""
)}
onDoubleClick={(e) => {
setInputDescription(true);
@ -625,13 +628,13 @@ export default function GenericNode({
}
title={getFieldTitle(
data.node?.template!,
templateField,
templateField
)}
info={data.node?.template[templateField].info}
name={templateField}
tooltipTitle={
data.node?.template[templateField].input_types?.join(
"\n",
"\n"
) ?? data.node?.template[templateField].type
}
required={data.node!.template[templateField].required}
@ -658,7 +661,7 @@ export default function GenericNode({
<div
className={classNames(
Object.keys(data.node!.template).length < 1 ? "hidden" : "",
"flex-max-width justify-center",
"flex-max-width justify-center"
)}
>
{" "}

View file

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

View file

@ -10,8 +10,7 @@ const useHandleOnNewValue = (
debouncedHandleUpdateValues,
setNode,
renderTooltips,
isLoading,
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

@ -84,7 +84,6 @@ export default function IOFileInput({ field, updateValue }: IOFileInputProps) {
uploadFile(file, currentFlowId)
.then((res) => res.data)
.then((data) => {
console.log("File uploaded successfully");
// Get the file name from the response
const { file_path, flowId } = data;
setFilePath(file_path);

View file

@ -4,23 +4,45 @@
* @param {boolean} isAuth - If the API is authenticated
* @returns {string} - The curl code
*/
export default function getCurlCode(
export function getCurlRunCode(
flowId: string,
isAuth: boolean,
tweaksBuildedObject,
endpointName?: string
): string {
const tweaksObject = tweaksBuildedObject[0];
// show the endpoint name in the curl command if it exists
return `curl -X POST \\
${window.location.protocol}//${
window.location.host
}/api/v1/run/${flowId}?stream=false \\
"${window.location.protocol}//${window.location.host}/api/v1/run/${
endpointName || flowId
}?stream=false" \\
-H 'Content-Type: application/json'\\${
!isAuth ? `\n -H 'x-api-key: <your api key>'\\` : ""
}
-d '{"input_value": "message",
"output_type": "chat",
"input_type": "chat",
"tweaks": ${JSON.stringify(tweaksObject, null, 2)}'
"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 { getCurlRunCode, getCurlWebhookCode } from "../utils/get-curl-code";
import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value";
import { getValue } from "../utils/get-value";
import getPythonApiCode from "../utils/get-python-api-code";
import getCurlCode from "../utils/get-curl-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(
(
@ -35,7 +35,7 @@ const ApiModal = forwardRef(
flow: FlowType;
children: ReactNode;
},
ref,
ref
) => {
const tweak = useTweaksStore((state) => state.tweak);
const addTweaks = useTweaksStore((state) => state.setTweak);
@ -47,18 +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(flow?.id, autoLogin, tweak);
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 &&
@ -88,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]);
@ -106,7 +121,7 @@ const ApiModal = forwardRef(
buildTweakObject(
nodeId,
element.data.node.template[templateField].value,
element.data.node.template[templateField],
element.data.node.template[templateField]
);
}
});
@ -123,7 +138,7 @@ const ApiModal = forwardRef(
async function buildTweakObject(
tw: string,
changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType,
template: TemplateVariableType
) {
changes = getChangesType(changes, template);
@ -161,7 +176,12 @@ const ApiModal = forwardRef(
const addCodes = (cloneTweak) => {
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, cloneTweak);
const curl_code = getCurlCode(flow?.id, autoLogin, cloneTweak);
const curl_code = getCurlRunCode(
flow?.id,
autoLogin,
cloneTweak,
flow?.endpoint_name
);
const pythonCode = getPythonCode(flow?.name, cloneTweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
@ -204,7 +224,7 @@ const ApiModal = forwardRef(
</BaseModal.Content>
</BaseModal>
);
},
}
);
export default ApiModal;

View file

@ -29,7 +29,7 @@ export default function DictAreaModal({
useEffect(() => {
if (value) ref.current = value;
}, [ref]);
}, [value]);
return (
<BaseModal size="medium-h-full" open={open} setOpen={setOpen}>

View file

@ -43,19 +43,23 @@ import BaseModal from "../baseModal";
const EditNodeModal = forwardRef(
(
{
data,
nodeLength,
open,
setOpen,
data,
}: {
data: NodeDataType;
nodeLength: number;
open: boolean;
setOpen: (open: boolean) => void;
data: NodeDataType;
},
ref,
ref
) => {
const [myData, setMyData] = useState(data);
const nodes = useFlowStore((state) => state.nodes);
const dataFromStore = nodes.find((node) => node.id === node.id)?.data;
const [myData, setMyData] = useState(dataFromStore ?? data);
const edges = useFlowStore((state) => state.edges);
const setNode = useFlowStore((state) => state.setNode);
@ -121,7 +125,7 @@ const EditNodeModal = forwardRef(
"edit-node-modal-box",
nodeLength > limitScrollFieldsModal
? "overflow-scroll overflow-x-hidden custom-scroll"
: "",
: ""
)}
>
{nodeLength > 0 && (
@ -143,8 +147,8 @@ const EditNodeModal = forwardRef(
templateParam.charAt(0) !== "_" &&
myData.node?.template[templateParam].show &&
LANGFLOW_SUPPORTED_TYPES.has(
myData.node!.template[templateParam].type,
),
myData.node!.template[templateParam].type
)
)
.map((templateParam, index) => {
let id = {
@ -166,8 +170,8 @@ const EditNodeModal = forwardRef(
myData.node?.template[templateParam]
.proxy,
}
: id,
),
: id
)
) ?? false;
return (
<TableRow
@ -229,7 +233,7 @@ const EditNodeModal = forwardRef(
onChange={(value: string[]) => {
handleOnNewValue(
value,
templateParam,
templateParam
);
}}
/>
@ -253,11 +257,11 @@ const EditNodeModal = forwardRef(
.value ?? ""
}
onChange={(
value: string | string[],
value: string | string[]
) => {
handleOnNewValue(
value,
templateParam,
templateParam
);
}}
/>
@ -297,9 +301,7 @@ const EditNodeModal = forwardRef(
myData.node!.template[
templateParam
]?.value?.toString() === "{}"
? {
// yourkey: "value",
}
? {}
: myData.node!.template[templateParam]
.value
}
@ -309,7 +311,7 @@ const EditNodeModal = forwardRef(
].value = newValue;
handleOnNewValue(
newValue,
templateParam,
templateParam
);
}}
id="editnode-div-dict-input"
@ -326,7 +328,7 @@ const EditNodeModal = forwardRef(
myData.node!.template[templateParam].value
?.length > 1
? "my-3"
: "",
: ""
)}
>
<KeypairListComponent
@ -342,7 +344,7 @@ const EditNodeModal = forwardRef(
myData.node!.template[
templateParam
].value,
type(templateParam)!,
type(templateParam)!
)
}
duplicateKey={errorDuplicateKey}
@ -353,11 +355,11 @@ const EditNodeModal = forwardRef(
templateParam
].value = valueToNumbers;
setErrorDuplicateKey(
hasDuplicateKeys(valueToNumbers),
hasDuplicateKeys(valueToNumbers)
);
handleOnNewValue(
valueToNumbers,
templateParam,
templateParam
);
}}
isList={
@ -387,7 +389,7 @@ const EditNodeModal = forwardRef(
setEnabled={(isEnabled) => {
handleOnNewValue(
isEnabled,
templateParam,
templateParam
);
}}
size="small"
@ -630,7 +632,7 @@ const EditNodeModal = forwardRef(
</BaseModal.Footer>
</BaseModal>
);
},
}
);
export default EditNodeModal;

View file

@ -1,19 +1,16 @@
import { ColDef, ColGroupDef } from "ag-grid-community";
import { AxiosError } from "axios";
import { useEffect, useRef, useState } from "react";
import IconComponent from "../../components/genericIconComponent";
import TableComponent from "../../components/tableComponent";
import { Tabs, TabsList, TabsTrigger } from "../../components/ui/tabs";
import { getMessagesTable, getTransactionTable } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { FlowSettingsPropsType } from "../../types/components";
import { FlowType, NodeDataType } from "../../types/flow";
import BaseModal from "../baseModal";
import TableComponent from "../../components/tableComponent";
import { getMessagesTable, getTransactionTable } from "../../controllers/API";
import {
ColDef,
ColGroupDef,
SizeColumnsToFitGridStrategy,
} from "ag-grid-community";
import useAlertStore from "../../stores/alertStore";
import useFlowStore from "../../stores/flowStore";
export default function FlowLogsModal({
open,
@ -41,8 +38,17 @@ export default function FlowLogsModal({
function handleClick(): void {
currentFlow!.name = name;
currentFlow!.description = description;
saveFlow(currentFlow!);
setOpen(false);
saveFlow(currentFlow!)
?.then(() => {
setOpen(false);
})
.catch((err) => {
useAlertStore.getState().setErrorData({
title: "Error while saving changes",
list: [(err as AxiosError).response?.data.detail ?? ""],
});
console.error(err);
});
}
useEffect(() => {
@ -66,7 +72,7 @@ export default function FlowLogsModal({
.some((template) => template["stream"] && template["stream"].value);
console.log(
haStream,
nodes.map((nodes) => (nodes.data as NodeDataType).node!.template),
nodes.map((nodes) => (nodes.data as NodeDataType).node!.template)
);
if (haStream) {
setNoticeData({

View file

@ -3,6 +3,7 @@ import EditFlowSettings from "../../components/editFlowSettingsComponent";
import IconComponent from "../../components/genericIconComponent";
import { Button } from "../../components/ui/button";
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants/constants";
import useAlertStore from "../../stores/alertStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { FlowSettingsPropsType } from "../../types/components";
import { FlowType } from "../../types/flow";
@ -22,12 +23,23 @@ export default function FlowSettingsModal({
const [name, setName] = useState(currentFlow!.name);
const [description, setDescription] = useState(currentFlow!.description);
const [endpoint_name, setEndpointName] = useState(currentFlow!.endpoint_name);
function handleClick(): void {
currentFlow!.name = name;
currentFlow!.description = description;
saveFlow(currentFlow!);
setOpen(false);
currentFlow!.endpoint_name = endpoint_name;
saveFlow(currentFlow!)
?.then(() => {
setOpen(false);
})
.catch((err) => {
useAlertStore.getState().setErrorData({
title: "Error while saving changes",
list: [(err as AxiosError).response?.data.detail ?? ""],
});
console.error(err);
});
}
const [nameLists, setNameList] = useState<string[]>([]);
@ -41,7 +53,7 @@ export default function FlowSettingsModal({
}, [flows]);
return (
<BaseModal open={open} setOpen={setOpen} size="smaller">
<BaseModal open={open} setOpen={setOpen} size="smaller-h-full">
<BaseModal.Header description={SETTINGS_DIALOG_SUBTITLE}>
<span className="pr-2">Settings</span>
<IconComponent name="Settings2" className="mr-2 h-4 w-4 " />
@ -51,8 +63,10 @@ export default function FlowSettingsModal({
invalidNameList={nameLists}
name={name}
description={description}
endpointName={endpoint_name}
setName={setName}
setDescription={setDescription}
setEndpointName={setEndpointName}
/>
</BaseModal.Content>

View file

@ -83,7 +83,7 @@ export default function GenericModal({
}
const filteredWordsHighlight = matches.filter(
(word) => !invalid_chars.includes(word),
(word) => !invalid_chars.includes(word)
);
setWordsHighlight(filteredWordsHighlight);
@ -134,7 +134,7 @@ export default function GenericModal({
// to the first key of the custom_fields object
if (field_name === "") {
field_name = Array.isArray(
apiReturn.data?.frontend_node?.custom_fields?.[""],
apiReturn.data?.frontend_node?.custom_fields?.[""]
)
? apiReturn.data?.frontend_node?.custom_fields?.[""][0] ?? ""
: apiReturn.data?.frontend_node?.custom_fields?.[""] ?? "";
@ -166,7 +166,6 @@ export default function GenericModal({
}
})
.catch((error) => {
console.log(error);
setIsEdit(true);
return setErrorData({
title: PROMPT_ERROR_ALERT,
@ -210,7 +209,7 @@ export default function GenericModal({
<div
className={classNames(
!isEdit ? "rounded-lg border" : "",
"flex h-full w-full",
"flex h-full w-full"
)}
>
{type === TypeModal.PROMPT && isEdit && !readonly ? (

View file

@ -147,6 +147,7 @@ export default function SecretKeyModal({
{renderKey === false && (
<div className="float-right">
<Button
type="button"
className="mr-3"
variant="outline"
onClick={() => {

View file

@ -283,7 +283,7 @@ export default function ExtraSidebar(): JSX.Element {
<div className="side-bar-components-div-arrangement">
<div className="parent-disclosure-arrangement">
<div className="flex items-center gap-4 align-middle">
<span className="parent-disclosure-title">Core Components</span>
<span className="parent-disclosure-title">Basic Components</span>
</div>
</div>
{Object.keys(dataFilter)
@ -360,9 +360,9 @@ export default function ExtraSidebar(): JSX.Element {
)}{" "}
<ParentDisclosureComponent
openDisc={false}
key={"Extended"}
key={"Advanced"}
button={{
title: "Extended",
title: "Advanced",
Icon: nodeIconsLucide.unknown,
}}
testId="extended-disclosure"

View file

@ -29,7 +29,7 @@ import {
expandGroupNode,
updateFlowPosition,
} from "../../../../utils/reactflowUtils";
import { classNames } from "../../../../utils/utils";
import { classNames, cn } from "../../../../utils/utils";
import ToolbarSelectItem from "./toolbarSelectItem";
export default function NodeToolbarComponent({
@ -68,7 +68,7 @@ export default function NodeToolbarComponent({
const isMinimal = numberOfHandles <= 1;
const isGroup = data.node?.flow ? true : false;
// const frozen = data.node?.frozen ?? false;
const frozen = data.node?.frozen ?? false;
const paste = useFlowStore((state) => state.paste);
const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges);
@ -430,7 +430,7 @@ export default function NodeToolbarComponent({
</button>
</ShadTooltip>
{/* <ShadTooltip content="Freeze" side="top">
<ShadTooltip content="Freeze" side="top">
<button
className={classNames(
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
@ -443,7 +443,7 @@ export default function NodeToolbarComponent({
...old.data,
node: {
...old.data.node,
// frozen: old.data?.node?.frozen ? false : true,
frozen: old.data?.node?.frozen ? false : true,
},
},
}));
@ -458,7 +458,7 @@ export default function NodeToolbarComponent({
)}
/>
</button>
</ShadTooltip> */}
</ShadTooltip>
<Select onValueChange={handleSelectChange} value="">
<ShadTooltip content="More" side="top">

View file

@ -11,7 +11,7 @@ export default function PlaygroundPage() {
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const getFlowById = useFlowsManagerStore((state) => state.getFlowById);
const setCurrentFlowId = useFlowsManagerStore(
(state) => state.setCurrentFlowId,
(state) => state.setCurrentFlowId
);
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
@ -29,7 +29,6 @@ export default function PlaygroundPage() {
// Set flow tab id
useEffect(() => {
console.log("id", id);
if (getFlowById(id!)) {
setCurrentFlowId(id!);
} else {

View file

@ -466,7 +466,6 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
status: BuildStatus,
runId: string,
) {
console.log("handleBuildUpdate", vertexBuildData, status, runId);
if (vertexBuildData && vertexBuildData.inactivated_vertices) {
get().removeFromVerticesBuild(vertexBuildData.inactivated_vertices);
get().updateBuildStatus(

View file

@ -1,4 +1,3 @@
import { AxiosError } from "axios";
import { cloneDeep, debounce } from "lodash";
import { Edge, Node, Viewport, XYPosition } from "reactflow";
import { create } from "zustand";
@ -87,12 +86,12 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
if (dbData) {
const { data, flows } = processFlows(dbData, false);
const examples = flows.filter(
(flow) => flow.folder_id === starterFolderId,
(flow) => flow.folder_id === starterFolderId
);
get().setExamples(examples);
const flowsWithoutStarterFolder = flows.filter(
(flow) => flow.folder_id !== starterFolderId,
(flow) => flow.folder_id !== starterFolderId
);
get().setFlows(flowsWithoutStarterFolder);
@ -120,7 +119,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
if (get().currentFlow) {
get().saveFlow(
{ ...get().currentFlow!, data: { nodes, edges, viewport } },
true,
true
);
}
},
@ -146,7 +145,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
return updatedFlow;
}
return flow;
}),
})
);
//update tabs state
@ -155,11 +154,9 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
}
})
.catch((err) => {
useAlertStore.getState().setErrorData({
title: "Error while saving changes",
list: [(err as AxiosError).message],
});
reject(err);
set({ saveLoading: false });
throw err;
});
});
}, SAVE_DEBOUNCE_TIME),
@ -197,7 +194,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
flow?: FlowType,
override?: boolean,
position?: XYPosition,
fromDragAndDrop?: boolean,
fromDragAndDrop?: boolean
): Promise<string | undefined> => {
if (newProject) {
let flowData = flow
@ -213,7 +210,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
const newFlow = createNewFlow(
flowData!,
flow!,
folder_id || my_collection_id!,
folder_id || my_collection_id!
);
const { id } = await saveFlowToDatabase(newFlow);
newFlow.id = id;
@ -233,11 +230,10 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
// addFlowToLocalState(newFlow);
return;
}
console.log("folder id", folder_id);
const newFlow = createNewFlow(
flowData!,
flow!,
folder_id || my_collection_id!,
folder_id || my_collection_id!
);
const newName = addVersionToDuplicates(newFlow, get().flows);
@ -273,7 +269,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
.getState()
.paste(
{ nodes: flow!.data!.nodes, edges: flow!.data!.edges },
position ?? { x: 10, y: 10 },
position ?? { x: 10, y: 10 }
);
}
},
@ -283,7 +279,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
multipleDeleteFlowsComponents(id)
.then(() => {
const { data, flows } = processFlows(
get().flows.filter((flow) => !id.includes(flow.id)),
get().flows.filter((flow) => !id.includes(flow.id))
);
get().setFlows(flows);
set({ isLoading: false });
@ -303,7 +299,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
deleteFlowFromDatabase(id)
.then(() => {
const { data, flows } = processFlows(
get().flows.filter((flow) => flow.id !== id),
get().flows.filter((flow) => flow.id !== id)
);
get().setFlows(flows);
set({ isLoading: false });
@ -325,7 +321,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
return new Promise<void>((resolve) => {
let componentFlow = get().flows.find(
(componentFlow) =>
componentFlow.is_component && componentFlow.name === key,
componentFlow.is_component && componentFlow.name === key
);
if (componentFlow) {
@ -373,7 +369,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
fileData,
undefined,
position,
true,
true
);
resolve(id);
}
@ -414,7 +410,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
return get().addFlow(
true,
createFlowComponent(component, useDarkStore.getState().version),
override,
override
);
},
takeSnapshot: () => {
@ -435,7 +431,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
if (pastLength > 0) {
past[currentFlowId] = past[currentFlowId].slice(
pastLength - defaultOptions.maxHistorySize + 1,
pastLength,
pastLength
);
past[currentFlowId].push(newState);

View file

@ -9,9 +9,7 @@
body {
@apply bg-background text-foreground;
font-feature-settings:
"rlig" 1,
"calt" 1;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
@ -115,6 +113,57 @@
.button-disable {
@apply pointer-events-none;
}
/* Frozen state border */
.border-ring-frozen {
position: relative;
@apply rounded-md border shadow-frozen-ring;
}
.border-ring-frozen::before {
content: "";
position: absolute;
top: -2px; /* Adjust based on desired border width */
bottom: -2px;
left: -2px;
right: -2px;
/* use the frozen-blue color from tailwind */
border-radius: inherit;
pointer-events: none;
@apply border-2 border-frozen-blue;
}
.border-frozen {
@apply border shadow-frozen-ring;
}
.frosted {
@apply rounded-md bg-frozen-blue backdrop-blur-xs;
}
.frozen {
position: relative;
overflow: hidden;
}
.frozen::before,
.frozen::after {
content: "";
position: absolute;
top: -10px;
bottom: -10px;
left: -10px;
right: -10px;
background: rgba(
255,
255,
255,
0.5
); /* Reduced opacity for better readability */
border-radius: 10px;
pointer-events: none;
}
.frozen::before {
filter: blur(5px); /* Less blur for better readability */
}
.frozen::after {
filter: blur(10px); /* Less blur for better readability */
opacity: 0.2; /* Reduced opacity */
}
.extra-side-bar-buttons {
@apply relative inline-flex w-full items-center justify-center rounded-md bg-background px-2 py-2 text-foreground transition-all duration-500 ease-in-out;
}

View file

@ -287,9 +287,11 @@ export type IconComponentProps = {
export type InputProps = {
name: string | null;
description: string | null;
endpointName?: string;
maxLength?: number;
setName?: (name: string) => void;
setDescription?: (description: string) => void;
setEndpointName?: (endpointName: string) => void;
invalidNameList?: string[];
};
@ -541,7 +543,7 @@ export type nodeToolbarPropsType = {
updateNodeCode?: (
newNodeClass: APIClassType,
code: string,
name: string,
name: string
) => void;
setShowState: (show: boolean | SetStateAction<boolean>) => void;
isOutdated?: boolean;
@ -591,7 +593,7 @@ export type chatMessagePropsType = {
updateChat: (
chat: ChatMessageType,
message: string,
stream_url?: string,
stream_url?: string
) => void;
};
@ -683,12 +685,12 @@ export type codeTabsPropsType = {
value: string,
node: NodeType,
template: TemplateVariableType,
tweak: tweakType,
tweak: tweakType
) => string;
buildTweakObject?: (
tw: string,
changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType,
template: TemplateVariableType
) => Promise<string | void>;
};
activeTweaks?: boolean;

View file

@ -7,6 +7,7 @@ export type FlowType = {
id: string;
data: ReactFlowJsonObject | null;
description: string;
endpoint_name?: string;
style?: FlowStyleType;
is_component?: boolean;
last_tested_version?: string;
@ -18,6 +19,7 @@ export type FlowType = {
icon?: string;
icon_bg_color?: string;
folder_id?: string;
webhook?: boolean;
};
export type NodeType = {

View file

@ -55,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
@ -64,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());
@ -77,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());
@ -181,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);
@ -216,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<{
@ -242,7 +242,7 @@ export function groupByFamily(
baseClassesSet.has(template.type)) ||
(template.input_types &&
template.input_types.some((inputType) =>
baseClassesSet.has(inputType),
baseClassesSet.has(inputType)
)))
);
};
@ -262,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,
});
@ -279,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,
};
@ -351,7 +351,7 @@ export function isTimeStampString(str: string): boolean {
export function extractColumnsFromRows(
rows: object[],
mode: "intersection" | "union" | "all",
mode: "intersection" | "union" | "all"
): (ColDef<any> | ColGroupDef<any>)[] {
const columnsKeys: { [key: string]: ColDef<any> | ColGroupDef<any> } = {};
if (rows.length === 0) {

View file

@ -44,6 +44,8 @@ module.exports = {
"slow-wiggle": "wiggle 500ms ease-in-out 1",
},
colors: {
"frozen-blue": "rgba(128, 190, 219, 0.86)", // Custom blue color for the frozen effect
"frosted-glass": "rgba(255, 255, 255, 0.8)", // Custom frosted glass effect
"component-icon": "var(--component-icon)",
"flow-icon": "var(--flow-icon)",
"low-indigo": "var(--low-indigo)",
@ -139,6 +141,13 @@ module.exports = {
fontFamily: {
sans: ["var(--font-sans)", ...fontFamily.sans],
},
boxShadow: {
"frozen-ring": "0 0 10px 2px rgba(128, 190, 230, 0.5)",
"frosted-ring": "0 0 10px 2px rgba(128, 190, 230, 0.7)",
},
backdropBlur: {
xs: "2px",
},
},
},