Refactor: Remove unnecessary isMac prop from toolbarSelectItem component and add IS_MAC constant

This commit is contained in:
ogabrielluiz 2024-06-09 11:26:42 -03:00
commit e6147871ee
6 changed files with 93 additions and 108 deletions

View file

@ -9,7 +9,7 @@ import {
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants"; import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants";
import { SAVED_HOVER } from "../../../../constants/constants"; import { IS_MAC, SAVED_HOVER } from "../../../../constants/constants";
import ExportModal from "../../../../modals/exportModal"; import ExportModal from "../../../../modals/exportModal";
import FlowLogsModal from "../../../../modals/flowLogsModal"; import FlowLogsModal from "../../../../modals/flowLogsModal";
import FlowSettingsModal from "../../../../modals/flowSettingsModal"; import FlowSettingsModal from "../../../../modals/flowSettingsModal";
@ -113,7 +113,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
title: UPLOAD_ERROR_ALERT, title: UPLOAD_ERROR_ALERT,
list: [error], list: [error],
}); });
}, }
); );
}} }}
> >
@ -137,7 +137,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
> >
<IconComponent name="Undo" className="header-menu-options " /> <IconComponent name="Undo" className="header-menu-options " />
Undo Undo
{navigator.userAgent.toUpperCase().includes("MAC") ? ( {IS_MAC ? (
<IconComponent <IconComponent
name="Command" name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
@ -157,7 +157,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
> >
<IconComponent name="Redo" className="header-menu-options " /> <IconComponent name="Redo" className="header-menu-options " />
Redo Redo
{navigator.userAgent.toUpperCase().includes("MAC") ? ( {IS_MAC ? (
<IconComponent <IconComponent
name="Command" name="Command"
className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
@ -195,7 +195,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"} name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"}
className={cn( className={cn(
"h-4 w-4", "h-4 w-4",
isBuilding || saveLoading ? "animate-spin" : "animate-wiggle", isBuilding || saveLoading ? "animate-spin" : "animate-wiggle"
)} )}
/> />
{printByBuildStatus()} {printByBuildStatus()}

View file

@ -734,14 +734,16 @@ export const AUTHORIZED_DUPLICATE_REQUESTS = [
export const SAVE_DEBOUNCE_TIME = 300; export const SAVE_DEBOUNCE_TIME = 300;
export const IS_MAC = navigator.userAgent.toUpperCase().includes("MAC");
export const defaultShortcuts = [ export const defaultShortcuts = [
{ {
name: "Advanced Settings", name: "Advanced Settings",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + A`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + A`,
}, },
{ {
name: "Minimize", name: "Minimize",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Q`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Q`,
}, },
{ {
name: "Code", name: "Code",
@ -749,23 +751,23 @@ export const defaultShortcuts = [
}, },
{ {
name: "Copy", name: "Copy",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + C`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + C`,
}, },
{ {
name: "Duplicate", name: "Duplicate",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + D`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + D`,
}, },
{ {
name: "Share", name: "Share",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + S`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + S`,
}, },
{ {
name: "Docs", name: "Docs",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + D`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + D`,
}, },
{ {
name: "Save", name: "Save",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + S`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + S`,
}, },
{ {
name: "Delete", name: "Delete",
@ -773,43 +775,43 @@ export const defaultShortcuts = [
}, },
{ {
name: "Open playground", name: "Open playground",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + K`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + K`,
}, },
{ {
name: "Undo", name: "Undo",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Z`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Z`,
}, },
{ {
name: "Redo", name: "Redo",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Y`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Y`,
}, },
{ {
name: "Group", name: "Group",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + G`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + G`,
}, },
{ {
name: "Cut", name: "Cut",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + X`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + X`,
}, },
{ {
name: "Paste", name: "Paste",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + V`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + V`,
}, },
{ {
name: "API", name: "API",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + R`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + R`,
}, },
{ {
name: "Download", name: "Download",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + J`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + J`,
}, },
{ {
name: "Update", name: "Update",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + U`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + U`,
}, },
{ {
name: "Freeze", name: "Freeze",
shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + F`, shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + F`,
}, },
]; ];

View file

@ -11,7 +11,6 @@ import {
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
} from "../../../../components/ui/select-custom"; } from "../../../../components/ui/select-custom";
import { postCustomComponent } from "../../../../controllers/API";
import ConfirmationModal from "../../../../modals/confirmationModal"; import ConfirmationModal from "../../../../modals/confirmationModal";
import EditNodeModal from "../../../../modals/editNodeModal"; import EditNodeModal from "../../../../modals/editNodeModal";
import ShareModal from "../../../../modals/shareModal"; import ShareModal from "../../../../modals/shareModal";
@ -58,16 +57,14 @@ export default function NodeToolbarComponent({
data.node.template[templateField].type === "Any" || data.node.template[templateField].type === "Any" ||
data.node.template[templateField].type === "int" || data.node.template[templateField].type === "int" ||
data.node.template[templateField].type === "dict" || data.node.template[templateField].type === "dict" ||
data.node.template[templateField].type === "NestedDict"), data.node.template[templateField].type === "NestedDict")
).length; ).length;
const templates = useTypesStore((state) => state.templates);
const hasStore = useStoreStore((state) => state.hasStore); const hasStore = useStoreStore((state) => state.hasStore);
const hasApiKey = useStoreStore((state) => state.hasApiKey); const hasApiKey = useStoreStore((state) => state.hasApiKey);
const validApiKey = useStoreStore((state) => state.validApiKey); const validApiKey = useStoreStore((state) => state.validApiKey);
const shortcuts = useShortcutsStore((state) => state.shortcuts); const shortcuts = useShortcutsStore((state) => state.shortcuts);
const unselectAll = useFlowStore((state) => state.unselectAll); const unselectAll = useFlowStore((state) => state.unselectAll);
function handleMinimizeWShortcut(e: KeyboardEvent) { function handleMinimizeWShortcut(e: KeyboardEvent) {
e.preventDefault(); e.preventDefault();
if (isMinimal) { if (isMinimal) {
@ -199,7 +196,7 @@ export default function NodeToolbarComponent({
const [showconfirmShare, setShowconfirmShare] = useState(false); const [showconfirmShare, setShowconfirmShare] = useState(false);
const [showOverrideModal, setShowOverrideModal] = useState(false); const [showOverrideModal, setShowOverrideModal] = useState(false);
const [flowComponent, setFlowComponent] = useState<FlowType>( const [flowComponent, setFlowComponent] = useState<FlowType>(
createFlowComponent(cloneDeep(data), version), createFlowComponent(cloneDeep(data), version)
); );
// useEffect(() => { // useEffect(() => {
@ -218,7 +215,7 @@ export default function NodeToolbarComponent({
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const setLastCopiedSelection = useFlowStore( const setLastCopiedSelection = useFlowStore(
(state) => state.setLastCopiedSelection, (state) => state.setLastCopiedSelection
); );
const setSuccessData = useAlertStore((state) => state.setSuccessData); const setSuccessData = useAlertStore((state) => state.setSuccessData);
@ -292,7 +289,7 @@ export default function NodeToolbarComponent({
nodes, nodes,
edges, edges,
setNodes, setNodes,
setEdges, setEdges
); );
break; break;
case "override": case "override":
@ -316,20 +313,20 @@ export default function NodeToolbarComponent({
y: 10, y: 10,
paneX: nodes.find((node) => node.id === data.id)?.position.x, paneX: nodes.find((node) => node.id === data.id)?.position.x,
paneY: nodes.find((node) => node.id === data.id)?.position.y, paneY: nodes.find((node) => node.id === data.id)?.position.y,
}, }
); );
break; break;
} }
}; };
const isSaved = flows.some((flow) => const isSaved = flows.some((flow) =>
Object.values(flow).includes(data.node?.display_name!), Object.values(flow).includes(data.node?.display_name!)
); );
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
const handleOnNewValue = ( const handleOnNewValue = (
newValue: string | string[] | boolean | Object[], newValue: string | string[] | boolean | Object[]
): void => { ): void => {
if (data.node!.template[name].value !== newValue) { if (data.node!.template[name].value !== newValue) {
takeSnapshot(); takeSnapshot();
@ -428,7 +425,7 @@ export default function NodeToolbarComponent({
<ShadTooltip content="Freeze" side="top"> <ShadTooltip content="Freeze" side="top">
<button <button
className={classNames( 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) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -449,7 +446,7 @@ export default function NodeToolbarComponent({
className={cn( className={cn(
"h-4 w-4 transition-all", "h-4 w-4 transition-all",
// TODO UPDATE THIS COLOR TO BE A VARIABLE // TODO UPDATE THIS COLOR TO BE A VARIABLE
frozen ? "animate-wiggle text-ice" : "", frozen ? "animate-wiggle text-ice" : ""
)} )}
/> />
</button> </button>
@ -477,7 +474,7 @@ export default function NodeToolbarComponent({
<div <div
data-testid="more-options-modal" data-testid="more-options-modal"
className={classNames( className={classNames(
"relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background 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 h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
)} )}
> >
<IconComponent <IconComponent
@ -495,7 +492,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Code")?.shortcut! shortcuts.find((obj) => obj.name === "Code")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Code"} value={"Code"}
icon={"Code"} icon={"Code"}
dataTestId="code-button-modal" dataTestId="code-button-modal"
@ -509,7 +505,6 @@ export default function NodeToolbarComponent({
shortcuts.find((obj) => obj.name === "Advanced Settings") shortcuts.find((obj) => obj.name === "Advanced Settings")
?.shortcut! ?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Advanced"} value={"Advanced"}
icon={"Settings2"} icon={"Settings2"}
dataTestId="edit-button-modal" dataTestId="edit-button-modal"
@ -521,7 +516,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Save")?.shortcut! shortcuts.find((obj) => obj.name === "Save")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Save"} value={"Save"}
icon={"SaveAll"} icon={"SaveAll"}
dataTestId="save-button-modal" dataTestId="save-button-modal"
@ -532,7 +526,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Duplicate")?.shortcut! shortcuts.find((obj) => obj.name === "Duplicate")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Duplicate"} value={"Duplicate"}
icon={"Copy"} icon={"Copy"}
dataTestId="copy-button-modal" dataTestId="copy-button-modal"
@ -543,7 +536,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Copy")?.shortcut! shortcuts.find((obj) => obj.name === "Copy")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Copy"} value={"Copy"}
icon={"Clipboard"} icon={"Clipboard"}
dataTestId="copy-button-modal" dataTestId="copy-button-modal"
@ -558,7 +550,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Share")?.shortcut! shortcuts.find((obj) => obj.name === "Share")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Share"} value={"Share"}
icon={"Share3"} icon={"Share3"}
dataTestId="share-button-modal" dataTestId="share-button-modal"
@ -572,7 +563,6 @@ export default function NodeToolbarComponent({
shortcuts.find((obj) => obj.name === "Download") shortcuts.find((obj) => obj.name === "Download")
?.shortcut! ?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Download"} value={"Download"}
icon={"Download"} icon={"Download"}
dataTestId="Download-button-modal" dataTestId="Download-button-modal"
@ -587,7 +577,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Docs")?.shortcut! shortcuts.find((obj) => obj.name === "Docs")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Docs"} value={"Docs"}
icon={"FileText"} icon={"FileText"}
dataTestId="docs-button-modal" dataTestId="docs-button-modal"
@ -600,7 +589,6 @@ export default function NodeToolbarComponent({
shortcuts.find((obj) => obj.name === "Minimize") shortcuts.find((obj) => obj.name === "Minimize")
?.shortcut! ?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={showNode ? "Minimize" : "Expand"} value={showNode ? "Minimize" : "Expand"}
icon={showNode ? "Minimize2" : "Maximize2"} icon={showNode ? "Minimize2" : "Maximize2"}
dataTestId="minimize-button-modal" dataTestId="minimize-button-modal"
@ -613,7 +601,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Group")?.shortcut! shortcuts.find((obj) => obj.name === "Group")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Ungroup"} value={"Ungroup"}
icon={"Ungroup"} icon={"Ungroup"}
dataTestId="group-button-modal" dataTestId="group-button-modal"
@ -625,7 +612,6 @@ export default function NodeToolbarComponent({
shortcut={ shortcut={
shortcuts.find((obj) => obj.name === "Freeze")?.shortcut! shortcuts.find((obj) => obj.name === "Freeze")?.shortcut!
} }
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
value={"Freeze"} value={"Freeze"}
icon={"Snowflake"} icon={"Snowflake"}
dataTestId="group-button-modal" dataTestId="group-button-modal"

View file

@ -8,7 +8,6 @@ export default function ToolbarSelectItem({
dataTestId, dataTestId,
ping, ping,
shortcut, shortcut,
isMac,
}: toolbarSelectItemProps) { }: toolbarSelectItemProps) {
let hasShift = false; let hasShift = false;
const fixedShortcut = shortcut?.split("+"); const fixedShortcut = shortcut?.split("+");
@ -18,7 +17,7 @@ export default function ToolbarSelectItem({
} }
}); });
const filteredShortcut = fixedShortcut.filter( const filteredShortcut = fixedShortcut.filter(
(key) => !key.toLowerCase().includes("shift"), (key) => !key.toLowerCase().includes("shift")
); );
let shortcutWPlus = ""; let shortcutWPlus = "";
if (!hasShift) shortcutWPlus = filteredShortcut.join("+"); if (!hasShift) shortcutWPlus = filteredShortcut.join("+");

View file

@ -491,7 +491,7 @@ export type ChatInputType = {
isDragging: boolean; isDragging: boolean;
files: FilePreviewType[]; files: FilePreviewType[];
setFiles: ( setFiles: (
files: FilePreviewType[] | ((prev: FilePreviewType[]) => FilePreviewType[]), files: FilePreviewType[] | ((prev: FilePreviewType[]) => FilePreviewType[])
) => void; ) => void;
chatValue: string; chatValue: string;
inputRef: { inputRef: {
@ -593,7 +593,7 @@ export type chatMessagePropsType = {
updateChat: ( updateChat: (
chat: ChatMessageType, chat: ChatMessageType,
message: string, message: string,
stream_url?: string, stream_url?: string
) => void; ) => void;
}; };
@ -685,12 +685,12 @@ export type codeTabsPropsType = {
value: string, value: string,
node: NodeType, node: NodeType,
template: TemplateVariableType, template: TemplateVariableType,
tweak: tweakType, tweak: tweakType
) => string; ) => string;
buildTweakObject?: ( buildTweakObject?: (
tw: string, tw: string,
changes: string | string[] | boolean | number | Object[] | Object, changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType, template: TemplateVariableType
) => Promise<string | void>; ) => Promise<string | void>;
}; };
activeTweaks?: boolean; activeTweaks?: boolean;
@ -772,7 +772,6 @@ export type IOFileInputProps = {
}; };
export type toolbarSelectItemProps = { export type toolbarSelectItemProps = {
isMac: boolean;
value: string; value: string;
icon: string; icon: string;
style?: string; style?: string;

View file

@ -11,6 +11,7 @@ import ShortUniqueId from "short-unique-id";
import getFieldTitle from "../CustomNodes/utils/get-field-title"; import getFieldTitle from "../CustomNodes/utils/get-field-title";
import { import {
INPUT_TYPES, INPUT_TYPES,
IS_MAC,
LANGFLOW_SUPPORTED_TYPES, LANGFLOW_SUPPORTED_TYPES,
OUTPUT_TYPES, OUTPUT_TYPES,
SUCCESS_BUILD, SUCCESS_BUILD,
@ -99,18 +100,18 @@ export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) {
export function isValidConnection( export function isValidConnection(
{ source, target, sourceHandle, targetHandle }: Connection, { source, target, sourceHandle, targetHandle }: Connection,
nodes: Node[], nodes: Node[],
edges: Edge[], edges: Edge[]
) { ) {
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!); const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!); const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
if ( if (
targetHandleObject.inputTypes?.some( targetHandleObject.inputTypes?.some(
(n) => n === sourceHandleObject.dataType, (n) => n === sourceHandleObject.dataType
) || ) ||
sourceHandleObject.baseClasses.some( sourceHandleObject.baseClasses.some(
(t) => (t) =>
targetHandleObject.inputTypes?.some((n) => n === t) || targetHandleObject.inputTypes?.some((n) => n === t) ||
t === targetHandleObject.type, t === targetHandleObject.type
) )
) { ) {
let targetNode = nodes.find((node) => node.id === target!)?.data?.node; let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
@ -143,7 +144,7 @@ export function removeApiKeys(flow: FlowType): FlowType {
export function updateTemplate( export function updateTemplate(
reference: APITemplateType, reference: APITemplateType,
objectToUpdate: APITemplateType, objectToUpdate: APITemplateType
): APITemplateType { ): APITemplateType {
let clonedObject: APITemplateType = cloneDeep(reference); let clonedObject: APITemplateType = cloneDeep(reference);
@ -203,7 +204,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => {
export function updateIds( export function updateIds(
{ edges, nodes }: { edges: Edge[]; nodes: Node[] }, { edges, nodes }: { edges: Edge[]; nodes: Node[] },
selection?: { edges: Edge[]; nodes: Node[] }, selection?: { edges: Edge[]; nodes: Node[] }
) { ) {
let idsMap = {}; let idsMap = {};
const selectionIds = selection?.nodes.map((n) => n.id); const selectionIds = selection?.nodes.map((n) => n.id);
@ -231,7 +232,7 @@ export function updateIds(
edge.source = idsMap[edge.source]; edge.source = idsMap[edge.source];
edge.target = idsMap[edge.target]; edge.target = idsMap[edge.target];
const sourceHandleObject: sourceHandleType = scapeJSONParse( const sourceHandleObject: sourceHandleType = scapeJSONParse(
edge.sourceHandle!, edge.sourceHandle!
); );
edge.sourceHandle = scapedJSONStringfy({ edge.sourceHandle = scapedJSONStringfy({
...sourceHandleObject, ...sourceHandleObject,
@ -241,7 +242,7 @@ export function updateIds(
edge.data.sourceHandle.id = edge.source; edge.data.sourceHandle.id = edge.source;
} }
const targetHandleObject: targetHandleType = scapeJSONParse( const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle!, edge.targetHandle!
); );
edge.targetHandle = scapedJSONStringfy({ edge.targetHandle = scapedJSONStringfy({
...targetHandleObject, ...targetHandleObject,
@ -287,11 +288,11 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
(scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName === (scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName ===
t && t &&
(scapeJSONParse(edge.targetHandle!) as targetHandleType).id === (scapeJSONParse(edge.targetHandle!) as targetHandleType).id ===
node.id, node.id
) )
) { ) {
errors.push( errors.push(
`${displayName || type} is missing ${getFieldTitle(template, t)}.`, `${displayName || type} is missing ${getFieldTitle(template, t)}.`
); );
} else if ( } else if (
template[t].type === "dict" && template[t].type === "dict" &&
@ -305,15 +306,15 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
errors.push( errors.push(
`${displayName || type} (${getFieldTitle( `${displayName || type} (${getFieldTitle(
template, template,
t, t
)}) contains duplicate keys with the same values.`, )}) contains duplicate keys with the same values.`
); );
if (hasEmptyKey(template[t].value)) if (hasEmptyKey(template[t].value))
errors.push( errors.push(
`${displayName || type} (${getFieldTitle( `${displayName || type} (${getFieldTitle(
template, template,
t, t
)}) field must not be empty.`, )}) field must not be empty.`
); );
} }
return errors; return errors;
@ -322,7 +323,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
export function validateNodes( export function validateNodes(
nodes: Node[], nodes: Node[],
edges: Edge[], edges: Edge[]
): // this returns an array of tuples with the node id and the errors ): // this returns an array of tuples with the node id and the errors
Array<{ id: string; errors: Array<string> }> { Array<{ id: string; errors: Array<string> }> {
if (nodes.length === 0) { if (nodes.length === 0) {
@ -343,7 +344,7 @@ export function updateEdges(edges: Edge[]) {
if (edges) if (edges)
edges.forEach((edge) => { edges.forEach((edge) => {
const targetHandleObject: targetHandleType = scapeJSONParse( const targetHandleObject: targetHandleType = scapeJSONParse(
edge.targetHandle!, edge.targetHandle!
); );
edge.className = ""; edge.className = "";
}); });
@ -410,7 +411,7 @@ export function handleKeyDown(
| React.KeyboardEvent<HTMLInputElement> | React.KeyboardEvent<HTMLInputElement>
| React.KeyboardEvent<HTMLTextAreaElement>, | React.KeyboardEvent<HTMLTextAreaElement>,
inputValue: string | string[] | null, inputValue: string | string[] | null,
block: string, block: string
) { ) {
//condition to fix bug control+backspace on Windows/Linux //condition to fix bug control+backspace on Windows/Linux
if ( if (
@ -420,9 +421,7 @@ export function handleKeyDown(
(inputValue === block || (inputValue === block ||
inputValue?.charAt(inputValue?.length - 1) === " " || inputValue?.charAt(inputValue?.length - 1) === " " ||
specialCharsRegex.test(inputValue?.charAt(inputValue?.length - 1)))) || specialCharsRegex.test(inputValue?.charAt(inputValue?.length - 1)))) ||
(navigator.userAgent.toUpperCase().includes("MAC") && (IS_MAC && e.ctrlKey === true && e.key === "Backspace")
e.ctrlKey === true &&
e.key === "Backspace")
) { ) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -435,7 +434,7 @@ export function handleKeyDown(
} }
export function handleOnlyIntegerInput( export function handleOnlyIntegerInput(
event: React.KeyboardEvent<HTMLInputElement>, event: React.KeyboardEvent<HTMLInputElement>
) { ) {
if ( if (
event.key === "." || event.key === "." ||
@ -451,7 +450,7 @@ export function handleOnlyIntegerInput(
export function getConnectedNodes( export function getConnectedNodes(
edge: Edge, edge: Edge,
nodes: Array<NodeType>, nodes: Array<NodeType>
): Array<NodeType> { ): Array<NodeType> {
const sourceId = edge.source; const sourceId = edge.source;
const targetId = edge.target; const targetId = edge.target;
@ -552,7 +551,7 @@ export function checkOldEdgesHandles(edges: Edge[]): boolean {
!edge.sourceHandle || !edge.sourceHandle ||
!edge.targetHandle || !edge.targetHandle ||
!edge.sourceHandle.includes("{") || !edge.sourceHandle.includes("{") ||
!edge.targetHandle.includes("{"), !edge.targetHandle.includes("{")
); );
} }
@ -575,7 +574,7 @@ export function customStringify(obj: any): string {
const keys = Object.keys(obj).sort(); const keys = Object.keys(obj).sort();
const keyValuePairs = keys.map( const keyValuePairs = keys.map(
(key) => `"${key}":${customStringify(obj[key])}`, (key) => `"${key}":${customStringify(obj[key])}`
); );
return `{${keyValuePairs.join(",")}}`; return `{${keyValuePairs.join(",")}}`;
} }
@ -604,7 +603,7 @@ export function getHandleId(
source: string, source: string,
sourceHandle: string, sourceHandle: string,
target: string, target: string,
targetHandle: string, targetHandle: string
) { ) {
return ( return (
"reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle "reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle
@ -615,7 +614,7 @@ export function generateFlow(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
nodes: Node[], nodes: Node[],
edges: Edge[], edges: Edge[],
name: string, name: string
): generateFlowType { ): generateFlowType {
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } }; const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
const uid = new ShortUniqueId({ length: 5 }); const uid = new ShortUniqueId({ length: 5 });
@ -624,7 +623,7 @@ export function generateFlow(
newFlowData.edges = selection.edges.filter( newFlowData.edges = selection.edges.filter(
(edge) => (edge) =>
selection.nodes.some((node) => node.id === edge.target) && selection.nodes.some((node) => node.id === edge.target) &&
selection.nodes.some((node) => node.id === edge.source), selection.nodes.some((node) => node.id === edge.source)
); );
newFlowData.nodes = selection.nodes; newFlowData.nodes = selection.nodes;
@ -645,7 +644,7 @@ export function generateFlow(
(edge) => (edge) =>
(selection.nodes.some((node) => node.id === edge.target) || (selection.nodes.some((node) => node.id === edge.target) ||
selection.nodes.some((node) => node.id === edge.source)) && selection.nodes.some((node) => node.id === edge.source)) &&
newFlowData.edges.every((e) => e.id !== edge.id), newFlowData.edges.every((e) => e.id !== edge.id)
), ),
}; };
} }
@ -656,13 +655,13 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
const { nodes, edges } = groupNode.data.node!.flow!.data!; const { nodes, edges } = groupNode.data.node!.flow!.data!;
const lastNode = findLastNode(groupNode.data.node!.flow!.data!); const lastNode = findLastNode(groupNode.data.node!.flow!.data!);
newEdges = newEdges.filter( newEdges = newEdges.filter(
(e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id), (e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id)
); );
newEdges.forEach((edge) => { newEdges.forEach((edge) => {
if (lastNode && edge.source === lastNode.id) { if (lastNode && edge.source === lastNode.id) {
edge.source = groupNode.id; edge.source = groupNode.id;
let newSourceHandle: sourceHandleType = scapeJSONParse( let newSourceHandle: sourceHandleType = scapeJSONParse(
edge.sourceHandle!, edge.sourceHandle!
); );
newSourceHandle.id = groupNode.id; newSourceHandle.id = groupNode.id;
edge.sourceHandle = scapedJSONStringfy(newSourceHandle); edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
@ -689,7 +688,7 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
export function filterFlow( export function filterFlow(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
) { ) {
setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node))); setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node)));
setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge))); setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge)));
@ -727,7 +726,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) {
export function concatFlows( export function concatFlows(
flow: FlowType, flow: FlowType,
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
) { ) {
const { nodes, edges } = flow.data!; const { nodes, edges } = flow.data!;
setNodes((old) => [...old, ...nodes]); setNodes((old) => [...old, ...nodes]);
@ -736,7 +735,7 @@ export function concatFlows(
export function validateSelection( export function validateSelection(
selection: OnSelectionChangeParams, selection: OnSelectionChangeParams,
edges: Edge[], edges: Edge[]
): Array<string> { ): Array<string> {
const clonedSelection = cloneDeep(selection); const clonedSelection = cloneDeep(selection);
const clonedEdges = cloneDeep(edges); const clonedEdges = cloneDeep(edges);
@ -750,7 +749,7 @@ export function validateSelection(
let nodesSet = new Set(clonedSelection.nodes.map((n) => n.id)); let nodesSet = new Set(clonedSelection.nodes.map((n) => n.id));
// then filter the edges that are connected to the nodes in the set // then filter the edges that are connected to the nodes in the set
let connectedEdges = clonedSelection.edges.filter( let connectedEdges = clonedSelection.edges.filter(
(e) => nodesSet.has(e.source) && nodesSet.has(e.target), (e) => nodesSet.has(e.source) && nodesSet.has(e.target)
); );
// add the edges to the selection // add the edges to the selection
clonedSelection.edges = connectedEdges; clonedSelection.edges = connectedEdges;
@ -764,17 +763,17 @@ export function validateSelection(
clonedSelection.nodes.some( clonedSelection.nodes.some(
(node) => (node) =>
isInputNode(node.data as NodeDataType) || isInputNode(node.data as NodeDataType) ||
isOutputNode(node.data as NodeDataType), isOutputNode(node.data as NodeDataType)
) )
) { ) {
errorsArray.push( errorsArray.push(
"Please select only nodes that are not input or output nodes", "Please select only nodes that are not input or output nodes"
); );
} }
//check if there are two or more nodes with free outputs //check if there are two or more nodes with free outputs
if ( if (
clonedSelection.nodes.filter( clonedSelection.nodes.filter(
(n) => !clonedSelection.edges.some((e) => e.source === n.id), (n) => !clonedSelection.edges.some((e) => e.source === n.id)
).length > 1 ).length > 1
) { ) {
errorsArray.push("Please select only one node with free outputs"); errorsArray.push("Please select only one node with free outputs");
@ -785,7 +784,7 @@ export function validateSelection(
clonedSelection.nodes.some( clonedSelection.nodes.some(
(node) => (node) =>
!clonedSelection.edges.some((edge) => edge.target === node.id) && !clonedSelection.edges.some((edge) => edge.target === node.id) &&
!clonedSelection.edges.some((edge) => edge.source === node.id), !clonedSelection.edges.some((edge) => edge.source === node.id)
) )
) { ) {
errorsArray.push("Please select only nodes that are connected"); errorsArray.push("Please select only nodes that are connected");
@ -842,8 +841,8 @@ export function mergeNodeTemplates({
nodeTemplate[key].display_name nodeTemplate[key].display_name
? nodeTemplate[key].display_name ? nodeTemplate[key].display_name
: nodeTemplate[key].name : nodeTemplate[key].name
? toTitleCase(nodeTemplate[key].name) ? toTitleCase(nodeTemplate[key].name)
: toTitleCase(key); : toTitleCase(key);
} }
} }
}); });
@ -854,7 +853,7 @@ function isHandleConnected(
edges: Edge[], edges: Edge[],
key: string, key: string,
field: TemplateVariableType, field: TemplateVariableType,
nodeId: string, nodeId: string
) { ) {
/* /*
this function receives a flow and a handleId and check if there is a connection with this handle this function receives a flow and a handleId and check if there is a connection with this handle
@ -870,7 +869,7 @@ function isHandleConnected(
id: nodeId, id: nodeId,
proxy: { id: field.proxy!.id, field: field.proxy!.field }, proxy: { id: field.proxy!.id, field: field.proxy!.field },
inputTypes: field.input_types, inputTypes: field.input_types,
} as targetHandleType), } as targetHandleType)
) )
) { ) {
return true; return true;
@ -885,7 +884,7 @@ function isHandleConnected(
fieldName: key, fieldName: key,
id: nodeId, id: nodeId,
inputTypes: field.input_types, inputTypes: field.input_types,
} as targetHandleType), } as targetHandleType)
) )
) { ) {
return true; return true;
@ -908,7 +907,7 @@ export function generateNodeTemplate(Flow: FlowType) {
export function generateNodeFromFlow( export function generateNodeFromFlow(
flow: FlowType, flow: FlowType,
getNodeId: (type: string) => string, getNodeId: (type: string) => string
): NodeType { ): NodeType {
const { nodes } = flow.data!; const { nodes } = flow.data!;
const outputNode = cloneDeep(findLastNode(flow.data!)); const outputNode = cloneDeep(findLastNode(flow.data!));
@ -939,7 +938,7 @@ export function generateNodeFromFlow(
export function connectedInputNodesOnHandle( export function connectedInputNodesOnHandle(
nodeId: string, nodeId: string,
handleId: string, handleId: string,
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] }, { nodes, edges }: { nodes: NodeType[]; edges: Edge[] }
) { ) {
const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> = const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> =
[]; [];
@ -976,7 +975,7 @@ export function connectedInputNodesOnHandle(
export function updateProxyIdsOnTemplate( export function updateProxyIdsOnTemplate(
template: APITemplateType, template: APITemplateType,
idsMap: { [key: string]: string }, idsMap: { [key: string]: string }
) { ) {
Object.keys(template).forEach((key) => { Object.keys(template).forEach((key) => {
if (template[key].proxy && idsMap[template[key].proxy!.id]) { if (template[key].proxy && idsMap[template[key].proxy!.id]) {
@ -987,7 +986,7 @@ export function updateProxyIdsOnTemplate(
export function updateEdgesIds( export function updateEdgesIds(
edges: Edge[], edges: Edge[],
idsMap: { [key: string]: string }, idsMap: { [key: string]: string }
) { ) {
edges.forEach((edge) => { edges.forEach((edge) => {
let targetHandle: targetHandleType = edge.data.targetHandle; let targetHandle: targetHandleType = edge.data.targetHandle;
@ -1014,7 +1013,7 @@ export function expandGroupNode(
nodes: Node[], nodes: Node[],
edges: Edge[], edges: Edge[],
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
) { ) {
const idsMap = updateIds(flow!.data!); const idsMap = updateIds(flow!.data!);
updateProxyIdsOnTemplate(template, idsMap); updateProxyIdsOnTemplate(template, idsMap);
@ -1057,7 +1056,7 @@ export function expandGroupNode(
const lastNode = cloneDeep(findLastNode(flow!.data!)); const lastNode = cloneDeep(findLastNode(flow!.data!));
newEdge.source = lastNode!.id; newEdge.source = lastNode!.id;
let newSourceHandle: sourceHandleType = scapeJSONParse( let newSourceHandle: sourceHandleType = scapeJSONParse(
newEdge.sourceHandle!, newEdge.sourceHandle!
); );
newSourceHandle.id = lastNode!.id; newSourceHandle.id = lastNode!.id;
newEdge.data.sourceHandle = newSourceHandle; newEdge.data.sourceHandle = newSourceHandle;
@ -1114,7 +1113,7 @@ export function expandGroupNode(
export function getGroupStatus( export function getGroupStatus(
flow: FlowType, flow: FlowType,
ssData: { [key: string]: { valid: boolean; params: string } }, ssData: { [key: string]: { valid: boolean; params: string } }
) { ) {
let status = { valid: true, params: SUCCESS_BUILD }; let status = { valid: true, params: SUCCESS_BUILD };
const { nodes } = flow.data!; const { nodes } = flow.data!;
@ -1133,7 +1132,7 @@ export function getGroupStatus(
export function createFlowComponent( export function createFlowComponent(
nodeData: NodeDataType, nodeData: NodeDataType,
version: string, version: string
): FlowType { ): FlowType {
const flowNode: FlowType = { const flowNode: FlowType = {
data: { data: {
@ -1169,7 +1168,7 @@ export function downloadNode(NodeFLow: FlowType) {
export function updateComponentNameAndType( export function updateComponentNameAndType(
data: any, data: any,
component: NodeDataType, component: NodeDataType
) {} ) {}
export function removeFileNameFromComponents(flow: FlowType) { export function removeFileNameFromComponents(flow: FlowType) {
@ -1243,7 +1242,7 @@ export function extractFieldsFromComponenents(data: APIObjectType) {
export function downloadFlow( export function downloadFlow(
flow: FlowType, flow: FlowType,
flowName: string, flowName: string,
flowDescription?: string, flowDescription?: string
) { ) {
let clonedFlow = cloneDeep(flow); let clonedFlow = cloneDeep(flow);
removeFileNameFromComponents(clonedFlow); removeFileNameFromComponents(clonedFlow);
@ -1253,7 +1252,7 @@ export function downloadFlow(
...clonedFlow, ...clonedFlow,
name: flowName, name: flowName,
description: flowDescription, description: flowDescription,
}), })
)}`; )}`;
// create a link element and set its properties // create a link element and set its properties
@ -1268,7 +1267,7 @@ export function downloadFlow(
export function downloadFlows() { export function downloadFlows() {
downloadFlowsFromDatabase().then((flows) => { downloadFlowsFromDatabase().then((flows) => {
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
JSON.stringify(flows), JSON.stringify(flows)
)}`; )}`;
// create a link element and set its properties // create a link element and set its properties
@ -1292,7 +1291,7 @@ export function getRandomDescription(): string {
export const createNewFlow = ( export const createNewFlow = (
flowData: ReactFlowJsonObject, flowData: ReactFlowJsonObject,
flow: FlowType, flow: FlowType,
folderId: string, folderId: string
) => { ) => {
return { return {
description: flow?.description ?? getRandomDescription(), description: flow?.description ?? getRandomDescription(),