diff --git a/apps/http-backend/src/index.ts b/apps/http-backend/src/index.ts index 5c829d7..f6a39d4 100644 --- a/apps/http-backend/src/index.ts +++ b/apps/http-backend/src/index.ts @@ -33,7 +33,7 @@ app.use(cookieParser()); app.use("/user" , userRouter) app.use('/node', sheetRouter) -app.use('/oauth/google', googleAuth) // ← CHANGED THIS LINE! +app.use('/auth/google', googleAuth) // ← CHANGED THIS LINE! const PORT= 3002 diff --git a/apps/http-backend/tsconfig.tsbuildinfo b/apps/http-backend/tsconfig.tsbuildinfo index b0eadf1..cd93c21 100644 --- a/apps/http-backend/tsconfig.tsbuildinfo +++ b/apps/http-backend/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/index.ts","./src/routes/google_callback.ts","./src/routes/nodes.routes.ts","./src/routes/userRoutes/userMiddleware.ts","./src/routes/userRoutes/userRoutes.ts","./src/scheduler/token-scheduler.ts","./src/services/token-refresh.service.ts"],"version":"5.7.3"} \ No newline at end of file +{"root":["./src/index.ts","./src/routes/google_callback.ts","./src/routes/nodes.routes.ts","./src/routes/userroutes/usermiddleware.ts","./src/routes/userroutes/userroutes.ts","./src/scheduler/token-scheduler.ts","./src/services/token-refresh.service.ts"],"version":"5.7.3"} \ No newline at end of file diff --git a/apps/web/app/lib/api.ts b/apps/web/app/lib/api.ts index 0953af7..ade5c0f 100644 --- a/apps/web/app/lib/api.ts +++ b/apps/web/app/lib/api.ts @@ -90,4 +90,22 @@ export const api = { headers: { "Content-Type": "application/json" }, }), }, + google: { + getDocuments: async (CredentialId : string) => { + const data = await axios.get(`${BACKEND_URL}/node/getDocuments/${CredentialId}`,{ + withCredentials: true, + headers: {"Content-Type" : "application/json"}, + }) + + console.log(data.data.files) + return data.data.files + }, + getSheets: async (documentId: string, CredentialId: string) => { + const data = await axios.get(`${BACKEND_URL}/node/getSheets/${CredentialId}/${documentId}`,{ + withCredentials: true, + headers: {"Content-Type":"application/json"} + }) + return data.data.files.data + }, + } }; diff --git a/apps/web/app/lib/nodeConfigs/googleSheet.action.ts b/apps/web/app/lib/nodeConfigs/googleSheet.action.ts index b950ca9..01b4f84 100644 --- a/apps/web/app/lib/nodeConfigs/googleSheet.action.ts +++ b/apps/web/app/lib/nodeConfigs/googleSheet.action.ts @@ -6,7 +6,7 @@ export const googleSheetActionConfig: NodeConfig = { label: "Google Sheet", icon: "📊", description: "Read or write data to Google Sheets", - credentials: "google", // Requires Google OAuth + credentials: "google_oauth", // Requires Google OAuth fields: [ { @@ -18,20 +18,20 @@ export const googleSheetActionConfig: NodeConfig = { description: "Choose which Google account to use" }, { - name: "spreadsheetId", - label: "Spreadsheet", + name: "spreadsheetId", type: "dropdown", + label: "Spreadsheet", required: true, - description: "Select the Google Spreadsheet", - dependsOn: "credentialId" // Only show after credential is selected + dependsOn: "credentialId", // <-- This field depends on credentialId + fetchOptions: "google.getDocuments", // <-- API method to call }, { name: "sheetName", - label: "Sheet Name", - type: "dropdown", + type: "dropdown", + label: "Sheet", required: true, - description: "Select the specific sheet within the spreadsheet", - dependsOn: "spreadsheetId" // Only show after spreadsheet is selected + dependsOn: "spreadsheetId", + fetchOptions: "google.getSheets", }, { name: "action", @@ -45,6 +45,13 @@ export const googleSheetActionConfig: NodeConfig = { required: true, defaultValue: "read_rows", description: "What operation to perform on the sheet" + }, + { + name: "Range", + type: "text", + label: "range", + value: "A1:Z100", + required: true } ], diff --git a/apps/web/app/lib/types/node.types.ts b/apps/web/app/lib/types/node.types.ts index f81e7de..af60d83 100644 --- a/apps/web/app/lib/types/node.types.ts +++ b/apps/web/app/lib/types/node.types.ts @@ -28,7 +28,8 @@ export interface ConfigField { required?: boolean; defaultValue?: string | number | boolean; // Initial value if not set placeholder?: string; - + fetchOptions?: string, + value? : string, options?: Array<{ label: string; value: string | number }>; // For dropdowns dependsOn?: string; // Name of another field this depends on description?: string; // Help text for this field diff --git a/apps/web/app/workflow/lib/config.ts b/apps/web/app/workflow/lib/config.ts index 6cca46f..bbf7f57 100644 --- a/apps/web/app/workflow/lib/config.ts +++ b/apps/web/app/workflow/lib/config.ts @@ -37,7 +37,7 @@ export const getCredentials = async(type: string)=>{ console.log("response from config: ",response); const Data = JSON.stringify(response.data.Data); - return response.data.Data; + return response.data.data; } catch(e){ console.error("Error fetching credentials:", e); diff --git a/apps/web/app/workflows/[id]/components/ConfigModal.tsx b/apps/web/app/workflows/[id]/components/ConfigModal.tsx index 61018da..8e0eca1 100644 --- a/apps/web/app/workflows/[id]/components/ConfigModal.tsx +++ b/apps/web/app/workflows/[id]/components/ConfigModal.tsx @@ -5,6 +5,7 @@ import { HOOKS_URL } from "@repo/common/zod"; import { useAppSelector } from "@/app/hooks/redux"; import { toast } from "sonner"; import { useCredentials } from "@/app/hooks/useCredential"; +import { api } from "@/app/lib/api"; interface ConfigModalProps { isOpen: boolean; @@ -22,8 +23,36 @@ export default function ConfigModal({ workflowId, }: ConfigModalProps) { const [config, setConfig] = useState>({}); + const [dynamicOptions, setDynamicOptions] = useState>({}); const [loading, setLoading] = useState(false); const userId = useAppSelector((state) => state.user.userId) as string; + + const fetchOptionsMap: Record Promise> = { + "google.getDocuments" : ({credentialId}) => api.google.getDocuments(credentialId), + "google.getSheets" : ({spreadsheetId, credentialId}) => api.google.getSheets(spreadsheetId, credentialId) + } + + const handleFieldChange = async (fieldName: string, value: string, nodeConfig: any) => { + // Update config with new value + const updatedConfig = ({ ...config, [fieldName]: value }) + console.log(fieldName, " ", value, " ", nodeConfig) + console.log(config, "from handle field function - 1") + setConfig((prev) => ({ ...prev, [fieldName]: value })); + console.log(config, "from handle field fun - 2") + console.log({ ...config, [fieldName]: value }, "what we're setting") + // Find fields that depend on this field + const dependentFields = nodeConfig.fields.filter((f:any) => f.dependsOn === fieldName); + + for (const depField of dependentFields) { + const fetchFn = depField.fetchOptions ? fetchOptionsMap[depField.fetchOptions] : undefined; + console.log(fetchFn, "fecth FN") + if (fetchFn) { + const options = await fetchFn(updatedConfig); + // console.log(({ ...config, [depField.name]: options }), "optiops setting") + setDynamicOptions((prev) => ({ ...prev, [depField.name]: options })); + } + } +}; // console.log("This is the credential Data from config from backend" , config); // Fetch credentials with hook based on node config (google, etc) if appropriate let credType: string | null = null; @@ -53,7 +82,7 @@ export default function ConfigModal({ } }; - const renderField = (field: any) => { + const renderField = (field: any, nodeConfig: any) => { const fieldValue = config[field.name] || ""; if (field.type === "dropdown" && field.name === "credentialId") { @@ -68,12 +97,10 @@ export default function ConfigModal({ <> - setConfig({ - ...config, - [field.name]: e.target.value, - }) - } + onChange={async(e) => { + await handleFieldChange(field.name, e.target.value, nodeConfig); + }} className="w-full p-3 border border-gray-900 bg-black text-white rounded-md" required={field.required} > - {(field.options || []).map((opt: any) => ( - ))} @@ -154,7 +180,7 @@ export default function ConfigModal({ ); } - if (field.type === "textarea") { + if (field.type === "text") { return (