diff --git a/server/src/models/Robot.ts b/server/src/models/Robot.ts index ed9d7780..a48b9af1 100644 --- a/server/src/models/Robot.ts +++ b/server/src/models/Robot.ts @@ -19,6 +19,11 @@ interface RobotAttributes { id: string; recording_meta: RobotMeta; recording: RobotWorkflow; + google_sheet_email?: string | null; + google_sheet_name?: string | null; + google_sheet_id?: string | null; + google_access_token?: string | null; + google_refresh_token?: string | null; } interface RobotCreationAttributes extends Optional { } @@ -27,6 +32,11 @@ class Robot extends Model implements R public id!: string; public recording_meta!: RobotMeta; public recording!: RobotWorkflow; + public google_sheet_email!: string | null; + public google_sheet_name?: string | null; + public google_sheet_id?: string | null; + public google_access_token!: string | null; + public google_refresh_token!: string | null; } Robot.init( @@ -44,6 +54,26 @@ Robot.init( type: DataTypes.JSONB, allowNull: false, }, + google_sheet_email: { + type: DataTypes.STRING, + allowNull: true, + }, + google_sheet_name: { + type: DataTypes.STRING, + allowNull: true, + }, + google_sheet_id: { + type: DataTypes.STRING, + allowNull: true, + }, + google_access_token: { + type: DataTypes.STRING, + allowNull: true, + }, + google_refresh_token: { + type: DataTypes.STRING, + allowNull: true, + }, }, { sequelize, diff --git a/server/src/models/User.ts b/server/src/models/User.ts index b50c1e0f..5a3d552c 100644 --- a/server/src/models/User.ts +++ b/server/src/models/User.ts @@ -12,7 +12,6 @@ interface UserAttributes { proxy_password?: string | null; } -// Optional fields for creating a new user interface UserCreationAttributes extends Optional { } class User extends Model implements UserAttributes { diff --git a/server/src/routes/auth.ts b/server/src/routes/auth.ts index 170831a5..697a1129 100644 --- a/server/src/routes/auth.ts +++ b/server/src/routes/auth.ts @@ -1,9 +1,11 @@ import { Router, Request, Response } from 'express'; import User from '../models/User'; +import Robot from '../models/Robot'; import jwt from 'jsonwebtoken'; import { hashPassword, comparePassword } from '../utils/auth'; import { requireSignIn } from '../middlewares/auth'; import { genAPIKey } from '../utils/api'; +import { google } from 'googleapis'; export const router = Router(); interface AuthenticatedRequest extends Request { @@ -163,3 +165,192 @@ router.delete('/delete-api-key', requireSignIn, async (req, res) => { return res.status(500).json({ message: 'Error deleting API key', error: error.message }); } }); + +const oauth2Client = new google.auth.OAuth2( + process.env.GOOGLE_CLIENT_ID, + process.env.GOOGLE_CLIENT_SECRET, + process.env.GOOGLE_REDIRECT_URI +); + +// Step 1: Redirect to Google for authentication +router.get('/google', (req, res) => { + const { robotId } = req.query; + if (!robotId) { + return res.status(400).json({ message: 'Robot ID is required' }); + } + const scopes = [ + 'https://www.googleapis.com/auth/spreadsheets', + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/drive.readonly', + ]; + const url = oauth2Client.generateAuthUrl({ + access_type: 'offline', + prompt: 'consent', // Ensures you get a refresh token on first login + scope: scopes, + state: robotId.toString(), + }); + res.redirect(url); +}); + +// Step 2: Handle Google OAuth callback +router.get('/google/callback', requireSignIn, async (req, res) => { + const { code, state } = req.query; + try { + if (!state) { + return res.status(400).json({ message: 'Robot ID is required' }); + } + + const robotId = state + + // Get access and refresh tokens + if (typeof code !== 'string') { + return res.status(400).json({ message: 'Invalid code' }); + } + const { tokens } = await oauth2Client.getToken(code); + oauth2Client.setCredentials(tokens); + + // Get user profile from Google + const oauth2 = google.oauth2({ version: 'v2', auth: oauth2Client }); + const { data: { email } } = await oauth2.userinfo.get(); + + if (!email) { + return res.status(400).json({ message: 'Email not found' }); + } + + // Get the currently authenticated user (from `requireSignIn`) + let user = await User.findOne({ where: { id: req.user.id } }); + + if (!user) { + return res.status(400).json({ message: 'User not found' }); + } + + let robot = await Robot.findOne({ where: { 'recording_meta.id': robotId } }); + + if (!robot) { + return res.status(400).json({ message: 'Robot not found' }); + } + + robot = await robot.update({ + google_sheet_email: email, + google_access_token: tokens.access_token, + google_refresh_token: tokens.refresh_token, + }); + + // List user's Google Sheets from their Google Drive + const drive = google.drive({ version: 'v3', auth: oauth2Client }); + const response = await drive.files.list({ + q: "mimeType='application/vnd.google-apps.spreadsheet'", // List only Google Sheets files + fields: 'files(id, name)', // Retrieve the ID and name of each file + }); + + const files = response.data.files || []; + if (files.length === 0) { + return res.status(404).json({ message: 'No spreadsheets found.' }); + } + + // Generate JWT token for session + const jwtToken = jwt.sign({ userId: user.id }, process.env.JWT_SECRET as string, { expiresIn: '12h' }); + res.cookie('token', jwtToken, { httpOnly: true }); + + res.json({ + message: 'Google authentication successful', + google_sheet_email: robot.google_sheet_email, + jwtToken, + files + }); + } catch (error: any) { + res.status(500).json({ message: `Google OAuth error: ${error.message}` }); + } +}); + +// Step 3: Get data from Google Sheets +router.post('/gsheets/data', requireSignIn, async (req, res) => { + const { spreadsheetId, robotId } = req.body; + const user = await User.findByPk(req.user.id, { raw: true }); + + if (!user) { + return res.status(400).json({ message: 'User not found' }); + } + + const robot = await Robot.findOne({ where: { 'recording_meta.id': robotId }, raw: true }); + + if (!robot) { + return res.status(400).json({ message: 'Robot not found' }); + } + + // Set Google OAuth credentials + oauth2Client.setCredentials({ + access_token: robot.google_access_token, + refresh_token: robot.google_refresh_token, + }); + + const sheets = google.sheets({ version: 'v4', auth: oauth2Client }); + + try { + // Fetch data from the spreadsheet (you can let the user choose a specific range too) + const sheetData = await sheets.spreadsheets.values.get({ + spreadsheetId, + range: 'Sheet1!A1:D5', // Default range, could be dynamic based on user input + }); + res.json(sheetData.data); + } catch (error: any) { + res.status(500).json({ message: `Error accessing Google Sheets: ${error.message}` }); + } +}); + +// Step 4: Get user's Google Sheets files (new route) +router.get('/gsheets/files', requireSignIn, async (req, res) => { + try { + const robotId = req.query.robotId; + const robot = await Robot.findOne({ where: { 'recording_meta.id': robotId }, raw:true }); + + if (!robot) { + return res.status(400).json({ message: 'Robot not found' }); + } + + oauth2Client.setCredentials({ + access_token: robot.google_access_token, + refresh_token: robot.google_refresh_token, + }); + + // List user's Google Sheets files from their Google Drive + const drive = google.drive({ version: 'v3', auth: oauth2Client }); + const response = await drive.files.list({ + q: "mimeType='application/vnd.google-apps.spreadsheet'", + fields: 'files(id, name)', + }); + + const files = response.data.files || []; + if (files.length === 0) { + return res.status(404).json({ message: 'No spreadsheets found.' }); + } + + res.json(files); + } catch (error: any) { + console.log('Error fetching Google Sheets files:', error); + res.status(500).json({ message: `Error retrieving Google Sheets files: ${error.message}` }); + } +}); + +// Step 5: Update robot's google_sheet_id when a Google Sheet is selected +router.post('/gsheets/update', requireSignIn, async (req, res) => { + const { spreadsheetId, spreadsheetName, robotId } = req.body; + + if (!spreadsheetId || !robotId) { + return res.status(400).json({ message: 'Spreadsheet ID and Robot ID are required' }); + } + + try { + let robot = await Robot.findOne({ where: { 'recording_meta.id': robotId } }); + + if (!robot) { + return res.status(404).json({ message: 'Robot not found' }); + } + + await robot.update({ google_sheet_id: spreadsheetId, google_sheet_name: spreadsheetName }); + + res.json({ message: 'Robot updated with selected Google Sheet ID' }); + } catch (error: any) { + res.status(500).json({ message: `Error updating robot: ${error.message}` }); + } +}); diff --git a/server/src/routes/storage.ts b/server/src/routes/storage.ts index e7e92e64..ada5acdd 100644 --- a/server/src/routes/storage.ts +++ b/server/src/routes/storage.ts @@ -12,7 +12,7 @@ import { requireSignIn } from '../middlewares/auth'; import Robot from '../models/Robot'; import Run from '../models/Run'; import { BinaryOutputService } from '../storage/mino'; -import { workflowQueue } from '../worker'; +// import { workflowQueue } from '../worker'; export const router = Router(); @@ -37,6 +37,23 @@ router.get('/recordings', requireSignIn, async (req, res) => { } }); +/** + * GET endpoint for getting a recording. + */ +router.get('/recordings/:id', requireSignIn, async (req, res) => { + try { + const data = await Robot.findOne({ + where: { 'recording_meta.id': req.params.id }, + raw: true + } + ); + return res.send(data); + } catch (e) { + logger.log('info', 'Error while reading recordings'); + return res.send(null); + } +}) + /** * DELETE endpoint for deleting a recording from the storage. */ @@ -202,13 +219,17 @@ router.post('/runs/run/:id', requireSignIn, async (req, res) => { serializableOutput: interpretationInfo.serializableOutput, binaryOutput: uploadedBinaryOutput, }); - googleSheetUpdateTasks[req.params.id] = { - name: plainRun.name, - runId: plainRun.runId, - status: 'pending', - retries: 5, - }; - processGoogleSheetUpdates(); + try { + googleSheetUpdateTasks[plainRun.runId] = { + robotId: plainRun.robotMetaId, + runId: plainRun.runId, + status: 'pending', + retries: 5, + }; + processGoogleSheetUpdates(); + } catch (err: any) { + logger.log('error', `Failed to update Google Sheet for run: ${plainRun.runId}: ${err.message}`); + } return res.send(true); } else { throw new Error('Could not destroy browser'); @@ -282,16 +303,16 @@ router.put('/schedule/:id/', requireSignIn, async (req, res) => { const runId = uuid(); const userId = req.user.id; - await workflowQueue.add( - 'run workflow', - { id, runId, userId }, - { - repeat: { - pattern: cronExpression, - tz: timezone - } - } - ); + // await workflowQueue.add( + // 'run workflow', + // { id, runId, userId }, + // { + // repeat: { + // pattern: cronExpression, + // tz: timezone + // } + // } + // ); res.status(200).json({ message: 'success', diff --git a/server/src/workflow-management/integrations/gsheet.ts b/server/src/workflow-management/integrations/gsheet.ts index 40ddb652..a1a76814 100644 --- a/server/src/workflow-management/integrations/gsheet.ts +++ b/server/src/workflow-management/integrations/gsheet.ts @@ -1,10 +1,10 @@ import { google } from "googleapis"; -import fs from 'fs'; -import path from 'path'; import logger from "../../logger"; -import { readFile } from "../storage"; +import Run from "../../models/Run"; +import Robot from "../../models/Robot"; + interface GoogleSheetUpdateTask { - name: string; + robotId: string; runId: string; status: 'pending' | 'completed' | 'failed'; retries: number; @@ -14,80 +14,101 @@ const MAX_RETRIES = 5; export let googleSheetUpdateTasks: { [runId: string]: GoogleSheetUpdateTask } = {}; - -// *** Temporary Path to the JSON file that will store the integration details *** -const getIntegrationsFilePath = (fileName: string) => path.join(__dirname, `integrations-${fileName}.json`); - -export function loadIntegrations(fileName: string) { - const filePath = getIntegrationsFilePath(fileName); - if (fs.existsSync(filePath)) { - const data = fs.readFileSync(filePath, 'utf-8'); - return JSON.parse(data); - } - return {}; -} - -export function saveIntegrations(fileName: string, integrations: any) { - const filePath = getIntegrationsFilePath(fileName); - fs.writeFileSync(filePath, JSON.stringify(integrations, null, 2)); -} - -export async function updateGoogleSheet(fileName: string, runId: string) { +export async function updateGoogleSheet(robotId: string, runId: string) { try { - const run = await readFile(`./../storage/runs/${fileName}_${runId}.json`); - const parsedRun = JSON.parse(run); + const run = await Run.findOne({ where: { runId } }); - if (parsedRun.status === 'success' && parsedRun.serializableOutput) { - const data = parsedRun.serializableOutput['item-0'] as { [key: string]: any }[]; - const integrationConfig = await loadIntegrations(fileName); - - if (integrationConfig) { - const { fileName, spreadsheetId, range, credentials } = integrationConfig; - - if (fileName && spreadsheetId && range && credentials) { - // Convert data to Google Sheets format (headers and rows) - const headers = Object.keys(data[0]); - const rows = data.map((row: { [key: string]: any }) => Object.values(row)); - const outputData = [headers, ...rows]; - - await writeDataToSheet(fileName, spreadsheetId, range, outputData); - logger.log('info', `Data written to Google Sheet successfully for ${fileName}_${runId}`); - } - } - logger.log('error', `Google Sheet integration not configured for ${fileName}_${runId}`); + if (!run) { + throw new Error(`Run not found for runId: ${runId}`); + } + + const plainRun = run.toJSON(); + + if (plainRun.status === 'success' && plainRun.serializableOutput) { + const data = plainRun.serializableOutput['item-0'] as { [key: string]: any }[]; + + const robot = await Robot.findOne({ where: { 'recording_meta.id': robotId } }); + + if (!robot) { + throw new Error(`Robot not found for robotId: ${robotId}`); + } + + const plainRobot = robot.toJSON(); + + const spreadsheetId = plainRobot.google_sheet_id; + if (plainRobot.google_sheet_email && spreadsheetId) { + console.log(`Preparing to write data to Google Sheet for robot: ${robotId}, spreadsheetId: ${spreadsheetId}`); + + const headers = Object.keys(data[0]); + const rows = data.map((row: { [key: string]: any }) => Object.values(row)); + const outputData = [headers, ...rows]; + + await writeDataToSheet(robotId, spreadsheetId, outputData); + console.log(`Data written to Google Sheet successfully for Robot: ${robotId} and Run: ${runId}`); + } else { + console.log('Google Sheets integration not configured.'); + } + } else { + console.log('Run status is not success or serializableOutput is missing.'); } - logger.log('error', `Run not successful or no data to update for ${fileName}_${runId}`); } catch (error: any) { - logger.log('error', `Failed to write data to Google Sheet for ${fileName}_${runId}: ${error.message}`); + console.error(`Failed to write data to Google Sheet for Robot: ${robotId} and Run: ${runId}: ${error.message}`); } }; -export async function writeDataToSheet(fileName: string, spreadsheetId: string, range: string, data: any[]) { +export async function writeDataToSheet(robotId: string, spreadsheetId: string, data: any[]) { try { - const integrationCredentialsPath = getIntegrationsFilePath(fileName); - const integrationCredentials = JSON.parse(fs.readFileSync(integrationCredentialsPath, 'utf-8'));; + const robot = await Robot.findOne({ where: { 'recording_meta.id': robotId } }); - const auth = new google.auth.GoogleAuth({ - credentials: { - client_email: integrationCredentials.credentials.client_email, - private_key: integrationCredentials.credentials.private_key, - }, - scopes: ['https://www.googleapis.com/auth/spreadsheets'], + if (!robot) { + throw new Error(`Robot not found for robotId: ${robotId}`); + } + + const plainRobot = robot.toJSON(); + + if (!plainRobot.google_access_token || !plainRobot.google_refresh_token) { + throw new Error('Google Sheets access not configured for user'); + } + + const oauth2Client = new google.auth.OAuth2( + process.env.GOOGLE_CLIENT_ID, + process.env.GOOGLE_CLIENT_SECRET, + process.env.GOOGLE_REDIRECT_URI + ); + + oauth2Client.setCredentials({ + access_token: plainRobot.google_access_token, + refresh_token: plainRobot.google_refresh_token, }); - const authToken = await auth.getClient(); - const sheets = google.sheets({ version: 'v4', auth: authToken as any }); + oauth2Client.on('tokens', async (tokens) => { + if (tokens.refresh_token) { + await robot.update({ google_refresh_token: tokens.refresh_token }); + } + if (tokens.access_token) { + await robot.update({ google_access_token: tokens.access_token }); + } + }); + + const sheets = google.sheets({ version: 'v4', auth: oauth2Client }); const resource = { values: data }; + console.log('Attempting to write to spreadsheet:', spreadsheetId); - await sheets.spreadsheets.values.append({ + const response = await sheets.spreadsheets.values.append({ spreadsheetId, - range, + range: 'Sheet1!A1', valueInputOption: 'USER_ENTERED', requestBody: resource, }); - logger.log(`info`, `Data written to Google Sheet: ${spreadsheetId}, Range: ${range}`); + if (response.status === 200) { + console.log('Data successfully appended to Google Sheet.'); + } else { + console.error('Google Sheets append failed:', response); + } + + logger.log(`info`, `Data written to Google Sheet: ${spreadsheetId}`); } catch (error: any) { logger.log(`error`, `Error writing data to Google Sheet: ${error.message}`); throw error; @@ -99,25 +120,33 @@ export const processGoogleSheetUpdates = async () => { let hasPendingTasks = false; for (const runId in googleSheetUpdateTasks) { const task = googleSheetUpdateTasks[runId]; + console.log(`Processing task for runId: ${runId}, status: ${task.status}`); + if (task.status === 'pending') { hasPendingTasks = true; try { - await updateGoogleSheet(task.name, task.runId); + await updateGoogleSheet(task.robotId, task.runId); + console.log(`Successfully updated Google Sheet for runId: ${runId}`); delete googleSheetUpdateTasks[runId]; } catch (error: any) { + console.error(`Failed to update Google Sheets for run ${task.runId}:`, error); if (task.retries < MAX_RETRIES) { googleSheetUpdateTasks[runId].retries += 1; + console.log(`Retrying task for runId: ${runId}, attempt: ${task.retries}`); } else { - // Mark as failed after maximum retries googleSheetUpdateTasks[runId].status = 'failed'; + console.log(`Max retries reached for runId: ${runId}. Marking task as failed.`); } - console.error(`Failed to update Google Sheets for run ${task.runId}:`, error); } } } + if (!hasPendingTasks) { + console.log('No pending tasks. Exiting loop.'); break; } + + console.log('Waiting for 5 seconds before checking again...'); await new Promise(resolve => setTimeout(resolve, 5000)); } -}; +}; \ No newline at end of file diff --git a/server/src/workflow-management/scheduler/index.ts b/server/src/workflow-management/scheduler/index.ts index 3ea6fe53..1b9d1460 100644 --- a/server/src/workflow-management/scheduler/index.ts +++ b/server/src/workflow-management/scheduler/index.ts @@ -132,7 +132,7 @@ async function executeRun(id: string) { }); googleSheetUpdateTasks[id] = { - name: plainRun.name, + robotId: plainRun.robotMetaId, runId: id, status: 'pending', retries: 5, diff --git a/src/api/storage.ts b/src/api/storage.ts index 2ff1e82a..98e4a3b4 100644 --- a/src/api/storage.ts +++ b/src/api/storage.ts @@ -32,6 +32,20 @@ export const getStoredRuns = async (): Promise => { } }; +export const getStoredRecording = async (id: string) => { + try { + const response = await axios.get(`http://localhost:8080/storage/recordings/${id}`); + if (response.status === 200) { + return response.data; + } else { + throw new Error(`Couldn't retrieve stored recording ${id}`); + } + } catch(error: any) { + console.log(error); + return null; + } +} + export const deleteRecordingFromStorage = async (id: string): Promise => { try { const response = await axios.delete(`http://localhost:8080/storage/recordings/${id}`); diff --git a/src/components/molecules/IntegrationSettings.tsx b/src/components/molecules/IntegrationSettings.tsx index ed6bea50..b1e87347 100644 --- a/src/components/molecules/IntegrationSettings.tsx +++ b/src/components/molecules/IntegrationSettings.tsx @@ -1,8 +1,11 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { GenericModal } from "../atoms/GenericModal"; -import { MenuItem, TextField, Typography } from "@mui/material"; +import { MenuItem, Typography, CircularProgress } from "@mui/material"; import Button from "@mui/material/Button"; -import { modalStyle } from "./AddWhereCondModal"; +import TextField from "@mui/material/TextField"; +import axios from 'axios'; +import { useGlobalInfoStore } from '../../context/globalInfo'; +import { getStoredRecording } from '../../api/storage'; interface IntegrationProps { isOpen: boolean; @@ -11,71 +14,175 @@ interface IntegrationProps { } export interface IntegrationSettings { - credentials: string; spreadsheetId: string; - range: string; + spreadsheetName: string; data: string; } export const IntegrationSettingsModal = ({ isOpen, handleStart, handleClose }: IntegrationProps) => { - const [settings, setSettings] = useState({ - credentials: '', spreadsheetId: '', - range: '', + spreadsheetName: '', data: '', }); - const handleChange = (field: keyof IntegrationSettings) => (e: React.ChangeEvent) => { - setSettings({ ...settings, [field]: e.target.value }); + const [spreadsheets, setSpreadsheets] = useState<{ id: string, name: string }[]>([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const { recordingId } = useGlobalInfoStore(); + const [recording, setRecording] = useState(null); + + const authenticateWithGoogle = () => { + window.location.href = `http://localhost:8080/auth/google?robotId=${recordingId}`; }; + const handleOAuthCallback = async () => { + try { + const response = await axios.get(`http://localhost:8080/auth/google/callback`); + const { google_sheet_email, files } = response.data; + } catch (error) { + setError('Error authenticating with Google'); + } + }; + + const fetchSpreadsheetFiles = async () => { + try { + const response = await axios.get(`http://localhost:8080/auth/gsheets/files?robotId=${recordingId}`, { + withCredentials: true, + }); + setSpreadsheets(response.data); + } catch (error: any) { + console.error('Error fetching spreadsheet files:', error.response?.data?.message || error.message); + } + }; + + const handleSpreadsheetSelect = (e: React.ChangeEvent) => { + const selectedSheet = spreadsheets.find(sheet => sheet.id === e.target.value); + if (selectedSheet) { + setSettings({ ...settings, spreadsheetId: selectedSheet.id, spreadsheetName: selectedSheet.name }); + } + }; + + const updateGoogleSheetId = async () => { + try { + const response = await axios.post( + `http://localhost:8080/auth/gsheets/update`, + { spreadsheetId: settings.spreadsheetId, spreadsheetName: settings.spreadsheetName, robotId: recordingId }, + { withCredentials: true } + ); + console.log('Google Sheet ID updated:', response.data); + } catch (error: any) { + console.error('Error updating Google Sheet ID:', error.response?.data?.message || error.message); + } + }; + + useEffect(() => { + // Check if we're on the callback URL + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + if (code) { + handleOAuthCallback(); + } + + const fetchRecordingInfo = async () => { + if (!recordingId) return; + const recording = await getStoredRecording(recordingId); + if (recording) { + setRecording(recording); + } + }; + + fetchRecordingInfo(); + }, [recordingId]); + return ( - -
+ +
Google Sheets Integration - + {recording && recording.google_sheet_id ? ( + + Google Sheet Integrated Successfully! +
+ Sheet Name: {recording.google_sheet_name} +
+ Sheet ID: {recording.google_sheet_id} +
+ ) : ( + <> + {!recording?.google_sheet_email ? ( + + ) : ( + <> + {recording.google_sheet_email && ( + + Logged in as: {recording.google_sheet_email} + + )} - + {loading ? ( + + ) : error ? ( + {error} + ) : spreadsheets.length === 0 ? ( + + ) : ( + <> + + {spreadsheets.map(sheet => ( + + {sheet.name} + + ))} + - + {settings.spreadsheetId && ( + + Selected Sheet: {spreadsheets.find(s => s.id === settings.spreadsheetId)?.name} (ID: {settings.spreadsheetId}) + + )} - + + + )} + + )} + + )}
); diff --git a/src/components/organisms/Recordings.tsx b/src/components/organisms/Recordings.tsx index 06af02fd..ec215b98 100644 --- a/src/components/organisms/Recordings.tsx +++ b/src/components/organisms/Recordings.tsx @@ -9,7 +9,7 @@ interface RecordingsProps { handleEditRecording: (id: string, fileName: string) => void; handleRunRecording: (settings: RunSettings) => void; handleScheduleRecording: (settings: ScheduleSettings) => void; - handleIntegrateRecording: (settings: IntegrationSettings) => void; + handleIntegrateRecording: (id: string, settings: IntegrationSettings) => void; setRecordingInfo: (id: string, name: string) => void; } @@ -20,6 +20,8 @@ export const Recordings = ({ handleEditRecording, handleRunRecording, setRecordi const [params, setParams] = useState([]); const [selectedRecordingId, setSelectedRecordingId] = useState(''); + console.log(`Selected reocrding id: ${selectedRecordingId}`); + const handleSettingsAndIntegrate = (id: string, name: string, params: string[]) => { if (params.length === 0) { setIntegrateSettingsAreOpen(true); @@ -94,7 +96,7 @@ export const Recordings = ({ handleEditRecording, handleRunRecording, setRecordi /> handleIntegrateRecording(settings)} + handleStart={(settings) => handleIntegrateRecording(selectedRecordingId, settings)} /> diff --git a/src/components/organisms/RightSidePanel.tsx b/src/components/organisms/RightSidePanel.tsx index 96f0269d..ad50c68a 100644 --- a/src/components/organisms/RightSidePanel.tsx +++ b/src/components/organisms/RightSidePanel.tsx @@ -346,6 +346,10 @@ export const RightSidePanel: React.FC = ({ onFinishCapture } }); resetListState(); + setShowPaginationOptions(false); + setShowLimitOptions(false); + setCaptureStage('initial'); + setConfirmedListTextFields({}); notify('error', 'Capture List Discarded'); }, [browserSteps, stopGetList, deleteBrowserStep, resetListState]);