first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,97 @@
import type { INodeProperties } from 'n8n-workflow';
export const fieldOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['field'],
},
},
options: [
{
name: 'Get Many',
value: 'getAll',
description: 'Get many fields',
action: 'Get many fields',
},
],
default: 'getAll',
},
];
export const fieldFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* field:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['field'],
operation: ['getAll'],
},
},
description: 'The table identifier',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['field'],
operation: ['getAll'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['field'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
maxValue: 100,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['field'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Include Field Perms',
name: 'includeFieldPerms',
type: 'boolean',
default: false,
description: 'Whether to get back the custom permissions for the field(s)',
},
],
},
];
@@ -0,0 +1,106 @@
import type { INodeProperties } from 'n8n-workflow';
export const fileOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['file'],
},
},
options: [
{
name: 'Delete',
value: 'delete',
description: 'Delete a file',
action: 'Delete a file',
},
{
name: 'Download',
value: 'download',
description: 'Download a file',
action: 'Download a file',
},
],
default: 'download',
},
];
export const fileFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* file:download */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['file'],
operation: ['download', 'delete'],
},
},
description: 'The table identifier',
},
{
displayName: 'Record ID',
name: 'recordId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['file'],
operation: ['download', 'delete'],
},
},
description: 'The unique identifier of the record',
},
{
displayName: 'Field ID',
name: 'fieldId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['file'],
operation: ['download', 'delete'],
},
},
description: 'The unique identifier of the field',
},
{
displayName: 'Version Number',
name: 'versionNumber',
type: 'number',
default: 1,
required: true,
displayOptions: {
show: {
resource: ['file'],
operation: ['download', 'delete'],
},
},
description: 'The file attachment version number',
},
{
displayName: 'Input Binary Field',
displayOptions: {
show: {
resource: ['file'],
operation: ['download'],
},
},
name: 'binaryPropertyName',
type: 'string',
default: 'data',
hint: 'The name of the input binary field containing the file to be written',
required: true,
},
];
@@ -0,0 +1,137 @@
import type {
IDataObject,
IExecuteFunctions,
IHookFunctions,
IHttpRequestMethods,
ILoadOptionsFunctions,
IRequestOptions,
IWebhookFunctions,
JsonObject,
} from 'n8n-workflow';
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
export async function quickbaseApiRequest(
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions | IWebhookFunctions,
method: IHttpRequestMethods,
resource: string,
body: any = {},
qs: IDataObject = {},
option: IDataObject = {},
): Promise<any> {
const credentials = await this.getCredentials('quickbaseApi');
if (!credentials.hostname) {
throw new NodeOperationError(this.getNode(), 'Hostname must be defined');
}
if (!credentials.userToken) {
throw new NodeOperationError(this.getNode(), 'User Token must be defined');
}
try {
const options: IRequestOptions = {
headers: {
'QB-Realm-Hostname': credentials.hostname,
'User-Agent': 'n8n',
Authorization: `QB-USER-TOKEN ${credentials.userToken}`,
'Content-Type': 'application/json',
},
method,
body,
qs,
uri: `https://api.quickbase.com/v1${resource}`,
json: true,
};
if (Object.keys(body as IDataObject).length === 0) {
delete options.body;
}
if (Object.keys(qs).length === 0) {
delete options.qs;
}
if (Object.keys(option).length !== 0) {
Object.assign(options, option);
}
return await this.helpers?.request(options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
export async function getFieldsObject(
this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions,
tableId: string,
): Promise<any> {
const fieldsLabelKey: { [key: string]: number } = {};
const fieldsIdKey: { [key: number]: string } = {};
const data = await quickbaseApiRequest.call(this, 'GET', '/fields', {}, { tableId });
for (const field of data) {
fieldsLabelKey[field.label] = field.id;
fieldsIdKey[field.id] = field.label;
}
return { fieldsLabelKey, fieldsIdKey };
}
export async function quickbaseApiRequestAllItems(
this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions,
method: IHttpRequestMethods,
resource: string,
body: any = {},
query: IDataObject = {},
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData = [];
if (method === 'POST') {
body.options = {
skip: 0,
top: 100,
};
} else {
query.skip = 0;
query.top = 100;
}
let metadata;
do {
const {
data,
fields,
metadata: meta,
} = await quickbaseApiRequest.call(this, method, resource, body, query);
metadata = meta;
const fieldsIdKey: { [key: string]: string } = {};
for (const field of fields) {
fieldsIdKey[field.id] = field.label;
}
for (const record of data) {
const recordData: IDataObject = {};
for (const [key, value] of Object.entries(record as IDataObject)) {
recordData[fieldsIdKey[key]] = (value as IDataObject).value;
}
responseData.push(recordData);
}
if (method === 'POST') {
body.options.skip += body.options.top;
} else {
//@ts-ignore
query.skip += query.top;
}
returnData.push.apply(returnData, responseData);
responseData = [];
} while (returnData.length < metadata.totalRecords);
return returnData;
}
@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.quickbase",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Data & Storage"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/quickbase/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.quickbase/"
}
]
}
}
@@ -0,0 +1,642 @@
/* eslint-disable n8n-nodes-base/node-filename-against-convention */
import type {
IExecuteFunctions,
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
import { fieldFields, fieldOperations } from './FieldDescription';
import { fileFields, fileOperations } from './FileDescription';
import {
getFieldsObject,
quickbaseApiRequest,
quickbaseApiRequestAllItems,
} from './GenericFunctions';
import { recordFields, recordOperations } from './RecordDescription';
import { reportFields, reportOperations } from './ReportDescription';
import { generatePairedItemData } from '../../utils/utilities';
export class QuickBase implements INodeType {
description: INodeTypeDescription = {
displayName: 'Quick Base',
name: 'quickbase',
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
icon: 'file:quickbase.png',
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Integrate with the Quick Base RESTful API',
defaults: {
name: 'Quick Base',
},
usableAsTool: true,
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'quickbaseApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Field',
value: 'field',
},
{
name: 'File',
value: 'file',
},
{
name: 'Record',
value: 'record',
},
{
name: 'Report',
value: 'report',
},
],
default: 'record',
},
...fieldOperations,
...fieldFields,
...fileOperations,
...fileFields,
...recordOperations,
...recordFields,
...reportOperations,
...reportFields,
],
};
methods = {
loadOptions: {
async getTableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const tableId = this.getCurrentNodeParameter('tableId') as string;
const fields = await quickbaseApiRequest.call(this, 'GET', '/fields', {}, { tableId });
for (const field of fields) {
returnData.push({
name: field.label,
value: field.id,
});
}
return returnData;
},
async getUniqueTableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const tableId = this.getCurrentNodeParameter('tableId') as string;
const fields = await quickbaseApiRequest.call(this, 'GET', '/fields', {}, { tableId });
for (const field of fields) {
//upsert can be achived just with fields that are set as unique and are no the primary key
if (field.unique === true && field.properties.primaryKey === false) {
returnData.push({
name: field.label,
value: field.id,
});
}
}
return returnData;
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const itemData = generatePairedItemData(items.length);
const returnData: INodeExecutionData[] = [];
const length = items.length;
const qs: IDataObject = {};
let responseData;
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
if (resource === 'field') {
if (operation === 'getAll') {
for (let i = 0; i < length; i++) {
const returnAll = this.getNodeParameter('returnAll', i);
const tableId = this.getNodeParameter('tableId', i) as string;
const options = this.getNodeParameter('options', i);
Object.assign(
{
tableId,
},
options,
);
responseData = await quickbaseApiRequest.call(this, 'GET', '/fields', {}, qs);
if (!returnAll) {
const limit = this.getNodeParameter('limit', i);
responseData = responseData.splice(0, limit);
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
}
}
if (resource === 'file') {
if (operation === 'delete') {
for (let i = 0; i < length; i++) {
const tableId = this.getNodeParameter('tableId', i) as string;
const recordId = this.getNodeParameter('recordId', i) as string;
const fieldId = this.getNodeParameter('fieldId', i) as string;
const versionNumber = this.getNodeParameter('versionNumber', i) as string;
responseData = await quickbaseApiRequest.call(
this,
'DELETE',
`/files/${tableId}/${recordId}/${fieldId}/${versionNumber}`,
);
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
}
if (operation === 'download') {
for (let i = 0; i < length; i++) {
const tableId = this.getNodeParameter('tableId', i) as string;
const recordId = this.getNodeParameter('recordId', i) as string;
const fieldId = this.getNodeParameter('fieldId', i) as string;
const versionNumber = this.getNodeParameter('versionNumber', i) as string;
const newItem: INodeExecutionData = {
json: items[i].json,
binary: {},
};
if (items[i].binary !== undefined) {
// Create a shallow copy of the binary data so that the old
// data references which do not get changed still stay behind
// but the incoming data does not get changed.
Object.assign(newItem.binary!, items[i].binary);
}
items[i] = newItem;
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i);
responseData = await quickbaseApiRequest.call(
this,
'GET',
`/files/${tableId}/${recordId}/${fieldId}/${versionNumber}`,
{},
{},
{ json: false, resolveWithFullResponse: true },
);
//content-disposition': 'attachment; filename="dog-puppy-on-garden-royalty-free-image-1586966191.jpg"',
const contentDisposition: string = responseData.headers['content-disposition'];
const data = Buffer.from(responseData.body as string, 'base64');
items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(
data as unknown as Buffer,
contentDisposition.split('=')[1],
);
}
return [items];
}
}
if (resource === 'record') {
if (operation === 'create') {
const tableId = this.getNodeParameter('tableId', 0) as string;
const simple = this.getNodeParameter('simple', 0) as boolean;
const data: IDataObject[] = [];
const options = this.getNodeParameter('options', 0);
for (let i = 0; i < length; i++) {
const record: IDataObject = {};
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map((column) => column.trim());
if (options.useFieldIDs === true) {
for (const key of Object.keys(items[i].json)) {
record[key] = { value: items[i].json[key] };
}
} else {
const { fieldsLabelKey } = await getFieldsObject.call(this, tableId);
for (const key of Object.keys(items[i].json)) {
if (fieldsLabelKey.hasOwnProperty(key) && columnList.includes(key)) {
record[fieldsLabelKey[key].toString()] = { value: items[i].json[key] };
}
}
}
data.push(record);
}
const body: IDataObject = {
data,
to: tableId,
};
// If no fields are set return at least the record id
// 3 == Default Quickbase RecordID #
body.fieldsToReturn = [3];
if (options.fields) {
body.fieldsToReturn = options.fields as string[];
}
responseData = await quickbaseApiRequest.call(this, 'POST', '/records', body);
if (simple) {
const { data: records } = responseData;
responseData = [];
for (const record of records) {
const recordData: IDataObject = {};
for (const [key, value] of Object.entries(record as IDataObject)) {
recordData[key] = (value as IDataObject).value;
}
responseData.push(recordData);
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData },
);
returnData.push(...executionData);
}
if (operation === 'delete') {
for (let i = 0; i < length; i++) {
const tableId = this.getNodeParameter('tableId', i) as string;
const where = this.getNodeParameter('where', i) as string;
const body: IDataObject = {
from: tableId,
where,
};
responseData = await quickbaseApiRequest.call(this, 'DELETE', '/records', body);
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
}
if (operation === 'getAll') {
for (let i = 0; i < length; i++) {
const returnAll = this.getNodeParameter('returnAll', i);
const tableId = this.getNodeParameter('tableId', i) as string;
const options = this.getNodeParameter('options', i);
const body: IDataObject = {
from: tableId,
};
Object.assign(body, options);
if (options.sortByUi) {
const sort = (options.sortByUi as IDataObject).sortByValues as IDataObject[];
body.sortBy = sort;
delete body.sortByUi;
}
// if (options.groupByUi) {
// const group = (options.groupByUi as IDataObject).groupByValues as IDataObject[];
// body.groupBy = group;
// delete body.groupByUi;
// }
if (returnAll) {
responseData = await quickbaseApiRequestAllItems.call(
this,
'POST',
'/records/query',
body,
qs,
);
} else {
body.options = { top: this.getNodeParameter('limit', i) };
responseData = await quickbaseApiRequest.call(this, 'POST', '/records/query', body, qs);
const { data: records, fields } = responseData;
responseData = [];
const fieldsIdKey: { [key: string]: string } = {};
for (const field of fields) {
fieldsIdKey[field.id] = field.label;
}
for (const record of records) {
const data: IDataObject = {};
for (const [key, value] of Object.entries(record as IDataObject)) {
data[fieldsIdKey[key]] = (value as IDataObject).value;
}
responseData.push(data);
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
}
if (operation === 'update') {
const tableId = this.getNodeParameter('tableId', 0) as string;
const { fieldsLabelKey: _fieldsLabelKey, fieldsIdKey } = await getFieldsObject.call(
this,
tableId,
);
const simple = this.getNodeParameter('simple', 0) as boolean;
const updateKey = this.getNodeParameter('updateKey', 0) as string;
const data: IDataObject[] = [];
const options = this.getNodeParameter('options', 0);
for (let i = 0; i < length; i++) {
const record: IDataObject = {};
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map((column) => column.trim());
if (options.useFieldIDs === true) {
for (const key of Object.keys(items[i].json)) {
record[key] = { value: items[i].json[key] };
}
} else {
const { fieldsLabelKey } = await getFieldsObject.call(this, tableId);
for (const key of Object.keys(items[i].json)) {
if (fieldsLabelKey.hasOwnProperty(key) && columnList.includes(key)) {
record[fieldsLabelKey[key].toString()] = { value: items[i].json[key] };
}
}
}
if (items[i].json[updateKey] === undefined) {
throw new NodeOperationError(
this.getNode(),
`The update key ${updateKey} could not be found in the input`,
{ itemIndex: i },
);
}
data.push(record);
}
const body: IDataObject = {
data,
to: tableId,
};
// If no fields are set return at least the record id
// 3 == Default Quickbase RecordID #
//body.fieldsToReturn = [fieldsLabelKey['Record ID#']];
if (options.fields) {
body.fieldsToReturn = options.fields as string[];
}
responseData = await quickbaseApiRequest.call(this, 'POST', '/records', body);
if (simple) {
const { data: records } = responseData;
responseData = [];
for (const record of records) {
const recordData: IDataObject = {};
for (const [key, value] of Object.entries(record as IDataObject)) {
recordData[fieldsIdKey[key]] = (value as IDataObject).value;
}
responseData.push(recordData);
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData },
);
returnData.push(...executionData);
}
if (operation === 'upsert') {
const tableId = this.getNodeParameter('tableId', 0) as string;
const simple = this.getNodeParameter('simple', 0) as boolean;
const updateKey = this.getNodeParameter('updateKey', 0) as string;
const mergeFieldId = this.getNodeParameter('mergeFieldId', 0) as string;
const data: IDataObject[] = [];
const options = this.getNodeParameter('options', 0);
for (let i = 0; i < length; i++) {
const record: IDataObject = {};
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map((column) => column.trim());
if (options.useFieldIDs === true) {
for (const key of Object.keys(items[i].json)) {
record[key] = { value: items[i].json[key] };
}
} else {
const { fieldsLabelKey } = await getFieldsObject.call(this, tableId);
for (const key of Object.keys(items[i].json)) {
if (fieldsLabelKey.hasOwnProperty(key) && columnList.includes(key)) {
record[fieldsLabelKey[key].toString()] = { value: items[i].json[key] };
}
}
}
if (items[i].json[updateKey] === undefined) {
throw new NodeOperationError(
this.getNode(),
`The update key ${updateKey} could not be found in the input`,
{ itemIndex: i },
);
}
record[mergeFieldId] = { value: items[i].json[updateKey] };
data.push(record);
}
const body: IDataObject = {
data,
to: tableId,
mergeFieldId,
};
// If no fields are set return at least the record id
// 3 == Default Quickbase RecordID #
body.fieldsToReturn = [3];
if (options.fields) {
body.fieldsToReturn = options.fields as string[];
}
responseData = await quickbaseApiRequest.call(this, 'POST', '/records', body);
if (simple) {
const { data: records } = responseData;
responseData = [];
for (const record of records) {
const recordData: IDataObject = {};
for (const [key, value] of Object.entries(record as IDataObject)) {
recordData[key] = (value as IDataObject).value;
}
responseData.push(recordData);
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData },
);
returnData.push(...executionData);
}
}
if (resource === 'report') {
if (operation === 'run') {
for (let i = 0; i < length; i++) {
const returnAll = this.getNodeParameter('returnAll', i);
const tableId = this.getNodeParameter('tableId', i) as string;
const reportId = this.getNodeParameter('reportId', i) as string;
qs.tableId = tableId;
if (returnAll) {
responseData = await quickbaseApiRequestAllItems.call(
this,
'POST',
`/reports/${reportId}/run`,
{},
qs,
);
} else {
qs.top = this.getNodeParameter('limit', i);
responseData = await quickbaseApiRequest.call(
this,
'POST',
`/reports/${reportId}/run`,
{},
qs,
);
const { data: records, fields } = responseData;
responseData = [];
const fieldsIdKey: { [key: string]: string } = {};
for (const field of fields) {
fieldsIdKey[field.id] = field.label;
}
for (const record of records) {
const data: IDataObject = {};
for (const [key, value] of Object.entries(record as IDataObject)) {
data[fieldsIdKey[key]] = (value as IDataObject).value;
}
responseData.push(data);
}
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
}
if (operation === 'get') {
for (let i = 0; i < length; i++) {
const reportId = this.getNodeParameter('reportId', i) as string;
const tableId = this.getNodeParameter('tableId', i) as string;
qs.tableId = tableId;
responseData = await quickbaseApiRequest.call(
this,
'GET',
`/reports/${reportId}`,
{},
qs,
);
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
}
}
return [returnData];
}
}
@@ -0,0 +1,508 @@
import type { INodeProperties } from 'n8n-workflow';
export const recordOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['record'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a record',
action: 'Create a record',
},
{
name: 'Create or Update',
value: 'upsert',
description: 'Create a new record, or update the current one if it already exists (upsert)',
action: 'Create or update a record',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a record',
action: 'Delete a record',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Get many records',
action: 'Get many records',
},
{
name: 'Update',
value: 'update',
description: 'Update a record',
action: 'Update a record',
},
],
default: 'create',
},
];
export const recordFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* record:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['record'],
operation: ['create'],
},
},
description: 'The table identifier',
},
{
displayName: 'Columns',
name: 'columns',
type: 'string',
displayOptions: {
show: {
resource: ['record'],
operation: ['create'],
},
},
default: '',
required: true,
placeholder: 'Select Fields...',
description:
'Comma-separated list of the properties which should used as columns for the new rows',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
resource: ['record'],
operation: ['create'],
},
},
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add option',
default: {},
displayOptions: {
show: {
resource: ['record'],
operation: ['create'],
},
},
options: [
{
displayName: 'Return Field Names or IDs',
name: 'fields',
type: 'multiOptions',
typeOptions: {
loadOptionsMethod: 'getTableFields',
loadOptionsDependsOn: ['tableId'],
},
default: [],
description:
'Specify an array of field IDs that will return data for any updates or added record. Record ID (FID 3) is always returned if any field ID is requested. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Use Field IDs',
name: 'useFieldIDs',
type: 'boolean',
default: false,
description: 'Whether to use Field IDs instead of Field Names in Columns',
},
],
},
/* -------------------------------------------------------------------------- */
/* record:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['record'],
operation: ['delete'],
},
},
description: 'The table identifier',
},
{
displayName: 'Where',
name: 'where',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['record'],
operation: ['delete'],
},
},
description:
'The filter to delete records. To delete all records specify a filter that will include all records, for example {3.GT.0} where 3 is the ID of the Record ID field.',
},
/* -------------------------------------------------------------------------- */
/* record:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['record'],
operation: ['getAll'],
},
},
description: 'The table identifier',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['record'],
operation: ['getAll'],
},
},
default: false,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['record'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
minValue: 1,
maxValue: 100,
},
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['record'],
operation: ['getAll'],
},
},
options: [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options
displayName: 'Select',
name: 'select',
type: 'multiOptions',
typeOptions: {
loadOptionsMethod: 'getTableFields',
},
default: [],
description:
'An array of field IDs for the fields that should be returned in the response. If empty, the default columns on the table will be returned. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Sort By',
name: 'sortByUi',
placeholder: 'Add Sort By',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
options: [
{
name: 'sortByValues',
displayName: 'Sort By',
values: [
{
displayName: 'Field Name or ID',
name: 'fieldId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getTableFields',
},
default: '',
description:
'The unique identifier of a field in a table. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Order',
name: 'order',
type: 'options',
options: [
{
name: 'ASC',
value: 'ASC',
},
{
name: 'DESC',
value: 'DESC',
},
],
default: 'ASC',
},
],
},
],
description:
'By default, queries will be sorted by the given sort fields or the default sort if the query does not provide any. Set to false to avoid sorting when the order of the data returned is not important. Returning data without sorting can improve performance.',
},
{
displayName: 'Where',
name: 'where',
type: 'string',
default: '',
description:
'The filter, using the <a href="https://help.quickbase.com/api-guide/componentsquery.html">Quick Base query language</a>, which determines the records to return',
},
],
},
/* -------------------------------------------------------------------------- */
/* record:update */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['record'],
operation: ['update'],
},
},
description: 'The table identifier',
},
{
displayName: 'Columns',
name: 'columns',
type: 'string',
displayOptions: {
show: {
resource: ['record'],
operation: ['update'],
},
},
default: '',
required: true,
placeholder: 'id,name,description',
description:
'Comma-separated list of the properties which should used as columns for the new rows',
},
{
displayName: 'Update Key',
name: 'updateKey',
type: 'string',
displayOptions: {
show: {
resource: ['record'],
operation: ['update'],
},
},
default: '',
description: 'Update can use the key field on the table, or any other supported unique field',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
resource: ['record'],
operation: ['update'],
},
},
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add option',
default: {},
displayOptions: {
show: {
resource: ['record'],
operation: ['update'],
},
},
options: [
{
displayName: 'Field Names or IDs',
name: 'fields',
type: 'multiOptions',
typeOptions: {
loadOptionsMethod: 'getTableFields',
loadOptionsDependsOn: ['tableId'],
},
default: [],
description:
'Specify an array of field IDs that will return data for any updates or added record. Record ID (FID 3) is always returned if any field ID is requested. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Use Field IDs',
name: 'useFieldIDs',
type: 'boolean',
default: false,
description: 'Whether to use Field IDs instead of Field Names in Columns',
},
// {
// displayName: 'Merge Field ID',
// name: 'mergeFieldId',
// type: 'options',
// typeOptions: {
// loadOptionsMethod: 'getUniqueTableFields',
// },
// default: '',
// description: `You're updating records in a Quick Base table with data from an external file. In order for a merge like this to work,
// Quick Base needs a way to match records in the source data with corresponding records in the destination table. You make this possible by
// choosing the field in the app table that holds unique matching values. This is called a merge field.`,
// },
],
},
/* -------------------------------------------------------------------------- */
/* record:upsert */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['record'],
operation: ['upsert'],
},
},
description: 'The table identifier',
},
{
displayName: 'Columns',
name: 'columns',
type: 'string',
displayOptions: {
show: {
resource: ['record'],
operation: ['upsert'],
},
},
default: '',
required: true,
placeholder: 'id,name,description',
description:
'Comma-separated list of the properties which should used as columns for the new rows',
},
{
displayName: 'Update Key',
name: 'updateKey',
type: 'string',
displayOptions: {
show: {
resource: ['record'],
operation: ['upsert'],
},
},
default: '',
description: 'Update can use the key field on the table, or any other supported unique field',
},
{
displayName: 'Merge Field Name or ID',
name: 'mergeFieldId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getUniqueTableFields',
},
displayOptions: {
show: {
resource: ['record'],
operation: ['upsert'],
},
},
default: '',
description:
'<p>You\'re updating records in a Quick Base table with data from an external file. In order for a merge like this to work, Quick Base needs a way to match records in the source data with corresponding records in the destination table.</p><p>You make this possible by choosing the field in the app table that holds unique matching values. This is called a merge field.</p>. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
resource: ['record'],
operation: ['upsert'],
},
},
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add option',
default: {},
displayOptions: {
show: {
resource: ['record'],
operation: ['upsert'],
},
},
options: [
{
displayName: 'Field Names or IDs',
name: 'fields',
type: 'multiOptions',
typeOptions: {
loadOptionsMethod: 'getTableFields',
loadOptionsDependsOn: ['tableId'],
},
default: [],
description:
'Specify an array of field IDs that will return data for any updates or added record. Record ID (FID 3) is always returned if any field ID is requested. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Use Field IDs',
name: 'useFieldIDs',
type: 'boolean',
default: false,
description: 'Whether to use Field IDs instead of Field Names in Columns',
},
],
},
];
@@ -0,0 +1,128 @@
import type { INodeProperties } from 'n8n-workflow';
export const reportOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['report'],
},
},
options: [
{
name: 'Get',
value: 'get',
description: 'Get a report',
action: 'Get a report',
},
{
name: 'Run',
value: 'run',
description: 'Run a report',
action: 'Run a report',
},
],
default: 'get',
},
];
export const reportFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* report:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['report'],
operation: ['get'],
},
},
description: 'The table identifier',
},
{
displayName: 'Report ID',
name: 'reportId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['report'],
operation: ['get'],
},
},
description: 'The identifier of the report, unique to the table',
},
/* -------------------------------------------------------------------------- */
/* report:run */
/* -------------------------------------------------------------------------- */
{
displayName: 'Table ID',
name: 'tableId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['report'],
operation: ['run'],
},
},
description: 'The table identifier',
},
{
displayName: 'Report ID',
name: 'reportId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['report'],
operation: ['run'],
},
},
description: 'The identifier of the report, unique to the table',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: ['report'],
operation: ['run'],
},
},
default: true,
description: 'Whether to return all results or only up to a given limit',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: ['report'],
operation: ['run'],
},
hide: {
returnAll: [true],
},
},
typeOptions: {
minValue: 1,
maxValue: 100,
},
default: 100,
description: 'Max number of results to return',
},
];
@@ -0,0 +1,9 @@
{
"type": "object",
"properties": {
"3": {
"type": "integer"
}
},
"version": 1
}
@@ -0,0 +1,15 @@
{
"type": "object",
"properties": {
"Date Modified": {
"type": "string"
},
"NSN": {
"type": "string"
},
"Status": {
"type": "string"
}
},
"version": 2
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB