chore: lint
This commit is contained in:
@@ -23,7 +23,7 @@ chromium.use(stealthPlugin());
|
|||||||
export const router = Router();
|
export const router = Router();
|
||||||
|
|
||||||
export const processWorkflowActions = async (workflow: any[], checkLimit: boolean = false): Promise<any[]> => {
|
export const processWorkflowActions = async (workflow: any[], checkLimit: boolean = false): Promise<any[]> => {
|
||||||
const processedWorkflow = JSON.parse(JSON.stringify(workflow));
|
const processedWorkflow = JSON.parse(JSON.stringify(workflow));
|
||||||
|
|
||||||
processedWorkflow.forEach((pair: any) => {
|
processedWorkflow.forEach((pair: any) => {
|
||||||
pair.what.forEach((action: any) => {
|
pair.what.forEach((action: any) => {
|
||||||
@@ -108,52 +108,52 @@ router.get('/recordings/:id', requireSignIn, async (req, res) => {
|
|||||||
router.get(('/recordings/:id/runs'), requireSignIn, async (req, res) => {
|
router.get(('/recordings/:id/runs'), requireSignIn, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const runs = await Run.findAll({
|
const runs = await Run.findAll({
|
||||||
where: {
|
where: {
|
||||||
robotMetaId: req.params.id
|
robotMetaId: req.params.id
|
||||||
},
|
},
|
||||||
raw: true
|
raw: true
|
||||||
});
|
});
|
||||||
const formattedRuns = runs.map(formatRunResponse);
|
const formattedRuns = runs.map(formatRunResponse);
|
||||||
const response = {
|
const response = {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
messageCode: "success",
|
messageCode: "success",
|
||||||
runs: {
|
runs: {
|
||||||
totalCount: formattedRuns.length,
|
totalCount: formattedRuns.length,
|
||||||
items: formattedRuns,
|
items: formattedRuns,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
res.status(200).json(response);
|
res.status(200).json(response);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching runs:", error);
|
console.error("Error fetching runs:", error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
messageCode: "error",
|
messageCode: "error",
|
||||||
message: "Failed to retrieve runs",
|
message: "Failed to retrieve runs",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function formatRunResponse(run: any) {
|
function formatRunResponse(run: any) {
|
||||||
const formattedRun = {
|
const formattedRun = {
|
||||||
id: run.id,
|
id: run.id,
|
||||||
status: run.status,
|
status: run.status,
|
||||||
name: run.name,
|
name: run.name,
|
||||||
robotId: run.robotMetaId, // Renaming robotMetaId to robotId
|
robotId: run.robotMetaId, // Renaming robotMetaId to robotId
|
||||||
startedAt: run.startedAt,
|
startedAt: run.startedAt,
|
||||||
finishedAt: run.finishedAt,
|
finishedAt: run.finishedAt,
|
||||||
runId: run.runId,
|
runId: run.runId,
|
||||||
runByUserId: run.runByUserId,
|
runByUserId: run.runByUserId,
|
||||||
runByScheduleId: run.runByScheduleId,
|
runByScheduleId: run.runByScheduleId,
|
||||||
runByAPI: run.runByAPI,
|
runByAPI: run.runByAPI,
|
||||||
data: {},
|
data: {},
|
||||||
screenshot: null,
|
screenshot: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (run.serializableOutput && run.serializableOutput['item-0']) {
|
if (run.serializableOutput && run.serializableOutput['item-0']) {
|
||||||
formattedRun.data = run.serializableOutput['item-0'];
|
formattedRun.data = run.serializableOutput['item-0'];
|
||||||
} else if (run.binaryOutput && run.binaryOutput['item-0']) {
|
} else if (run.binaryOutput && run.binaryOutput['item-0']) {
|
||||||
formattedRun.screenshot = run.binaryOutput['item-0'];
|
formattedRun.screenshot = run.binaryOutput['item-0'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return formattedRun;
|
return formattedRun;
|
||||||
@@ -170,81 +170,81 @@ interface Credentials {
|
|||||||
|
|
||||||
function handleWorkflowActions(workflow: any[], credentials: Credentials) {
|
function handleWorkflowActions(workflow: any[], credentials: Credentials) {
|
||||||
return workflow.map(step => {
|
return workflow.map(step => {
|
||||||
if (!step.what) return step;
|
if (!step.what) return step;
|
||||||
|
|
||||||
const newWhat: any[] = [];
|
const newWhat: any[] = [];
|
||||||
const processedSelectors = new Set<string>();
|
const processedSelectors = new Set<string>();
|
||||||
|
|
||||||
for (let i = 0; i < step.what.length; i++) {
|
|
||||||
const action = step.what[i];
|
|
||||||
|
|
||||||
if (!action?.action || !action?.args?.[0]) {
|
|
||||||
newWhat.push(action);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selector = action.args[0];
|
for (let i = 0; i < step.what.length; i++) {
|
||||||
const credential = credentials[selector];
|
const action = step.what[i];
|
||||||
|
|
||||||
if (!credential) {
|
if (!action?.action || !action?.args?.[0]) {
|
||||||
newWhat.push(action);
|
newWhat.push(action);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (action.action === 'click') {
|
|
||||||
newWhat.push(action);
|
|
||||||
|
|
||||||
if (!processedSelectors.has(selector) &&
|
|
||||||
i + 1 < step.what.length &&
|
|
||||||
(step.what[i + 1].action === 'type' || step.what[i + 1].action === 'press')) {
|
|
||||||
|
|
||||||
newWhat.push({
|
|
||||||
action: 'type',
|
|
||||||
args: [selector, encrypt(credential.value), credential.type]
|
|
||||||
});
|
|
||||||
|
|
||||||
newWhat.push({
|
|
||||||
action: 'waitForLoadState',
|
|
||||||
args: ['networkidle']
|
|
||||||
});
|
|
||||||
|
|
||||||
processedSelectors.add(selector);
|
|
||||||
|
|
||||||
while (i + 1 < step.what.length &&
|
|
||||||
(step.what[i + 1].action === 'type' ||
|
|
||||||
step.what[i + 1].action === 'press' ||
|
|
||||||
step.what[i + 1].action === 'waitForLoadState')) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((action.action === 'type' || action.action === 'press') &&
|
|
||||||
!processedSelectors.has(selector)) {
|
|
||||||
newWhat.push({
|
|
||||||
action: 'type',
|
|
||||||
args: [selector, encrypt(credential.value), credential.type]
|
|
||||||
});
|
|
||||||
|
|
||||||
newWhat.push({
|
|
||||||
action: 'waitForLoadState',
|
|
||||||
args: ['networkidle']
|
|
||||||
});
|
|
||||||
|
|
||||||
processedSelectors.add(selector);
|
|
||||||
|
|
||||||
// Skip subsequent type/press/waitForLoadState actions for this selector
|
|
||||||
while (i + 1 < step.what.length &&
|
|
||||||
(step.what[i + 1].action === 'type' ||
|
|
||||||
step.what[i + 1].action === 'press' ||
|
|
||||||
step.what[i + 1].action === 'waitForLoadState')) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const selector = action.args[0];
|
||||||
...step,
|
const credential = credentials[selector];
|
||||||
what: newWhat
|
|
||||||
};
|
if (!credential) {
|
||||||
|
newWhat.push(action);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.action === 'click') {
|
||||||
|
newWhat.push(action);
|
||||||
|
|
||||||
|
if (!processedSelectors.has(selector) &&
|
||||||
|
i + 1 < step.what.length &&
|
||||||
|
(step.what[i + 1].action === 'type' || step.what[i + 1].action === 'press')) {
|
||||||
|
|
||||||
|
newWhat.push({
|
||||||
|
action: 'type',
|
||||||
|
args: [selector, encrypt(credential.value), credential.type]
|
||||||
|
});
|
||||||
|
|
||||||
|
newWhat.push({
|
||||||
|
action: 'waitForLoadState',
|
||||||
|
args: ['networkidle']
|
||||||
|
});
|
||||||
|
|
||||||
|
processedSelectors.add(selector);
|
||||||
|
|
||||||
|
while (i + 1 < step.what.length &&
|
||||||
|
(step.what[i + 1].action === 'type' ||
|
||||||
|
step.what[i + 1].action === 'press' ||
|
||||||
|
step.what[i + 1].action === 'waitForLoadState')) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((action.action === 'type' || action.action === 'press') &&
|
||||||
|
!processedSelectors.has(selector)) {
|
||||||
|
newWhat.push({
|
||||||
|
action: 'type',
|
||||||
|
args: [selector, encrypt(credential.value), credential.type]
|
||||||
|
});
|
||||||
|
|
||||||
|
newWhat.push({
|
||||||
|
action: 'waitForLoadState',
|
||||||
|
args: ['networkidle']
|
||||||
|
});
|
||||||
|
|
||||||
|
processedSelectors.add(selector);
|
||||||
|
|
||||||
|
// Skip subsequent type/press/waitForLoadState actions for this selector
|
||||||
|
while (i + 1 < step.what.length &&
|
||||||
|
(step.what[i + 1].action === 'type' ||
|
||||||
|
step.what[i + 1].action === 'press' ||
|
||||||
|
step.what[i + 1].action === 'waitForLoadState')) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...step,
|
||||||
|
what: newWhat
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
|
|||||||
|
|
||||||
if (targetUrl) {
|
if (targetUrl) {
|
||||||
const updatedWorkflow = [...robot.recording.workflow];
|
const updatedWorkflow = [...robot.recording.workflow];
|
||||||
|
|
||||||
for (let i = updatedWorkflow.length - 1; i >= 0; i--) {
|
for (let i = updatedWorkflow.length - 1; i >= 0; i--) {
|
||||||
const step = updatedWorkflow[i];
|
const step = updatedWorkflow[i];
|
||||||
for (let j = 0; j < step.what.length; j++) {
|
for (let j = 0; j < step.what.length; j++) {
|
||||||
@@ -286,7 +286,7 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
|
|||||||
if (step.where?.url && step.where.url !== "about:blank") {
|
if (step.where?.url && step.where.url !== "about:blank") {
|
||||||
step.where.url = targetUrl;
|
step.where.url = targetUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.set('recording', { ...robot.recording, workflow: updatedWorkflow });
|
robot.set('recording', { ...robot.recording, workflow: updatedWorkflow });
|
||||||
robot.changed('recording', true);
|
robot.changed('recording', true);
|
||||||
i = -1;
|
i = -1;
|
||||||
@@ -307,16 +307,16 @@ router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, r
|
|||||||
if (limits && Array.isArray(limits) && limits.length > 0) {
|
if (limits && Array.isArray(limits) && limits.length > 0) {
|
||||||
for (const limitInfo of limits) {
|
for (const limitInfo of limits) {
|
||||||
const { pairIndex, actionIndex, argIndex, limit } = limitInfo;
|
const { pairIndex, actionIndex, argIndex, limit } = limitInfo;
|
||||||
|
|
||||||
const pair = workflow[pairIndex];
|
const pair = workflow[pairIndex];
|
||||||
if (!pair || !pair.what) continue;
|
if (!pair || !pair.what) continue;
|
||||||
|
|
||||||
const action = pair.what[actionIndex];
|
const action = pair.what[actionIndex];
|
||||||
if (!action || !action.args) continue;
|
if (!action || !action.args) continue;
|
||||||
|
|
||||||
const arg = action.args[argIndex];
|
const arg = action.args[argIndex];
|
||||||
if (!arg || typeof arg !== 'object') continue;
|
if (!arg || typeof arg !== 'object') continue;
|
||||||
|
|
||||||
(arg as { limit: number }).limit = limit;
|
(arg as { limit: number }).limit = limit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ router.post('/recordings/:id/duplicate', requireSignIn, async (req: Authenticate
|
|||||||
|
|
||||||
step.what.forEach((action) => {
|
step.what.forEach((action) => {
|
||||||
if (action.action === "goto" && action.args?.length) {
|
if (action.action === "goto" && action.args?.length) {
|
||||||
action.args[0] = targetUrl;
|
action.args[0] = targetUrl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -394,22 +394,22 @@ router.post('/recordings/:id/duplicate', requireSignIn, async (req: Authenticate
|
|||||||
const currentTimestamp = new Date().toLocaleString();
|
const currentTimestamp = new Date().toLocaleString();
|
||||||
|
|
||||||
const newRobot = await Robot.create({
|
const newRobot = await Robot.create({
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
userId: originalRobot.userId,
|
userId: originalRobot.userId,
|
||||||
recording_meta: {
|
recording_meta: {
|
||||||
...originalRobot.recording_meta,
|
...originalRobot.recording_meta,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
name: `${originalRobot.recording_meta.name} (${lastWord})`,
|
name: `${originalRobot.recording_meta.name} (${lastWord})`,
|
||||||
createdAt: currentTimestamp,
|
createdAt: currentTimestamp,
|
||||||
updatedAt: currentTimestamp,
|
updatedAt: currentTimestamp,
|
||||||
},
|
},
|
||||||
recording: { ...originalRobot.recording, workflow },
|
recording: { ...originalRobot.recording, workflow },
|
||||||
google_sheet_email: null,
|
google_sheet_email: null,
|
||||||
google_sheet_name: null,
|
google_sheet_name: null,
|
||||||
google_sheet_id: null,
|
google_sheet_id: null,
|
||||||
google_access_token: null,
|
google_access_token: null,
|
||||||
google_refresh_token: null,
|
google_refresh_token: null,
|
||||||
schedule: null,
|
schedule: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.log('info', `Robot with ID ${id} duplicated successfully as ${newRobot.id}.`);
|
logger.log('info', `Robot with ID ${id} duplicated successfully as ${newRobot.id}.`);
|
||||||
@@ -534,11 +534,11 @@ router.put('/runs/:id', requireSignIn, async (req: AuthenticatedRequest, res) =>
|
|||||||
|
|
||||||
// Generate runId first
|
// Generate runId first
|
||||||
const runId = uuid();
|
const runId = uuid();
|
||||||
|
|
||||||
// Check if user has reached browser limit
|
// Check if user has reached browser limit
|
||||||
const userBrowserIds = browserPool.getAllBrowserIdsForUser(req.user.id);
|
const userBrowserIds = browserPool.getAllBrowserIdsForUser(req.user.id);
|
||||||
const canCreateBrowser = userBrowserIds.length < 2;
|
const canCreateBrowser = userBrowserIds.length < 2;
|
||||||
|
|
||||||
if (canCreateBrowser) {
|
if (canCreateBrowser) {
|
||||||
// User has available browser slots, create it directly
|
// User has available browser slots, create it directly
|
||||||
const id = createRemoteBrowserForRun(req.user.id);
|
const id = createRemoteBrowserForRun(req.user.id);
|
||||||
@@ -572,7 +572,7 @@ router.put('/runs/:id', requireSignIn, async (req: AuthenticatedRequest, res) =>
|
|||||||
|
|
||||||
if (browserId) {
|
if (browserId) {
|
||||||
// User has reached the browser limit, queue the run
|
// User has reached the browser limit, queue the run
|
||||||
try {
|
try {
|
||||||
// Create the run record with 'queued' status
|
// Create the run record with 'queued' status
|
||||||
await Run.create({
|
await Run.create({
|
||||||
status: 'queued',
|
status: 'queued',
|
||||||
@@ -589,7 +589,7 @@ router.put('/runs/:id', requireSignIn, async (req: AuthenticatedRequest, res) =>
|
|||||||
serializableOutput: {},
|
serializableOutput: {},
|
||||||
binaryOutput: {},
|
binaryOutput: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.send({
|
return res.send({
|
||||||
browserId: browserId,
|
browserId: browserId,
|
||||||
runId: runId,
|
runId: runId,
|
||||||
@@ -664,17 +664,17 @@ router.post('/runs/run/:id', requireSignIn, async (req: AuthenticatedRequest, re
|
|||||||
|
|
||||||
// Queue the execution job
|
// Queue the execution job
|
||||||
await pgBoss.createQueue(userQueueName);
|
await pgBoss.createQueue(userQueueName);
|
||||||
|
|
||||||
const jobId = await pgBoss.send(userQueueName, {
|
const jobId = await pgBoss.send(userQueueName, {
|
||||||
userId: req.user.id,
|
userId: req.user.id,
|
||||||
runId: req.params.id,
|
runId: req.params.id,
|
||||||
browserId: plainRun.browserId
|
browserId: plainRun.browserId
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.log('info', `Queued run execution job with ID: ${jobId} for run: ${req.params.id}`);
|
logger.log('info', `Queued run execution job with ID: ${jobId} for run: ${req.params.id}`);
|
||||||
} catch (queueError: any) {
|
} catch (queueError: any) {
|
||||||
logger.log('error', `Failed to queue run execution`);
|
logger.log('error', `Failed to queue run execution`);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const { message } = e as Error;
|
const { message } = e as Error;
|
||||||
@@ -889,15 +889,15 @@ router.delete('/schedule/:id', requireSignIn, async (req: AuthenticatedRequest,
|
|||||||
*/
|
*/
|
||||||
router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest, res) => {
|
router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return res.status(401).send({ error: 'Unauthorized' });
|
return res.status(401).send({ error: 'Unauthorized' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const run = await Run.findOne({
|
const run = await Run.findOne({
|
||||||
where: {
|
where: {
|
||||||
runId: req.params.id,
|
runId: req.params.id,
|
||||||
runByUserId: req.user.id,
|
runByUserId: req.user.id,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!run) {
|
if (!run) {
|
||||||
@@ -905,8 +905,8 @@ router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!['running', 'queued'].includes(run.status)) {
|
if (!['running', 'queued'].includes(run.status)) {
|
||||||
return res.status(400).send({
|
return res.status(400).send({
|
||||||
error: `Cannot abort run with status: ${run.status}`
|
error: `Cannot abort run with status: ${run.status}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -920,13 +920,13 @@ router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest,
|
|||||||
finishedAt: new Date().toLocaleString(),
|
finishedAt: new Date().toLocaleString(),
|
||||||
log: 'Run aborted while queued'
|
log: 'Run aborted while queued'
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.send({ success: true, message: 'Queued run aborted' });
|
return res.send({ success: true, message: 'Queued run aborted' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const userQueueName = `abort-run-user-${req.user.id}`;
|
const userQueueName = `abort-run-user-${req.user.id}`;
|
||||||
await pgBoss.createQueue(userQueueName);
|
await pgBoss.createQueue(userQueueName);
|
||||||
|
|
||||||
const jobId = await pgBoss.send(userQueueName, {
|
const jobId = await pgBoss.send(userQueueName, {
|
||||||
userId: req.user.id,
|
userId: req.user.id,
|
||||||
runId: req.params.id
|
runId: req.params.id
|
||||||
@@ -934,10 +934,10 @@ router.post('/runs/abort/:id', requireSignIn, async (req: AuthenticatedRequest,
|
|||||||
|
|
||||||
logger.log('info', `Abort signal sent for run ${req.params.id}, job ID: ${jobId}`);
|
logger.log('info', `Abort signal sent for run ${req.params.id}, job ID: ${jobId}`);
|
||||||
|
|
||||||
return res.send({
|
return res.send({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Abort signal sent',
|
message: 'Abort signal sent',
|
||||||
jobId
|
jobId
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user