Skip to content

Commit 3647a3e

Browse files
aadamgoughaadamgough
andauthored
improvement(tools): added add worksheet to excel block (#2061)
Co-authored-by: aadamgough <[email protected]>
1 parent f609b6e commit 3647a3e

File tree

6 files changed

+245
-5
lines changed

6 files changed

+245
-5
lines changed

apps/docs/content/docs/en/tools/microsoft_excel.mdx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ In Sim, the Microsoft Excel integration provides seamless access to spreadsheet
2727

2828
## Usage Instructions
2929

30-
Integrate Microsoft Excel into the workflow. Can read, write, update, and add to table.
30+
Integrate Microsoft Excel into the workflow. Can read, write, update, add to table, and create new worksheets.
3131

3232

3333

@@ -94,6 +94,23 @@ Add new rows to a Microsoft Excel table
9494
| `values` | array | Array of rows that were added to the table |
9595
| `metadata` | object | Spreadsheet metadata |
9696

97+
### `microsoft_excel_worksheet_add`
98+
99+
Create a new worksheet (sheet) in a Microsoft Excel workbook
100+
101+
#### Input
102+
103+
| Parameter | Type | Required | Description |
104+
| --------- | ---- | -------- | ----------- |
105+
| `spreadsheetId` | string | Yes | The ID of the Excel workbook to add the worksheet to |
106+
| `worksheetName` | string | Yes | The name of the new worksheet. Must be unique within the workbook and cannot exceed 31 characters |
107+
108+
#### Output
109+
110+
| Parameter | Type | Description |
111+
| --------- | ---- | ----------- |
112+
| `worksheet` | object | Details of the newly created worksheet |
113+
97114

98115

99116
## Notes

apps/sim/blocks/blocks/microsoft_excel.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
99
description: 'Read, write, and update data',
1010
authMode: AuthMode.OAuth,
1111
longDescription:
12-
'Integrate Microsoft Excel into the workflow. Can read, write, update, and add to table.',
12+
'Integrate Microsoft Excel into the workflow. Can read, write, update, add to table, and create new worksheets.',
1313
docsLink: 'https://docs.sim.ai/tools/microsoft_excel',
1414
category: 'tools',
1515
bgColor: '#E0E0E0',
@@ -23,6 +23,7 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
2323
{ label: 'Read Data', id: 'read' },
2424
{ label: 'Write/Update Data', id: 'write' },
2525
{ label: 'Add to Table', id: 'table_add' },
26+
{ label: 'Add Worksheet', id: 'worksheet_add' },
2627
],
2728
value: () => 'read',
2829
},
@@ -80,6 +81,14 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
8081
condition: { field: 'operation', value: ['table_add'] },
8182
required: true,
8283
},
84+
{
85+
id: 'worksheetName',
86+
title: 'Worksheet Name',
87+
type: 'short-input',
88+
placeholder: 'Name of the new worksheet (max 31 characters)',
89+
condition: { field: 'operation', value: ['worksheet_add'] },
90+
required: true,
91+
},
8392
{
8493
id: 'values',
8594
title: 'Values',
@@ -129,7 +138,12 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
129138
},
130139
],
131140
tools: {
132-
access: ['microsoft_excel_read', 'microsoft_excel_write', 'microsoft_excel_table_add'],
141+
access: [
142+
'microsoft_excel_read',
143+
'microsoft_excel_write',
144+
'microsoft_excel_table_add',
145+
'microsoft_excel_worksheet_add',
146+
],
133147
config: {
134148
tool: (params) => {
135149
switch (params.operation) {
@@ -139,13 +153,22 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
139153
return 'microsoft_excel_write'
140154
case 'table_add':
141155
return 'microsoft_excel_table_add'
156+
case 'worksheet_add':
157+
return 'microsoft_excel_worksheet_add'
142158
default:
143159
throw new Error(`Invalid Microsoft Excel operation: ${params.operation}`)
144160
}
145161
},
146162
params: (params) => {
147-
const { credential, values, spreadsheetId, manualSpreadsheetId, tableName, ...rest } =
148-
params
163+
const {
164+
credential,
165+
values,
166+
spreadsheetId,
167+
manualSpreadsheetId,
168+
tableName,
169+
worksheetName,
170+
...rest
171+
} = params
149172

150173
const effectiveSpreadsheetId = (spreadsheetId || manualSpreadsheetId || '').trim()
151174

@@ -164,6 +187,10 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
164187
throw new Error('Table name is required for table operations.')
165188
}
166189

190+
if (params.operation === 'worksheet_add' && !worksheetName) {
191+
throw new Error('Worksheet name is required for worksheet operations.')
192+
}
193+
167194
const baseParams = {
168195
...rest,
169196
spreadsheetId: effectiveSpreadsheetId,
@@ -178,6 +205,13 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
178205
}
179206
}
180207

208+
if (params.operation === 'worksheet_add') {
209+
return {
210+
...baseParams,
211+
worksheetName,
212+
}
213+
}
214+
181215
return baseParams
182216
},
183217
},
@@ -189,6 +223,7 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
189223
manualSpreadsheetId: { type: 'string', description: 'Manual spreadsheet identifier' },
190224
range: { type: 'string', description: 'Cell range' },
191225
tableName: { type: 'string', description: 'Table name' },
226+
worksheetName: { type: 'string', description: 'Worksheet name' },
192227
values: { type: 'string', description: 'Cell values data' },
193228
valueInputOption: { type: 'string', description: 'Value input option' },
194229
},
@@ -207,5 +242,9 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
207242
},
208243
index: { type: 'number', description: 'Row index for table add operations' },
209244
values: { type: 'json', description: 'Cell values array for table add operations' },
245+
worksheet: {
246+
type: 'json',
247+
description: 'Details of the newly created worksheet (worksheet_add operations)',
248+
},
210249
},
211250
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { readTool } from '@/tools/microsoft_excel/read'
22
import { tableAddTool } from '@/tools/microsoft_excel/table_add'
3+
import { worksheetAddTool } from '@/tools/microsoft_excel/worksheet_add'
34
import { writeTool } from '@/tools/microsoft_excel/write'
45

