first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import * as click from './click.operation';
|
||||
import * as fill from './fill.operation';
|
||||
import * as hover from './hover.operation';
|
||||
import * as scroll from './scroll.operation';
|
||||
import * as type from './type.operation';
|
||||
import { sessionIdField, windowIdField } from '../common/fields';
|
||||
export { click, fill, hover, scroll, type };
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Click an Element',
|
||||
value: 'click',
|
||||
description: 'Execute a click on an element given a description',
|
||||
action: 'Click an element',
|
||||
},
|
||||
{
|
||||
name: 'Fill Form',
|
||||
value: 'fill',
|
||||
description: 'Fill a form with the provided information',
|
||||
action: 'Fill form',
|
||||
},
|
||||
{
|
||||
name: 'Hover on an Element',
|
||||
value: 'hover',
|
||||
description: 'Execute a hover action on an element given a description',
|
||||
action: 'Hover on an element',
|
||||
},
|
||||
{
|
||||
name: 'Scroll',
|
||||
value: 'scroll',
|
||||
description: 'Execute a scroll action on the page',
|
||||
action: 'Scroll on page',
|
||||
},
|
||||
{
|
||||
name: 'Type',
|
||||
value: 'type',
|
||||
description: 'Execute a Type action on an element given a description',
|
||||
action: 'Type text',
|
||||
},
|
||||
],
|
||||
default: 'click',
|
||||
},
|
||||
{
|
||||
...sessionIdField,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
...windowIdField,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
},
|
||||
},
|
||||
},
|
||||
...click.description,
|
||||
...fill.description,
|
||||
...hover.description,
|
||||
...scroll.description,
|
||||
...type.description,
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['click', 'hover', 'type', 'scroll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Visual Scope',
|
||||
name: 'visualScope',
|
||||
type: 'options',
|
||||
default: 'auto',
|
||||
description: 'Defines the strategy for visual analysis of the current window',
|
||||
options: [
|
||||
{
|
||||
name: 'Auto',
|
||||
description: 'Provides the simplest out-of-the-box experience for most web pages',
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Viewport',
|
||||
description: 'For analysis of the current browser view only',
|
||||
value: 'viewport',
|
||||
},
|
||||
{
|
||||
name: 'Page',
|
||||
description: 'For analysis of the entire page',
|
||||
value: 'page',
|
||||
},
|
||||
{
|
||||
name: 'Scan',
|
||||
description:
|
||||
"For a full page analysis on sites that have compatibility issues with 'Page' mode",
|
||||
value: 'scan',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Wait Until Event After Navigation',
|
||||
name: 'waitForNavigation',
|
||||
type: 'options',
|
||||
default: 'load',
|
||||
description:
|
||||
"The condition to wait for the navigation to complete after an interaction (click, type or hover). Defaults to 'Fully Loaded'.",
|
||||
options: [
|
||||
{
|
||||
name: 'Fully Loaded (Slower)',
|
||||
value: 'load',
|
||||
},
|
||||
{
|
||||
name: 'DOM Only Loaded (Faster)',
|
||||
value: 'domcontentloaded',
|
||||
},
|
||||
{
|
||||
name: 'All Network Activity Has Stopped',
|
||||
value: 'networkidle0',
|
||||
},
|
||||
{
|
||||
name: 'Most Network Activity Has Stopped',
|
||||
value: 'networkidle2',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { constructInteractionRequest } from './helpers';
|
||||
import {
|
||||
validateRequiredStringField,
|
||||
validateSessionAndWindowId,
|
||||
validateAirtopApiResponse,
|
||||
} from '../../GenericFunctions';
|
||||
import { apiRequest } from '../../transport';
|
||||
import { elementDescriptionField } from '../common/fields';
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
...elementDescriptionField,
|
||||
placeholder: 'e.g. the green "save" button at the top of the page',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['click'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Click Type',
|
||||
name: 'clickType',
|
||||
type: 'options',
|
||||
default: 'click',
|
||||
description: 'The type of click to perform. Defaults to left click.',
|
||||
options: [
|
||||
{
|
||||
name: 'Left Click',
|
||||
value: 'click',
|
||||
},
|
||||
{
|
||||
name: 'Double Click',
|
||||
value: 'doubleClick',
|
||||
},
|
||||
{
|
||||
name: 'Right Click',
|
||||
value: 'rightClick',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['click'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export async function execute(
|
||||
this: IExecuteFunctions,
|
||||
index: number,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
const { sessionId, windowId } = validateSessionAndWindowId.call(this, index);
|
||||
const elementDescription = validateRequiredStringField.call(
|
||||
this,
|
||||
index,
|
||||
'elementDescription',
|
||||
'Element Description',
|
||||
);
|
||||
|
||||
const clickType = validateRequiredStringField.call(this, index, 'clickType', 'Click Type');
|
||||
|
||||
const request = constructInteractionRequest.call(this, index, {
|
||||
elementDescription,
|
||||
configuration: {
|
||||
clickType,
|
||||
},
|
||||
});
|
||||
|
||||
const response = await apiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/sessions/${sessionId}/windows/${windowId}/click`,
|
||||
request,
|
||||
);
|
||||
|
||||
validateAirtopApiResponse(this.getNode(), response);
|
||||
|
||||
return this.helpers.returnJsonArray({ sessionId, windowId, ...response });
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodeProperties,
|
||||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { ERROR_MESSAGES, OPERATION_TIMEOUT } from '../../constants';
|
||||
import {
|
||||
validateRequiredStringField,
|
||||
validateSessionAndWindowId,
|
||||
validateAirtopApiResponse,
|
||||
} from '../../GenericFunctions';
|
||||
import { apiRequest } from '../../transport';
|
||||
import type { IAirtopResponse } from '../../transport/types';
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Form Data',
|
||||
name: 'formData',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
rows: 4,
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['fill'],
|
||||
},
|
||||
},
|
||||
description: 'The information to fill into the form written in natural language',
|
||||
placeholder: 'e.g. "Name: John Doe, Email: john.doe@example.com"',
|
||||
},
|
||||
];
|
||||
|
||||
export async function execute(
|
||||
this: IExecuteFunctions,
|
||||
index: number,
|
||||
timeout = OPERATION_TIMEOUT,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
const { sessionId, windowId } = validateSessionAndWindowId.call(this, index);
|
||||
const formData = validateRequiredStringField.call(this, index, 'formData', 'Form Data');
|
||||
|
||||
// run automation
|
||||
const asyncAutomationResponse = await apiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/async/sessions/${sessionId}/windows/${windowId}/execute-automation`,
|
||||
{
|
||||
automationId: 'auto',
|
||||
parameters: {
|
||||
customData: formData,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const reqId = asyncAutomationResponse.requestId as string;
|
||||
|
||||
// Poll status every second until it's completed or timeout is reached
|
||||
const startTime = Date.now();
|
||||
let automationStatusResponse: IAirtopResponse;
|
||||
|
||||
while (true) {
|
||||
automationStatusResponse = await apiRequest.call(this, 'GET', `/requests/${reqId}/status`);
|
||||
const status = automationStatusResponse?.status ?? '';
|
||||
|
||||
validateAirtopApiResponse(this.getNode(), automationStatusResponse);
|
||||
|
||||
if (status === 'completed' || status === 'error') {
|
||||
break;
|
||||
}
|
||||
|
||||
const elapsedTime = Date.now() - startTime;
|
||||
if (elapsedTime >= timeout) {
|
||||
throw new NodeApiError(this.getNode(), {
|
||||
message: ERROR_MESSAGES.TIMEOUT_REACHED,
|
||||
code: 500,
|
||||
});
|
||||
}
|
||||
|
||||
// Wait one second
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
return this.helpers.returnJsonArray({ sessionId, windowId, ...automationStatusResponse });
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { IExecuteFunctions } from 'n8n-workflow';
|
||||
|
||||
import type { IAirtopInteractionRequest } from '../../transport/types';
|
||||
|
||||
export function constructInteractionRequest(
|
||||
this: IExecuteFunctions,
|
||||
index: number,
|
||||
parameters: Partial<IAirtopInteractionRequest> = {},
|
||||
): IAirtopInteractionRequest {
|
||||
const additionalFields = this.getNodeParameter('additionalFields', index);
|
||||
const request: IAirtopInteractionRequest = {
|
||||
...parameters,
|
||||
configuration: {
|
||||
...(parameters.configuration ?? {}),
|
||||
},
|
||||
};
|
||||
|
||||
if (additionalFields.visualScope) {
|
||||
request.configuration.visualAnalysis = {
|
||||
scope: additionalFields.visualScope as string,
|
||||
};
|
||||
}
|
||||
|
||||
if (additionalFields.waitForNavigation) {
|
||||
request.waitForNavigation = true;
|
||||
request.configuration.waitForNavigationConfig = {
|
||||
waitUntil: additionalFields.waitForNavigation as string,
|
||||
};
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { constructInteractionRequest } from './helpers';
|
||||
import {
|
||||
validateRequiredStringField,
|
||||
validateSessionAndWindowId,
|
||||
validateAirtopApiResponse,
|
||||
} from '../../GenericFunctions';
|
||||
import { apiRequest } from '../../transport';
|
||||
import { elementDescriptionField } from '../common/fields';
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
...elementDescriptionField,
|
||||
required: true,
|
||||
placeholder: 'e.g. the rounded user profile image at the top right of the page',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['hover'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export async function execute(
|
||||
this: IExecuteFunctions,
|
||||
index: number,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
const { sessionId, windowId } = validateSessionAndWindowId.call(this, index);
|
||||
const elementDescription = validateRequiredStringField.call(
|
||||
this,
|
||||
index,
|
||||
'elementDescription',
|
||||
'Element Description',
|
||||
);
|
||||
|
||||
const request = constructInteractionRequest.call(this, index, {
|
||||
elementDescription,
|
||||
});
|
||||
|
||||
const response = await apiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/sessions/${sessionId}/windows/${windowId}/hover`,
|
||||
request,
|
||||
);
|
||||
|
||||
validateAirtopApiResponse(this.getNode(), response);
|
||||
|
||||
return this.helpers.returnJsonArray({ sessionId, windowId, ...response });
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { constructInteractionRequest } from './helpers';
|
||||
import {
|
||||
validateRequiredStringField,
|
||||
validateSessionAndWindowId,
|
||||
validateAirtopApiResponse,
|
||||
validateScrollByAmount,
|
||||
validateScrollingMode,
|
||||
} from '../../GenericFunctions';
|
||||
import { apiRequest } from '../../transport';
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Scroll Mode',
|
||||
name: 'scrollingMode',
|
||||
type: 'options',
|
||||
description: 'Choose the mode of scrolling',
|
||||
options: [
|
||||
{
|
||||
name: 'Automatic',
|
||||
value: 'automatic',
|
||||
description: 'Describe with natural language the element to scroll to',
|
||||
},
|
||||
{
|
||||
name: 'Manual',
|
||||
value: 'manual',
|
||||
description: 'Define the direction and amount to scroll by',
|
||||
},
|
||||
],
|
||||
default: 'automatic',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['scroll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Element Description',
|
||||
default: '',
|
||||
description: 'A natural language description of the element to scroll to',
|
||||
name: 'scrollToElement',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. the page section titled "Contact Us"',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['scroll'],
|
||||
scrollingMode: ['automatic'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Scroll To Edge',
|
||||
name: 'scrollToEdge',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
placeholder: 'Add Edge Direction',
|
||||
description:
|
||||
"The direction to scroll to. When 'Scroll By' is defined, 'Scroll To Edge' action will be executed first, then 'Scroll By' action.",
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['scroll'],
|
||||
scrollingMode: ['manual'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Page Edges',
|
||||
name: 'edgeValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Vertically',
|
||||
name: 'yAxis',
|
||||
type: 'options',
|
||||
default: '',
|
||||
options: [
|
||||
{
|
||||
name: 'Empty',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: 'Top',
|
||||
value: 'top',
|
||||
},
|
||||
{
|
||||
name: 'Bottom',
|
||||
value: 'bottom',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Horizontally',
|
||||
name: 'xAxis',
|
||||
type: 'options',
|
||||
default: '',
|
||||
options: [
|
||||
{
|
||||
name: 'Empty',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
name: 'Left',
|
||||
value: 'left',
|
||||
},
|
||||
{
|
||||
name: 'Right',
|
||||
value: 'right',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Scroll By',
|
||||
name: 'scrollBy',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
description:
|
||||
"The amount to scroll by. When 'Scroll To Edge' is defined, 'Scroll By' action will be executed after 'Scroll To Edge'.",
|
||||
placeholder: 'Add Scroll Amount',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['scroll'],
|
||||
scrollingMode: ['manual'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'scrollValues',
|
||||
displayName: 'Scroll Values',
|
||||
description: 'The amount in pixels or percentage to scroll by',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Vertically',
|
||||
name: 'yAxis',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. 200px, 50%, -100px',
|
||||
},
|
||||
{
|
||||
displayName: 'Horizontally',
|
||||
name: 'xAxis',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. 50px, 10%, -200px',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Scrollable Area',
|
||||
name: 'scrollWithin',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Scroll within an element on the page',
|
||||
placeholder: 'e.g. the left sidebar',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['scroll'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export async function execute(
|
||||
this: IExecuteFunctions,
|
||||
index: number,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
const { sessionId, windowId } = validateSessionAndWindowId.call(this, index);
|
||||
|
||||
const scrollingMode = validateScrollingMode.call(this, index);
|
||||
const isAutomatic = scrollingMode === 'automatic';
|
||||
|
||||
const scrollToElement = isAutomatic
|
||||
? validateRequiredStringField.call(this, index, 'scrollToElement', 'Element Description')
|
||||
: '';
|
||||
|
||||
const scrollToEdge = this.getNodeParameter('scrollToEdge.edgeValues', index, {}) as {
|
||||
xAxis?: string;
|
||||
yAxis?: string;
|
||||
};
|
||||
|
||||
const scrollBy = validateScrollByAmount.call(this, index, 'scrollBy.scrollValues');
|
||||
|
||||
const scrollWithin = this.getNodeParameter('scrollWithin', index, '') as string;
|
||||
|
||||
const request: IDataObject = {
|
||||
// when scrollingMode is 'Manual'
|
||||
...(!isAutomatic ? { scrollToEdge } : {}),
|
||||
...(!isAutomatic ? { scrollBy } : {}),
|
||||
// when scrollingMode is 'Automatic'
|
||||
...(isAutomatic ? { scrollToElement } : {}),
|
||||
// when scrollWithin is defined
|
||||
...(scrollWithin ? { scrollWithin } : {}),
|
||||
};
|
||||
|
||||
const fullRequest = constructInteractionRequest.call(this, index, request);
|
||||
|
||||
const response = await apiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/sessions/${sessionId}/windows/${windowId}/scroll`,
|
||||
fullRequest,
|
||||
);
|
||||
|
||||
validateAirtopApiResponse(this.getNode(), response);
|
||||
|
||||
return this.helpers.returnJsonArray({ sessionId, windowId, ...response });
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
type INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { constructInteractionRequest } from './helpers';
|
||||
import {
|
||||
validateRequiredStringField,
|
||||
validateSessionAndWindowId,
|
||||
validateAirtopApiResponse,
|
||||
} from '../../GenericFunctions';
|
||||
import { apiRequest } from '../../transport';
|
||||
import { elementDescriptionField } from '../common/fields';
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['type'],
|
||||
},
|
||||
},
|
||||
description: 'The text to type into the browser window',
|
||||
placeholder: 'e.g. email@example.com',
|
||||
},
|
||||
{
|
||||
displayName: 'Press Enter Key',
|
||||
name: 'pressEnterKey',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to press the Enter key after typing the text',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['type'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
...elementDescriptionField,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['interaction'],
|
||||
operation: ['type'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export async function execute(
|
||||
this: IExecuteFunctions,
|
||||
index: number,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
const { sessionId, windowId } = validateSessionAndWindowId.call(this, index);
|
||||
const text = validateRequiredStringField.call(this, index, 'text', 'Text');
|
||||
const pressEnterKey = this.getNodeParameter('pressEnterKey', index) as boolean;
|
||||
const elementDescription = this.getNodeParameter('elementDescription', index) as string;
|
||||
|
||||
const request = constructInteractionRequest.call(this, index, {
|
||||
text,
|
||||
pressEnterKey,
|
||||
elementDescription,
|
||||
});
|
||||
|
||||
const response = await apiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/sessions/${sessionId}/windows/${windowId}/type`,
|
||||
request,
|
||||
);
|
||||
|
||||
validateAirtopApiResponse(this.getNode(), response);
|
||||
|
||||
return this.helpers.returnJsonArray({ sessionId, windowId, ...response });
|
||||
}
|
||||
Reference in New Issue
Block a user