From b3a394a38f86ac22be9bc9a85f064e4180beb128 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Thu, 30 Jan 2020 17:02:09 -0500 Subject: [PATCH 1/3] :sparkles: Added push a button operation --- packages/nodes-base/nodes/Coda/Coda.node.ts | 42 ++++++- .../nodes-base/nodes/Coda/TableDescription.ts | 115 +++++++++++++++++- 2 files changed, 153 insertions(+), 4 deletions(-) diff --git a/packages/nodes-base/nodes/Coda/Coda.node.ts b/packages/nodes-base/nodes/Coda/Coda.node.ts index d0274d1fb8..c731b92de8 100644 --- a/packages/nodes-base/nodes/Coda/Coda.node.ts +++ b/packages/nodes-base/nodes/Coda/Coda.node.ts @@ -105,6 +105,30 @@ export class Coda implements INodeType { } return returnData; }, + // Get all the available columns to display them to user so that he can + // select them easily + async getColumns(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let columns; + + const docId = this.getCurrentNodeParameter('docId'); + const tableId = this.getCurrentNodeParameter('tableId'); + + try { + columns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables/${tableId}/columns`, {}); + } catch (err) { + throw new Error(`Coda Error: ${err}`); + } + for (const column of columns) { + const columnName = column.name; + const columnId = column.id; + returnData.push({ + name: columnName, + value: columnId, + }); + } + return returnData; + }, }, }; @@ -217,6 +241,9 @@ export class Coda implements INodeType { if (options.visibleOnly) { qs.visibleOnly = options.visibleOnly as boolean; } + if (options.query) { + qs.query = options.query as string; + } try { if (returnAll === true) { responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}, qs); @@ -266,8 +293,21 @@ export class Coda implements INodeType { // Return the incoming data return [items]; } - } + // https://coda.io/developers/apis/v1beta1#operation/pushButton + if (operation === 'pushButton') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const tableId = this.getNodeParameter('tableId', i) as string; + const rowId = this.getNodeParameter('rowId', i) as string; + const columnId = this.getNodeParameter('columnId', i) as string; + const endpoint = `/docs/${docId}/tables/${tableId}/rows/${rowId}/buttons/${columnId}`; + responseData = await codaApiRequest.call(this, 'POST', endpoint, {}); + returnData.push(responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + } return []; } } diff --git a/packages/nodes-base/nodes/Coda/TableDescription.ts b/packages/nodes-base/nodes/Coda/TableDescription.ts index 647d92e1cb..04377870f2 100644 --- a/packages/nodes-base/nodes/Coda/TableDescription.ts +++ b/packages/nodes-base/nodes/Coda/TableDescription.ts @@ -33,6 +33,11 @@ export const tableOperations = [ value: 'deleteRow', description: 'Delete one or multiple rows', }, + { + name: 'Push Button', + value: 'pushButton', + description: 'Pushes a button', + }, ], default: 'createRow', description: 'The operation to perform.', @@ -42,7 +47,7 @@ export const tableOperations = [ export const tableFields = [ /* -------------------------------------------------------------------------- */ -/* table:createRow */ +/* table:createRow */ /* -------------------------------------------------------------------------- */ { displayName: 'Doc', @@ -125,7 +130,7 @@ export const tableFields = [ }, /* -------------------------------------------------------------------------- */ -/* table:get */ +/* table:get */ /* -------------------------------------------------------------------------- */ { displayName: 'Doc', @@ -249,7 +254,7 @@ export const tableFields = [ ] }, /* -------------------------------------------------------------------------- */ -/* table:getAll */ +/* table:getAll */ /* -------------------------------------------------------------------------- */ { displayName: 'Doc', @@ -354,6 +359,18 @@ export const tableFields = [ }, }, options: [ + { + displayName: 'Query', + name: 'query', + type: 'string', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: `Query used to filter returned rows, specified as :.
+ If you'd like to use a column name instead of an ID, you must quote it (e.g., "My Column":123).
+ Also note that value is a JSON value; if you'd like to use a string, you must surround it in quotes (e.g., "groceries").`, + }, { displayName: 'Use Column Names', name: 'useColumnNames', @@ -484,5 +501,97 @@ export const tableFields = [ }, description: 'Row IDs to delete.', }, +/* -------------------------------------------------------------------------- */ +/* table:pushButton */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'pushButton', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Table', + name: 'tableId', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'docId', + ], + loadOptionsMethod: 'getTables', + }, + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'pushButton', + ] + }, + }, + description: 'The table to get the row from.', + }, + { + displayName: 'Row ID', + name: 'rowId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'pushButton', + ] + }, + }, + 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: 'Column', + name: 'columnId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getColumns', + loadOptionsDependsOn: [ + 'docId', + 'tableId', + ], + }, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'pushButton', + ] + }, + }, + }, ] as INodeProperties[]; From 1a6e6aaa6d773d326419fa2f45db7818331c322c Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Mon, 3 Feb 2020 19:40:03 -0500 Subject: [PATCH 2/3] :zap: Added more resources and operations --- packages/nodes-base/nodes/Coda/Coda.node.ts | 362 ++++++++- .../nodes/Coda/ControlDescription.ts | 141 ++++ .../nodes/Coda/FormulaDescription.ts | 141 ++++ .../nodes-base/nodes/Coda/TableDescription.ts | 167 +++- .../nodes-base/nodes/Coda/ViewDescription.ts | 714 ++++++++++++++++++ 5 files changed, 1520 insertions(+), 5 deletions(-) create mode 100644 packages/nodes-base/nodes/Coda/ControlDescription.ts create mode 100644 packages/nodes-base/nodes/Coda/FormulaDescription.ts create mode 100644 packages/nodes-base/nodes/Coda/ViewDescription.ts diff --git a/packages/nodes-base/nodes/Coda/Coda.node.ts b/packages/nodes-base/nodes/Coda/Coda.node.ts index c731b92de8..a2946e71f4 100644 --- a/packages/nodes-base/nodes/Coda/Coda.node.ts +++ b/packages/nodes-base/nodes/Coda/Coda.node.ts @@ -17,6 +17,18 @@ import { tableFields, tableOperations, } from './TableDescription'; +import { + formulaFields, + formulaOperations, +} from './FormulaDescription'; +import { + controlFields, + controlOperations, +} from './ControlDescription'; +import { + viewFields, + viewOperations, +} from './ViewDescription'; export class Coda implements INodeType { description: INodeTypeDescription = { @@ -25,7 +37,7 @@ export class Coda implements INodeType { icon: 'file:coda.png', group: ['output'], version: 1, - subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}', description: 'Consume Coda Beta API', defaults: { name: 'Coda', @@ -50,12 +62,33 @@ export class Coda implements INodeType { value: 'table', description: `Access data of tables in documents.`, }, + { + name: 'Formula', + value: 'formula', + description: 'Formulas can be great for performing one-off computations', + }, + { + name: 'Control', + value: 'control', + description: 'Controls provide a user-friendly way to input a value that can affect other parts of the doc.', + }, + { + name: 'View', + value: 'view', + description: `Access data of views in documents.`, + }, ], default: 'table', description: 'Resource to consume.', }, ...tableOperations, ...tableFields, + ...formulaOperations, + ...formulaFields, + ...controlOperations, + ...controlFields, + ...viewOperations, + ...viewFields, ], }; @@ -129,6 +162,94 @@ export class Coda implements INodeType { } return returnData; }, + // Get all the available views to display them to user so that he can + // select them easily + async getViews(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let views; + const docId = this.getCurrentNodeParameter('docId'); + try { + views = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views`, {}); + } catch (err) { + throw new Error(`Coda Error: ${err}`); + } + for (const view of views) { + const viewName = view.name; + const viewId = view.id; + returnData.push({ + name: viewName, + value: viewId, + }); + } + return returnData; + }, + // Get all the available formulas to display them to user so that he can + // select them easily + async getFormulas(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let formulas; + const docId = this.getCurrentNodeParameter('docId'); + try { + formulas = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/formulas`, {}); + } catch (err) { + throw new Error(`Coda Error: ${err}`); + } + for (const formula of formulas) { + const formulaName = formula.name; + const formulaId = formula.id; + returnData.push({ + name: formulaName, + value: formulaId, + }); + } + return returnData; + }, + // Get all the available view rows to display them to user so that he can + // select them easily + async getViewRows(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let viewRows; + const docId = this.getCurrentNodeParameter('docId'); + const viewId = this.getCurrentNodeParameter('viewId'); + try { + viewRows = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/rows`, {}); + } catch (err) { + throw new Error(`Coda Error: ${err}`); + } + for (const viewRow of viewRows) { + const viewRowName = viewRow.name; + const viewRowId = viewRow.id; + returnData.push({ + name: viewRowName, + value: viewRowId, + }); + } + return returnData; + }, + // Get all the available view columns to display them to user so that he can + // select them easily + async getViewColumns(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let viewColumns; + + const docId = this.getCurrentNodeParameter('docId'); + const viewId = this.getCurrentNodeParameter('viewId'); + + try { + viewColumns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/columns`, {}); + } catch (err) { + throw new Error(`Coda Error: ${err}`); + } + for (const viewColumn of viewColumns) { + const viewColumnName = viewColumn.name; + const viewColumnId = viewColumn.id; + returnData.push({ + name: viewColumnName, + value: viewColumnId, + }); + } + return returnData; + }, }, }; @@ -138,7 +259,6 @@ export class Coda implements INodeType { let responseData; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; - let qs: IDataObject = {}; if (resource === 'table') { @@ -253,7 +373,7 @@ export class Coda implements INodeType { responseData = responseData.items; } } catch (err) { - throw new Error(`Flow Error: ${err.message}`); + throw new Error(`Coda Error: ${err.message}`); } if (options.rawData === true) { @@ -306,7 +426,243 @@ export class Coda implements INodeType { } return [this.helpers.returnJsonArray(returnData)]; } + //https://coda.io/developers/apis/v1beta1#operation/getColumn + if (operation === 'getColumn') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const tableId = this.getNodeParameter('tableId', i) as string; + const columnId = this.getNodeParameter('columnId', i) as string; + const endpoint = `/docs/${docId}/tables/${tableId}/columns/${columnId}`; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); + returnData.push(responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + //https://coda.io/developers/apis/v1beta1#operation/listColumns + if (operation === 'getAllColumns') { + for (let i = 0; i < items.length; i++) { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const docId = this.getNodeParameter('docId', i) as string; + const tableId = this.getNodeParameter('tableId', i) as string; + const endpoint = `/docs/${docId}/tables/${tableId}/columns`; + if (returnAll) { + responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}); + } else { + qs.limit = this.getNodeParameter('limit', 0) as number; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + } + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + } + if (resource === 'formula') { + //https://coda.io/developers/apis/v1beta1#operation/getFormula + if (operation === 'get') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const formulaId = this.getNodeParameter('formulaId', i) as string; + const endpoint = `/docs/${docId}/formulas/${formulaId}`; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); + returnData.push(responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + //https://coda.io/developers/apis/v1beta1#operation/listFormulas + if (operation === 'getAll') { + for (let i = 0; i < items.length; i++) { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const docId = this.getNodeParameter('docId', i) as string; + const endpoint = `/docs/${docId}/formulas`; + if (returnAll) { + responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}); + } else { + qs.limit = this.getNodeParameter('limit', 0) as number; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + } + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + } + if (resource === 'control') { + //https://coda.io/developers/apis/v1beta1#operation/getControl + if (operation === 'get') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const controlId = this.getNodeParameter('controlId', i) as string; + const endpoint = `/docs/${docId}/controls/${controlId}`; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); + returnData.push(responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + //https://coda.io/developers/apis/v1beta1#operation/listControls + if (operation === 'getAll') { + for (let i = 0; i < items.length; i++) { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const docId = this.getNodeParameter('docId', i) as string; + const endpoint = `/docs/${docId}/controls`; + if (returnAll) { + responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}); + } else { + qs.limit = this.getNodeParameter('limit', 0) as number; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + } + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + } + if (resource === 'view') { + //https://coda.io/developers/apis/v1beta1#operation/getView + if (operation === 'get') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const viewId = this.getNodeParameter('viewId', i) as string; + const endpoint = `/docs/${docId}/views/${viewId}`; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); + returnData.push(responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + //https://coda.io/developers/apis/v1beta1#operation/listViews + if (operation === 'getAll') { + for (let i = 0; i < items.length; i++) { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const docId = this.getNodeParameter('docId', i) as string; + const endpoint = `/docs/${docId}/views`; + if (returnAll) { + responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}); + } else { + qs.limit = this.getNodeParameter('limit', 0) as number; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + } + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + if (operation === 'getAllViewRows') { + const docId = this.getNodeParameter('docId', 0) as string; + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const viewId = this.getNodeParameter('viewId', 0) as string; + const options = this.getNodeParameter('options', 0) as IDataObject; + const endpoint = `/docs/${docId}/views/${viewId}/rows`; + if (options.useColumnNames === false) { + qs.useColumnNames = options.useColumnNames as boolean; + } else { + qs.useColumnNames = true; + } + if (options.valueFormat) { + qs.valueFormat = options.valueFormat as string; + } + if (options.sortBy) { + qs.sortBy = options.sortBy as string; + } + if (options.query) { + qs.query = options.query as string; + } + 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(`Coda Error: ${err.message}`); + } + if (options.rawData === true) { + return [this.helpers.returnJsonArray(responseData)]; + } else { + for (const item of responseData) { + returnData.push({ + id: item.id, + ...item.values + }); + } + return [this.helpers.returnJsonArray(returnData)]; + } + } + //https://coda.io/developers/apis/v1beta1#operation/deleteViewRow + if (operation === 'deleteViewRow') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const viewId = this.getNodeParameter('viewId', i) as string; + const rowId = this.getNodeParameter('rowId', i) as string; + const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}`; + responseData = await codaApiRequest.call(this, 'DELETE', endpoint); + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + //https://coda.io/developers/apis/v1beta1#operation/pushViewButton + if (operation === 'pushViewButton') { + for (let i = 0; i < items.length; i++) { + const docId = this.getNodeParameter('docId', i) as string; + const viewId = this.getNodeParameter('viewId', i) as string; + const rowId = this.getNodeParameter('rowId', i) as string; + const columnId = this.getNodeParameter('columnId', i) as string; + const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}/buttons/${columnId}`; + responseData = await codaApiRequest.call(this, 'POST', endpoint); + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + if (operation === 'getAllViewColumns') { + for (let i = 0; i < items.length; i++) { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const docId = this.getNodeParameter('docId', i) as string; + const viewId = this.getNodeParameter('viewId', i) as string; + const endpoint = `/docs/${docId}/views/${viewId}/columns`; + if (returnAll) { + responseData = await codaApiRequestAllItems.call(this, 'items', 'GET', endpoint, {}); + } else { + qs.limit = this.getNodeParameter('limit', 0) as number; + responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); + responseData = responseData.items; + } + returnData.push.apply(returnData,responseData) + } + return [this.helpers.returnJsonArray(returnData)]; + } + //https://coda.io/developers/apis/v1beta1#operation/updateViewRow + if (operation === 'updateViewRow') { + for (let i = 0; i < items.length; i++) { + qs = {}; + const docId = this.getNodeParameter('docId', i) as string; + const viewId = this.getNodeParameter('viewId', i) as string; + const rowId = this.getNodeParameter('rowId', i) as string; + const keyName = this.getNodeParameter('keyName', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + const body: IDataObject = {}; + const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}`; + if (options.disableParsing) { + qs.disableParsing = options.disableParsing as boolean; + } + const cells = []; + cells.length = 0; + //@ts-ignore + for (const key of Object.keys(items[i].json[keyName])) { + cells.push({ + column: key, + //@ts-ignore + value: items[i].json[keyName][key], + }); + } + body.row = { + cells + }, + await codaApiRequest.call(this, 'PUT', endpoint, body, qs); + } + return [items]; + } } return []; } diff --git a/packages/nodes-base/nodes/Coda/ControlDescription.ts b/packages/nodes-base/nodes/Coda/ControlDescription.ts new file mode 100644 index 0000000000..49311d549b --- /dev/null +++ b/packages/nodes-base/nodes/Coda/ControlDescription.ts @@ -0,0 +1,141 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const controlOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'control', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Get a control', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all controls', + }, + ], + default: 'get', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const controlFields = [ + +/* -------------------------------------------------------------------------- */ +/* control:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'control', + ], + operation: [ + 'get', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Control ID', + name: 'controlId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'control', + ], + operation: [ + 'get', + ] + }, + }, + description: 'The control to get the row from.', + }, +/* -------------------------------------------------------------------------- */ +/* control:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'control', + ], + operation: [ + 'getAll', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'control', + ], + 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: [ + 'control', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Coda/FormulaDescription.ts b/packages/nodes-base/nodes/Coda/FormulaDescription.ts new file mode 100644 index 0000000000..9e6ddbc043 --- /dev/null +++ b/packages/nodes-base/nodes/Coda/FormulaDescription.ts @@ -0,0 +1,141 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const formulaOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'formula', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Get a formula', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all formulas', + }, + ], + default: 'get', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const formulaFields = [ + +/* -------------------------------------------------------------------------- */ +/* formula:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'formula', + ], + operation: [ + 'get', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Formula ID', + name: 'formulaId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'formula', + ], + operation: [ + 'get', + ] + }, + }, + description: 'The formula to get the row from.', + }, +/* -------------------------------------------------------------------------- */ +/* formula:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'formula', + ], + operation: [ + 'getAll', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'formula', + ], + 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: [ + 'formula', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Coda/TableDescription.ts b/packages/nodes-base/nodes/Coda/TableDescription.ts index 04377870f2..1b601ccf30 100644 --- a/packages/nodes-base/nodes/Coda/TableDescription.ts +++ b/packages/nodes-base/nodes/Coda/TableDescription.ts @@ -38,6 +38,16 @@ export const tableOperations = [ value: 'pushButton', description: 'Pushes a button', }, + { + name: 'Get Column', + value: 'getColumn', + description: 'Get a column', + }, + { + name: 'Get All Columns', + value: 'getAllColumns', + description: 'Get all columns', + }, ], default: 'createRow', description: 'The operation to perform.', @@ -128,7 +138,6 @@ export const tableFields = [ }, ] }, - /* -------------------------------------------------------------------------- */ /* table:get */ /* -------------------------------------------------------------------------- */ @@ -593,5 +602,159 @@ export const tableFields = [ }, }, }, - +/* -------------------------------------------------------------------------- */ +/* table:getColumn */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'getColumn', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Table', + name: 'tableId', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'docId', + ], + loadOptionsMethod: 'getTables', + }, + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'getColumn', + ] + }, + }, + description: 'The table to get the row from.', + }, + { + displayName: 'Column ID', + name: 'columnId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'getColumn', + ] + }, + }, + description: 'The table to get the row from.', + }, +/* -------------------------------------------------------------------------- */ +/* table:getAllColumns */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'getAllColumns', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Table', + name: 'tableId', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'docId', + ], + loadOptionsMethod: 'getTables', + }, + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'getAllColumns', + ] + }, + }, + description: 'The table to get the row from.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'table', + ], + operation: [ + 'getAllColumns', + ] + }, + }, + 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: [ + 'table', + ], + operation: [ + 'getAllColumns', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Coda/ViewDescription.ts b/packages/nodes-base/nodes/Coda/ViewDescription.ts new file mode 100644 index 0000000000..a462e3848c --- /dev/null +++ b/packages/nodes-base/nodes/Coda/ViewDescription.ts @@ -0,0 +1,714 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const viewOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'view', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Get a view', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all views', + }, + { + name: 'Get Rows', + value: 'getAllViewRows', + description: 'Get all views rows', + }, + { + name: 'Get Columns', + value: 'getAllViewColumns', + description: 'Get all views columns', + }, + { + name: 'Update Row', + value: 'updateViewRow', + description: 'Update row', + }, + { + name: 'Delete Row', + value: 'deleteViewRow', + description: 'Delete view row', + }, + { + name: 'Push Button', + value: 'pushViewButton', + description: 'Push view button', + }, + ], + default: 'get', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const viewFields = [ + +/* -------------------------------------------------------------------------- */ +/* view:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'get', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'View ID', + name: 'viewId', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'get', + ] + }, + }, + description: 'The view to get the row from.', + }, +/* -------------------------------------------------------------------------- */ +/* view:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAll', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'view', + ], + 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: [ + 'view', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +/* -------------------------------------------------------------------------- */ +/* view:getAllViewRows */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewRows', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'View', + name: 'viewId', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'docId', + ], + loadOptionsMethod: 'getViews', + }, + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewRows', + ] + }, + }, + description: 'The table to get the rows from.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewRows', + ] + }, + }, + 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: [ + 'view', + ], + operation: [ + 'getAllViewRows', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewRows', + ], + }, + }, + options: [ + { + displayName: 'Query', + name: 'query', + type: 'string', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: `Query used to filter returned rows, specified as :.
+ If you'd like to use a column name instead of an ID, you must quote it (e.g., "My Column":123).
+ Also note that value is a JSON value; if you'd like to use a string, you must surround it in quotes (e.g., "groceries").`, + }, + { + 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: 'RAW Data', + name: 'rawData', + type: 'boolean', + default: false, + description: `Returns the data exactly in the way it got received from the API.`, + }, + { + 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.`, + }, + ] + }, +/* -------------------------------------------------------------------------- */ +/* view:getAllViewColumns */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewColumns', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'View', + name: 'viewId', + type: 'options', + typeOptions: { + loadOptionsDependsOn: [ + 'docId', + ], + loadOptionsMethod: 'getViews', + }, + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewColumns', + ] + }, + }, + description: 'The table to get the rows from.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'getAllViewColumns', + ] + }, + }, + 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: [ + 'view', + ], + operation: [ + 'getAllViewColumns', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +/* -------------------------------------------------------------------------- */ +/* view:deleteViewRow */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'deleteViewRow', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'View', + name: 'viewId', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: 'getViews', + loadOptionsDependsOn: [ + 'docId', + ], + }, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'deleteViewRow', + ] + }, + }, + description: 'The view to get the row from.', + }, + { + displayName: 'Row', + name: 'rowId', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: 'getViewRows', + loadOptionsDependsOn: [ + 'viewId', + ], + }, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'deleteViewRow', + ] + }, + }, + description: 'The view to get the row from.', + }, +/* -------------------------------------------------------------------------- */ +/* view:pushViewButton */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'pushViewButton', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'View', + name: 'viewId', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: 'getViews', + loadOptionsDependsOn: [ + 'docId', + ], + }, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'pushViewButton', + ] + }, + }, + description: 'The view to get the row from.', + }, + { + displayName: 'Row', + name: 'rowId', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: 'getViewRows', + loadOptionsDependsOn: [ + 'viewId', + ], + }, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'pushViewButton', + ] + }, + }, + description: 'The view to get the row from.', + }, + { + displayName: 'Column', + name: 'columnId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getViewColumns', + loadOptionsDependsOn: [ + 'docId', + 'viewId', + ], + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'pushViewButton', + ] + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* view:updateViewRow */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Doc', + name: 'docId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getDocs', + }, + default: '', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'updateViewRow', + ] + }, + }, + description: 'ID of the doc.', + }, + { + displayName: 'View', + name: 'viewId', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: 'getViews', + loadOptionsDependsOn: [ + 'docId', + ], + }, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'updateViewRow', + ] + }, + }, + description: 'The view to get the row from.', + }, + { + displayName: 'Row', + name: 'rowId', + type: 'options', + required: true, + default: '', + typeOptions: { + loadOptionsMethod: 'getViewRows', + loadOptionsDependsOn: [ + 'viewId', + ], + }, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'updateViewRow', + ] + }, + }, + description: 'The view to get the row from.', + }, + { + displayName: 'Key Name', + name: 'keyName', + type: 'string', + required: true, + default: 'columns', + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'updateViewRow', + ] + }, + }, + description: 'The view to get the row from.', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'view', + ], + operation: [ + 'updateViewRow', + ], + }, + }, + options: [ + { + displayName: 'Disable Parsing', + name: 'disableParsing', + type: 'boolean', + default: false, + description: `If true, the API will not attempt to parse the data in any way.`, + }, + ] + }, +] as INodeProperties[]; From 651c86e9f01dd05bcd9f3ae74175c53ddf410ff0 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 5 Feb 2020 16:47:40 -0800 Subject: [PATCH 3/3] :zap: Minor Coda-Node improvements --- packages/nodes-base/nodes/Coda/Coda.node.ts | 89 ++++------- .../nodes-base/nodes/Coda/GenericFunctions.ts | 2 +- .../nodes-base/nodes/Coda/TableDescription.ts | 140 +++++++++--------- .../nodes-base/nodes/Coda/ViewDescription.ts | 22 +-- 4 files changed, 111 insertions(+), 142 deletions(-) diff --git a/packages/nodes-base/nodes/Coda/Coda.node.ts b/packages/nodes-base/nodes/Coda/Coda.node.ts index a2946e71f4..04d611aa53 100644 --- a/packages/nodes-base/nodes/Coda/Coda.node.ts +++ b/packages/nodes-base/nodes/Coda/Coda.node.ts @@ -37,7 +37,7 @@ export class Coda implements INodeType { icon: 'file:coda.png', group: ['output'], version: 1, - subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}', + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Coda Beta API', defaults: { name: 'Coda', @@ -58,9 +58,9 @@ export class Coda implements INodeType { type: 'options', options: [ { - name: 'Table', - value: 'table', - description: `Access data of tables in documents.`, + name: 'Control', + value: 'control', + description: 'Controls provide a user-friendly way to input a value that can affect other parts of the doc.', }, { name: 'Formula', @@ -68,9 +68,9 @@ export class Coda implements INodeType { description: 'Formulas can be great for performing one-off computations', }, { - name: 'Control', - value: 'control', - description: 'Controls provide a user-friendly way to input a value that can affect other parts of the doc.', + name: 'Table', + value: 'table', + description: `Access data of tables in documents.`, }, { name: 'View', @@ -99,12 +99,7 @@ export class Coda implements INodeType { async getDocs(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const qs = {}; - let docs; - try { - docs = await codaApiRequestAllItems.call(this,'items', 'GET', `/docs`, {}, qs); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const docs = await codaApiRequestAllItems.call(this,'items', 'GET', `/docs`, {}, qs); for (const doc of docs) { const docName = doc.name; const docId = doc.id; @@ -119,15 +114,10 @@ export class Coda implements INodeType { // select them easily async getTables(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - let tables; const docId = this.getCurrentNodeParameter('docId'); - try { - tables = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables`, {}); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const tables = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables`, {}); for (const table of tables) { const tableName = table.name; const tableId = table.id; @@ -142,16 +132,11 @@ export class Coda implements INodeType { // select them easily async getColumns(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - let columns; const docId = this.getCurrentNodeParameter('docId'); const tableId = this.getCurrentNodeParameter('tableId'); - try { - columns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables/${tableId}/columns`, {}); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const columns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables/${tableId}/columns`, {}); for (const column of columns) { const columnName = column.name; const columnId = column.id; @@ -166,13 +151,8 @@ export class Coda implements INodeType { // select them easily async getViews(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - let views; const docId = this.getCurrentNodeParameter('docId'); - try { - views = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views`, {}); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const views = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views`, {}); for (const view of views) { const viewName = view.name; const viewId = view.id; @@ -187,13 +167,8 @@ export class Coda implements INodeType { // select them easily async getFormulas(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - let formulas; const docId = this.getCurrentNodeParameter('docId'); - try { - formulas = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/formulas`, {}); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const formulas = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/formulas`, {}); for (const formula of formulas) { const formulaName = formula.name; const formulaId = formula.id; @@ -208,14 +183,9 @@ export class Coda implements INodeType { // select them easily async getViewRows(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - let viewRows; const docId = this.getCurrentNodeParameter('docId'); const viewId = this.getCurrentNodeParameter('viewId'); - try { - viewRows = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/rows`, {}); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const viewRows = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/rows`, {}); for (const viewRow of viewRows) { const viewRowName = viewRow.name; const viewRowId = viewRow.id; @@ -230,16 +200,11 @@ export class Coda implements INodeType { // select them easily async getViewColumns(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - let viewColumns; const docId = this.getCurrentNodeParameter('docId'); const viewId = this.getCurrentNodeParameter('viewId'); - try { - viewColumns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/columns`, {}); - } catch (err) { - throw new Error(`Coda Error: ${err}`); - } + const viewColumns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/columns`, {}); for (const viewColumn of viewColumns) { const viewColumnName = viewColumn.name; const viewColumnId = viewColumn.id; @@ -422,7 +387,7 @@ export class Coda implements INodeType { const columnId = this.getNodeParameter('columnId', i) as string; const endpoint = `/docs/${docId}/tables/${tableId}/rows/${rowId}/buttons/${columnId}`; responseData = await codaApiRequest.call(this, 'POST', endpoint, {}); - returnData.push(responseData) + returnData.push(responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -434,7 +399,7 @@ export class Coda implements INodeType { const columnId = this.getNodeParameter('columnId', i) as string; const endpoint = `/docs/${docId}/tables/${tableId}/columns/${columnId}`; responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); - returnData.push(responseData) + returnData.push(responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -452,7 +417,7 @@ export class Coda implements INodeType { responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = responseData.items; } - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -465,7 +430,7 @@ export class Coda implements INodeType { const formulaId = this.getNodeParameter('formulaId', i) as string; const endpoint = `/docs/${docId}/formulas/${formulaId}`; responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); - returnData.push(responseData) + returnData.push(responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -482,7 +447,7 @@ export class Coda implements INodeType { responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = responseData.items; } - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -495,7 +460,7 @@ export class Coda implements INodeType { const controlId = this.getNodeParameter('controlId', i) as string; const endpoint = `/docs/${docId}/controls/${controlId}`; responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); - returnData.push(responseData) + returnData.push(responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -512,7 +477,7 @@ export class Coda implements INodeType { responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = responseData.items; } - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -525,7 +490,7 @@ export class Coda implements INodeType { const viewId = this.getNodeParameter('viewId', i) as string; const endpoint = `/docs/${docId}/views/${viewId}`; responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); - returnData.push(responseData) + returnData.push(responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -542,7 +507,7 @@ export class Coda implements INodeType { responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = responseData.items; } - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -584,7 +549,7 @@ export class Coda implements INodeType { for (const item of responseData) { returnData.push({ id: item.id, - ...item.values + ...item.values, }); } return [this.helpers.returnJsonArray(returnData)]; @@ -598,7 +563,7 @@ export class Coda implements INodeType { const rowId = this.getNodeParameter('rowId', i) as string; const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}`; responseData = await codaApiRequest.call(this, 'DELETE', endpoint); - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -611,7 +576,7 @@ export class Coda implements INodeType { const columnId = this.getNodeParameter('columnId', i) as string; const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}/buttons/${columnId}`; responseData = await codaApiRequest.call(this, 'POST', endpoint); - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } @@ -628,7 +593,7 @@ export class Coda implements INodeType { responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = responseData.items; } - returnData.push.apply(returnData,responseData) + returnData.push.apply(returnData,responseData); } return [this.helpers.returnJsonArray(returnData)]; } diff --git a/packages/nodes-base/nodes/Coda/GenericFunctions.ts b/packages/nodes-base/nodes/Coda/GenericFunctions.ts index 2d26d593a7..5752a81314 100644 --- a/packages/nodes-base/nodes/Coda/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Coda/GenericFunctions.ts @@ -32,7 +32,7 @@ export async function codaApiRequest(this: IExecuteFunctions | IExecuteSingleFun errorMessage = error.response.body.message || error.response.body.Message || error.message; } - throw new Error(errorMessage); + throw new Error('Coda Error: ' + errorMessage); } } diff --git a/packages/nodes-base/nodes/Coda/TableDescription.ts b/packages/nodes-base/nodes/Coda/TableDescription.ts index 1b601ccf30..4eb40bbe6a 100644 --- a/packages/nodes-base/nodes/Coda/TableDescription.ts +++ b/packages/nodes-base/nodes/Coda/TableDescription.ts @@ -19,34 +19,34 @@ export const tableOperations = [ description: 'Create/Upsert a row', }, { - name: 'Get Row', - value: 'getRow', - description: 'Get row', + name: 'Delete Row', + value: 'deleteRow', + description: 'Delete one or multiple rows', + }, + { + name: 'Get All Columns', + value: 'getAllColumns', + description: 'Get all columns', }, { name: 'Get All Rows', value: 'getAllRows', description: 'Get all the rows', }, - { - name: 'Delete Row', - value: 'deleteRow', - description: 'Delete one or multiple rows', - }, - { - name: 'Push Button', - value: 'pushButton', - description: 'Pushes a button', - }, { name: 'Get Column', value: 'getColumn', description: 'Get a column', }, { - name: 'Get All Columns', - value: 'getAllColumns', - description: 'Get all columns', + name: 'Get Row', + value: 'getRow', + description: 'Get row', + }, + { + name: 'Push Button', + value: 'pushButton', + description: 'Pushes a button', }, ], default: 'createRow', @@ -121,14 +121,6 @@ export const tableFields = [ }, }, options: [ - { - displayName: 'Key Columns', - name: 'keyColumns', - type: 'string', - default: '', - 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', @@ -136,6 +128,14 @@ export const tableFields = [ default: false, description: `If true, the API will not attempt to parse the data in any way.`, }, + { + displayName: 'Key Columns', + name: 'keyColumns', + type: 'string', + default: '', + description: `Optional column IDs, URLs, or names (fragile and discouraged)
, + specifying columns to be used as upsert keys. If more than one separate by ,`, + }, ] }, /* -------------------------------------------------------------------------- */ @@ -202,9 +202,11 @@ export const tableFields = [ ] }, }, - 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`, + 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: 'Options', @@ -223,6 +225,13 @@ export const tableFields = [ }, }, options: [ + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + default: false, + description: `Returns the data exactly in the way it got received from the API.`, + }, { displayName: 'Use Column Names', name: 'useColumnNames', @@ -232,13 +241,6 @@ export const tableFields = [ This is generally discouraged as it is fragile. If columns are renamed,
code using original names may throw errors.`, }, - { - displayName: 'RAW Data', - name: 'rawData', - type: 'boolean', - default: false, - description: `Returns the data exactly in the way it got received from the API.`, - }, { displayName: 'ValueFormat', name: 'valueFormat', @@ -380,36 +382,6 @@ export const tableFields = [ If you'd like to use a column name instead of an ID, you must quote it (e.g., "My Column":123).
Also note that value is a JSON value; if you'd like to use a string, you must surround it in quotes (e.g., "groceries").`, }, - { - 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: 'RAW Data', name: 'rawData', @@ -432,9 +404,39 @@ export const tableFields = [ value: 'natural', }, ], - description: `Specifies the sort order of the rows returned. + description: `Specifies the sort order of the rows returned.
If left unspecified, rows are returned by creation time ascending.`, }, + { + 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: 'Visible Only', name: 'visibleOnly', @@ -574,9 +576,11 @@ export const tableFields = [ ] }, }, - 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`, + 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: 'Column', diff --git a/packages/nodes-base/nodes/Coda/ViewDescription.ts b/packages/nodes-base/nodes/Coda/ViewDescription.ts index a462e3848c..d9c8472609 100644 --- a/packages/nodes-base/nodes/Coda/ViewDescription.ts +++ b/packages/nodes-base/nodes/Coda/ViewDescription.ts @@ -13,6 +13,11 @@ export const viewOperations = [ }, }, options: [ + { + name: 'Delete Row', + value: 'deleteViewRow', + description: 'Delete view row', + }, { name: 'Get', value: 'get', @@ -23,26 +28,21 @@ export const viewOperations = [ value: 'getAll', description: 'Get all views', }, - { - name: 'Get Rows', - value: 'getAllViewRows', - description: 'Get all views rows', - }, { name: 'Get Columns', value: 'getAllViewColumns', description: 'Get all views columns', }, + { + name: 'Get Rows', + value: 'getAllViewRows', + description: 'Get all views rows', + }, { name: 'Update Row', value: 'updateViewRow', description: 'Update row', }, - { - name: 'Delete Row', - value: 'deleteViewRow', - description: 'Delete view row', - }, { name: 'Push Button', value: 'pushViewButton', @@ -333,7 +333,7 @@ export const viewFields = [ value: 'natural', }, ], - description: `Specifies the sort order of the rows returned. + description: `Specifies the sort order of the rows returned.
If left unspecified, rows are returned by creation time ascending.`, }, ]