From ac1d1a8d75f8212b58bca0b7d6050617e8c14338 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 05:08:19 +0300 Subject: [PATCH 01/15] fix: zoom optimization fix --- frontend/src/pages/Flow.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/frontend/src/pages/Flow.tsx b/frontend/src/pages/Flow.tsx index 07f831be..abc6009e 100755 --- a/frontend/src/pages/Flow.tsx +++ b/frontend/src/pages/Flow.tsx @@ -11,7 +11,7 @@ import { addEdge, reconnectEdge, useEdgesState, - useNodesState, + useNodesState } from "@xyflow/react" import React, { useCallback, useContext, useEffect, useRef, useState } from "react" @@ -372,7 +372,6 @@ export default function Flow() { edgeTypes={edgeTypes} nodes={nodes} edges={edges} - onMoveStart={handleFullUpdateFlowData} onMoveEnd={handleFullUpdateFlowData} panOnScroll={true} panOnScrollSpeed={1.5} @@ -385,15 +384,10 @@ export default function Flow() { onEdgesChange={onEdgesChange} onReconnect={onEdgeUpdate} onReconnectStart={onEdgeUpdateStart} - // onReconnectEnd={onEdgeUpdateEnd} onNodeDragStart={() => takeSnapshot()} onNodeDragStop={handleFullUpdateFlowData} onConnect={onConnect} - // onNodesDelete={onNodesDelete} - // onEdgesDelete={onEdgesDelete} onBeforeDelete={validateDeletion} - // onPaneMouseEnter={() => setDisableCopyPaste(false)} - // onPaneMouseLeave={() => setDisableCopyPaste(true)} edgesReconnectable={!managerMode} nodesConnectable={!managerMode} nodesDraggable={!managerMode} From 4cb0bbde89e854e8cf75e4f7583650d468c5eb7f Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 06:48:16 +0300 Subject: [PATCH 02/15] fix: validate node trigger update fix --- frontend/src/components/nodes/DefaultNode.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/nodes/DefaultNode.tsx b/frontend/src/components/nodes/DefaultNode.tsx index 5de21360..325395c4 100644 --- a/frontend/src/components/nodes/DefaultNode.tsx +++ b/frontend/src/components/nodes/DefaultNode.tsx @@ -36,7 +36,7 @@ const DefaultNode = memo(({ data }: { data: DefaultNodeDataType }) => { isOpen: isResponseOpen, } = useDisclosure() - const validate_node = useMemo(() => data.response?.data.length && data.conditions?.length, []) + const validate_node = useMemo(() => data.response?.data.length && data.conditions?.length, [data.conditions?.length, data.response?.data.length]) return ( <> From 2b1f6fcd7b11bf6421474cf0eef75afd93306e3d Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 06:48:27 +0300 Subject: [PATCH 03/15] fix: node data update fix --- frontend/src/modals/NodeModal/NodeModal.tsx | 16 ++------ frontend/src/pages/Flow.tsx | 45 +++++++++++++++------ 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/frontend/src/modals/NodeModal/NodeModal.tsx b/frontend/src/modals/NodeModal/NodeModal.tsx index 62bd52b7..a35567b7 100644 --- a/frontend/src/modals/NodeModal/NodeModal.tsx +++ b/frontend/src/modals/NodeModal/NodeModal.tsx @@ -36,7 +36,7 @@ const NodeModal = ({ nodeDataState, setNodeDataState, }: NodeModalProps) => { - const { getNodes, setNodes } = useReactFlow() + const { getNodes, setNodes, updateNodeData } = useReactFlow() const { quietSaveFlows, validateNodeDeletion } = useContext(flowContext) const { takeSnapshot } = useContext(undoRedoContext) @@ -64,18 +64,8 @@ const NodeModal = ({ } const onNodeSave = () => { - const nodes = getNodes() - const node = nodes.find((node) => node.data.id === data.id) - const new_nodes = nodes.map((node) => { - if (node.data.id === data.id) { - return { ...node, data: { ...node.data, ...nodeDataState } } - } - return node - }) - if (node) { - takeSnapshot() - setNodes(() => new_nodes) - } + takeSnapshot() + updateNodeData(data.id, { ...nodeDataState }) quietSaveFlows() onClose() } diff --git a/frontend/src/pages/Flow.tsx b/frontend/src/pages/Flow.tsx index abc6009e..79b4230d 100755 --- a/frontend/src/pages/Flow.tsx +++ b/frontend/src/pages/Flow.tsx @@ -11,7 +11,7 @@ import { addEdge, reconnectEdge, useEdgesState, - useNodesState + useNodesState, } from "@xyflow/react" import React, { useCallback, useContext, useEffect, useRef, useState } from "react" @@ -70,7 +70,8 @@ export default function Flow() { managerMode, } = useContext(workspaceContext) const { screenLoading } = useContext(MetaContext) - const { takeSnapshot, copy, paste, copiedSelection, setDisableCopyPaste, disableCopyPaste } = useContext(undoRedoContext) + const { takeSnapshot, copy, paste, copiedSelection, disableCopyPaste } = + useContext(undoRedoContext) const { flowId } = useParams() @@ -84,17 +85,31 @@ export default function Flow() { const isEdgeUpdateSuccess = useRef(false) const { notification: n } = useContext(NotificationsContext) - const handleUpdateFlowData = useCallback(() => { - if (reactFlowInstance && flow && flow.name === flowId) { - flow.data = reactFlowInstance.toObject() as ReactFlowJsonObject - updateFlow(flow) - } - }, [flow, flowId, reactFlowInstance, updateFlow]) + const handleUpdateFlowData = useCallback( + (nodes?: AppNode[], edges?: Edge[]) => { + if (reactFlowInstance && flow && flow.name === flowId) { + flow.data = reactFlowInstance.toObject() as ReactFlowJsonObject + if (nodes) { + flow.data.nodes = flow.data.nodes.map((node) => { + const curr_node = nodes.find((nd) => nd.id === node.id) + if (curr_node) { + return curr_node + } else { + return node + } + }) + } + updateFlow(flow) + } + }, + [flow, flowId, reactFlowInstance, updateFlow] + ) const handleFullUpdateFlowData = useCallback(() => { if (reactFlowInstance && flow && flow.name === flowId) { const _node = reactFlowInstance.getNodes()[0] if (_node && _node.id === flow.data.nodes[0].id) { + console.log(reactFlowInstance.toObject() as ReactFlowJsonObject) flow.data = reactFlowInstance.toObject() as ReactFlowJsonObject updateFlow(flow) } @@ -127,7 +142,11 @@ export default function Flow() { const onNodesChangeMod = useCallback( (nds: NodeChange[]) => { + console.log("nds change") if (nds) { + if (nds.every((nd) => nd.type === "replace")) { + handleUpdateFlowData(nds.map((nd) => nd.item)) + } nds .sort((nd1: NodeChange, nd2: NodeChange) => { if (nd1.type === "select" && nd2.type === "select") { @@ -137,6 +156,7 @@ export default function Flow() { } }) .forEach((nd) => { + console.log(nd) if (nd.type === "select") { if (nd.selected) { setSelectedNode(nd.id) @@ -150,7 +170,7 @@ export default function Flow() { } onNodesChange(nds) }, - [onNodesChange, setSelectedNode] + [handleUpdateFlowData, onNodesChange, setSelectedNode] ) const onEdgeUpdateStart = useCallback(() => { @@ -168,7 +188,7 @@ export default function Flow() { ) const onNodeClick = useCallback( - (event: React.MouseEvent, node: AppNode) => { + (_event: React.MouseEvent, node: AppNode) => { const node_ = node as AppNode setSelected(node_.id) setSelectedNode(node_.id) @@ -177,7 +197,7 @@ export default function Flow() { ) const onEdgeClick = useCallback( - (event: React.MouseEvent, edge: Edge) => { + (_event: React.MouseEvent, edge: Edge) => { setSelected(edge.id) }, [setSelected] @@ -276,7 +296,7 @@ export default function Flow() { ) const [mousePos, setMousePos] = useState({ x: 0, y: 0 }) - + useEffect(() => { const kbdHandler = (e: KeyboardEvent) => { if ((e.ctrlKey || e.metaKey) && e.key === "c" && !disableCopyPaste) { @@ -319,6 +339,7 @@ export default function Flow() { }, [ copiedSelection, copy, + disableCopyPaste, flow, flowId, flows, From e922a4faead49270a6faeb4a4678ca8bee84d76b Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 07:13:11 +0300 Subject: [PATCH 04/15] fix: link error state fix --- frontend/src/components/nodes/LinkNode.tsx | 30 +++++++++++++--------- frontend/src/types/NodeTypes.ts | 14 +--------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/nodes/LinkNode.tsx b/frontend/src/components/nodes/LinkNode.tsx index 3491faac..7c2e438f 100755 --- a/frontend/src/components/nodes/LinkNode.tsx +++ b/frontend/src/components/nodes/LinkNode.tsx @@ -19,7 +19,7 @@ import { Tooltip, useDisclosure, } from "@nextui-org/react" -import { Handle, Position } from "@xyflow/react" +import { Edge, Handle, Position, useReactFlow } from "@xyflow/react" import "@xyflow/react/dist/style.css" import classNames from "classnames" import { AlertTriangle, Link2, Trash2 } from "lucide-react" @@ -31,12 +31,14 @@ import { FlowType } from "../../types/FlowTypes" import { AppNode, LinkNodeDataType } from "../../types/NodeTypes" const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { + const { updateNodeData } = useReactFlow() const { onOpen, onClose, isOpen } = useDisclosure() const { flows, deleteNode } = useContext(flowContext) const [toFlow, setToFlow] = useState() const [toNode, setToNode] = useState() const [error, setError] = useState(false) - const [r, setR] = useState(0) + const [isConfigured, setIsConfigured] = useState(data.transition.is_configured ?? false) + // const [r, setR] = useState(0) const { notification: n } = useContext(NotificationsContext) // const { openPopUp } = useContext(PopUpContext) @@ -76,10 +78,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { ) useEffect(() => { - if (r === 0) { - return setR((r) => r + 1) - } - if (!TO_FLOW || !TO_NODE) { + if ((!TO_FLOW || !TO_NODE) && isConfigured) { setError(true) n.add({ message: `Link ${data.id} is broken! Please configure it again.`, @@ -104,8 +103,15 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { const onSave = () => { if (toFlow && toNode) { - data.transition.target_flow = toFlow.name - data.transition.target_node = toNode.data.id + updateNodeData(data.id, { + ...data, + transition: { + target_flow: toFlow.name, + target_node: toNode.data.id, + is_configured: true + } + }) + setIsConfigured(true) onClose() } } @@ -114,7 +120,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { <>
+ className={classNames(`default_node px-6 py-4`, error && "border-error",)}>
{ ID: {data.id} - {(!toFlow || !toNode) && ( + {((!toFlow || !toNode) && isConfigured) && ( @@ -155,7 +161,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => {
- {TO_FLOW ? TO_FLOW.name : "ERROR"} / {TO_NODE ? TO_NODE.data.name : "ERROR"} + {TO_FLOW ? TO_FLOW.name : isConfigured ? "ERROR" : ""} / {TO_NODE ? TO_NODE.data.name : isConfigured ? "ERROR" : ""}
@@ -176,7 +182,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { className='text-white' color='warning' radius='sm' - content='Link options is required to add a link'> + content='Link options is required for creating a link'> export type AppNodeDataType = DefaultNodeDataType | LinkNodeDataType -export type NodeDataType = { - id: string - name: string - flags?: string[] - conditions?: conditionType[] - global_conditions?: string[] - local_conditions?: string[] - transition: { - target_flow: string - target_node: string - } - response?: responseType -} export type NodeComponentType = { data: DefaultNodeDataType From 3aa27c4f7e217d56dad586cb2767203ad822b31a Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 10:09:03 +0300 Subject: [PATCH 05/15] fix: fallback background fix --- frontend/src/pages/Fallback.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/Fallback.tsx b/frontend/src/pages/Fallback.tsx index eb50bf0a..9ead175e 100644 --- a/frontend/src/pages/Fallback.tsx +++ b/frontend/src/pages/Fallback.tsx @@ -14,7 +14,7 @@ const Fallback = () => { return (
+ className='flex flex-col items-center justify-center w-screen h-screen bg-background'> Date: Mon, 2 Sep 2024 10:31:00 +0300 Subject: [PATCH 06/15] chore: consts update --- frontend/src/consts.tsx | 1 + frontend/src/contexts/flowContext.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/consts.tsx b/frontend/src/consts.tsx index 6b9f5048..23174d3d 100644 --- a/frontend/src/consts.tsx +++ b/frontend/src/consts.tsx @@ -161,6 +161,7 @@ export const FLOW_COLORS = [ "#FF9500", "#FFCC00", "#00CC99", + "#00AAAA", "#3300FF", "#7000FF", "#CC66CC", diff --git a/frontend/src/contexts/flowContext.tsx b/frontend/src/contexts/flowContext.tsx index cb848f7a..12e08ecc 100644 --- a/frontend/src/contexts/flowContext.tsx +++ b/frontend/src/contexts/flowContext.tsx @@ -14,7 +14,7 @@ import { NotificationsContext } from "./notificationsContext" const globalFlow: FlowType = { id: "GLOBAL", name: "Global", - description: "This is Global Flow", + description: "This is Global Flow. It will be able to use soon...", color: FLOW_COLORS[5], data: { nodes: [ From 7c25a8c75b20560181a308a077a9b16146cbc7b7 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 11:43:05 +0300 Subject: [PATCH 07/15] chore: add functions documentation to current components --- frontend/src/contexts/flowContext.tsx | 46 +++++++++++++++++++ .../src/contexts/notificationsContext.tsx | 28 ++++++++++- frontend/src/contexts/undoRedoContext.tsx | 27 +++++++---- frontend/src/pages/Flow.tsx | 26 +++++++++-- 4 files changed, 111 insertions(+), 16 deletions(-) diff --git a/frontend/src/contexts/flowContext.tsx b/frontend/src/contexts/flowContext.tsx index 12e08ecc..c09d1e88 100644 --- a/frontend/src/contexts/flowContext.tsx +++ b/frontend/src/contexts/flowContext.tsx @@ -111,10 +111,15 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { const { screenLoading } = useContext(MetaContext) useEffect(() => { + // set null reactFlowInstance before Init new flow setReactFlowInstance(null) setTab(flowId || "") }, [flowId]) + /** + * API flows get function + * @returns {FlowType[]} flows array + */ const getFlows = async () => { screenLoading.addScreenLoading() try { @@ -135,16 +140,24 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { } } + // initial get flows useEffect(() => { getFlows() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + /** + * + * @param {FlowType[]} flows flows to save array + */ const saveFlows = async (flows: FlowType[]) => { await save_flows(flows) setFlows(flows) } + /** + * quiet save flows function - saves flows automatically + */ const quietSaveFlows = async () => { setTimeout(async () => { console.log("quiet save flows") @@ -153,10 +166,18 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { }, 100) } + /** + * get updated flows function + */ const getLocaleFlows = useCallback(() => { return flows }, [flows]) + + /** + * Delete flow function + * @param {FlowType} flow delete this flow + */ const deleteFlow = useCallback( (flow: FlowType) => { const new_flows = flows.filter((f) => f.name !== flow.name) @@ -166,6 +187,10 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { [flows] ) + /** + * Update flow function + * @param {FlowType} flow updates this flow in local state + */ const updateFlow = useCallback( (flow: FlowType) => { const new_flows = flows.map((f) => (f.name === flow.name ? flow : f)) @@ -175,6 +200,13 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { [flows] ) + /** + * @async Validate object deletion function + * @param {AppNode[]} nodes nodes to check before deletion + * @param {Edge[]} edges edges to check before delete (unused) + * @returns {boolean} Promise(boolean is_deletion_valid value) + * ONLY FOR "OnBeforeDelete ReactFlow handler" + */ const validateDeletion = ({ nodes, edges }: { nodes: AppNode[]; edges: Edge[] }) => { const is_nodes_valid = nodes.every((node) => { if (node.type === "default_node" && node?.data.flags?.includes("start")) { @@ -196,6 +228,11 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { }) } + /** + * Validate node deletion function + * @param {AppNode} node node to check before deletion + * @returns {boolean} boolean is_deletion_valid value + */ const validateNodeDeletion = (node: AppNode) => { if (node.type === "default_node" && node.data.flags.includes("start")) { n.add({ title: "Warning!", message: "Can't delete start node", type: "warning" }) @@ -212,6 +249,9 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { return true } + /** + * @deprecated + */ const deleteNode = useCallback( (id: string) => { const flow = flows.find((flow) => flow.data.nodes.some((node) => node.id === id)) @@ -241,6 +281,9 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { [flowId, flows, n] ) + /** + * @deprecated + */ const deleteEdge = useCallback( (id: string) => { const flow = flows.find((flow) => flow.data.edges.some((edge) => edge.id === id)) @@ -258,6 +301,9 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { [flowId, flows] ) + /** + * @deprecated + */ const deleteObject = useCallback( (id: string) => { const flow_node = flows.find((flow) => flow.data.nodes.some((node) => node.id === id)) diff --git a/frontend/src/contexts/notificationsContext.tsx b/frontend/src/contexts/notificationsContext.tsx index d2e3f259..b100856c 100644 --- a/frontend/src/contexts/notificationsContext.tsx +++ b/frontend/src/contexts/notificationsContext.tsx @@ -47,6 +47,11 @@ export const NotificationsContext = createContext({ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => { const [notifications, setNotifications] = useLocalStorage("notifications", []) + /** + * This function returns notification toast classNames by notification type + * @param type notification type + * @returns notification toast classNames + */ const notificationTypeColor = (type: string) => { switch (type) { case "success": @@ -62,6 +67,11 @@ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => { } } + /** + * This function returns notification header text color by notification type + * @param type notification type + * @returns notification header text color + */ const notificationHeaderColor = (type: string) => { switch (type) { case "success": @@ -76,6 +86,12 @@ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => { return "text-neutral-500" } } + + /** + * This functions returns icon by notification type + * @param type notification type + * @returns icon by notification type + */ const notificationTypeIcon = (type: string) => { switch (type) { case "success": @@ -91,6 +107,11 @@ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => { } } + /** + * Create new notification function + * @param {createNotificationType} notification_object message, title, type, duration, timestamp, stack of notifications + * Calls new notification + */ const addNotification = ({ message, title, @@ -134,8 +155,11 @@ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => { ) } - const deleteNotification = (timestamp: number) => { - + /** + * Delete notification by timestamp (as id) function + * @param {number} timestamp as notification id + */ + const deleteNotification = (timestamp: number) => { setNotifications((prevNotifications) => prevNotifications.filter((notification) => notification.timestamp !== timestamp) ) diff --git a/frontend/src/contexts/undoRedoContext.tsx b/frontend/src/contexts/undoRedoContext.tsx index f6c78c21..cd5b58d4 100644 --- a/frontend/src/contexts/undoRedoContext.tsx +++ b/frontend/src/contexts/undoRedoContext.tsx @@ -28,14 +28,6 @@ type UseUndoRedoOptions = { enableShortcuts: boolean } -// type UseUndoRedo = (options?: UseUndoRedoOptions) => { -// undo: () => void -// redo: () => void -// takeSnapshot: () => void -// canUndo: boolean -// canRedo: boolean -// } - type HistoryItem = { nodes: Node[] edges: Edge[] @@ -78,6 +70,9 @@ export function UndoRedoProvider({ children }: { children: React.ReactNode }) { const { setNodes, setEdges, getNodes, getEdges } = useReactFlow() + /** + * Take snapshot for undo/redo functions + */ const takeSnapshot = useCallback(() => { // push the current graph to the past state if (tabIndex > -1) { @@ -101,6 +96,9 @@ export function UndoRedoProvider({ children }: { children: React.ReactNode }) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [getNodes, getEdges, past, future, flows, tab, setPast, setFuture, tabIndex]) + /** + * Undo function + */ const undo = useCallback(() => { // get the last state that we want to go back to const pastState = past[tabIndex][past[tabIndex].length - 1] @@ -126,6 +124,9 @@ export function UndoRedoProvider({ children }: { children: React.ReactNode }) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [setNodes, setEdges, getNodes, getEdges, future, past, setFuture, setPast, tabIndex]) + /** + * Redo function + */ const redo = useCallback(() => { const futureState = future[tabIndex][future[tabIndex].length - 1] @@ -183,6 +184,10 @@ export function UndoRedoProvider({ children }: { children: React.ReactNode }) { } }, [modalsOpened]) + /** + * Copy function + * @param selection last selection to copy + */ const copy = (selection: OnSelectionChangeParams) => { if (selection && (selection.nodes.length || selection.edges.length)) { setCopiedSelection(cloneDeep(selection)) @@ -202,7 +207,11 @@ export function UndoRedoProvider({ children }: { children: React.ReactNode }) { } } - // eslint-disable-next-line @typescript-eslint/no-unused-vars + /** + * Paste function + * @param selectionInstance last selection of nodes&edges + * @param position position of pasting nodes&edges + */ const paste = ( selectionInstance: OnSelectionChangeParams, position: { x: number; y: number; paneX?: number; paneY?: number } diff --git a/frontend/src/pages/Flow.tsx b/frontend/src/pages/Flow.tsx index 79b4230d..c75d34a5 100755 --- a/frontend/src/pages/Flow.tsx +++ b/frontend/src/pages/Flow.tsx @@ -72,9 +72,7 @@ export default function Flow() { const { screenLoading } = useContext(MetaContext) const { takeSnapshot, copy, paste, copiedSelection, disableCopyPaste } = useContext(undoRedoContext) - const { flowId } = useParams() - const flow = flows.find((flow: FlowType) => flow.name === flowId) const [nodes, setNodes, onNodesChange] = useNodesState(flow?.data.nodes || []) @@ -85,6 +83,11 @@ export default function Flow() { const isEdgeUpdateSuccess = useRef(false) const { notification: n } = useContext(NotificationsContext) + /** + * Function update flow data function translates reactFlowInstanceJSON to flow.data + * @param {AppNode[]} nodes optional changed nodes + * @param {Edge[]} edges optional changed edges + */ const handleUpdateFlowData = useCallback( (nodes?: AppNode[], edges?: Edge[]) => { if (reactFlowInstance && flow && flow.name === flowId) { @@ -105,17 +108,23 @@ export default function Flow() { [flow, flowId, reactFlowInstance, updateFlow] ) + /** + * Function update flow data function translates reactFlowInstanceJSON to flow.data + * With additional first node check + */ const handleFullUpdateFlowData = useCallback(() => { if (reactFlowInstance && flow && flow.name === flowId) { const _node = reactFlowInstance.getNodes()[0] if (_node && _node.id === flow.data.nodes[0].id) { - console.log(reactFlowInstance.toObject() as ReactFlowJsonObject) flow.data = reactFlowInstance.toObject() as ReactFlowJsonObject updateFlow(flow) } } }, [flow, flowId, reactFlowInstance, updateFlow]) + /** + * update flow.data when edges or nodes.length changed (no check nodes array) + * */ useEffect(() => { handleUpdateFlowData() // eslint-disable-next-line react-hooks/exhaustive-deps @@ -133,6 +142,10 @@ export default function Flow() { } }, [flow, flowId, reactFlowInstance, setEdges, setNodes]) + /** + * Initiate new reactFlowInstance object + * @param {CustomReactFlowInstanceType} e new reactFlowInstance object value + */ const onInit = useCallback( (e: CustomReactFlowInstanceType) => { setReactFlowInstance(e) @@ -144,6 +157,7 @@ export default function Flow() { (nds: NodeChange[]) => { console.log("nds change") if (nds) { + // only calls update flow data function when node change type = "replace" (no call when move) if (nds.every((nd) => nd.type === "replace")) { handleUpdateFlowData(nds.map((nd) => nd.item)) } @@ -175,13 +189,11 @@ export default function Flow() { const onEdgeUpdateStart = useCallback(() => { takeSnapshot() - isEdgeUpdateSuccess.current = false }, [takeSnapshot]) const onEdgeUpdate = useCallback( (oldEdge: Edge, newConnection: Connection) => { setEdges((els) => reconnectEdge(oldEdge, newConnection, els)) - isEdgeUpdateSuccess.current = true }, // eslint-disable-next-line react-hooks/exhaustive-deps [setEdges] @@ -297,6 +309,10 @@ export default function Flow() { const [mousePos, setMousePos] = useState({ x: 0, y: 0 }) + + /** + * Keyboard shortcuts handlers + */ useEffect(() => { const kbdHandler = (e: KeyboardEvent) => { if ((e.ctrlKey || e.metaKey) && e.key === "c" && !disableCopyPaste) { From ee55dddec160c2ca87abf0159532501c2476e963 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 11:59:58 +0300 Subject: [PATCH 08/15] chore: lint warnings done --- frontend/cypress.config.ts | 2 +- frontend/src/components/ModalComponent.tsx | 3 ++- frontend/src/components/nodes/DefaultNode.tsx | 1 + frontend/src/components/nodes/LinkNode.tsx | 2 ++ .../notifications/NotificationsWindow.tsx | 14 +------------- frontend/src/contexts/flowContext.tsx | 4 ++-- frontend/src/contexts/runContext.tsx | 2 +- frontend/src/contexts/workspaceContext.tsx | 5 +++++ frontend/src/icons/PlusFlagIcon.tsx | 7 ++++++- .../nodes/conditions/CustomConditionIcon.tsx | 2 +- .../src/modals/ConditionModal/ConditionModal.tsx | 2 +- frontend/src/modals/NodeModal/NodeModal.tsx | 2 +- .../src/modals/ResponseModal/ResponseModal.tsx | 3 +-- frontend/src/pages/Flow.tsx | 16 ++++++++-------- frontend/src/utils.ts | 2 +- 15 files changed, 34 insertions(+), 33 deletions(-) diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts index 17161e32..e1c55815 100644 --- a/frontend/cypress.config.ts +++ b/frontend/cypress.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from "cypress"; export default defineConfig({ e2e: { - setupNodeEvents(on, config) { + setupNodeEvents() { // implement node event listeners here }, }, diff --git a/frontend/src/components/ModalComponent.tsx b/frontend/src/components/ModalComponent.tsx index a1a5d9e1..33fa5386 100644 --- a/frontend/src/components/ModalComponent.tsx +++ b/frontend/src/components/ModalComponent.tsx @@ -3,7 +3,7 @@ import { useContext, useEffect, useState } from "react" import { workspaceContext } from "../contexts/workspaceContext" const ModalComponent = ({ ...props }: ModalProps) => { - const { setModalsOpened, modalsOpened } = useContext(workspaceContext) + const { setModalsOpened } = useContext(workspaceContext) const [isModalOpen, setIsModalOpen] = useState(false) @@ -24,6 +24,7 @@ const ModalComponent = ({ ...props }: ModalProps) => { setModalsOpened((prev) => prev + 1) } // Пустой массив зависимостей гарантирует, что этот эффект будет выполнен только один раз, после того как компонент был смонтирован + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) return {props.children} diff --git a/frontend/src/components/nodes/DefaultNode.tsx b/frontend/src/components/nodes/DefaultNode.tsx index 325395c4..fc225ff7 100644 --- a/frontend/src/components/nodes/DefaultNode.tsx +++ b/frontend/src/components/nodes/DefaultNode.tsx @@ -25,6 +25,7 @@ const DefaultNode = memo(({ data }: { data: DefaultNodeDataType }) => { isOpen: isConditionOpen, } = useDisclosure() + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { selectedNode } = useContext(workspaceContext) const [nodeDataState, setNodeDataState] = useState(data) diff --git a/frontend/src/components/nodes/LinkNode.tsx b/frontend/src/components/nodes/LinkNode.tsx index 7c2e438f..b17ebfc1 100755 --- a/frontend/src/components/nodes/LinkNode.tsx +++ b/frontend/src/components/nodes/LinkNode.tsx @@ -58,6 +58,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { if (!data.transition.target_node) { onOpen() } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [data.transition.target_node]) const handleFlowSelectionChange = (e: React.ChangeEvent) => { @@ -88,6 +89,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { } else { setError(false) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [TO_FLOW, TO_NODE]) const onDismiss = () => { diff --git a/frontend/src/components/notifications/NotificationsWindow.tsx b/frontend/src/components/notifications/NotificationsWindow.tsx index 31f1abb8..53e2fd08 100644 --- a/frontend/src/components/notifications/NotificationsWindow.tsx +++ b/frontend/src/components/notifications/NotificationsWindow.tsx @@ -16,20 +16,8 @@ type NotificationsWindowProps = { setIsOpen: React.Dispatch> } -// const getNotificationsStack = (notifications: notificationType[], index: number) => { -// const notification_instance: notificationType = notifications[index] -// let counter = 1 -// while ( -// notifications[index + counter]?.title === notification_instance?.title && -// notifications[index + counter]?.message === notification_instance?.message && -// notifications[index + counter]?.type === notification_instance?.type -// ) { -// counter += 1 -// } -// return counter -// } -export const NotificationsWindow = ({ isOpen, setIsOpen }: NotificationsWindowProps) => { +export const NotificationsWindow = ({ setIsOpen }: NotificationsWindowProps) => { const { notifications, notification } = useContext(NotificationsContext) const [notificationFilter, setNotificationFilter] = useState([]) diff --git a/frontend/src/contexts/flowContext.tsx b/frontend/src/contexts/flowContext.tsx index c09d1e88..ab18447f 100644 --- a/frontend/src/contexts/flowContext.tsx +++ b/frontend/src/contexts/flowContext.tsx @@ -204,10 +204,10 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => { * @async Validate object deletion function * @param {AppNode[]} nodes nodes to check before deletion * @param {Edge[]} edges edges to check before delete (unused) - * @returns {boolean} Promise(boolean is_deletion_valid value) + * @returns {Promise} Promise(boolean is_deletion_valid value) * ONLY FOR "OnBeforeDelete ReactFlow handler" */ - const validateDeletion = ({ nodes, edges }: { nodes: AppNode[]; edges: Edge[] }) => { + const validateDeletion = ({ nodes }: { nodes: AppNode[]; edges: Edge[] }): Promise => { const is_nodes_valid = nodes.every((node) => { if (node.type === "default_node" && node?.data.flags?.includes("start")) { n.add({ title: "Warning!", message: "Can't delete start node", type: "warning" }) diff --git a/frontend/src/contexts/runContext.tsx b/frontend/src/contexts/runContext.tsx index 96ccea4a..af20ab46 100644 --- a/frontend/src/contexts/runContext.tsx +++ b/frontend/src/contexts/runContext.tsx @@ -57,7 +57,7 @@ export const RunProvider = ({ children }: { children: React.ReactNode }) => { const [runPending, setRunPending] = useState(false) const [runStatus, setRunStatus] = useState("stopped") const [runs, setRuns] = useState([]) - const { setBuildsHandler, builds: context_builds } = useContext(buildContext) + const { setBuildsHandler } = useContext(buildContext) const { notification: n } = useContext(NotificationsContext) const setRunsHandler = (runs: runMinifyApiType[]) => { diff --git a/frontend/src/contexts/workspaceContext.tsx b/frontend/src/contexts/workspaceContext.tsx index fd40bffa..c2e948e6 100644 --- a/frontend/src/contexts/workspaceContext.tsx +++ b/frontend/src/contexts/workspaceContext.tsx @@ -67,6 +67,10 @@ export const WorkspaceProvider = ({ children }: { children: React.ReactNode }) = const [modalsOpened, setModalsOpened] = useState(0) const { notification: n } = useContext(NotificationsContext) + + /** + * Count opened modals for correct shortcuts work + */ useEffect(() => { if (modalsOpened === 0) { setMouseOnPane(true) @@ -78,6 +82,7 @@ export const WorkspaceProvider = ({ children }: { children: React.ReactNode }) = } }, [modalsOpened]) + const toggleWorkspaceMode = useCallback(() => { setWorkspaceMode(() => !workspaceMode) n.add({ diff --git a/frontend/src/icons/PlusFlagIcon.tsx b/frontend/src/icons/PlusFlagIcon.tsx index bee5067f..127bdbdc 100644 --- a/frontend/src/icons/PlusFlagIcon.tsx +++ b/frontend/src/icons/PlusFlagIcon.tsx @@ -1,8 +1,13 @@ import React from "react" -export const PlusFlagIcon = ({ fill="#00CC99", stroke="#00CC99", className }: React.SVGAttributes) => { +export const PlusFlagIcon = ({ + fill = "#00CC99", + stroke = "#00CC99", + className, +}: React.SVGAttributes) => { return ( ) => { +const CustomConditionIcon = ({ className, stroke="var(--foreground)" }: React.SVGAttributes) => { return ( () const { notification: n } = useContext(NotificationsContext) - const { updateFlow, flows, quietSaveFlows } = useContext(flowContext) + const { flows, quietSaveFlows } = useContext(flowContext) const { flowId } = useParams() const [currentCondition, setCurrentCondition] = useState( diff --git a/frontend/src/modals/NodeModal/NodeModal.tsx b/frontend/src/modals/NodeModal/NodeModal.tsx index a35567b7..d21cf9b6 100644 --- a/frontend/src/modals/NodeModal/NodeModal.tsx +++ b/frontend/src/modals/NodeModal/NodeModal.tsx @@ -49,7 +49,7 @@ const NodeModal = ({ (e: React.ChangeEvent) => { setNodeDataState({ ...nodeDataState, [e.target.name]: e.target.value }) }, - [nodeDataState] + [nodeDataState, setNodeDataState] ) const setTextResponseValue = (e: React.ChangeEvent) => { diff --git a/frontend/src/modals/ResponseModal/ResponseModal.tsx b/frontend/src/modals/ResponseModal/ResponseModal.tsx index 7041dc06..d2ab7e99 100644 --- a/frontend/src/modals/ResponseModal/ResponseModal.tsx +++ b/frontend/src/modals/ResponseModal/ResponseModal.tsx @@ -40,7 +40,7 @@ const ResponseModal = ({ size = "3xl", }: ResponseModalProps) => { const { getNode, setNodes, getNodes } = useReactFlow() - const { flows, quietSaveFlows, updateFlow } = useContext(flowContext) + const { flows, quietSaveFlows } = useContext(flowContext) const { flowId } = useParams() const [selected, setSelected] = useState(response.type ?? "python") // const [nodeDataState, setNodeDataState] = useState(data) @@ -89,7 +89,6 @@ const ResponseModal = ({ /> ), }), - // eslint-disable-next-line react-hooks/exhaustive-deps [currentResponse] ) diff --git a/frontend/src/pages/Flow.tsx b/frontend/src/pages/Flow.tsx index c75d34a5..bedf4825 100755 --- a/frontend/src/pages/Flow.tsx +++ b/frontend/src/pages/Flow.tsx @@ -13,7 +13,7 @@ import { useEdgesState, useNodesState, } from "@xyflow/react" -import React, { useCallback, useContext, useEffect, useRef, useState } from "react" +import React, { useCallback, useContext, useEffect, useState } from "react" import { a, useTransition } from "@react-spring/web" import "@xyflow/react/dist/style.css" @@ -80,7 +80,6 @@ export default function Flow() { const [selection, setSelection] = useState() const [selected, setSelected] = useState() - const isEdgeUpdateSuccess = useRef(false) const { notification: n } = useContext(NotificationsContext) /** @@ -95,11 +94,13 @@ export default function Flow() { if (nodes) { flow.data.nodes = flow.data.nodes.map((node) => { const curr_node = nodes.find((nd) => nd.id === node.id) - if (curr_node) { - return curr_node - } else { - return node - } + return curr_node ?? node + }) + } + if (edges) { + flow.data.edges = flow.data.edges.map((edge) => { + const curr_edge = edges.find(ed => ed.id === edge.id) + return curr_edge ?? edge }) } updateFlow(flow) @@ -195,7 +196,6 @@ export default function Flow() { (oldEdge: Edge, newConnection: Connection) => { setEdges((els) => reconnectEdge(oldEdge, newConnection, els)) }, - // eslint-disable-next-line react-hooks/exhaustive-deps [setEdges] ) diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts index bbafbfec..ca22bcc3 100644 --- a/frontend/src/utils.ts +++ b/frontend/src/utils.ts @@ -65,7 +65,7 @@ export const isNodeDeletionValid = (nodes: AppNode[], id: string) => { } export function delay(ms: number) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(resolve, ms) }) } From 637012bcbfac839cbc4293a812ce568647cea5d7 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 12:24:05 +0300 Subject: [PATCH 09/15] fix: typescript no build fix --- frontend/src/pages/Flow.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/Flow.tsx b/frontend/src/pages/Flow.tsx index bedf4825..945dbc5e 100755 --- a/frontend/src/pages/Flow.tsx +++ b/frontend/src/pages/Flow.tsx @@ -96,10 +96,10 @@ export default function Flow() { const curr_node = nodes.find((nd) => nd.id === node.id) return curr_node ?? node }) - } + } if (edges) { flow.data.edges = flow.data.edges.map((edge) => { - const curr_edge = edges.find(ed => ed.id === edge.id) + const curr_edge = edges.find((ed) => ed.id === edge.id) return curr_edge ?? edge }) } @@ -160,7 +160,16 @@ export default function Flow() { if (nds) { // only calls update flow data function when node change type = "replace" (no call when move) if (nds.every((nd) => nd.type === "replace")) { - handleUpdateFlowData(nds.map((nd) => nd.item)) + const update_nodes = nds + .filter((nd) => nd.type === "replace") + .map((nd) => { + if (nd.type === "replace") { + return nd.item + } + }) + if (update_nodes.every((nd) => nd !== undefined)) { + handleUpdateFlowData(update_nodes as AppNode[]) + } } nds .sort((nd1: NodeChange, nd2: NodeChange) => { @@ -309,9 +318,8 @@ export default function Flow() { const [mousePos, setMousePos] = useState({ x: 0, y: 0 }) - /** - * Keyboard shortcuts handlers + * Keyboard shortcuts handlers */ useEffect(() => { const kbdHandler = (e: KeyboardEvent) => { From 81e623afe669f759769d39dba792b0d81e6b5132 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 2 Sep 2024 17:26:52 +0800 Subject: [PATCH 10/15] chore: Update `bun.lockb` --- frontend/bun.lockb | Bin 457390 -> 457390 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/frontend/bun.lockb b/frontend/bun.lockb index 78d333fe07c163424e343384dfdc4c167a9ccf66..5dda435e2fb2e60cb0c0b8457f70ffeb570cba52 100755 GIT binary patch delta 40 ucmZ4YReIf5>4p}@7N!>FEiBCu9E@>>MtVki2JPJuEI`b4p}@7N!>FEiBCu983%l(B2)v0>rG_yCc|?7XbhmA`ET- From 396ec719109772369d5c76edd7c423f222587790 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 2 Sep 2024 20:45:59 +0800 Subject: [PATCH 11/15] chore: Provide make cmd to init_with_cc --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index b474d072..bff4b922 100644 --- a/Makefile +++ b/Makefile @@ -151,6 +151,11 @@ init_proj: install_backend_env ## Initiates a new project using chatsky-ui cd ${BACKEND_DIR} && poetry run chatsky.ui init --destination ../ +.PHONY: init_with_cc +init_with_cc: ## Initiates a new project using cookiecutter + cookiecutter https://github.com/Ramimashkouk/df_d_template.git + + .PHONY: build_docs build_docs: install_backend_env ## Builds the docs cd ${BACKEND_DIR} && \ From 6050cd0ff7668cc0b45bca410ce81e0f22bfb153 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 2 Sep 2024 20:46:19 +0800 Subject: [PATCH 12/15] update readme.md --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 764f1309..fce37cbc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Quick Start ## System Requirements -Ensure you have Python version 3.8 or higher installed. +Ensure you have Python version 3.8.1 or higher installed. ## Installation To install the necessary package, run the following command: @@ -13,7 +13,7 @@ You may add a `.env` file in the root directory and configure any of following e ```.env HOST=0.0.0.0 PORT=8000 -CONF_RELOAD=True +CONF_RELOAD=False LOG_LEVEL=info GRACEFUL_TERMINATION_TIMEOUT=2 # Waiting for process to stop @@ -25,6 +25,8 @@ RUN_RUNNING_TIMEOUT=5 ``` ## Project Initiation +💡 You are encouraged to run `chatsky.ui --help` to explore the available CLI options. + Initialize your project by running: ```bash chatsky.ui init @@ -32,7 +34,10 @@ chatsky.ui init The `chatsky.ui init` command will start an interactive `cookiecutter` process to create a project based on a predefined template. The resulting project will be a simple example template that you can customize to suit your needs. ## Running Your Project -To run your project, use the following command: +To start your project, use the following command: ```bash -chatsky.ui run_app --project-dir # enter the slug you choose for your project with the help of the previous command +chatsky.ui run_app --project-dir # Replace with the slug you specified during initialization ``` + +## Documentation +You can refer to the [documentaion](https://deeppavlov.github.io/chatsky-ui/) to dig into the application code understanding. From 347050c68b3169aa9d6c7c826e5921cc1158ae13 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 17:42:44 +0300 Subject: [PATCH 13/15] chore: add name input to the link modal --- frontend/src/components/nodes/LinkNode.tsx | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/nodes/LinkNode.tsx b/frontend/src/components/nodes/LinkNode.tsx index b17ebfc1..901cded5 100755 --- a/frontend/src/components/nodes/LinkNode.tsx +++ b/frontend/src/components/nodes/LinkNode.tsx @@ -1,5 +1,6 @@ import { Button, + Input, Modal, ModalBody, ModalContent, @@ -34,6 +35,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { const { updateNodeData } = useReactFlow() const { onOpen, onClose, isOpen } = useDisclosure() const { flows, deleteNode } = useContext(flowContext) + const [name, setName] = useState(data.name ?? "") const [toFlow, setToFlow] = useState() const [toNode, setToNode] = useState() const [error, setError] = useState(false) @@ -58,7 +60,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { if (!data.transition.target_node) { onOpen() } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [data.transition.target_node]) const handleFlowSelectionChange = (e: React.ChangeEvent) => { @@ -89,7 +91,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { } else { setError(false) } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [TO_FLOW, TO_NODE]) const onDismiss = () => { @@ -107,11 +109,12 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { if (toFlow && toNode) { updateNodeData(data.id, { ...data, + name: name, transition: { target_flow: toFlow.name, target_node: toNode.data.id, - is_configured: true - } + is_configured: true, + }, }) setIsConfigured(true) onClose() @@ -122,7 +125,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { <>
+ className={classNames(`default_node px-6 py-4`, error && "border-error")}>
{ ID: {data.id} - {((!toFlow || !toNode) && isConfigured) && ( + {(!toFlow || !toNode) && isConfigured && ( @@ -163,7 +166,8 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => {
- {TO_FLOW ? TO_FLOW.name : isConfigured ? "ERROR" : ""} / {TO_NODE ? TO_NODE.data.name : isConfigured ? "ERROR" : ""} + {TO_FLOW ? TO_FLOW.name : isConfigured ? "ERROR" : ""} /{" "} + {TO_NODE ? TO_NODE.data.name : isConfigured ? "ERROR" : ""}
@@ -195,6 +199,16 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => {
+
+ +
From 17828a209f22d637696c5bc70467e86d4bda04d2 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 17:47:40 +0300 Subject: [PATCH 14/15] chore: some link refactoring and functions documentation --- frontend/src/components/nodes/LinkNode.tsx | 24 +++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/nodes/LinkNode.tsx b/frontend/src/components/nodes/LinkNode.tsx index 901cded5..19b88878 100755 --- a/frontend/src/components/nodes/LinkNode.tsx +++ b/frontend/src/components/nodes/LinkNode.tsx @@ -40,12 +40,13 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { const [toNode, setToNode] = useState() const [error, setError] = useState(false) const [isConfigured, setIsConfigured] = useState(data.transition.is_configured ?? false) - // const [r, setR] = useState(0) const { notification: n } = useContext(NotificationsContext) - // const { openPopUp } = useContext(PopUpContext) + /** + * This useEffect checks if link configured + */ useEffect(() => { - if (data.transition.target_node) { + if (data.transition.is_configured) { const to_flow = flows.find((flow) => flow.data.nodes.some((node) => node.data.id === data.transition.target_node) ) @@ -57,7 +58,7 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { setToNode(to_node) } } - if (!data.transition.target_node) { + if (!data.transition.is_configured) { onOpen() } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -80,6 +81,9 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { [TO_FLOW?.data.nodes, data.transition.target_node] ) + /** + * This useEffect checks the TO_FLOW and TO_NODE values is correct, and calls error if not + */ useEffect(() => { if ((!TO_FLOW || !TO_NODE) && isConfigured) { setError(true) @@ -94,6 +98,9 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [TO_FLOW, TO_NODE]) + /** + * This function will delete current link if TO_FLOW and TO_NODE values wasn't defined + */ const onDismiss = () => { setToFlow(TO_FLOW) setToNode(TO_NODE) @@ -105,6 +112,9 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { } } + /** + * Link data save function + */ const onSave = () => { if (toFlow && toNode) { updateNodeData(data.id, { @@ -204,9 +214,9 @@ const LinkNode = memo(({ data }: { data: LinkNodeDataType }) => { label='Name' value={name} onValueChange={setName} - radius="sm" - variant="bordered" - labelPlacement="outside" + radius='sm' + variant='bordered' + labelPlacement='outside' />
From 29d278a472335e9e2e6b4a5876fee08ecc719037 Mon Sep 17 00:00:00 2001 From: MXerFix Date: Mon, 2 Sep 2024 17:53:30 +0300 Subject: [PATCH 15/15] fix: run status button color mini-fix --- frontend/src/components/header/BuildMenu.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/header/BuildMenu.tsx b/frontend/src/components/header/BuildMenu.tsx index 67452b26..0793fa89 100644 --- a/frontend/src/components/header/BuildMenu.tsx +++ b/frontend/src/components/header/BuildMenu.tsx @@ -13,7 +13,7 @@ import { parseSearchParams } from "../../utils" const BuildMenu = () => { const { buildStart, buildPending } = useContext(buildContext) const { chat, setChat } = useContext(chatContext) - const { runStart, runPending, runStatus, runStop, run } = useContext(runContext) + const { runStart, runPending, runStatus, runStop, run, setRunStatus } = useContext(runContext) const [searchParams, setSearchParams] = useSearchParams() return ( @@ -38,6 +38,7 @@ const BuildMenu = () => { style={{}} onClick={async () => { if (runStatus !== "alive") { + setRunStatus(() => 'running') await buildStart({ wait_time: 1, end_status: "success" }) await runStart({ end_status: "success", wait_time: 0 }) } else if (runStatus === "alive" && run) {