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,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.flow",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Productivity"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/flow/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.flow/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
JsonObject,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeApiError } from 'n8n-workflow';
|
||||
|
||||
import { flowApiRequest, FlowApiRequestAllItems } from './GenericFunctions';
|
||||
import { taskFields, taskOperations } from './TaskDescription';
|
||||
import type { ITask, TaskInfo } from './TaskInterface';
|
||||
|
||||
export class Flow implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Flow',
|
||||
name: 'flow',
|
||||
icon: 'file:flow.svg',
|
||||
group: ['output'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Flow API',
|
||||
defaults: {
|
||||
name: 'Flow',
|
||||
},
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'flowApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Task',
|
||||
value: 'task',
|
||||
description:
|
||||
'Tasks are units of work that can be private or assigned to a list. Through this endpoint, you can manipulate your tasks in Flow, including creating new ones.',
|
||||
},
|
||||
],
|
||||
default: 'task',
|
||||
},
|
||||
...taskOperations,
|
||||
...taskFields,
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const credentials = await this.getCredentials('flowApi');
|
||||
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const length = items.length;
|
||||
let responseData;
|
||||
const qs: IDataObject = {};
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (resource === 'task') {
|
||||
//https://developer.getflow.com/api/#tasks_create-task
|
||||
if (operation === 'create') {
|
||||
const workspaceId = this.getNodeParameter('workspaceId', i) as string;
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i);
|
||||
const body: ITask = {
|
||||
organization_id: credentials.organizationId as number,
|
||||
};
|
||||
const task: TaskInfo = {
|
||||
name,
|
||||
workspace_id: parseInt(workspaceId, 10),
|
||||
};
|
||||
if (additionalFields.ownerId) {
|
||||
task.owner_id = parseInt(additionalFields.ownerId as string, 10);
|
||||
}
|
||||
if (additionalFields.listId) {
|
||||
task.list_id = parseInt(additionalFields.listId as string, 10);
|
||||
}
|
||||
if (additionalFields.startsOn) {
|
||||
task.starts_on = additionalFields.startsOn as string;
|
||||
}
|
||||
if (additionalFields.dueOn) {
|
||||
task.due_on = additionalFields.dueOn as string;
|
||||
}
|
||||
if (additionalFields.mirrorParentSubscribers) {
|
||||
task.mirror_parent_subscribers = additionalFields.mirrorParentSubscribers as boolean;
|
||||
}
|
||||
if (additionalFields.mirrorParentTags) {
|
||||
task.mirror_parent_tags = additionalFields.mirrorParentTags as boolean;
|
||||
}
|
||||
if (additionalFields.noteContent) {
|
||||
task.note_content = additionalFields.noteContent as string;
|
||||
}
|
||||
if (additionalFields.noteMimeType) {
|
||||
task.note_mime_type = additionalFields.noteMimeType as string;
|
||||
}
|
||||
if (additionalFields.parentId) {
|
||||
task.parent_id = parseInt(additionalFields.parentId as string, 10);
|
||||
}
|
||||
if (additionalFields.positionList) {
|
||||
task.position_list = additionalFields.positionList as number;
|
||||
}
|
||||
if (additionalFields.positionUpcoming) {
|
||||
task.position_upcoming = additionalFields.positionUpcoming as number;
|
||||
}
|
||||
if (additionalFields.position) {
|
||||
task.position = additionalFields.position as number;
|
||||
}
|
||||
if (additionalFields.sectionId) {
|
||||
task.section_id = additionalFields.sectionId as number;
|
||||
}
|
||||
if (additionalFields.tags) {
|
||||
task.tags = (additionalFields.tags as string).split(',');
|
||||
}
|
||||
body.task = task;
|
||||
try {
|
||||
responseData = await flowApiRequest.call(this, 'POST', '/tasks', body);
|
||||
responseData = responseData.task;
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
//https://developer.getflow.com/api/#tasks_update-a-task
|
||||
if (operation === 'update') {
|
||||
const workspaceId = this.getNodeParameter('workspaceId', i) as string;
|
||||
const taskId = this.getNodeParameter('taskId', i) as string;
|
||||
const updateFields = this.getNodeParameter('updateFields', i);
|
||||
const body: ITask = {
|
||||
organization_id: credentials.organizationId as number,
|
||||
};
|
||||
const task: TaskInfo = {
|
||||
workspace_id: parseInt(workspaceId, 10),
|
||||
id: parseInt(taskId, 10),
|
||||
};
|
||||
if (updateFields.name) {
|
||||
task.name = updateFields.name as string;
|
||||
}
|
||||
if (updateFields.ownerId) {
|
||||
task.owner_id = parseInt(updateFields.ownerId as string, 10);
|
||||
}
|
||||
if (updateFields.listId) {
|
||||
task.list_id = parseInt(updateFields.listId as string, 10);
|
||||
}
|
||||
if (updateFields.startsOn) {
|
||||
task.starts_on = updateFields.startsOn as string;
|
||||
}
|
||||
if (updateFields.dueOn) {
|
||||
task.due_on = updateFields.dueOn as string;
|
||||
}
|
||||
if (updateFields.mirrorParentSubscribers) {
|
||||
task.mirror_parent_subscribers = updateFields.mirrorParentSubscribers as boolean;
|
||||
}
|
||||
if (updateFields.mirrorParentTags) {
|
||||
task.mirror_parent_tags = updateFields.mirrorParentTags as boolean;
|
||||
}
|
||||
if (updateFields.noteContent) {
|
||||
task.note_content = updateFields.noteContent as string;
|
||||
}
|
||||
if (updateFields.noteMimeType) {
|
||||
task.note_mime_type = updateFields.noteMimeType as string;
|
||||
}
|
||||
if (updateFields.parentId) {
|
||||
task.parent_id = parseInt(updateFields.parentId as string, 10);
|
||||
}
|
||||
if (updateFields.positionList) {
|
||||
task.position_list = updateFields.positionList as number;
|
||||
}
|
||||
if (updateFields.positionUpcoming) {
|
||||
task.position_upcoming = updateFields.positionUpcoming as number;
|
||||
}
|
||||
if (updateFields.position) {
|
||||
task.position = updateFields.position as number;
|
||||
}
|
||||
if (updateFields.sectionId) {
|
||||
task.section_id = updateFields.sectionId as number;
|
||||
}
|
||||
if (updateFields.tags) {
|
||||
task.tags = (updateFields.tags as string).split(',');
|
||||
}
|
||||
if (updateFields.completed) {
|
||||
task.completed = updateFields.completed as boolean;
|
||||
}
|
||||
body.task = task;
|
||||
try {
|
||||
responseData = await flowApiRequest.call(this, 'PUT', `/tasks/${taskId}`, body);
|
||||
responseData = responseData.task;
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
//https://developer.getflow.com/api/#tasks_get-task
|
||||
if (operation === 'get') {
|
||||
const taskId = this.getNodeParameter('taskId', i) as string;
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
qs.organization_id = credentials.organizationId as number;
|
||||
if (filters.include) {
|
||||
qs.include = (filters.include as string[]).join(',');
|
||||
}
|
||||
try {
|
||||
responseData = await flowApiRequest.call(this, 'GET', `/tasks/${taskId}`, {}, qs);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
//https://developer.getflow.com/api/#tasks_get-tasks
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
qs.organization_id = credentials.organizationId as number;
|
||||
if (filters.include) {
|
||||
qs.include = (filters.include as string[]).join(',');
|
||||
}
|
||||
if (filters.order) {
|
||||
qs.order = filters.order as string;
|
||||
}
|
||||
if (filters.workspaceId) {
|
||||
qs.workspace_id = filters.workspaceId as string;
|
||||
}
|
||||
if (filters.createdBefore) {
|
||||
qs.created_before = filters.createdBefore as string;
|
||||
}
|
||||
if (filters.createdAfter) {
|
||||
qs.created_after = filters.createdAfter as string;
|
||||
}
|
||||
if (filters.updateBefore) {
|
||||
qs.updated_before = filters.updateBefore as string;
|
||||
}
|
||||
if (filters.updateAfter) {
|
||||
qs.updated_after = filters.updateAfter as string;
|
||||
}
|
||||
if (filters.deleted) {
|
||||
qs.deleted = filters.deleted as boolean;
|
||||
}
|
||||
if (filters.cleared) {
|
||||
qs.cleared = filters.cleared as boolean;
|
||||
}
|
||||
try {
|
||||
if (returnAll) {
|
||||
responseData = await FlowApiRequestAllItems.call(
|
||||
this,
|
||||
'tasks',
|
||||
'GET',
|
||||
'/tasks',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
qs.limit = this.getNodeParameter('limit', i);
|
||||
responseData = await flowApiRequest.call(this, 'GET', '/tasks', {}, qs);
|
||||
responseData = responseData.tasks;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject, { itemIndex: i });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
}
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.flowTrigger",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Productivity"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/flow/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.flowtrigger/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
import type {
|
||||
IHookFunctions,
|
||||
IWebhookFunctions,
|
||||
IDataObject,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IWebhookResponseData,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { flowApiRequest } from './GenericFunctions';
|
||||
|
||||
export class FlowTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Flow Trigger',
|
||||
name: 'flowTrigger',
|
||||
icon: 'file:flow.svg',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Handle Flow events via webhooks',
|
||||
defaults: {
|
||||
name: 'Flow Trigger',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'flowApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
default: '',
|
||||
options: [
|
||||
{
|
||||
name: 'Project',
|
||||
value: 'list',
|
||||
},
|
||||
{
|
||||
name: 'Task',
|
||||
value: 'task',
|
||||
},
|
||||
],
|
||||
description: 'Resource that triggers the webhook',
|
||||
},
|
||||
{
|
||||
displayName: 'Project ID',
|
||||
name: 'listIds',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['list'],
|
||||
},
|
||||
hide: {
|
||||
resource: ['task'],
|
||||
},
|
||||
},
|
||||
description: 'Lists IDs, perhaps known better as "Projects" separated by a comma (,)',
|
||||
},
|
||||
{
|
||||
displayName: 'Task ID',
|
||||
name: 'taskIds',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
},
|
||||
hide: {
|
||||
resource: ['list'],
|
||||
},
|
||||
},
|
||||
description: 'Task IDs separated by a comma (,)',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
webhookMethods = {
|
||||
default: {
|
||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
const credentials = await this.getCredentials('flowApi');
|
||||
|
||||
let webhooks;
|
||||
const qs: IDataObject = {};
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
if (!Array.isArray(webhookData.webhookIds)) {
|
||||
webhookData.webhookIds = [];
|
||||
}
|
||||
if (!(webhookData.webhookIds as [number]).length) {
|
||||
return false;
|
||||
}
|
||||
qs.organization_id = credentials.organizationId as number;
|
||||
const endpoint = '/integration_webhooks';
|
||||
webhooks = await flowApiRequest.call(this, 'GET', endpoint, {}, qs);
|
||||
webhooks = webhooks.integration_webhooks;
|
||||
for (const webhook of webhooks) {
|
||||
// @ts-ignore
|
||||
if (webhookData.webhookIds.includes(webhook.id)) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
async create(this: IHookFunctions): Promise<boolean> {
|
||||
const credentials = await this.getCredentials('flowApi');
|
||||
|
||||
let resourceIds, body, responseData;
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const resource = this.getNodeParameter('resource') as string;
|
||||
const endpoint = '/integration_webhooks';
|
||||
if (resource === 'list') {
|
||||
resourceIds = (this.getNodeParameter('listIds') as string).split(',');
|
||||
}
|
||||
if (resource === 'task') {
|
||||
resourceIds = (this.getNodeParameter('taskIds') as string).split(',');
|
||||
}
|
||||
// @ts-ignore
|
||||
for (const resourceId of resourceIds) {
|
||||
body = {
|
||||
organization_id: credentials.organizationId as number,
|
||||
integration_webhook: {
|
||||
name: 'n8n-trigger',
|
||||
url: webhookUrl,
|
||||
resource_type: resource,
|
||||
resource_id: parseInt(resourceId, 10),
|
||||
},
|
||||
};
|
||||
try {
|
||||
responseData = await flowApiRequest.call(this, 'POST', endpoint, body);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
responseData.integration_webhook === undefined ||
|
||||
responseData.integration_webhook.id === undefined
|
||||
) {
|
||||
// Required data is missing so was not successful
|
||||
return false;
|
||||
}
|
||||
// @ts-ignore
|
||||
webhookData.webhookIds.push(responseData.integration_webhook.id);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
async delete(this: IHookFunctions): Promise<boolean> {
|
||||
const credentials = await this.getCredentials('flowApi');
|
||||
|
||||
const qs: IDataObject = {};
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
qs.organization_id = credentials.organizationId as number;
|
||||
// @ts-ignore
|
||||
if (webhookData.webhookIds.length > 0) {
|
||||
// @ts-ignore
|
||||
for (const webhookId of webhookData.webhookIds) {
|
||||
const endpoint = `/integration_webhooks/${webhookId}`;
|
||||
try {
|
||||
await flowApiRequest.call(this, 'DELETE', endpoint, {}, qs);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
delete webhookData.webhookIds;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
const req = this.getRequestObject();
|
||||
return {
|
||||
workflowData: [this.helpers.returnJsonArray(req.body as IDataObject[])],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
IHttpRequestMethods,
|
||||
ILoadOptionsFunctions,
|
||||
IRequestOptions,
|
||||
JsonObject,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
export async function flowApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
resource: string,
|
||||
|
||||
body: any = {},
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
option: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const credentials = await this.getCredentials('flowApi');
|
||||
|
||||
let options: IRequestOptions = {
|
||||
headers: { Authorization: `Bearer ${credentials.accessToken}` },
|
||||
method,
|
||||
qs,
|
||||
body,
|
||||
uri: uri || `https://api.getflow.com/v2${resource}`,
|
||||
json: true,
|
||||
};
|
||||
options = Object.assign({}, options, option);
|
||||
if (Object.keys(options.body as IDataObject).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.helpers.request(options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API request to paginated flow endpoint
|
||||
* and return all results
|
||||
*/
|
||||
export async function FlowApiRequestAllItems(
|
||||
this: IHookFunctions | IExecuteFunctions,
|
||||
propertyName: string,
|
||||
method: IHttpRequestMethods,
|
||||
resource: string,
|
||||
|
||||
body: any = {},
|
||||
query: IDataObject = {},
|
||||
): Promise<any> {
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
|
||||
query.limit = 100;
|
||||
|
||||
let uri: string | undefined;
|
||||
|
||||
do {
|
||||
responseData = await flowApiRequest.call(this, method, resource, body, query, uri, {
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
uri = responseData.headers.link;
|
||||
returnData.push.apply(returnData, responseData.body[propertyName] as IDataObject[]);
|
||||
} while (responseData.headers.link !== undefined && responseData.headers.link !== '');
|
||||
|
||||
return returnData;
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const taskOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new task',
|
||||
action: 'Create a task',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a task',
|
||||
action: 'Update a task',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a task',
|
||||
action: 'Get a task',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many tasks',
|
||||
action: 'Get many tasks',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
},
|
||||
];
|
||||
|
||||
export const taskFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workspace ID',
|
||||
name: 'workspaceId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description: 'Create resources under the given workspace',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
description: 'The title of the task',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['create'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Owner ID',
|
||||
name: 'ownerid',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of the account to whom this task will be assigned',
|
||||
},
|
||||
{
|
||||
displayName: 'List ID',
|
||||
name: 'listID',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Put the new task in a list ("project"). Omit this param to have the task be private.',
|
||||
},
|
||||
{
|
||||
displayName: 'Starts On',
|
||||
name: 'startsOn',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'The date on which the task should start',
|
||||
},
|
||||
{
|
||||
displayName: 'Due On',
|
||||
name: 'dueOn',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'The date on which the task should be due',
|
||||
},
|
||||
{
|
||||
displayName: 'Mirror Parent Subscribers',
|
||||
name: 'mirrorParentSubscribers',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
"Whether this task will be a subtask, and this is true, the parent tasks's subscribers will be mirrored to this one",
|
||||
},
|
||||
{
|
||||
displayName: 'Mirror Parent Tags',
|
||||
name: 'mirrorParentTags',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
"Whether this task will be a subtask, and this is true, the parent tasks's tags will be mirrored to this one",
|
||||
},
|
||||
{
|
||||
displayName: 'Note Content',
|
||||
name: 'noteContent',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: "Provide the content for the task's note",
|
||||
},
|
||||
{
|
||||
displayName: 'Note Mime Type',
|
||||
name: 'noteMimeType',
|
||||
type: 'options',
|
||||
default: 'text/plain',
|
||||
options: [
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'text/plain',
|
||||
value: 'text/plain',
|
||||
},
|
||||
{
|
||||
name: 'text/x-markdown',
|
||||
value: 'text/x-markdown',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'text/html',
|
||||
value: 'text/html',
|
||||
},
|
||||
],
|
||||
description: 'Identify which markup language is used to format the given note',
|
||||
},
|
||||
{
|
||||
displayName: 'Parent ID',
|
||||
name: 'parentId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'If provided, this task will become a subtask of the given task',
|
||||
},
|
||||
{
|
||||
displayName: 'Position List',
|
||||
name: 'positionList',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Determines the sort order when showing tasks in, or grouped by, a list',
|
||||
},
|
||||
{
|
||||
displayName: 'Position Upcoming',
|
||||
name: 'positionUpcoming',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Determines the sort order when showing tasks grouped by their due_date',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'position',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Determines the sort order of tasks',
|
||||
},
|
||||
{
|
||||
displayName: 'Section ID',
|
||||
name: 'sectionId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Specify which section under which to create this task',
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A list of tag names to apply to the new task separated by a comma (,)',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:update */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workspace ID',
|
||||
name: 'workspaceId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
description: 'Create resources under the given workspace',
|
||||
},
|
||||
{
|
||||
displayName: 'Task ID',
|
||||
name: 'taskId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Update Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['update'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The title of the task',
|
||||
},
|
||||
{
|
||||
displayName: 'Completed',
|
||||
name: 'completed',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to complete the task',
|
||||
},
|
||||
{
|
||||
displayName: 'Owner ID',
|
||||
name: 'ownerid',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The ID of the account to whom this task will be assigned',
|
||||
},
|
||||
{
|
||||
displayName: 'List ID',
|
||||
name: 'listID',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Put the new task in a list ("project"). Omit this param to have the task be private.',
|
||||
},
|
||||
{
|
||||
displayName: 'Starts On',
|
||||
name: 'startsOn',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'The date on which the task should start',
|
||||
},
|
||||
{
|
||||
displayName: 'Due On',
|
||||
name: 'dueOn',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'The date on which the task should be due',
|
||||
},
|
||||
{
|
||||
displayName: 'Mirror Parent Subscribers',
|
||||
name: 'mirrorParentSubscribers',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
"Whether this task will be a subtask, and this is true, the parent tasks's subscribers will be mirrored to this one",
|
||||
},
|
||||
{
|
||||
displayName: 'Mirror Parent Tags',
|
||||
name: 'mirrorParentTags',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
"Whether this task will be a subtask, and this is true, the parent tasks's tags will be mirrored to this one",
|
||||
},
|
||||
{
|
||||
displayName: 'Note Content',
|
||||
name: 'noteContent',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: "Provide the content for the task's note",
|
||||
},
|
||||
{
|
||||
displayName: 'Note Mime Type',
|
||||
name: 'noteMimeType',
|
||||
type: 'options',
|
||||
default: 'text/plain',
|
||||
options: [
|
||||
{
|
||||
name: 'Text/plain',
|
||||
value: 'text/plain',
|
||||
},
|
||||
{
|
||||
name: 'text/x-markdown',
|
||||
value: 'text/x-markdown',
|
||||
},
|
||||
{
|
||||
name: 'Text/html',
|
||||
value: 'text/html',
|
||||
},
|
||||
],
|
||||
description: 'Identify which markup language is used to format the given note',
|
||||
},
|
||||
{
|
||||
displayName: 'Parent ID',
|
||||
name: 'parentId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'If provided, this task will become a subtask of the given task',
|
||||
},
|
||||
{
|
||||
displayName: 'Position List',
|
||||
name: 'positionList',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Determines the sort order when showing tasks in, or grouped by, a list',
|
||||
},
|
||||
{
|
||||
displayName: 'Position Upcoming',
|
||||
name: 'positionUpcoming',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Determines the sort order when showing tasks grouped by their due_date',
|
||||
},
|
||||
{
|
||||
displayName: 'Position',
|
||||
name: 'position',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Determines the sort order of tasks',
|
||||
},
|
||||
{
|
||||
displayName: 'Section ID',
|
||||
name: 'sectionId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Specify which section under which to create this task',
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A list of tag names to apply to the new task separated by a comma (,)',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Task ID',
|
||||
name: 'taskId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'multiOptions',
|
||||
default: [],
|
||||
options: [
|
||||
{
|
||||
name: 'Schedule',
|
||||
value: 'schedule',
|
||||
},
|
||||
{
|
||||
name: 'Files',
|
||||
value: 'files',
|
||||
},
|
||||
{
|
||||
name: 'File Associations',
|
||||
value: 'file_associations',
|
||||
},
|
||||
{
|
||||
name: 'Parent',
|
||||
value: 'parent',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* task:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
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: ['task'],
|
||||
operation: ['getAll'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 100,
|
||||
},
|
||||
default: 50,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['task'],
|
||||
operation: ['getAll'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Include',
|
||||
name: 'include',
|
||||
type: 'multiOptions',
|
||||
default: [],
|
||||
options: [
|
||||
{
|
||||
name: 'Schedule',
|
||||
value: 'schedule',
|
||||
},
|
||||
{
|
||||
name: 'Files',
|
||||
value: 'files',
|
||||
},
|
||||
{
|
||||
name: 'File Associations',
|
||||
value: 'file_associations',
|
||||
},
|
||||
{
|
||||
name: 'Parent',
|
||||
value: 'parent',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Order',
|
||||
name: 'order',
|
||||
type: 'options',
|
||||
default: 'created_at',
|
||||
options: [
|
||||
{
|
||||
name: 'Account ID',
|
||||
value: 'account_id',
|
||||
},
|
||||
{
|
||||
name: 'Completed At',
|
||||
value: 'completed_at',
|
||||
},
|
||||
{
|
||||
name: 'Created At',
|
||||
value: 'created_at',
|
||||
},
|
||||
{
|
||||
name: 'Due On',
|
||||
value: 'due_on',
|
||||
},
|
||||
{
|
||||
name: 'List ID',
|
||||
value: 'list_id',
|
||||
},
|
||||
{
|
||||
name: 'Name',
|
||||
value: 'name',
|
||||
},
|
||||
{
|
||||
name: 'Owner ID',
|
||||
value: 'owner_id',
|
||||
},
|
||||
{
|
||||
name: 'Position',
|
||||
value: 'position',
|
||||
},
|
||||
{
|
||||
name: 'Section ID',
|
||||
value: 'section_id',
|
||||
},
|
||||
{
|
||||
name: 'Starts On',
|
||||
value: 'starts_on',
|
||||
},
|
||||
{
|
||||
name: 'Updated At',
|
||||
value: 'updated_at',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Workspace ID',
|
||||
name: 'workspaceId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Create resources under the given workspace',
|
||||
},
|
||||
{
|
||||
displayName: 'Created Before',
|
||||
name: 'createdBefore',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Select resources created before a certain time',
|
||||
},
|
||||
{
|
||||
displayName: 'Created After',
|
||||
name: 'createdAfter',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Select resources created after a certain time',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Before',
|
||||
name: 'updateBefore',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Select resources updated before a certain time',
|
||||
},
|
||||
{
|
||||
displayName: 'Update After',
|
||||
name: 'updateAfter',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Select resources updated after a certain time',
|
||||
},
|
||||
{
|
||||
displayName: 'Deleted',
|
||||
name: 'deleted',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to select deleted resources',
|
||||
},
|
||||
{
|
||||
displayName: 'Cleared',
|
||||
name: 'cleared',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to select cleared resources',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,26 @@
|
||||
export interface ITask {
|
||||
organization_id?: number;
|
||||
task?: TaskInfo;
|
||||
}
|
||||
|
||||
export interface TaskInfo {
|
||||
workspace_id?: number;
|
||||
id?: number;
|
||||
name?: string;
|
||||
owner_id?: number;
|
||||
list_id?: number;
|
||||
starts_on?: string;
|
||||
due_on?: string;
|
||||
mirror_parent_subscribers?: boolean;
|
||||
mirror_parent_tags?: boolean;
|
||||
note_content?: string;
|
||||
note_mime_type?: string;
|
||||
parent_id?: number;
|
||||
position_list?: number;
|
||||
position_upcoming?: number;
|
||||
position?: number;
|
||||
section_id?: number;
|
||||
subscriptions?: number;
|
||||
tags?: string[];
|
||||
completed?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.2967 5.06586C13.8219 5.01628 14.3493 4.99467 14.8768 5.00111C23.0257 5.00111 29.5683 11.6316 29.6296 19.9714C29.5748 22.5524 27.8223 24.605 25.4377 24.605C23.0296 24.605 20.9454 22.8904 20.9454 19.9688C20.9454 16.6238 18.0802 13.982 14.6379 13.982C11.1994 13.982 8.72213 16.8466 8.67642 20.2809C8.67642 26.2962 12.1109 31.9528 16.9036 34.4742C17.3124 34.7332 17.4717 34.7591 17.8439 34.9689C16.7769 35.2668 15.5481 35.3704 14.8742 35.3704C6.6601 35.3704 0 28.6687 0 20.2796C0 12.4966 5.77209 5.88172 13.2941 5.06586H13.2967Z" fill="#46B1FF"/>
|
||||
<path d="M22.1121 5.30853C27.6667 7.47988 31.3254 13.8565 31.3737 20.2785C31.2994 23.8642 28.3917 26.4594 25.3106 26.4594C22.2334 26.4594 19.0415 24.2557 19.0415 20.2759C19.0415 17.621 17.0361 15.8166 14.53 15.8166C12.17 15.8166 10.3706 17.7533 10.3706 20.2759C10.3706 22.4667 10.7931 23.7021 11.0056 24.6057C11.2142 25.5105 12.0513 27.1957 12.0709 27.2372C12.1491 27.3967 12.9445 28.8667 13.9563 30.0943C14.6212 30.878 15.3624 31.5945 16.169 32.2333C16.2512 32.2981 16.8992 32.7907 17.1469 32.9592C17.2382 33.0214 18.842 34.0481 20.4249 34.5615C22.0104 35.0722 23.3456 35.3704 25.1059 35.3704C33.2852 35.3704 40.0002 28.6748 40.0002 20.2785C40.0028 11.8809 33.4899 5 25.188 5C24.304 5 22.9545 5.15556 22.1108 5.30853H22.1121Z" fill="#8ED4FE"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
Reference in New Issue
Block a user