/* eslint-disable n8n-nodes-base/node-filename-against-convention */ import type { INodeType, INodeTypeDescription, IExecuteFunctions, INodeExecutionData, } from 'n8n-workflow'; import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow'; import { document, sheet } from '../../Google/Sheet/GoogleSheetsTrigger.node'; import { readFilter } from '../../Google/Sheet/v2/actions/sheet/read.operation'; import { authentication } from '../../Google/Sheet/v2/actions/versionDescription'; import type { ILookupValues } from '../../Google/Sheet/v2/helpers/GoogleSheets.types'; import { listSearch, loadOptions } from '../methods'; import { getGoogleSheet, getResults, getRowsLeft, getNumberOfRowsLeftFiltered, getSheet, } from '../utils/evaluationTriggerUtils'; export const DEFAULT_STARTING_ROW = 2; export class EvaluationTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Evaluation Trigger', icon: 'fa:check-double', name: 'evaluationTrigger', group: ['trigger'], version: 4.6, description: 'Run a test dataset through your workflow to check performance', eventTriggerDescription: '', defaults: { name: 'When fetching a dataset row', color: '#c3c9d5', }, inputs: [], outputs: [NodeConnectionTypes.Main], properties: [ { displayName: 'Pulls a test dataset from a Google Sheet. The workflow will run once for each row, in sequence. Tips for wiring this node up here.', name: 'notice', type: 'notice', default: '', }, { displayName: 'Credentials', name: 'credentials', type: 'credentials', default: '', }, authentication, { ...document, displayName: 'Document Containing Dataset', hint: 'Example dataset format here', }, { ...sheet, displayName: 'Sheet Containing Dataset' }, { displayName: 'Limit Rows', name: 'limitRows', type: 'boolean', default: false, noDataExpression: true, description: 'Whether to limit number of rows to process', }, { displayName: 'Max Rows to Process', name: 'maxRows', type: 'number', default: 10, description: 'Maximum number of rows to process', noDataExpression: false, displayOptions: { show: { limitRows: [true] } }, }, readFilter, ], codex: { alias: ['Test', 'Metrics', 'Evals', 'Set Output', 'Set Metrics'], }, credentials: [ { name: 'googleApi', required: true, displayOptions: { show: { authentication: ['serviceAccount'], }, }, testedBy: 'googleApiCredentialTest', }, { name: 'googleSheetsOAuth2Api', required: true, displayOptions: { show: { authentication: ['oAuth2'], }, }, }, ], }; methods = { loadOptions, listSearch }; async execute(this: IExecuteFunctions): Promise { const inputData = this.getInputData(); const MAX_ROWS = 1000; const maxRows = this.getNodeParameter('limitRows', 0) ? (this.getNodeParameter('maxRows', 0) as number) + 1 : MAX_ROWS; const previousRunRowNumber = inputData?.[0]?.json?.row_number; const previousRunRowsLeft = inputData?.[0]?.json?._rowsLeft; const firstDataRow = typeof previousRunRowNumber === 'number' && previousRunRowsLeft !== 0 ? previousRunRowNumber + 1 : DEFAULT_STARTING_ROW; const rangeOptions = { rangeDefinition: 'specifyRange', headerRow: 1, firstDataRow, }; const googleSheetInstance = getGoogleSheet.call(this); const googleSheet = await getSheet.call(this, googleSheetInstance); const allRows = await getResults.call(this, [], googleSheetInstance, googleSheet, rangeOptions); // This is for test runner which requires a different return format if (inputData[0].json.requestDataset) { const testRunnerResult = await getResults.call( this, [], googleSheetInstance, googleSheet, {}, ); const result = testRunnerResult.slice(0, maxRows - 1); return [result]; } const hasFilter = this.getNodeParameter('filtersUI.values', 0, []) as ILookupValues[]; if (hasFilter.length > 0) { const currentRow = allRows[0]; const currentRowNumber = currentRow.json?.row_number as number; if (currentRow === undefined) { throw new NodeOperationError(this.getNode(), 'No row found'); } const rowsLeft = await getNumberOfRowsLeftFiltered.call( this, googleSheetInstance, googleSheet.title, currentRowNumber + 1, maxRows, ); currentRow.json._rowsLeft = rowsLeft; return [[currentRow]]; } else { const currentRow = allRows.find((row) => (row?.json?.row_number as number) === firstDataRow); const rowsLeft = await getRowsLeft.call( this, googleSheetInstance, googleSheet.title, `${googleSheet.title}!${firstDataRow}:${maxRows}`, ); if (currentRow === undefined) { throw new NodeOperationError(this.getNode(), 'No row found'); } currentRow.json._rowsLeft = rowsLeft; return [[currentRow]]; } } }