@jacobwoodward/n8n-nodes-smartsuite
Version:
n8n community node for SmartSuite - Interact with SmartSuite's API to manage records, search data, and perform operations on your SmartSuite solutions
1,097 lines • 56.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmartSuite = void 0;
const GenericFunctions_1 = require("./GenericFunctions");
class SmartSuite {
constructor() {
this.description = {
displayName: "SmartSuite",
name: "smartsuite",
icon: "file:SmartSuite.svg",
group: ["transform"],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: "Interact with SmartSuite API to manage records, search data, and perform operations on your SmartSuite solutions.",
defaults: {
name: "SmartSuite",
},
usableAsTool: true,
inputs: ["main"],
outputs: ["main"],
credentials: [
{
name: "smartSuiteApi",
required: true,
},
],
tool: {
name: "smartsuite",
displayName: "SmartSuite",
description: "Use SmartSuite to manage and retrieve data from your solutions. You can get, list, search, and update records as well as manage tables.",
returnType: "json",
loadOptions: {},
properties: [
{
displayName: "Operation",
name: "operation",
type: "options",
options: [
{
name: "Get Record",
value: "get"
},
{
name: "List Records",
value: "list"
},
{
name: "Search Records",
value: "search"
},
{
name: "Update Record",
value: "update"
},
{
name: "Create Record",
value: "create"
},
{
name: "List Tables",
value: "listTables"
},
{
name: "Get Table",
value: "getTable"
},
{
name: "Create Table",
value: "createTable"
},
{
name: "Create Field",
value: "createField"
}
],
default: "get",
required: true,
},
{
displayName: "Solution ID",
name: "solutionId",
type: "string",
description: "The ID of the SmartSuite solution",
required: true,
},
{
displayName: "Table ID",
name: "tableId",
type: "string",
description: "The ID of the SmartSuite table",
required: true,
displayOptions: {
show: {
operation: ["get", "list", "search", "update"]
}
},
},
{
displayName: "Record ID",
name: "recordId",
type: "string",
description: "The ID of the record to get or update",
displayOptions: {
show: {
operation: ["get", "update"]
}
},
required: true,
},
{
displayName: "Field Values",
name: "fieldValues",
type: "array",
description: "The field values for the new record (for record create operation)",
displayOptions: {
show: {
operation: ["create"]
}
},
required: true,
items: {
type: "object",
properties: {
field: {
type: "string",
description: "Name of the field",
required: true
},
value: {
type: "string",
description: "Value for the field",
required: true
},
start_date: {
type: "string",
description: "Start date for due_date field (ISO 8601 format)",
required: false
},
include_start_time: {
type: "boolean",
description: "Whether to include time for start date",
required: false
},
end_date: {
type: "string",
description: "End date for due_date field (ISO 8601 format)",
required: false
},
include_end_time: {
type: "boolean",
description: "Whether to include time for end date",
required: false
}
}
}
},
{
displayName: "Specific Table ID",
name: "specificTableId",
type: "string",
description: "The ID of the table to operate on",
displayOptions: {
show: {
operation: ["getTable", "createField"]
}
},
required: true,
},
{
name: 'tableName',
description: 'The name of the table to create (for table create operation)',
displayOptions: {
show: {
operation: ["createTable"]
}
},
required: true,
type: 'string'
},
{
name: 'tableLabel',
description: 'The label of the table to create (for table create operation)',
displayOptions: {
show: {
operation: ["createTable"]
}
},
required: true,
type: 'string'
},
{
name: 'tableDescription',
description: 'The description of the table to create (for table create operation)',
displayOptions: {
show: {
operation: ["createTable"]
}
},
required: false,
type: 'string'
},
{
name: 'icon',
description: 'The icon name for the table (for table create operation)',
displayOptions: {
show: {
operation: ["createTable"]
}
},
required: false,
type: 'string'
},
{
name: 'primaryFieldName',
description: 'The name of the primary field (for table create operation)',
displayOptions: {
show: {
operation: ["createTable"]
}
},
required: false,
type: 'string'
},
{
name: 'fieldName',
description: 'The name of the field to create (for field create operation)',
displayOptions: {
show: {
operation: ["createField"]
}
},
required: true,
type: 'string'
},
{
name: 'fieldLabel',
description: 'The label of the field to create (for field create operation)',
displayOptions: {
show: {
operation: ["createField"]
}
},
required: true,
type: 'string'
},
{
name: 'fieldType',
description: 'The type of the field to create (for field create operation)',
displayOptions: {
show: {
operation: ["createField"]
}
},
required: true,
type: 'string',
enum: [
"TEXT", "NUMBER", "BOOLEAN", "DATE", "EMAIL", "URL", "PHONE",
"MULTI_SELECT", "SINGLE_SELECT", "USER", "FILE", "REFERENCE"
]
},
{
name: 'fieldDescription',
description: 'The description of the field to create (for field create operation)',
displayOptions: {
show: {
operation: ["createField"]
}
},
required: false,
type: 'string'
},
{
name: 'selectOptions',
description: 'Options for select fields (only for MULTI_SELECT or SINGLE_SELECT field types)',
displayOptions: {
show: {
operation: ["createField"],
fieldType: ["MULTI_SELECT", "SINGLE_SELECT"]
}
},
required: false,
type: 'array',
items: {
type: 'object',
properties: {
label: {
type: 'string',
description: 'Display name of the option',
required: true
},
color: {
type: 'string',
description: 'Color for the option (hex code)',
required: false
}
}
}
}
]
},
properties: [
{
displayName: "Resource",
name: "resource",
type: "options",
options: [
{
name: "Record",
value: "record",
},
{
name: "Table",
value: "table",
},
],
default: "record",
required: true,
},
{
displayName: "Solution",
name: "solutionId",
type: "options",
typeOptions: {
loadOptionsMethod: "getSolutions",
},
default: "",
required: true,
description: "Select a SmartSuite Solution",
},
{
displayName: "Table",
name: "tableId",
type: "options",
typeOptions: {
loadOptionsMethod: "getTables",
loadOptionsDependsOn: ["solutionId"],
},
default: "",
required: true,
displayOptions: {
show: {
resource: ["record"],
},
},
description: "Select a Table from the Solution",
},
{
displayName: "Operation",
name: "operation",
type: "options",
displayOptions: {
show: {
resource: ["record"],
},
},
options: [
{
name: "Get",
value: "get",
description: "Get a record by ID",
},
{
name: "List",
value: "list",
description: "List records from a table",
},
{
name: "Search",
value: "search",
description: "Search records with filters",
},
{
name: "Create",
value: "create",
description: "Create a new record",
},
{
name: "Update",
value: "update",
description: "Update a record",
},
],
default: "get",
},
{
displayName: "Record ID",
name: "recordId",
type: "string",
default: "",
required: true,
displayOptions: {
show: {
resource: ["record"],
operation: ["get", "update"],
},
},
description: "The ID of the record to retrieve or update",
},
{
displayName: "Field Values",
name: "fieldValues",
type: "fixedCollection",
typeOptions: {
multipleValues: true,
loadOptionsMethod: "getTableFields",
loadOptionsDependsOn: ["tableId"],
},
default: {},
displayOptions: {
show: {
resource: ["record"],
operation: ["create"],
},
},
options: [
{
name: "fieldValues",
displayName: "Field Values",
values: [
{
displayName: "Field",
name: "field",
type: "options",
typeOptions: {
loadOptionsMethod: "getTableFields",
loadOptionsDependsOn: ["tableId"],
},
default: "",
description: "Select a field to set",
},
{
displayName: "Value",
name: "value",
type: "string",
default: "",
description: "Enter the value for the field",
},
],
},
],
description: "Fields to set for the new record",
},
{
displayName: "Hydrated",
name: "hydrated",
type: "boolean",
default: false,
displayOptions: {
show: {
resource: ["record"],
operation: ["get", "list", "search"],
},
},
description: "Whether to return hydrated records with full field data",
},
{
displayName: "Search Operator",
name: "searchOperator",
type: "options",
options: [
{
name: "AND",
value: "AND",
},
{
name: "OR",
value: "OR",
},
],
default: "AND",
displayOptions: {
show: {
resource: ["record"],
operation: ["search"],
},
},
description: "Whether all filters should match (AND) or any (OR)",
},
{
displayName: "Filters",
name: "filters",
type: "fixedCollection",
typeOptions: {
multipleValues: true,
},
default: {},
placeholder: "Add Filter",
displayOptions: {
show: {
resource: ["record"],
operation: ["search"],
},
},
options: [
{
name: "filterFields",
displayName: "Filter",
values: [
{
displayName: "Field",
name: "field",
type: "options",
typeOptions: {
loadOptionsMethod: "getTableFields",
loadOptionsDependsOn: ["tableId"],
},
default: "",
description: "The field to filter on",
},
{
displayName: "Condition",
name: "condition",
type: "options",
options: [
{
name: "Contains",
value: "contains",
description: "String contains the value (text fields)",
},
{
name: "Does Not Contain",
value: "does_not_contain",
description: "String does not contain the value (text fields)",
},
{
name: "Equals",
value: "equals",
description: "Exact match (works for most fields)",
},
{
name: "Not Equals",
value: "not_equals",
description: "Not equal to (works for most fields)",
},
{
name: "Starts With",
value: "starts_with",
description: "String starts with value (text fields)",
},
{
name: "Ends With",
value: "ends_with",
description: "String ends with value (text fields)",
},
{
name: "Greater Than",
value: "greater_than",
description: "Greater than (number fields)",
},
{
name: "Less Than",
value: "less_than",
description: "Less than (number fields)",
},
{
name: "Between",
value: "between",
description: "Between two values (number and date fields)",
},
{
name: "Is",
value: "is",
description: "Equal to date (date fields)",
},
{
name: "Is Not",
value: "is_not",
description: "Not equal to date (date fields)",
},
{
name: "Is Before",
value: "is_before",
description: "Before date (date fields)",
},
{
name: "Is After",
value: "is_after",
description: "After date (date fields)",
},
{
name: "Is Between",
value: "is_between",
description: "Between dates (date fields)",
},
{
name: "Is Empty",
value: "is_empty",
description: "Field has no value (most fields)",
},
{
name: "Is Not Empty",
value: "is_not_empty",
description: "Field has some value (most fields)",
},
],
default: "equals",
description: "The condition to set. Use the appropriate condition for your field type.",
},
{
displayName: "Value",
name: "value",
type: "string",
default: "",
description: "The value to set",
displayOptions: {
hide: {
condition: ["is_empty", "is_not_empty"],
},
},
},
],
},
],
},
{
displayName: "Fields to Update",
name: "fields",
type: "fixedCollection",
typeOptions: {
multipleValues: true,
loadOptionsMethod: "getTableFields",
loadOptionsDependsOn: ["tableId"],
},
default: {},
displayOptions: {
show: {
resource: ["record"],
operation: ["update"],
},
},
options: [
{
name: "fieldValues",
displayName: "Field Values",
values: [
{
displayName: "Field",
name: "field",
type: "options",
typeOptions: {
loadOptionsMethod: "getTableFields",
loadOptionsDependsOn: ["tableId"],
},
default: "",
description: "Select a field to update",
},
{
displayName: "Value",
name: "value",
type: "string",
default: "",
description: "Enter the new value for the field",
},
],
},
],
},
{
displayName: "Operation",
name: "operation",
type: "options",
displayOptions: {
show: {
resource: ["table"],
},
},
options: [
{
name: "List",
value: "list",
description: "List all tables in a solution",
},
{
name: "Get",
value: "get",
description: "Get a table by ID",
},
{
name: "Create",
value: "create",
description: "Create a new table",
},
{
name: "Create Field",
value: "createField",
description: "Create a new field in a table",
action: "Create a new field in a table",
},
],
default: "list",
},
{
displayName: "Table ID",
name: "specificTableId",
type: "string",
default: "",
required: true,
displayOptions: {
show: {
resource: ["table"],
operation: ["get", "createField"],
},
},
description: "ID of the table to retrieve",
},
{
displayName: "Table Name",
name: "tableName",
type: "string",
default: "",
required: true,
displayOptions: {
show: {
resource: ["table"],
operation: ["create"],
},
},
description: "The name of the table to create",
},
{
displayName: "Table Label",
name: "tableLabel",
type: "string",
default: "",
required: true,
displayOptions: {
show: {
resource: ["table"],
operation: ["create"],
},
},
description: "The label of the table to create",
},
{
displayName: "Table Description",
name: "tableDescription",
type: "string",
default: "",
displayOptions: {
show: {
resource: ["table"],
operation: ["create"],
},
},
description: "The description of the table to create",
},
{
displayName: "Icon",
name: "icon",
type: "string",
default: "table",
displayOptions: {
show: {
resource: ["table"],
operation: ["create"],
},
},
description: "The icon name for the table",
},
{
displayName: "Primary Field Name",
name: "primaryFieldName",
type: "string",
default: "Title",
displayOptions: {
show: {
resource: ["table"],
operation: ["create"],
},
},
description: "The name of the primary field",
},
{
displayName: "Field Name",
name: "fieldName",
type: "string",
default: "",
required: true,
displayOptions: {
show: {
resource: ["table"],
operation: ["createField"],
},
},
description: "Name of the field to create",
},
{
displayName: "Field Label",
name: "fieldLabel",
type: "string",
default: "",
required: true,
displayOptions: {
show: {
resource: ["table"],
operation: ["createField"],
},
},
description: "Label of the field to create",
},
{
displayName: "Field Type",
name: "fieldType",
type: "options",
options: [
{
name: "Text",
value: "TEXT",
},
{
name: "Number",
value: "NUMBER",
},
{
name: "Checkbox",
value: "BOOLEAN",
},
{
name: "Date",
value: "DATE",
},
{
name: "Email",
value: "EMAIL",
},
{
name: "URL",
value: "URL",
},
{
name: "Phone",
value: "PHONE",
},
{
name: "Multi-Select",
value: "MULTI_SELECT",
},
{
name: "Single-Select",
value: "SINGLE_SELECT",
},
{
name: "User",
value: "USER",
},
{
name: "File",
value: "FILE",
},
{
name: "Reference",
value: "REFERENCE",
},
],
default: "TEXT",
required: true,
displayOptions: {
show: {
resource: ["table"],
operation: ["createField"],
},
},
description: "Type of the field to create",
},
{
displayName: "Field Description",
name: "fieldDescription",
type: "string",
default: "",
required: false,
displayOptions: {
show: {
resource: ["table"],
operation: ["createField"],
},
},
description: "Description of the field",
},
{
displayName: "Select Options",
name: "selectOptions",
type: "fixedCollection",
typeOptions: {
multipleValues: true,
},
default: {},
displayOptions: {
show: {
resource: ["table"],
operation: ["createField"],
fieldType: ["MULTI_SELECT", "SINGLE_SELECT"],
},
},
options: [
{
name: "options",
displayName: "Options",
values: [
{
displayName: "Label",
name: "label",
type: "string",
default: "",
description: "The display name of the option",
required: true,
},
{
displayName: "Color",
name: "color",
type: "string",
default: "#3399ff",
description: "The color for the option (hex code)",
required: false,
},
],
},
],
description: "Options for the select field",
},
],
};
this.methods = {
loadOptions: {
async getSolutions() {
console.log("=== START GET SOLUTIONS ===");
const response = await GenericFunctions_1.smartSuiteApiRequest.call(this, "GET", "/solutions/");
console.log("Raw solutions response:", JSON.stringify(response, null, 2));
if (!Array.isArray(response)) {
console.log("Response is not an array:", response);
return [];
}
const options = response.map((solution) => {
console.log("Processing solution:", solution);
return {
name: solution.Name || solution.name,
value: solution.Id || solution.id,
};
});
console.log("Final options:", JSON.stringify(options, null, 2));
console.log("=== END GET SOLUTIONS ===");
return options;
},
async getTables() {
const solutionId = this.getCurrentNodeParameter("solutionId");
if (!solutionId) {
return [];
}
const response = await GenericFunctions_1.smartSuiteApiRequest.call(this, "GET", `/applications/?solution=${solutionId}`);
return response.map((table) => ({
name: table.Name || table.name,
value: table.Id || table.id,
}));
},
async getTableFields() {
console.log("=== START GET TABLE FIELDS ===");
const tableId = this.getCurrentNodeParameter("tableId");
console.log("Table ID:", tableId);
if (!tableId) {
console.log("No table ID provided");
return [];
}
try {
const response = await GenericFunctions_1.smartSuiteApiRequest.call(this, "GET", `/applications/${tableId}/`);
console.log("Raw table response:", JSON.stringify(response, null, 2));
if (!response.structure || !Array.isArray(response.structure)) {
console.log("No structure array found in response");
return [];
}
const fields = [];
for (const field of response.structure) {
console.log("Processing field:", field);
if (field.slug === "due_date") {
fields.push({
name: "Start Date",
value: "start_date",
description: `Type: DATE (maps to from_date in the API)`,
});
fields.push({
name: "Due Date",
value: "due_date",
description: `Type: DATE (maps to to_date in the API)`,
});
}
else {
fields.push({
name: field.label || field.Label,
value: field.slug || field.Slug,
description: `Type: ${field.field_type || field.FieldType}`,
});
}
}
console.log("Final field options:", JSON.stringify(fields, null, 2));
console.log("=== END GET TABLE FIELDS ===");
return fields;
}
catch (error) {
console.log("Error getting table fields:", error);
return [];
}
},
},
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
const resource = this.getNodeParameter("resource", 0);
const operation = this.getNodeParameter("operation", 0);
const solutionId = this.getNodeParameter("solutionId", 0);
const tableId = resource === "record" ? this.getNodeParameter("tableId", 0) : "";
let responseData;
for (let i = 0; i < items.length; i++) {
try {
if (resource === "record") {
if (operation === "get") {
const recordId = this.getNodeParameter("recordId", i);
const hydrated = this.getNodeParameter("hydrated", i);
const queryParams = hydrated ? { hydrated: true } : {};
responseData = await GenericFunctions_1.smartSuiteApiRequest.call(this, "GET", `/applications/${tableId}/records/${recordId}`, {}, queryParams);
}
else if (operation === "list") {
const hydrated = this.getNodeParameter("hydrated", i);
const listBody = hydrated ? { hydrated: true } : {};
responseData = await GenericFunctions_1.smartSuiteApiRequest.call(this, "POST", `/applications/${tableId}/records/list/`, listBody, {});
}
else if (operation === "search") {
const searchOperator = this.getNodeParameter("searchOperator", i);
const filterData = this.getNodeParameter("filters.filterFields", i, []);
const fields = filterData.map((filter) => {
if (filter.condition === "is_empty" ||
filter.condition === "is_not_empty") {
return {
field: filter.field,
comparison: filter.condition,
value: "",
};
}
return {
field: filter.field,
comparison: filter.condition,
value: filter.value,
};
});
const hydrated = this.getNodeParameter("hydrated", i);
const searchQuery = {
filter: {
operator: searchOperator.toLowerCase(),
fields,
},
...(hydrated ? { hydrated: true } : {}),
};
responseData = await GenericFunctions_1.smartSuiteApiRequest.call(this, "POST", `/applications/${tableId}/records/list/`, searchQuery, {});
}
else if (operation === "create") {
const fields = this.getNodeParameter("fieldValues.fieldValues", i, []);
console.log("Create fields input:", JSON.stringify(fields, null, 2));
const createData = {};
let startDate = undefined;
let dueDate = undefined;
for (const { field, value } of fields) {
if (field === "start_date") {
startDate = value;
}
else if (field === "due_date") {
dueDate = value;
}
else {
createData[field] = value;
}
}
if (startDate || dueDate) {
createData.due_date = {
from_date: {
date: startDate || "",
include_time: true,
},
to_date: {
date: dueDate || "",
include_time: true,
},
};
}
console.log("Final create data:", JSON.stringify(createData, null, 2));
responseData = await GenericFunctions_1.smartSuiteApiRequest.call(this, "POST", `/applications/${tableId}/records/`, createData);
}
else if (operation === "update") {
const recordId = this.getNodeParameter("recordId", i);
const fields = this.getNodeParameter("fields.fieldValues", i, []);
console.log("Update fields input:", JSON.stringify(fields, null, 2));
const updateData = {};
let startDate = undefined;
let dueDate = undefined;
for (const { field, value } of fields) {
if (field === "start_date") {
startDate = value;
}
else if