merge fix

This commit is contained in:
cristhianzl 2024-03-13 11:12:42 -03:00
commit 34f5a1300a
73 changed files with 2165 additions and 1531 deletions

View file

@ -102,35 +102,46 @@ export default function App() {
)}
</ErrorBoundary>
<div></div>
<div className="app-div z-40">
{tempNotificationList.map((alert) => (
<div key={alert.id}>
{alert.type === "error" ? (
<ErrorAlert
key={alert.id}
title={alert.title}
list={alert.list}
id={alert.id}
removeAlert={removeAlert}
/>
) : alert.type === "notice" ? (
<NoticeAlert
key={alert.id}
title={alert.title}
link={alert.link}
id={alert.id}
removeAlert={removeAlert}
/>
) : (
<SuccessAlert
key={alert.id}
title={alert.title}
id={alert.id}
removeAlert={removeAlert}
/>
)}
</div>
))}
<div className="app-div">
<div className="flex flex-col-reverse" style={{ zIndex: 999 }}>
{tempNotificationList.map((alert) => (
<div key={alert.id}>
{alert.type === "error" && (
<ErrorAlert
key={alert.id}
title={alert.title}
list={alert.list}
id={alert.id}
removeAlert={removeAlert}
/>
)}
</div>
))}
</div>
<div className="z-40 flex flex-col-reverse">
{tempNotificationList.map((alert) => (
<div key={alert.id}>
{alert.type === "notice" ? (
<NoticeAlert
key={alert.id}
title={alert.title}
link={alert.link}
id={alert.id}
removeAlert={removeAlert}
/>
) : (
alert.type === "success" && (
<SuccessAlert
key={alert.id}
title={alert.title}
id={alert.id}
removeAlert={removeAlert}
/>
)
)}
</div>
))}
</div>
</div>
</div>
);

View file

