overhaul operation structure as requested by michael-radency

This commit is contained in:
Christoph Dyllick-Brenzinger 2024-07-08 09:27:49 +02:00
parent 9ae72e8e8e
commit 2454db80de
64 changed files with 1229 additions and 1341 deletions

View file

@ -65,9 +65,8 @@ function endpointCtxExpr(ctx: ICtx, endpoint: string): string {
endpointVariables.dtable_uuid = ctx?.base?.dtable_uuid;
return endpoint.replace(
/({{ *(access_token|dtable_uuid|server) *}})/g,
/{{ *(access_token|dtable_uuid|server) *}}/g,
(match: string, name: TEndpointVariableName) => {
// I need expr. Why?
return (endpointVariables[name] as string) || match;
},
);
@ -127,7 +126,7 @@ export async function seaTableApiRequest(
}
// DEBUG-MODE OR API-REQUESTS
// console.log(options);
//console.log(options);
if (Object.keys(body).length === 0) {
delete options.body;

View file

@ -0,0 +1,47 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
const properties: INodeProperties[] = [
{
displayName: 'Asset Path',
name: 'assetPath',
type: 'string',
placeholder: '/images/2023-09/logo.png',
required: true,
default: '',
},
];
const displayOptions = {
show: {
resource: ['asset'],
operation: ['getPublicURL'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const assetPath = this.getNodeParameter('assetPath', index) as string;
let responseData = [] as IDataObject[];
if (assetPath) {
responseData = await seaTableApiRequest.call(
this,
{},
'GET',
`/api/v2.1/dtable/app-download-link/?path=${assetPath}`,
);
}
return this.helpers.returnJsonArray(responseData);
}

View file

@ -1,18 +0,0 @@
import type { AssetProperties } from '../../Interfaces';
export const assetGetPublicURLDescription: AssetProperties = [
{
displayName: 'Asset Path',
name: 'assetPath',
type: 'string',
placeholder: '/images/2023-09/logo.png',
required: true,
displayOptions: {
show: {
resource: ['asset'],
operation: ['getPublicURL'],
},
},
default: '',
},
];

View file

@ -1,21 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function getPublicURL(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const assetPath = this.getNodeParameter('assetPath', index) as string;
let responseData = [] as IDataObject[];
if (assetPath) {
responseData = await seaTableApiRequest.call(
this,
{},
'GET',
`/api/v2.1/dtable/app-download-link/?path=${assetPath}`,
);
}
return this.helpers.returnJsonArray(responseData);
}

View file

@ -1,4 +0,0 @@
import { getPublicURL as execute } from './execute';
import { assetGetPublicURLDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,6 @@
import type { INodeProperties } from 'n8n-workflow';
import * as upload from './upload';
import * as getPublicURL from './getPublicURL';
import * as upload from './upload.operation';
import * as getPublicURL from './getPublicURL.operation';
export { upload, getPublicURL };

View file

@ -1,8 +1,94 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
import type { IUploadLink, IRowObject } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
import type { IUploadLink, IRowObject } from '../Interfaces';
export async function upload(
const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column Name',
name: 'uploadColumn',
type: 'options',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getAssetColumns',
},
required: true,
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Select the column for the upload. Choose from the list, or specify the name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Row ID',
name: 'rowId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true,
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
default: '',
},
{
displayName: 'Property Name',
name: 'dataPropertyName',
type: 'string',
default: 'data',
required: true,
description: 'Name of the binary property which contains the data for the file to be written',
},
{
displayName: 'Replace Existing File',
name: 'replace',
type: 'boolean',
default: true,
description:
'Whether to replace the existing asset with the same name (true). Otherwise, a new version with a different name (numeral in parentheses) will be uploaded (false).',
},
{
displayName: 'Append to Column',
name: 'append',
type: 'boolean',
default: true,
description:
'Whether to keep existing files/images in the column and append the new asset (true). Otherwise, the existing files/images are removed from the column (false).',
},
];
const displayOptions = {
show: {
resource: ['asset'],
operation: ['upload'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {

View file

@ -1,108 +0,0 @@
import type { AssetProperties } from '../../Interfaces';
export const assetUploadDescription: AssetProperties = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['asset'],
operation: ['upload'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column Name',
name: 'uploadColumn',
type: 'options',
displayOptions: {
show: {
resource: ['asset'],
operation: ['upload'],
},
},
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getAssetColumns',
},
required: true,
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Select the column for the upload. Choose from the list, or specify the name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Row ID',
name: 'rowId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true,
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['asset'],
operation: ['upload'],
},
},
default: '',
},
{
displayName: 'Property Name',
name: 'dataPropertyName',
type: 'string',
default: 'data',
required: true,
displayOptions: {
show: {
resource: ['asset'],
operation: ['upload'],
},
},
description: 'Name of the binary property which contains the data for the file to be written',
},
{
displayName: 'Replace Existing File',
name: 'replace',
type: 'boolean',
default: true,
displayOptions: {
show: {
resource: ['asset'],
operation: ['upload'],
},
},
description:
'Whether to replace the existing asset with the same name (true). Otherwise, a new version with a different name (numeral in parentheses) will be uploaded (false).',
},
{
displayName: 'Append to Column',
name: 'append',
type: 'boolean',
default: true,
displayOptions: {
show: {
resource: ['asset'],
operation: ['upload'],
},
},
description:
'Whether to keep existing files/images in the column and append the new asset (true). Otherwise, the existing files/images are removed from the column (false).',
},
];

View file

@ -1,4 +0,0 @@
import { upload as execute } from './execute';
import { assetUploadDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,14 @@
import type { BaseProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
import type { APITypes } from '../../types';
export const baseApiCallDescription: BaseProperties = [
export const properties: INodeProperties[] = [
{
displayName: 'HTTP Method',
name: 'apiMethod',
@ -23,12 +31,6 @@ export const baseApiCallDescription: BaseProperties = [
value: 'DELETE',
},
],
displayOptions: {
show: {
resource: ['base'],
operation: ['apiCall'],
},
},
required: true,
default: 'POST',
},
@ -37,22 +39,11 @@ export const baseApiCallDescription: BaseProperties = [
name: 'notice',
type: 'notice',
default: '',
displayOptions: {
show: {
resource: ['base'],
operation: ['apiCall'],
},
},
},
{
displayName: 'URL',
name: 'apiEndpoint',
type: 'string',
displayOptions: {
show: {
operation: ['apiCall'],
},
},
required: true,
default: '',
placeholder: '/dtable-server/...',
@ -88,23 +79,11 @@ export const baseApiCallDescription: BaseProperties = [
],
},
],
displayOptions: {
show: {
resource: ['base'],
operation: ['apiCall'],
},
},
},
{
displayName: 'Body',
name: 'apiBody',
type: 'json',
displayOptions: {
show: {
resource: ['base'],
operation: ['apiCall'],
},
},
typeOptions: {
rows: 4,
},
@ -117,14 +96,51 @@ export const baseApiCallDescription: BaseProperties = [
name: 'responseObjectName',
type: 'string',
placeholder: 'Leave it empty or use a value like "rows", "metadata", "views" etc.',
displayOptions: {
show: {
resource: ['base'],
operation: ['apiCall'],
},
},
default: '',
description:
'When using the SeaTable API, you can specify a parameter to retrieve either the entire array of objects or a specific object within it. This allows you to choose whether to fetch the complete output or only the object related to the provided parameter.',
},
];
const displayOptions = {
show: {
resource: ['base'],
operation: ['apiCall'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const apiMethod = this.getNodeParameter('apiMethod', index) as APITypes;
const apiEndpoint = this.getNodeParameter('apiEndpoint', index) as APITypes;
const responseObjectName = this.getNodeParameter('responseObjectName', index) as string;
// body params
const apiBody = this.getNodeParameter('apiBody', index) as any;
// query params
const apiParams: IDataObject = {};
const params = this.getNodeParameter('apiParams.apiParamsValues', index, []) as any;
for (const param of params) {
apiParams[`${param.key}`] = param.value;
}
const responseData = await seaTableApiRequest.call(
this,
{},
apiMethod,
apiEndpoint,
apiBody,
apiParams,
);
if (responseObjectName) {
return this.helpers.returnJsonArray(responseData[responseObjectName] as IDataObject[]);
} else {
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
}

View file

@ -1,37 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
import type { APITypes } from '../../../types';
export async function apiCall(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const apiMethod = this.getNodeParameter('apiMethod', index) as APITypes;
const apiEndpoint = this.getNodeParameter('apiEndpoint', index) as APITypes;
const responseObjectName = this.getNodeParameter('responseObjectName', index) as string;
// body params
const apiBody = this.getNodeParameter('apiBody', index) as any;
// query params
const apiParams: IDataObject = {};
const params = this.getNodeParameter('apiParams.apiParamsValues', index, []) as any;
for (const param of params) {
apiParams[`${param.key}`] = param.value;
}
const responseData = await seaTableApiRequest.call(
this,
{},
apiMethod,
apiEndpoint,
apiBody,
apiParams,
);
if (responseObjectName) {
return this.helpers.returnJsonArray(responseData[responseObjectName] as IDataObject[]);
} else {
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
}

View file

@ -1,4 +0,0 @@
import { apiCall as execute } from './execute';
import { baseApiCallDescription as description } from './description';
export { description, execute };

View file

@ -0,0 +1,53 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
import type { ICollaborator } from '../Interfaces';
export const properties: INodeProperties[] = [
{
displayName: 'Name or email of the collaborator',
name: 'searchString',
type: 'string',
placeholder: 'Enter the name or the email or the collaborator',
required: true,
default: '',
description:
'SeaTable identifies users with a unique username like 244b43hr6fy54bb4afa2c2cb7369d244@auth.local. Get this username from an email or the name of a collaborator.',
},
];
const displayOptions = {
show: {
resource: ['base'],
operation: ['collaborator'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const searchString = this.getNodeParameter('searchString', index) as string;
const collaboratorsResult = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/related-users/',
);
const collaborators = collaboratorsResult.user_list || [];
const data = collaborators.filter(
(col: ICollaborator) =>
col.contact_email.includes(searchString) || col.name.includes(searchString),
);
return this.helpers.returnJsonArray(data as IDataObject[]);
}

View file

@ -1,20 +0,0 @@
import type { BaseProperties } from '../../Interfaces';
export const baseCollaboratorDescription: BaseProperties = [
{
displayName: 'Name or email of the collaborator',
name: 'searchString',
type: 'string',
placeholder: 'Enter the name or the email or the collaborator',
required: true,
displayOptions: {
show: {
resource: ['base'],
operation: ['collaborator'],
},
},
default: '',
description:
'SeaTable identifies users with a unique username like 244b43hr6fy54bb4afa2c2cb7369d244@auth.local. Get this username from an email or the name of a collaborator.',
},
];

View file

@ -1,25 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
import type { ICollaborator } from '../../Interfaces';
export async function collaborator(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const searchString = this.getNodeParameter('searchString', index) as string;
const collaboratorsResult = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/related-users/',
);
const collaborators = collaboratorsResult.user_list || [];
const data = collaborators.filter(
(col: ICollaborator) =>
col.contact_email.includes(searchString) || col.name.includes(searchString),
);
return this.helpers.returnJsonArray(data as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { collaborator as execute } from './execute';
import { baseCollaboratorDescription as description } from './description';
export { description, execute };

View file

@ -1,8 +1,8 @@
import type { INodeProperties } from 'n8n-workflow';
import * as snapshot from './snapshot';
import * as metadata from './metadata';
import * as apiCall from './apiCall';
import * as collaborator from './collaborator';
import * as snapshot from './snapshot.operation';
import * as metadata from './metadata.operation';
import * as apiCall from './apiCall.operation';
import * as collaborator from './collaborator.operation';
export { snapshot, metadata, apiCall, collaborator };

View file

@ -0,0 +1,29 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const properties: INodeProperties[] = [];
const displayOptions = {
show: {
resource: ['base'],
operation: ['metadata'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
const responseData = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/metadata/',
);
return this.helpers.returnJsonArray(responseData.metadata as IDataObject[]);
}

View file

@ -1,3 +0,0 @@
import type { BaseProperties } from '../../Interfaces';
export const baseMetadataDescription: BaseProperties = [];

View file

@ -1,12 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function metadata(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
const responseData = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/metadata/',
);
return this.helpers.returnJsonArray(responseData.metadata as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { metadata as execute } from './execute';
import { baseMetadataDescription as description } from './description';
export { description, execute };

View file

@ -0,0 +1,31 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const properties: INodeProperties[] = [];
const displayOptions = {
show: {
resource: ['base'],
operation: ['snapshot'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/snapshot/',
{ dtable_name: 'snapshot' },
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,3 +0,0 @@
import type { BaseProperties } from '../../Interfaces';
export const baseSnapshotDescription: BaseProperties = [];

View file

@ -1,14 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function snapshot(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/snapshot/',
{ dtable_name: 'snapshot' },
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { snapshot as execute } from './execute';
import { baseSnapshotDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,13 @@
import type { LinkProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const linkAddDescription: LinkProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name (Source)',
@ -11,12 +18,6 @@ export const linkAddDescription: LinkProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNameAndId',
},
displayOptions: {
show: {
resource: ['link'],
operation: ['add'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -27,12 +28,6 @@ export const linkAddDescription: LinkProperties = [
displayName: 'Link Column',
name: 'linkColumn',
type: 'options',
displayOptions: {
show: {
resource: ['link'],
operation: ['add'],
},
},
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getLinkColumns',
@ -47,12 +42,6 @@ export const linkAddDescription: LinkProperties = [
displayName: 'Row ID From the Source Table',
name: 'linkColumnSourceId',
type: 'string',
displayOptions: {
show: {
resource: ['link'],
operation: ['add'],
},
},
required: true,
default: '',
description: 'Provide the row ID of table you selected',
@ -61,14 +50,46 @@ export const linkAddDescription: LinkProperties = [
displayName: 'Row ID From the Target',
name: 'linkColumnTargetId',
type: 'string',
displayOptions: {
show: {
resource: ['link'],
operation: ['add'],
},
},
required: true,
default: '',
description: 'Provide the row ID of table you want to link',
},
];
const displayOptions = {
show: {
resource: ['link'],
operation: ['add'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const linkColumn = this.getNodeParameter('linkColumn', index) as any;
const linkColumnSourceId = this.getNodeParameter('linkColumnSourceId', index) as string;
const linkColumnTargetId = this.getNodeParameter('linkColumnTargetId', index) as string;
const body = {
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
other_table_id: linkColumn.split(':::')[2],
other_rows_ids_map: {
[linkColumnSourceId]: [linkColumnTargetId],
},
};
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/base/{{dtable_uuid}}/links/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,28 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function add(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const linkColumn = this.getNodeParameter('linkColumn', index) as any;
const linkColumnSourceId = this.getNodeParameter('linkColumnSourceId', index) as string;
const linkColumnTargetId = this.getNodeParameter('linkColumnTargetId', index) as string;
const body = {
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
other_table_id: linkColumn.split(':::')[2],
other_rows_ids_map: {
[linkColumnSourceId]: [linkColumnTargetId],
},
};
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/base/{{dtable_uuid}}/links/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { add as execute } from './execute';
import { linkAddDescription as description } from './description';
export { description, execute };

View file

@ -1,7 +1,7 @@
import type { INodeProperties } from 'n8n-workflow';
import * as add from './add';
import * as list from './list';
import * as remove from './remove';
import * as add from './add.operation';
import * as list from './list.operation';
import * as remove from './remove.operation';
export { add, list, remove };

View file

@ -1,9 +1,16 @@
import type { LinkProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const listLinkDescription: LinkProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name 32',
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
@ -11,12 +18,6 @@ export const listLinkDescription: LinkProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNameAndId',
},
displayOptions: {
show: {
resource: ['link'],
operation: ['list'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -27,12 +28,6 @@ export const listLinkDescription: LinkProperties = [
displayName: 'Link Column',
name: 'linkColumn',
type: 'options',
displayOptions: {
show: {
resource: ['link'],
operation: ['list'],
},
},
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getLinkColumnsWithColumnKey',
@ -55,12 +50,45 @@ export const listLinkDescription: LinkProperties = [
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['link'],
operation: ['list'],
},
},
default: '',
},
];
const displayOptions = {
show: {
resource: ['link'],
operation: ['list'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
// get parameters
const tableName = this.getNodeParameter('tableName', index) as string;
const linkColumn = this.getNodeParameter('linkColumn', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
// get rows
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/linked-records/{{dtable_uuid}}/',
{
table_id: tableName.split(':::')[1],
link_column: linkColumn.split(':::')[3],
rows: [
{
row_id: rowId,
offset: 0,
limit: 100,
},
],
},
);
return this.helpers.returnJsonArray(responseData[rowId] as IDataObject[]);
}

View file

@ -1,29 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function list(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]> {
// get parameters
const tableName = this.getNodeParameter('tableName', index) as string;
const linkColumn = this.getNodeParameter('linkColumn', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
// get rows
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/linked-records/{{dtable_uuid}}/',
{
table_id: tableName.split(':::')[1],
link_column: linkColumn.split(':::')[3],
rows: [
{
row_id: rowId,
offset: 0,
limit: 100,
},
],
},
);
return this.helpers.returnJsonArray(responseData[rowId] as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { list as execute } from './execute';
import { listLinkDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,13 @@
import type { LinkProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const linkRemoveDescription: LinkProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name (Source)',
@ -11,12 +18,6 @@ export const linkRemoveDescription: LinkProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNameAndId',
},
displayOptions: {
show: {
resource: ['link'],
operation: ['remove'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -27,12 +28,6 @@ export const linkRemoveDescription: LinkProperties = [
displayName: 'Link Column',
name: 'linkColumn',
type: 'options',
displayOptions: {
show: {
resource: ['link'],
operation: ['remove'],
},
},
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getLinkColumns',
@ -47,12 +42,6 @@ export const linkRemoveDescription: LinkProperties = [
displayName: 'Row ID From the Source Table',
name: 'linkColumnSourceId',
type: 'string',
displayOptions: {
show: {
resource: ['link'],
operation: ['remove'],
},
},
required: true,
default: '',
description: 'Provide the row ID of table you selected',
@ -61,14 +50,46 @@ export const linkRemoveDescription: LinkProperties = [
displayName: 'Row ID From the Target Table',
name: 'linkColumnTargetId',
type: 'string',
displayOptions: {
show: {
resource: ['link'],
operation: ['remove'],
},
},
required: true,
default: '',
description: 'Provide the row ID of table you want to link',
},
];
const displayOptions = {
show: {
resource: ['link'],
operation: ['remove'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const linkColumn = this.getNodeParameter('linkColumn', index) as any;
const linkColumnSourceId = this.getNodeParameter('linkColumnSourceId', index) as string;
const linkColumnTargetId = this.getNodeParameter('linkColumnTargetId', index) as string;
const body = {
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
other_table_id: linkColumn.split(':::')[2],
other_rows_ids_map: {
[linkColumnSourceId]: [linkColumnTargetId],
},
};
const responseData = await seaTableApiRequest.call(
this,
{},
'DELETE',
'/dtable-db/api/v1/base/{{dtable_uuid}}/links/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,31 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function remove(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const linkColumn = this.getNodeParameter('linkColumn', index) as any;
const linkColumnSourceId = this.getNodeParameter('linkColumnSourceId', index) as string;
const linkColumnTargetId = this.getNodeParameter('linkColumnTargetId', index) as string;
const body = {
link_id: linkColumn.split(':::')[1],
table_id: tableName.split(':::')[1],
other_table_id: linkColumn.split(':::')[2],
other_rows_ids_map: {
[linkColumnSourceId]: [linkColumnTargetId],
},
};
const responseData = await seaTableApiRequest.call(
this,
{},
'DELETE',
'/dtable-db/api/v1/base/{{dtable_uuid}}/links/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { remove as execute } from './execute';
import { linkRemoveDescription as description } from './description';
export { description, execute };

View file

@ -0,0 +1,215 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import {
seaTableApiRequest,
getTableColumns,
split,
rowExport,
updateAble,
splitStringColumnsToArrays,
} from '../../GenericFunctions';
import type { IRowObject } from '../Interfaces';
import type { TColumnValue, TColumnsUiValues } from '../../types';
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Data to Send',
name: 'fieldsToSend',
type: 'options',
options: [
{
name: 'Auto-Map Input Data to Columns',
value: 'autoMapInputData',
description: 'Use when node input properties match destination column names',
},
{
name: 'Define Below for Each Column',
value: 'defineBelow',
description: 'Set the value for each destination column',
},
],
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 SeaTable. (Use an "Edit Fields" node before this node to change them if required.)',
name: 'notice',
type: 'notice',
default: '',
displayOptions: {
show: {
'/fieldsToSend': ['autoMapInputData'],
},
},
},
{
displayName: 'Inputs to Ignore',
name: 'inputsToIgnore',
type: 'string',
default: '',
description:
'List of input properties to avoid sending, separated by commas. Leave empty to send all properties.',
placeholder: 'Enter properties...',
displayOptions: {
show: {
'/fieldsToSend': ['autoMapInputData'],
},
},
},
{
displayName: 'Columns to Send',
name: 'columnsUi',
placeholder: 'Add Column',
type: 'fixedCollection',
typeOptions: {
multipleValueButtonText: 'Add Column to Send',
multipleValues: true,
},
displayOptions: {
show: {
'/fieldsToSend': ['defineBelow'],
},
},
options: [
{
displayName: 'Column',
name: 'columnValues',
values: [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column Name',
name: 'columnName',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify the column name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getTableUpdateAbleColumns',
},
default: '',
},
{
displayName: 'Column Value',
name: 'columnValue',
type: 'string',
default: '',
},
],
},
],
default: {},
description:
'Add destination column with its value. Provide the value in this way. Date: YYYY-MM-DD or YYYY-MM-DD hh:mm. Duration: time in seconds. Checkbox: true, on or 1. Multi-Select: comma-separated list.',
},
{
displayName: 'Save to "Big Data" Backend',
name: 'bigdata',
type: 'boolean',
default: false,
description:
'Whether write to Big Data backend (true) or not (false). True requires the activation of the Big Data backend in the base.',
},
{
displayName:
'Hint: Link, files, images or digital signatures have to be added separately. These column types cannot be set with this node.',
name: 'notice',
type: 'notice',
default: '',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['create'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const tableColumns = await getTableColumns.call(this, tableName);
const fieldsToSend = this.getNodeParameter('fieldsToSend', index) as
| 'defineBelow'
| 'autoMapInputData';
const bigdata = this.getNodeParameter('bigdata', index) as string;
const body = {
table_name: tableName,
row: {},
} as IDataObject;
let rowInput = {} as IRowObject;
// get rowInput, an object of key:value pairs like { Name: 'Promo Action 1', Status: "Draft" }.
if (fieldsToSend === 'autoMapInputData') {
const items = this.getInputData();
const incomingKeys = Object.keys(items[index].json);
const inputDataToIgnore = split(this.getNodeParameter('inputsToIgnore', index, '') as string);
for (const key of incomingKeys) {
if (inputDataToIgnore.includes(key)) continue;
rowInput[key] = items[index].json[key] as TColumnValue;
}
} else {
const columns = this.getNodeParameter('columnsUi.columnValues', index, []) as TColumnsUiValues;
for (const column of columns) {
rowInput[column.columnName] = column.columnValue;
}
}
// only keep key:value pairs for columns that are allowed to update.
rowInput = rowExport(rowInput, updateAble(tableColumns));
// string to array: multi-select and collaborators
rowInput = splitStringColumnsToArrays(rowInput, tableColumns);
// save to big data backend
if (bigdata) {
body.rows = [rowInput];
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/insert-rows/{{dtable_uuid}}/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
// save to normal backend
else {
body.row = rowInput;
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
}

View file

@ -1,140 +0,0 @@
import type { RowProperties } from '../../Interfaces';
export const rowCreateDescription: RowProperties = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Data to Send',
name: 'fieldsToSend',
type: 'options',
options: [
{
name: 'Auto-Map Input Data to Columns',
value: 'autoMapInputData',
description: 'Use when node input properties match destination column names',
},
{
name: 'Define Below for Each Column',
value: 'defineBelow',
description: 'Set the value for each destination column',
},
],
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
},
},
default: 'defineBelow',
description: 'Whether to insert the input data this node receives in the new row',
},
{
displayName: 'Inputs to Ignore',
name: 'inputsToIgnore',
type: 'string',
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
fieldsToSend: ['autoMapInputData'],
},
},
default: '',
description:
'List of input properties to avoid sending, separated by commas. Leave empty to send all properties.',
placeholder: 'Enter properties...',
},
{
displayName: 'Columns to Send',
name: 'columnsUi',
placeholder: 'Add Column',
type: 'fixedCollection',
typeOptions: {
multipleValueButtonText: 'Add Column to Send',
multipleValues: true,
},
options: [
{
displayName: 'Column',
name: 'columnValues',
values: [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column Name',
name: 'columnName',
type: 'options',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify the column name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getTableUpdateAbleColumns',
},
default: '',
},
{
displayName: 'Column Value',
name: 'columnValue',
type: 'string',
default: '',
},
],
},
],
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
fieldsToSend: ['defineBelow'],
},
},
default: {},
description:
'Add destination column with its value. Provide the value in this way. Date: YYYY-MM-DD or YYYY-MM-DD hh:mm. Duration: time in seconds. Checkbox: true, on or 1. Multi-Select: comma-separated list.',
},
{
displayName: 'Save to "Big Data" Backend',
name: 'bigdata',
type: 'boolean',
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
},
},
default: false,
description:
'Whether write to Big Data backend (true) or not (false). True requires the activation of the Big Data backend in the base.',
},
{
displayName: 'Hint: Link, files, images or digital signatures have to be added separately.',
name: 'notice',
type: 'notice',
default: '',
displayOptions: {
show: {
resource: ['row'],
operation: ['create'],
},
},
},
];

View file

@ -1,76 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import {
seaTableApiRequest,
getTableColumns,
split,
rowExport,
updateAble,
splitStringColumnsToArrays,
} from '../../../GenericFunctions';
import type { IRowObject } from '../../Interfaces';
import type { TColumnValue, TColumnsUiValues } from '../../../types';
export async function create(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const tableColumns = await getTableColumns.call(this, tableName);
const fieldsToSend = this.getNodeParameter('fieldsToSend', index) as
| 'defineBelow'
| 'autoMapInputData';
const bigdata = this.getNodeParameter('bigdata', index) as string;
const body = {
table_name: tableName,
row: {},
} as IDataObject;
let rowInput = {} as IRowObject;
// get rowInput, an object of key:value pairs like { Name: 'Promo Action 1', Status: "Draft" }.
if (fieldsToSend === 'autoMapInputData') {
const items = this.getInputData();
const incomingKeys = Object.keys(items[index].json);
const inputDataToIgnore = split(this.getNodeParameter('inputsToIgnore', index, '') as string);
for (const key of incomingKeys) {
if (inputDataToIgnore.includes(key)) continue;
rowInput[key] = items[index].json[key] as TColumnValue;
}
} else {
const columns = this.getNodeParameter('columnsUi.columnValues', index, []) as TColumnsUiValues;
for (const column of columns) {
rowInput[column.columnName] = column.columnValue;
}
}
// only keep key:value pairs for columns that are allowed to update.
rowInput = rowExport(rowInput, updateAble(tableColumns));
// string to array: multi-select and collaborators
rowInput = splitStringColumnsToArrays(rowInput, tableColumns);
// save to big data backend
if (bigdata) {
body.rows = [rowInput];
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/insert-rows/{{dtable_uuid}}/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
// save to normal backend
else {
body.row = rowInput;
const responseData = await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}
}

View file

@ -1,4 +0,0 @@
import { create as execute } from './execute';
import { rowCreateDescription as description } from './description';
export { description, execute };

View file

@ -0,0 +1,99 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import {
seaTableApiRequest,
enrichColumns,
simplify_new,
getBaseCollaborators,
} from '../../GenericFunctions';
import type { IRowResponse, IDtableMetadataColumn } from '../Interfaces';
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Row ID',
name: 'rowId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true,
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
default: '',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['get'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
// get parameters
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const simple = this.getNodeParameter('simple', index) as boolean;
// get collaborators
const collaborators = await getBaseCollaborators.call(this);
// get rows
const sqlResult = (await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/query/{{dtable_uuid}}/',
{
sql: `SELECT * FROM \`${tableName}\` WHERE _id = '${rowId}'`,
convert_keys: true,
},
)) as IRowResponse;
const metadata = sqlResult.metadata as IDtableMetadataColumn[];
const rows = sqlResult.results;
// hide columns like button
rows.map((row) => enrichColumns(row, metadata, collaborators));
// remove columns starting with _ if simple;
if (simple) {
rows.map((row) => simplify_new(row));
}
return this.helpers.returnJsonArray(rows as IDataObject[]);
}

View file

@ -1,42 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import {
seaTableApiRequest,
enrichColumns,
simplify_new,
getBaseCollaborators,
} from '../../../GenericFunctions';
import type { IRowResponse, IDtableMetadataColumn } from './../../Interfaces';
export async function get(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]> {
// get parameters
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const simple = this.getNodeParameter('simple', index) as boolean;
// get collaborators
const collaborators = await getBaseCollaborators.call(this);
// get rows
const sqlResult = (await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/query/{{dtable_uuid}}/',
{
sql: `SELECT * FROM \`${tableName}\` WHERE _id = '${rowId}'`,
convert_keys: true,
},
)) as IRowResponse;
const metadata = sqlResult.metadata as IDtableMetadataColumn[];
const rows = sqlResult.results;
// hide columns like button
rows.map((row) => enrichColumns(row, metadata, collaborators));
// remove columns starting with _ if simple;
if (simple) {
rows.map((row) => simplify_new(row));
}
return this.helpers.returnJsonArray(rows as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { get as execute } from './execute';
import { rowGetDescription as description } from './description';
export { description, execute };

View file

@ -1,12 +1,12 @@
import type { INodeProperties } from 'n8n-workflow';
import * as create from './create';
import * as get from './get';
import * as list from './list';
import * as search from './search';
import * as update from './update';
import * as remove from './remove';
import * as lock from './lock';
import * as unlock from './unlock';
import * as create from './create.operation';
import * as get from './get.operation';
import * as list from './list.operation';
import * as search from './search.operation';
import * as update from './update.operation';
import * as remove from './remove.operation';
import * as lock from './lock.operation';
import * as unlock from './unlock.operation';
export { create, get, search, update, remove, lock, unlock, list };

View file

@ -0,0 +1,111 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import {
seaTableApiRequest,
enrichColumns,
simplify_new,
getBaseCollaborators,
} from '../../GenericFunctions';
import type { IRow } from '../Interfaces';
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNameAndId',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify by using an expression. Provide it in the way "table_name:::table_id".',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'View Name',
name: 'viewName',
type: 'options',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getTableViews',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable view to access, or specify by using an expression. Provide it in the way "col.name:::col.type".',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['list'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
// get parameters
const tableName = this.getNodeParameter('tableName', index) as string;
const viewName = this.getNodeParameter('viewName', index) as string;
const simple = this.getNodeParameter('simple', index) as boolean;
// get collaborators
const collaborators = await getBaseCollaborators.call(this);
// get rows
const requestMeta = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/metadata/',
);
const requestRows = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
{},
{
table_name: tableName,
view_name: viewName,
limit: 1000,
},
);
const metadata =
requestMeta.metadata.tables.find((table: { name: string }) => table.name === tableName)
?.columns ?? [];
const rows = requestRows.rows as IRow[];
// hide columns like button
rows.map((row) => enrichColumns(row, metadata, collaborators));
// remove columns starting with _ if simple;
if (simple) {
rows.map((row) => simplify_new(row));
}
return this.helpers.returnJsonArray(rows as IDataObject[]);
}

View file

@ -1,58 +0,0 @@
import type { RowProperties } from '../../Interfaces';
export const rowListDescription: RowProperties = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNameAndId',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['list'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Choose from the list, or specify by using an expression. Provide it in the way "table_name:::table_id".',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'View Name',
name: 'viewName',
type: 'options',
displayOptions: {
show: {
resource: ['row'],
operation: ['list'],
},
},
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getTableViews',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable view to access, or specify by using an expression. Provide it in the way "col.name:::col.type".',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
resource: ['row'],
operation: ['list'],
},
},
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
];

View file

@ -1,54 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import {
seaTableApiRequest,
enrichColumns,
simplify_new,
getBaseCollaborators,
} from '../../../GenericFunctions';
import type { IRow } from './../../Interfaces';
export async function list(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]> {
// get parameters
const tableName = this.getNodeParameter('tableName', index) as string;
const viewName = this.getNodeParameter('viewName', index) as string;
const simple = this.getNodeParameter('simple', index) as boolean;
// get collaborators
const collaborators = await getBaseCollaborators.call(this);
// get rows
const requestMeta = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/metadata/',
);
const requestRows = await seaTableApiRequest.call(
this,
{},
'GET',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/rows/',
{},
{
table_name: tableName,
view_name: viewName,
limit: 1000,
},
);
const metadata =
requestMeta.metadata.tables.find((table: { name: string }) => table.name === tableName)
?.columns ?? [];
const rows = requestRows.rows as IRow[];
// hide columns like button
rows.map((row) => enrichColumns(row, metadata, collaborators));
// remove columns starting with _ if simple;
if (simple) {
rows.map((row) => simplify_new(row));
}
return this.helpers.returnJsonArray(rows as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { list as execute } from './execute';
import { rowListDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,13 @@
import type { RowProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const rowLockDescription: RowProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
@ -11,12 +18,6 @@ export const rowLockDescription: RowProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['lock'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -35,12 +36,36 @@ export const rowLockDescription: RowProperties = [
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['lock'],
},
},
default: '',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['lock'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/lock-rows/',
{
table_name: tableName,
row_ids: [rowId],
},
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,20 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function lock(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/lock-rows/',
{
table_name: tableName,
row_ids: [rowId],
},
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { lock as execute } from './execute';
import { rowLockDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,13 @@
import type { RowProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const rowRemoveDescription: RowProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
@ -11,12 +18,6 @@ export const rowRemoveDescription: RowProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['remove'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -32,15 +33,41 @@ export const rowRemoveDescription: RowProperties = [
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['remove'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Remove any row from the normal or big data backend based on its unique row ID. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['remove'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const requestBody: IDataObject = {
table_name: tableName,
row_ids: [rowId],
};
const responseData = await seaTableApiRequest.call(
this,
{},
'DELETE',
'/dtable-db/api/v1/delete-rows/{{dtable_uuid}}/',
requestBody,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,25 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function remove(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const requestBody: IDataObject = {
table_name: tableName,
row_ids: [rowId],
};
const responseData = await seaTableApiRequest.call(
this,
{},
'DELETE',
'/dtable-db/api/v1/delete-rows/{{dtable_uuid}}/',
requestBody,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { remove as execute } from './execute';
import { rowRemoveDescription as description } from './description';
export { description, execute };

View file

@ -0,0 +1,137 @@
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import {
seaTableApiRequest,
enrichColumns,
simplify_new,
getBaseCollaborators,
} from '../../GenericFunctions';
import type { IDtableMetadataColumn, IRowResponse } from '../Interfaces';
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column Name',
name: 'searchColumn',
type: 'options',
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getSearchableColumns',
},
required: true,
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Select the column to be searched. Not all column types are supported for search. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Search Term',
name: 'searchTerm',
type: 'string',
required: true,
default: '',
description: 'What to look for?',
},
{
displayName: 'Case Insensitive Search',
name: 'insensitive',
type: 'boolean',
default: false,
description:
'Whether the search ignores case sensitivity (true). Otherwise, it distinguishes between uppercase and lowercase characters.',
},
{
displayName: 'Activate Wildcard Search',
name: 'wildcard',
type: 'boolean',
default: false,
description:
'Whether the search only results perfect matches (true). Otherwise, it finds a row even if the search value is part of a string (false).',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['search'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const searchColumn = this.getNodeParameter('searchColumn', index) as string;
const searchTerm = this.getNodeParameter('searchTerm', index) as string | number;
let searchTermString = String(searchTerm);
const insensitive = this.getNodeParameter('insensitive', index) as boolean;
const wildcard = this.getNodeParameter('wildcard', index) as boolean;
const simple = this.getNodeParameter('simple', index) as boolean;
// get collaborators
const collaborators = await getBaseCollaborators.call(this);
// this is the base query. The WHERE has to be finalized...
let sqlQuery = `SELECT * FROM \`${tableName}\` WHERE \`${searchColumn}\``;
if (insensitive) {
searchTermString = searchTermString.toLowerCase();
sqlQuery = `SELECT * FROM \`${tableName}\` WHERE lower(\`${searchColumn}\`)`;
}
if (wildcard) sqlQuery = sqlQuery + ' LIKE "%' + searchTermString + '%"';
else if (!wildcard) sqlQuery = sqlQuery + ' = "' + searchTermString + '"';
const sqlResult = (await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/query/{{dtable_uuid}}/',
{
sql: sqlQuery,
convert_keys: true,
},
)) as IRowResponse;
const metadata = sqlResult.metadata as IDtableMetadataColumn[];
const rows = sqlResult.results;
// hide columns like button
rows.map((row) => enrichColumns(row, metadata, collaborators));
// remove columns starting with _;
if (simple) {
rows.map((row) => simplify_new(row));
}
return this.helpers.returnJsonArray(rows as IDataObject[]);
}

View file

@ -1,101 +0,0 @@
import type { RowProperties } from '../../Interfaces';
export const rowSearchDescription: RowProperties = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['search'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Column Name',
name: 'searchColumn',
type: 'options',
displayOptions: {
show: {
resource: ['row'],
operation: ['search'],
},
},
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getSearchableColumns',
},
required: true,
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'Select the column to be searched. Not all column types are supported for search. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Search Term',
name: 'searchTerm',
type: 'string',
displayOptions: {
show: {
resource: ['row'],
operation: ['search'],
},
},
required: true,
default: '',
description: 'What to look for?',
},
{
displayName: 'Case Insensitive Search',
name: 'insensitive',
type: 'boolean',
displayOptions: {
show: {
resource: ['row'],
operation: ['search'],
},
},
default: false,
description:
'Whether the search ignores case sensitivity (true). Otherwise, it distinguishes between uppercase and lowercase characters.',
},
{
displayName: 'Activate Wildcard Search',
name: 'wildcard',
type: 'boolean',
displayOptions: {
show: {
resource: ['row'],
operation: ['search'],
},
},
default: false,
description:
'Whether the search only results perfect matches (true). Otherwise, it finds a row even if the search value is part of a string (false).',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
default: true,
displayOptions: {
show: {
resource: ['row'],
operation: ['search'],
},
},
description: 'Whether to return a simplified version of the response instead of the raw data',
},
];

View file

@ -1,58 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import {
seaTableApiRequest,
enrichColumns,
simplify_new,
getBaseCollaborators,
} from '../../../GenericFunctions';
import type { IDtableMetadataColumn, IRowResponse } from '../../Interfaces';
export async function search(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const searchColumn = this.getNodeParameter('searchColumn', index) as string;
const searchTerm = this.getNodeParameter('searchTerm', index) as string | number;
let searchTermString = String(searchTerm);
const insensitive = this.getNodeParameter('insensitive', index) as boolean;
const wildcard = this.getNodeParameter('wildcard', index) as boolean;
const simple = this.getNodeParameter('simple', index) as boolean;
// get collaborators
const collaborators = await getBaseCollaborators.call(this);
// this is the base query. The WHERE has to be finalized...
let sqlQuery = `SELECT * FROM \`${tableName}\` WHERE \`${searchColumn}\``;
if (insensitive) {
searchTermString = searchTermString.toLowerCase();
sqlQuery = `SELECT * FROM \`${tableName}\` WHERE lower(\`${searchColumn}\`)`;
}
if (wildcard) sqlQuery = sqlQuery + ' LIKE "%' + searchTermString + '%"';
else if (!wildcard) sqlQuery = sqlQuery + ' = "' + searchTermString + '"';
const sqlResult = (await seaTableApiRequest.call(
this,
{},
'POST',
'/dtable-db/api/v1/query/{{dtable_uuid}}/',
{
sql: sqlQuery,
convert_keys: true,
},
)) as IRowResponse;
const metadata = sqlResult.metadata as IDtableMetadataColumn[];
const rows = sqlResult.results;
// hide columns like button
rows.map((row) => enrichColumns(row, metadata, collaborators));
// remove columns starting with _;
if (simple) {
rows.map((row) => simplify_new(row));
}
return this.helpers.returnJsonArray(rows as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { search as execute } from './execute';
import { rowSearchDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,13 @@
import type { RowProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import { seaTableApiRequest } from '../../GenericFunctions';
export const rowGetDescription: RowProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
@ -11,12 +18,6 @@ export const rowGetDescription: RowProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['get'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -34,25 +35,36 @@ export const rowGetDescription: RowProperties = [
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['get'],
},
},
default: '',
},
{
displayName: 'Simplify',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
resource: ['row'],
operation: ['get'],
},
},
default: true,
description: 'Whether to return a simplified version of the response instead of the raw data',
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['unlock'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/unlock-rows/',
{
table_name: tableName,
row_ids: [rowId],
},
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,45 +0,0 @@
import type { RowProperties } from '../../Interfaces';
export const rowUnlockDescription: RowProperties = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
name: 'tableName',
type: 'options',
placeholder: 'Select a table',
required: true,
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['unlock'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
'The name of SeaTable table to access. Choose from the list, or specify a name using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Row ID',
name: 'rowId',
type: 'options',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true,
typeOptions: {
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['unlock'],
},
},
default: '',
},
];

View file

@ -1,23 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import { seaTableApiRequest } from '../../../GenericFunctions';
export async function unlock(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const rowId = this.getNodeParameter('rowId', index) as string;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-server/api/v1/dtables/{{dtable_uuid}}/unlock-rows/',
{
table_name: tableName,
row_ids: [rowId],
},
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { unlock as execute } from './execute';
import { rowUnlockDescription as description } from './description';
export { description, execute };

View file

@ -1,6 +1,22 @@
import type { RowProperties } from '../../Interfaces';
import {
type IDataObject,
type INodeExecutionData,
type INodeProperties,
type IExecuteFunctions,
updateDisplayOptions,
} from 'n8n-workflow';
import {
seaTableApiRequest,
getTableColumns,
split,
rowExport,
updateAble,
splitStringColumnsToArrays,
} from '../../GenericFunctions';
import type { IRowObject } from '../Interfaces';
import type { TColumnsUiValues, TColumnValue } from '../../types';
export const rowUpdateDescription: RowProperties = [
export const properties: INodeProperties[] = [
{
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options
displayName: 'Table Name',
@ -11,12 +27,6 @@ export const rowUpdateDescription: RowProperties = [
typeOptions: {
loadOptionsMethod: 'getTableNames',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['update'],
},
},
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-wrong-for-dynamic-options
description:
@ -35,12 +45,6 @@ export const rowUpdateDescription: RowProperties = [
loadOptionsDependsOn: ['tableName'],
loadOptionsMethod: 'getRowIds',
},
displayOptions: {
show: {
resource: ['row'],
operation: ['update'],
},
},
default: '',
},
{
@ -59,12 +63,6 @@ export const rowUpdateDescription: RowProperties = [
description: 'Set the value for each destination column',
},
],
displayOptions: {
show: {
resource: ['row'],
operation: ['update'],
},
},
default: 'defineBelow',
description: 'Whether to insert the input data this node receives in the new row',
},
@ -137,11 +135,70 @@ export const rowUpdateDescription: RowProperties = [
name: 'notice',
type: 'notice',
default: '',
displayOptions: {
show: {
resource: ['row'],
operation: ['update'],
},
},
},
];
const displayOptions = {
show: {
resource: ['row'],
operation: ['update'],
},
};
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const tableColumns = await getTableColumns.call(this, tableName);
const fieldsToSend = this.getNodeParameter('fieldsToSend', index) as
| 'defineBelow'
| 'autoMapInputData';
const rowId = this.getNodeParameter('rowId', index) as string;
let rowInput = {} as IRowObject;
// get rowInput, an object of key:value pairs like { Name: 'Promo Action 1', Status: "Draft" }.
if (fieldsToSend === 'autoMapInputData') {
const items = this.getInputData();
const incomingKeys = Object.keys(items[index].json);
const inputDataToIgnore = split(this.getNodeParameter('inputsToIgnore', index, '') as string);
for (const key of incomingKeys) {
if (inputDataToIgnore.includes(key)) continue;
rowInput[key] = items[index].json[key] as TColumnValue;
}
} else {
const columns = this.getNodeParameter('columnsUi.columnValues', index, []) as TColumnsUiValues;
for (const column of columns) {
rowInput[column.columnName] = column.columnValue;
}
}
// only keep key:value pairs for columns that are allowed to update.
rowInput = rowExport(rowInput, updateAble(tableColumns));
// string to array: multi-select and collaborators
rowInput = splitStringColumnsToArrays(rowInput, tableColumns);
const body = {
table_name: tableName,
updates: [
{
row_id: rowId,
row: rowInput,
},
],
} as IDataObject;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-db/api/v1/update-rows/{{dtable_uuid}}/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,67 +0,0 @@
import type { IExecuteFunctions, IDataObject, INodeExecutionData } from 'n8n-workflow';
import {
seaTableApiRequest,
getTableColumns,
split,
rowExport,
updateAble,
splitStringColumnsToArrays,
} from '../../../GenericFunctions';
import type { IRowObject } from '../../Interfaces';
import type { TColumnsUiValues, TColumnValue } from '../../../types';
export async function update(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const tableName = this.getNodeParameter('tableName', index) as string;
const tableColumns = await getTableColumns.call(this, tableName);
const fieldsToSend = this.getNodeParameter('fieldsToSend', index) as
| 'defineBelow'
| 'autoMapInputData';
const rowId = this.getNodeParameter('rowId', index) as string;
let rowInput = {} as IRowObject;
// get rowInput, an object of key:value pairs like { Name: 'Promo Action 1', Status: "Draft" }.
if (fieldsToSend === 'autoMapInputData') {
const items = this.getInputData();
const incomingKeys = Object.keys(items[index].json);
const inputDataToIgnore = split(this.getNodeParameter('inputsToIgnore', index, '') as string);
for (const key of incomingKeys) {
if (inputDataToIgnore.includes(key)) continue;
rowInput[key] = items[index].json[key] as TColumnValue;
}
} else {
const columns = this.getNodeParameter('columnsUi.columnValues', index, []) as TColumnsUiValues;
for (const column of columns) {
rowInput[column.columnName] = column.columnValue;
}
}
// only keep key:value pairs for columns that are allowed to update.
rowInput = rowExport(rowInput, updateAble(tableColumns));
// string to array: multi-select and collaborators
rowInput = splitStringColumnsToArrays(rowInput, tableColumns);
const body = {
table_name: tableName,
updates: [
{
row_id: rowId,
row: rowInput,
},
],
} as IDataObject;
const responseData = await seaTableApiRequest.call(
this,
{},
'PUT',
'/dtable-db/api/v1/update-rows/{{dtable_uuid}}/',
body,
);
return this.helpers.returnJsonArray(responseData as IDataObject[]);
}

View file

@ -1,4 +0,0 @@
import { update as execute } from './execute';
import { rowUpdateDescription as description } from './description';
export { description, execute };