56
export const microsoftExcelReadTool = readTool
67
export const microsoftExcelTableAddTool = tableAddTool
8+
export const microsoftExcelWorksheetAddTool = worksheetAddTool
79
export const microsoftExcelWriteTool = writeTool

apps/sim/tools/microsoft_excel/types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ export interface MicrosoftExcelTableAddResponse extends ToolResponse {
4848
}
4949
}
5050

51+
export interface MicrosoftExcelWorksheetAddResponse extends ToolResponse {
52+
output: {
53+
worksheet: {
54+
id: string
55+
name: string
56+
position: number
57+
visibility: string
58+
}
59+
metadata: MicrosoftExcelMetadata
60+
}
61+
}
62+
5163
export interface MicrosoftExcelToolParams {
5264
accessToken: string
5365
spreadsheetId: string
@@ -68,7 +80,14 @@ export interface MicrosoftExcelTableToolParams {
6880
rowIndex?: number
6981
}
7082

83+
export interface MicrosoftExcelWorksheetToolParams {
84+
accessToken: string
85+
spreadsheetId: string
86+
worksheetName: string
87+
}
88+
7189
export type MicrosoftExcelResponse =
7290
| MicrosoftExcelReadResponse
7391
| MicrosoftExcelWriteResponse
7492
| MicrosoftExcelTableAddResponse
93+
| MicrosoftExcelWorksheetAddResponse
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import type {
2+
MicrosoftExcelWorksheetAddResponse,
3+
MicrosoftExcelWorksheetToolParams,
4+
} from '@/tools/microsoft_excel/types'
5+
import { getSpreadsheetWebUrl } from '@/tools/microsoft_excel/utils'
6+
import type { ToolConfig } from '@/tools/types'
7+
8+
/**
9+
* Tool for adding a new worksheet to a Microsoft Excel workbook
10+
* Uses Microsoft Graph API endpoint: POST /me/drive/items/{id}/workbook/worksheets/add
11+
*/
12+
export const worksheetAddTool: ToolConfig<
13+
MicrosoftExcelWorksheetToolParams,
14+
MicrosoftExcelWorksheetAddResponse
15+
> = {
16+
id: 'microsoft_excel_worksheet_add',
17+
name: 'Add Worksheet to Microsoft Excel',
18+
description: 'Create a new worksheet (sheet) in a Microsoft Excel workbook',
19+
version: '1.0',
20+
21+
oauth: {
22+
required: true,
23+
provider: 'microsoft-excel',
24+
},
25+
26+
params: {
27+
accessToken: {
28+
type: 'string',
29+
required: true,
30+
visibility: 'hidden',
31+
description: 'The access token for the Microsoft Excel API',
32+
},
33+
spreadsheetId: {
34+
type: 'string',
35+
required: true,
36+
visibility: 'user-only',
37+
description: 'The ID of the Excel workbook to add the worksheet to',
38+
},
39+
worksheetName: {
40+
type: 'string',
41+
required: true,
42+
visibility: 'user-or-llm',
43+
description:
44+
'The name of the new worksheet. Must be unique within the workbook and cannot exceed 31 characters',
45+
},
46+
},
47+
48+
request: {
49+
url: (params) => {
50+
const spreadsheetId = params.spreadsheetId?.trim()
51+
if (!spreadsheetId) {
52+
throw new Error('Spreadsheet ID is required')
53+
}
54+
return `https://graph.microsoft.com/v1.0/me/drive/items/${spreadsheetId}/workbook/worksheets/add`
55+
},
56+
method: 'POST',
57+
headers: (params) => {
58+
if (!params.accessToken) {
59+
throw new Error('Access token is required')
60+
}
61+
62+
return {
63+
Authorization: `Bearer ${params.accessToken}`,
64+
'Content-Type': 'application/json',
65+
}
66+
},
67+
body: (params) => {
68+
const worksheetName = params.worksheetName?.trim()
69+
70+
if (!worksheetName) {
71+
throw new Error('Worksheet name is required')
72+
}
73+
74+
// Validate worksheet name length (Excel limitation)
75+
if (worksheetName.length > 31) {
76+
throw new Error('Worksheet name cannot exceed 31 characters. Please provide a shorter name')
77+
}
78+
79+
// Validate worksheet name doesn't contain invalid characters
80+
const invalidChars = ['\\', '/', '?', '*', '[', ']', ':']
81+
for (const char of invalidChars) {
82+
if (worksheetName.includes(char)) {
83+
throw new Error(`Worksheet name cannot contain the following characters: \\ / ? * [ ] :`)
84+
}
85+
}
86+
87+
return {
88+
name: worksheetName,
89+
}
90+
},
91+
},
92+
93+
transformResponse: async (response: Response, params?: MicrosoftExcelWorksheetToolParams) => {
94+
if (!response.ok) {
95+
const errorData = await response.json().catch(() => ({}))
96+
const errorMessage =
97+
errorData?.error?.message || `Failed to create worksheet: ${response.statusText}`
98+
99+
// Handle specific error cases
100+
if (response.status === 409) {
101+
throw new Error('A worksheet with this name already exists. Please choose a different name')
102+
}
103+
104+
throw new Error(errorMessage)
105+
}
106+
107+
const data = await response.json()
108+
109+
const urlParts = response.url.split('/drive/items/')
110+
const spreadsheetId = urlParts[1]?.split('/')[0] || ''
111+
112+
// Fetch the browser-accessible web URL
113+
const accessToken = params?.accessToken
114+
if (!accessToken) {
115+
throw new Error('Access token is required')
116+
}
117+
const webUrl = await getSpreadsheetWebUrl(spreadsheetId, accessToken)
118+
119+
const result: MicrosoftExcelWorksheetAddResponse = {
120+
success: true,
121+
output: {
122+
worksheet: {
123+
id: data.id || '',
124+
name: data.name || '',
125+
position: data.position ?? 0,
126+
visibility: data.visibility || 'Visible',
127+
},
128+
metadata: {
129+
spreadsheetId,
130+
spreadsheetUrl: webUrl,
131+
},
132+
},
133+
}
134+
135+
return result
136+
},
137+
138+
outputs: {
139+
worksheet: {
140+
type: 'object',
141+
description: 'Details of the newly created worksheet',
142+
properties: {
143+
id: { type: 'string', description: 'The unique ID of the worksheet' },
144+
name: { type: 'string', description: 'The name of the worksheet' },
145+
position: { type: 'number', description: 'The zero-based position of the worksheet' },
146+
visibility: {
147+
type: 'string',
148+
description: 'The visibility state of the worksheet (Visible/Hidden/VeryHidden)',
149+
},
150+
},
151+
},
152+
metadata: {
153+
type: 'object',
154+
description: 'Spreadsheet metadata',
155+
properties: {
156+
spreadsheetId: { type: 'string', description: 'The ID of the spreadsheet' },
157+
spreadsheetUrl: { type: 'string', description: 'URL to access the spreadsheet' },
158+
},
159+
},
160+
},
161+
}

apps/sim/tools/registry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ import { memoryAddTool, memoryDeleteTool, memoryGetAllTool, memoryGetTool } from
348348
import {
349349
microsoftExcelReadTool,
350350
microsoftExcelTableAddTool,
351+
microsoftExcelWorksheetAddTool,
351352
microsoftExcelWriteTool,
352353
} from '@/tools/microsoft_excel'
353354
import {
@@ -1172,6 +1173,7 @@ export const tools: Record<string, ToolConfig> = {
11721173
microsoft_excel_read: microsoftExcelReadTool,
11731174
microsoft_excel_write: microsoftExcelWriteTool,
11741175
microsoft_excel_table_add: microsoftExcelTableAddTool,
1176+
microsoft_excel_worksheet_add: microsoftExcelWorksheetAddTool,
11751177
microsoft_planner_create_task: microsoftPlannerCreateTaskTool,
11761178
microsoft_planner_read_task: microsoftPlannerReadTaskTool,
11771179
microsoft_planner_update_task: microsoftPlannerUpdateTaskTool,

0 commit comments

Comments
 (0)