diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 8b76fc243..eab8a4246 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -121,7 +121,7 @@ export default function ParameterComponent({ debouncedHandleUpdateValues, setNode, renderTooltips, - setIsLoading + setIsLoading, ); const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass( @@ -130,7 +130,7 @@ export default function ParameterComponent({ takeSnapshot, setNode, updateNodeInternals, - renderTooltips + renderTooltips, ); const { handleRefreshButtonPress: handleRefreshButtonPressHook } = @@ -139,7 +139,7 @@ export default function ParameterComponent({ let disabled = edges.some( (edge) => - edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id) + edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id), ) ?? false; const handleRefreshButtonPress = async (name, data) => { @@ -152,12 +152,12 @@ export default function ParameterComponent({ handleUpdateValues, setNode, renderTooltips, - setIsLoading + setIsLoading, ); const handleOnNewValue = async ( newValue: string | string[] | boolean | Object[], - skipSnapshot: boolean | undefined = false + skipSnapshot: boolean | undefined = false, ): Promise => { handleOnNewValueHook(newValue, skipSnapshot); }; @@ -196,10 +196,11 @@ export default function ParameterComponent({ } } - // If optionalHandle is an empty list, then it is not an optional handle - if (optionalHandle && optionalHandle.length === 0) { - optionalHandle = null; - } + useEffect(() => { + if (optionalHandle && optionalHandle.length === 0) { + optionalHandle = null; + } + }, [optionalHandle]); useEffect(() => { renderTooltips(); @@ -239,7 +240,7 @@ export default function ParameterComponent({ className={classNames( left ? "my-12 -ml-0.5 " : " my-12 -mr-0.5 ", "h-3 w-3 rounded-full border-2 bg-background", - !showNode ? "mt-0" : "" + !showNode ? "mt-0" : "", )} style={{ borderColor: color ?? nodeColors.unknown, @@ -309,7 +310,7 @@ export default function ParameterComponent({ "h-5 w-5 rounded-md", displayOutputPreview && !unknownOutput ? " hover:bg-secondary-foreground/5 hover:text-medium-indigo" - : " cursor-not-allowed text-muted-foreground" + : " cursor-not-allowed text-muted-foreground", )} name={"ScanEye"} /> @@ -359,7 +360,7 @@ export default function ParameterComponent({ } className={classNames( left ? "-ml-0.5" : "-mr-0.5", - "h-3 w-3 rounded-full border-2 bg-background" + "h-3 w-3 rounded-full border-2 bg-background", )} style={{ borderColor: color ?? nodeColors.unknown }} onClick={() => setFilterEdge(groupedEdge.current)} diff --git a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx index cf392872c..953305c84 100644 --- a/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx +++ b/src/frontend/src/alerts/alertDropDown/components/singleAlertComponent/index.tsx @@ -13,7 +13,7 @@ export default function SingleAlert({ return ( - output.data.message || (!output.data.message && output.artifacts) + output.data.message || (!output.data.message && output.artifacts), ) .map((output, index) => { try { @@ -138,7 +138,7 @@ export default function ChatView({ function updateChat( chat: ChatMessageType, message: string, - stream_url?: string + stream_url?: string, ) { chat.message = message; updateFlowPool(chat.componentId, { @@ -154,7 +154,7 @@ export default function ChatView({ setIsDragging, setFiles, currentFlowId, - setErrorData + setErrorData, ); return ( @@ -204,7 +204,7 @@ export default function ChatView({ {CHAT_FIRST_INITIAL_TEXT}{" "} {" "} diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index e68592efa..5ad04b0ae 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -191,11 +191,9 @@ export default function CodeAreaModal({ (error?.detail?.error !== undefined ? "h-2/6" : "h-0") } > -
-

- {error?.detail?.error} -

-
+
+

{error?.detail?.error}

+
{error?.detail?.traceback} diff --git a/src/frontend/src/modals/editNodeModal/index.tsx b/src/frontend/src/modals/editNodeModal/index.tsx index 05a3a4354..cb6f82f59 100644 --- a/src/frontend/src/modals/editNodeModal/index.tsx +++ b/src/frontend/src/modals/editNodeModal/index.tsx @@ -25,7 +25,7 @@ const EditNodeModal = forwardRef( // setOpenWDoubleClick: (open: boolean) => void; data: NodeDataType; }, - ref + ref, ) => { const myData = useRef(cloneDeep(data)); @@ -53,7 +53,7 @@ const EditNodeModal = forwardRef( handleOnNewValue, handleOnChangeDb, changeAdvanced, - open + open, ); const [gridApi, setGridApi] = useState(null); @@ -78,9 +78,11 @@ const EditNodeModal = forwardRef( {data.type} - - ID: {data.id} - +
+ + ID: {data.id} + +
@@ -117,7 +119,7 @@ const EditNodeModal = forwardRef( /> ); - } + }, ); export default EditNodeModal; diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 797fb0368..f5600a22d 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -59,22 +59,21 @@ export default function Page({ flow: FlowType; view?: boolean; }): JSX.Element { - const preventDefault = true; const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); const autoSaveCurrentFlow = useFlowsManagerStore( - (state) => state.autoSaveCurrentFlow + (state) => state.autoSaveCurrentFlow, ); const types = useTypesStore((state) => state.types); const templates = useTypesStore((state) => state.templates); const setFilterEdge = useFlowStore((state) => state.setFilterEdge); const reactFlowWrapper = useRef(null); const [showCanvas, setSHowCanvas] = useState( - Object.keys(templates).length > 0 && Object.keys(types).length > 0 + Object.keys(templates).length > 0 && Object.keys(types).length > 0, ); const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance); const setReactFlowInstance = useFlowStore( - (state) => state.setReactFlowInstance + (state) => state.setReactFlowInstance, ); const nodes = useFlowStore((state) => state.nodes); const edges = useFlowStore((state) => state.edges); @@ -91,10 +90,10 @@ export default function Page({ const paste = useFlowStore((state) => state.paste); const resetFlow = useFlowStore((state) => state.resetFlow); const lastCopiedSelection = useFlowStore( - (state) => state.lastCopiedSelection + (state) => state.lastCopiedSelection, ); const setLastCopiedSelection = useFlowStore( - (state) => state.setLastCopiedSelection + (state) => state.setLastCopiedSelection, ); const onConnect = useFlowStore((state) => state.onConnect); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); @@ -117,7 +116,7 @@ export default function Page({ clonedSelection!, clonedNodes, clonedEdges, - getRandomName() + getRandomName(), ); const newGroupNode = generateNodeFromFlow(newFlow, getNodeId); const newEdges = reconnectEdges(newGroupNode, removedEdges); @@ -125,8 +124,8 @@ export default function Page({ ...clonedNodes.filter( (oldNodes) => !clonedSelection?.nodes.some( - (selectionNode) => selectionNode.id === oldNodes.id - ) + (selectionNode) => selectionNode.id === oldNodes.id, + ), ), newGroupNode, ]); @@ -136,8 +135,8 @@ export default function Page({ !clonedSelection!.nodes.some( (selectionNode) => selectionNode.id === oldEdge.target || - selectionNode.id === oldEdge.source - ) + selectionNode.id === oldEdge.source, + ), ), ...newEdges, ]); @@ -179,17 +178,17 @@ export default function Page({ }, []); function handleUndo(e: KeyboardEvent) { - e.preventDefault(); - (e as unknown as Event).stopImmediatePropagation(); if (!isWrappedWithClass(e, "noundo")) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); undo(); } } function handleRedo(e: KeyboardEvent) { - e.preventDefault(); - (e as unknown as Event).stopImmediatePropagation(); if (!isWrappedWithClass(e, "noundo")) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); redo(); } } @@ -213,55 +212,52 @@ export default function Page({ { x: position.current.x, y: position.current.y, - } + }, ); } } function handleCopy(e: KeyboardEvent) { - e.preventDefault(); - (e as unknown as Event).stopImmediatePropagation(); - if ( - !isWrappedWithClass(e, "nocopy") && - window.getSelection()?.toString().length === 0 && - lastSelection - ) { - setLastCopiedSelection(_.cloneDeep(lastSelection)); + if (!isWrappedWithClass(e, "nocopy")) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + if (window.getSelection()?.toString().length === 0 && lastSelection) { + setLastCopiedSelection(_.cloneDeep(lastSelection)); + } } } function handleCut(e: KeyboardEvent) { - e.preventDefault(); - (e as unknown as Event).stopImmediatePropagation(); - if ( - !isWrappedWithClass(e, "nocopy") && - window.getSelection()?.toString().length === 0 && - lastSelection - ) { - setLastCopiedSelection(_.cloneDeep(lastSelection), true); + if (!isWrappedWithClass(e, "nocopy")) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + if (window.getSelection()?.toString().length === 0 && lastSelection) { + setLastCopiedSelection(_.cloneDeep(lastSelection), true); + } } } function handlePaste(e: KeyboardEvent) { - e.preventDefault(); - (e as unknown as Event).stopImmediatePropagation(); - if ( - !isWrappedWithClass(e, "nocopy") && - window.getSelection()?.toString().length === 0 && - lastCopiedSelection - ) { - takeSnapshot(); - paste(lastCopiedSelection, { - x: position.current.x, - y: position.current.y, - }); + if (!isWrappedWithClass(e, "nocopy")) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); + if ( + window.getSelection()?.toString().length === 0 && + lastCopiedSelection + ) { + takeSnapshot(); + paste(lastCopiedSelection, { + x: position.current.x, + y: position.current.y, + }); + } } } function handleDelete(e: KeyboardEvent) { - e.preventDefault(); - (e as unknown as Event).stopImmediatePropagation(); if (!isWrappedWithClass(e, "nodelete") && lastSelection) { + e.preventDefault(); + (e as unknown as Event).stopImmediatePropagation(); takeSnapshot(); deleteNode(lastSelection.nodes.map((node) => node.id)); deleteEdge(lastSelection.edges.map((edge) => edge.id)); @@ -277,27 +273,27 @@ export default function Page({ const cutAction = useShortcutsStore((state) => state.cut); const pasteAction = useShortcutsStore((state) => state.paste); //@ts-ignore - useHotkeys(undoAction, handleUndo, { preventDefault }); + useHotkeys(undoAction, handleUndo); //@ts-ignore - useHotkeys(redoAction, handleRedo, { preventDefault }); + useHotkeys(redoAction, handleRedo); //@ts-ignore - useHotkeys(groupAction, handleGroup, { preventDefault }); + useHotkeys(groupAction, handleGroup); //@ts-ignore - useHotkeys(duplicate, handleDuplicate, { preventDefault }); + useHotkeys(duplicate, handleDuplicate); //@ts-ignore - useHotkeys(copyAction, handleCopy, { preventDefault }); + useHotkeys(copyAction, handleCopy); //@ts-ignore - useHotkeys(cutAction, handleCut, { preventDefault }); + useHotkeys(cutAction, handleCut); //@ts-ignore - useHotkeys(pasteAction, handlePaste, { preventDefault }); + useHotkeys(pasteAction, handlePaste); //@ts-ignore - useHotkeys(deleteAction, handleDelete, { preventDefault }); + useHotkeys(deleteAction, handleDelete); //@ts-ignore - useHotkeys("delete", handleDelete, { preventDefault }); + useHotkeys("delete", handleDelete); useEffect(() => { setSHowCanvas( - Object.keys(templates).length > 0 && Object.keys(types).length > 0 + Object.keys(templates).length > 0 && Object.keys(types).length > 0, ); }, [templates, types]); @@ -306,7 +302,7 @@ export default function Page({ takeSnapshot(); onConnect(params); }, - [takeSnapshot, onConnect] + [takeSnapshot, onConnect], ); const onNodeDragStart: NodeDragHandler = useCallback(() => { @@ -347,7 +343,7 @@ export default function Page({ // Extract the data from the drag event and parse it as a JSON object const data: { type: string; node?: APIClassType } = JSON.parse( - event.dataTransfer.getData("nodedata") + event.dataTransfer.getData("nodedata"), ); const newId = getNodeId(data.type); @@ -363,7 +359,7 @@ export default function Page({ }; paste( { nodes: [newNode], edges: [] }, - { x: event.clientX, y: event.clientY } + { x: event.clientX, y: event.clientY }, ); } else if (event.dataTransfer.types.some((types) => types === "Files")) { takeSnapshot(); @@ -392,7 +388,7 @@ export default function Page({ } }, // Specify dependencies for useCallback - [getNodeId, setNodes, takeSnapshot, paste] + [getNodeId, setNodes, takeSnapshot, paste], ); const onEdgeUpdateStart = useCallback(() => { @@ -408,7 +404,7 @@ export default function Page({ setEdges((els) => updateEdge(oldEdge, newConnection, els)); } }, - [setEdges] + [setEdges], ); const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => { @@ -441,7 +437,7 @@ export default function Page({ (flow: OnSelectionChangeParams): void => { setLastSelection(flow); }, - [] + [], ); const onPaneClick = useCallback((flow) => { diff --git a/src/frontend/src/style/applies.css b/src/frontend/src/style/applies.css index fe51b6af4..8a015dd3d 100644 --- a/src/frontend/src/style/applies.css +++ b/src/frontend/src/style/applies.css @@ -411,7 +411,7 @@ } .error-build-message { - @apply mt-6 w-96 cursor-pointer rounded-md bg-error-background p-4 shadow-xl; + @apply mt-6 w-96 rounded-md bg-error-background p-4 shadow-xl; } .error-build-message-circle { @apply alert-icon text-status-red; diff --git a/src/frontend/src/style/classes.css b/src/frontend/src/style/classes.css index 55ab7a4cc..8a98fa09e 100644 --- a/src/frontend/src/style/classes.css +++ b/src/frontend/src/style/classes.css @@ -97,10 +97,6 @@ select:-webkit-autofill:focus { background-color: #141924 !important; } -.grabbing { - cursor: grabbing; -} - -.react-flow__node { - cursor: grab; +.react-flow__node.dragging * { + cursor: grabbing !important; } diff --git a/src/frontend/src/style/index.css b/src/frontend/src/style/index.css index 522162e3b..9a35b45aa 100644 --- a/src/frontend/src/style/index.css +++ b/src/frontend/src/style/index.css @@ -32,6 +32,7 @@ --error-background: #fef2f2; --error-foreground: #991b1b; + --error: #991b1b; --success-background: #f0fdf4; --success-foreground: #14532d; @@ -111,6 +112,7 @@ --error-foreground: #fef2f2; --error-background: #450a0a; + --error: #991b1b; --info-foreground: #eff6ff; --info-background: #172554; diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js index a97e4cec0..02ba4460b 100644 --- a/src/frontend/tailwind.config.js +++ b/src/frontend/tailwind.config.js @@ -64,8 +64,11 @@ module.exports = { "dark-blue": "var(--dark-blue)", "dark-gray": "var(--dark-gray)", "dark-red": "var(--dark-red)", - "error-background": "var(--error-background)", - "error-foreground": "var(--error-foreground)", + error: { + DEFAULT: "var(--error)", + background: "var(--error-background)", + foreground: "var(--error-foreground)", + }, "high-dark-gray": "var(--high-dark-gray)", "high-indigo": "var(--high-indigo)", "high-light-gray": "var(--high-light-gray)", diff --git a/src/frontend/tests/end-to-end/actionsMainPage.spec.ts b/src/frontend/tests/end-to-end/actionsMainPage.spec.ts index 9ebc39753..d14feb50a 100644 --- a/src/frontend/tests/end-to-end/actionsMainPage.spec.ts +++ b/src/frontend/tests/end-to-end/actionsMainPage.spec.ts @@ -89,6 +89,11 @@ test("search components", async ({ page }) => { } await page.getByRole("heading", { name: "Basic Prompting" }).click(); + await page.getByTitle("fit view").click(); + await page.getByTitle("zoom out").click(); + await page.getByTitle("zoom out").click(); + await page.getByTitle("zoom out").click(); + await page.getByText("Chat Input").first().click(); await page.getByTestId("more-options-modal").click(); @@ -152,6 +157,11 @@ test("user should be able to download a flow or a component", async ({ } await page.getByRole("heading", { name: "Basic Prompting" }).click(); + await page.getByTitle("fit view").click(); + await page.getByTitle("zoom out").click(); + await page.getByTitle("zoom out").click(); + await page.getByTitle("zoom out").click(); + await page.getByText("Chat Input", { exact: true }).click(); await page.getByTestId("more-options-modal").click(); @@ -224,6 +234,12 @@ test("user should be able to duplicate a flow or a component", async ({ } await page.getByRole("heading", { name: "Basic Prompting" }).click(); + + await page.getByTitle("fit view").click(); + await page.getByTitle("zoom out").click(); + await page.getByTitle("zoom out").click(); + await page.getByTitle("zoom out").click(); + await page.getByText("Chat Input", { exact: true }).click(); await page.getByTestId("more-options-modal").click(); diff --git a/src/frontend/tests/end-to-end/chatInputOutput.spec.ts b/src/frontend/tests/end-to-end/chatInputOutput.spec.ts index 17cc25efb..aa43bfa8a 100644 --- a/src/frontend/tests/end-to-end/chatInputOutput.spec.ts +++ b/src/frontend/tests/end-to-end/chatInputOutput.spec.ts @@ -62,7 +62,7 @@ test("chat_io_teste", async ({ page }) => { // Click and hold on the first element await page .locator( - '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[2]/div/div[2]/div[10]/button/div/div' + '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[2]/div/div[2]/div[8]/button/div/div' ) .hover(); await page.mouse.down(); @@ -70,7 +70,7 @@ test("chat_io_teste", async ({ page }) => { // Move to the second element await page .locator( - '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[1]/div/div[2]/div[4]/div/button/div/div' + '//*[@id="react-flow-id"]/div/div[1]/div[1]/div/div[2]/div[1]/div/div[2]/div[3]/div/button/div/div' ) .hover(); diff --git a/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts b/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts index 89a066415..9393a2cb7 100644 --- a/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts +++ b/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts @@ -1,5 +1,7 @@ import { expect, test } from "@playwright/test"; +import * as dotenv from "dotenv"; import { readFileSync } from "fs"; +import path from "path"; test("user must interact with chat with Input/Output", async ({ page }) => { if (!process.env.CI) { diff --git a/src/frontend/tests/end-to-end/generalBugs.spec.ts b/src/frontend/tests/end-to-end/generalBugs.spec.ts index 49ac0af65..104023a38 100644 --- a/src/frontend/tests/end-to-end/generalBugs.spec.ts +++ b/src/frontend/tests/end-to-end/generalBugs.spec.ts @@ -1,4 +1,6 @@ import { expect, test } from "@playwright/test"; +import * as dotenv from "dotenv"; +import path from "path"; test("should interact with api request", async ({ page }) => { await page.goto("/"); diff --git a/src/frontend/tests/end-to-end/group.spec.ts b/src/frontend/tests/end-to-end/group.spec.ts index 5cf1607ee..ff58e7a9c 100644 --- a/src/frontend/tests/end-to-end/group.spec.ts +++ b/src/frontend/tests/end-to-end/group.spec.ts @@ -26,6 +26,10 @@ test.describe("group node test", () => { .click(); await page.waitForTimeout(2000); await page.getByLabel("fit view").first().click(); + + await page.getByTestId("title-OpenAI").click(); + await page.getByTestId("title-OpenAI").click({ modifiers: ["Control"] }); + await page.getByTestId("title-Prompt").click({ modifiers: ["Control"] }); await page.getByTestId("title-OpenAI").click({ modifiers: ["Control"] }); await page.getByRole("button", { name: "Group" }).click(); diff --git a/src/frontend/tests/end-to-end/logs.spec.ts b/src/frontend/tests/end-to-end/logs.spec.ts index 38310e2e3..9d3c0120b 100644 --- a/src/frontend/tests/end-to-end/logs.spec.ts +++ b/src/frontend/tests/end-to-end/logs.spec.ts @@ -50,13 +50,16 @@ test("should able to see and interact with logs", async ({ page }) => { await page.getByRole("gridcell").first().isVisible(); await page.getByText("Messages", { exact: true }).click(); - await page.getByText("Index").isVisible(); - await page.getByText("Timestamp").isVisible(); - await page.getByText("Flow Id", { exact: true }).isVisible(); - await page.getByText("Source").isVisible(); - await page.getByText("Target", { exact: true }).isVisible(); - await page.getByText("Target Args", { exact: true }).isVisible(); - await page.getByText("Status", { exact: true }).isVisible(); - await page.getByText("Error", { exact: true }).isVisible(); + await page.getByText("index", { exact: true }).last().isVisible(); + await page.getByText("timestamp", { exact: true }).isVisible(); + await page.getByText("flow_id", { exact: true }).isVisible(); + await page.getByText("source", { exact: true }).isVisible(); + await page.getByText("target", { exact: true }).isVisible(); + await page.getByText("vertex_id", { exact: true }).isVisible(); + await page.getByText("status", { exact: true }).isVisible(); + await page.getByText("error", { exact: true }).isVisible(); + await page.getByText("outputs", { exact: true }).isVisible(); + await page.getByText("inputs", { exact: true }).isVisible(); + await page.getByRole("gridcell").first().isVisible(); });