Skip to content

Commit 0b5ff93

Browse files
authored
[20988] feat(smartsheet): add sheet, row, column, search, and identity actions (#20997)
* refactor(smartsheet): migrate deprecated smartsheet api's - improve doc links - optimize existing smartsheet actions for LLM * chore(smartsheet): modify description, bump major version * chore(smartsheet): update package version * chore(smartsheet): update package version * chore(smartsheet): update package version * refactor(smartsheet): add token-based pagination in list-workspace-children api call * feat(smartsheet): add new actions and fix doc url's - 20 actions * chore(smartsheet): eslint * fix(smartsheet): address coderabbit review comments * fix(smartsheet): add workspaceId param in folderId propDef * fix(smartsheet): address coderabbit review comments * fix(smartsheet): address coderabbit review comments * fix(smartsheet): change destructiveHint, modify positive-row-id validation * fix(smartsheet): Remove unwanted ConfigurationError block - Modify prop description * chore(smartsheet): Remove dead-code * chore(smartsheet): bump patch version * chore(smartsheet): bump package version * fix(smartsheet): address coderabbit review comments * chore(smartsheet): update package versions * chore(smartsheet): update @pipedream/platform package version from ^1.6.8 to ^3.1.1 * chore(smartsheet): update pnpm-lock.yaml * fix(smartsheet): address coderabbit review comments
1 parent a742ab2 commit 0b5ff93

36 files changed

Lines changed: 1669 additions & 185 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { ConfigurationError } from "@pipedream/platform";
2+
import { COLUMN_TYPES } from "../../common/constants.mjs";
3+
import smartsheet from "../../smartsheet.app.mjs";
4+
5+
export default {
6+
key: "smartsheet-add-column",
7+
name: "Add Column",
8+
description:
9+
"Add a new column to a sheet. Specify the column title, type, and optionally the position and picklist options."
10+
+ " For PICKLIST columns, provide the `options` array with valid values."
11+
+ " Use **List Columns** to see existing columns before adding."
12+
+ " [See the documentation](https://developers.smartsheet.com/api/smartsheet/openapi/columns/columns-addtosheet)",
13+
version: "0.0.1",
14+
type: "action",
15+
annotations: {
16+
destructiveHint: false,
17+
openWorldHint: true,
18+
readOnlyHint: false,
19+
},
20+
props: {
21+
smartsheet,
22+
sheetId: {
23+
type: "string",
24+
label: "Sheet ID",
25+
description: "The ID of the sheet to add a column to. Use **List Sheets** to find sheet IDs.",
26+
},
27+
title: {
28+
type: "string",
29+
label: "Column Title",
30+
description: "The column title. Must be unique within the sheet.",
31+
},
32+
type: {
33+
type: "string",
34+
label: "Column Type",
35+
description: "The data type for this column.",
36+
options: COLUMN_TYPES,
37+
},
38+
index: {
39+
type: "integer",
40+
label: "Position Index",
41+
description: "Zero-based position for the new column. If omitted, the column is added at the end.",
42+
optional: true,
43+
},
44+
options: {
45+
type: "string",
46+
label: "Picklist Options",
47+
description:
48+
"JSON array of option strings for PICKLIST columns."
49+
+ " Example: `[\"Low\", \"Medium\", \"High\", \"Critical\"]`",
50+
optional: true,
51+
},
52+
validation: {
53+
type: "boolean",
54+
label: "Validation",
55+
description: "Set to `true` to restrict cell values to the picklist options. For PICKLIST columns only.",
56+
optional: true,
57+
},
58+
},
59+
async run({ $ }) {
60+
let index = this.index;
61+
if (index === undefined) {
62+
const result = await this.smartsheet.listColumns(this.sheetId, {
63+
$,
64+
params: {
65+
includeAll: true,
66+
},
67+
});
68+
index = result.totalCount ?? result.data?.length ?? 0;
69+
}
70+
71+
const column = {
72+
title: this.title,
73+
type: this.type,
74+
index,
75+
};
76+
if (this.options) {
77+
if (this.type !== "PICKLIST") {
78+
throw new ConfigurationError("`Picklist Options` is only supported for PICKLIST columns.");
79+
}
80+
let parsedOptions;
81+
try {
82+
parsedOptions = JSON.parse(this.options);
83+
} catch {
84+
throw new ConfigurationError("`Picklist Options` must be a valid JSON array (e.g. `[\"Low\", \"High\"]`).");
85+
}
86+
if (
87+
!Array.isArray(parsedOptions)
88+
|| !parsedOptions.length
89+
|| parsedOptions.some((v) => typeof v !== "string" || !v.trim())
90+
) {
91+
throw new ConfigurationError("`Picklist Options` must be a non-empty JSON array of non-empty strings.");
92+
}
93+
column.options = parsedOptions;
94+
}
95+
if (this.validation !== undefined) {
96+
if (this.type !== "PICKLIST") {
97+
throw new ConfigurationError("`Validation` is only supported for PICKLIST columns.");
98+
}
99+
column.validation = this.validation;
100+
}
101+
102+
const response = await this.smartsheet.addColumn(this.sheetId, {
103+
$,
104+
data: [
105+
column,
106+
],
107+
});
108+
$.export("$summary", `Added column "${this.title}" (${this.type}) to sheet ${this.sheetId}`);
109+
return response;
110+
},
111+
};
Lines changed: 72 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,102 @@
1+
import { ConfigurationError } from "@pipedream/platform";
12
import smartsheet from "../../smartsheet.app.mjs";
23

34
export default {
45
key: "smartsheet-add-row-to-sheet",
56
name: "Add Row to Sheet",
6-
description: "Adds a row to a sheet. [See the documentation](https://developers.smartsheet.com/api/smartsheet/openapi/rows#operation/rows-addToSheet)",
7-
version: "0.0.4",
7+
description:
8+
"Add one or more rows to a sheet. Accepts column NAMES as keys — resolves to column IDs internally."
9+
+ " Call **Get Sheet** or **List Columns** first to learn column names."
10+
+ " Pass rows as a JSON array of objects mapping column names to values:"
11+
+ " `[{\"Task\": \"Review doc\", \"Status\": \"Open\"}]`."
12+
+ " For a single row, pass a one-element array."
13+
+ " [See the documentation](https://developers.smartsheet.com/api/smartsheet/openapi/rows/rows-addtosheet)",
14+
version: "1.0.0",
15+
type: "action",
816
annotations: {
917
destructiveHint: false,
1018
openWorldHint: true,
1119
readOnlyHint: false,
1220
},
13-
type: "action",
1421
props: {
1522
smartsheet,
1623
sheetId: {
17-
propDefinition: [
18-
smartsheet,
19-
"sheetId",
20-
],
21-
reloadProps: true,
24+
type: "string",
25+
label: "Sheet ID",
26+
description: "The ID of the sheet to add rows to. Use **List Sheets** to find sheet IDs.",
27+
},
28+
rows: {
29+
type: "string",
30+
label: "Rows",
31+
description:
32+
"JSON array of row objects mapping column names to values."
33+
+ " Example: `[{\"Species\": \"Triceratops\", \"Status\": \"Contained\"}]`."
34+
+ " Call **Get Sheet** or **List Columns** to discover column names.",
2235
},
2336
toTop: {
2437
type: "boolean",
25-
label: "To Top",
26-
description: "Set to `true` to add new row to the top of the sheet",
38+
label: "Add to Top",
39+
description: "Set to `true` to add new rows to the top of the sheet. Defaults to bottom.",
2740
optional: true,
28-
default: false,
2941
},
30-
cells: {
31-
type: "string[]",
32-
label: "Cells",
33-
description: "Array of objects representing cell values. Use to manually create row when `sheetId` is entered as a custom expression. Example: `{{ [{\"columnId\": 7960873114331012,\"value\": \"New status\"}] }}`",
34-
optional: true,
35-
},
36-
},
37-
async additionalProps() {
38-
const props = {};
39-
const { data: columns } = await this.smartsheet.listColumns(this.sheetId, {
40-
params: {
41-
include: "columnType",
42-
},
43-
});
44-
if (!columns) {
45-
return props;
46-
}
47-
for (const column of columns) {
48-
props[column.id] = {
49-
type: "string",
50-
label: column.title,
51-
description: column?.description || "Enter the column value",
52-
optional: true,
53-
};
54-
if (column.type.includes("CONTACT_LIST")) {
55-
props[column.id] = {
56-
...props[column.id],
57-
options: async ({ page }) => {
58-
const { data } = await this.smartsheet.listContacts({
59-
params: {
60-
page,
61-
},
62-
});
63-
return data?.map(({ email }) => email ) || [];
64-
},
65-
};
66-
}
67-
else if (column?.options) {
68-
props[column.id].options = column.options;
69-
}
70-
}
71-
return props;
7242
},
7343
async run({ $ }) {
74-
const {
75-
sheetId,
76-
toTop,
77-
cells = [],
78-
smartsheet,
79-
...columnProps
80-
} = this;
81-
82-
const data = {
83-
cells: [],
84-
};
85-
if (toTop) {
86-
data.toTop = true;
87-
}
88-
for (const cell of cells) {
89-
const cellValue = typeof cell === "object"
90-
? cell
91-
: JSON.parse(cell);
92-
data.cells.push(cellValue);
44+
let parsedRows;
45+
try {
46+
parsedRows = JSON.parse(this.rows);
47+
} catch {
48+
throw new ConfigurationError("`Rows` must be a valid JSON array of objects.");
9349
}
94-
for (const key of Object.keys(columnProps)) {
95-
data.cells.push({
96-
columnId: key,
97-
value: columnProps[key],
98-
});
50+
if (!Array.isArray(parsedRows) || !parsedRows.length) {
51+
throw new ConfigurationError("`Rows` must be a non-empty JSON array.");
9952
}
10053

101-
const response = await smartsheet.addRow(sheetId, {
102-
data,
54+
const { byName } = await this.smartsheet.getColumnMap(this.sheetId, {
10355
$,
10456
});
10557

106-
$.export("$summary", `Successfully created row with ID ${response.result.id}`);
58+
const apiRows = parsedRows.map((row, rowIndex) => {
59+
if (!row || typeof row !== "object" || Array.isArray(row)) {
60+
throw new ConfigurationError(`Row at index ${rowIndex} must be an object of column name/value pairs.`);
61+
}
62+
const entries = Object.entries(row);
63+
if (!entries.length) {
64+
throw new ConfigurationError(`Row at index ${rowIndex} is empty.`);
65+
}
66+
const cells = [];
67+
const unknownColumns = [];
68+
for (const [
69+
name,
70+
value,
71+
] of entries) {
72+
const columnId = byName[name.toLowerCase()];
73+
if (columnId) {
74+
cells.push({
75+
columnId,
76+
value,
77+
});
78+
} else {
79+
unknownColumns.push(name);
80+
}
81+
}
82+
if (unknownColumns.length) {
83+
throw new ConfigurationError(`Row at index ${rowIndex} references unknown column(s): ${unknownColumns.join(", ")}. Use **Get Sheet** or **List Columns** to see valid column names.`);
84+
}
85+
const rowObj = {
86+
cells,
87+
};
88+
if (this.toTop) rowObj.toTop = true;
89+
else rowObj.toBottom = true;
90+
return rowObj;
91+
});
92+
93+
const response = await this.smartsheet.addRow(this.sheetId, {
94+
$,
95+
data: apiRows,
96+
});
10797

98+
const count = response.result?.length || 1;
99+
$.export("$summary", `Added ${count} row(s) to sheet ${this.sheetId}`);
108100
return response;
109101
},
110102
};
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { ConfigurationError } from "@pipedream/platform";
2+
import {
3+
parseRowIds, toPositiveInteger,
4+
} from "../../common/utils.mjs";
5+
import smartsheet from "../../smartsheet.app.mjs";
6+
7+
export default {
8+
key: "smartsheet-copy-rows",
9+
name: "Copy Rows",
10+
description:
11+
"Copy one or more rows from a source sheet to a destination sheet. The rows remain in the source sheet and are duplicated in the destination."
12+
+ " Cell values, formatting, and attachments are copied. The destination sheet must have compatible columns."
13+
+ " Use **Get Sheet** to find row IDs in the source sheet."
14+
+ " To move rows instead (removing them from the source), use **Move Rows**."
15+
+ " [See the documentation](https://developers.smartsheet.com/api/smartsheet/openapi/rows/copy-rows)",
16+
version: "0.0.1",
17+
type: "action",
18+
annotations: {
19+
destructiveHint: false,
20+
openWorldHint: true,
21+
readOnlyHint: false,
22+
},
23+
props: {
24+
smartsheet,
25+
sheetId: {
26+
type: "string",
27+
label: "Source Sheet ID",
28+
description: "The ID of the source sheet containing the rows. Use **List Sheets** to find sheet IDs.",
29+
},
30+
rowIds: {
31+
type: "string",
32+
label: "Row IDs",
33+
description:
34+
"Comma-separated list of row IDs to copy, or a JSON array."
35+
+ " Example: `1234567890, 9876543210` or `[1234567890, 9876543210]`."
36+
+ " Use **Get Sheet** to find row IDs.",
37+
},
38+
destinationSheetId: {
39+
type: "string",
40+
label: "Destination Sheet ID",
41+
description: "The ID of the destination sheet to copy rows into. Use **List Sheets** to find sheet IDs.",
42+
},
43+
},
44+
async run({ $ }) {
45+
const rowIds = parseRowIds(this.rowIds);
46+
const destinationSheetId = toPositiveInteger(this.destinationSheetId);
47+
if (!Number.isInteger(destinationSheetId) || destinationSheetId <= 0) {
48+
throw new ConfigurationError("`Destination Sheet ID` must be a positive integer sheet ID.");
49+
}
50+
51+
const response = await this.smartsheet.copyRows(this.sheetId, {
52+
$,
53+
data: {
54+
rowIds,
55+
to: {
56+
sheetId: destinationSheetId,
57+
},
58+
},
59+
});
60+
$.export("$summary", `Copied ${rowIds.length} row(s) from sheet ${this.sheetId} to sheet ${this.destinationSheetId}`);
61+
return response;
62+
},
63+
};

0 commit comments

Comments
 (0)