-
Notifications
You must be signed in to change notification settings - Fork 0
feat: integrate redux-persist for workflow state management #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,7 @@ app.use(cookieParser()); | |
|
|
||
| app.use("/user" , userRouter) | ||
| app.use('/node', sheetRouter) | ||
| app.use('/oauth/google', googleAuth) | ||
| app.use('/auth/google', googleAuth) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for old route references in the codebase
rg -n 'oauth/google' --type ts --type tsx --type js
# Search for new route references
rg -n 'auth/google' --type ts --type tsx --type jsRepository: Dev-Pross/BuildFlow Length of output: 118 🏁 Script executed: #!/bin/bash
# Search for old route references in the codebase (broader search)
echo "=== Searching for 'oauth/google' references ==="
rg -n 'oauth/google' -t ts -t js
echo -e "\n=== Searching for 'auth/google' references ==="
rg -n 'auth/google' -t ts -t js
echo -e "\n=== Checking the index.ts file context ==="
head -50 apps/http-backend/src/index.tsRepository: Dev-Pross/BuildFlow Length of output: 3051 🏁 Script executed: #!/bin/bash
# Check the googleAuth handler to see what routes it exposes
echo "=== Content of google_callback.ts ==="
cat -n apps/http-backend/src/routes/google_callback.ts
echo -e "\n=== Checking for any callback endpoint definitions ==="
rg -n 'callback|router\.' apps/http-backend/src/routes/google_callback.tsRepository: Dev-Pross/BuildFlow Length of output: 11672 Critical: Route change breaks OAuth callback flow—update GOOGLE_REDIRECT_URI environment variable. The Google OAuth route was moved from Update the 🤖 Prompt for AI Agents |
||
| app.use('/execute', execRouter) | ||
|
|
||
| const PORT= 3002 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -361,7 +361,7 @@ router.get( | |
| try { | ||
| if (!req.user) | ||
| return res | ||
| .status(statusCodes.BAD_GATEWAY) | ||
| .status(statusCodes.UNAUTHORIZED) | ||
| .json({ message: "User isnot logged in /not authorized" }); | ||
| const userId = req.user.sub; | ||
|
|
||
|
|
@@ -373,7 +373,7 @@ router.get( | |
| }, | ||
| include: { | ||
| Trigger: true, | ||
| nodes: { orderBy: { position: "asc" } }, | ||
| nodes: { orderBy: { stage: "asc" } }, | ||
| }, | ||
| }); | ||
| if (!getWorkflow) { | ||
|
|
@@ -441,6 +441,9 @@ router.put("/workflow/update", userMiddleware, async (req: AuthRequest, res: Res | |
| } | ||
| }) | ||
|
|
||
| //------------------------------------------ TRIGGER AND NODE CREATION ------------------------------ | ||
|
|
||
| //TRIGGER CREATION | ||
| router.post( | ||
| "/create/trigger", | ||
| userMiddleware, | ||
|
|
@@ -465,6 +468,7 @@ router.post( | |
| AvailableTriggerID: dataSafe.data.AvailableTriggerID, | ||
| config: dataSafe.data.Config, | ||
| workflowId: dataSafe.data.WorkflowId, | ||
| Position: dataSafe.data.Position || {} | ||
| // trigger type pettla db lo ledu aa column | ||
| }, | ||
| }); | ||
|
|
@@ -499,6 +503,7 @@ router.post( | |
| } | ||
| ); | ||
|
|
||
| //NODE CREATION | ||
| router.post( | ||
| "/create/node", | ||
| userMiddleware, | ||
|
|
@@ -510,7 +515,7 @@ router.post( | |
| }); | ||
| } | ||
| const data = req.body; | ||
| console.log(" from http-backeden", data); | ||
| // console.log(" from http-backeden", data); | ||
|
|
||
| const dataSafe = NodeSchema.safeParse(data); | ||
| console.log("The error is ", dataSafe.error); | ||
|
|
@@ -524,19 +529,18 @@ router.post( | |
| // Config must be valid JSON (not an empty string) | ||
| // const stage = dataSafe.data.Position | ||
| console.log("This is from the backend log of positions", dataSafe.data.position) | ||
| const { credentialId, ...restConfig } = dataSafe.data.Config; | ||
| const createdNode = await prismaClient.node.create({ | ||
| data: { | ||
| name: dataSafe.data.Name, | ||
| workflowId: dataSafe.data.WorkflowId, | ||
| config: restConfig || {}, | ||
| config: dataSafe.data.Config || {}, | ||
| stage: Number(dataSafe.data.stage ?? 0), | ||
| position: { | ||
| x: dataSafe.data.position.x, | ||
| y: dataSafe.data.position.y | ||
| }, | ||
| AvailableNodeID: dataSafe.data.AvailableNodeId, | ||
| CredentialsID: credentialId | ||
| CredentialsID: dataSafe.data.CredentialId | ||
| }, | ||
| }); | ||
|
|
||
|
|
@@ -556,8 +560,7 @@ router.post( | |
|
|
||
| // ------------------------- UPDATE NODES AND TRIGGES --------------------------- | ||
|
|
||
| router.put( | ||
| "/update/node", | ||
| router.put("/update/node", | ||
| userMiddleware, | ||
| async (req: AuthRequest, res: Response) => { | ||
| try { | ||
|
|
@@ -578,10 +581,11 @@ router.put( | |
| const updateNode = await prismaClient.node.update({ | ||
| where: { id: dataSafe.data.NodeId }, | ||
| data: { | ||
| position: dataSafe.data.position, | ||
| config: dataSafe.data.Config , | ||
| CredentialsID: dataSafe.data.Config?.credentialId || null | ||
| }, | ||
|
|
||
| ...(dataSafe.data.position !== undefined ? { position: dataSafe.data.position } : {}), | ||
| ...(dataSafe.data.Config !== undefined ? { config: dataSafe.data.Config } : {}), | ||
| ...(dataSafe.data.Config?.credentialId ? { CredentialsID: dataSafe.data.Config.credentialId } : {}) | ||
| } | ||
|
Comment on lines
+584
to
+588
|
||
| }); | ||
|
|
||
| if (updateNode) | ||
|
|
@@ -598,8 +602,7 @@ router.put( | |
| } | ||
| ); | ||
|
|
||
| router.put( | ||
| "/update/trigger", | ||
| router.put("/update/trigger", | ||
| userMiddleware, | ||
| async (req: AuthRequest, res: Response) => { | ||
| try { | ||
|
|
@@ -619,7 +622,9 @@ router.put( | |
| const updatedTrigger = await prismaClient.trigger.update({ | ||
| where: { id: dataSafe.data.TriggerId }, | ||
| data: { | ||
| config: dataSafe.data.Config, | ||
| ...(dataSafe.data.Config !== undefined ? { config: dataSafe.data.Config} : {}) , | ||
| ...(dataSafe.data.CredentialID !== undefined ? { CredentialsID: dataSafe.data.CredentialID} : {}), | ||
| ...(dataSafe.data.Position !== undefined ? {Position: dataSafe.data.Position} : {}) | ||
| }, | ||
| }); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,83 @@ | ||||||||||||||||||||||||||||||
| "use client" | ||||||||||||||||||||||||||||||
| import { useEffect, useState } from "react"; | ||||||||||||||||||||||||||||||
| import { useAppDispatch, useAppSelector } from "./redux"; | ||||||||||||||||||||||||||||||
| import { api } from "../lib/api"; | ||||||||||||||||||||||||||||||
| import { store } from "@/store"; | ||||||||||||||||||||||||||||||
| import { workflowActions } from "@/store/slices/workflowSlice"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type Status = "saved" | "error" | "saving" | ||||||||||||||||||||||||||||||
| export function useAutoSave(workflowId: string){ | ||||||||||||||||||||||||||||||
| const [saveStatus, setSaveStatus] = useState<Status>("saved") | ||||||||||||||||||||||||||||||
| const dispatch = useAppDispatch() | ||||||||||||||||||||||||||||||
| const isChangedState = useAppSelector(s=> s.workflow.isChanged) | ||||||||||||||||||||||||||||||
| const hasUnChanged = isChangedState.trigger || isChangedState.edges || isChangedState.nodes; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const displayStatus = saveStatus === 'saving' ? 'Saving...' : | ||||||||||||||||||||||||||||||
| saveStatus === 'error' ? 'Save Error' : | ||||||||||||||||||||||||||||||
| hasUnChanged ? 'Unsaved Changes' : 'Saved' | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const batchSave = async()=>{ | ||||||||||||||||||||||||||||||
| const { data, isChanged, changedNodeIds } = store.getState().workflow | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const anyChanges = isChanged.edges || isChanged.nodes || isChanged.trigger; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if(!anyChanges || !data.workflowId) return; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| setSaveStatus("saving") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try{ | ||||||||||||||||||||||||||||||
| if(isChanged.nodes && data.nodes){ | ||||||||||||||||||||||||||||||
| const changedNodes = data.nodes.filter(n => changedNodeIds.includes(n.NodeId)) | ||||||||||||||||||||||||||||||
| await Promise.all( | ||||||||||||||||||||||||||||||
| changedNodes.map(node => api.nodes.update({ | ||||||||||||||||||||||||||||||
| NodeId: node.NodeId, | ||||||||||||||||||||||||||||||
| Config: node.Config, | ||||||||||||||||||||||||||||||
| position: node.position | ||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| if(isChanged.trigger){ | ||||||||||||||||||||||||||||||
| const trigger = data.trigger; | ||||||||||||||||||||||||||||||
| if(trigger) | ||||||||||||||||||||||||||||||
| await api.triggers.update({ | ||||||||||||||||||||||||||||||
| TriggerId: trigger.TriggerId, | ||||||||||||||||||||||||||||||
| Config: trigger.Config, | ||||||||||||||||||||||||||||||
| Position: trigger.position | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| if(isChanged.edges){ | ||||||||||||||||||||||||||||||
| const edges = data.edges; | ||||||||||||||||||||||||||||||
| if(edges) | ||||||||||||||||||||||||||||||
| await api.workflows.put({workflowId: workflowId,edges}) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| setSaveStatus("saved") | ||||||||||||||||||||||||||||||
| dispatch(workflowActions.markSynced()) | ||||||||||||||||||||||||||||||
| }catch(e){ | ||||||||||||||||||||||||||||||
| setSaveStatus("error") | ||||||||||||||||||||||||||||||
| console.error("error while auto saving: ", e instanceof Error ? e.message : "") | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| useEffect(()=>{ | ||||||||||||||||||||||||||||||
| const interval = setInterval(batchSave,30000); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const handleBeforeUnload = (e: BeforeUnloadEvent) =>{ | ||||||||||||||||||||||||||||||
| const { isChanged } = store.getState().workflow | ||||||||||||||||||||||||||||||
| if(isChanged.edges || isChanged.nodes || isChanged.trigger){ | ||||||||||||||||||||||||||||||
| e.preventDefault() | ||||||||||||||||||||||||||||||
| batchSave(); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+64
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Async
Consider using Alternative: warn only, don't attempt async save const handleBeforeUnload = (e: BeforeUnloadEvent) =>{
const { isChanged } = store.getState().workflow
if(isChanged.edges || isChanged.nodes || isChanged.trigger){
e.preventDefault()
- batchSave();
+ // Browser will show "unsaved changes" dialog
+ // Async save won't complete before unload; rely on interval/manual save
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| window.addEventListener("beforeunload", handleBeforeUnload) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return ()=>{ | ||||||||||||||||||||||||||||||
| clearInterval(interval); | ||||||||||||||||||||||||||||||
| window.removeEventListener("beforeunload", handleBeforeUnload) | ||||||||||||||||||||||||||||||
| batchSave() | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+74
to
+78
|
||||||||||||||||||||||||||||||
| }, [workflowId]) | ||||||||||||||||||||||||||||||
|
Comment on lines
+74
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cleanup effect calls async When the component unmounts, React won't wait for the Additionally, 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return { saveStatus, batchSave, displayStatus} | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing the mounted OAuth router path to
/auth/googleappears to break existing OAuth URLs/redirect URIs that still use/oauth/google/...(e.g.apps/http-backend/src/routes/google_callback.tsdefaults tohttp://localhost:3002/oauth/google/callback). Please update the redirect URI defaults and any frontend/back-end links to match the new mount path (or keep the old path as an alias).