From c6276ebe73972b005a4c130883c000f839db2641 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Tue, 2 Dec 2025 10:35:10 +0100 Subject: [PATCH] Add measure operations Signed-off-by: Bryan Frimin --- .../n8n-node/nodes/Probo/GenericFunctions.ts | 91 ++++++++++++ packages/n8n-node/nodes/Probo/Probo.node.ts | 55 +++----- .../actions/execute/execute.operation.ts | 80 +++++++++++ .../nodes/Probo/actions/execute/index.ts | 29 ++++ .../n8n-node/nodes/Probo/actions/index.ts | 58 ++++++++ .../Probo/actions/measure/create.operation.ts | 104 ++++++++++++++ .../Probo/actions/measure/delete.operation.ts | 41 ++++++ .../Probo/actions/measure/get.operation.ts | 54 ++++++++ .../Probo/actions/measure/getAll.operation.ts | 98 +++++++++++++ .../nodes/Probo/actions/measure/index.ts | 61 +++++++++ .../Probo/actions/measure/update.operation.ts | 129 ++++++++++++++++++ .../nodes/Probo/operations/execute.ts | 81 ----------- .../n8n-node/nodes/Probo/operations/index.ts | 16 --- packages/n8n-node/package.json | 8 +- 14 files changed, 769 insertions(+), 136 deletions(-) create mode 100644 packages/n8n-node/nodes/Probo/GenericFunctions.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/execute/execute.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/execute/index.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/index.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/measure/create.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/measure/delete.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/measure/get.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/measure/getAll.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/measure/index.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/measure/update.operation.ts delete mode 100644 packages/n8n-node/nodes/Probo/operations/execute.ts delete mode 100644 packages/n8n-node/nodes/Probo/operations/index.ts diff --git a/packages/n8n-node/nodes/Probo/GenericFunctions.ts b/packages/n8n-node/nodes/Probo/GenericFunctions.ts new file mode 100644 index 000000000..d0e850ad5 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/GenericFunctions.ts @@ -0,0 +1,91 @@ +import type { + IExecuteFunctions, + IHookFunctions, + IDataObject, + JsonObject, + IHttpRequestOptions, +} from 'n8n-workflow'; +import { NodeApiError } from 'n8n-workflow'; + +export async function proboApiRequest( + this: IExecuteFunctions | IHookFunctions, + query: string, + variables: IDataObject = {}, +): Promise { + const credentials = await this.getCredentials('proboApi'); + + if (!credentials?.apiKey) { + throw new NodeApiError(this.getNode(), { message: 'API Key is required' } as JsonObject); + } + + const options: IHttpRequestOptions = { + method: 'POST', + baseURL: `${credentials.server}`, + url: '/api/console/v1/query', + headers: { + Authorization: `Bearer ${credentials.apiKey}`, + 'Content-Type': 'application/json', + }, + body: { + query, + variables, + }, + json: true, + }; + + try { + return await this.helpers.httpRequest(options); + } catch (error) { + throw new NodeApiError(this.getNode(), error as JsonObject); + } +} + +export async function proboApiRequestAllItems( + this: IExecuteFunctions, + query: string, + variables: IDataObject, + getConnection: (response: any) => any, + returnAll: boolean = true, + limit: number = 0, +): Promise { + const items: any[] = []; + let hasNextPage = true; + let cursor: string | null = null; + const pageSize = 50; + + while (hasNextPage) { + const currentLimit = returnAll ? pageSize : Math.min(pageSize, limit - items.length); + + if (currentLimit <= 0) { + break; + } + + const requestVariables: IDataObject = { + ...variables, + first: currentLimit, + }; + if (cursor) { + requestVariables.after = cursor; + } + + const responseData = await proboApiRequest.call(this, query, requestVariables); + const connection = getConnection(responseData); + + if (connection?.edges) { + items.push(...connection.edges.map((edge: any) => edge.node)); + } + + if (connection?.pageInfo) { + hasNextPage = connection.pageInfo.hasNextPage; + cursor = connection.pageInfo.endCursor; + } else { + hasNextPage = false; + } + + if (!returnAll && items.length >= limit) { + hasNextPage = false; + } + } + + return items; +} diff --git a/packages/n8n-node/nodes/Probo/Probo.node.ts b/packages/n8n-node/nodes/Probo/Probo.node.ts index c73886187..81a9bb6d2 100644 --- a/packages/n8n-node/nodes/Probo/Probo.node.ts +++ b/packages/n8n-node/nodes/Probo/Probo.node.ts @@ -5,7 +5,11 @@ import { type INodeType, type INodeTypeDescription, } from 'n8n-workflow'; -import { executeOperation } from './operations'; +import { + getAllResourceOperations, + getAllResourceFields, + getExecuteFunction, +} from './actions'; export class Probo implements INodeType { description: INodeTypeDescription = { @@ -14,7 +18,7 @@ export class Probo implements INodeType { icon: { light: 'file:../../icons/probo.svg', dark: 'file:../../icons/probo.svg' }, group: ['input'], version: 1, - subtitle: '={{$parameter["operation"]}}', + subtitle: '={{$parameter["resource"]}} / {{$parameter["operation"]}}', description: 'Consume data from the Probo API', defaults: { name: 'Probo', @@ -53,8 +57,8 @@ export class Probo implements INodeType { default: 'apiKey', }, { - displayName: 'Operation', - name: 'operation', + displayName: 'Resource', + name: 'resource', type: 'options', noDataExpression: true, options: [ @@ -62,39 +66,17 @@ export class Probo implements INodeType { name: 'Execute', value: 'execute', description: 'Execute a GraphQL query or mutation', - action: 'Execute a GraphQL operation', + }, + { + name: 'Measure', + value: 'measure', + description: 'Manage measures', }, ], default: 'execute', }, - { - displayName: 'Query', - name: 'query', - type: 'string', - typeOptions: { - rows: 5, - }, - displayOptions: { - show: { - operation: ['execute'], - }, - }, - default: '', - description: 'The complete GraphQL operation including operation name and variable declarations (e.g., "query GetUser($userId: ID!) { node(id: $userId) { id } }" or "mutation UpdateUser($input: UpdateUserInput!) { updateUser(input: $input) { id } }")', - required: true, - }, - { - displayName: 'Variables', - name: 'variables', - type: 'json', - displayOptions: { - show: { - operation: ['execute'], - }, - }, - default: '{}', - description: 'GraphQL variables as JSON object', - }, + ...getAllResourceOperations(), + ...getAllResourceFields(), ], }; @@ -103,8 +85,11 @@ export class Probo implements INodeType { const returnData: INodeExecutionData[] = []; for (let i = 0; i < items.length; i++) { - const operation = this.getNodeParameter('operation', i) as string; - const result = await executeOperation.call(this, operation, i); + const resource = this.getNodeParameter('resource', i) as string; + const operation = this.getNodeParameter('operation', i, 'execute') as string; + + const executeFunction = getExecuteFunction(resource, operation); + const result = await executeFunction.call(this, i); returnData.push(result); } diff --git a/packages/n8n-node/nodes/Probo/actions/execute/execute.operation.ts b/packages/n8n-node/nodes/Probo/actions/execute/execute.operation.ts new file mode 100644 index 000000000..75e22d5e4 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/execute/execute.operation.ts @@ -0,0 +1,80 @@ +import { parse, getOperationAST, type DocumentNode } from 'graphql'; +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Query', + name: 'query', + type: 'string', + typeOptions: { + rows: 5, + }, + displayOptions: { + show: { + resource: ['execute'], + }, + }, + default: '', + description: + 'The complete GraphQL operation including operation name and variable declarations (e.g., "query GetUser($userId: ID!) { node(id: $userId) { id } }" or "mutation UpdateUser($input: UpdateUserInput!) { updateUser(input: $input) { id } }")', + required: true, + }, + { + displayName: 'Variables', + name: 'variables', + type: 'json', + displayOptions: { + show: { + resource: ['execute'], + }, + }, + default: '{}', + description: 'GraphQL variables as JSON object', + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const query = this.getNodeParameter('query', itemIndex) as string; + const variablesParam = this.getNodeParameter('variables', itemIndex) as string; + + let document: DocumentNode; + try { + document = parse(query); + } catch (error) { + throw new Error( + `Invalid GraphQL operation: ${error instanceof Error ? error.message : String(error)}`, + ); + } + + const operationAST = getOperationAST(document); + if (!operationAST) { + throw new Error('GraphQL operation must contain a query, mutation, or subscription'); + } + + if (!operationAST.name) { + throw new Error( + 'GraphQL operation must have a name (e.g., "query GetUser { ... }" or "mutation UpdateUser { ... }")', + ); + } + + let variables = {}; + if (variablesParam) { + try { + variables = + typeof variablesParam === 'string' ? JSON.parse(variablesParam) : variablesParam; + } catch (error) { + throw new Error(`Invalid JSON in Variables: ${error}`); + } + } + + const responseData = await proboApiRequest.call(this, query, variables); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/execute/index.ts b/packages/n8n-node/nodes/Probo/actions/execute/index.ts new file mode 100644 index 000000000..a937835c3 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/execute/index.ts @@ -0,0 +1,29 @@ +import type { INodeProperties } from 'n8n-workflow'; +import * as executeOp from './execute.operation'; + +export const description: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: ['execute'], + }, + }, + options: [ + { + name: 'Execute', + value: 'execute', + description: 'Execute a GraphQL query or mutation', + action: 'Execute GraphQL', + }, + ], + default: 'execute', + }, + ...executeOp.description, +]; + +export { executeOp as execute }; + diff --git a/packages/n8n-node/nodes/Probo/actions/index.ts b/packages/n8n-node/nodes/Probo/actions/index.ts new file mode 100644 index 000000000..806785092 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/index.ts @@ -0,0 +1,58 @@ +import type { IExecuteFunctions, INodeExecutionData, INodeProperties } from 'n8n-workflow'; +import * as execute from './execute'; +import * as measure from './measure'; + +export interface ResourceModule { + description: INodeProperties[]; + [key: string]: OperationModule | INodeProperties[] | any; +} + +export interface OperationModule { + description: INodeProperties[]; + execute: (this: IExecuteFunctions, itemIndex: number) => Promise; +} + +export const resources: Record = { + execute: execute as ResourceModule, + measure: measure as ResourceModule, +}; + +export function getAllResourceOperations(): INodeProperties[] { + const operations: INodeProperties[] = []; + + for (const resource of Object.values(resources)) { + const operationProp = resource.description.find((prop) => prop.name === 'operation'); + if (operationProp) { + operations.push(operationProp); + } + } + + return operations; +} + +export function getAllResourceFields(): INodeProperties[] { + const fields: INodeProperties[] = []; + + for (const resource of Object.values(resources)) { + fields.push(...resource.description.filter((prop) => prop.name !== 'operation')); + } + + return fields; +} + +export function getExecuteFunction(resourceName: string, operationName: string) { + const resource = resources[resourceName]; + if (!resource) { + throw new Error(`Unknown resource: ${resourceName}`); + } + + const operationKey = resourceName === 'execute' ? 'execute' : operationName; + + const operation = resource[operationKey] as OperationModule; + + if (!operation || typeof operation.execute !== 'function') { + throw new Error(`Unknown operation: ${operationName} for resource: ${resourceName}`); + } + + return operation.execute; +} diff --git a/packages/n8n-node/nodes/Probo/actions/measure/create.operation.ts b/packages/n8n-node/nodes/Probo/actions/measure/create.operation.ts new file mode 100644 index 000000000..6d429079f --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/measure/create.operation.ts @@ -0,0 +1,104 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['create'], + }, + }, + default: '', + description: 'The ID of the organization', + required: true, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['create'], + }, + }, + default: '', + description: 'The name of the measure', + required: true, + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['create'], + }, + }, + default: '', + description: 'The description of the measure', + }, + { + displayName: 'Category', + name: 'category', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['create'], + }, + }, + default: '', + description: 'The category of the measure', + required: true, + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const organizationId = this.getNodeParameter('organizationId', itemIndex) as string; + const name = this.getNodeParameter('name', itemIndex) as string; + const description = this.getNodeParameter('description', itemIndex, '') as string; + const category = this.getNodeParameter('category', itemIndex) as string; + + const query = ` + mutation CreateMeasure($input: CreateMeasureInput!) { + createMeasure(input: $input) { + measureEdge { + node { + id + name + description + category + state + createdAt + updatedAt + } + } + } + } + `; + + const variables = { + input: { + organizationId, + name, + ...(description && { description }), + category, + }, + }; + + const responseData = await proboApiRequest.call(this, query, variables); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/measure/delete.operation.ts b/packages/n8n-node/nodes/Probo/actions/measure/delete.operation.ts new file mode 100644 index 000000000..0ecc16459 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/measure/delete.operation.ts @@ -0,0 +1,41 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Measure ID', + name: 'measureId', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['delete'], + }, + }, + default: '', + description: 'The ID of the measure to delete', + required: true, + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const measureId = this.getNodeParameter('measureId', itemIndex) as string; + + const query = ` + mutation DeleteMeasure($input: DeleteMeasureInput!) { + deleteMeasure(input: $input) { + deletedMeasureId + } + } + `; + + const responseData = await proboApiRequest.call(this, query, { input: { measureId } }); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/measure/get.operation.ts b/packages/n8n-node/nodes/Probo/actions/measure/get.operation.ts new file mode 100644 index 000000000..8d71be8c3 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/measure/get.operation.ts @@ -0,0 +1,54 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Measure ID', + name: 'measureId', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['get'], + }, + }, + default: '', + description: 'The ID of the measure', + required: true, + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const measureId = this.getNodeParameter('measureId', itemIndex) as string; + + const query = ` + query GetMeasure($measureId: ID!) { + node(id: $measureId) { + ... on Measure { + id + name + description + category + state + createdAt + updatedAt + } + } + } + `; + + const variables = { + measureId, + }; + + const responseData = await proboApiRequest.call(this, query, variables); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} + diff --git a/packages/n8n-node/nodes/Probo/actions/measure/getAll.operation.ts b/packages/n8n-node/nodes/Probo/actions/measure/getAll.operation.ts new file mode 100644 index 000000000..0967ca0be --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/measure/getAll.operation.ts @@ -0,0 +1,98 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboApiRequestAllItems } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['getAll'], + }, + }, + default: '', + description: 'The ID of the organization', + required: true, + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: ['measure'], + operation: ['getAll'], + }, + }, + default: false, + description: 'Whether to return all results or only up to a given limit', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: ['measure'], + operation: ['getAll'], + returnAll: [false], + }, + }, + typeOptions: { + minValue: 1, + }, + default: 50, + description: 'Max number of results to return', + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const organizationId = this.getNodeParameter('organizationId', itemIndex) as string; + const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean; + const limit = this.getNodeParameter('limit', itemIndex, 50) as number; + + const query = ` + query GetMeasures($organizationId: ID!, $first: Int, $after: CursorKey) { + node(id: $organizationId) { + ... on Organization { + measures(first: $first, after: $after) { + edges { + node { + id + name + description + category + state + createdAt + updatedAt + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + } + `; + + const measures = await proboApiRequestAllItems.call( + this, + query, + { organizationId }, + (response) => response?.data?.node?.measures, + returnAll, + limit, + ); + + return { + json: { measures }, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/measure/index.ts b/packages/n8n-node/nodes/Probo/actions/measure/index.ts new file mode 100644 index 000000000..2c02e9757 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/measure/index.ts @@ -0,0 +1,61 @@ +import type { INodeProperties } from 'n8n-workflow'; +import * as createOp from './create.operation'; +import * as updateOp from './update.operation'; +import * as deleteOp from './delete.operation'; +import * as getOp from './get.operation'; +import * as getAllOp from './getAll.operation'; + +export const description: INodeProperties[] = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: ['measure'], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new measure', + action: 'Create a measure', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a measure', + action: 'Delete a measure', + }, + { + name: 'Get', + value: 'get', + description: 'Get a measure', + action: 'Get a measure', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all measures', + action: 'Get all measures', + }, + { + name: 'Update', + value: 'update', + description: 'Update an existing measure', + action: 'Update a measure', + }, + ], + default: 'create', + }, + ...createOp.description, + ...updateOp.description, + ...deleteOp.description, + ...getOp.description, + ...getAllOp.description, +]; + +export { createOp as create, updateOp as update, deleteOp as delete, getOp as get, getAllOp as getAll }; + diff --git a/packages/n8n-node/nodes/Probo/actions/measure/update.operation.ts b/packages/n8n-node/nodes/Probo/actions/measure/update.operation.ts new file mode 100644 index 000000000..a0b03f933 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/measure/update.operation.ts @@ -0,0 +1,129 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Measure ID', + name: 'id', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['update'], + }, + }, + default: '', + description: 'The ID of the measure to update', + required: true, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['update'], + }, + }, + default: '', + description: 'The name of the measure', + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['update'], + }, + }, + default: '', + description: 'The description of the measure', + }, + { + displayName: 'Category', + name: 'category', + type: 'string', + displayOptions: { + show: { + resource: ['measure'], + operation: ['update'], + }, + }, + default: '', + description: 'The category of the measure', + }, + { + displayName: 'State', + name: 'state', + type: 'options', + displayOptions: { + show: { + resource: ['measure'], + operation: ['update'], + }, + }, + options: [ + { + name: 'Not Started', + value: 'NOT_STARTED', + }, + { + name: 'In Progress', + value: 'IN_PROGRESS', + }, + { + name: 'Not Applicable', + value: 'NOT_APPLICABLE', + }, + { + name: 'Implemented', + value: 'IMPLEMENTED', + }, + ], + default: '', + description: 'The state of the measure', + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const id = this.getNodeParameter('id', itemIndex) as string; + const name = this.getNodeParameter('name', itemIndex, '') as string; + const description = this.getNodeParameter('description', itemIndex, '') as string; + const category = this.getNodeParameter('category', itemIndex, '') as string; + const state = this.getNodeParameter('state', itemIndex, '') as string; + + const query = ` + mutation UpdateMeasure($input: UpdateMeasureInput!) { + updateMeasure(input: $input) { + measure { + id + name + description + category + state + createdAt + updatedAt + } + } + } + `; + + const input: Record = { id }; + if (name) input.name = name; + if (description) input.description = description; + if (category) input.category = category; + if (state) input.state = state; + + const responseData = await proboApiRequest.call(this, query, { input }); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/operations/execute.ts b/packages/n8n-node/nodes/Probo/operations/execute.ts deleted file mode 100644 index c0da3119f..000000000 --- a/packages/n8n-node/nodes/Probo/operations/execute.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { parse, getOperationAST, type DocumentNode } from 'graphql'; -import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; - -export interface GraphQLParameters { - query: string; - variables?: string; -} - -export async function executeGraphQL( - this: IExecuteFunctions, - itemIndex: number, -): Promise { - const query = this.getNodeParameter('query', itemIndex) as string; - const variablesParam = this.getNodeParameter('variables', itemIndex) as string; - - let document: DocumentNode; - try { - document = parse(query); - } catch (error) { - throw new Error(`Invalid GraphQL operation: ${error instanceof Error ? error.message : String(error)}`); - } - - const operationAST = getOperationAST(document); - if (!operationAST) { - throw new Error('GraphQL operation must contain a query, mutation, or subscription'); - } - - if (!operationAST.name) { - throw new Error('GraphQL operation must have a name (e.g., "query GetUser { ... }" or "mutation UpdateUser { ... }")'); - } - - const operationName = operationAST.name.value; - - let variables = {}; - if (variablesParam) { - try { - variables = - typeof variablesParam === 'string' ? JSON.parse(variablesParam) : variablesParam; - } catch (error) { - throw new Error(`Invalid JSON in Variables: ${error}`); - } - } - - const body: { - query: string; - operationName?: string; - variables?: Record; - } = { - query, - operationName, - }; - - if (Object.keys(variables).length > 0) { - body.variables = variables; - } - - const credentials = await this.getCredentials('proboApi'); - - if (!credentials!.apiKey) { - throw new Error('API Key is required'); - } - - const responseData = await this.helpers.httpRequest({ - method: 'POST', - baseURL: `${credentials!.server}`, - url: '/api/console/v1/query', - headers: { - Authorization: `Bearer ${credentials!.apiKey}`, - 'Content-Type': 'application/json', - }, - body: body, - json: true, - returnFullResponse: true, - }); - - return { - json: responseData, - pairedItem: { item: itemIndex }, - }; -} - diff --git a/packages/n8n-node/nodes/Probo/operations/index.ts b/packages/n8n-node/nodes/Probo/operations/index.ts deleted file mode 100644 index 934e4a5f8..000000000 --- a/packages/n8n-node/nodes/Probo/operations/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; -import { executeGraphQL } from './execute'; - -export async function executeOperation( - this: IExecuteFunctions, - operation: string, - itemIndex: number, -): Promise { - switch (operation) { - case 'execute': - return executeGraphQL.call(this, itemIndex); - default: - throw new Error(`Unknown operation: ${operation}`); - } -} - diff --git a/packages/n8n-node/package.json b/packages/n8n-node/package.json index 82961071a..7c16eec94 100644 --- a/packages/n8n-node/package.json +++ b/packages/n8n-node/package.json @@ -25,14 +25,14 @@ }, "license": "ISC", "description": "", - "devDependencies": { - "@n8n/node-cli": "^0.17.0", - "eslint": "9.32.0" - }, "peerDependencies": { "n8n-workflow": "*" }, "dependencies": { "graphql": "^16.12.0" + }, + "devDependencies": { + "@n8n/node-cli": "^0.17.0", + "eslint": "9.32.0" } }