mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-02 07:01:30 -08:00
✨ Add Kitemaker node (#1676)
* ⚡ Add Kitemaker node * ⚡ Require status ID for workItem:create * ✏️ Reword button text * ⚡ Add credentials file * ⚡ Implement pagination * ⚡ Improvements * ⚡ Remove not needed parameter Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
parent
efd40ea7a6
commit
4cf8055224
18
packages/nodes-base/credentials/KitemakerApi.credentials.ts
Normal file
18
packages/nodes-base/credentials/KitemakerApi.credentials.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class KitemakerApi implements ICredentialType {
|
||||
name = 'kitemakerApi';
|
||||
displayName = 'Kitemaker API';
|
||||
documentationUrl = 'kitemaker';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Personal Access Token',
|
||||
name: 'personalAccessToken',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
85
packages/nodes-base/nodes/Kitemaker/GenericFunctions.ts
Normal file
85
packages/nodes-base/nodes/Kitemaker/GenericFunctions.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
IHookFunctions,
|
||||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export async function kitemakerRequest(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
|
||||
body: IDataObject = {},
|
||||
) {
|
||||
const { personalAccessToken } = this.getCredentials('kitemakerApi') as { personalAccessToken: string };
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
Authorization: `Bearer ${personalAccessToken}`,
|
||||
},
|
||||
method: 'POST',
|
||||
body,
|
||||
uri: 'https://toil.kitemaker.co/developers/graphql',
|
||||
json: true,
|
||||
};
|
||||
|
||||
const responseData = await this.helpers.request!.call(this, options);
|
||||
|
||||
if (responseData.errors) {
|
||||
throw new NodeApiError(this.getNode(), responseData);
|
||||
}
|
||||
|
||||
return responseData;
|
||||
}
|
||||
|
||||
export async function kitemakerRequestAllItems(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||
body: { query: string; variables: { [key: string]: string } },
|
||||
) {
|
||||
const resource = this.getNodeParameter('resource', 0) as 'space' | 'user' | 'workItem';
|
||||
const [group, items] = getGroupAndItems(resource);
|
||||
|
||||
const returnAll = this.getNodeParameter('returnAll', 0, false) as boolean;
|
||||
const limit = this.getNodeParameter('limit', 0, 0) as number;
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
let responseData;
|
||||
|
||||
do {
|
||||
responseData = await kitemakerRequest.call(this, body);
|
||||
body.variables.cursor = responseData.data[group].cursor;
|
||||
returnData.push(...responseData.data[group][items]);
|
||||
|
||||
if (!returnAll && returnData.length > limit) {
|
||||
return returnData.slice(0, limit);
|
||||
}
|
||||
|
||||
} while (responseData.data[group].hasMore);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
function getGroupAndItems(resource: 'space' | 'user' | 'workItem') {
|
||||
const map: { [key: string]: { [key: string]: string } } = {
|
||||
space: { group: 'organization', items: 'spaces' },
|
||||
user: { group: 'organization', items: 'users' },
|
||||
workItem: { group: 'workItems', items: 'workItems' },
|
||||
};
|
||||
|
||||
return [
|
||||
map[resource]['group'],
|
||||
map[resource]['items'],
|
||||
];
|
||||
}
|
||||
|
||||
export function createLoadOptions(
|
||||
resources: Array<{ name?: string; username?: string; title?: string; id: string }>,
|
||||
): Array<{ name: string; value: string }> {
|
||||
return resources.map(option => {
|
||||
if (option.username) return ({ name: option.username, value: option.id });
|
||||
if (option.title) return ({ name: option.title, value: option.id });
|
||||
return ({ name: option.name ?? 'Unnamed', value: option.id });
|
||||
});
|
||||
}
|
321
packages/nodes-base/nodes/Kitemaker/Kitemaker.node.ts
Normal file
321
packages/nodes-base/nodes/Kitemaker/Kitemaker.node.ts
Normal file
|
@ -0,0 +1,321 @@
|
|||
import {
|
||||
IExecuteFunctions
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
ILoadOptionsFunctions,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
organizationOperations,
|
||||
spaceFields,
|
||||
spaceOperations,
|
||||
userFields,
|
||||
userOperations,
|
||||
workItemFields,
|
||||
workItemOperations,
|
||||
} from './descriptions';
|
||||
|
||||
import {
|
||||
createLoadOptions,
|
||||
kitemakerRequest,
|
||||
kitemakerRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import {
|
||||
getAllSpaces,
|
||||
getAllUsers,
|
||||
getAllWorkItems,
|
||||
getLabels,
|
||||
getOrganization,
|
||||
getSpaces,
|
||||
getStatuses,
|
||||
getUsers,
|
||||
getWorkItem,
|
||||
getWorkItems,
|
||||
} from './queries';
|
||||
|
||||
import {
|
||||
createWorkItem,
|
||||
editWorkItem,
|
||||
} from './mutations';
|
||||
|
||||
export class Kitemaker implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Kitemaker',
|
||||
name: 'kitemaker',
|
||||
icon: 'file:kitemaker.svg',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
|
||||
description: 'Consume the Kitemaker GraphQL API',
|
||||
defaults: {
|
||||
name: 'Kitemaker',
|
||||
color: '#662482',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'kitemakerApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Organization',
|
||||
value: 'organization',
|
||||
},
|
||||
{
|
||||
name: 'Space',
|
||||
value: 'space',
|
||||
},
|
||||
{
|
||||
name: 'User',
|
||||
value: 'user',
|
||||
},
|
||||
{
|
||||
name: 'Work Item',
|
||||
value: 'workItem',
|
||||
},
|
||||
],
|
||||
default: 'workItem',
|
||||
required: true,
|
||||
description: 'Resource to operate on.',
|
||||
},
|
||||
...organizationOperations,
|
||||
...spaceOperations,
|
||||
...spaceFields,
|
||||
...userOperations,
|
||||
...userFields,
|
||||
...workItemOperations,
|
||||
...workItemFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
async getLabels(this: ILoadOptionsFunctions) {
|
||||
const responseData = await kitemakerRequest.call(this, { query: getLabels });
|
||||
const { data: { organization: { spaces } } } = responseData;
|
||||
|
||||
return createLoadOptions(spaces[0].labels);
|
||||
},
|
||||
|
||||
async getSpaces(this: ILoadOptionsFunctions) {
|
||||
const responseData = await kitemakerRequest.call(this, { query: getSpaces });
|
||||
const { data: { organization: { spaces } } } = responseData;
|
||||
|
||||
return createLoadOptions(spaces);
|
||||
},
|
||||
|
||||
async getStatuses(this: ILoadOptionsFunctions) {
|
||||
const responseData = await kitemakerRequest.call(this, { query: getStatuses });
|
||||
const { data: { organization: { spaces } } } = responseData;
|
||||
|
||||
return createLoadOptions(spaces[0].statuses);
|
||||
},
|
||||
|
||||
async getUsers(this: ILoadOptionsFunctions) {
|
||||
const responseData = await kitemakerRequest.call(this, { query: getUsers });
|
||||
const { data: { organization: { users } } } = responseData;
|
||||
|
||||
return createLoadOptions(users);
|
||||
},
|
||||
|
||||
async getWorkItems(this: ILoadOptionsFunctions) {
|
||||
const spaceId = this.getNodeParameter('spaceId', 0) as string;
|
||||
|
||||
const responseData = await kitemakerRequest.call(this, {
|
||||
query: getWorkItems,
|
||||
variables: { spaceId },
|
||||
});
|
||||
|
||||
const { data: { workItems: { workItems } } } = responseData;
|
||||
|
||||
return createLoadOptions(workItems);
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
|
||||
let responseData;
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
// https://github.com/kitemakerhq/docs/blob/main/kitemaker.graphql
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
||||
if (resource === 'organization') {
|
||||
|
||||
// *********************************************************************
|
||||
// organization
|
||||
// *********************************************************************
|
||||
|
||||
if (operation === 'get') {
|
||||
|
||||
// ----------------------------------
|
||||
// organization: get
|
||||
// ----------------------------------
|
||||
|
||||
responseData = await kitemakerRequest.call(this, {
|
||||
query: getOrganization,
|
||||
});
|
||||
|
||||
returnData.push(responseData.data.organization);
|
||||
|
||||
}
|
||||
|
||||
} else if (resource === 'space') {
|
||||
|
||||
// *********************************************************************
|
||||
// space
|
||||
// *********************************************************************
|
||||
|
||||
if (operation === 'getAll') {
|
||||
|
||||
// ----------------------------------
|
||||
// space: getAll
|
||||
// ----------------------------------
|
||||
|
||||
const allItems = await kitemakerRequestAllItems.call(this, {
|
||||
query: getAllSpaces,
|
||||
variables: {},
|
||||
});
|
||||
|
||||
returnData.push(...allItems);
|
||||
|
||||
}
|
||||
|
||||
} else if (resource === 'user') {
|
||||
|
||||
// *********************************************************************
|
||||
// user
|
||||
// *********************************************************************
|
||||
|
||||
if (operation === 'getAll') {
|
||||
|
||||
// ----------------------------------
|
||||
// user: getAll
|
||||
// ----------------------------------
|
||||
|
||||
const allItems = await kitemakerRequestAllItems.call(this, {
|
||||
query: getAllUsers,
|
||||
variables: {},
|
||||
});
|
||||
|
||||
returnData.push(...allItems);
|
||||
|
||||
}
|
||||
|
||||
} else if (resource === 'workItem') {
|
||||
|
||||
// *********************************************************************
|
||||
// workItem
|
||||
// *********************************************************************
|
||||
|
||||
if (operation === 'create') {
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: create
|
||||
// ----------------------------------
|
||||
|
||||
const input = {
|
||||
title: this.getNodeParameter('title', i) as string,
|
||||
statusId: this.getNodeParameter('statusId', i) as string[],
|
||||
};
|
||||
|
||||
if (!input.statusId.length) {
|
||||
throw new Error('Please enter a status to set for the work item to create.');
|
||||
}
|
||||
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
|
||||
if (Object.keys(additionalFields).length) {
|
||||
Object.assign(input, additionalFields);
|
||||
}
|
||||
|
||||
responseData = await kitemakerRequest.call(this, {
|
||||
query: createWorkItem,
|
||||
variables: { input },
|
||||
});
|
||||
|
||||
returnData.push(responseData.data.createWorkItem.workItem);
|
||||
|
||||
} else if (operation === 'get') {
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: get
|
||||
// ----------------------------------
|
||||
|
||||
const workItemId = this.getNodeParameter('workItemId', i) as string;
|
||||
|
||||
responseData = await kitemakerRequest.call(this, {
|
||||
query: getWorkItem,
|
||||
variables: { workItemId },
|
||||
});
|
||||
|
||||
returnData.push(responseData.data.workItem);
|
||||
|
||||
} else if (operation === 'getAll') {
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: getAll
|
||||
// ----------------------------------
|
||||
|
||||
const allItems = await kitemakerRequestAllItems.call(this, {
|
||||
query: getAllWorkItems,
|
||||
variables: {
|
||||
spaceId: this.getNodeParameter('spaceId', i) as string,
|
||||
},
|
||||
});
|
||||
|
||||
returnData.push(...allItems);
|
||||
|
||||
} else if (operation === 'update') {
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: update
|
||||
// ----------------------------------
|
||||
|
||||
const input = {
|
||||
id: this.getNodeParameter('workItemId', i),
|
||||
};
|
||||
|
||||
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
|
||||
|
||||
if (!Object.keys(updateFields).length) {
|
||||
throw new Error('Please enter at least one field to update for the work item.');
|
||||
}
|
||||
|
||||
Object.assign(input, updateFields);
|
||||
|
||||
responseData = await kitemakerRequest.call(this, {
|
||||
query: editWorkItem,
|
||||
variables: { input },
|
||||
});
|
||||
|
||||
returnData.push(responseData.data.editWorkItem.workItem);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import {
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export const organizationOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
default: 'get',
|
||||
description: 'Operation to perform.',
|
||||
options: [
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Retrieve data on the logged-in user\'s organization.',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'organization',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,71 @@
|
|||
import {
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export const spaceOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
default: 'getAll',
|
||||
description: 'Operation to perform.',
|
||||
options: [
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Retrieve data on all the spaces in the<br>logged-in user\'s organization.',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'space',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const spaceFields = [
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Return all results.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'space',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
default: 5,
|
||||
description: 'The number of results to return.',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 1000,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'space',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,71 @@
|
|||
import {
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export const userOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
default: 'getAll',
|
||||
description: 'Operation to perform.',
|
||||
options: [
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Retrieve data on all the users in the<br>logged-in user\'s organization.',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'user',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const userFields = [
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Return all results.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'user',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
default: 5,
|
||||
description: 'The number of results to return.',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 1000,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'user',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,372 @@
|
|||
import {
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export const workItemOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
default: 'get',
|
||||
description: 'Operation to perform.',
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const workItemFields = [
|
||||
// ----------------------------------
|
||||
// workItem: create
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Title of the work item to create.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Status ID',
|
||||
name: 'statusId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getStatuses',
|
||||
},
|
||||
default: [],
|
||||
required: true,
|
||||
description: 'ID of the status to set on the item to create.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
description: 'Description of the item to create. Markdown supported.',
|
||||
},
|
||||
{
|
||||
displayName: 'Effort',
|
||||
name: 'effort',
|
||||
type: 'options',
|
||||
default: 'SMALL',
|
||||
description: 'Effort to set for the item to create.',
|
||||
options: [
|
||||
{
|
||||
name: 'Small',
|
||||
value: 'SMALL',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: 'MEDIUM',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
value: 'LARGE',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Impact',
|
||||
name: 'impact',
|
||||
type: 'options',
|
||||
default: 'SMALL',
|
||||
description: 'Impact to set for the item to create.',
|
||||
options: [
|
||||
{
|
||||
name: 'Small',
|
||||
value: 'SMALL',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: 'MEDIUM',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
value: 'LARGE',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Label IDs',
|
||||
name: 'labelIds',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLabels',
|
||||
},
|
||||
default: [],
|
||||
description: 'ID of the label to set on the item to create.',
|
||||
},
|
||||
{
|
||||
displayName: 'Member IDs',
|
||||
name: 'memberIds',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getUsers',
|
||||
},
|
||||
default: [],
|
||||
description: 'ID of the user to assign to the item to create.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: get
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Work Item ID',
|
||||
name: 'workItemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'ID of the work item to retrieve.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Space ID',
|
||||
name: 'spaceId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getSpaces',
|
||||
},
|
||||
default: [],
|
||||
required: true,
|
||||
description: 'ID of the space to retrieve the work items from.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Return all results.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
default: 5,
|
||||
description: 'The number of results to return.',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 1000,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// workItem: update
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Work Item ID',
|
||||
name: 'workItemId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'ID of the work item to update.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workItem',
|
||||
],
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
description: 'Description of the item to update. Markdown supported.',
|
||||
},
|
||||
{
|
||||
displayName: 'Effort',
|
||||
name: 'effort',
|
||||
type: 'options',
|
||||
default: 'SMALL',
|
||||
description: 'Effort to set for the item to update.',
|
||||
options: [
|
||||
{
|
||||
name: 'Small',
|
||||
value: 'SMALL',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: 'MEDIUM',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
value: 'LARGE',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Impact',
|
||||
name: 'impact',
|
||||
type: 'options',
|
||||
default: 'SMALL',
|
||||
description: 'Impact to set for the item to update.',
|
||||
options: [
|
||||
{
|
||||
name: 'Small',
|
||||
value: 'SMALL',
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: 'MEDIUM',
|
||||
},
|
||||
{
|
||||
name: 'Large',
|
||||
value: 'LARGE',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Status ID',
|
||||
name: 'statusId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getStatuses',
|
||||
},
|
||||
default: [],
|
||||
description: 'ID of the status to set on the item to update.',
|
||||
},
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Title to set for the work item to update.',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,4 @@
|
|||
export * from './OrganizationDescription';
|
||||
export * from './SpaceDescription';
|
||||
export * from './UserDescription';
|
||||
export * from './WorkItemDescription';
|
18
packages/nodes-base/nodes/Kitemaker/kitemaker.svg
Normal file
18
packages/nodes-base/nodes/Kitemaker/kitemaker.svg
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="170.000000pt" height="170.000000pt" viewBox="-30 -25 220.000000 220.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,170.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path fill="#662482" d="M1065 1445 c-302 -140 -560 -254 -572 -254 -17 -1 -61 50 -200 229
|
||||
-178 229 -206 256 -242 233 -14 -9 -16 -89 -19 -793 -1 -570 1 -786 9 -796 35
|
||||
-43 33 -46 852 774 558 558 787 794 787 809 0 26 -25 53 -48 52 -9 0 -264
|
||||
-115 -567 -254z"/>
|
||||
<path fill="#e61b73" d="M694 448 c-133 -134 -244 -251 -247 -260 -3 -9 2 -26 11 -38 16 -18
|
||||
67 -26 599 -85 320 -35 589 -62 597 -59 19 7 29 38 21 62 -3 9 -159 152 -346
|
||||
317 -241 212 -348 301 -367 303 -23 2 -59 -30 -268 -240z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 922 B |
69
packages/nodes-base/nodes/Kitemaker/mutations.ts
Normal file
69
packages/nodes-base/nodes/Kitemaker/mutations.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
// ----------------------------------
|
||||
// mutations
|
||||
// ----------------------------------
|
||||
|
||||
export const createWorkItem = `
|
||||
mutation($input: CreateWorkItemInput!) {
|
||||
createWorkItem(input: $input) {
|
||||
workItem {
|
||||
id
|
||||
number
|
||||
title
|
||||
description
|
||||
status {
|
||||
id
|
||||
name
|
||||
}
|
||||
members {
|
||||
id
|
||||
username
|
||||
}
|
||||
watchers {
|
||||
id
|
||||
username
|
||||
}
|
||||
labels {
|
||||
id
|
||||
name
|
||||
}
|
||||
effort
|
||||
impact
|
||||
updatedAt
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const editWorkItem = `
|
||||
mutation ($input: EditWorkItemInput!) {
|
||||
editWorkItem(input: $input) {
|
||||
workItem {
|
||||
id
|
||||
number
|
||||
title
|
||||
description
|
||||
status {
|
||||
id
|
||||
name
|
||||
}
|
||||
members {
|
||||
id
|
||||
username
|
||||
}
|
||||
watchers {
|
||||
id
|
||||
username
|
||||
}
|
||||
labels {
|
||||
id
|
||||
name
|
||||
}
|
||||
effort
|
||||
impact
|
||||
updatedAt
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
199
packages/nodes-base/nodes/Kitemaker/queries.ts
Normal file
199
packages/nodes-base/nodes/Kitemaker/queries.ts
Normal file
|
@ -0,0 +1,199 @@
|
|||
// ----------------------------------
|
||||
// queries
|
||||
// ----------------------------------
|
||||
|
||||
export const getAllSpaces = `
|
||||
query {
|
||||
organization {
|
||||
spaces {
|
||||
id
|
||||
name
|
||||
labels {
|
||||
id
|
||||
name
|
||||
color
|
||||
}
|
||||
statuses {
|
||||
id
|
||||
name
|
||||
type
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getAllUsers = `
|
||||
query {
|
||||
organization {
|
||||
users {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getLabels = `
|
||||
query {
|
||||
organization {
|
||||
spaces {
|
||||
labels {
|
||||
id
|
||||
name
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getOrganization = `
|
||||
query {
|
||||
organization {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getSpaces = `
|
||||
query {
|
||||
organization {
|
||||
spaces {
|
||||
id
|
||||
name
|
||||
labels {
|
||||
id
|
||||
name
|
||||
color
|
||||
}
|
||||
statuses {
|
||||
id
|
||||
name
|
||||
type
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getStatuses = `
|
||||
query {
|
||||
organization {
|
||||
spaces {
|
||||
statuses {
|
||||
id
|
||||
name
|
||||
type
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getUsers = `
|
||||
query {
|
||||
organization {
|
||||
users {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getWorkItems = `
|
||||
query($spaceId: ID!) {
|
||||
workItems(spaceId: $spaceId) {
|
||||
workItems {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getWorkItem = `
|
||||
query($workItemId: ID!) {
|
||||
workItem(id: $workItemId) {
|
||||
id
|
||||
number
|
||||
title
|
||||
description
|
||||
status {
|
||||
id
|
||||
name
|
||||
}
|
||||
sort
|
||||
members {
|
||||
id
|
||||
username
|
||||
}
|
||||
watchers {
|
||||
id
|
||||
username
|
||||
}
|
||||
labels {
|
||||
id
|
||||
name
|
||||
}
|
||||
comments {
|
||||
id
|
||||
actor {
|
||||
__typename
|
||||
}
|
||||
body
|
||||
threadId
|
||||
updatedAt
|
||||
createdAt
|
||||
}
|
||||
effort
|
||||
impact
|
||||
updatedAt
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getAllWorkItems = `
|
||||
query($spaceId: ID!, $cursor: String) {
|
||||
workItems(spaceId: $spaceId, cursor: $cursor) {
|
||||
hasMore,
|
||||
cursor,
|
||||
workItems {
|
||||
id
|
||||
title
|
||||
description
|
||||
labels {
|
||||
id
|
||||
}
|
||||
comments {
|
||||
id
|
||||
body
|
||||
actor {
|
||||
... on User {
|
||||
id
|
||||
username
|
||||
}
|
||||
... on IntegrationUser {
|
||||
id
|
||||
externalName
|
||||
}
|
||||
... on Integration {
|
||||
id
|
||||
type
|
||||
}
|
||||
... on Application {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -133,6 +133,7 @@
|
|||
"dist/credentials/JotFormApi.credentials.js",
|
||||
"dist/credentials/Kafka.credentials.js",
|
||||
"dist/credentials/KeapOAuth2Api.credentials.js",
|
||||
"dist/credentials/KitemakerApi.credentials.js",
|
||||
"dist/credentials/LemlistApi.credentials.js",
|
||||
"dist/credentials/LineNotifyOAuth2Api.credentials.js",
|
||||
"dist/credentials/LingvaNexApi.credentials.js",
|
||||
|
@ -406,6 +407,7 @@
|
|||
"dist/nodes/Kafka/KafkaTrigger.node.js",
|
||||
"dist/nodes/Keap/Keap.node.js",
|
||||
"dist/nodes/Keap/KeapTrigger.node.js",
|
||||
"dist/nodes/Kitemaker/Kitemaker.node.js",
|
||||
"dist/nodes/Lemlist/Lemlist.node.js",
|
||||
"dist/nodes/Lemlist/LemlistTrigger.node.js",
|
||||
"dist/nodes/Line/Line.node.js",
|
||||
|
|
Loading…
Reference in a new issue