Minor Coda-Node improvements

This commit is contained in:
Jan Oberhauser 2020-02-05 16:47:40 -08:00
parent 1a6e6aaa6d
commit 651c86e9f0
4 changed files with 111 additions and 142 deletions

View file

@ -37,7 +37,7 @@ export class Coda implements INodeType {
icon: 'file:coda.png', icon: 'file:coda.png',
group: ['output'], group: ['output'],
version: 1, version: 1,
subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}', subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Coda Beta API', description: 'Consume Coda Beta API',
defaults: { defaults: {
name: 'Coda', name: 'Coda',
@ -58,9 +58,9 @@ export class Coda implements INodeType {
type: 'options', type: 'options',
options: [ options: [
{ {
name: 'Table', name: 'Control',
value: 'table', value: 'control',
description: `Access data of tables in documents.`, description: 'Controls provide a user-friendly way to input a value that can affect other parts of the doc.',
}, },
{ {
name: 'Formula', name: 'Formula',
@ -68,9 +68,9 @@ export class Coda implements INodeType {
description: 'Formulas can be great for performing one-off computations', description: 'Formulas can be great for performing one-off computations',
}, },
{ {
name: 'Control', name: 'Table',
value: 'control', value: 'table',
description: 'Controls provide a user-friendly way to input a value that can affect other parts of the doc.', description: `Access data of tables in documents.`,
}, },
{ {
name: 'View', name: 'View',
@ -99,12 +99,7 @@ export class Coda implements INodeType {
async getDocs(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getDocs(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const qs = {}; const qs = {};
let docs; const docs = await codaApiRequestAllItems.call(this,'items', 'GET', `/docs`, {}, qs);
try {
docs = await codaApiRequestAllItems.call(this,'items', 'GET', `/docs`, {}, qs);
} catch (err) {
throw new Error(`Coda Error: ${err}`);
}
for (const doc of docs) { for (const doc of docs) {
const docName = doc.name; const docName = doc.name;
const docId = doc.id; const docId = doc.id;
@ -119,15 +114,10 @@ export class Coda implements INodeType {
// select them easily // select them easily
async getTables(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getTables(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
let tables;
const docId = this.getCurrentNodeParameter('docId'); const docId = this.getCurrentNodeParameter('docId');
try { const tables = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables`, {});
tables = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables`, {});
} catch (err) {
throw new Error(`Coda Error: ${err}`);
}
for (const table of tables) { for (const table of tables) {
const tableName = table.name; const tableName = table.name;
const tableId = table.id; const tableId = table.id;
@ -142,16 +132,11 @@ export class Coda implements INodeType {
// select them easily // select them easily
async getColumns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getColumns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
let columns;
const docId = this.getCurrentNodeParameter('docId'); const docId = this.getCurrentNodeParameter('docId');
const tableId = this.getCurrentNodeParameter('tableId'); const tableId = this.getCurrentNodeParameter('tableId');
try { const columns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/tables/${tableId}/columns`, {});
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) { for (const column of columns) {
const columnName = column.name; const columnName = column.name;
const columnId = column.id; const columnId = column.id;
@ -166,13 +151,8 @@ export class Coda implements INodeType {
// select them easily // select them easily
async getViews(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getViews(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
let views;
const docId = this.getCurrentNodeParameter('docId'); const docId = this.getCurrentNodeParameter('docId');
try { const views = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views`, {});
views = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views`, {});
} catch (err) {
throw new Error(`Coda Error: ${err}`);
}
for (const view of views) { for (const view of views) {
const viewName = view.name; const viewName = view.name;
const viewId = view.id; const viewId = view.id;
@ -187,13 +167,8 @@ export class Coda implements INodeType {
// select them easily // select them easily
async getFormulas(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getFormulas(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
let formulas;
const docId = this.getCurrentNodeParameter('docId'); const docId = this.getCurrentNodeParameter('docId');
try { const formulas = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/formulas`, {});
formulas = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/formulas`, {});
} catch (err) {
throw new Error(`Coda Error: ${err}`);
}
for (const formula of formulas) { for (const formula of formulas) {
const formulaName = formula.name; const formulaName = formula.name;
const formulaId = formula.id; const formulaId = formula.id;
@ -208,14 +183,9 @@ export class Coda implements INodeType {
// select them easily // select them easily
async getViewRows(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getViewRows(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
let viewRows;
const docId = this.getCurrentNodeParameter('docId'); const docId = this.getCurrentNodeParameter('docId');
const viewId = this.getCurrentNodeParameter('viewId'); const viewId = this.getCurrentNodeParameter('viewId');
try { const viewRows = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/rows`, {});
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) { for (const viewRow of viewRows) {
const viewRowName = viewRow.name; const viewRowName = viewRow.name;
const viewRowId = viewRow.id; const viewRowId = viewRow.id;
@ -230,16 +200,11 @@ export class Coda implements INodeType {
// select them easily // select them easily
async getViewColumns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getViewColumns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
let viewColumns;
const docId = this.getCurrentNodeParameter('docId'); const docId = this.getCurrentNodeParameter('docId');
const viewId = this.getCurrentNodeParameter('viewId'); const viewId = this.getCurrentNodeParameter('viewId');
try { const viewColumns = await codaApiRequestAllItems.call(this, 'items', 'GET', `/docs/${docId}/views/${viewId}/columns`, {});
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) { for (const viewColumn of viewColumns) {
const viewColumnName = viewColumn.name; const viewColumnName = viewColumn.name;
const viewColumnId = viewColumn.id; const viewColumnId = viewColumn.id;
@ -422,7 +387,7 @@ export class Coda implements INodeType {
const columnId = this.getNodeParameter('columnId', i) as string; const columnId = this.getNodeParameter('columnId', i) as string;
const endpoint = `/docs/${docId}/tables/${tableId}/rows/${rowId}/buttons/${columnId}`; const endpoint = `/docs/${docId}/tables/${tableId}/rows/${rowId}/buttons/${columnId}`;
responseData = await codaApiRequest.call(this, 'POST', endpoint, {}); responseData = await codaApiRequest.call(this, 'POST', endpoint, {});
returnData.push(responseData) returnData.push(responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -434,7 +399,7 @@ export class Coda implements INodeType {
const columnId = this.getNodeParameter('columnId', i) as string; const columnId = this.getNodeParameter('columnId', i) as string;
const endpoint = `/docs/${docId}/tables/${tableId}/columns/${columnId}`; const endpoint = `/docs/${docId}/tables/${tableId}/columns/${columnId}`;
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); responseData = await codaApiRequest.call(this, 'GET', endpoint, {});
returnData.push(responseData) returnData.push(responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -452,7 +417,7 @@ export class Coda implements INodeType {
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = responseData.items; responseData = responseData.items;
} }
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -465,7 +430,7 @@ export class Coda implements INodeType {
const formulaId = this.getNodeParameter('formulaId', i) as string; const formulaId = this.getNodeParameter('formulaId', i) as string;
const endpoint = `/docs/${docId}/formulas/${formulaId}`; const endpoint = `/docs/${docId}/formulas/${formulaId}`;
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); responseData = await codaApiRequest.call(this, 'GET', endpoint, {});
returnData.push(responseData) returnData.push(responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -482,7 +447,7 @@ export class Coda implements INodeType {
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = responseData.items; responseData = responseData.items;
} }
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -495,7 +460,7 @@ export class Coda implements INodeType {
const controlId = this.getNodeParameter('controlId', i) as string; const controlId = this.getNodeParameter('controlId', i) as string;
const endpoint = `/docs/${docId}/controls/${controlId}`; const endpoint = `/docs/${docId}/controls/${controlId}`;
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); responseData = await codaApiRequest.call(this, 'GET', endpoint, {});
returnData.push(responseData) returnData.push(responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -512,7 +477,7 @@ export class Coda implements INodeType {
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = responseData.items; responseData = responseData.items;
} }
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -525,7 +490,7 @@ export class Coda implements INodeType {
const viewId = this.getNodeParameter('viewId', i) as string; const viewId = this.getNodeParameter('viewId', i) as string;
const endpoint = `/docs/${docId}/views/${viewId}`; const endpoint = `/docs/${docId}/views/${viewId}`;
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}); responseData = await codaApiRequest.call(this, 'GET', endpoint, {});
returnData.push(responseData) returnData.push(responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -542,7 +507,7 @@ export class Coda implements INodeType {
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = responseData.items; responseData = responseData.items;
} }
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -584,7 +549,7 @@ export class Coda implements INodeType {
for (const item of responseData) { for (const item of responseData) {
returnData.push({ returnData.push({
id: item.id, id: item.id,
...item.values ...item.values,
}); });
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
@ -598,7 +563,7 @@ export class Coda implements INodeType {
const rowId = this.getNodeParameter('rowId', i) as string; const rowId = this.getNodeParameter('rowId', i) as string;
const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}`; const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}`;
responseData = await codaApiRequest.call(this, 'DELETE', endpoint); responseData = await codaApiRequest.call(this, 'DELETE', endpoint);
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -611,7 +576,7 @@ export class Coda implements INodeType {
const columnId = this.getNodeParameter('columnId', i) as string; const columnId = this.getNodeParameter('columnId', i) as string;
const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}/buttons/${columnId}`; const endpoint = `/docs/${docId}/views/${viewId}/rows/${rowId}/buttons/${columnId}`;
responseData = await codaApiRequest.call(this, 'POST', endpoint); responseData = await codaApiRequest.call(this, 'POST', endpoint);
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
@ -628,7 +593,7 @@ export class Coda implements INodeType {
responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs); responseData = await codaApiRequest.call(this, 'GET', endpoint, {}, qs);
responseData = responseData.items; responseData = responseData.items;
} }
returnData.push.apply(returnData,responseData) returnData.push.apply(returnData,responseData);
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }

View file

@ -32,7 +32,7 @@ export async function codaApiRequest(this: IExecuteFunctions | IExecuteSingleFun
errorMessage = error.response.body.message || error.response.body.Message || error.message; errorMessage = error.response.body.message || error.response.body.Message || error.message;
} }
throw new Error(errorMessage); throw new Error('Coda Error: ' + errorMessage);
} }
} }

View file

@ -19,34 +19,34 @@ export const tableOperations = [
description: 'Create/Upsert a row', description: 'Create/Upsert a row',
}, },
{ {
name: 'Get Row', name: 'Delete Row',
value: 'getRow', value: 'deleteRow',
description: 'Get row', description: 'Delete one or multiple rows',
},
{
name: 'Get All Columns',
value: 'getAllColumns',
description: 'Get all columns',
}, },
{ {
name: 'Get All Rows', name: 'Get All Rows',
value: 'getAllRows', value: 'getAllRows',
description: 'Get all the rows', 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', name: 'Get Column',
value: 'getColumn', value: 'getColumn',
description: 'Get a column', description: 'Get a column',
}, },
{ {
name: 'Get All Columns', name: 'Get Row',
value: 'getAllColumns', value: 'getRow',
description: 'Get all columns', description: 'Get row',
},
{
name: 'Push Button',
value: 'pushButton',
description: 'Pushes a button',
}, },
], ],
default: 'createRow', default: 'createRow',
@ -121,14 +121,6 @@ export const tableFields = [
}, },
}, },
options: [ 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', displayName: 'Disable Parsing',
name: 'disableParsing', name: 'disableParsing',
@ -136,6 +128,14 @@ export const tableFields = [
default: false, default: false,
description: `If true, the API will not attempt to parse the data in any way.`, 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)<br />,
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. description: `ID or name of the row. Names are discouraged because<br />
If you're using a name, be sure to URI-encode it. they're easily prone to being changed by users. If you're<br />
If there are multiple rows with the same value in the identifying column, an arbitrary one will be selected`, using a name, be sure to URI-encode it. If there are<br />
multiple rows with the same value in the identifying column,<br />
an arbitrary one will be selected`,
}, },
{ {
displayName: 'Options', displayName: 'Options',
@ -223,6 +225,13 @@ export const tableFields = [
}, },
}, },
options: [ 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', displayName: 'Use Column Names',
name: 'useColumnNames', name: 'useColumnNames',
@ -232,13 +241,6 @@ export const tableFields = [
This is generally discouraged as it is fragile. If columns are renamed,</br> This is generally discouraged as it is fragile. If columns are renamed,</br>
code using original names may throw errors.`, 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', displayName: 'ValueFormat',
name: '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).<br/> If you'd like to use a column name instead of an ID, you must quote it (e.g., "My Column":123).<br/>
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").`, 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.</br>
This is generally discouraged as it is fragile. If columns are renamed,</br>
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', displayName: 'RAW Data',
name: 'rawData', name: 'rawData',
@ -432,9 +404,39 @@ export const tableFields = [
value: 'natural', value: 'natural',
}, },
], ],
description: `Specifies the sort order of the rows returned. description: `Specifies the sort order of the rows returned.<br />
If left unspecified, rows are returned by creation time ascending.`, 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.</br>
This is generally discouraged as it is fragile. If columns<br />
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', displayName: 'Visible Only',
name: 'visibleOnly', 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. description: `ID or name of the row. Names are discouraged because<br />
If you're using a name, be sure to URI-encode it. they're easily prone to being changed by users. If you're<br />
If there are multiple rows with the same value in the identifying column, an arbitrary one will be selected`, using a name, be sure to URI-encode it. If there are multiple<br />
rows with the same value in the identifying column, an arbitrary<br />
one will be selected`,
}, },
{ {
displayName: 'Column', displayName: 'Column',

View file

@ -13,6 +13,11 @@ export const viewOperations = [
}, },
}, },
options: [ options: [
{
name: 'Delete Row',
value: 'deleteViewRow',
description: 'Delete view row',
},
{ {
name: 'Get', name: 'Get',
value: 'get', value: 'get',
@ -23,26 +28,21 @@ export const viewOperations = [
value: 'getAll', value: 'getAll',
description: 'Get all views', description: 'Get all views',
}, },
{
name: 'Get Rows',
value: 'getAllViewRows',
description: 'Get all views rows',
},
{ {
name: 'Get Columns', name: 'Get Columns',
value: 'getAllViewColumns', value: 'getAllViewColumns',
description: 'Get all views columns', description: 'Get all views columns',
}, },
{
name: 'Get Rows',
value: 'getAllViewRows',
description: 'Get all views rows',
},
{ {
name: 'Update Row', name: 'Update Row',
value: 'updateViewRow', value: 'updateViewRow',
description: 'Update row', description: 'Update row',
}, },
{
name: 'Delete Row',
value: 'deleteViewRow',
description: 'Delete view row',
},
{ {
name: 'Push Button', name: 'Push Button',
value: 'pushViewButton', value: 'pushViewButton',
@ -333,7 +333,7 @@ export const viewFields = [
value: 'natural', value: 'natural',
}, },
], ],
description: `Specifies the sort order of the rows returned. description: `Specifies the sort order of the rows returned.<br />
If left unspecified, rows are returned by creation time ascending.`, If left unspecified, rows are returned by creation time ascending.`,
}, },
] ]