@ -1,5 +1,6 @@
import { cloneDeep } from "lodash";
import { useCallback, useEffect, useState } from "react";
import { NodeToolbar } from "reactflow";
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
import ShadTooltip from "../../components/ShadTooltipComponent";
import IconComponent from "../../components/genericIconComponent";
import InputComponent from "../../components/inputComponent";
@ -9,6 +10,7 @@ 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,
@ -20,6 +22,7 @@ import { useDarkStore } from "../../stores/darkStore";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { useTypesStore } from "../../stores/typesStore";
import { APIClassType } from "../../types/api";
import { validationStatusType } from "../../types/components";
import { NodeDataType } from "../../types/flow";
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
@ -39,10 +42,12 @@ export default function GenericNode({
yPos: number;
}): JSX.Element {
const types = useTypesStore((state) => state.types);
const templates = useTypesStore((state) => state.templates);
const deleteNode = useFlowStore((state) => state.deleteNode);
const flowPool = useFlowStore((state) => state.flowPool);
const buildFlow = useFlowStore((state) => state.buildFlow);
const setNode = useFlowStore((state) => state.setNode);
const updateNodeInternals = useUpdateNodeInternals();
const setErrorData = useAlertStore((state) => state.setErrorData);
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
const [inputName, setInputName] = useState(false);
@ -51,6 +56,7 @@ export default function GenericNode({
const [nodeDescription, setNodeDescription] = useState(
data.node?.description!
);
const [isOutdated, setIsOutdated] = useState(false);
const buildStatus = useFlowStore(
(state) => state.flowBuildStatus[data.id]?.status
);
@ -65,6 +71,52 @@ export default function GenericNode({
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
useEffect(() => {
// 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;
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;
if (currentCode !== thisNodesCode) {
setIsOutdated(true);
} else {
setIsOutdated(false);
}
// template.code can be undefined
}, [data.node?.template?.code?.value]);
const updateNodeCode = useCallback(
(newNodeClass: APIClassType, code: string, name: string) => {
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...newNode.data,
node: newNodeClass,
description: newNodeClass.description ?? data.node!.description,
display_name: newNodeClass.display_name ?? data.node!.display_name,
};
newNode.data.node.template[name].value = code;
setIsOutdated(false);
return newNode;
});
updateNodeInternals(data.id);
},
[data.id, data.node, setNode, setIsOutdated]
);
if (!data.node!.template) {
setErrorData({
title: `Error in component ${data.node!.display_name}`,
@ -305,6 +357,8 @@ export default function GenericNode({
showNode={showNode}
openAdvancedModal={false}
onCloseAdvancedModal={() => {}}
updateNodeCode={updateNodeCode}
isOutdated={isOutdated}
selected={selected}
></NodeToolbarComponent>
</NodeToolbar>

View file

@ -55,8 +55,6 @@ export default function CodeTabsComponent({
const dark = useDarkStore((state) => state.dark);
const unselectAll = useFlowStore((state) => state.unselectAll);
const setNodes = useFlowStore((state) => state.setNodes);
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
useEffect(() => {

View file

@ -16,7 +16,6 @@ import FlowSettingsModal from "../../../../modals/flowSettingsModal";
import useAlertStore from "../../../../stores/alertStore";
import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { useStoreStore } from "../../../../stores/storeStore";
import { cn } from "../../../../utils/utils";
import ShadTooltip from "../../../ShadTooltipComponent";
import IconComponent from "../../../genericIconComponent";
@ -34,10 +33,8 @@ export const MenuBar = ({
const redo = useFlowsManagerStore((state) => state.redo);
const saveLoading = useFlowsManagerStore((state) => state.saveLoading);
const [openSettings, setOpenSettings] = useState(false);
const n = useFlowStore((state) => state.nodes);
const nodes = useFlowStore((state) => state.nodes);
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
const hasApiKey = useStoreStore((state) => state.hasApiKey);
const validApiKey = useStoreStore((state) => state.validApiKey);
const navigate = useNavigate();
const isBuilding = useFlowStore((state) => state.isBuilding);
@ -46,7 +43,6 @@ export const MenuBar = ({
addFlow(true).then((id) => {
navigate("/flow/" + id);
});
// saveFlowStyleInDataBase();
} catch (err) {
setErrorData(err as { title: string; list?: Array<string> });
}
@ -65,7 +61,7 @@ export const MenuBar = ({
<div className="round-button-div">
<button
onClick={() => {
removeFunction(n);
removeFunction(nodes);
navigate(-1);
}}
>

View file

@ -33,7 +33,7 @@ export default function Header(): JSX.Element {
const removeFlow = useFlowsManagerStore((store) => store.removeFlow);
const hasStore = useStoreStore((state) => state.hasStore);
const { id } = useParams();
const n = useFlowStore((state) => state.nodes);
const nodes = useFlowStore((state) => state.nodes);
const dark = useDarkStore((state) => state.dark);
const setDark = useDarkStore((state) => state.setDark);
@ -57,7 +57,7 @@ export default function Header(): JSX.Element {
return (
<div className="header-arrangement">
<div className="header-start-display lg:w-[30%]">
<Link to="/" onClick={() => checkForChanges(n)}>
<Link to="/" onClick={() => checkForChanges(nodes)}>
<span className="ml-4 text-2xl">⛓️</span>
</Link>
<MenuBar removeFunction={checkForChanges} />
@ -74,7 +74,7 @@ export default function Header(): JSX.Element {
}
size="sm"
onClick={() => {
checkForChanges(n);
checkForChanges(nodes);
}}
>
<IconComponent name="Home" className="h-4 w-4" />
@ -100,7 +100,7 @@ export default function Header(): JSX.Element {
variant={location.pathname === "/store" ? "primary" : "secondary"}
size="sm"
onClick={() => {
checkForChanges(n);
checkForChanges(nodes);
}}
>
<IconComponent name="Store" className="h-4 w-4" />

View file

@ -43,7 +43,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 flex w-full max-w-lg translate-x-[-50%] translate-y-[-50%] flex-col gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
"fixed z-50 flex w-full max-w-lg flex-col gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] sm:rounded-lg md:w-full",
className
)}
{...props}

View file

@ -28,6 +28,9 @@ export default function RenameLabel(props) {
}
}
resizeInput();
return () => {
if(isRename) document.removeEventListener("keydown", () => {});
};
}, [isRename]);
const inputRef = useRef<HTMLInputElement | null>(null);

View file

@ -40,7 +40,7 @@ export const COMPONENTS_ERROR_ALERT = "Error getting components.";
// NOTICE
export const NOCHATOUTPUT_NOTICE_ALERT =
"There is no ChatOutput node in the flow.";
"There is no ChatOutput Component in the flow.";
export const API_WARNING_NOTICE_ALERT =
"Warning: Critical data, JSON file may include API keys.";
export const COPIED_NOTICE_ALERT = "API Key copied!";

View file

@ -740,6 +740,16 @@ export const PRIORITY_SIDEBAR_ORDER = [
"helpers",
"experimental",
];
export const NATIVE_CATEGORIES = [
"inputs",
"outputs",
"prompts",
"data",
"prompt",
"models",
"helpers",
"experimental",
];
/*
Data ingestion
Basic Prompting

View file

@ -1,7 +1,6 @@
import axios, { AxiosError, AxiosInstance } from "axios";
import { useContext, useEffect } from "react";
import { Cookies } from "react-cookie";
import { useNavigate } from "react-router-dom";
import { renewAccessToken } from ".";
import { BuildStatus } from "../../constants/enums";
import { AuthContext } from "../../contexts/authContext";
@ -17,26 +16,28 @@ function ApiInterceptor() {
const setErrorData = useAlertStore((state) => state.setErrorData);
let { accessToken, login, logout, authenticationErrorCount, autoLogin } =
useContext(AuthContext);
const navigate = useNavigate();
const cookies = new Cookies();
useEffect(() => {
const interceptor = api.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
if (error.response?.status === 401) {
const accessToken = cookies.get("access_token_lf");
if (error.response?.status === 403 || error.response?.status === 401) {
if (!autoLogin) {
const stillRefresh = checkErrorCount();
if (!stillRefresh) {
return Promise.reject(error);
}
const acceptedRequest = await tryToRenewAccessToken(error);
if (accessToken && !autoLogin) {
checkErrorCount();
await tryToRenewAccessToken(error);
const accessToken = cookies.get("access_token_lf");
if (!accessToken && error?.config?.url?.includes("login")) {
return Promise.reject(error);
}
return acceptedRequest;
}
if (!accessToken && error?.config?.url?.includes("login")) {
return Promise.reject(error);
}
return logout();
}
await clearBuildVerticesState(error);
return Promise.reject(error);
@ -98,11 +99,15 @@ function ApiInterceptor() {
if (authenticationErrorCount > 3) {
authenticationErrorCount = 0;
logout();
return false;
}
return true;
}
async function tryToRenewAccessToken(error: AxiosError) {
try {
if (window.location.pathname.includes("/login")) return;
const res = await renewAccessToken();
if (res?.data?.access_token && res?.data?.refresh_token) {
login(res?.data?.access_token);
@ -116,7 +121,9 @@ function ApiInterceptor() {
return response;
}
} catch (error) {
clearBuildVerticesState(error);
logout();
return Promise.reject("Authentication error");
}
}

View file

@ -4,6 +4,7 @@ import { BASE_URL_API } from "../../constants/constants";
import { api } from "../../controllers/API/api";
import {
APIObjectType,
APITemplateType,
Component,
LoginType,
Users,
@ -369,11 +370,13 @@ export async function postCustomComponent(
export async function postCustomComponentUpdate(
code: string,
template: APITemplateType,
field: string,
field_value: any
): Promise<AxiosResponse<APIClassType>> {
return await api.post(`${BASE_URL_API}custom_component/update`, {
code,
template,
field,
field_value,
});

View file

@ -9,7 +9,7 @@ const SvgBotMessageSquare = (props) => (
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-bot-message-square"
className="lucide lucide-bot-message-square"
{...props}
>
<path d="M12 6V2H8" />

View file

@ -23,7 +23,6 @@ import {
import { postCustomComponent, postValidateCode } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore";
import { useDarkStore } from "../../stores/darkStore";
import useFlowStore from "../../stores/flowStore";
import { CodeErrorDataTypeAPI } from "../../types/api";
import { codeAreaModalPropsType } from "../../types/components";
import BaseModal from "../baseModal";
@ -45,14 +44,12 @@ export default function CodeAreaModal({
? [myOpen, mySetOpen]
: useState(false);
const dark = useDarkStore((state) => state.dark);
const unselectAll = useFlowStore((state) => state.unselectAll);
const [height, setHeight] = useState<string | null>(null);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const [error, setError] = useState<{
detail: CodeErrorDataTypeAPI;
} | null>(null);
const nodes = useFlowStore((state) => state.nodes);
useEffect(() => {
// if nodeClass.template has more fields other than code and dynamic is true

View file

@ -250,10 +250,20 @@ export default function ExtraSidebar(): JSX.Element {
setSearch(event.target.value);
}}
/>
<div className="search-icon">
<div
className="search-icon "
onClick={() => {
if (search) {
setFilterData(data);
setSearch("");
}
}}
>
<IconComponent
name="Search"
className={"h-5 w-5 stroke-[1.5] text-primary"}
name={search ? "X" : "Search"}
className={`h-5 w-5 stroke-[1.5] text-primary ${
search ? "cursor-pointer" : "cursor-default"
}`}
aria-hidden="true"
/>
</div>

View file

@ -10,6 +10,7 @@ import {
SelectItem,
SelectTrigger,
} from "../../../../components/ui/select-custom";
import { postCustomComponent } from "../../../../controllers/API";
import ConfirmationModal from "../../../../modals/ConfirmationModal";
import EditNodeModal from "../../../../modals/EditNodeModal";
import ShareModal from "../../../../modals/shareModal";
@ -18,6 +19,7 @@ import { useDarkStore } from "../../../../stores/darkStore";
import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import { useStoreStore } from "../../../../stores/storeStore";
import { useTypesStore } from "../../../../stores/typesStore";
import { APIClassType } from "../../../../types/api";
import { nodeToolbarPropsType } from "../../../../types/components";
import { FlowType } from "../../../../types/flow";
@ -28,6 +30,7 @@ import {
updateFlowPosition,
} from "../../../../utils/reactflowUtils";
import { classNames, cn } from "../../../../utils/utils";
import ToolbarSelectItem from "./toolbarSelectItem";
export default function NodeToolbarComponent({
data,
@ -38,8 +41,10 @@ export default function NodeToolbarComponent({
showNode,
name = "code",
selected,
updateNodeCode,
setShowState,
onCloseAdvancedModal,
isOutdated,
}: nodeToolbarPropsType): JSX.Element {
const nodeLength = Object.keys(data.node!.template).filter(
(templateField) =>
@ -56,7 +61,7 @@ export default function NodeToolbarComponent({
data.node.template[templateField].type === "dict" ||
data.node.template[templateField].type === "NestedDict")
).length;
const templates = useTypesStore((state) => state.templates);
const hasStore = useStoreStore((state) => state.hasStore);
const hasApiKey = useStoreStore((state) => state.hasApiKey);
const validApiKey = useStoreStore((state) => state.validApiKey);
@ -70,6 +75,7 @@ export default function NodeToolbarComponent({
const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges);
const setNodes = useFlowStore((state) => state.setNodes);
const setEdges = useFlowStore((state) => state.setEdges);
const unselectAll = useFlowStore((state) => state.unselectAll);
const saveComponent = useFlowsManagerStore((state) => state.saveComponent);
@ -79,7 +85,6 @@ export default function NodeToolbarComponent({
const [showModalAdvanced, setShowModalAdvanced] = useState(false);
const [showconfirmShare, setShowconfirmShare] = useState(false);
const [showOverrideModal, setShowOverrideModal] = useState(false);
const [flowComponent, setFlowComponent] = useState<FlowType>();
const openInNewTab = (url) => {
@ -170,6 +175,37 @@ export default function NodeToolbarComponent({
paneY: nodes.find((node) => node.id === data.id)?.position.y,
}
);
break;
case "update":
takeSnapshot();
// to update we must get the code from the templates in useTypesStore
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;
if (data.node) {
postCustomComponent(currentCode, data.node)
.then((apiReturn) => {
const { data } = apiReturn;
if (data && updateNodeCode) {
updateNodeCode(data, currentCode, "code");
}
})
.catch((err) => {
console.log(err);
});
setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode);
newNode.data = {
...data,
};
newNode.data.node.template.code.value = currentCode;
return newNode;
});
}
break;
}
};
@ -411,93 +447,59 @@ export default function NodeToolbarComponent({
<SelectContent>
{nodeLength > 0 && (
<SelectItem value={nodeLength === 0 ? "disabled" : "advanced"}>
<div className="flex" data-testid="edit-button-modal">
<IconComponent
name="Settings2"
className="relative top-0.5 mr-2 h-4 w-4 "
/>{" "}
<span className="">Edit</span>{" "}
{navigator.userAgent.toUpperCase().includes("MAC") ? (
<IconComponent
name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
) : (
<span className="absolute right-[1.15rem] top-[0.40em] stroke-2">
Ctrl +{" "}
</span>
)}
<span className="absolute right-2 top-[0.46em]">E</span>
</div>
<ToolbarSelectItem
keyboardKey="E"
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
shift={false}
value={"Edit"}
icon={"Settings2"}
/>
</SelectItem>
)}
<SelectItem value={"duplicate"}>
<div className="flex" data-testid="duplicate-button-modal">
<IconComponent
name="Copy"
className="relative top-0.5 mr-2 h-4 w-4"
/>
Duplicate
{navigator.userAgent.toUpperCase().includes("MAC") ? (
<IconComponent
name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
) : (
<span className="absolute right-[1.20rem] top-[0.40em] stroke-2">
Ctrl +{" "}
</span>
)}
<span className="absolute right-2 top-[0.4em]">D</span>
</div>{" "}
<ToolbarSelectItem
keyboardKey="D"
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
shift={false}
value={"Duplicate"}
icon={"Copy"}
/>
</SelectItem>
<SelectItem value={"copy"}>
<div className="flex">
<IconComponent
name="Clipboard"
className="relative top-0.5 mr-2 h-4 w-4 "
/>{" "}
<span className="">Copy</span>{" "}
{navigator.userAgent.toUpperCase().includes("MAC") ? (
<IconComponent
name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
) : (
<span className="absolute right-[1.15rem] top-[0.40em] stroke-2">
Ctrl +{" "}
</span>
)}
<span className="absolute right-2 top-[0.4em]">C</span>
</div>
<ToolbarSelectItem
keyboardKey="C"
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
shift={false}
value={"Copy"}
icon={"Clipboard"}
/>
</SelectItem>
{isOutdated && (
<SelectItem value={"update"}>
<ToolbarSelectItem
keyboardKey="U"
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
shift={false}
value={"Update"}
icon={"Code"}
/>
</SelectItem>
)}
{hasStore && (
<SelectItem
value={"Share"}
disabled={!hasApiKey || !validApiKey}
>
<div className="flex" data-testid="share-button-modal">
<IconComponent
name="Share3"
className="relative top-0.5 -m-1 mr-1 h-6 w-6"
/>{" "}
Share{" "}
{navigator.userAgent.toUpperCase().includes("MAC") ? (
<IconComponent
name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
) : (
<span className="absolute right-[2.10rem] top-[0.43em] stroke-2">
Ctrl
</span>
)}
<IconComponent
name="ArrowBigUp"
className="absolute right-[1.09rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
<span className="absolute right-2 top-[0.45em]">S</span>
</div>{" "}
<ToolbarSelectItem
keyboardKey="S"
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
shift={true}
value={"Share"}
icon={"Share3"}
styleObj={{
iconClasses: "relative top-0.5 -m-1 mr-1 h-6 w-6",
}}
/>
</SelectItem>
)}
{!hasStore && (
@ -515,28 +517,13 @@ export default function NodeToolbarComponent({
value={"documentation"}
disabled={data.node?.documentation === ""}
>
<div className="flex">
<IconComponent
name="FileText"
className="relative top-0.5 mr-2 h-4 w-4 "
/>{" "}
<span className="">Docs</span>{" "}
{navigator.userAgent.toUpperCase().includes("MAC") ? (
<IconComponent
name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
) : (
<span className="absolute right-[2.10rem] top-[0.43em] stroke-2">
Ctrl
</span>
)}
<IconComponent
name="ArrowBigUp"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
></IconComponent>
<span className="absolute right-2 top-[0.43em]">D</span>
</div>
<ToolbarSelectItem
keyboardKey="D"
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
shift={true}
value={"Docs"}
icon={"FileText"}
/>
</SelectItem>
{isMinimal && (
<SelectItem value={"show"}>

View file

@ -0,0 +1,44 @@
import { useEffect } from "react";
import ForwardedIconComponent from "../../../../../components/genericIconComponent";
import { toolbarSelectItemProps } from "../../../../../types/components";
export default function ToolbarSelectItem({
shift,
isMac,
keyboardKey,
value,
icon,
styleObj,
}: toolbarSelectItemProps) {
return (
<div className="flex">
<ForwardedIconComponent
name={icon}
className={`relative top-0.5 mr-2 h-4 w-4 ${styleObj?.iconClasses}`}
/>{" "}
<span className={styleObj?.valueClasses}>{value}</span>{" "}
{isMac ? (
<ForwardedIconComponent
name="Command"
className={`absolute right-[${shift ? "2rem" : "1.15rem"}] top-[0.65em] h-3.5 w-3.5 stroke-2 ${styleObj?.commandClasses}`}
></ForwardedIconComponent>
) : (
<span className={`absolute right-[${shift ? "2.10rem" : "1.15rem"}] top-[0.43em] stroke-2 ${styleObj?.ctrlClasses}`}>
{shift ? (
"Ctrl"
) : (
"Ctrl +"
)}
</span>
)}
{shift && (
<ForwardedIconComponent
name="ArrowBigUp"
className={`absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2 ${styleObj?.shiftClasses}`}
/>
)}
<span className={`absolute right-2 top-[0.43em] ${styleObj?.keyClasses}`}>{keyboardKey}</span>
</div>
);
}

View file

@ -147,7 +147,7 @@ export default function StorePage(): JSX.Element {
}
})
.catch((err) => {
if (err.response.status === 403 || err.response.status === 401) {
if (err.response?.status === 403 || err.response?.status === 401) {
setValidApiKey(false);
} else {
setSearchData([]);

View file

@ -584,7 +584,7 @@
}
.app-div {
@apply fixed bottom-5 left-5 flex flex-col-reverse;
@apply absolute bottom-5 left-5 flex flex-col-reverse;
}
.chat-input-modal-txtarea {

View file

@ -491,7 +491,13 @@ export type nodeToolbarPropsType = {
openAdvancedModal?: boolean;
onCloseAdvancedModal?: (close: boolean) => void;
selected: boolean;
updateNodeCode?: (
newNodeClass: APIClassType,
code: string,
name: string
) => void;
setShowState: (show: boolean | SetStateAction<boolean>) => void;
isOutdated?: boolean;
};
export type parsedDataType = {
@ -682,3 +688,19 @@ export type IOFileInputProps = {
field: TemplateVariableType;
updateValue: (e: any, type: string) => void;
};
export type toolbarSelectItemProps = {
isMac: boolean;
shift: boolean;
keyboardKey: string;
value: string;
icon: string;
styleObj?: {
iconClasses?: string;
commandClasses?: string;
shiftClasses?: string;
ctrlClasses?: string;
keyClasses?: string;
valueClasses?: string;
}
};

View file

@ -9,9 +9,15 @@ export const handleUpdateValues = async (name: string, data: NodeDataType) => {
console.error("Code not found in the template");
return;
}
const template = data.node?.template;
if (!template) {
console.error("No template found in the node.");
return;
}
try {
let newTemplate = await postCustomComponentUpdate(
code,
template,
name,
data.node?.template[name]?.value
)

View file

@ -264,7 +264,7 @@ export function buildTweaks(flow: FlowType) {
export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
if (!node.data?.node?.template || !Object.keys(node.data.node.template)) {
return [
"We've noticed a potential issue with a node in the flow. Please review it and, if necessary, submit a bug report with your exported flow file. Thank you for your help!",
"We've noticed a potential issue with a Component in the flow. Please review it and, if necessary, submit a bug report with your exported flow file. Thank you for your help!",
];
}

View file

@ -278,6 +278,7 @@ export const nodeNames: { [char: string]: string } = {
};
export const nodeIconsLucide: iconsType = {
X: X,
Notify: Bell,
ListFlows: Group,
ClearMessageHistory: FileClock,

View file

@ -386,7 +386,7 @@ export function getCurlCode(
-H 'Content-Type: application/json'\\${
!isAuth ? `\n -H 'x-api-key: <your api key>'\\` : ""
}
-d '{"inputs": ${inputs}, "tweaks": ${
-d '{"inputs": [${inputs}], "tweaks": ${
tweak && tweak.length > 0
? buildTweakObject(tweak)
: JSON.stringify(tweaks, null, 2)