diff --git a/packages/nodes-base/nodes/Coda/Coda.node.ts b/packages/nodes-base/nodes/Coda/Coda.node.ts index 605db290f6..38110a228a 100644 --- a/packages/nodes-base/nodes/Coda/Coda.node.ts +++ b/packages/nodes-base/nodes/Coda/Coda.node.ts @@ -89,211 +89,102 @@ export class Coda implements INodeType { }; async execute(this: IExecuteFunctions): Promise { - const items = this.getInputData(); const returnData: IDataObject[] = []; + const items = this.getInputData(); + const credentials = this.getCredentials('codaApi'); + const docId = credentials!.docId; const length = items.length as unknown as number; let responseData; const qs: IDataObject = {}; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; - - 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) as IDataObject; - // 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 (err) { - // throw new Error(`Flow Error: ${err.message}`); - // } - // } - // //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) as IDataObject; - // 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 (err) { - // throw new Error(`Flow Error: ${err.message}`); - // } - // } - // //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) as IDataObject; - // 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 (err) { - // throw new Error(`Flow Error: ${err.message}`); - // } - // } - // //https://developer.getflow.com/api/#tasks_get-tasks - // if (operation === 'getAll') { - // const returnAll = this.getNodeParameter('returnAll', i) as boolean; - // const filters = this.getNodeParameter('filters', i) as IDataObject; - // 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 === true) { - // responseData = await FlowApiRequestAllItems.call(this, 'tasks', 'GET', '/tasks', {}, qs); - // } else { - // qs.limit = this.getNodeParameter('limit', i) as number; - // responseData = await flowApiRequest.call(this, 'GET', '/tasks', {}, qs); - // responseData = responseData.tasks; - // } - // } catch (err) { - // throw new Error(`Flow Error: ${err.message}`); - // } - // } - // } - // if (Array.isArray(responseData)) { - // returnData.push.apply(returnData, responseData as IDataObject[]); - // } else { - // returnData.push(responseData as IDataObject); - // } + if (resource === 'row') { + //https://coda.io/developers/apis/v1beta1#operation/upsertRows + if (operation === 'create') { + const tableId = this.getNodeParameter('tableId', 0) as string; + const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject; + const endpoint = `/docs/${docId}/tables/${tableId}/rows`; + if (additionalFields.keyColumns) { + // @ts-ignore + items[0].json['keyColumns'] = additionalFields.keyColumns.split(',') as string[]; + } + if (additionalFields.disableParsing) { + qs.disableParsing = additionalFields.disableParsing as boolean; + } + try { + responseData = await codaApiRequest.call(this, 'POST', endpoint, items[0].json, qs); + } catch (err) { + throw new Error(`Coda Error: ${err.message}`); + } + } + //https://coda.io/developers/apis/v1beta1#operation/getRow + if (operation === 'get') { + const tableId = this.getNodeParameter('tableId', 0) as string; + const rowId = this.getNodeParameter('rowId', 0) as string; + const filters = this.getNodeParameter('filters', 0) as IDataObject; + const endpoint = `/docs/${docId}/tables/${tableId}/rows/${rowId}`; + if (filters.useColumnNames) { + qs.useColumnNames = filters.useColumnNames as boolean; + } + if (filters.valueFormat) { + qs.valueFormat = filters.valueFormat as string; + } + try { + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + } catch (err) { + throw new Error(`Coda Error: ${err.message}`); + } + } + //https://coda.io/developers/apis/v1beta1#operation/listRows + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const tableId = this.getNodeParameter('tableId', 0) as string; + const filters = this.getNodeParameter('filters', 0) as IDataObject; + const endpoint = `/docs/${docId}/tables/${tableId}/rows`; + if (filters.useColumnNames) { + qs.useColumnNames = filters.useColumnNames as boolean; + } + if (filters.valueFormat) { + qs.valueFormat = filters.valueFormat as string; + } + if (filters.sortBy) { + qs.sortBy = filters.sortBy as string; + } + if (filters.visibleOnly) { + qs.visibleOnly = filters.visibleOnly as boolean; + } + try { + if (returnAll === true) { + responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}, qs); + } else { + qs.limit = this.getNodeParameter('limit', 0) as number; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + } + } catch (err) { + throw new Error(`Flow Error: ${err.message}`); + } + } + //https://coda.io/developers/apis/v1beta1#operation/deleteRows + if (operation === 'delete') { + const tableId = this.getNodeParameter('tableId', 0) as string; + const rowId = this.getNodeParameter('rowId', 0) as string; + const body = {}; + const endpoint = `/docs/${docId}/tables/${tableId}/rows`; + try { + // @ts-ignore + body['rowIds'] = rowId.split(',') as string[]; + responseData = await codaApiRequest.call(this, 'DELETE', endpoint, body, qs); + } catch (err) { + throw new Error(`Coda Error: ${err.message}`); + } + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } } - return [this.helpers.returnJsonArray({})]; + return [this.helpers.returnJsonArray(responseData)]; } } diff --git a/packages/nodes-base/nodes/Coda/GenericFunctions.ts b/packages/nodes-base/nodes/Coda/GenericFunctions.ts index ecd6bcf64b..2d26d593a7 100644 --- a/packages/nodes-base/nodes/Coda/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Coda/GenericFunctions.ts @@ -1,12 +1,10 @@ import { OptionsWithUri } from 'request'; import { IExecuteFunctions, - IHookFunctions, ILoadOptionsFunctions, IExecuteSingleFunctions, } from 'n8n-core'; import { IDataObject } from 'n8n-workflow'; -import { response } from 'express'; export async function codaApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('codaApi'); diff --git a/packages/nodes-base/nodes/Coda/RowDescription.ts b/packages/nodes-base/nodes/Coda/RowDescription.ts index 831d381426..d9520266d6 100644 --- a/packages/nodes-base/nodes/Coda/RowDescription.ts +++ b/packages/nodes-base/nodes/Coda/RowDescription.ts @@ -18,11 +18,6 @@ export const rowOpeations = [ value: 'create', description: 'Create/Upsert a row', }, - { - name: 'Update', - value: 'update', - description: 'Update row', - }, { name: 'Get', value: 'get', @@ -33,6 +28,11 @@ export const rowOpeations = [ value: 'getAll', description: 'Get all the rows', }, + { + name: 'Delete', + value: 'delete', + description: 'Delete one or multiple rows', + }, ], default: 'create', description: 'The operation to perform.', @@ -46,7 +46,7 @@ export const rowFields = [ /* -------------------------------------------------------------------------- */ { displayName: 'Table', - name: 'table', + name: 'tableId', type: 'options', required: true, typeOptions: { @@ -63,11 +63,11 @@ export const rowFields = [ ] }, }, - description: 'The title of the task.', + description: 'Tables on document', }, { displayName: 'Additional Fields', - name: 'options', + name: 'additionalFields', type: 'collection', placeholder: 'Add Field', default: {}, @@ -90,6 +90,291 @@ export const rowFields = [ description: `Optional column IDs, URLs, or names (fragile and discouraged), specifying columns to be used as upsert keys. If more than one separate by ,`, }, + { + displayName: 'Disable Parsing', + name: 'disableParsing', + type: 'boolean', + default: false, + description: `If true, the API will not attempt to parse the data in any way.`, + }, ] }, + +/* -------------------------------------------------------------------------- */ +/* row:get */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Table', + name: 'tableId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getTables', + }, + default: [], + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'get' + ] + }, + }, + description: 'Tables on document', +}, +{ + displayName: 'Row ID', + name: 'rowId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'get' + ] + }, + }, + description: `ID or name of the row. Names are discouraged because they're easily prone to being changed by users. + If you're using a name, be sure to URI-encode it. + If there are multiple rows with the same value in the identifying column, an arbitrary one will be selected`, +}, +{ + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'get', + ], + }, + }, + options: [ + { + displayName: 'Use Column Names', + name: 'useColumnNames', + type: 'boolean', + default: false, + description: `Use column names instead of column IDs in the returned output.
+ This is generally discouraged as it is fragile. If columns are renamed,
+ code using original names may throw errors.`, + }, + { + displayName: 'ValueFormat', + name: 'valueFormat', + type: 'options', + default: [], + options: [ + { + name: 'Simple', + value: 'simple', + }, + { + name: 'Simple With Arrays', + value: 'simpleWithArrays', + }, + { + name: 'Rich', + value: 'rich', + }, + ], + description: `The format that cell values are returned as.`, + }, + ] +}, + +/* -------------------------------------------------------------------------- */ +/* get:all */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Table', + name: 'tableId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getTables', + }, + default: [], + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'getAll' + ] + }, + }, + description: 'Tables on document', +}, +{ + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'getAll' + ] + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', +}, +{ + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'getAll' + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', +}, +{ + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Use Column Names', + name: 'useColumnNames', + type: 'boolean', + default: false, + description: `Use column names instead of column IDs in the returned output.
+ This is generally discouraged as it is fragile. If columns are renamed,
+ code using original names may throw errors.`, + }, + { + displayName: 'ValueFormat', + name: 'valueFormat', + type: 'options', + default: [], + options: [ + { + name: 'Simple', + value: 'simple', + }, + { + name: 'Simple With Arrays', + value: 'simpleWithArrays', + }, + { + name: 'Rich', + value: 'rich', + }, + ], + description: `The format that cell values are returned as.`, + }, + { + displayName: 'Sort By', + name: 'sortBy', + type: 'options', + default: [], + options: [ + { + name: 'Created At', + value: 'createdAt', + }, + { + name: 'Natural', + value: 'natural', + }, + ], + description: `Specifies the sort order of the rows returned. + If left unspecified, rows are returned by creation time ascending.`, + }, + { + displayName: 'Visible Only', + name: 'visibleOnly', + type: 'boolean', + default: false, + description: `If true, returns only visible rows and columns for the table.`, + }, + ] +}, + +/* -------------------------------------------------------------------------- */ +/* row:delete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Table', + name: 'tableId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getTables', + }, + default: [], + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'delete' + ] + }, + }, + description: 'Tables on document', +}, +{ + displayName: 'Row ID', + name: 'rowId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'row', + ], + operation: [ + 'delete' + ] + }, + }, + description: `Row IDs to delete separated by ,.`, +}, + ] as INodeProperties[];