From 96a62e9adaf017c2a5be03693893a1ff2f1e025d Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Fri, 6 Feb 2026 10:32:37 +0100 Subject: [PATCH] Add member n8n actions Signed-off-by: Bryan Frimin --- packages/n8n-node/nodes/Probo/Probo.node.ts | 5 + .../n8n-node/nodes/Probo/actions/index.ts | 2 + .../Probo/actions/member/delete.operation.ts | 58 +++++++ .../Probo/actions/member/get.operation.ts | 124 ++++++++++++++ .../Probo/actions/member/getAll.operation.ts | 117 +++++++++++++ .../nodes/Probo/actions/member/index.ts | 60 +++++++ .../Probo/actions/member/invite.operation.ts | 113 ++++++++++++ .../Probo/actions/member/update.operation.ts | 161 ++++++++++++++++++ 8 files changed, 640 insertions(+) create mode 100644 packages/n8n-node/nodes/Probo/actions/member/delete.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/member/get.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/member/getAll.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/member/index.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/member/invite.operation.ts create mode 100644 packages/n8n-node/nodes/Probo/actions/member/update.operation.ts diff --git a/packages/n8n-node/nodes/Probo/Probo.node.ts b/packages/n8n-node/nodes/Probo/Probo.node.ts index 2f99db160..160ae4c05 100644 --- a/packages/n8n-node/nodes/Probo/Probo.node.ts +++ b/packages/n8n-node/nodes/Probo/Probo.node.ts @@ -97,6 +97,11 @@ export class Probo implements INodeType { value: 'meeting', description: 'Manage meetings', }, + { + name: 'Member', + value: 'member', + description: 'Manage organization members', + }, { name: 'Organization', value: 'organization', diff --git a/packages/n8n-node/nodes/Probo/actions/index.ts b/packages/n8n-node/nodes/Probo/actions/index.ts index 0a619ddbe..824c39a03 100644 --- a/packages/n8n-node/nodes/Probo/actions/index.ts +++ b/packages/n8n-node/nodes/Probo/actions/index.ts @@ -5,6 +5,7 @@ import * as datum from './datum'; import * as execute from './execute'; import * as framework from './framework'; import * as measure from './measure'; +import * as member from './member'; import * as meeting from './meeting'; import * as organization from './organization'; import * as people from './people'; @@ -28,6 +29,7 @@ export const resources: Record = { execute: execute as ResourceModule, framework: framework as ResourceModule, measure: measure as ResourceModule, + member: member as ResourceModule, meeting: meeting as ResourceModule, organization: organization as ResourceModule, people: people as ResourceModule, diff --git a/packages/n8n-node/nodes/Probo/actions/member/delete.operation.ts b/packages/n8n-node/nodes/Probo/actions/member/delete.operation.ts new file mode 100644 index 000000000..3ea3d6f73 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/member/delete.operation.ts @@ -0,0 +1,58 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboConnectApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['delete'], + }, + }, + default: '', + description: 'The ID of the organization', + required: true, + }, + { + displayName: 'Membership ID', + name: 'membershipId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['delete'], + }, + }, + default: '', + description: 'The ID of the membership to remove', + required: true, + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const organizationId = this.getNodeParameter('organizationId', itemIndex) as string; + const membershipId = this.getNodeParameter('membershipId', itemIndex) as string; + + const query = ` + mutation RemoveMember($input: RemoveMemberInput!) { + removeMember(input: $input) { + deletedMembershipId + } + } + `; + + const responseData = await proboConnectApiRequest.call(this, query, { + input: { organizationId, membershipId }, + }); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/member/get.operation.ts b/packages/n8n-node/nodes/Probo/actions/member/get.operation.ts new file mode 100644 index 000000000..9b306d6c4 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/member/get.operation.ts @@ -0,0 +1,124 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboConnectApiRequest } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Membership ID', + name: 'membershipId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['get'], + }, + }, + default: '', + description: 'The ID of the membership', + required: true, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: ['member'], + operation: ['get'], + }, + }, + options: [ + { + displayName: 'Include Identity', + name: 'includeIdentity', + type: 'boolean', + default: true, + description: 'Whether to include identity (email, fullName) in the response', + }, + { + displayName: 'Include Profile', + name: 'includeProfile', + type: 'boolean', + default: true, + description: 'Whether to include profile in the response', + }, + { + displayName: 'Include Organization', + name: 'includeOrganization', + type: 'boolean', + default: true, + description: 'Whether to include organization in the response', + }, + ], + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const membershipId = this.getNodeParameter('membershipId', itemIndex) as string; + const options = this.getNodeParameter('options', itemIndex, {}) as { + includeIdentity?: boolean; + includeProfile?: boolean; + includeOrganization?: boolean; + }; + + const identityFragment = + options.includeIdentity !== false + ? `identity { + id + email + fullName + emailVerified + }` + : ''; + + const profileFragment = + options.includeProfile !== false + ? `profile { + id + fullName + createdAt + updatedAt + }` + : ''; + + const organizationFragment = + options.includeOrganization !== false + ? `organization { + id + name + email + }` + : ''; + + const query = ` + query GetMember($membershipId: ID!) { + node(id: $membershipId) { + ... on Membership { + id + createdAt + role + source + state + ${identityFragment} + ${profileFragment} + ${organizationFragment} + } + } + } + `; + + const variables = { + membershipId, + }; + + const responseData = await proboConnectApiRequest.call(this, query, variables); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/member/getAll.operation.ts b/packages/n8n-node/nodes/Probo/actions/member/getAll.operation.ts new file mode 100644 index 000000000..1efaee73e --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/member/getAll.operation.ts @@ -0,0 +1,117 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData, IDataObject } from 'n8n-workflow'; +import { proboConnectApiRequestAllItems } from '../../GenericFunctions'; + +export const description: INodeProperties[] = [ + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['getAll'], + }, + }, + default: '', + description: 'The ID of the organization', + required: true, + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: ['member'], + 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: ['member'], + 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 GetMembers($organizationId: ID!, $first: Int, $after: CursorKey) { + node(id: $organizationId) { + ... on Organization { + members(first: $first, after: $after) { + edges { + node { + id + createdAt + role + source + state + identity { + id + email + fullName + emailVerified + } + profile { + id + fullName + createdAt + updatedAt + } + organization { + id + name + email + } + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + } + `; + + const members = await proboConnectApiRequestAllItems.call( + this, + query, + { organizationId }, + (response) => { + const data = response?.data as IDataObject | undefined; + const node = data?.node as IDataObject | undefined; + return node?.members as IDataObject | undefined; + }, + returnAll, + limit, + ); + + return { + json: { members }, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/member/index.ts b/packages/n8n-node/nodes/Probo/actions/member/index.ts new file mode 100644 index 000000000..c94baf837 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/member/index.ts @@ -0,0 +1,60 @@ +import type { INodeProperties } from 'n8n-workflow'; +import * as inviteOp from './invite.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: ['member'], + }, + }, + options: [ + { + name: 'Delete', + value: 'delete', + description: 'Remove a member from an organization', + action: 'Delete a member', + }, + { + name: 'Get', + value: 'get', + description: 'Get a member (membership) by ID', + action: 'Get a member', + }, + { + name: 'Get Many', + value: 'getAll', + description: 'Get many members of an organization', + action: 'Get many members', + }, + { + name: 'Invite', + value: 'invite', + description: 'Invite a new member to an organization', + action: 'Invite a member', + }, + { + name: 'Update', + value: 'update', + description: 'Update a member\'s role', + action: 'Update a member', + }, + ], + default: 'invite', + }, + ...inviteOp.description, + ...updateOp.description, + ...deleteOp.description, + ...getOp.description, + ...getAllOp.description, +]; + +export { inviteOp as invite, updateOp as update, deleteOp as delete, getOp as get, getAllOp as getAll }; diff --git a/packages/n8n-node/nodes/Probo/actions/member/invite.operation.ts b/packages/n8n-node/nodes/Probo/actions/member/invite.operation.ts new file mode 100644 index 000000000..bc84bd0c5 --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/member/invite.operation.ts @@ -0,0 +1,113 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboConnectApiRequest } from '../../GenericFunctions'; + +const roleOptions = [ + { name: 'Owner', value: 'OWNER' }, + { name: 'Admin', value: 'ADMIN' }, + { name: 'Employee', value: 'EMPLOYEE' }, + { name: 'Viewer', value: 'VIEWER' }, + { name: 'Auditor', value: 'AUDITOR' }, +]; + +export const description: INodeProperties[] = [ + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['invite'], + }, + }, + default: '', + description: 'The ID of the organization', + required: true, + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['invite'], + }, + }, + default: '', + placeholder: 'name@email.com', + description: 'Email address of the person to invite', + required: true, + }, + { + displayName: 'Full Name', + name: 'fullName', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['invite'], + }, + }, + default: '', + description: 'Full name of the person to invite', + required: true, + }, + { + displayName: 'Role', + name: 'role', + type: 'options', + displayOptions: { + show: { + resource: ['member'], + operation: ['invite'], + }, + }, + options: roleOptions, + default: 'EMPLOYEE', + description: 'Role to assign to the member', + required: true, + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const organizationId = this.getNodeParameter('organizationId', itemIndex) as string; + const email = this.getNodeParameter('email', itemIndex) as string; + const fullName = this.getNodeParameter('fullName', itemIndex) as string; + const role = this.getNodeParameter('role', itemIndex) as string; + + const query = ` + mutation InviteMember($input: InviteMemberInput!) { + inviteMember(input: $input) { + invitationEdge { + node { + id + email + fullName + role + expiresAt + status + createdAt + } + } + } + } + `; + + const input = { + organizationId, + email, + fullName, + role, + }; + + const responseData = await proboConnectApiRequest.call(this, query, { input }); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +} diff --git a/packages/n8n-node/nodes/Probo/actions/member/update.operation.ts b/packages/n8n-node/nodes/Probo/actions/member/update.operation.ts new file mode 100644 index 000000000..cc17c910e --- /dev/null +++ b/packages/n8n-node/nodes/Probo/actions/member/update.operation.ts @@ -0,0 +1,161 @@ +import type { INodeProperties, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; +import { proboConnectApiRequest } from '../../GenericFunctions'; + +const roleOptions = [ + { name: 'Owner', value: 'OWNER' }, + { name: 'Admin', value: 'ADMIN' }, + { name: 'Employee', value: 'EMPLOYEE' }, + { name: 'Viewer', value: 'VIEWER' }, + { name: 'Auditor', value: 'AUDITOR' }, +]; + +export const description: INodeProperties[] = [ + { + displayName: 'Organization ID', + name: 'organizationId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['update'], + }, + }, + default: '', + description: 'The ID of the organization', + required: true, + }, + { + displayName: 'Membership ID', + name: 'membershipId', + type: 'string', + displayOptions: { + show: { + resource: ['member'], + operation: ['update'], + }, + }, + default: '', + description: 'The ID of the membership to update', + required: true, + }, + { + displayName: 'Role', + name: 'role', + type: 'options', + displayOptions: { + show: { + resource: ['member'], + operation: ['update'], + }, + }, + options: roleOptions, + default: 'EMPLOYEE', + description: 'New role for the member', + required: true, + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: ['member'], + operation: ['update'], + }, + }, + options: [ + { + displayName: 'Include Identity', + name: 'includeIdentity', + type: 'boolean', + default: true, + description: 'Whether to include identity (email, fullName) in the response', + }, + { + displayName: 'Include Profile', + name: 'includeProfile', + type: 'boolean', + default: true, + description: 'Whether to include profile in the response', + }, + { + displayName: 'Include Organization', + name: 'includeOrganization', + type: 'boolean', + default: true, + description: 'Whether to include organization in the response', + }, + ], + }, +]; + +export async function execute( + this: IExecuteFunctions, + itemIndex: number, +): Promise { + const organizationId = this.getNodeParameter('organizationId', itemIndex) as string; + const membershipId = this.getNodeParameter('membershipId', itemIndex) as string; + const role = this.getNodeParameter('role', itemIndex) as string; + const options = this.getNodeParameter('options', itemIndex, {}) as { + includeIdentity?: boolean; + includeProfile?: boolean; + includeOrganization?: boolean; + }; + + const identityFragment = + options.includeIdentity !== false + ? `identity { + id + email + fullName + }` + : ''; + + const profileFragment = + options.includeProfile !== false + ? `profile { + id + fullName + }` + : ''; + + const organizationFragment = + options.includeOrganization !== false + ? `organization { + id + name + }` + : ''; + + const query = ` + mutation UpdateMembership($input: UpdateMembershipInput!) { + updateMembership(input: $input) { + membership { + id + createdAt + role + source + state + ${identityFragment} + ${profileFragment} + ${organizationFragment} + } + } + } + `; + + const input = { + organizationId, + membershipId, + role, + }; + + const responseData = await proboConnectApiRequest.call(this, query, { input }); + + return { + json: responseData, + pairedItem: { item: itemIndex }, + }; +}