Merge remote-tracking branch 'origin/dev' into fix/minor_bugs
This commit is contained in:
commit
81f61201be
435 changed files with 9714 additions and 13063 deletions
710
src/frontend/harFiles/example.har
Normal file
710
src/frontend/harFiles/example.har
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,3 +1,4 @@
|
|||
import axios from "axios";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
|
@ -15,6 +16,7 @@ import {
|
|||
} from "./constants/constants";
|
||||
import { AuthContext } from "./contexts/authContext";
|
||||
import { autoLogin, getGlobalVariables, getHealth } from "./controllers/API";
|
||||
import { setupAxiosDefaults } from "./controllers/API/utils";
|
||||
import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path";
|
||||
import Router from "./routes";
|
||||
import useAlertStore from "./stores/alertStore";
|
||||
|
|
@ -114,6 +116,7 @@ export default function App() {
|
|||
return new Promise<void>(async (resolve, reject) => {
|
||||
if (isAuthenticated) {
|
||||
try {
|
||||
await setupAxiosDefaults();
|
||||
await getFoldersApi();
|
||||
await getTypes();
|
||||
await refreshFlows();
|
||||
|
|
|
|||
|
|
@ -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 }) {
|
||||
|
|
|
|||
|
|
@ -841,9 +841,7 @@ export default function CodeTabsComponent({
|
|||
node.data.node!.template[
|
||||
templateField
|
||||
].value?.toString() === "{}"
|
||||
? {
|
||||
// yourkey: "value",
|
||||
}
|
||||
? {}
|
||||
: node.data.node!
|
||||
.template[
|
||||
templateField
|
||||
|
|
|
|||
|
|
@ -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,15 +22,14 @@ 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(
|
||||
value.length > 1 && editNode ? "my-1" : "",
|
||||
"flex flex-col gap-3"
|
||||
"flex flex-col gap-3",
|
||||
)}
|
||||
>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
@ -84,13 +99,39 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
|||
<span
|
||||
className={cn(
|
||||
"font-normal text-muted-foreground word-break-break-word",
|
||||
description === "" ? "font-light italic" : ""
|
||||
description === "" ? "font-light italic" : "",
|
||||
)}
|
||||
>
|
||||
{description === "" ? "No description" : description}
|
||||
</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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ export default function Header(): JSX.Element {
|
|||
/>
|
||||
</div>
|
||||
</AlertDropdown>
|
||||
{!autoLogin && (
|
||||
{autoLogin && (
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate("/account/api-keys");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
@ -55,4 +55,4 @@ const AlertDescription = React.forwardRef<
|
|||
));
|
||||
AlertDescription.displayName = "AlertDescription";
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription };
|
||||
export { Alert, AlertDescription, AlertTitle };
|
||||
|
|
|
|||
|
|
@ -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 <body> 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 <body> 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.";
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
32
src/frontend/src/controllers/API/utils.tsx
Normal file
32
src/frontend/src/controllers/API/utils.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import axios from "axios";
|
||||
import { BASE_URL_API } from "../../constants/constants";
|
||||
|
||||
/**
|
||||
* Fetches the configuration data from the API.
|
||||
* @returns {Promise<any>} A promise that resolves to the configuration data.
|
||||
* @throws {Error} If there was an error fetching the configuration data.
|
||||
*/
|
||||
export async function fetchConfig() {
|
||||
try {
|
||||
const response = await axios.get(`${BASE_URL_API}config`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch configuration:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up default configurations for Axios.
|
||||
* Fetches the timeout configuration and sets it as the default timeout for Axios requests.
|
||||
*/
|
||||
export async function setupAxiosDefaults() {
|
||||
const config = await fetchConfig();
|
||||
// Create Axios instance with the fetched timeout configuration
|
||||
|
||||
const timeoutInMilliseconds = config.frontend_timeout
|
||||
? config.frontend_timeout * 1000
|
||||
: 30000;
|
||||
axios.defaults.baseURL = "";
|
||||
axios.defaults.timeout = timeoutInMilliseconds;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export const TEXT_FIELD_TYPES: string[] = ["str", "SecretStr"];
|
||||
|
|
@ -46,6 +46,7 @@ import useHandleOnNewValue from "../../../hooks/use-handle-new-value";
|
|||
import useHandleNodeClass from "../../../hooks/use-handle-node-class";
|
||||
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
|
||||
import TooltipRenderComponent from "../tooltipRenderComponent";
|
||||
import { TEXT_FIELD_TYPES } from "./constants";
|
||||
|
||||
export default function ParameterComponent({
|
||||
left,
|
||||
|
|
@ -88,7 +89,6 @@ export default function ParameterComponent({
|
|||
debouncedHandleUpdateValues,
|
||||
setNode,
|
||||
renderTooltips,
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
);
|
||||
|
||||
|
|
@ -238,7 +238,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>
|
||||
|
|
@ -309,7 +309,7 @@ export default function ParameterComponent({
|
|||
<Case
|
||||
condition={
|
||||
left === true &&
|
||||
type === "str" &&
|
||||
TEXT_FIELD_TYPES.includes(type ?? "") &&
|
||||
!data.node?.template[name]?.options
|
||||
}
|
||||
>
|
||||
|
|
@ -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}
|
||||
|
|
@ -547,9 +545,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}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import Loading from "../../components/ui/loading";
|
|||
import { Textarea } from "../../components/ui/textarea";
|
||||
import Xmark from "../../components/ui/xmark";
|
||||
import {
|
||||
NATIVE_CATEGORIES,
|
||||
RUN_TIMESTAMP_PREFIX,
|
||||
STATUS_BUILD,
|
||||
STATUS_BUILDING,
|
||||
|
|
@ -28,9 +27,9 @@ import { NodeDataType } from "../../types/flow";
|
|||
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||
import { classNames, cn } from "../../utils/utils";
|
||||
import ParameterComponent from "./components/parameterComponent";
|
||||
import getFieldTitle from "../utils/get-field-title";
|
||||
import sortFields from "../utils/sort-fields";
|
||||
import ParameterComponent from "./components/parameterComponent";
|
||||
|
||||
export default function GenericNode({
|
||||
data,
|
||||
|
|
@ -77,18 +76,14 @@ export default function GenericNode({
|
|||
// This one should run only once
|
||||
// first check if data.type in NATIVE_CATEGORIES
|
||||
// if not return
|
||||
if (
|
||||
!NATIVE_CATEGORIES.includes(types[data.type]) ||
|
||||
!data.node?.template?.code?.value
|
||||
)
|
||||
return;
|
||||
if (!data.node?.template?.code?.value) return;
|
||||
const thisNodeTemplate = templates[data.type].template;
|
||||
// if the template does not have a code key
|
||||
// return
|
||||
if (!thisNodeTemplate.code) return;
|
||||
const currentCode = thisNodeTemplate.code?.value;
|
||||
const thisNodesCode = data.node!.template?.code?.value;
|
||||
const componentsToIgnore = ["Custom Component", "Prompt"];
|
||||
const componentsToIgnore = ["Custom Component"];
|
||||
if (
|
||||
currentCode !== thisNodesCode &&
|
||||
!componentsToIgnore.includes(data.node!.display_name)
|
||||
|
|
@ -334,16 +329,20 @@ export default function GenericNode({
|
|||
|
||||
const baseBorderClass = getBaseBorderClass(selected);
|
||||
const nodeSizeClass = getNodeSizeClass(showNode);
|
||||
return classNames(
|
||||
const names = classNames(
|
||||
baseBorderClass,
|
||||
nodeSizeClass,
|
||||
"generic-node-div",
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ const useHandleOnNewValue = (
|
|||
debouncedHandleUpdateValues,
|
||||
setNode,
|
||||
renderTooltips,
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
) => {
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"}'
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,47 +12,47 @@ export default function getPythonApiCode(
|
|||
): string {
|
||||
const tweaksObject = tweaksBuildedObject[0];
|
||||
return `import requests
|
||||
from typing import Optional
|
||||
from typing import Optional
|
||||
|
||||
BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run"
|
||||
FLOW_ID = "${flowId}"
|
||||
# You can tweak the flow by adding a tweaks dictionary
|
||||
# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}}
|
||||
TWEAKS = ${JSON.stringify(tweaksObject, null, 2)}
|
||||
BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run"
|
||||
FLOW_ID = "${flowId}"
|
||||
# You can tweak the flow by adding a tweaks dictionary
|
||||
# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}}
|
||||
TWEAKS = ${JSON.stringify(tweaksObject, null, 2)}
|
||||
|
||||
def run_flow(message: str,
|
||||
flow_id: str,
|
||||
output_type: str = "chat",
|
||||
input_type: str = "chat",
|
||||
tweaks: Optional[dict] = None,
|
||||
api_key: Optional[str] = None) -> dict:
|
||||
"""
|
||||
Run a flow with a given message and optional tweaks.
|
||||
def run_flow(message: str,
|
||||
flow_id: str,
|
||||
output_type: str = "chat",
|
||||
input_type: str = "chat",
|
||||
tweaks: Optional[dict] = None,
|
||||
api_key: Optional[str] = None) -> dict:
|
||||
"""
|
||||
Run a flow with a given message and optional tweaks.
|
||||
|
||||
:param message: The message to send to the flow
|
||||
:param flow_id: The ID of the flow to run
|
||||
:param tweaks: Optional tweaks to customize the flow
|
||||
:return: The JSON response from the flow
|
||||
"""
|
||||
api_url = f"{BASE_API_URL}/{flow_id}"
|
||||
:param message: The message to send to the flow
|
||||
:param flow_id: The ID of the flow to run
|
||||
:param tweaks: Optional tweaks to customize the flow
|
||||
:return: The JSON response from the flow
|
||||
"""
|
||||
api_url = f"{BASE_API_URL}/{flow_id}"
|
||||
|
||||
payload = {
|
||||
"input_value": message,
|
||||
"output_type": output_type,
|
||||
"input_type": input_type,
|
||||
}
|
||||
headers = None
|
||||
if tweaks:
|
||||
payload["tweaks"] = tweaks
|
||||
if api_key:
|
||||
headers = {"x-api-key": api_key}
|
||||
response = requests.post(api_url, json=payload, headers=headers)
|
||||
return response.json()
|
||||
payload = {
|
||||
"input_value": message,
|
||||
"output_type": output_type,
|
||||
"input_type": input_type,
|
||||
}
|
||||
headers = None
|
||||
if tweaks:
|
||||
payload["tweaks"] = tweaks
|
||||
if api_key:
|
||||
headers = {"x-api-key": api_key}
|
||||
response = requests.post(api_url, json=payload, headers=headers)
|
||||
return response.json()
|
||||
|
||||
# Setup any tweaks you want to apply to the flow
|
||||
message = "message"
|
||||
${!isAuth ? `api_key = "<your api key>"` : ""}
|
||||
print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${
|
||||
# Setup any tweaks you want to apply to the flow
|
||||
message = "message"
|
||||
${!isAuth ? `api_key = "<your api key>"` : ""}
|
||||
print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${
|
||||
!isAuth ? `, api_key=api_key` : ""
|
||||
}))`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ export default function getPythonCode(
|
|||
const tweaksObject = tweaksBuildedObject[0];
|
||||
|
||||
return `from langflow.load import run_flow_from_json
|
||||
TWEAKS = ${JSON.stringify(tweaksObject, null, 2)}
|
||||
TWEAKS = ${JSON.stringify(tweaksObject, null, 2)}
|
||||
|
||||
result = run_flow_from_json(flow="${flowName}.json",
|
||||
input_value="message",
|
||||
fallback_to_env_vars=True, # False by default
|
||||
tweaks=TWEAKS)`;
|
||||
result = run_flow_from_json(flow="${flowName}.json",
|
||||
input_value="message",
|
||||
fallback_to_env_vars=True, # False by default
|
||||
tweaks=TWEAKS)`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <body> 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 <body> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
(
|
||||
|
|
@ -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]);
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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}>
|
||||
|
|
|
|||
|
|
@ -42,19 +42,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,
|
||||
) => {
|
||||
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);
|
||||
|
|
@ -306,9 +310,7 @@ const EditNodeModal = forwardRef(
|
|||
myData.node!.template[
|
||||
templateParam
|
||||
]?.value?.toString() === "{}"
|
||||
? {
|
||||
// yourkey: "value",
|
||||
}
|
||||
? {}
|
||||
: myData.node!.template[templateParam]
|
||||
.value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(() => {
|
||||
|
|
|
|||
|
|
@ -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[]>([]);
|
||||
|
|
@ -44,7 +56,7 @@ export default function FlowSettingsModal({
|
|||
<BaseModal
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
size="smaller"
|
||||
size="smaller-h-full"
|
||||
onSubmit={handleClick}
|
||||
>
|
||||
<BaseModal.Header description={SETTINGS_DIALOG_SUBTITLE}>
|
||||
|
|
@ -56,8 +68,10 @@ export default function FlowSettingsModal({
|
|||
invalidNameList={nameLists}
|
||||
name={name}
|
||||
description={description}
|
||||
endpointName={endpoint_name}
|
||||
setName={setName}
|
||||
setDescription={setDescription}
|
||||
setEndpointName={setEndpointName}
|
||||
/>
|
||||
</BaseModal.Content>
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,6 @@ export default function GenericModal({
|
|||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setIsEdit(true);
|
||||
return setErrorData({
|
||||
title: PROMPT_ERROR_ALERT,
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ export default function SecretKeyModal({
|
|||
{renderKey === false && (
|
||||
<div className="float-right">
|
||||
<Button
|
||||
type="button"
|
||||
className="mr-3"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
|
|
|
|||
|
|
@ -284,7 +284,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)
|
||||
|
|
@ -361,9 +361,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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -271,7 +271,7 @@ export default function NodeToolbarComponent({
|
|||
selected &&
|
||||
(hasApiKey || hasStore) &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "u"
|
||||
event.key.toUpperCase() === "U"
|
||||
) {
|
||||
event.preventDefault();
|
||||
handleSelectChange("update");
|
||||
|
|
@ -280,7 +280,7 @@ export default function NodeToolbarComponent({
|
|||
selected &&
|
||||
isGroup &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "g"
|
||||
event.key.toUpperCase() === "G"
|
||||
) {
|
||||
event.preventDefault();
|
||||
handleSelectChange("ungroup");
|
||||
|
|
@ -290,7 +290,7 @@ export default function NodeToolbarComponent({
|
|||
(hasApiKey || hasStore) &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "S"
|
||||
event.key.toUpperCase() === "S"
|
||||
) {
|
||||
event.preventDefault();
|
||||
setShowconfirmShare((state) => !state);
|
||||
|
|
@ -300,7 +300,7 @@ export default function NodeToolbarComponent({
|
|||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "Q"
|
||||
event.key.toUpperCase() === "Q"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (isMinimal) {
|
||||
|
|
@ -317,7 +317,7 @@ export default function NodeToolbarComponent({
|
|||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "U"
|
||||
event.key.toUpperCase() === "U"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (hasCode) return setOpenModal((state) => !state);
|
||||
|
|
@ -327,12 +327,16 @@ export default function NodeToolbarComponent({
|
|||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "A"
|
||||
event.key.toUpperCase() === "A"
|
||||
) {
|
||||
event.preventDefault();
|
||||
setShowModalAdvanced((state) => !state);
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "s") {
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key.toUpperCase() === "S"
|
||||
) {
|
||||
if (isSaved) {
|
||||
event.preventDefault();
|
||||
return setShowOverrideModal((state) => !state);
|
||||
|
|
@ -347,7 +351,7 @@ export default function NodeToolbarComponent({
|
|||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "D"
|
||||
event.key.toUpperCase() === "D"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (data.node?.documentation) {
|
||||
|
|
@ -357,7 +361,11 @@ export default function NodeToolbarComponent({
|
|||
title: `${data.id} docs is not available at the moment.`,
|
||||
});
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "j") {
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key.toUpperCase() === "J"
|
||||
) {
|
||||
event.preventDefault();
|
||||
downloadNode(flowComponent!);
|
||||
}
|
||||
|
|
@ -422,10 +430,10 @@ 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"
|
||||
"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",
|
||||
)}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
|
@ -435,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,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
@ -446,11 +454,11 @@ export default function NodeToolbarComponent({
|
|||
className={cn(
|
||||
"h-4 w-4 transition-all",
|
||||
// TODO UPDATE THIS COLOR TO BE A VARIABLE
|
||||
frozen ? "animate-wiggle text-ice" : ""
|
||||
frozen ? "animate-wiggle text-ice" : "",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
</ShadTooltip> */}
|
||||
</ShadTooltip>
|
||||
|
||||
<Select onValueChange={handleSelectChange} value="">
|
||||
<ShadTooltip content="More" side="top">
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ export default function PlaygroundPage() {
|
|||
|
||||
// Set flow tab id
|
||||
useEffect(() => {
|
||||
console.log("id", id);
|
||||
if (getFlowById(id!)) {
|
||||
setCurrentFlowId(id!);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -464,7 +464,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(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { AxiosError } from "axios";
|
||||
import { cloneDeep, debounce } from "lodash";
|
||||
import { Edge, Node, Viewport, XYPosition } from "reactflow";
|
||||
import { create } from "zustand";
|
||||
|
|
@ -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),
|
||||
|
|
@ -233,7 +230,6 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
|
|||
// addFlowToLocalState(newFlow);
|
||||
return;
|
||||
}
|
||||
console.log("folder id", folder_id);
|
||||
const newFlow = createNewFlow(
|
||||
flowData!,
|
||||
flow!,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,9 +269,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[];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue