diff --git a/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts b/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts
index b1eddae550..fd010508f0 100644
--- a/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts
+++ b/packages/nodes-base/nodes/NocoDB/NocoDB.node.ts
@@ -20,7 +20,7 @@ export class NocoDB implements INodeType {
name: 'nocoDb',
icon: 'file:nocodb.svg',
group: ['input'],
- version: [1, 2],
+ version: [1, 2, 3],
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Read, update, write and delete data from NocoDB',
defaults: {
@@ -54,14 +54,14 @@ export class NocoDB implements INodeType {
name: 'authentication',
type: 'options',
options: [
- {
- name: 'User Token',
- value: 'nocoDb',
- },
{
name: 'API Token',
value: 'nocoDbApiToken',
},
+ {
+ name: 'User Token',
+ value: 'nocoDb',
+ },
],
default: 'nocoDb',
},
@@ -69,11 +69,6 @@ export class NocoDB implements INodeType {
displayName: 'API Version',
name: 'version',
type: 'options',
- displayOptions: {
- show: {
- '@version': [1],
- },
- },
isNodeSetting: true,
options: [
{
@@ -84,18 +79,22 @@ export class NocoDB implements INodeType {
name: 'v0.90.0 Onwards',
value: 2,
},
+ {
+ name: 'v0.200.0 Onwards',
+ value: 3,
+ },
],
+ displayOptions: {
+ show: {
+ '@version': [1],
+ },
+ },
default: 1,
},
{
displayName: 'API Version',
name: 'version',
type: 'options',
- displayOptions: {
- show: {
- '@version': [2],
- },
- },
isNodeSetting: true,
options: [
{
@@ -106,9 +105,44 @@ export class NocoDB implements INodeType {
name: 'v0.90.0 Onwards',
value: 2,
},
+ {
+ name: 'v0.200.0 Onwards',
+ value: 3,
+ },
],
+ displayOptions: {
+ show: {
+ '@version': [2],
+ },
+ },
default: 2,
},
+ {
+ displayName: 'API Version',
+ name: 'version',
+ type: 'options',
+ isNodeSetting: true,
+ options: [
+ {
+ name: 'Before v0.90.0',
+ value: 1,
+ },
+ {
+ name: 'v0.90.0 Onwards',
+ value: 2,
+ },
+ {
+ name: 'v0.200.0 Onwards',
+ value: 3,
+ },
+ ],
+ displayOptions: {
+ show: {
+ '@version': [3],
+ },
+ },
+ default: 3,
+ },
{
displayName: 'Resource',
name: 'resource',
@@ -172,26 +206,51 @@ export class NocoDB implements INodeType {
methods = {
loadOptions: {
- async getProjects(this: ILoadOptionsFunctions) {
+ async getWorkspaces(this: ILoadOptionsFunctions) {
try {
const requestMethod = 'GET';
- const endpoint = '/api/v1/db/meta/projects/';
+ const endpoint = '/api/v1/workspaces/';
const responseData = await apiRequest.call(this, requestMethod, endpoint, {}, {});
return responseData.list.map((i: IDataObject) => ({ name: i.title, value: i.id }));
+ } catch (e) {
+ return [{ name: 'No Workspace', value: 'none' }];
+ }
+ },
+ async getBases(this: ILoadOptionsFunctions) {
+ const version = this.getNodeParameter('version', 0) as number;
+ const workspaceId = this.getNodeParameter('workspaceId', 0) as string;
+ try {
+ if (workspaceId && workspaceId !== 'none') {
+ const requestMethod = 'GET';
+ const endpoint = `/api/v1/workspaces/${workspaceId}/bases/`;
+ const responseData = await apiRequest.call(this, requestMethod, endpoint, {}, {});
+ return responseData.list.map((i: IDataObject) => ({ name: i.title, value: i.id }));
+ } else {
+ const requestMethod = 'GET';
+ const endpoint = version === 3 ? '/api/v2/meta/bases/' : '/api/v1/db/meta/projects/';
+ const responseData = await apiRequest.call(this, requestMethod, endpoint, {}, {});
+ return responseData.list.map((i: IDataObject) => ({ name: i.title, value: i.id }));
+ }
} catch (e) {
throw new NodeOperationError(
this.getNode(),
- new Error('Error while fetching projects!', { cause: e }),
+ new Error(`Error while fetching ${version === 3 ? 'bases' : 'projects'}!`, {
+ cause: e,
+ }),
);
}
},
- // This only supports using the Project ID
+ // This only supports using the Base ID
async getTables(this: ILoadOptionsFunctions) {
- const projectId = this.getNodeParameter('projectId', 0) as string;
- if (projectId) {
+ const version = this.getNodeParameter('version', 0) as number;
+ const baseId = this.getNodeParameter('projectId', 0) as string;
+ if (baseId) {
try {
const requestMethod = 'GET';
- const endpoint = `/api/v1/db/meta/projects/${projectId}/tables`;
+ const endpoint =
+ version === 3
+ ? `/api/v2/meta/bases/${baseId}/tables`
+ : `/api/v1/db/meta/projects/${baseId}/tables`;
const responseData = await apiRequest.call(this, requestMethod, endpoint, {}, {});
return responseData.list.map((i: IDataObject) => ({ name: i.title, value: i.id }));
} catch (e) {
@@ -201,7 +260,10 @@ export class NocoDB implements INodeType {
);
}
} else {
- throw new NodeOperationError(this.getNode(), 'No project selected!');
+ throw new NodeOperationError(
+ this.getNode(),
+ `No ${version === 3 ? 'base' : 'project'} selected!`,
+ );
}
},
},
@@ -223,7 +285,7 @@ export class NocoDB implements INodeType {
let endPoint = '';
- const projectId = this.getNodeParameter('projectId', 0) as string;
+ const baseId = this.getNodeParameter('projectId', 0) as string;
const table = this.getNodeParameter('table', 0) as string;
if (resource === 'row') {
@@ -231,9 +293,11 @@ export class NocoDB implements INodeType {
requestMethod = 'POST';
if (version === 1) {
- endPoint = `/nc/${projectId}/api/v1/${table}/bulk`;
+ endPoint = `/nc/${baseId}/api/v1/${table}/bulk`;
} else if (version === 2) {
- endPoint = `/api/v1/db/data/bulk/noco/${projectId}/${table}`;
+ endPoint = `/api/v1/db/data/bulk/noco/${baseId}/${table}`;
+ } else if (version === 3) {
+ endPoint = `/api/v2/tables/${table}/records`;
}
const body: IDataObject[] = [];
@@ -278,7 +342,7 @@ export class NocoDB implements INodeType {
},
json: JSON.stringify({
api: 'xcAttachmentUpload',
- project_id: projectId,
+ project_id: baseId,
dbAlias: 'db',
args: {},
}),
@@ -289,6 +353,8 @@ export class NocoDB implements INodeType {
postUrl = '/dashboard';
} else if (version === 2) {
postUrl = '/api/v1/db/storage/upload';
+ } else if (version === 3) {
+ postUrl = '/api/v2/storage/upload';
}
responseData = await apiRequest.call(
@@ -296,13 +362,15 @@ export class NocoDB implements INodeType {
'POST',
postUrl,
{},
- { project_id: projectId },
+ version === 3 ? { base_id: baseId } : { project_id: baseId },
undefined,
{
formData,
},
);
- newItem[field.fieldName] = JSON.stringify([responseData]);
+ newItem[field.fieldName] = JSON.stringify(
+ Array.isArray(responseData) ? responseData : [responseData],
+ );
}
}
}
@@ -311,13 +379,21 @@ export class NocoDB implements INodeType {
try {
responseData = await apiRequest.call(this, requestMethod, endPoint, body, qs);
- // Calculate ID manually and add to return data
- let id = responseData[0];
- for (let i = body.length - 1; i >= 0; i--) {
- body[i].id = id--;
- }
+ if (version === 3) {
+ for (let i = body.length - 1; i >= 0; i--) {
+ body[i] = { ...body[i], ...responseData[i] };
+ }
- returnData.push(...body);
+ returnData.push(...body);
+ } else {
+ // Calculate ID manually and add to return data
+ let id = responseData[0];
+ for (let i = body.length - 1; i >= 0; i--) {
+ body[i].id = id--;
+ }
+
+ returnData.push(...body);
+ }
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.toString() });
@@ -331,9 +407,16 @@ export class NocoDB implements INodeType {
let primaryKey = 'id';
if (version === 1) {
- endPoint = `/nc/${projectId}/api/v1/${table}/bulk`;
+ endPoint = `/nc/${baseId}/api/v1/${table}/bulk`;
} else if (version === 2) {
- endPoint = `/api/v1/db/data/bulk/noco/${projectId}/${table}`;
+ endPoint = `/api/v1/db/data/bulk/noco/${baseId}/${table}`;
+
+ primaryKey = this.getNodeParameter('primaryKey', 0) as string;
+ if (primaryKey === 'custom') {
+ primaryKey = this.getNodeParameter('customPrimaryKey', 0) as string;
+ }
+ } else if (version === 3) {
+ endPoint = `/api/v2/tables/${table}/records`;
primaryKey = this.getNodeParameter('primaryKey', 0) as string;
if (primaryKey === 'custom') {
@@ -349,13 +432,7 @@ export class NocoDB implements INodeType {
}
try {
- responseData = (await apiRequest.call(
- this,
- requestMethod,
- endPoint,
- body,
- qs,
- )) as number[];
+ responseData = (await apiRequest.call(this, requestMethod, endPoint, body, qs)) as any[];
if (version === 1) {
returnData.push(...items.map((item) => item.json));
} else if (version === 2) {
@@ -377,6 +454,8 @@ export class NocoDB implements INodeType {
};
}),
);
+ } else if (version === 3) {
+ returnData.push(...responseData);
}
} catch (error) {
if (this.continueOnFail()) {
@@ -394,9 +473,11 @@ export class NocoDB implements INodeType {
requestMethod = 'GET';
if (version === 1) {
- endPoint = `/nc/${projectId}/api/v1/${table}`;
+ endPoint = `/nc/${baseId}/api/v1/${table}`;
} else if (version === 2) {
- endPoint = `/api/v1/db/data/noco/${projectId}/${table}`;
+ endPoint = `/api/v1/db/data/noco/${baseId}/${table}`;
+ } else if (version === 3) {
+ endPoint = `/api/v2/tables/${table}/records`;
}
returnAll = this.getNodeParameter('returnAll', 0);
@@ -421,7 +502,7 @@ export class NocoDB implements INodeType {
} else {
qs.limit = this.getNodeParameter('limit', 0);
responseData = await apiRequest.call(this, requestMethod, endPoint, {}, qs);
- if (version === 2) {
+ if (version === 2 || version === 3) {
responseData = responseData.list;
}
}
@@ -468,9 +549,11 @@ export class NocoDB implements INodeType {
const id = this.getNodeParameter('id', i) as string;
if (version === 1) {
- endPoint = `/nc/${projectId}/api/v1/${table}/${id}`;
+ endPoint = `/nc/${baseId}/api/v1/${table}/${id}`;
} else if (version === 2) {
- endPoint = `/api/v1/db/data/noco/${projectId}/${table}/${id}`;
+ endPoint = `/api/v1/db/data/noco/${baseId}/${table}/${id}`;
+ } else if (version === 3) {
+ endPoint = `/api/v2/tables/${table}/records/${id}`;
}
responseData = await apiRequest.call(this, requestMethod, endPoint, {}, qs);
@@ -542,22 +625,24 @@ export class NocoDB implements INodeType {
let primaryKey = 'id';
if (version === 1) {
- endPoint = `/nc/${projectId}/api/v1/${table}/bulk`;
+ endPoint = `/nc/${baseId}/api/v1/${table}/bulk`;
requestMethod = 'PUT';
} else if (version === 2) {
- endPoint = `/api/v1/db/data/bulk/noco/${projectId}/${table}`;
+ endPoint = `/api/v1/db/data/bulk/noco/${baseId}/${table}`;
primaryKey = this.getNodeParameter('primaryKey', 0) as string;
if (primaryKey === 'custom') {
primaryKey = this.getNodeParameter('customPrimaryKey', 0) as string;
}
+ } else if (version === 3) {
+ endPoint = `/api/v2/tables/${table}/records`;
}
const body: IDataObject[] = [];
for (let i = 0; i < items.length; i++) {
- const id = this.getNodeParameter('id', i) as string;
- const newItem: IDataObject = { [primaryKey]: id };
+ const id = version === 3 ? null : (this.getNodeParameter('id', i) as string);
+ const newItem: IDataObject = version === 3 ? {} : { [primaryKey]: id };
const dataToSend = this.getNodeParameter('dataToSend', i) as
| 'defineBelow'
| 'autoMapInputData';
@@ -596,7 +681,7 @@ export class NocoDB implements INodeType {
},
json: JSON.stringify({
api: 'xcAttachmentUpload',
- project_id: projectId,
+ project_id: baseId,
dbAlias: 'db',
args: {},
}),
@@ -606,19 +691,24 @@ export class NocoDB implements INodeType {
postUrl = '/dashboard';
} else if (version === 2) {
postUrl = '/api/v1/db/storage/upload';
+ } else if (version === 3) {
+ postUrl = '/api/v2/storage/upload';
}
+
responseData = await apiRequest.call(
this,
'POST',
postUrl,
{},
- { project_id: projectId },
+ version === 3 ? { base_id: baseId } : { project_id: baseId },
undefined,
{
formData,
},
);
- newItem[field.fieldName] = JSON.stringify([responseData]);
+ newItem[field.fieldName] = JSON.stringify(
+ Array.isArray(responseData) ? responseData : [responseData],
+ );
}
}
}
@@ -626,13 +716,7 @@ export class NocoDB implements INodeType {
}
try {
- responseData = (await apiRequest.call(
- this,
- requestMethod,
- endPoint,
- body,
- qs,
- )) as number[];
+ responseData = (await apiRequest.call(this, requestMethod, endPoint, body, qs)) as any[];
if (version === 1) {
returnData.push(...body);
@@ -655,6 +739,12 @@ export class NocoDB implements INodeType {
};
}),
);
+ } else if (version === 3) {
+ for (let i = body.length - 1; i >= 0; i--) {
+ body[i] = { ...body[i], ...responseData[i] };
+ }
+
+ returnData.push(...body);
}
} catch (error) {
if (this.continueOnFail()) {
diff --git a/packages/nodes-base/nodes/NocoDB/OperationDescription.ts b/packages/nodes-base/nodes/NocoDB/OperationDescription.ts
index be2be114ed..aaf43206c8 100644
--- a/packages/nodes-base/nodes/NocoDB/OperationDescription.ts
+++ b/packages/nodes-base/nodes/NocoDB/OperationDescription.ts
@@ -4,6 +4,40 @@ export const operationFields: INodeProperties[] = [
// ----------------------------------
// Shared
// ----------------------------------
+ {
+ displayName: 'Workspace Name or ID',
+ name: 'workspaceId',
+ type: 'options',
+ default: 'none',
+ displayOptions: {
+ show: {
+ version: [3],
+ },
+ },
+ description:
+ 'Choose from the list, or specify an ID using an expression',
+ typeOptions: {
+ loadOptionsMethod: 'getWorkspaces',
+ },
+ },
+ {
+ displayName: 'Base Name or ID',
+ name: 'projectId',
+ type: 'options',
+ default: '',
+ displayOptions: {
+ show: {
+ version: [3],
+ },
+ },
+ required: true,
+ description:
+ 'Choose from the list, or specify an ID using an expression',
+ typeOptions: {
+ loadOptionsDependsOn: ['workspaceId'],
+ loadOptionsMethod: 'getBases',
+ },
+ },
{
displayName: 'Project ID',
name: 'projectId',
@@ -31,7 +65,7 @@ export const operationFields: INodeProperties[] = [
description:
'Choose from the list, or specify an ID using an expression',
typeOptions: {
- loadOptionsMethod: 'getProjects',
+ loadOptionsMethod: 'getBases',
},
},
{
@@ -41,7 +75,7 @@ export const operationFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
- version: [2],
+ version: [2, 3],
},
},
required: true,
@@ -91,10 +125,42 @@ export const operationFields: INodeProperties[] = [
],
displayOptions: {
show: {
+ version: [1, 2],
operation: ['delete', 'update'],
},
},
},
+ {
+ displayName: 'Primary Key Type',
+ name: 'primaryKey',
+ type: 'options',
+ default: 'id',
+ options: [
+ {
+ name: 'Default',
+ value: 'id',
+ description:
+ 'Default, added when table was created from UI by those options: Create new table / Import from Excel / Import from CSV',
+ },
+ {
+ name: 'Imported From Airtable',
+ value: 'ncRecordId',
+ description: 'Select if table was imported from Airtable',
+ },
+ {
+ name: 'Custom',
+ value: 'custom',
+ description:
+ 'When connecting to existing external database as existing primary key field is retained as is, enter the name of the primary key field below',
+ },
+ ],
+ displayOptions: {
+ show: {
+ version: [3],
+ operation: ['delete'],
+ },
+ },
+ },
{
displayName: 'Field Name',
name: 'customPrimaryKey',
@@ -102,11 +168,25 @@ export const operationFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
+ version: [1, 2],
operation: ['delete', 'update'],
primaryKey: ['custom'],
},
},
},
+ {
+ displayName: 'Field Name',
+ name: 'customPrimaryKey',
+ type: 'string',
+ default: '',
+ displayOptions: {
+ show: {
+ version: [3],
+ operation: ['delete'],
+ primaryKey: ['custom'],
+ },
+ },
+ },
{
displayName: 'Row ID Value',
name: 'id',
@@ -116,10 +196,25 @@ export const operationFields: INodeProperties[] = [
description: 'The value of the ID field',
displayOptions: {
show: {
+ version: [1, 2],
operation: ['delete', 'get', 'update'],
},
},
},
+ {
+ displayName: 'Row ID Value',
+ name: 'id',
+ type: 'string',
+ default: '',
+ required: true,
+ description: 'The value of the ID field',
+ displayOptions: {
+ show: {
+ version: [3],
+ operation: ['delete', 'get'],
+ },
+ },
+ },
// ----------------------------------
// delete
// ----------------------------------
@@ -195,6 +290,17 @@ export const operationFields: INodeProperties[] = [
default: {},
placeholder: 'Add Option',
options: [
+ {
+ displayName: 'View ID',
+ name: 'viewId',
+ type: 'string',
+ typeOptions: {
+ multipleValues: false,
+ },
+ default: '',
+ placeholder: 'View ID',
+ description: 'The select fields of the returned rows',
+ },
{
displayName: 'Fields',
name: 'fields',
@@ -207,14 +313,6 @@ export const operationFields: INodeProperties[] = [
placeholder: 'Name',
description: 'The select fields of the returned rows',
},
- {
- displayName: 'Filter By Formula',
- name: 'where',
- type: 'string',
- default: '',
- placeholder: '(name,like,example%)~or(name,eq,test)',
- description: 'A formula used to filter rows',
- },
{
displayName: 'Sort',
name: 'sort',
@@ -260,6 +358,14 @@ export const operationFields: INodeProperties[] = [
},
],
},
+ {
+ displayName: 'Filter By Formula',
+ name: 'where',
+ type: 'string',
+ default: '',
+ placeholder: '(name,like,example%)~or(name,eq,test)',
+ description: 'A formula used to filter rows',
+ },
],
},
// ----------------------------------
@@ -322,6 +428,30 @@ export const operationFields: INodeProperties[] = [
default: 'defineBelow',
description: 'Whether to insert the input data this node receives in the new row',
},
+ {
+ displayName:
+ "In this mode, make sure the incoming data fields are named the same as the columns in NocoDB. (Use a 'set' node before this node to change them if required.)",
+ name: 'info',
+ type: 'notice',
+ default: '',
+ displayOptions: {
+ show: {
+ dataToSend: ['autoMapInputData'],
+ },
+ },
+ },
+ {
+ displayName: 'This operation requires the primary key to be included for each row.',
+ name: 'info',
+ type: 'notice',
+ default: '',
+ displayOptions: {
+ show: {
+ operation: ['update'],
+ version: [3],
+ },
+ },
+ },
{
displayName: 'Inputs to Ignore',
name: 'inputsToIgnore',
diff --git a/packages/nodes-base/nodes/NocoDB/nocodb.svg b/packages/nodes-base/nodes/NocoDB/nocodb.svg
index 42a90146ba..d6a0515eb6 100644
--- a/packages/nodes-base/nodes/NocoDB/nocodb.svg
+++ b/packages/nodes-base/nodes/NocoDB/nocodb.svg
@@ -1,425 +1,4 @@
-
-
-