diff --git a/apps/http-backend/src/routes/userRoutes/userRoutes.ts b/apps/http-backend/src/routes/userRoutes/userRoutes.ts index e0e916b..ab1d441 100644 --- a/apps/http-backend/src/routes/userRoutes/userRoutes.ts +++ b/apps/http-backend/src/routes/userRoutes/userRoutes.ts @@ -68,8 +68,7 @@ router.post("/createAvaliableNode", async (req: AuthRequest, res: Response) => { } }); -router.get( - "/getAvailableNodes", +router.get("/getAvailableNodes", userMiddleware, async (req: AuthRequest, res: Response) => { if (!req.user) { @@ -94,8 +93,7 @@ router.get( } ); -router.post( - "/createTriggers", +router.post("/createAvaliableTriggers", userMiddleware, async (req: AuthRequest, res: Response) => { try { @@ -129,8 +127,7 @@ router.post( } ); -router.get( - "/getAvailableTriggers", +router.get("/getAvailableTriggers", userMiddleware, async (req: AuthRequest, res: Response) => { try { @@ -158,47 +155,44 @@ router.get( router.get('/getCredentials/:type', userMiddleware, - async (req: AuthRequest, res) => { - try { - console.log("user from getcredentials: ", req.user); - if (!req.user) { - return res.status(statusCodes.BAD_REQUEST).json({ - message: "User is not Loggedin", - }); - } - const userId = req.user.sub; - const type = req.params.type; - console.log(userId, " -userid"); - if (!type || !userId) { - return res.status(statusCodes.BAD_REQUEST).json({ - message: "Incorrect type Input", - }); - } - const executor = new GoogleSheetsNodeExecutor(); - const response = await executor.getAllCredentials(userId, type); - // console.log( typeof(response)); - // console.log("response: ",response) - const authUrl = typeof response === "string" ? response : null; - // console.log(authUrl); - - const credentials = response instanceof Object ? response : null; - // console.log(credentials) - if (authUrl) { - return res.status(statusCodes.OK).json({ - message: - "Credentials not found create credentials using this auth url", + async (req: AuthRequest, res) =>{ + try{ + console.log("user from getcredentials: ",req.user) + if(!req.user){ + return res.status(statusCodes.BAD_REQUEST).json({ + message: "User is not Loggedin" + }) + } + const userId = req.user.sub; + const type = req.params.type + console.log(userId," -userid") + if(!type || !userId){ + return res.status(statusCodes.BAD_REQUEST).json({ + message: "Incorrect type Input", + }); + } + const executor = new GoogleSheetsNodeExecutor() + const response = await executor.getAllCredentials(userId,type) + // console.log( typeof(response)); + // console.log("response: ",response) + const authUrl = typeof response === 'string' ? response : null + // console.log(authUrl); + + const credentials = response instanceof Object ? response : null + // console.log(credentials) + if(authUrl){ + return res.status(statusCodes.OK).json({ + message: "Credentials not found create credentials using this auth url", Data: authUrl, }); - } else - return res.status(statusCodes.OK).json({ + } + else return res.status(statusCodes.OK).json({ message: "Credentials Fetched succesfully", Data: credentials, }); - } catch (e) { - console.log( - "Error Fetching the credentials ", - e instanceof Error ? e.message : "Unkown reason" - ); + } + catch(e){ + console.log("Error Fetching the credentials ", e instanceof Error ? e.message : "Unkown reason"); return res .status(statusCodes.INTERNAL_SERVER_ERROR) .json({ message: "Internal server from fetching the credentials" }); @@ -206,8 +200,34 @@ router.get('/getCredentials/:type', } ); -router.post( - "/create/workflow", +router.get('/getAllCreds', userMiddleware, async(req: AuthRequest, res:Response) =>{ + try{ + if(!req.user){ + return res.status(statusCodes.BAD_REQUEST).json({ + message: "User is not Loggedin" + }) + } + const userId = req.user.sub; + const creds = await prismaClient.credential.findMany({ + where:{ userId: userId} + }) + if(creds){ + return res.status(statusCodes.OK).json({ + message: "Fetched all credentials of the User!", + data: creds + }) + } + } + catch(e){ + console.log("Error Fetching the credentials ", e instanceof Error ? e.message : "Unkown reason"); + return res + .status(statusCodes.INTERNAL_SERVER_ERROR) + .json({ message: "Internal server from fetching the credentials" }); + } +}) +// ----------------------------------- CREATE WORKFLOW --------------------------------- + +router.post("/create/workflow", userMiddleware, async (req: AuthRequest, res) => { try { @@ -257,8 +277,9 @@ router.post( } ); -router.get( - "/workflows", +// ------------------------------------ FETCHING WORKFLOWS ----------------------------------- + +router.get("/workflows", userMiddleware, async (req: AuthRequest, res: Response) => { try { @@ -286,8 +307,35 @@ router.get( } ); -router.get( - "/workflow/:workflowId", +router.get('/empty/workflow', userMiddleware, async(req:AuthRequest, res: Response)=>{ + try{ + if (!req.user) + return res + .status(statusCodes.UNAUTHORIZED) + .json({ message: "User is not logged in /not authorized" }); + const userId = req.user.id; + const workflow = await prismaClient.workflow.findFirst({ + where:{ + userId: userId, + isEmpty: true + }, + orderBy: { + createdAt: 'desc' + } + }) + return res + .status(statusCodes.OK) + .json({ message: "Workflow fetched succesful", Data: workflow }); + + }catch(e){ + console.log("The error is from getting wrkflows", e instanceof Error ? e.message : "UNKNOWN ERROR"); + + return res.status(statusCodes.INTERNAL_SERVER_ERROR).json({ + meesage: "Internal Server Error From getting workflows for the user", + }); + } +}) +router.get("/workflow/:workflowId", userMiddleware, async (req: AuthRequest, res: Response) => { try { diff --git a/apps/web/app/components/nodes/CreateWorkFlow.tsx b/apps/web/app/components/nodes/CreateWorkFlow.tsx index 503b69f..619ac7f 100644 --- a/apps/web/app/components/nodes/CreateWorkFlow.tsx +++ b/apps/web/app/components/nodes/CreateWorkFlow.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; import "@xyflow/react/dist/style.css"; -import { Background, Controls, ReactFlow } from "@xyflow/react"; +import { ReactFlow } from "@xyflow/react"; import PlaceholderNode from "./PlaceHolder"; import { TriggerNode } from "./TriggerNode"; @@ -15,6 +15,7 @@ import { createWorkflow, getEmptyWorkflow, getworkflowData } from "@/app/workflo import { useAppSelector } from '@/app/hooks/redux'; + interface NodeType { id: string; type: "placeholder" | "trigger" | "action"; @@ -38,7 +39,9 @@ export const CreateWorkFlow = () => { const [sidebarOpen, setSidebarOpen] = useState(false); const [actionSidebarOpen, setActionSidebarOpen] = useState(false); const [credType, setCredType] = useState(""); - const [loadSheet, setLoadSheet] = useState(false); + const [nodeIDType, setNodeIDType] = useState('') + const [loadSheet, setLoadSheet] = useState(false) + const [selectedNodeConfig, setSelectedNodeConfig] = useState(undefined); const dispatch = useDispatch(); const userId = useAppSelector(s=>s.user.userId) const workflowId = useAppSelector(s=>s.workflow.workflow_id) @@ -117,20 +120,35 @@ export const CreateWorkFlow = () => { ]); }; - useEffect(() => { - async function getEmptyWorkflowID() { - const workflow = await getEmptyWorkflow(); - - if (workflow) { - const { id, isEmpty } = workflow; - dispatch(workflowActions.setWorkflowId(id)); - dispatch(workflowActions.setWorkflowStatus(isEmpty)); - } else { - // const newWorkflow + useEffect(()=>{ + async function getEmptyWorkflowID(){ + const workflow = await getEmptyWorkflow() + + if(workflow){ + const {id, isEmpty} = workflow + dispatch(workflowActions.setWorkflowId(id)) + dispatch(workflowActions.setWorkflowStatus(isEmpty)) + } + else{ + if (!userId) return + const newWorkflow = await createWorkflow() + dispatch(workflowActions.setWorkflowId(newWorkflow.id)) + dispatch(workflowActions.setWorkflowStatus(newWorkflow.isEmpty)) } } - getEmptyWorkflowID(); - }, [dispatch]); + async function getWorkflowData(){ + if(!workflowId) return + const workflow = await getworkflowData(workflowId) + if(workflow.success){ + dispatch(workflowActions.setWorkflowStatus(false)) + dispatch(workflowActions.setWorkflowNodes(workflow.data.nodes)) + dispatch(workflowActions.setWorkflowTrigger(workflow.data.Trigger)) + // console.log(`workfklow from redux: ${workflow.data}`) + } + } + // if(!workflowId) getEmptyWorkflowID() + getWorkflowData(); + },[dispatch, userId, workflowId]) useEffect(()=>{ // Guard: only rebuild nodes/edges if there's actual stored data @@ -279,7 +297,8 @@ export const CreateWorkFlow = () => { nodeTypes={nodeTypes} nodes={nodes} edges={edges} - onNodeClick={async (event, node) => { + onNodeClick={async(event, node) => { + console.log("Node clicked:", node.id, node.type, node.data); if (node.type === "placeholder") { const hasTrigger = nodes.some((n) => n.type === "trigger"); if (hasTrigger) { @@ -288,26 +307,22 @@ export const CreateWorkFlow = () => { setSidebarOpen(true); } } - if (node.type === "action" || node.type === "trigger") { - if (node.data.name === "Google Sheet") { - console.log("sheet called"); - console.log(node.id); - // setNodeId("550e8400-e29b-41d4-a716-446655440000") - // getCredentials(node.data.type ? node.data.type : "") - // setNodeId(node.id.split("trigger-")[1] || "") - // if(cred) setLoadSheet(true) - setCredType( - node.data.type === "google_sheet" ? "google_oauth" : "" - ); - setLoadSheet(!loadSheet); - console.log("hook called"); + if(node.type === 'action' || node.type === 'trigger'){ + // Check by type instead of name (more reliable) + const nodeType = node.data.type?.toLowerCase() || ''; + if(nodeType.includes('google_sheet') || nodeType.includes('google sheet')){ + console.log("Google Sheet node clicked") + console.log("Node ID:", node.id) + setNodeIDType(node.id) + setCredType("google_oauth") + console.log("config from node: ", node.data.config) + setSelectedNodeConfig(node.data.config) + setLoadSheet(!loadSheet) + console.log("Form opened") } - } + } }} - > - - - + /> { onSelectAction={handleSelectAction} /> - {loadSheet && } + {loadSheet && + + } ); }; diff --git a/apps/web/app/workflow/lib/config.ts b/apps/web/app/workflow/lib/config.ts index c1d3645..26ff178 100644 --- a/apps/web/app/workflow/lib/config.ts +++ b/apps/web/app/workflow/lib/config.ts @@ -1,6 +1,7 @@ import { BACKEND_URL } from "@repo/common/zod"; import { GoogleSheetsNodeExecutor } from "@repo/nodes"; -import axios from "axios"; +import axios from "axios" +const date = new Date() export const getAvailableTriggers = async () => { try { const response = await axios.get( @@ -11,7 +12,7 @@ export const getAvailableTriggers = async () => { ); console.log(response.data.Data); console.log(response.data); - + const Data = JSON.stringify(response.data.Data); console.log(Data); console.log("This is the name from the", response.data.Data); @@ -24,20 +25,198 @@ export const getAvailableTriggers = async () => { } }; -export const getCredentials = async (type: string) => { - try { +export const getCredentials = async(type: string)=>{ + try{ + const response = await axios.get( `${BACKEND_URL}/user/getCredentials/${type}`, { withCredentials: true, } ); - console.log("response from config: ", response); - + console.log("response from config: ",response); + const Data = JSON.stringify(response.data.Data); return response.data.Data; - } catch (e) { + } + catch(e){ console.error("Error fetching credentials:", e); throw e; } -}; +} + +export const getAllCredentials = async()=>{ + try{ + const res = await axios.get(`${BACKEND_URL}/user/getAllCreds`, { + withCredentials: true + }) + const data = res.data.data + console.log("credentails: ",data) + return data + } + catch(e){ + console.error("Error fetching credentials:", e); + throw e; + } +} + + +export const getAllWorkflows = async()=>{ + try{ + const res = await axios.get(`${BACKEND_URL}/user/workflows`,{ + withCredentials: true + }) + const data = res.data.Data + console.log("workflows: ",data) + return data + }catch(e){ + console.error("Error fetching credentials:", e); + throw e; + } +} + +export const createWorkflow = async()=>{ + try{ + const response = await axios.post(`${BACKEND_URL}/user/create/workflow`, + { + Name:`workflow-${date.getTime()}`, + // UserId: userId, + Config: {} + },{ + headers: { + 'Content-Type': 'application/json' + }, + withCredentials: true + } + ) + + const workflow = response.data + console.log('new workflow: ',workflow) + return workflow.Data + }catch(e){ + console.error("Error in creating workflow:", e); + throw e; + } +} + +interface Triggercontext{ + // userId: formData.userId, + name: string, + workflowId: string, + node_Trigger: string, + config: { + credId: string, + operation: string, + spreadsheetId: string, + range: string, + sheetName: string, + }, + }; +export const createTrigger = async(context: Triggercontext)=>{ + try{ + console.log('Trigger context: ', context) + const response = await axios.post(`${BACKEND_URL}/user/create/trigger`, + { + Name: context.name, + AvailableTriggerID: context.node_Trigger, + Config: context.config, + WorkflowId: context.workflowId, + TriggerType:"" + }, + { + headers: {"Content-Type": "application/json"}, + withCredentials:true + }) + + const trigger = (response.data) + console.log('trigger created: ', trigger); + return { + success: true, + data: trigger + } + }catch(e){ + console.error("Error in creating Trigger:", e); + return { + success: false, + data: e instanceof Error ? e.message : `unknown error ${e}` + } + } +} + +interface Nodecontext{ + // userId: formData.userId, + name: string, + workflowId: string, + node_Trigger: string, + position? :number, + config: { + credId: string, + operation: string, + spreadsheetId: string, + range: string, + sheetName: string, + }, + }; +export const createNode = async(context: Nodecontext)=>{ + try{ + console.log('Node context: ', context) + + const response = await axios.post(`${BACKEND_URL}/user/create/node`,{ + + Name: context.name, + AvailableNodeId: context.node_Trigger, + WorkflowId: context.workflowId, + Config: context.config, + Position: context.position ? context.position : 0 + },{ + headers: {"Content-Type": "application/json"}, + withCredentials:true + }) + + const node = (response.data) + console.log('Node created: ', node); + return { + success: true, + data: node + } + + }catch(e){ + console.error("Error in creating Node:", e); + return {success: false, + data: e instanceof Error ? e.message : `unknown error ${e}` + }; + } +} + +export const getEmptyWorkflow = async()=>{ + try{ + const res = await axios.get(`${BACKEND_URL}/user/empty/workflow`,{ + withCredentials: true + }) + + const workflow = res.data.Data + return workflow + } + catch(e){ + console.error("Error in fetching workflows:", e); + throw e; + } +} + +export const getworkflowData = async(workflowId: string)=>{ + try{ + const res = await axios.get(`${BACKEND_URL}/user/workflow/${workflowId}`,{ + withCredentials: true + }) + console.log('workflow data includes trigger and nodes: ', res.data.Data ) + return { + success: true, + data: res.data.Data + } + }catch(e){ + console.error("Error in creating Node:", e); + return {success: false, + data: e instanceof Error ? e.message : `unknown error ${e}` + }; + } +} \ No newline at end of file